import * as React from "react"; import { StyleSheet, Platform, Keyboard } from "react-native"; import { Picker as NativePickerComponent } from "@react-native-picker/picker"; import { useDeepCompareMemo } from "../../utilities"; import { CommonPickerProps, SinglePickerProps, normalizeToPickerOptions, } from "./PickerCommon"; import PickerInputContainer from "./PickerInputContainer"; import { withTheme } from "@draftbit/theme"; const isAndroid = Platform.OS === "android"; const isWeb = Platform.OS === "web"; const NativePicker: React.FC = ({ options: optionsProp = [], onValueChange, Icon, placeholder, value, autoDismissKeyboard = true, theme, disabled, ...rest }) => { const pickerRef = React.useRef>(null); const [pickerVisible, setPickerVisible] = React.useState(false); const options = useDeepCompareMemo(() => { const normalizedOptions = normalizeToPickerOptions(optionsProp); // Underlying Picker component defaults selection to first element when value is not provided (or undefined) // Placholder must be the 1st option in order to allow selection of the 'actual' 1st option if (placeholder) { return [{ label: placeholder, value: placeholder }, ...normalizedOptions]; } else { return normalizedOptions; } }, [placeholder, optionsProp]); // When no placeholder is provided then first item should be marked selected to reflect underlying Picker internal state if (!placeholder && options.length && !value && value !== options[0].value) { onValueChange?.(options[0].value); } const renderNativePicker = () => ( { if (newValue !== placeholder) { onValueChange?.(newValue); } else if (newValue === placeholder) { onValueChange?.(""); } }} style={styles.nativePicker} onBlur={() => setPickerVisible(false)} > {options.map((option) => ( ))} ); React.useEffect(() => { if (pickerVisible && pickerRef.current) { pickerRef?.current?.focus(); } }, [pickerVisible, pickerRef]); React.useEffect(() => { if (pickerVisible && autoDismissKeyboard) { Keyboard.dismiss(); } }, [pickerVisible, autoDismissKeyboard]); return ( setPickerVisible(!pickerVisible)} disabled={disabled} {...rest} > {/* Web version is collapsed by default, always show to allow direct expand */} {/* Android version needs to always be visible to allow .focus() call to launch the dialog */} {(pickerVisible || isAndroid || isWeb) && !disabled && renderNativePicker()} ); }; const styles = StyleSheet.create({ nativePicker: { position: "absolute", bottom: 0, left: 0, right: 0, flexDirection: "row", justifyContent: "center", width: "100%", backgroundColor: "white", opacity: 0, ...Platform.select({ web: { height: "100%", }, android: { opacity: 0, }, }), }, }); export default withTheme(NativePicker);