Files
react-native/Libraries/Components/Picker/PickerIOS.ios.js
T
Tom Underhill dbe0d7d4b5 Add NativeColorType opaque type to normalizeColor() ahead of PlatformColor PR. (#28040)
Summary:
The [PlatformColor PR](https://github.com/facebook/react-native/pull/27908) is currently open to implement the [PlatformColor proposal](react-native-community/discussions-and-proposals#126).   When that PR was imported into Facebooks internal builds it was found that the change to the `processColor()` function to return an opaque type or `number` instead of just `number` breaks internal components.

This PR is a simplification of the PlatformColor PR only changing the return type of `processColor()` from `?number` to `?number | NativeColorType` where `NativeColorType` is just an empty but opaque type.   This will allow changes to be made to these internal components but with less risk than the larger PR.

## Changelog

[General] [Changed] - Add NativeColorType opaque type to normalizeColor() ahead of PlatformColor PR
Pull Request resolved: https://github.com/facebook/react-native/pull/28040

Test Plan: Flow checks, Jest test, iOS unit tests, iOS integration tests, and manual testing performed on RNTester for iOS and Android.

Differential Revision: D19860205

Pulled By: TheSavior

fbshipit-source-id: 799662c6621d3974158b375ccccfa136982c43b4
2020-02-19 19:33:27 -08:00

164 lines
4.3 KiB
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.
*
* @format
* @flow strict-local
*/
// This is a controlled component version of RCTPickerIOS.
'use strict';
const React = require('react');
const StyleSheet = require('../../StyleSheet/StyleSheet');
const View = require('../View/View');
const invariant = require('invariant');
const processColor = require('../../StyleSheet/processColor');
import RCTPickerNativeComponent, {
Commands as PickerCommands,
} from './RCTPickerNativeComponent';
import type {TextStyleProp} from '../../StyleSheet/StyleSheet';
import type {ColorValue} from '../../StyleSheet/StyleSheetTypes';
import type {SyntheticEvent} from '../../Types/CoreEventTypes';
import type {ViewProps} from '../View/ViewPropTypes';
type PickerIOSChangeEvent = SyntheticEvent<
$ReadOnly<{|
newValue: number | string,
newIndex: number,
|}>,
>;
type RCTPickerIOSItemType = $ReadOnly<{|
label: ?Label,
value: ?(number | string),
textColor: ?number,
|}>;
type Label = Stringish | number;
type Props = $ReadOnly<{|
...ViewProps,
children: React.ChildrenArray<React.Element<typeof PickerIOSItem>>,
itemStyle?: ?TextStyleProp,
onChange?: ?(event: PickerIOSChangeEvent) => mixed,
onValueChange?: ?(itemValue: string | number, itemIndex: number) => mixed,
selectedValue: ?(number | string),
accessibilityLabel?: ?string,
|}>;
type State = {|
selectedIndex: number,
items: $ReadOnlyArray<RCTPickerIOSItemType>,
|};
type ItemProps = $ReadOnly<{|
label: ?Label,
value?: ?(number | string),
color?: ?ColorValue,
|}>;
const PickerIOSItem = (props: ItemProps): null => {
return null;
};
class PickerIOS extends React.Component<Props, State> {
_picker: ?React.ElementRef<typeof RCTPickerNativeComponent> = null;
_lastNativeValue: ?number;
state: State = {
selectedIndex: 0,
items: [],
};
static Item: (props: ItemProps) => null = PickerIOSItem;
static getDerivedStateFromProps(props: Props): State {
let selectedIndex = 0;
const items = [];
React.Children.toArray(props.children)
.filter(child => child !== null)
.forEach(function(child, index) {
if (child.props.value === props.selectedValue) {
selectedIndex = index;
}
const processedTextColor = processColor(child.props.color);
invariant(
processedTextColor == null || typeof processedTextColor === 'number',
'Unexpected color given for PickerIOSItem color',
);
items.push({
value: child.props.value,
label: child.props.label,
textColor: processedTextColor,
});
});
return {selectedIndex, items};
}
render(): React.Node {
return (
<View style={this.props.style}>
<RCTPickerNativeComponent
ref={picker => {
this._picker = picker;
}}
testID={this.props.testID}
style={[styles.pickerIOS, this.props.itemStyle]}
items={this.state.items}
selectedIndex={this.state.selectedIndex}
onChange={this._onChange}
accessibilityLabel={this.props.accessibilityLabel}
/>
</View>
);
}
componentDidUpdate() {
// This is necessary in case native updates the picker and JS decides
// that the update should be ignored and we should stick with the value
// that we have in JS.
if (
this._picker &&
this._lastNativeValue !== undefined &&
this._lastNativeValue !== this.state.selectedIndex
) {
PickerCommands.setNativeSelectedIndex(
this._picker,
this.state.selectedIndex,
);
}
}
_onChange = event => {
if (this.props.onChange) {
this.props.onChange(event);
}
if (this.props.onValueChange) {
this.props.onValueChange(
event.nativeEvent.newValue,
event.nativeEvent.newIndex,
);
}
this._lastNativeValue = event.nativeEvent.newIndex;
this.forceUpdate();
};
}
const styles = StyleSheet.create({
pickerIOS: {
// 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: 216,
},
});
module.exports = PickerIOS;