import React, { useCallback, useEffect, useRef, useState } from 'react'; import type { TextInputProps as NativeTextInputProps, SectionList, } from 'react-native'; import { View } from 'react-native'; import { useKeyboard } from '../../../utils/helpers'; import BottomSheet from '../../BottomSheet'; import Box from '../../Box'; import type { TextInputProps } from '../../TextInput'; import TextInput from '../../TextInput'; import Footer from '../Footer'; import { getScrollParams, toFlatOptions, toSections } from '../helpers'; import { StyledSearchBar, StyledTouchableOpacity } from '../StyledSelect'; import type { SectionType, SelectOptionType, SelectProps } from '../types'; import OptionList from './OptionList'; import { isOptionSelected } from './utils'; export interface MultiSelectProps< V, T extends SelectOptionType = SelectOptionType > extends SelectProps { /** * Current selected value. */ value: V[]; /** * event handler for footer button. */ onConfirm: (value: V[]) => void; /** * Footer label. */ footerLabel: | string | (({ value, closeModal, }: { value: V[]; closeModal: () => void; }) => React.ReactNode); /** * Customise the selected value rendering. */ renderSelectedValue?: ( selectedValue: V[], inputProps: NativeTextInputProps ) => React.ReactNode; /** * Supported orientations for the MultiSelect modal, iOS only. */ supportedOrientations?: ('portrait' | 'landscape')[]; } // Add an internal prop type for TextInputComponent, not exported export interface InternalMultiSelectProps< V, T extends SelectOptionType = SelectOptionType > extends MultiSelectProps { TextInputComponent?: React.ComponentType; groupStyleEnabled?: boolean; } function MultiSelect>({ footerLabel, label, loading = false, inputProps, onConfirm, onDismiss, onEndReached, onQueryChange, options, renderOption, renderSelectedValue, query, error, editable = true, disabled = false, required, style, testID, value, supportedOrientations = ['portrait'], bottomSheetConfig = {}, groupStyleEnabled = false, ...rest }: InternalMultiSelectProps) { const { isKeyboardVisible, keyboardHeight } = useKeyboard(); const [open, setOpen] = useState(false); const [selectingValue, setSelectingValue] = useState(value); const sectionListRef = useRef>(null); const sections = toSections(options); const flatOptions = toFlatOptions(options); const displayedValue = flatOptions .filter((opt) => isOptionSelected(value, opt)) .map((opt) => opt.text) .join(', '); const rawValue = value.length > 0 ? value.join(', ') : ''; const { variant: bottomSheetVariant, header: bottomSheetHeader } = bottomSheetConfig; const TextInputComponent = rest.TextInputComponent || TextInput; const onPress = useCallback(() => { setOpen(true); }, []); let selectSuffix: TextInputProps['suffix']; if (editable && !disabled) { selectSuffix = open ? 'arrow-up' : 'arrow-down'; } useEffect(() => { setSelectingValue(value); }, [open, value]); return ( <> { // prevent users from focusing TextInput } 0 ? (props) => renderSelectedValue(value, props) : undefined } /> { onDismiss?.(); setOpen(false); }} header={bottomSheetHeader || label} style={{ paddingBottom: isKeyboardVisible ? keyboardHeight : 0, }} footer={ typeof footerLabel === 'string' ? (