import type { Dispatch, ForwardedRef, Reducer } from 'react'; import React, { forwardRef, useEffect, useReducer, useRef } from 'react'; import type { SectionListData, ViewStyle } from 'react-native'; import { StyleSheet, UIManager, View } from 'react-native'; import { Portal } from '@gorhom/portal'; import { COLORS, Portals } from '../../constants'; import { OptionsListContextProvider, SelectContextProvider } from '../../context'; import { isAndroid, mergeObjects } from '../../helpers'; import type { ActionType, CreateInitialStateType, State } from '../../state'; import { createInitialState, reducer } from '../../state'; import { themes } from '../../themes'; import type { OnPressOptionType, OptionsType, OptionType, SelectProps, SelectRef, SelectStyles, } from '../../types'; import { Backdrop } from '../backdrop'; import { OptionsList } from '../options-list'; import { SelectControl } from '../select-control'; import { useSelect } from './select.hooks'; if (isAndroid && UIManager.setLayoutAnimationEnabledExperimental) { UIManager.setLayoutAnimationEnabledExperimental(true); } const SelectComponent = (props: SelectProps, ref: ForwardedRef>) => { const { // Required options, // Basic animation = true, clearable = true, closeOptionsListOnSelect = true, defaultOption, disabled = false, hasBackdrop = true, hideArrow = false, multiple = false, separatedMultiple = false, widthThreshold, noOptionsText = 'No options', placeholderText = 'Select...', placeholderTextColor = COLORS.GRAY, pressableSelectedOption = true, scrollToSelectedOption = true, searchable = false, reinitializeOptions = false, searchPattern = (payload: string) => `(${payload})`, styles: customStyles, theme = 'none', // Callbacks onSelectChangeText, onSectionSelect, onSectionRemove, onSelect, onSelectOpened, onSelectClosed, onRemove, // Customized arrowContainerProps, arrowImageProps, backdropChildProps, backdropProps, clearOptionButtonProps, clearOptionImageProps, flatListProps, noOptionsProps, noOptionsTextProps, optionButtonProps, optionTextProps, selectContainerProps, selectInputProps, selectLeftIconImageProps, selectLeftIconsProps, selectRightIconsProps, selectTextProps, sectionHeaderButtonProps, sectionHeaderImageProps, sectionHeaderTextProps, sectionListProps, hideSelectedOptions = false, } = props; const [state, dispatch] = useReducer< Reducer, ActionType>, CreateInitialStateType >(reducer, { options, searchable, animation, defaultOption }, createInitialState); const { isOpened, selectedOption, optionsData, openedPosition, searchValue, searchedOptions, selectedOptionIndex, } = state; useEffect(() => { if (reinitializeOptions) { dispatch({ type: 'reinitializeOptions', payload: options }); } }, [options, reinitializeOptions]); const { aboveSelectControl } = openedPosition; const mainStyles: SelectStyles = mergeObjects(themes[theme], customStyles); const selectControlRef = useRef(null); const optionsListRef = useRef(null); const { setOptionsListPosition, onPressOption, onOutsidePress, onPressSelectControl, onPressSection, } = useSelect({ selectControlRef, optionsListRef, dispatch, onRemove, disabled, closeOptionsListOnSelect, searchable, multiple, onSelectOpened, onSelectClosed, ref, state, onSectionSelect, onSectionRemove, onSelect, }); return ( , placeholderText, placeholderTextColor, searchPattern, searchValue, onPressSelectControl, selectInputProps, onRemove: onRemove as | ((option: OptionType, optionIndex: number) => void) | undefined, dispatch: dispatch as Dispatch>, setOptionsListPosition, selectedOption, selectedOptionIndex, styles: mainStyles, clearOptionButtonProps, clearOptionImageProps, arrowContainerProps, arrowImageProps, selectRightIconsProps, selectLeftIconsProps, selectLeftIconImageProps, selectTextProps, selectContainerProps, onSelectChangeText, }} > {isOpened && ( <> {hasBackdrop && ( )} , scrollToSelectedOption, searchValue, onPressOption: onPressOption as OnPressOptionType, onPressSection, selectedOption, searchedOptions: searchedOptions as OptionsType, selectedOptionIndex, sectionListProps: sectionListProps as SectionListData< OptionsType >, styles: mainStyles, optionButtonProps, optionTextProps, noOptionsProps, noOptionsTextProps, sectionHeaderButtonProps, sectionHeaderImageProps, sectionHeaderTextProps, pressableSelectedOption, multiple, disabled, hideSelectedOptions, }} > )} ); }; type Styles = { relative: ViewStyle; }; const styles = StyleSheet.create({ relative: { position: 'relative', }, }); export const Select = forwardRef(SelectComponent) as ( props: SelectProps & { ref?: ForwardedRef> }, ) => ReturnType;