import React, { useState, useRef, useCallback, useMemo } from 'react'; import { View, Text, StyleSheet, FlatList, SectionList, SectionListData, } from 'react-native'; import { isNil, omit } from 'lodash'; import { FloatingLayer, ShouldRender, Button, Input, InputInstance, Loading, } from '@xrnjs/ui'; import CheckboxItem from './CheckboxItem'; import createStyles from './styles/FlatSelect.style'; import { SelectProps, Option, Group } from './interface'; import { Type } from './enum'; import { IconXSearchfor1 } from '../../icons'; import { useLocale } from '../Locale/locale'; import { FloatingLayerRef } from '../FloatingLayer/interface'; import { useMaxHeight } from '../../utils'; import ErrorBlock from '../ErrorBlock/errorBlock'; import { useTheme } from '../Theme'; import sectionListGetItemLayout from '../IndexBar/getItemLayout'; import RedirectItem from './RedirectItem'; import { addLabelPosition, doFilterOptions, doFilterGroupOptions, isGroup, countOptions, groupsToSections, groupsToCheckboxSections, } from './utils'; const SHOW_TIP_LIMIT = 10; const ROW_HEIGHT = 56; const HIGH_ROW_HEIGHT = 76; const SECTION_HEADER_HEIGHT = 38; const WINDOW_SIZE = 2; const INIT_RENDER_NUM = 12; const Select = ({ type, visible, options, defaultValue = '', title, showFooter = true, showConfirmButton = false, value, currencySelectProps, showSearch = false, searchInputProps = {}, cancelable = true, customFooter, contentStyle, itemFullContainer = false, showNoMoreTip = true, dataEmptyText, searchEmptyText, onPressOverlay, onConfirm, onCancel, onChange, onSearch, filterOption, onRepeatClick, showTipLimit = SHOW_TIP_LIMIT, loading, testID = '', onDisabledPress, extra, containerHeight, ...resetProps }: SelectProps) => { const locale = useLocale(); const [selectedValues, setSelectedValues] = useState< string | string[] | undefined >(value ?? defaultValue); const [searchValue, setSearchValue] = useState(''); const searchRef = useRef(null); const floatingLayerRef = useRef(null); const maxHeight = useMaxHeight(); const token = useTheme(); const styles = useMemo(() => createStyles(token), [token]); // 有搜索框时,loading默认高度为480,否则为200 const minHeight = showSearch ? 480 : 200; const filteredOptions = useMemo(() => { if (!searchValue || options?.length < 1) { return [...options]; } if (isGroup(options as Group[])) { return doFilterGroupOptions( options as Group[], searchValue, filterOption ); } return doFilterOptions(options as Option[], searchValue, filterOption); }, [options, searchValue, filterOption]); const nonGroupedCheckboxData = useMemo(() => { if (isGroup(filteredOptions as Group[])) return null; if (type !== Type.checkbox) return null; return addLabelPosition(filteredOptions as Option[], styles); }, [filteredOptions, type, styles]); const groupRedirectSections = useMemo(() => { if (!isGroup(filteredOptions as Group[])) return null; if (type !== Type.redirect) return null; return groupsToSections(filteredOptions as Group[]); }, [filteredOptions, type]); const groupCheckboxSections = useMemo(() => { if (!isGroup(filteredOptions as Group[])) return null; if (type !== Type.checkbox) return null; return groupsToCheckboxSections(filteredOptions as Group[], styles); }, [filteredOptions, type, styles]); const getRowHeight = useCallback( (item: Option) => { // 优先使用 Option.height if (typeof item?.height === 'number' && item.height > 0) { return item.height; } const hasHighContent = item?.subLabel || item?.prefixIcon; const baseHeight = hasHighContent ? HIGH_ROW_HEIGHT : ROW_HEIGHT; return baseHeight; }, [itemFullContainer] ); const sectionListLayoutRedirect = useMemo( () => sectionListGetItemLayout({ getItemHeight: (rowData) => getRowHeight(rowData as Option), getSeparatorHeight: () => 0, getSectionHeaderHeight: () => SECTION_HEADER_HEIGHT, getSectionFooterHeight: () => 0, listHeaderHeight: 0, }), [options, getRowHeight] ); const sectionListLayoutCheckbox = useMemo( () => sectionListGetItemLayout({ getItemHeight: (rowData) => getRowHeight(rowData as Option), getSeparatorHeight: () => 0, getSectionHeaderHeight: () => SECTION_HEADER_HEIGHT, getSectionFooterHeight: () => 0, listHeaderHeight: 0, }), [options, getRowHeight] ); const onChangeFn = useCallback( (values: string | string[]) => { if (type === Type.radio && !cancelable && isNil(values)) { onRepeatClick?.(); } else { setSelectedValues(values); onChange?.(values); } }, [type, cancelable, onRepeatClick, onChange] ); const keyExtractor = useCallback((item: Option) => item.value, []); const multiple = type === Type.checkbox; const currentVal = !isNil(value) ? value : selectedValues; const flatListGetItemLayout = useCallback( (data: ArrayLike