@react-native-picker/picker
Version:
React Native Picker for iOS, Android, macOS, and Windows
169 lines (148 loc) • 4.6 kB
JavaScript
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* This is a controlled component version of RNCPickerMacOS
*
* @format
* @flow
*/
;
import * as React from 'react';
import {processColor, StyleSheet, View} from 'react-native';
import RNCPickerNativeComponent from './RNCPickerNativeComponent';
import type {SyntheticEvent} from 'react-native/Libraries/Types/CoreEventTypes';
import type {ColorValue} from 'react-native/Libraries/StyleSheet/StyleSheet';
import type {ProcessedColorValue} from 'react-native/Libraries/StyleSheet/processColor';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
ViewStyleProp,
TextStyleProp,
} from 'react-native/Libraries/StyleSheet/StyleSheet';
import type {Element, ElementRef, ChildrenArray} from 'react';
import type {HostComponent} from 'react-native/Libraries/Renderer/shims/ReactNativeTypes';
type PickerMacOSChangeEvent = SyntheticEvent<
$ReadOnly<{|
newValue: number | string,
newIndex: number,
|}>,
>;
type RNCPickerMacOSItemType = $ReadOnly<{|
label: ?Label,
value: ?(number | string),
textColor: ?ProcessedColorValue,
testID: ?string,
|}>;
type RNCPickerMacOSType = HostComponent<
$ReadOnly<{|
items: $ReadOnlyArray<RNCPickerMacOSItemType>,
onChange: (event: PickerMacOSChangeEvent) => void,
selectedIndex: number,
style?: ?TextStyleProp,
testID?: ?string,
|}>,
>;
type Label = Stringish | number;
type Props = $ReadOnly<{|
...ViewProps,
// $FlowFixMe
children: ChildrenArray<Element<typeof PickerMacOSItem>>,
itemStyle?: ?ViewStyleProp,
onChange?: ?(event: PickerMacOSChangeEvent) => mixed,
onValueChange?: ?(itemValue: string | number, itemIndex: number) => mixed,
selectedValue: ?(number | string),
|}>;
type State = {|
selectedIndex: number,
items: $ReadOnlyArray<RNCPickerMacOSItemType>,
|};
type ItemProps = $ReadOnly<{|
label: ?Label,
value?: ?(number | string),
color?: ?ColorValue,
testID: ?string,
|}>;
const PickerMacOSItem = (props: ItemProps): null => {
return null;
};
class PickerMacOS extends React.Component<Props, State> {
_picker: ?ElementRef<RNCPickerMacOSType> = null;
state: State = {
selectedIndex: 0,
items: [],
};
static Item: typeof PickerMacOSItem = PickerMacOSItem;
static getDerivedStateFromProps(props: Props): State {
let selectedIndex = 0;
const items = [];
React.Children.toArray<$FlowFixMe>(props.children).forEach(function (
child: $FlowFixMe,
index: number,
) {
if (child.props.value === props.selectedValue) {
selectedIndex = index;
}
items.push({
value: child.props.value,
label: child.props.label,
textColor: processColor(child.props.color),
testID: child.props.testID,
});
});
return {selectedIndex, items};
}
render(): React.Node {
return (
<View style={this.props.style}>
<RNCPickerNativeComponent
ref={(picker) => {
this._picker = picker;
}}
testID={this.props.testID}
style={[styles.pickerMacOS, this.props.itemStyle]}
// $FlowFixMe
items={this.state.items}
selectedIndex={this.state.selectedIndex}
onChange={this._onChange}
/>
</View>
);
}
_onChange = (event: $FlowFixMe) => {
if (this.props.onChange) {
this.props.onChange(event);
}
if (this.props.onValueChange) {
this.props.onValueChange(
event.nativeEvent.newValue,
event.nativeEvent.newIndex,
);
}
// The picker is a controlled component. This means we expect the
// on*Change handlers to be in charge of updating our
// `selectedValue` prop. That way they can also
// disallow/undo/mutate the selection of certain values. In other
// words, the embedder of this component should be the source of
// truth, not the native component.
if (
this._picker &&
this.state.selectedIndex !== event.nativeEvent.newIndex
) {
this._picker.setNativeProps({
selectedIndex: this.state.selectedIndex,
});
}
};
}
const styles = StyleSheet.create({
pickerMacOS: {
// The picker will conform to whatever width is given, but we do
// have to set the component's height explicitly on the
// surrounding view to ensure it gets rendered.
height: 24,
},
});
export default PickerMacOS;