import React, { useContext, useEffect, forwardRef, useCallback, useRef } from 'react'; import { View, Text } from 'react-native'; import isEqual from 'lodash-es/isEqual'; import LinearGradient from '../LinearGradient'; import WheelPicker from './WheelPicker'; import TouchableOpacity from '../TouchableOpacity'; import { useThemeFactory } from '../Theme'; import ConfigProviderContext from '../ConfigProvider/ConfigProviderContext'; import { useSetState } from '../hooks'; import { createStyle } from './style'; import type { PickerProps, PickerFieldNames, State } from './type'; import { isPlain, flateColumns, DataType, getDateType } from './utils'; const DEFAULT_PICKER_FIELD_NAMES: Required = { text: 'text', value: 'value', children: 'children', }; const Picker = forwardRef((props, ref) => { const { toolbarPosition = 'top', showToolbar = true, itemHeight = 44, visibleItemCount = 5, style, } = props; const { text: textKey, value: valueKey, children: childrenKey, } = Object.assign(DEFAULT_PICKER_FIELD_NAMES, props.columnsFieldNames); const { styles, theme } = useThemeFactory(createStyle); const { locale } = useContext(ConfigProviderContext); const dateType = useRef(DataType.SINGLE); const [state, updateState, stateRef] = useSetState({ values: [], options: [], indexs: [], columns: [], }); useEffect(() => { const { columns, value = [] } = props; dateType.current = getDateType(columns, childrenKey); const lastColumns = isPlain(columns) ? [columns] : columns; const lastValue = Array.isArray(value) ? value : [value]; const isColumesChanged = !isEqual(lastColumns, stateRef.current.columns); const isValueChanged = !isEqual(lastValue, stateRef.current.values); if (isColumesChanged || isValueChanged) { updateState(flateColumns(lastColumns, lastValue, valueKey, childrenKey)); } }, [props.columns, props.value]); const handleChange = useCallback( (index: number, columnIndex: number) => { const lastColumns = isPlain(props.columns) ? [props.columns] : props.columns; const { values, columns } = stateRef.current; const targetValue = columns[columnIndex][index][valueKey]; if (dateType.current === DataType.CASCADE) { values.splice(columnIndex, values.length - columnIndex, targetValue); } else { values[columnIndex] = targetValue; } const newState = flateColumns(lastColumns, values, valueKey, childrenKey); if (dateType.current === DataType.SINGLE) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore props.onChange?.(newState.values[0], newState.options[0], index); } else { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore props.onChange?.(newState.values, newState.options, index); } updateState(newState); }, [props.columns, valueKey, childrenKey, props.onChange] ); const handleConfirm = useCallback(() => { const { values, options } = stateRef.current; if (dateType.current === DataType.SINGLE) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore props.onConfirm?.(values[0], options[0]); } else { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore props.onConfirm?.(values, options); } }, [props.onConfirm]); const handleCacel = useCallback(() => { const { values, options } = stateRef.current; if (dateType.current === DataType.SINGLE) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore props.onCancel?.(values[0], options[0]); } else { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore props.onCancel?.(values, options); } }, [props.onCancel]); const renderToolbar = () => { if (showToolbar) { return ( {props.toolbar || ( <> {props.cancelButtonText || locale.cancel} {props.title && {props.title}} {props.confirmButtonText || locale.confirm} )} ); } return null; }; const renderColumns = () => { const wrapHeight = (visibleItemCount + 1) * itemHeight; const maskHeight = (wrapHeight - itemHeight) / 2; return ( {state.columns.map((item, index) => ( handleChange(idx, index)} /> ))} ); }; return ( {toolbarPosition === 'top' && renderToolbar()} {props.columnsTop} {renderColumns()} {props.columnsBottom} {toolbarPosition === 'bottom' && renderToolbar()} ); }); export default Picker;