-
Notifications
You must be signed in to change notification settings - Fork 748
Picker Refactor #1 #1000
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
Picker Refactor #1 #1000
Changes from 2 commits
f72e066
e2edb61
1c4cf1a
f62aa77
9dd94bb
2e8666a
7b6bbe0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,9 @@ | ||
| import _ from 'lodash'; | ||
| import PropTypes from 'prop-types'; | ||
| import React from 'react'; | ||
| import React, {useCallback, useEffect} from 'react'; | ||
| import {StyleSheet} from 'react-native'; | ||
| import {Colors, Typography} from '../../style'; | ||
| import {BaseComponent} from '../../commons'; | ||
| import * as Modifiers from '../../commons/modifiers'; | ||
| import Assets from '../../assets'; | ||
| import View from '../view'; | ||
| import TouchableOpacity from '../touchableOpacity'; | ||
|
|
@@ -16,153 +16,138 @@ import Text from '../text'; | |
| * @extendslink: docs/TouchableOpacity | ||
| * @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/PickerScreen.js | ||
| */ | ||
| class PickerItem extends BaseComponent { | ||
| static displayName = 'Picker.Item'; | ||
|
|
||
| static propTypes = { | ||
| /** | ||
| * Item's value | ||
| */ | ||
| value: PropTypes.oneOfType([PropTypes.object, PropTypes.string, PropTypes.number]), | ||
| /** | ||
| * Item's label | ||
| */ | ||
| label: PropTypes.string, | ||
| /** | ||
| * Custom function for the item label (e.g (value) => customLabel) | ||
| */ | ||
| getItemLabel: PropTypes.func, | ||
| /** | ||
| * DEPRECATE: Function to return the value out of the item value prop when value is custom shaped. | ||
| */ | ||
| getItemValue: PropTypes.func, | ||
| /** | ||
| * Is the item selected | ||
| */ | ||
| isSelected: PropTypes.bool, | ||
| /** | ||
| * Pass to change the selected icon | ||
| */ | ||
| selectedIcon: PropTypes.oneOfType([PropTypes.object, PropTypes.number]), | ||
| /** | ||
| * Pass to change the selected icon color | ||
| */ | ||
| selectedIconColor: PropTypes.string, | ||
| /** | ||
| * Is the item disabled | ||
| */ | ||
| disabled: PropTypes.bool, | ||
| /** | ||
| * Render custom item | ||
| */ | ||
| renderItem: PropTypes.elementType, | ||
| /** | ||
| * Callback for onPress action | ||
| */ | ||
| onPress: PropTypes.func, | ||
| /** | ||
| * Callback for onLayout event | ||
| */ | ||
| onSelectedLayout: PropTypes.func | ||
| }; | ||
|
|
||
|
|
||
| constructor(props) { | ||
| super(props); | ||
|
|
||
| if (_.isPlainObject(props.value)) { | ||
| const PickerItem = props => { | ||
| const { | ||
| renderItem, | ||
| value, | ||
| label, | ||
| onPress, | ||
| disabled, | ||
| isSelected, | ||
| selectedIcon = Assets.icons.check, | ||
| selectedIconColor, | ||
| testID | ||
| } = props; | ||
|
|
||
| useEffect(() => { | ||
| if (_.isPlainObject(value)) { | ||
| console.warn('UILib Picker.Item will stop supporting passing object as value & label (e.g {value, label}) in the next major version. Please pass separate label and value props'); | ||
| } | ||
| } | ||
|
|
||
| }, []); | ||
|
|
||
| generateStyles() { | ||
| this.styles = createStyles(this.props); | ||
| } | ||
| // TODO: deprecate the check for object | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO hints for
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed it in a following PR |
||
| const _onPress = useCallback(() => { | ||
| // onPress(_.isObject(value) ? value : {value, label}); | ||
| onPress(value); | ||
| }, [value, onPress]); | ||
|
|
||
| getLabel() { | ||
| const {value, label} = this.props; | ||
| const onSelectedLayout = useCallback((...args) => { | ||
| _.invoke(props, 'onSelectedLayout', ...args); | ||
| }, []); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we pass
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is internal usage. |
||
|
|
||
| const getLabel = () => { | ||
| if (_.isObject(value)) { | ||
| return _.invoke(this.props, 'getItemLabel', value) || _.get(value, 'label'); | ||
| return _.invoke(props, 'getItemLabel', value) || _.get(value, 'label'); | ||
| } | ||
| return label; | ||
| } | ||
|
|
||
| renderSelectedIndicator() { | ||
| const { | ||
| isSelected, | ||
| disabled, | ||
| selectedIcon = Assets.icons.check, | ||
| selectedIconColor = Colors.primary | ||
| } = this.props; | ||
| }; | ||
|
|
||
| const renderSelectedIndicator = () => { | ||
|
||
| if (isSelected) { | ||
| return <Image source={selectedIcon} tintColor={disabled ? Colors.dark60 : selectedIconColor}/>; | ||
| } | ||
| } | ||
|
|
||
| renderItem() { | ||
| const {disabled} = this.props; | ||
| }; | ||
|
|
||
| const _renderItem = () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also in here, should be memoized
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't want to overkill the component with memoization. memoizing this will require wrapping Anyway, Personally I still not certain what is best practice with how often to use
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha. confusing topic indeed :) |
||
| return ( | ||
| <View style={this.styles.container} flex row spread centerV> | ||
| <Text numberOfLines={1} style={[this.styles.labelText, disabled && this.styles.labelTextDisabled]}> | ||
| {this.getLabel()} | ||
| <View style={styles.container} flex row spread centerV> | ||
| <Text numberOfLines={1} style={[styles.labelText, disabled && styles.labelTextDisabled]}> | ||
| {getLabel()} | ||
| </Text> | ||
| {this.renderSelectedIndicator()} | ||
| {renderSelectedIndicator()} | ||
| </View> | ||
| ); | ||
| } | ||
|
|
||
| onSelectedLayout = (...args) => { | ||
| _.invoke(this.props, 'onSelectedLayout', ...args); | ||
| }; | ||
|
|
||
| render() { | ||
| const {renderItem, value, disabled, isSelected, testID} = this.props; | ||
|
|
||
| return ( | ||
| <TouchableOpacity | ||
| activeOpacity={0.5} | ||
| onPress={this.onPress} | ||
| onLayout={isSelected ? this.onSelectedLayout : undefined} | ||
| disabled={disabled} | ||
| testID={testID} | ||
| throttleTime={0} | ||
| {...this.extractAccessibilityProps()} | ||
| > | ||
| {renderItem ? renderItem(value, this.props, this.getLabel()) : this.renderItem()} | ||
| </TouchableOpacity> | ||
| ); | ||
| return ( | ||
| <TouchableOpacity | ||
| activeOpacity={0.5} | ||
| onPress={_onPress} | ||
| onLayout={isSelected ? onSelectedLayout : undefined} | ||
| disabled={disabled} | ||
| testID={testID} | ||
| throttleTime={0} | ||
| {...Modifiers.extractAccessibilityProps(props)} | ||
| > | ||
| {renderItem ? renderItem(value, props, getLabel()) : _renderItem()} | ||
| </TouchableOpacity> | ||
| ); | ||
| }; | ||
|
|
||
| const styles = StyleSheet.create({ | ||
| container: { | ||
| height: 56.5, | ||
| paddingHorizontal: 23, | ||
| borderColor: Colors.rgba(Colors.dark10, 0.1), | ||
| borderBottomWidth: 1 | ||
| }, | ||
| labelText: { | ||
| ...Typography.text70, | ||
| color: Colors.dark10, | ||
| flex: 1, | ||
| textAlign: 'left' | ||
| }, | ||
| labelTextDisabled: { | ||
| color: Colors.dark60 | ||
| } | ||
|
|
||
| // TODO: deprecate the check for object | ||
| onPress = () => { | ||
| const {value, onPress} = this.props; | ||
| // onPress(_.isObject(value) ? value : {value, label}); | ||
| onPress(value); | ||
| }; | ||
| } | ||
|
|
||
| function createStyles() { | ||
| return StyleSheet.create({ | ||
| container: { | ||
| height: 56.5, | ||
| paddingHorizontal: 23, | ||
| borderColor: Colors.rgba(Colors.dark10, 0.1), | ||
| borderBottomWidth: 1 | ||
| }, | ||
| labelText: { | ||
| ...Typography.text70, | ||
| color: Colors.dark10, | ||
| flex: 1, | ||
| textAlign: 'left' | ||
| }, | ||
| labelTextDisabled: { | ||
| color: Colors.dark60 | ||
| } | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| PickerItem.displayName = 'Picker.Item'; | ||
| PickerItem.propTypes = { | ||
| /** | ||
| * Item's value | ||
| */ | ||
| value: PropTypes.oneOfType([PropTypes.object, PropTypes.string, PropTypes.number]), | ||
| /** | ||
| * Item's label | ||
| */ | ||
| label: PropTypes.string, | ||
| /** | ||
| * Custom function for the item label (e.g (value) => customLabel) | ||
| */ | ||
| getItemLabel: PropTypes.func, | ||
| /** | ||
| * DEPRECATE: Function to return the value out of the item value prop when value is custom shaped. | ||
| */ | ||
| getItemValue: PropTypes.func, | ||
| /** | ||
| * Is the item selected | ||
| */ | ||
| isSelected: PropTypes.bool, | ||
| /** | ||
| * Pass to change the selected icon | ||
| */ | ||
| selectedIcon: PropTypes.oneOfType([PropTypes.object, PropTypes.number]), | ||
| /** | ||
| * Pass to change the selected icon color | ||
| */ | ||
| selectedIconColor: PropTypes.string, | ||
| /** | ||
| * Is the item disabled | ||
| */ | ||
| disabled: PropTypes.bool, | ||
| /** | ||
| * Render custom item | ||
| */ | ||
| renderItem: PropTypes.elementType, | ||
| /** | ||
| * Callback for onPress action | ||
| */ | ||
| onPress: PropTypes.func, | ||
| /** | ||
| * Callback for onLayout event | ||
| */ | ||
| onSelectedLayout: PropTypes.func | ||
| }; | ||
|
|
||
| export default PickerItem; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Due tho some of the of the props in PickerItem (like
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Understood :) |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lint error,
We should either pass
valueas a dependency or no square brackets to trigger on each renderThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done