Skip to content

Feat/with scroll enabler #807

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jun 24, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions demo/src/screens/MenuStructure.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ export const navigationData = {
{title: 'StateScreen', tags: 'empty state screen', screen: 'unicorn.screens.EmptyStateScreen'},
{title: 'TabController', tags: 'tabbar controller native', screen: 'unicorn.components.TabControllerScreen'},
{title: 'TabBar', tags: 'tab bar', screen: 'unicorn.components.TabBarScreen'},
{
title: 'withScrollEnabler',
tags: 'scroll enabled withScrollEnabler',
screen: 'unicorn.components.WithScrollEnablerScreen'
},
{title: 'Wizard', tags: 'wizard', screen: 'unicorn.components.WizardScreen'}
]
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import _ from 'lodash';
import React, {memo} from 'react';
import {
FlatList,
FlatListProps,
StyleSheet,
LayoutChangeEvent
} from 'react-native';
import memoize from 'memoize-one';
import {
Colors,
Text,
View,
withScrollEnabler,
WithScrollEnablerProps
} from 'react-native-ui-lib';

export type AutoLockScrollViewProps = FlatListProps<number> & {
numberOfItems: number;
};

const AutoLockFlatList = (props: AutoLockScrollViewProps) => {
const numberOfItems = props.numberOfItems;

const WithScrollEnabler = withScrollEnabler(
(props: WithScrollEnablerProps) => {
const getData = memoize((numberOfItems: number) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even though you memoize this function you still re-creating it on each render.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to useCallback

return [...Array(numberOfItems).keys()];
});

function keyExtractor(item: number) {
return item.toString();
}
function renderItem({index}: {index: number}) {
return (
<View key={index} style={styles.item}>
<Text>{index + 1}</Text>
</View>
);
}

function onContentSizeChange(
contentWidth: number,
contentHeight: number
) {
_.invoke(props, 'onContentSizeChange', contentWidth, contentHeight);
_.invoke(
props,
'scrollEnablerProps.onContentSizeChange',
contentWidth,
contentHeight
);
}

function onLayout(nativeEvent: LayoutChangeEvent) {
_.invoke(props, 'onLayout', nativeEvent);
_.invoke(props, 'scrollEnablerProps.onLayout', nativeEvent);
}

return (
<FlatList
{...props}
style={styles.flatList}
contentContainerStyle={styles.flatListContainer}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
data={getData(numberOfItems)}
renderItem={renderItem}
keyExtractor={keyExtractor}
onContentSizeChange={onContentSizeChange}
onLayout={onLayout}
scrollEnabled={props.scrollEnablerProps.scrollEnabled}
/>
);
}
);

return <WithScrollEnabler {...props} />;
};

export default memo(AutoLockFlatList);

const styles = StyleSheet.create({
flatList: {
height: 240
},
flatListContainer: {
alignItems: 'center'
},
item: {
width: 100,
height: 100,
margin: 9,
backgroundColor: Colors.grey40,
alignItems: 'center',
justifyContent: 'center'
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import _ from 'lodash';
import React, {memo} from 'react';
import {
ScrollView,
ScrollViewProps,
StyleSheet,
LayoutChangeEvent
} from 'react-native';
import {
Colors,
Text,
View,
withScrollEnabler,
WithScrollEnablerProps
} from 'react-native-ui-lib';

export type AutoLockScrollViewProps = ScrollViewProps & {
numberOfItems: number;
};

const AutoLockScrollView = (props: AutoLockScrollViewProps) => {
const numberOfItems = props.numberOfItems;

const WithScrollEnabler = withScrollEnabler(
(props: WithScrollEnablerProps) => {
function renderItem(index: number) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must use useCallback in order to define methods inside a function component.
Otherwise what will happen is that on every render you will re-create those functions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to useCallback

return (
<View key={index} style={styles.item}>
<Text>{index + 1}</Text>
</View>
);
}

function onContentSizeChange(
contentWidth: number,
contentHeight: number
) {
_.invoke(props, 'onContentSizeChange', contentWidth, contentHeight);
_.invoke(
props,
'scrollEnablerProps.onContentSizeChange',
contentWidth,
contentHeight
);
}

function onLayout(nativeEvent: LayoutChangeEvent) {
_.invoke(props, 'onLayout', nativeEvent);
_.invoke(props, 'scrollEnablerProps.onLayout', nativeEvent);
}

return (
<ScrollView
{...props}
style={styles.scrollView}
contentContainerStyle={styles.scrollViewContainer}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
onContentSizeChange={onContentSizeChange}
onLayout={onLayout}
scrollEnabled={props.scrollEnablerProps.scrollEnabled}
>
{_.times(numberOfItems, renderItem)}
</ScrollView>
);
}
);

return <WithScrollEnabler {...props} />;
};

export default memo(AutoLockScrollView);

const styles = StyleSheet.create({
scrollView: {
height: 240
},
scrollViewContainer: {
alignItems: 'center'
},
item: {
width: 100,
height: 100,
margin: 9,
backgroundColor: Colors.grey40,
alignItems: 'center',
justifyContent: 'center'
}
});
116 changes: 116 additions & 0 deletions demo/src/screens/componentScreens/WithScrollEnablerScreen/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React, {Component} from 'react';
import {LayoutChangeEvent} from 'react-native';
import {Text, View} from 'react-native-ui-lib';
import {
renderHeader,
renderBooleanOption,
renderSliderOption
} from '../../ExampleScreenPresenter';
import AutoLockScrollView from './AutoLockScrollView';
import AutoLockFlatList from './AutoLockFlatList';

class WithScrollEnablerScreen extends Component {
state = {
isListView: false,
isHorizontal: false,
numberOfItems: 3,
contentWidth: undefined,
contentHeight: undefined,
layoutWidth: undefined,
layoutHeight: undefined
};

onContentSizeChange = (contentWidth: number, contentHeight: number) => {
const {
contentWidth: currentContentWidth,
contentHeight: currentContentHeight
} = this.state;
if (
currentContentWidth !== contentWidth ||
currentContentHeight !== contentHeight
) {
this.setState({contentWidth, contentHeight});
}
};

onLayout = ({
nativeEvent: {
layout: {width, height}
}
}: LayoutChangeEvent) => {
const {layoutWidth, layoutHeight} = this.state;
if (width !== layoutWidth || height !== layoutHeight) {
this.setState({layoutWidth: width, layoutHeight: height});
}
};

renderList = () => {
const {isListView, isHorizontal, numberOfItems} = this.state;
const Container = isListView ? AutoLockScrollView : AutoLockFlatList;

return (
// @ts-ignore
<Container
key={`${isHorizontal}`}
horizontal={isHorizontal}
numberOfItems={numberOfItems}
onContentSizeChange={this.onContentSizeChange}
onLayout={this.onLayout}
/>
);
};

renderData = () => {
const {contentWidth, contentHeight, layoutWidth, layoutHeight} = this.state;
const contentText = `Content {width, height}: ${contentWidth}, ${contentHeight}`;
const layoutText = `Layout {width, height}: ${layoutWidth}, ${layoutHeight}`;
return (
<>
<Text text70>{contentText}</Text>
<Text text70>{layoutText}</Text>
</>
);
};

renderOptions = () => {
const {isListView, isHorizontal} = this.state;
const orientationText = isHorizontal ? 'Horizontal' : 'Vertical';
const listTypeText = isListView ? 'ListView' : 'FlatList';
return (
<>
<View row>
<View flex marginR-10>
{renderBooleanOption.call(this, orientationText, 'isHorizontal')}
</View>
<View flex marginL-10>
{renderBooleanOption.call(this, listTypeText, 'isListView')}
</View>
</View>
{renderSliderOption.call(
this,
'Number of items shown',
'numberOfItems',
{
min: 1,
max: 5,
step: 1,
initial: 3
}
)}
</>
);
};

render() {
return (
<View margin-10>
{renderHeader('withScrollEnabler', {'marginB-10': true})}
{this.renderOptions()}
{this.renderData()}
{this.renderList()}
</View>
);
}
}

export default WithScrollEnablerScreen;
1 change: 1 addition & 0 deletions demo/src/screens/componentScreens/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,6 @@ export function registerScreens(registrar) {
registrar('unicorn.screens.EmptyStateScreen', () => require('./EmptyStateScreen').default);
registrar('unicorn.screens.LoadingScreen', () => require('./LoadingScreen').default);
registrar('unicorn.screens.ModalScreen', () => require('./ModalScreen').default);
registrar('unicorn.components.WithScrollEnablerScreen', () => require('./WithScrollEnablerScreen').default);
}

1 change: 1 addition & 0 deletions generatedTypes/commons/new.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as UIComponent } from './UIComponent';
export { default as asBaseComponent, BaseComponentInjectedProps } from './asBaseComponent';
export { default as forwardRef, ForwardRefInjectedProps } from './forwardRef';
export { default as withScrollEnabler } from './withScrollEnabler';
export { ContainerModifiers, MarginModifiers, TypographyModifiers, ColorsModifiers, BackgroundColorModifier } from './modifiers';
14 changes: 14 additions & 0 deletions generatedTypes/commons/withScrollEnabler.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { FlatListProps, ScrollViewProps, LayoutChangeEvent } from 'react-native';
export declare type ScrollEnablerProps = {
onContentSizeChange: (contentWidth: number, contentHeight: number) => void;
onLayout: (event: LayoutChangeEvent) => void;
scrollEnabled: boolean;
};
declare type SupportedViews = FlatListProps<any> | ScrollViewProps;
export declare type WithScrollEnablerProps = SupportedViews & {
scrollEnablerProps: ScrollEnablerProps;
ref?: any;
};
declare function withScrollEnabler<PROPS extends SupportedViews>(WrappedComponent: React.ComponentType<WithScrollEnablerProps>): React.ComponentType<PROPS>;
export default withScrollEnabler;
1 change: 1 addition & 0 deletions generatedTypes/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Please use this file for declaring all the exports, so they could be picked up by typescript's complier
*/
export * from './style';
export {withScrollEnabler} from './commons/new';
export {default as Card} from './components/card';
export {default as View, ViewPropTypes} from './components/view';
export {default as Text} from './components/text';
Expand Down
3 changes: 3 additions & 0 deletions src/commons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ module.exports = {
},
get forwardRef() {
return require('./forwardRef').default;
},
get withScrollEnabler() {
return require('./withScrollEnabler').default;
}
};
1 change: 1 addition & 0 deletions src/commons/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
export {default as UIComponent} from './UIComponent';
export {default as asBaseComponent, BaseComponentInjectedProps} from './asBaseComponent';
export {default as forwardRef, ForwardRefInjectedProps} from './forwardRef';
export {default as withScrollEnabler} from './withScrollEnabler';
export {
ContainerModifiers,
MarginModifiers,
Expand Down
Loading