@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 20.7 kB
Source Map (JSON)
{"version":3,"file":"hooks.mjs","names":[],"sources":["../../../src/base-ui/Select/hooks.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ChangeEvent,\n type HTMLAttributes,\n type KeyboardEvent,\n type MutableRefObject,\n type Ref,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { useAppElement } from '@/ThemeProvider';\n\nimport {\n countVirtualItems,\n getOptionSearchText,\n isGroupOption,\n isValueEmpty,\n normalizeValueFor,\n splitBySeparators,\n} from './helpers';\nimport {\n type SelectOption,\n type SelectOptions,\n type SelectProps,\n type SelectRootChangeEventDetails,\n type SelectSize,\n} from './type';\n\ninterface UseSelectValueParams {\n defaultValue: SelectProps['defaultValue'];\n extraOptions: SelectOption<any>[];\n isMultiple: boolean;\n onChange: SelectProps['onChange'];\n onSelect: SelectProps['onSelect'];\n options: SelectOptions<any> | undefined;\n setExtraOptions: React.Dispatch<React.SetStateAction<SelectOption<any>[]>>;\n value: SelectProps['value'];\n}\n\nexport function useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n}: UseSelectValueParams) {\n const [uncontrolledValue, setUncontrolledValue] = useState<any>(() => {\n if (defaultValue !== undefined) return defaultValue;\n return isMultiple ? [] : null;\n });\n\n const normalizeValue = useMemo(() => normalizeValueFor(isMultiple), [isMultiple]);\n\n const mergedValue = value !== undefined ? value : uncontrolledValue;\n const normalizedValue = useMemo(() => normalizeValue(mergedValue), [mergedValue, normalizeValue]);\n\n const valueArray = useMemo(() => {\n if (isMultiple) return normalizedValue as any[];\n return isValueEmpty(normalizedValue) ? [] : [normalizedValue];\n }, [isMultiple, normalizedValue]);\n\n const { optionMap, resolvedOptions } = useMemo(() => {\n const baseOptions = options ?? [];\n const optionValueMap = new Map<any, SelectOption<any>>();\n\n const addOption = (item: SelectOption<any>) => {\n if (!optionValueMap.has(item.value)) {\n optionValueMap.set(item.value, item);\n }\n };\n\n baseOptions.forEach((item) => {\n if (isGroupOption(item)) {\n item.options.forEach(addOption);\n } else {\n addOption(item);\n }\n });\n\n const filteredExtraOptions = extraOptions.filter((item) => !optionValueMap.has(item.value));\n filteredExtraOptions.forEach(addOption);\n const mergedOptions: SelectOptions<any> = [...baseOptions, ...filteredExtraOptions];\n\n const missingValueOptions: SelectOption<any>[] = valueArray\n .filter((val) => !optionValueMap.has(val))\n .map((val) => ({ label: String(val), value: val }));\n missingValueOptions.forEach(addOption);\n\n return {\n optionMap: optionValueMap,\n resolvedOptions: missingValueOptions.length\n ? [...mergedOptions, ...missingValueOptions]\n : mergedOptions,\n };\n }, [extraOptions, options, valueArray]);\n\n const getOption = useCallback(\n (optionValue: any): SelectOption<any> => {\n const matched = optionMap.get(optionValue);\n if (matched) return matched;\n if (optionValue && typeof optionValue === 'object' && 'label' in optionValue) {\n return { label: (optionValue as any).label, value: optionValue };\n }\n return { label: String(optionValue), value: optionValue };\n },\n [optionMap],\n );\n\n const previousValueRef = useRef<any>(normalizedValue);\n useEffect(() => {\n previousValueRef.current = normalizedValue;\n }, [normalizedValue]);\n\n const handleValueChange = useCallback(\n (nextValue: any) => {\n const normalizedNextValue = normalizeValue(nextValue);\n const previousValue = previousValueRef.current;\n\n if (isMultiple) {\n const prevValues = Array.isArray(previousValue) ? previousValue : [];\n const nextValues = Array.isArray(normalizedNextValue) ? normalizedNextValue : [];\n const addedValues = nextValues.filter(\n (val) => !prevValues.some((prev) => Object.is(prev, val)),\n );\n addedValues.forEach((val) => onSelect?.(val, getOption(val)));\n\n if (value === undefined) setUncontrolledValue(nextValues);\n onChange?.(\n nextValues,\n nextValues.map((val) => getOption(val)),\n );\n } else {\n if (!isValueEmpty(normalizedNextValue) && !Object.is(previousValue, normalizedNextValue)) {\n onSelect?.(normalizedNextValue, getOption(normalizedNextValue));\n }\n if (value === undefined) setUncontrolledValue(normalizedNextValue);\n onChange?.(\n normalizedNextValue,\n isValueEmpty(normalizedNextValue) ? undefined : getOption(normalizedNextValue),\n );\n }\n\n previousValueRef.current = normalizedNextValue;\n },\n [getOption, isMultiple, normalizeValue, onChange, onSelect, value],\n );\n\n const appendTagValues = useCallback(\n (rawValues: string[]) => {\n const valuesToAdd = rawValues.map((val) => val.trim()).filter(Boolean);\n if (!valuesToAdd.length) return;\n\n const nextValues = [...valueArray];\n const newOptionValues = valuesToAdd.filter((val) => !optionMap.has(val));\n\n if (newOptionValues.length > 0) {\n setExtraOptions((prev) => {\n const existingValues = new Set(prev.map((item) => item.value));\n const merged = [...prev];\n newOptionValues.forEach((val) => {\n if (!existingValues.has(val)) {\n merged.push({ label: val, value: val });\n }\n });\n return merged;\n });\n }\n\n valuesToAdd.forEach((val) => {\n if (!nextValues.some((item) => Object.is(item, val))) {\n nextValues.push(val);\n }\n });\n\n if (nextValues.length !== valueArray.length) {\n handleValueChange(nextValues);\n }\n },\n [handleValueChange, optionMap, setExtraOptions, valueArray],\n );\n\n return {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n optionMap,\n resolvedOptions,\n valueArray,\n };\n}\n\ninterface UseSelectOpenParams {\n defaultOpen: boolean | undefined;\n onOpenChange: SelectProps['onOpenChange'];\n open: boolean | undefined;\n}\n\nexport function useSelectOpen({ defaultOpen, onOpenChange, open }: UseSelectOpenParams) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen));\n\n useEffect(() => {\n if (open !== undefined) setUncontrolledOpen(open);\n }, [open]);\n\n const mergedOpen = open ?? uncontrolledOpen;\n\n const handleOpenChange = useCallback(\n (nextOpen: boolean, eventDetails?: SelectRootChangeEventDetails) => {\n onOpenChange?.(nextOpen, eventDetails);\n if (open === undefined) setUncontrolledOpen(nextOpen);\n },\n [onOpenChange, open],\n );\n\n return { handleOpenChange, mergedOpen };\n}\n\ninterface UseSelectSearchParams {\n appendTagValues: (values: string[]) => void;\n handleOpenChange: (nextOpen: boolean) => void;\n mergedOpen: boolean;\n mode: SelectProps['mode'];\n resolvedOptions: SelectOptions;\n showSearch: boolean | undefined;\n tokenSeparators: string[] | undefined;\n}\n\nexport function useSelectSearch({\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n}: UseSelectSearchParams) {\n const [searchValue, setSearchValue] = useState('');\n const shouldShowSearch = Boolean(showSearch || mode === 'tags');\n\n useEffect(() => {\n if (!mergedOpen) setSearchValue('');\n }, [mergedOpen]);\n\n const handleSearchChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = event.target.value;\n if (mode === 'tags') {\n const parts = splitBySeparators(nextValue, tokenSeparators);\n if (parts.length > 1) {\n const pending = parts.pop() ?? '';\n appendTagValues(parts.filter(Boolean));\n setSearchValue(pending);\n return;\n }\n }\n setSearchValue(nextValue);\n },\n [appendTagValues, mode, tokenSeparators],\n );\n\n const handleSearchKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n\n if (event.key === 'Escape') {\n handleOpenChange(false);\n return;\n }\n if (mode !== 'tags') return;\n\n const isSeparator = tokenSeparators?.includes(event.key);\n if (event.key === 'Enter' || isSeparator) {\n event.preventDefault();\n event.stopPropagation();\n appendTagValues([searchValue]);\n setSearchValue('');\n }\n },\n [appendTagValues, handleOpenChange, mode, searchValue, tokenSeparators],\n );\n\n // Stop propagation in capture phase + on keyup to block base-ui Popup-level\n // `useTypeahead` (and any ancestor typeahead) from hijacking the search\n // input's first-letter focus behavior. Do not remove.\n const stopSearchPropagation = useCallback((event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n }, []);\n\n const filteredOptions = useMemo(() => {\n if (!shouldShowSearch || !searchValue.trim()) return resolvedOptions;\n const query = searchValue.trim().toLowerCase();\n\n return resolvedOptions\n .map((item) => {\n if (isGroupOption(item)) {\n const groupItems = item.options.filter((option) =>\n getOptionSearchText(option).toLowerCase().includes(query),\n );\n if (!groupItems.length) return null;\n return { ...item, options: groupItems };\n }\n return getOptionSearchText(item).toLowerCase().includes(query) ? item : null;\n })\n .filter(Boolean) as SelectOptions;\n }, [resolvedOptions, searchValue, shouldShowSearch]);\n\n return {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n };\n}\n\ninterface UseSelectVirtualParams {\n filteredOptions: SelectOptions;\n listItemHeight: number | undefined;\n size: SelectSize;\n valueArray: any[];\n virtual: boolean | undefined;\n}\n\nexport function useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n}: UseSelectVirtualParams) {\n const listRef = useRef<HTMLDivElement | null>(null);\n const pointerScrollRef = useRef(false);\n const pointerScrollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const renderVirtualItem = useCallback((props: HTMLAttributes<HTMLDivElement>) => {\n const { ref, ...rest } = props as HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>;\n };\n\n return (\n <div\n {...rest}\n ref={(node) => {\n if (node) {\n node.scrollIntoView = (...args) => {\n if (!pointerScrollRef.current) {\n HTMLElement.prototype.scrollIntoView.call(node, ...args);\n }\n };\n }\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref && 'current' in ref) {\n (ref as MutableRefObject<HTMLDivElement | null>).current = node;\n }\n }}\n />\n );\n }, []);\n\n const markPointerScroll = useCallback(() => {\n pointerScrollRef.current = true;\n if (pointerScrollTimeoutRef.current) {\n clearTimeout(pointerScrollTimeoutRef.current);\n }\n pointerScrollTimeoutRef.current = setTimeout(() => {\n pointerScrollRef.current = false;\n }, 120);\n }, []);\n\n const handleListScroll = useCallback(() => {\n if (!virtual || !pointerScrollRef.current) return;\n const listElement = listRef.current;\n const activeElement = document.activeElement;\n if (listElement && activeElement && listElement.contains(activeElement)) {\n listElement.focus({ preventScroll: true });\n }\n }, [virtual]);\n\n useEffect(() => {\n return () => {\n if (pointerScrollTimeoutRef.current) {\n clearTimeout(pointerScrollTimeoutRef.current);\n }\n };\n }, []);\n\n const virtualListStyle = useMemo(() => {\n if (!virtual) return undefined;\n const rowCount = countVirtualItems(filteredOptions);\n const maxVisibleRows = 6;\n const estimatedRowHeight =\n listItemHeight ?? (size === 'large' ? 40 : size === 'small' ? 28 : 32);\n const visibleRows = Math.min(Math.max(rowCount, 1), maxVisibleRows);\n const estimatedHeight = visibleRows * estimatedRowHeight + 8;\n\n return {\n height: `min(${estimatedHeight}px, var(--lobe-select-available-height, var(--available-height)))`,\n };\n }, [filteredOptions, listItemHeight, size, virtual]);\n\n const keepMountedIndices = useMemo(() => {\n if (!virtual || valueArray.length === 0) return undefined;\n const selectedSet = new Set(valueArray);\n const indices: number[] = [];\n let index = 0;\n\n filteredOptions.forEach((item) => {\n if (isGroupOption(item)) {\n if (item.options.some((option) => selectedSet.has(option.value))) {\n indices.push(index);\n }\n index += 1;\n return;\n }\n if (selectedSet.has(item.value)) indices.push(index);\n index += 1;\n });\n\n return indices.length ? indices : undefined;\n }, [filteredOptions, valueArray, virtual]);\n\n return {\n handleListScroll,\n keepMountedIndices,\n listRef,\n markPointerScroll,\n renderVirtualItem,\n virtualListStyle,\n };\n}\n\nexport function usePortalContainer() {\n const appElement = useAppElement();\n // `appElement` is the ThemeProvider wrapper div, which uses `display: contents`\n // so it has no layout box. `@base-ui/react/select` fails to mount its Popup\n // into a `display: contents` container in certain hosts (editor/chat inputs\n // with focus traps). Fall back to `document.body` in that case; keep the\n // original behavior when the wrapper has a real layout (older themes, SSR\n // snapshot, etc.).\n return useMemo(() => {\n if (typeof window === 'undefined') return appElement;\n if (!(appElement instanceof HTMLElement)) return undefined;\n const display = window.getComputedStyle(appElement).display;\n return display === 'contents' ? document.body : appElement;\n }, [appElement]);\n}\n"],"mappings":"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"}