react-native-picker-select
Advanced tools
Comparing version 7.0.0-beta.0 to 7.0.0
@@ -1,14 +0,54 @@ | ||
## 7.0.0 | ||
### 7.0.0 | ||
#### Breaking Changes | ||
##### Breaking Changes | ||
- Deprecated `placeholderTextColor` and `hideDoneBar` props removed | ||
- Typescript type definitions received a major overhaul (#248) | ||
- Base component is now a `Text` element to fix issues on Android (#234). This _should_ not cause any issues unless you are targeting the former `TextInput` in tests. | ||
- Deprecated prop `hideDoneBar` has been removed | ||
- Deprecated prop `placeholderTextColor` has been removed | ||
- Type definitions rewritten (#305) | ||
##### Chore | ||
- Remove deprecated ColorPropType | ||
--- | ||
### 6.6.0 | ||
##### New | ||
- Updated touchables to all be all TouchableOpacity (with override props available) | ||
- Done text now animates on depress like native select dialog (#215) | ||
--- | ||
### 6.5.1 | ||
##### Bugfix | ||
- Update iOS colors (#281) | ||
--- | ||
### 6.5.0 | ||
##### New | ||
- If an item has the `displayValue` property set to true, the TextInput shows the item `value` instead of the item `label` (#279) | ||
--- | ||
### 6.4.0 | ||
##### New | ||
- Opened up `onOpen` prop to now support Android when in headless or `useNativeAndroidPickerStyle={false}` mode | ||
--- | ||
### 6.3.4 | ||
##### Bugfix | ||
- Fix for `onDonePress` regression (#236) | ||
- "Done" Text element now set to `allowFontScaling={false}` (#247) | ||
- Fix for `onValueChange` event triggering a re-render on Android (#112) | ||
- Fix for `onDonePress` regression (#236) | ||
@@ -15,0 +55,0 @@ --- |
@@ -1,2 +0,9 @@ | ||
import { ViewStyle, TextStyle, ModalProps, TextInputProperties, PickerProps } from 'react-native'; | ||
import { | ||
ModalProps, | ||
PickerProps, | ||
TextInputProps, | ||
TextStyle, | ||
TouchableOpacityProps, | ||
ViewStyle, | ||
} from 'react-native'; | ||
import React from 'react'; | ||
@@ -9,3 +16,5 @@ | ||
color?: string; | ||
displayValue?: boolean; | ||
} | ||
export interface PickerStyle { | ||
@@ -18,2 +27,3 @@ chevron?: ViewStyle; | ||
done?: TextStyle; | ||
doneDepressed?: TextStyle; | ||
headlessAndroidContainer?: ViewStyle; | ||
@@ -33,14 +43,18 @@ headlessAndroidPicker?: ViewStyle; | ||
// Omit props needed by the library | ||
type PickerModalProps = Omit< | ||
ModalProps, | ||
| 'testID' | ||
| 'visible' | ||
| 'transparent' | ||
| 'animationType' | ||
| 'supportedOrientations' | ||
| 'onDismiss' | ||
| 'onOrientationChange' | ||
>; | ||
type CustomModalProps = Omit<ModalProps, 'visible' | 'transparent' | 'animationType'>; | ||
// 'testID', 'supportedOrientations', and 'onOrientationChange' are also used, but can be overwritten safely | ||
type CustomTextInputProps = Omit<TextInputProps, 'style' | 'value' | 'ref' | 'editable'>; | ||
// 'testID' is also used, but can be overwritten safely | ||
type CustomPickerProps = Omit<PickerProps, 'onValueChange' | 'selectedValue'>; | ||
// 'style' and 'enabled' are also used, but only in headless or native Android mode | ||
// 'testID' is also used, but can be overwritten safely | ||
type CustomTouchableDoneProps = Omit<TouchableOpacityProps, 'onPress'>; | ||
// 'testID', 'onPressIn', 'onPressOut', and 'hitSlop' are also used, but can be overwritten safely | ||
type CustomTouchableWrapperProps = Omit<TouchableOpacityProps, 'onPress'>; | ||
// 'testID' and 'activeOpacity' are also used, but can be overwritten safely | ||
export interface PickerSelectProps { | ||
@@ -55,5 +69,4 @@ onValueChange: (value: any, index: number) => void; | ||
children?: React.ReactNode; | ||
placeholderTextColor?: string; // deprecated | ||
onOpen?: () => void; | ||
useNativeAndroidPickerStyle?: boolean; | ||
hideDoneBar?: boolean; // deprecated | ||
doneText?: string; | ||
@@ -63,7 +76,8 @@ onDonePress?: () => void; | ||
onDownArrow?: () => void; | ||
onOpen?: () => void; | ||
onClose?: () => void; | ||
modalProps?: PickerModalProps; | ||
textInputProps?: TextInputProperties; | ||
pickerProps?: PickerProps; | ||
modalProps?: CustomModalProps; | ||
textInputProps?: CustomTextInputProps; | ||
pickerProps?: CustomPickerProps; | ||
touchableDoneProps?: CustomTouchableDoneProps; | ||
touchableWrapperProps?: CustomTouchableWrapperProps; | ||
Icon?: React.ReactNode; | ||
@@ -70,0 +84,0 @@ InputAccessoryView?: React.ReactNode; |
{ | ||
"name": "react-native-picker-select", | ||
"version": "7.0.0-beta.0", | ||
"version": "7.0.0", | ||
"description": "A Picker component for React Native which emulates the native <select> interfaces for each platform", | ||
@@ -41,3 +41,3 @@ "license": "MIT", | ||
"pretty-quick": "^1.8.0", | ||
"prop-types": "^15.6.2", | ||
"prop-types": "^15.7.2", | ||
"react": "16.6.1", | ||
@@ -71,7 +71,4 @@ "react-dom": "^16.6.1", | ||
"enzyme-to-json/serializer" | ||
], | ||
"testPathIgnorePatterns": [ | ||
"<rootDir>/demo/" | ||
] | ||
} | ||
} |
@@ -10,8 +10,6 @@ # react-native-picker-select | ||
For iOS, by default we are wrapping an unstyled Text component. | ||
For iOS, by default we are wrapping an unstyled TextInput component. You can then pass down styles to customize it to your needs. | ||
For Android, by default we are using the native Picker component. If you prefer, you can set `useNativeAndroidPickerStyle` to false, which will also render an unstyled Text component. | ||
For Android, by default we are using the native Picker component. If you prefer, you can set `useNativeAndroidPickerStyle` to false, which will also render an unstyled TextInput component. You can then pass down styles to customize it to your needs. | ||
The Text component can receive styles to customize it to your needs - for example, you may want it to look like your other TextInput components. | ||
For either platform, you can alternatively pass down a child element of your choice that will be wrapped in a touchable area. | ||
@@ -48,2 +46,9 @@ | ||
### Versioning | ||
| Component | React | | ||
| --------- | ------- | | ||
| >= 3.0.0 | >= 16.3 | | ||
| < 3.0.0 | < 16.3 | | ||
### Props | ||
@@ -54,3 +59,3 @@ | ||
| `onValueChange` | Callback which returns `value, index` | **required**<br>function | | ||
| `items` | The items for the component to render<br> - Each item should be in the following format:<br>`{label: 'Orange', value: 'orange', key: 'orange', color: 'orange'}`<br>- The label and the value are required<br>- The key and color are optional<br>- The key will be set to the label if not included<br>- The value can be any data type | **required**<br>array | | ||
| `items` | The items for the component to render<br> - Each item should be in the following format:<br>`{label: 'Orange', value: 'orange', key: 'orange', color: 'orange', displayValue: true}`<br>- `label` and `value` are required<br>- `key`, `color`, and `displayValue` are optional<br>- `key` will be set to equal `label` if not included<br>- `value` can be any data type<br>- If `displayValue` is truthy, the TextInput will display the `value` instead of the `label` | **required**<br>array | | ||
| `placeholder` | - An override for the default placeholder object with a label of `Select an item...` and a value of `null`<br>- An empty object can be used if you'd like to disable the placeholder entirely | object | | ||
@@ -64,3 +69,5 @@ | `disabled` | Disables interaction with the component | boolean | | ||
| `textInputProps` | Additional props to pass to the TextInput (some props are used in core functionality so use this carefully). This is iOS only unless `useNativeAndroidPickerStyle={false}`. | object | | ||
| `useNativeAndroidPickerStyle`<br>_Android only_ | The component defaults to using the native Android Picker in its un-selected state. Setting this flag to `false` will mimic the default iOS presentation where a tappable TextInput is displayed.<br>_More details in [styling](#styling)_ | boolean | | ||
| `touchableWrapperProps` | Additional props to pass to the touchable wrapping the TextInput (some props are used in core functionality so use this carefully) | object | | ||
| `onOpen`<br> | Callback triggered right before the opening of the picker<br>_Not supported when `useNativeAndroidPickerStyle={true}`_ | function | | ||
| `useNativeAndroidPickerStyle`<br>_Android only_ | The component defaults to using the native Android Picker in its un-selected state. Setting this flag to `false` will mimic the default iOS presentation where a tappable TextInput is displayed.<br>_More details in [styling](#styling)_ | Component | | ||
| `InputAccessoryView`<br>_iOS only_ | Replace the InputAcessoryView section (bar with tabbing arrown and Done button) of the opened picker with your own custom component. Can also return `null` here to hide completely. While this bar is typical on `select` elements on the web, the [interface guidelines](https://developer.apple.com/ios/human-interface-guidelines/controls/pickers/) does not include it. View the [snack](https://snack.expo.io/@lfkwtz/react-native-picker-select) to see examples on how this can be customized. | boolean | | ||
@@ -70,4 +77,5 @@ | `doneText`<br>_iOS only_ | "Done" default text on the modal. Can be overwritten here | string | | ||
| `onDonePress`<br>_iOS only_ | Callback when the 'Done' button is pressed | function | | ||
| `onOpen / onClose`<br>_iOS only_ | Callback triggered right before the opening or closing of the picker | function | | ||
| `onClose`<br>_iOS only_ | Callback triggered right before the closing of the picker | function | | ||
| `modalProps`<br>_iOS only_ | Additional props to pass to the Modal (some props are used in core functionality so use this carefully) | object | | ||
| `touchableDoneProps`<br>_iOS only_ | Additional props to pass to the Done touchable (some props are used in core functionality so use this carefully) | object | | ||
@@ -96,12 +104,5 @@ ### Styling | ||
### Versioning | ||
| Component | React | | ||
| --------- | ------- | | ||
| >= 3.0.0 | >= 16.3 | | ||
| < 3.0.0 | < 16.3 | | ||
## Testing | ||
This component has been tested on React Native v0.51 - v0.60 | ||
This component has been tested on React Native v0.51 - v0.61 | ||
@@ -108,0 +109,0 @@ [![BrowserStack](https://i.imgur.com/cOdhMed.png)](https://www.browserstack.com/) |
136
src/index.js
import React, { PureComponent } from 'react'; | ||
import { | ||
ColorPropType, | ||
Keyboard, | ||
@@ -9,4 +8,4 @@ Modal, | ||
Text, | ||
TextInput, | ||
TouchableOpacity, | ||
TouchableWithoutFeedback, | ||
View, | ||
@@ -26,3 +25,4 @@ } from 'react-native'; | ||
key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | ||
color: ColorPropType, | ||
color: PropTypes.string, | ||
displayValue: PropTypes.bool, | ||
}) | ||
@@ -35,3 +35,3 @@ ).isRequired, | ||
key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | ||
color: ColorPropType, | ||
color: PropTypes.string, | ||
}), | ||
@@ -42,2 +42,3 @@ disabled: PropTypes.bool, | ||
children: PropTypes.any, // eslint-disable-line react/forbid-prop-types | ||
onOpen: PropTypes.func, | ||
useNativeAndroidPickerStyle: PropTypes.bool, | ||
@@ -50,3 +51,2 @@ | ||
onDownArrow: PropTypes.func, | ||
onOpen: PropTypes.func, | ||
onClose: PropTypes.func, | ||
@@ -63,2 +63,8 @@ | ||
// Touchable Done props (iOS only) | ||
touchableDoneProps: PropTypes.shape({}), | ||
// Touchable wrapper props | ||
touchableWrapperProps: PropTypes.shape({}), | ||
// Custom Icon | ||
@@ -90,2 +96,4 @@ Icon: PropTypes.func, | ||
pickerProps: {}, | ||
touchableDoneProps: {}, | ||
touchableWrapperProps: {}, | ||
Icon: null, | ||
@@ -167,2 +175,3 @@ InputAccessoryView: null, | ||
orientation: 'portrait', | ||
doneDepressed: false, | ||
}; | ||
@@ -174,2 +183,3 @@ | ||
this.onOrientationChange = this.onOrientationChange.bind(this); | ||
this.setInputRef = this.setInputRef.bind(this); | ||
this.togglePicker = this.togglePicker.bind(this); | ||
@@ -191,15 +201,12 @@ this.renderInputAccessoryView = this.renderInputAccessoryView.bind(this); | ||
onValueChange(val, idx) { | ||
const { onValueChange, value } = this.props; | ||
onValueChange(value, index) { | ||
const { onValueChange } = this.props; | ||
onValueChange(val, idx); | ||
onValueChange(value, index); | ||
// if value prop is not used, maintain selectedItem internally | ||
if (isEqual(value, undefined)) { | ||
this.setState((prevState) => { | ||
return { | ||
selectedItem: prevState.items[idx], | ||
}; | ||
}); | ||
} | ||
this.setState((prevState) => { | ||
return { | ||
selectedItem: prevState.items[index], | ||
}; | ||
}); | ||
} | ||
@@ -213,2 +220,6 @@ | ||
setInputRef(ref) { | ||
this.inputRef = ref; | ||
} | ||
getPlaceholderStyle() { | ||
@@ -293,6 +304,9 @@ const { placeholder, style } = this.props; | ||
onDownArrow, | ||
onDonePress, | ||
style, | ||
onDonePress, | ||
touchableDoneProps, | ||
} = this.props; | ||
const { doneDepressed } = this.state; | ||
if (InputAccessoryView) { | ||
@@ -339,15 +353,32 @@ return <InputAccessoryView testID="custom_input_accessory_view" />; | ||
</View> | ||
<TouchableWithoutFeedback | ||
<TouchableOpacity | ||
testID="done_button" | ||
onPress={() => { | ||
this.togglePicker(true, onDonePress); | ||
}} | ||
onPressIn={() => { | ||
this.setState({ doneDepressed: true }); | ||
}} | ||
onPressOut={() => { | ||
this.setState({ doneDepressed: false }); | ||
}} | ||
hitSlop={{ top: 4, right: 4, bottom: 4, left: 4 }} | ||
testID="done_button" | ||
{...touchableDoneProps} | ||
> | ||
<View testID="needed_for_touchable"> | ||
<Text allowFontScaling={false} style={[defaultStyles.done, style.done]}> | ||
<Text | ||
testID="done_text" | ||
allowFontScaling={false} | ||
style={[ | ||
defaultStyles.done, | ||
style.done, | ||
doneDepressed | ||
? [defaultStyles.doneDepressed, style.doneDepressed] | ||
: {}, | ||
]} | ||
> | ||
{doneText} | ||
</Text> | ||
</View> | ||
</TouchableWithoutFeedback> | ||
</TouchableOpacity> | ||
</View> | ||
@@ -391,3 +422,4 @@ ); | ||
<View pointerEvents="box-only" style={containerStyle}> | ||
<Text | ||
<TextInput | ||
testID="text_input" | ||
style={[ | ||
@@ -397,6 +429,7 @@ Platform.OS === 'ios' ? style.inputIOS : style.inputAndroid, | ||
]} | ||
value={selectedItem.displayValue ? selectedItem.value : selectedItem.label} | ||
ref={this.setInputRef} | ||
editable={false} | ||
{...textInputProps} | ||
> | ||
{selectedItem.label} | ||
</Text> | ||
/> | ||
{this.renderIcon()} | ||
@@ -408,3 +441,3 @@ </View> | ||
renderIOS() { | ||
const { style, modalProps, pickerProps } = this.props; | ||
const { style, modalProps, pickerProps, touchableWrapperProps } = this.props; | ||
const { animationType, orientation, selectedItem, showPicker } = this.state; | ||
@@ -414,10 +447,12 @@ | ||
<View style={[defaultStyles.viewContainer, style.viewContainer]}> | ||
<TouchableWithoutFeedback | ||
<TouchableOpacity | ||
testID="ios_touchable_wrapper" | ||
onPress={() => { | ||
this.togglePicker(true); | ||
}} | ||
testID="ios_touchable_wrapper" | ||
activeOpacity={1} | ||
{...touchableWrapperProps} | ||
> | ||
{this.renderTextInputOrChildren()} | ||
</TouchableWithoutFeedback> | ||
</TouchableOpacity> | ||
<Modal | ||
@@ -462,23 +497,30 @@ testID="ios_modal" | ||
renderAndroidHeadless() { | ||
const { disabled, Icon, style, pickerProps } = this.props; | ||
const { disabled, Icon, style, pickerProps, onOpen, touchableWrapperProps } = this.props; | ||
const { selectedItem } = this.state; | ||
return ( | ||
<View style={style.headlessAndroidContainer}> | ||
{this.renderTextInputOrChildren()} | ||
<Picker | ||
style={[ | ||
Icon ? { backgroundColor: 'transparent' } : {}, // to hide native icon | ||
defaultStyles.headlessAndroidPicker, | ||
style.headlessAndroidPicker, | ||
]} | ||
testID="android_picker_headless" | ||
enabled={!disabled} | ||
onValueChange={this.onValueChange} | ||
selectedValue={selectedItem.value} | ||
{...pickerProps} | ||
> | ||
{this.renderPickerItems()} | ||
</Picker> | ||
</View> | ||
<TouchableOpacity | ||
testID="android_touchable_wrapper" | ||
onPress={onOpen} | ||
activeOpacity={1} | ||
{...touchableWrapperProps} | ||
> | ||
<View style={style.headlessAndroidContainer}> | ||
{this.renderTextInputOrChildren()} | ||
<Picker | ||
style={[ | ||
Icon ? { backgroundColor: 'transparent' } : {}, // to hide native icon | ||
defaultStyles.headlessAndroidPicker, | ||
style.headlessAndroidPicker, | ||
]} | ||
testID="android_picker_headless" | ||
enabled={!disabled} | ||
onValueChange={this.onValueChange} | ||
selectedValue={selectedItem.value} | ||
{...pickerProps} | ||
> | ||
{this.renderPickerItems()} | ||
</Picker> | ||
</View> | ||
</TouchableOpacity> | ||
); | ||
@@ -485,0 +527,0 @@ } |
@@ -15,3 +15,3 @@ import { StyleSheet } from 'react-native'; | ||
modalViewMiddle: { | ||
height: 44, | ||
height: 45, | ||
flexDirection: 'row', | ||
@@ -21,5 +21,5 @@ justifyContent: 'space-between', | ||
paddingHorizontal: 10, | ||
backgroundColor: '#EFF1F2', | ||
borderTopWidth: 0.5, | ||
borderTopColor: '#919498', | ||
backgroundColor: '#f8f8f8', | ||
borderTopWidth: 1, | ||
borderTopColor: '#dedede', | ||
zIndex: 2, | ||
@@ -34,3 +34,3 @@ }, | ||
backgroundColor: 'transparent', | ||
borderColor: '#D0D4DB', | ||
borderColor: '#a1a1a1', | ||
borderTopWidth: 1.5, | ||
@@ -48,17 +48,20 @@ borderRightWidth: 1.5, | ||
chevronActive: { | ||
borderColor: '#007AFE', | ||
borderColor: '#007aff', | ||
}, | ||
done: { | ||
color: '#007AFE', | ||
fontWeight: 'bold', | ||
fontSize: 15, | ||
color: '#007aff', | ||
fontWeight: '600', | ||
fontSize: 17, | ||
paddingTop: 1, | ||
paddingRight: 2, | ||
paddingRight: 11, | ||
}, | ||
doneDepressed: { | ||
fontSize: 19, | ||
}, | ||
modalViewBottom: { | ||
justifyContent: 'center', | ||
backgroundColor: '#D0D4DB', | ||
backgroundColor: '#d0d4da', | ||
}, | ||
placeholder: { | ||
color: '#C7C7CD', | ||
color: '#c7c7cd', | ||
}, | ||
@@ -65,0 +68,0 @@ headlessAndroidPicker: { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
46884
630
1
108