@umodeapporg/ui 0.22.3 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -155,6 +155,7 @@ function ControlledSelect({
|
|
|
155
155
|
}, [isOpen]);
|
|
156
156
|
const handleSelect = useCallback(
|
|
157
157
|
(option, event) => {
|
|
158
|
+
if (disabled) return;
|
|
158
159
|
if (multiple) {
|
|
159
160
|
event.stopPropagation();
|
|
160
161
|
event.preventDefault();
|
|
@@ -178,9 +179,10 @@ function ControlledSelect({
|
|
|
178
179
|
setIsOpen(false);
|
|
179
180
|
}
|
|
180
181
|
},
|
|
181
|
-
[multiple, selected, onChangeHook, options, infiniteScroll]
|
|
182
|
+
[disabled, multiple, selected, onChangeHook, options, infiniteScroll]
|
|
182
183
|
);
|
|
183
184
|
const handleClearSelection = useCallback(() => {
|
|
185
|
+
if (disabled) return;
|
|
184
186
|
if (multiple) {
|
|
185
187
|
setSelected([]);
|
|
186
188
|
onChangeHook([]);
|
|
@@ -195,7 +197,7 @@ function ControlledSelect({
|
|
|
195
197
|
if (onClearSearch) {
|
|
196
198
|
onClearSearch();
|
|
197
199
|
}
|
|
198
|
-
}, [multiple, onChangeHook, onClearSearch, options, infiniteScroll]);
|
|
200
|
+
}, [disabled, multiple, onChangeHook, onClearSearch, options, infiniteScroll]);
|
|
199
201
|
const getDisplayLabel = useCallback(() => {
|
|
200
202
|
if (multiple) {
|
|
201
203
|
const selectedArray = selected;
|
|
@@ -592,7 +594,7 @@ function ControlledSelect({
|
|
|
592
594
|
className: classNames("bg-muted-active text-lg", { "px-4 py-1": isLateralPosition }),
|
|
593
595
|
labelClassName: isLateralPosition ? "text-sm" : void 0,
|
|
594
596
|
onClose: (event) => handleSelect(option.value, event),
|
|
595
|
-
canClose:
|
|
597
|
+
canClose: !disabled
|
|
596
598
|
},
|
|
597
599
|
option.value
|
|
598
600
|
)) });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ControlledSelect.js","sources":["../../../src/components/Form/ControlledSelect.tsx"],"sourcesContent":["import { ReactNode, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport classNames from 'classnames';\nimport { useTranslation } from 'react-i18next';\nimport InfiniteScroll from 'react-infinite-scroll-component';\nimport { FixedSizeList as List } from 'react-window';\n\nimport {\n ControlledMenuHandler,\n ControlledMenuItem,\n ControlledMenuList,\n ControlledMenuRoot,\n} from '@/components/UI/ControlledMenu';\nimport ControlledTooltip from '@/components/UI/ControlledTooltip';\nimport { capitalizeAllLetters, formatFilter } from '@/helpers/stringHelpers';\nimport { uiLogger } from '@/helpers/uiLogger';\n\nimport { IFilterOption } from '../../interfaces/IFilterOption';\nimport UnifiedSearchBar from '../Search/UnifiedSearchBar';\nimport OutlinedChip from '../UI/Chips/OutlinedChip';\nimport LoadingSpinner from '../UI/LoadingSpinner';\nimport { MaterialSymbol } from '../UI/MaterialSymbol';\nimport NoDataFound from '../UI/NoDataFound';\n\nimport ControlledCheckbox from './ControlledCheckbox';\nimport ControlledInput from './ControlledInput';\n\nimport '../../styles/virtualizedSelect.css';\n\n/**\n * Contract of `fetchMoreOptions`, the single loader of infinite-scroll selects.\n * `reset: true` means \"replace the list with page 1 of `search`\" (a new search, a cleared\n * search, or the restore to the unfiltered baseline). `reset: false` means \"append the NEXT\n * page of the same `search`\". The consumer owns the page counter and the accumulated\n * `options` prop; this component never accumulates results itself.\n */\nexport interface IControlledSelectFetchParams {\n search: string;\n reset: boolean;\n}\n\ntype TDataAttributes = { [key: `data-${string}`]: string | number | boolean | undefined };\n\n/**\n * Native and ARIA attributes forwarded to the combobox trigger: `id` (so a `<label htmlFor>`\n * names it), `aria-labelledby` / `aria-describedby` / `aria-invalid`, `data-*`, `onBlur`.\n * `name` is submitted through hidden inputs carrying the selected value(s), never the label.\n */\ntype TControlledSelectTriggerProps = Pick<\n React.InputHTMLAttributes<HTMLInputElement>,\n 'id' | 'name' | 'required' | 'onBlur' | 'onFocus' | 'autoFocus'\n> &\n React.AriaAttributes &\n TDataAttributes;\n\ntype TControlledSelectProps = TControlledSelectTriggerProps & {\n label?: string;\n // Mantém a label flutuante visível (encolhida na borda) mesmo com um valor selecionado.\n // Padrão: false — a label some ao selecionar, assumindo que há um rótulo externo acima.\n persistentLabel?: boolean;\n options: Array<IFilterOption>;\n selectedValue: string | Array<string>;\n error?: boolean;\n multiple?: boolean;\n searchable?: boolean;\n disabled?: boolean;\n clearable?: boolean;\n className?: string;\n listClassName?: string;\n onChangeHook: (selected: string | Array<string>) => void;\n infiniteScroll?: boolean;\n fetchMoreOptions?: (params: IControlledSelectFetchParams) => Promise<unknown>;\n hasMoreOptions?: boolean;\n loading?: boolean;\n onClearSearch?: () => void;\n onOpen?: () => void;\n selectedItemsPosition?: 'bottom' | 'top' | 'left' | 'right';\n // When false, the selected-items chips are not rendered beside the trigger;\n // only the count summary (\"N itens selecionados\") shows inside the trigger.\n showSelectedItems?: boolean;\n // Multi-select only: render the selected values as chips inside the trigger\n // field (with a \"+N\" overflow indicator and a tooltip listing all of them)\n // instead of the generic \"N itens selecionados\" count.\n inFieldChips?: boolean;\n // Por padrão as labels passam por capitalizeAllLetters (Primeira Maiúscula, resto\n // minúsculo). Use true quando a label é um identificador literal — nome de tabela,\n // coluna, chave — em que o caixa original é significativo e não pode ser alterado.\n preserveLabelCase?: boolean;\n // Shape of the option swatch. Colors read as the square chip the libraries use;\n // the dot stays the default for tags and categories.\n swatchShape?: 'dot' | 'square';\n // Accessible name of the trigger, for a field whose meaning comes from the\n // surrounding layout and therefore renders no visible label or placeholder.\n ariaLabel?: string;\n // Marks the combobox trigger as required for assistive tech (aria-required).\n ariaRequired?: boolean;\n // Classes for the trigger input itself, for a select embedded in a composed\n // control (a segmented field) that must drop its own border, fill or minimum\n // width. `className` styles the wrapper and cannot reach the input.\n inputClassName?: string;\n // The dropdown follows the width of the field by default, so the panel and the search\n // box in it are never narrower than the trigger they belong to. A trigger below\n // MIN_LIST_WIDTH_CLASS keeps the panel at that floor, because an option list the width\n // of a 72px picker is unreadable. Pass false for a trigger that is not the visual\n // field and must keep the fixed panel width.\n matchTriggerWidth?: boolean;\n compact?: boolean;\n};\n\n// Width of the panel when it is not following the trigger (`matchTriggerWidth={false}`),\n// and the width the node carries until the measured one is written onto it.\nconst FALLBACK_LIST_WIDTH_CLASS = 'w-80 max-w-[calc(100vw-1.5rem)]';\n// Floor of the panel, applied through `min-width` so it wins over the measured width:\n// a 72px pagination picker or a narrow table cell editor would otherwise open an option\n// list too cramped to read.\nconst MIN_LIST_WIDTH_CLASS = 'min-w-56';\n\nconst ITEM_HEIGHT = 40;\nconst MAX_LIST_HEIGHT = 300;\nconst OVERSCAN_COUNT = 10;\nconst SEARCH_DEBOUNCE_MS = 300;\n// How many selected chips fit inside the trigger before collapsing into \"+N\".\nconst MAX_IN_FIELD_CHIPS = 2;\n\n// Marks the search field so focus can be handed back to it without matching the\n// option checkboxes, which are inputs too.\nconst SEARCH_INPUT_MARKER_CLASS = 'controlled-select-search-input';\nconst TYPEAHEAD_RESET_MS = 500;\nconst FOCUS_RETRY_FRAMES = 6;\n\nconst isPrintableKey = (event: React.KeyboardEvent) =>\n event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;\n\n/* Padding wrapper. The click is stopped here so a press on the search field is never read\n as a press on an option by the list above it. */\nconst SelectSearchSlot: React.FC<{ children?: ReactNode }> = ({ children }) => (\n <div className=\"px-1 py-0.5\" onClick={(event) => event.stopPropagation()}>\n {children}\n </div>\n);\n\nexport function ControlledSelect({\n label,\n persistentLabel = false,\n options: optionsProp,\n selectedValue,\n error = false,\n multiple = false,\n disabled = false,\n searchable = true,\n clearable = true,\n className,\n listClassName,\n onChangeHook,\n onClearSearch,\n infiniteScroll = false,\n fetchMoreOptions,\n hasMoreOptions = false,\n loading = false,\n onOpen,\n selectedItemsPosition = 'bottom',\n showSelectedItems = true,\n inFieldChips = false,\n preserveLabelCase = false,\n swatchShape = 'dot',\n ariaLabel,\n ariaRequired,\n inputClassName,\n matchTriggerWidth = true,\n compact = false,\n id,\n name,\n required,\n onBlur,\n onFocus,\n autoFocus,\n ...triggerAttributes\n}: TControlledSelectProps) {\n const { t } = useTranslation('ui');\n const options = useMemo(() => (Array.isArray(optionsProp) ? optionsProp : []), [optionsProp]);\n const formatLabel = useCallback(\n (value?: string) => (preserveLabelCase ? (value ?? '') : capitalizeAllLetters(value)),\n [preserveLabelCase],\n );\n const normalizeSelected = useCallback(\n (value: string | Array<string>): string | Array<string> => {\n if (multiple) {\n if (typeof value === 'string') {\n return value === '' ? [] : [value];\n }\n if (Array.isArray(value)) {\n // Legacy multi values arrive as one comma-joined string. A legitimate single value\n // that happens to contain a comma is recognizable by matching a loaded option.\n if (value.length === 1 && value[0].includes(',') && !options.some((option) => option.value === value[0])) {\n return value[0]\n .split(',')\n .map((item) => item.trim())\n .filter((item) => item !== '');\n }\n return value;\n }\n return [];\n } else {\n return typeof value === 'string' ? value : '';\n }\n },\n [multiple, options],\n );\n\n const [selected, setSelected] = useState<string | Array<string>>(() => normalizeSelected(selectedValue));\n\n useEffect(() => {\n setSelected(normalizeSelected(selectedValue));\n }, [selectedValue, normalizeSelected]);\n\n const [filteredOptions, setFilteredOptions] = useState(options);\n const [isOpen, setIsOpen] = useState(false);\n const menuListRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const triggerInputRef = useRef<HTMLInputElement>(null);\n const virtualListRef = useRef<List>(null);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [focusRequest, setFocusRequest] = useState(0);\n const pendingFocusIndexRef = useRef<number | null>(null);\n const typeaheadRef = useRef({ buffer: '', timer: 0 });\n const [currentSearchText, setCurrentSearchText] = useState('');\n\n // Unique per instance: a fixed id would make InfiniteScroll attach its scroll listener to\n // the FIRST matching node in the document, which can be another select's list still\n // mounted while its close animation plays.\n const scrollableContainerId = useId();\n const scrollableContainerRef = useRef<HTMLDivElement>(null);\n const isLoadingMoreRef = useRef(false);\n\n // Re-sync the rendered list when the consumer's options change. In client-filtered mode an\n // active search survives the re-sync (same predicate as UnifiedSearchBar), otherwise a parent\n // re-render would wipe the filter while the term stays in the search box.\n useEffect(() => {\n if (!infiniteScroll && currentSearchText) {\n setFilteredOptions(\n options.filter((option) =>\n [option.label, option.secondaryLabel].some((field) => formatFilter(String(field ?? ''), currentSearchText)),\n ),\n );\n return;\n }\n setFilteredOptions(options);\n }, [options]);\n\n const requestPagedOptions = useCallback(\n async (params: IControlledSelectFetchParams) => {\n if (!fetchMoreOptions) return;\n try {\n await fetchMoreOptions(params);\n } catch (fetchError) {\n uiLogger.error('Failed to fetch select options', fetchError);\n }\n },\n [fetchMoreOptions],\n );\n\n const handleLoadMoreFromScroll = useCallback(async () => {\n if (!infiniteScroll || !hasMoreOptions || isLoadingMoreRef.current) return;\n isLoadingMoreRef.current = true;\n try {\n await requestPagedOptions({ search: currentSearchText, reset: false });\n } finally {\n isLoadingMoreRef.current = false;\n }\n }, [infiniteScroll, hasMoreOptions, requestPagedOptions, currentSearchText]);\n\n const handleServerSearch = useCallback(\n (searchText: string) => {\n setCurrentSearchText(searchText);\n if (!infiniteScroll) return;\n if (scrollableContainerRef.current) scrollableContainerRef.current.scrollTop = 0;\n void requestPagedOptions({ search: searchText, reset: true });\n },\n [infiniteScroll, requestPagedOptions],\n );\n\n // Closing with an active search would leave the consumer's list holding only the search\n // results, so the next open would show a filtered list with an empty search box. Restore\n // the unfiltered baseline as the menu closes.\n useEffect(() => {\n if (isOpen || !infiniteScroll || currentSearchText === '') return;\n setCurrentSearchText('');\n void requestPagedOptions({ search: '', reset: true });\n }, [isOpen]);\n\n const handleSelect = useCallback(\n (option: string, event: React.MouseEvent) => {\n if (multiple) {\n event.stopPropagation();\n event.preventDefault();\n\n const currentSelection = selected as Array<string>;\n if (currentSelection.includes(option)) {\n const newSelection = currentSelection.filter((item) => item !== option);\n setSelected(newSelection);\n onChangeHook(newSelection);\n } else {\n const newSelection = [...currentSelection, option];\n setSelected(newSelection);\n onChangeHook(newSelection);\n }\n } else {\n setSelected(option);\n onChangeHook(option);\n if (!infiniteScroll) {\n setCurrentSearchText('');\n setFilteredOptions(options);\n }\n setIsOpen(false);\n }\n },\n [multiple, selected, onChangeHook, options, infiniteScroll],\n );\n\n const handleClearSelection = useCallback(() => {\n if (multiple) {\n setSelected([]);\n onChangeHook([]);\n } else {\n setSelected('');\n onChangeHook('');\n }\n\n if (!infiniteScroll) {\n setCurrentSearchText('');\n setFilteredOptions(options);\n }\n\n if (onClearSearch) {\n onClearSearch();\n }\n }, [multiple, onChangeHook, onClearSearch, options, infiniteScroll]);\n\n const getDisplayLabel = useCallback(() => {\n if (multiple) {\n const selectedArray = selected as Array<string>;\n if (selectedArray.length === 0) {\n return '';\n } else if (selectedArray.length === 1) {\n const foundOption = options.find((item) => item.value === selectedArray[0]);\n\n return formatLabel(foundOption?.label || selectedArray[0]);\n } else {\n return `${selectedArray.length} itens selecionados`;\n }\n } else {\n const foundOption = options.find((item) => item.value === selected);\n\n return formatLabel(foundOption?.label || (selected as string) || label);\n }\n }, [multiple, selected, options, label, formatLabel]);\n\n const getOptionId = useCallback(\n (index: number) => `${scrollableContainerId}-option-${index}`,\n [scrollableContainerId],\n );\n\n const isOptionEnabled = useCallback(\n (index: number) => {\n const option = filteredOptions[index];\n return Boolean(option) && !option.disabled;\n },\n [filteredOptions],\n );\n\n /** Next enabled index from `start` walking by `step`, or -1. Never wraps (APG select-only). */\n const findEnabledIndex = useCallback(\n (start: number, step: 1 | -1) => {\n for (let index = start; index >= 0 && index < filteredOptions.length; index += step) {\n if (isOptionEnabled(index)) return index;\n }\n return -1;\n },\n [filteredOptions.length, isOptionEnabled],\n );\n\n const getSelectedIndex = useCallback(() => {\n const firstSelected = multiple ? (selected as Array<string>)[0] : (selected as string);\n const index = filteredOptions.findIndex((option) => option.value === firstSelected);\n return index >= 0 && isOptionEnabled(index) ? index : -1;\n }, [multiple, selected, filteredOptions, isOptionEnabled]);\n\n const focusOptionAt = useCallback((index: number) => {\n if (index < 0) return;\n setActiveIndex(index);\n pendingFocusIndexRef.current = index;\n setFocusRequest((request) => request + 1);\n }, []);\n\n const focusSearchInput = useCallback(() => {\n const searchInput = menuListRef.current?.querySelector<HTMLInputElement>(`.${SEARCH_INPUT_MARKER_CLASS}`);\n if (!searchInput) return false;\n searchInput.focus();\n return true;\n }, []);\n\n const findTypeaheadMatch = useCallback(\n (key: string, fromIndex: number) => {\n const state = typeaheadRef.current;\n window.clearTimeout(state.timer);\n state.buffer += key.toLowerCase();\n state.timer = window.setTimeout(() => {\n state.buffer = '';\n }, TYPEAHEAD_RESET_MS);\n\n // Repeating one letter cycles through the options that start with it.\n const isCycling = state.buffer.split('').every((char) => char === state.buffer[0]);\n const term = isCycling ? state.buffer[0] : state.buffer;\n const start = isCycling ? fromIndex + 1 : Math.max(fromIndex, 0);\n const total = filteredOptions.length;\n\n for (let offset = 0; offset < total; offset += 1) {\n const index = (start + offset) % total;\n const label = formatLabel(filteredOptions[index]?.label).toLowerCase();\n if (isOptionEnabled(index) && label.startsWith(term)) return index;\n }\n return -1;\n },\n [filteredOptions, formatLabel, isOptionEnabled],\n );\n\n type TOpenTarget = 'selected' | 'first' | 'last' | number;\n\n const openAndFocus = useCallback(\n (target: TOpenTarget) => {\n if (disabled) return;\n if (!isOpen) {\n setIsOpen(true);\n onOpen?.();\n }\n\n if (searchable && target === 'selected') {\n // With a search field the keyboard lands on it; ArrowDown then walks into the options.\n pendingFocusIndexRef.current = -1;\n setFocusRequest((request) => request + 1);\n return;\n }\n\n let index: number;\n if (typeof target === 'number') index = target;\n else if (target === 'first') index = findEnabledIndex(0, 1);\n else if (target === 'last') index = findEnabledIndex(filteredOptions.length - 1, -1);\n else index = getSelectedIndex() >= 0 ? getSelectedIndex() : findEnabledIndex(0, 1);\n focusOptionAt(index);\n },\n [disabled, isOpen, onOpen, searchable, findEnabledIndex, filteredOptions.length, getSelectedIndex, focusOptionAt],\n );\n\n // Moves DOM focus to the requested option once it is rendered: a virtualized row far from\n // the viewport only exists after react-window re-renders at the new scroll offset.\n useEffect(() => {\n const index = pendingFocusIndexRef.current;\n if (!isOpen || index === null) return undefined;\n\n if (index >= 0) virtualListRef.current?.scrollToItem(index);\n\n let attempts = 0;\n let frame = 0;\n const tryFocus = () => {\n if (index < 0) {\n if (focusSearchInput()) {\n pendingFocusIndexRef.current = null;\n return;\n }\n } else {\n const node = document.getElementById(getOptionId(index));\n if (node) {\n pendingFocusIndexRef.current = null;\n node.focus({ preventScroll: Boolean(virtualListRef.current) });\n if (!virtualListRef.current) node.scrollIntoView?.({ block: 'nearest' });\n return;\n }\n }\n attempts += 1;\n if (attempts < FOCUS_RETRY_FRAMES) frame = window.requestAnimationFrame(tryFocus);\n };\n\n tryFocus();\n return () => window.cancelAnimationFrame(frame);\n }, [isOpen, focusRequest]);\n\n // Closing hands focus back to the trigger when it was inside the list (a keyboard or pointer\n // selection, ESC) or was lost with it; a click elsewhere keeps the focus it moved.\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (isOpen) {\n wasOpenRef.current = true;\n return;\n }\n if (!wasOpenRef.current) return;\n wasOpenRef.current = false;\n setActiveIndex(-1);\n pendingFocusIndexRef.current = null;\n\n const active = document.activeElement;\n const focusWasInList = Boolean(active && menuListRef.current?.contains(active));\n if (focusWasInList || active === document.body || active === null) {\n triggerInputRef.current?.focus({ preventScroll: true });\n }\n }, [isOpen]);\n\n useEffect(() => {\n setActiveIndex(-1);\n }, [filteredOptions]);\n\n // A multi-select toggle re-renders the virtualized rows, which replaces the focused node:\n // put focus back on the same option so the keyboard user keeps their place.\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return;\n const active = document.activeElement;\n if (active === null || active === document.body) focusOptionAt(activeIndex);\n }, [selected]);\n\n useEffect(() => () => window.clearTimeout(typeaheadRef.current.timer), []);\n\n // The list is named like its trigger, including a trigger named only by `<label htmlFor>`.\n const listboxLabel =\n triggerAttributes['aria-label'] ??\n ariaLabel ??\n label ??\n (isOpen ? triggerInputRef.current?.labels?.[0]?.textContent?.trim() || undefined : undefined);\n\n const handleTriggerKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return;\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n case 'ArrowDown':\n event.preventDefault();\n openAndFocus(isOpen && event.key === 'ArrowDown' && activeIndex >= 0 ? activeIndex : 'selected');\n return;\n case 'ArrowUp':\n event.preventDefault();\n openAndFocus(getSelectedIndex() >= 0 ? getSelectedIndex() : 'last');\n return;\n case 'Home':\n event.preventDefault();\n openAndFocus('first');\n return;\n case 'End':\n event.preventDefault();\n openAndFocus('last');\n return;\n case 'Escape':\n if (!isOpen) return;\n // Marks it handled so an enclosing dialog does not close too.\n event.preventDefault();\n setIsOpen(false);\n return;\n case 'Tab':\n if (isOpen) setIsOpen(false);\n return;\n default:\n if (!isPrintableKey(event) || searchable) return;\n event.preventDefault();\n openAndFocus(findTypeaheadMatch(event.key, getSelectedIndex()));\n }\n };\n\n const handleListKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n const target = event.target as HTMLElement;\n const isOnSearch = target.classList.contains(SEARCH_INPUT_MARKER_CLASS);\n const optionNode = target.closest<HTMLElement>('[role=\"option\"]');\n const currentIndex = optionNode ? Number(optionNode.dataset.optionIndex ?? -1) : activeIndex;\n\n switch (event.key) {\n case 'ArrowDown': {\n event.preventDefault();\n const next = isOnSearch ? findEnabledIndex(0, 1) : findEnabledIndex(currentIndex + 1, 1);\n focusOptionAt(next);\n return;\n }\n case 'ArrowUp': {\n if (isOnSearch) return;\n event.preventDefault();\n const previous = findEnabledIndex(currentIndex - 1, -1);\n if (previous >= 0) focusOptionAt(previous);\n else if (searchable) focusSearchInput();\n return;\n }\n case 'Home':\n case 'End':\n if (isOnSearch) return;\n event.preventDefault();\n focusOptionAt(event.key === 'Home' ? findEnabledIndex(0, 1) : findEnabledIndex(filteredOptions.length - 1, -1));\n return;\n case 'Escape':\n event.preventDefault();\n setIsOpen(false);\n return;\n case 'Tab':\n event.preventDefault();\n setIsOpen(false);\n triggerInputRef.current?.focus({ preventScroll: true });\n return;\n default:\n if (isOnSearch || !isPrintableKey(event) || event.key === ' ') return;\n event.preventDefault();\n focusOptionAt(findTypeaheadMatch(event.key, currentIndex));\n }\n };\n\n const renderOptionItem = useCallback(\n (option: IFilterOption, index: number, style?: React.CSSProperties) => {\n const isSelected = multiple\n ? Array.isArray(selected) && selected.includes(option.value)\n : option.value === selected;\n\n // A disabled option explains itself on hover over the WHOLE row, not just the info icon.\n const isDisabledWithReason = Boolean(option.disabled && option.tooltip);\n\n const menuItem = (\n <ControlledMenuItem\n key={isDisabledWithReason ? undefined : option.value}\n disabled={option.disabled}\n onClick={(event: React.MouseEvent) => handleSelect(option.value, event)}\n role=\"option\"\n id={getOptionId(index)}\n tabIndex={-1}\n aria-selected={isSelected}\n aria-setsize={filteredOptions.length}\n aria-posinset={index + 1}\n data-option-index={index}\n className={classNames(\n 'relative flex items-center p-2 pl-3 text-foreground',\n 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring',\n {\n // The hover variant has to live inside the selected branch: the menu item's own\n // default hover would otherwise wipe the selected tint.\n 'bg-brand-soft font-medium text-brand-emphasis hover:!bg-brand-soft focus:!bg-brand-soft': isSelected,\n 'hover:!bg-muted': !isSelected,\n },\n )}\n style={{\n ...(isDisabledWithReason ? {} : style),\n height: ITEM_HEIGHT - 1,\n }}\n >\n {isSelected && <span className=\"absolute inset-y-1 left-0 w-0.5 rounded-full bg-brand\" />}\n {multiple && (\n // The option itself carries aria-selected; the checkbox is only its picture.\n <span aria-hidden className=\"pointer-events-none\">\n <ControlledCheckbox checked={isSelected} onChange={() => {}} />\n </span>\n )}\n {option.tooltip && !isDisabledWithReason && (\n <ControlledTooltip content={option.tooltip} className=\"w-full max-w-72\">\n <MaterialSymbol icon=\"info\" size={15} color=\"rgb(var(--color-foreground-subtle))\" className=\"mr-1\" />\n </ControlledTooltip>\n )}\n {option.swatch && (\n <span\n className={classNames(\n 'mr-2 size-3.5 shrink-0 border border-border',\n swatchShape === 'square' ? 'rounded' : 'rounded-full',\n )}\n style={{ backgroundColor: option.swatch }}\n />\n )}\n <span className=\"truncate text-sm\">{formatLabel(option.label)}</span>\n {option.secondaryLabel && option.emphasizeSecondaryLabel && (\n <OutlinedChip\n label={option.secondaryLabel}\n tone=\"purple\"\n variant=\"soft\"\n size=\"xs\"\n preserveLabelCase\n truncate\n className=\"ml-auto max-w-[45%] shrink-0\"\n />\n )}\n {option.secondaryLabel && !option.emphasizeSecondaryLabel && (\n <span className=\"ml-auto max-w-[45%] shrink-0 truncate pl-3 text-xs text-foreground-faint\">\n {option.secondaryLabel}\n </span>\n )}\n </ControlledMenuItem>\n );\n\n // The wrapper div carries the virtualized position because the tooltip clones its child and\n // injects its own ref.\n return isDisabledWithReason ? (\n <ControlledTooltip key={option.value} content={option.tooltip} className=\"z-[9999] max-w-72\">\n <div style={style}>{menuItem}</div>\n </ControlledTooltip>\n ) : (\n menuItem\n );\n },\n [multiple, selected, handleSelect, formatLabel, getOptionId, filteredOptions.length],\n );\n\n const ItemRenderer = useCallback(\n ({ index, style }: { index: number; style: React.CSSProperties }) => {\n const option = filteredOptions[index];\n if (!option) return null;\n\n return renderOptionItem(option, index, style);\n },\n [filteredOptions, renderOptionItem],\n );\n\n const listHeight = useMemo(\n () => Math.min(filteredOptions.length * ITEM_HEIGHT, MAX_LIST_HEIGHT),\n [filteredOptions.length],\n );\n\n const selectedSwatch = useMemo(\n () => (multiple ? undefined : options.find((option) => option.value === selected)?.swatch),\n [multiple, options, selected],\n );\n\n // Com uma opção selecionada, o próprio valor identifica o campo: a label flutuante\n // some (evita duplicar quando já há um rótulo externo acima do select).\n const selectedHasValue = multiple ? (selected as Array<string>).length > 0 : selected !== '';\n\n /**\n * Opção declarada com valor vazio (\"Todas\", \"Nenhum\", \"Sem recorte\"): é uma\n * escolha de verdade, não a ausência de escolha, então o campo precisa exibir\n * o rótulo dela em vez de ficar em branco.\n */\n const hasEmptyValueOption = useMemo(\n () => !multiple && options.some((option) => option.value === ''),\n [multiple, options],\n );\n\n // The dropdown is portaled, so a percentage width would resolve against the\n // page, and a runtime pixel value cannot become a Tailwind arbitrary class.\n // The measured width is written straight onto the node: the floating logic\n // overwrites the MenuList `style` prop with its own position, and React never\n // clears `width` because it is not part of that style object.\n // It runs as a layout effect because the panel also carries a fallback width class:\n // measuring after paint would show that width for one frame, mid enter animation.\n useLayoutEffect(() => {\n const menuList = menuListRef.current;\n const trigger = triggerRef.current;\n if (!matchTriggerWidth || !isOpen || !menuList || !trigger) return undefined;\n\n const applyTriggerWidth = () => {\n menuList.style.width = `${trigger.getBoundingClientRect().width}px`;\n };\n\n applyTriggerWidth();\n\n const resizeObserver = new ResizeObserver(applyTriggerWidth);\n resizeObserver.observe(trigger);\n\n return () => resizeObserver.disconnect();\n }, [matchTriggerWidth, isOpen]);\n\n // Moving the pointer inside the menu makes floating-ui's list navigation pull\n // focus off the search field (it focuses the hovered option, or the menu\n // container on pointer leave). Take focus back whenever the pointer caused it,\n // while leaving keyboard navigation into the options alone.\n useEffect(() => {\n const menuList = menuListRef.current;\n if (!isOpen || !searchable || !menuList) return undefined;\n\n let isKeyboardInteraction = false;\n let restoreFrame = 0;\n\n const markKeyboardInteraction = () => {\n isKeyboardInteraction = true;\n };\n\n const markPointerInteraction = () => {\n isKeyboardInteraction = false;\n };\n\n const restoreSearchFocus = (event: FocusEvent) => {\n const searchInput = menuList.querySelector<HTMLInputElement>(`.${SEARCH_INPUT_MARKER_CLASS}`);\n if (!searchInput || event.target !== searchInput || isKeyboardInteraction) return;\n\n const nextFocused = event.relatedTarget as Node | null;\n if (nextFocused && !menuList.contains(nextFocused)) return;\n\n // The steal happens as this event is dispatched, so reclaim on the next frame.\n restoreFrame = window.requestAnimationFrame(() => searchInput.focus({ preventScroll: true }));\n };\n\n menuList.addEventListener('keydown', markKeyboardInteraction, true);\n menuList.addEventListener('pointermove', markPointerInteraction, true);\n menuList.addEventListener('focusout', restoreSearchFocus);\n\n return () => {\n window.cancelAnimationFrame(restoreFrame);\n menuList.removeEventListener('keydown', markKeyboardInteraction, true);\n menuList.removeEventListener('pointermove', markPointerInteraction, true);\n menuList.removeEventListener('focusout', restoreSearchFocus);\n };\n }, [isOpen, searchable]);\n\n const handleClearSearch = useCallback(() => {\n setCurrentSearchText('');\n\n if (infiniteScroll) {\n if (scrollableContainerRef.current) scrollableContainerRef.current.scrollTop = 0;\n void requestPagedOptions({ search: '', reset: true });\n } else {\n setFilteredOptions(options);\n }\n\n if (onClearSearch) {\n onClearSearch();\n }\n }, [infiniteScroll, requestPagedOptions, onClearSearch, options]);\n\n const getSelectedOptionsLabels = useCallback(() => {\n if (!multiple || !selected || (selected as Array<string>).length === 0) {\n return [];\n }\n\n const selectedArray = selected as Array<string>;\n\n return selectedArray.map((value) => {\n const trimmedValue = value.trim();\n const foundOption = options.find((option) => option.value === trimmedValue);\n return {\n value: trimmedValue,\n label: foundOption?.label || trimmedValue,\n swatch: foundOption?.swatch,\n };\n });\n }, [multiple, selected, options]);\n\n const isLateralPosition = selectedItemsPosition === 'left' || selectedItemsPosition === 'right';\n\n const inFieldChipItems = inFieldChips ? getSelectedOptionsLabels() : [];\n const showInFieldChips = inFieldChips && multiple && inFieldChipItems.length > 0;\n const visibleInFieldChips = inFieldChipItems.slice(0, MAX_IN_FIELD_CHIPS);\n const inFieldOverflow = inFieldChipItems.length - visibleInFieldChips.length;\n const inFieldChipsTooltip = inFieldChipItems.map((option) => formatLabel(option.label)).join(', ');\n\n const selectedItemsChips = showSelectedItems && multiple && getSelectedOptionsLabels().length > 1 && (\n <div className=\"flex flex-wrap gap-1\">\n {getSelectedOptionsLabels().map((option) => (\n <OutlinedChip\n key={option.value}\n label={option.label}\n preserveLabelCase={preserveLabelCase}\n dot={Boolean(option.swatch)}\n dotColor={option.swatch}\n className={classNames('bg-muted-active text-lg', { 'px-4 py-1': isLateralPosition })}\n labelClassName={isLateralPosition ? 'text-sm' : undefined}\n onClose={(event: React.MouseEvent) => handleSelect(option.value, event)}\n canClose\n />\n ))}\n </div>\n );\n\n const showClear =\n clearable &&\n !disabled &&\n Boolean(selected) &&\n (multiple ? (selected as Array<string>).length > 0 : selected !== '');\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n return (\n <ControlledMenuRoot\n placement=\"bottom-start\"\n open={isOpen && !disabled}\n handler={(next) => {\n if (disabled) return;\n setIsOpen(next);\n if (next) onOpen?.();\n }}\n dismiss={{ itemPress: !multiple }}\n >\n <ControlledMenuHandler skipTriggerAria>\n <div\n className={classNames('flex', {\n 'flex-col gap-y-2': selectedItemsPosition === 'bottom' || selectedItemsPosition === 'top',\n 'flex-row items-start gap-x-2': selectedItemsPosition === 'left' || selectedItemsPosition === 'right',\n })}\n >\n {(selectedItemsPosition === 'top' || selectedItemsPosition === 'left') && selectedItemsChips}\n <div ref={triggerRef} className={classNames('relative', cursorClassName, className)}>\n {selectedSwatch && (\n <span\n className={classNames(\n 'pointer-events-none absolute left-3 top-1/2 z-10 size-3.5 -translate-y-1/2 border border-border',\n swatchShape === 'square' ? 'rounded' : 'rounded-full',\n )}\n style={{ backgroundColor: selectedSwatch }}\n />\n )}\n {showInFieldChips && (\n <ControlledTooltip content={inFieldChipsTooltip} className=\"max-w-72\">\n <div\n className={classNames(\n 'absolute inset-y-0 left-2.5 right-14 z-10 flex items-center gap-1 overflow-hidden',\n cursorClassName,\n )}\n >\n {visibleInFieldChips.map((option) => (\n <OutlinedChip\n key={option.value}\n label={option.label}\n preserveLabelCase={preserveLabelCase}\n dot={Boolean(option.swatch)}\n dotColor={option.swatch}\n className=\"min-w-0 shrink-0 bg-muted-active\"\n labelClassName=\"text-xxs\"\n />\n ))}\n {inFieldOverflow > 0 && (\n <OutlinedChip\n label={t('controlledSelect.moreItems', { count: inFieldOverflow })}\n className=\"min-w-0 shrink-0 bg-muted-active\"\n labelClassName=\"text-xxs\"\n />\n )}\n </div>\n </ControlledTooltip>\n )}\n <ControlledInput\n {...triggerAttributes}\n id={id}\n inputRef={triggerInputRef}\n onBlur={onBlur}\n onFocus={onFocus}\n autoFocus={autoFocus}\n readOnly\n role=\"combobox\"\n // eslint-disable-next-line i18n-check/no-literal-jsx-strings -- ARIA token, not user-facing text\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? scrollableContainerId : undefined}\n onKeyDown={handleTriggerKeyDown}\n className={classNames(\n 'controlled-select-input flex w-full min-w-0 justify-between truncate text-left',\n !compact && 'tablet:min-w-52',\n cursorClassName,\n selectedSwatch && '!pl-9',\n // O \"x\" é absoluto SOBRE o input: sem esta reserva o rótulo passa por baixo dele.\n showClear && '!pr-14',\n inputClassName,\n )}\n error={error}\n autoComplete=\"off\"\n rightSlot={<MaterialSymbol className={cursorClassName} icon=\"keyboard_arrow_down\" size={15} />}\n label={selectedHasValue && !persistentLabel ? undefined : label}\n aria-label={triggerAttributes['aria-label'] ?? ariaLabel ?? label}\n aria-required={ariaRequired || required ? true : triggerAttributes['aria-required']}\n value={showInFieldChips ? ' ' : selectedHasValue || hasEmptyValueOption ? getDisplayLabel() : ''}\n disabled={disabled}\n />\n\n {showClear && (\n <ControlledTooltip content={t('dates.clearSelection')}>\n <div\n onClick={handleClearSelection}\n className=\"absolute inset-y-0 right-8 top-0.5 flex cursor-pointer items-center\"\n >\n <MaterialSymbol icon=\"close_small\" size={20} color=\"rgb(var(--color-foreground-subtle))\" />\n </div>\n </ControlledTooltip>\n )}\n </div>\n\n {name &&\n (multiple\n ? (selected as Array<string>).map((value) => (\n <input key={value} type=\"hidden\" name={name} value={value} disabled={disabled} />\n ))\n : selected !== '' && <input type=\"hidden\" name={name} value={selected as string} disabled={disabled} />)}\n\n {(selectedItemsPosition === 'bottom' || selectedItemsPosition === 'right') && selectedItemsChips}\n </div>\n </ControlledMenuHandler>\n\n <ControlledMenuList\n ref={menuListRef}\n role=\"presentation\"\n onKeyDown={handleListKeyDown}\n className={classNames(\n 'zIndexMax overflow-hidden',\n FALLBACK_LIST_WIDTH_CLASS,\n MIN_LIST_WIDTH_CLASS,\n listClassName,\n )}\n >\n {searchable && (\n <SelectSearchSlot>\n <UnifiedSearchBar\n mode=\"default\"\n label={t('actions.search')}\n debounceTime={SEARCH_DEBOUNCE_MS}\n // Em modo infinito quem filtra é o servidor: sem itens, a barra só reporta o\n // termo via onSearchTermChange e nunca escreve na lista local.\n searchableItems={infiniteScroll ? null : options}\n searchKeys={['label', 'secondaryLabel']}\n setFilteredItems={setFilteredOptions}\n onSearchTermChange={handleServerSearch}\n className={classNames('w-full', SEARCH_INPUT_MARKER_CLASS)}\n onClearFilter={handleClearSearch}\n initialValue={currentSearchText}\n />\n </SelectSearchSlot>\n )}\n\n <div\n ref={scrollableContainerRef}\n className={classNames({\n 'max-h-[250px] overflow-y-auto overscroll-contain': infiniteScroll,\n 'overflow-hidden': !infiniteScroll,\n })}\n id={scrollableContainerId}\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n aria-labelledby={triggerAttributes['aria-labelledby']}\n aria-label={triggerAttributes['aria-labelledby'] ? undefined : listboxLabel}\n >\n {infiniteScroll ? (\n <InfiniteScroll\n dataLength={filteredOptions.length}\n // O loader do InfiniteScroll é renderizado sempre que `hasMore` é verdadeiro, ao lado\n // do conteúdo. Com a lista vazia isso empilhava o spinner sobre o estado vazio (ou\n // sobre o próprio spinner de `loading`): sem opções, quem manda é o bloco abaixo.\n hasMore={hasMoreOptions && filteredOptions.length > 0}\n next={handleLoadMoreFromScroll}\n loader={\n <div className=\"flex size-full items-center justify-center py-1\">\n <LoadingSpinner size={4} label={t('controlledSelect.loadingOptions')} />\n </div>\n }\n scrollableTarget={scrollableContainerId}\n // `overflow-hidden` makes this a scroll port the user cannot scroll, so\n // `overscroll-none` here stopped the wheel from ever reaching the container\n // that does scroll: the list only moved by dragging its bar. Containment\n // belongs to that container, which already declares `overscroll-contain`.\n className=\"!overflow-hidden\"\n >\n {filteredOptions.length > 0 ? (\n filteredOptions.map((option, index) => renderOptionItem(option, index))\n ) : loading ? (\n <div className=\"flex w-full items-center justify-center py-4\">\n <LoadingSpinner size={4} label={t('controlledSelect.loadingOptions')} />\n </div>\n ) : (\n <ControlledMenuItem disabled role=\"presentation\">\n <NoDataFound compact message={t('controlledSelect.noDataToShow')} />\n </ControlledMenuItem>\n )}\n </InfiniteScroll>\n ) : filteredOptions.length > 0 ? (\n <List\n ref={virtualListRef}\n className=\"virtualized-select-list\"\n height={listHeight}\n // eslint-disable-next-line i18n-check/no-literal-jsx-strings\n width=\"100%\"\n itemCount={filteredOptions.length}\n itemSize={ITEM_HEIGHT}\n overscanCount={OVERSCAN_COUNT}\n >\n {ItemRenderer}\n </List>\n ) : loading ? (\n <div className=\"flex w-full items-center justify-center py-4\">\n <LoadingSpinner size={4} label={t('controlledSelect.loadingOptions')} />\n </div>\n ) : (\n <ControlledMenuItem disabled role=\"presentation\">\n <NoDataFound compact message={t('controlledSelect.noDataToShow')} />\n </ControlledMenuItem>\n )}\n </div>\n </ControlledMenuList>\n </ControlledMenuRoot>\n );\n}\n"],"names":["label","List"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ControlledSelect.js","sources":["../../../src/components/Form/ControlledSelect.tsx"],"sourcesContent":["import { ReactNode, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport classNames from 'classnames';\nimport { useTranslation } from 'react-i18next';\nimport InfiniteScroll from 'react-infinite-scroll-component';\nimport { FixedSizeList as List } from 'react-window';\n\nimport {\n ControlledMenuHandler,\n ControlledMenuItem,\n ControlledMenuList,\n ControlledMenuRoot,\n} from '@/components/UI/ControlledMenu';\nimport ControlledTooltip from '@/components/UI/ControlledTooltip';\nimport { capitalizeAllLetters, formatFilter } from '@/helpers/stringHelpers';\nimport { uiLogger } from '@/helpers/uiLogger';\n\nimport { IFilterOption } from '../../interfaces/IFilterOption';\nimport UnifiedSearchBar from '../Search/UnifiedSearchBar';\nimport OutlinedChip from '../UI/Chips/OutlinedChip';\nimport LoadingSpinner from '../UI/LoadingSpinner';\nimport { MaterialSymbol } from '../UI/MaterialSymbol';\nimport NoDataFound from '../UI/NoDataFound';\n\nimport ControlledCheckbox from './ControlledCheckbox';\nimport ControlledInput from './ControlledInput';\n\nimport '../../styles/virtualizedSelect.css';\n\n/**\n * Contract of `fetchMoreOptions`, the single loader of infinite-scroll selects.\n * `reset: true` means \"replace the list with page 1 of `search`\" (a new search, a cleared\n * search, or the restore to the unfiltered baseline). `reset: false` means \"append the NEXT\n * page of the same `search`\". The consumer owns the page counter and the accumulated\n * `options` prop; this component never accumulates results itself.\n */\nexport interface IControlledSelectFetchParams {\n search: string;\n reset: boolean;\n}\n\ntype TDataAttributes = { [key: `data-${string}`]: string | number | boolean | undefined };\n\n/**\n * Native and ARIA attributes forwarded to the combobox trigger: `id` (so a `<label htmlFor>`\n * names it), `aria-labelledby` / `aria-describedby` / `aria-invalid`, `data-*`, `onBlur`.\n * `name` is submitted through hidden inputs carrying the selected value(s), never the label.\n */\ntype TControlledSelectTriggerProps = Pick<\n React.InputHTMLAttributes<HTMLInputElement>,\n 'id' | 'name' | 'required' | 'onBlur' | 'onFocus' | 'autoFocus'\n> &\n React.AriaAttributes &\n TDataAttributes;\n\ntype TControlledSelectProps = TControlledSelectTriggerProps & {\n label?: string;\n // Mantém a label flutuante visível (encolhida na borda) mesmo com um valor selecionado.\n // Padrão: false — a label some ao selecionar, assumindo que há um rótulo externo acima.\n persistentLabel?: boolean;\n options: Array<IFilterOption>;\n selectedValue: string | Array<string>;\n error?: boolean;\n multiple?: boolean;\n searchable?: boolean;\n disabled?: boolean;\n clearable?: boolean;\n className?: string;\n listClassName?: string;\n onChangeHook: (selected: string | Array<string>) => void;\n infiniteScroll?: boolean;\n fetchMoreOptions?: (params: IControlledSelectFetchParams) => Promise<unknown>;\n hasMoreOptions?: boolean;\n loading?: boolean;\n onClearSearch?: () => void;\n onOpen?: () => void;\n selectedItemsPosition?: 'bottom' | 'top' | 'left' | 'right';\n // When false, the selected-items chips are not rendered beside the trigger;\n // only the count summary (\"N itens selecionados\") shows inside the trigger.\n showSelectedItems?: boolean;\n // Multi-select only: render the selected values as chips inside the trigger\n // field (with a \"+N\" overflow indicator and a tooltip listing all of them)\n // instead of the generic \"N itens selecionados\" count.\n inFieldChips?: boolean;\n // Por padrão as labels passam por capitalizeAllLetters (Primeira Maiúscula, resto\n // minúsculo). Use true quando a label é um identificador literal — nome de tabela,\n // coluna, chave — em que o caixa original é significativo e não pode ser alterado.\n preserveLabelCase?: boolean;\n // Shape of the option swatch. Colors read as the square chip the libraries use;\n // the dot stays the default for tags and categories.\n swatchShape?: 'dot' | 'square';\n // Accessible name of the trigger, for a field whose meaning comes from the\n // surrounding layout and therefore renders no visible label or placeholder.\n ariaLabel?: string;\n // Marks the combobox trigger as required for assistive tech (aria-required).\n ariaRequired?: boolean;\n // Classes for the trigger input itself, for a select embedded in a composed\n // control (a segmented field) that must drop its own border, fill or minimum\n // width. `className` styles the wrapper and cannot reach the input.\n inputClassName?: string;\n // The dropdown follows the width of the field by default, so the panel and the search\n // box in it are never narrower than the trigger they belong to. A trigger below\n // MIN_LIST_WIDTH_CLASS keeps the panel at that floor, because an option list the width\n // of a 72px picker is unreadable. Pass false for a trigger that is not the visual\n // field and must keep the fixed panel width.\n matchTriggerWidth?: boolean;\n compact?: boolean;\n};\n\n// Width of the panel when it is not following the trigger (`matchTriggerWidth={false}`),\n// and the width the node carries until the measured one is written onto it.\nconst FALLBACK_LIST_WIDTH_CLASS = 'w-80 max-w-[calc(100vw-1.5rem)]';\n// Floor of the panel, applied through `min-width` so it wins over the measured width:\n// a 72px pagination picker or a narrow table cell editor would otherwise open an option\n// list too cramped to read.\nconst MIN_LIST_WIDTH_CLASS = 'min-w-56';\n\nconst ITEM_HEIGHT = 40;\nconst MAX_LIST_HEIGHT = 300;\nconst OVERSCAN_COUNT = 10;\nconst SEARCH_DEBOUNCE_MS = 300;\n// How many selected chips fit inside the trigger before collapsing into \"+N\".\nconst MAX_IN_FIELD_CHIPS = 2;\n\n// Marks the search field so focus can be handed back to it without matching the\n// option checkboxes, which are inputs too.\nconst SEARCH_INPUT_MARKER_CLASS = 'controlled-select-search-input';\nconst TYPEAHEAD_RESET_MS = 500;\nconst FOCUS_RETRY_FRAMES = 6;\n\nconst isPrintableKey = (event: React.KeyboardEvent) =>\n event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;\n\n/* Padding wrapper. The click is stopped here so a press on the search field is never read\n as a press on an option by the list above it. */\nconst SelectSearchSlot: React.FC<{ children?: ReactNode }> = ({ children }) => (\n <div className=\"px-1 py-0.5\" onClick={(event) => event.stopPropagation()}>\n {children}\n </div>\n);\n\nexport function ControlledSelect({\n label,\n persistentLabel = false,\n options: optionsProp,\n selectedValue,\n error = false,\n multiple = false,\n disabled = false,\n searchable = true,\n clearable = true,\n className,\n listClassName,\n onChangeHook,\n onClearSearch,\n infiniteScroll = false,\n fetchMoreOptions,\n hasMoreOptions = false,\n loading = false,\n onOpen,\n selectedItemsPosition = 'bottom',\n showSelectedItems = true,\n inFieldChips = false,\n preserveLabelCase = false,\n swatchShape = 'dot',\n ariaLabel,\n ariaRequired,\n inputClassName,\n matchTriggerWidth = true,\n compact = false,\n id,\n name,\n required,\n onBlur,\n onFocus,\n autoFocus,\n ...triggerAttributes\n}: TControlledSelectProps) {\n const { t } = useTranslation('ui');\n const options = useMemo(() => (Array.isArray(optionsProp) ? optionsProp : []), [optionsProp]);\n const formatLabel = useCallback(\n (value?: string) => (preserveLabelCase ? (value ?? '') : capitalizeAllLetters(value)),\n [preserveLabelCase],\n );\n const normalizeSelected = useCallback(\n (value: string | Array<string>): string | Array<string> => {\n if (multiple) {\n if (typeof value === 'string') {\n return value === '' ? [] : [value];\n }\n if (Array.isArray(value)) {\n // Legacy multi values arrive as one comma-joined string. A legitimate single value\n // that happens to contain a comma is recognizable by matching a loaded option.\n if (value.length === 1 && value[0].includes(',') && !options.some((option) => option.value === value[0])) {\n return value[0]\n .split(',')\n .map((item) => item.trim())\n .filter((item) => item !== '');\n }\n return value;\n }\n return [];\n } else {\n return typeof value === 'string' ? value : '';\n }\n },\n [multiple, options],\n );\n\n const [selected, setSelected] = useState<string | Array<string>>(() => normalizeSelected(selectedValue));\n\n useEffect(() => {\n setSelected(normalizeSelected(selectedValue));\n }, [selectedValue, normalizeSelected]);\n\n const [filteredOptions, setFilteredOptions] = useState(options);\n const [isOpen, setIsOpen] = useState(false);\n const menuListRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const triggerInputRef = useRef<HTMLInputElement>(null);\n const virtualListRef = useRef<List>(null);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [focusRequest, setFocusRequest] = useState(0);\n const pendingFocusIndexRef = useRef<number | null>(null);\n const typeaheadRef = useRef({ buffer: '', timer: 0 });\n const [currentSearchText, setCurrentSearchText] = useState('');\n\n // Unique per instance: a fixed id would make InfiniteScroll attach its scroll listener to\n // the FIRST matching node in the document, which can be another select's list still\n // mounted while its close animation plays.\n const scrollableContainerId = useId();\n const scrollableContainerRef = useRef<HTMLDivElement>(null);\n const isLoadingMoreRef = useRef(false);\n\n // Re-sync the rendered list when the consumer's options change. In client-filtered mode an\n // active search survives the re-sync (same predicate as UnifiedSearchBar), otherwise a parent\n // re-render would wipe the filter while the term stays in the search box.\n useEffect(() => {\n if (!infiniteScroll && currentSearchText) {\n setFilteredOptions(\n options.filter((option) =>\n [option.label, option.secondaryLabel].some((field) => formatFilter(String(field ?? ''), currentSearchText)),\n ),\n );\n return;\n }\n setFilteredOptions(options);\n }, [options]);\n\n const requestPagedOptions = useCallback(\n async (params: IControlledSelectFetchParams) => {\n if (!fetchMoreOptions) return;\n try {\n await fetchMoreOptions(params);\n } catch (fetchError) {\n uiLogger.error('Failed to fetch select options', fetchError);\n }\n },\n [fetchMoreOptions],\n );\n\n const handleLoadMoreFromScroll = useCallback(async () => {\n if (!infiniteScroll || !hasMoreOptions || isLoadingMoreRef.current) return;\n isLoadingMoreRef.current = true;\n try {\n await requestPagedOptions({ search: currentSearchText, reset: false });\n } finally {\n isLoadingMoreRef.current = false;\n }\n }, [infiniteScroll, hasMoreOptions, requestPagedOptions, currentSearchText]);\n\n const handleServerSearch = useCallback(\n (searchText: string) => {\n setCurrentSearchText(searchText);\n if (!infiniteScroll) return;\n if (scrollableContainerRef.current) scrollableContainerRef.current.scrollTop = 0;\n void requestPagedOptions({ search: searchText, reset: true });\n },\n [infiniteScroll, requestPagedOptions],\n );\n\n // Closing with an active search would leave the consumer's list holding only the search\n // results, so the next open would show a filtered list with an empty search box. Restore\n // the unfiltered baseline as the menu closes.\n useEffect(() => {\n if (isOpen || !infiniteScroll || currentSearchText === '') return;\n setCurrentSearchText('');\n void requestPagedOptions({ search: '', reset: true });\n }, [isOpen]);\n\n const handleSelect = useCallback(\n (option: string, event: React.MouseEvent) => {\n if (disabled) return;\n\n if (multiple) {\n event.stopPropagation();\n event.preventDefault();\n\n const currentSelection = selected as Array<string>;\n if (currentSelection.includes(option)) {\n const newSelection = currentSelection.filter((item) => item !== option);\n setSelected(newSelection);\n onChangeHook(newSelection);\n } else {\n const newSelection = [...currentSelection, option];\n setSelected(newSelection);\n onChangeHook(newSelection);\n }\n } else {\n setSelected(option);\n onChangeHook(option);\n if (!infiniteScroll) {\n setCurrentSearchText('');\n setFilteredOptions(options);\n }\n setIsOpen(false);\n }\n },\n [disabled, multiple, selected, onChangeHook, options, infiniteScroll],\n );\n\n const handleClearSelection = useCallback(() => {\n if (disabled) return;\n\n if (multiple) {\n setSelected([]);\n onChangeHook([]);\n } else {\n setSelected('');\n onChangeHook('');\n }\n\n if (!infiniteScroll) {\n setCurrentSearchText('');\n setFilteredOptions(options);\n }\n\n if (onClearSearch) {\n onClearSearch();\n }\n }, [disabled, multiple, onChangeHook, onClearSearch, options, infiniteScroll]);\n\n const getDisplayLabel = useCallback(() => {\n if (multiple) {\n const selectedArray = selected as Array<string>;\n if (selectedArray.length === 0) {\n return '';\n } else if (selectedArray.length === 1) {\n const foundOption = options.find((item) => item.value === selectedArray[0]);\n\n return formatLabel(foundOption?.label || selectedArray[0]);\n } else {\n return `${selectedArray.length} itens selecionados`;\n }\n } else {\n const foundOption = options.find((item) => item.value === selected);\n\n return formatLabel(foundOption?.label || (selected as string) || label);\n }\n }, [multiple, selected, options, label, formatLabel]);\n\n const getOptionId = useCallback(\n (index: number) => `${scrollableContainerId}-option-${index}`,\n [scrollableContainerId],\n );\n\n const isOptionEnabled = useCallback(\n (index: number) => {\n const option = filteredOptions[index];\n return Boolean(option) && !option.disabled;\n },\n [filteredOptions],\n );\n\n /** Next enabled index from `start` walking by `step`, or -1. Never wraps (APG select-only). */\n const findEnabledIndex = useCallback(\n (start: number, step: 1 | -1) => {\n for (let index = start; index >= 0 && index < filteredOptions.length; index += step) {\n if (isOptionEnabled(index)) return index;\n }\n return -1;\n },\n [filteredOptions.length, isOptionEnabled],\n );\n\n const getSelectedIndex = useCallback(() => {\n const firstSelected = multiple ? (selected as Array<string>)[0] : (selected as string);\n const index = filteredOptions.findIndex((option) => option.value === firstSelected);\n return index >= 0 && isOptionEnabled(index) ? index : -1;\n }, [multiple, selected, filteredOptions, isOptionEnabled]);\n\n const focusOptionAt = useCallback((index: number) => {\n if (index < 0) return;\n setActiveIndex(index);\n pendingFocusIndexRef.current = index;\n setFocusRequest((request) => request + 1);\n }, []);\n\n const focusSearchInput = useCallback(() => {\n const searchInput = menuListRef.current?.querySelector<HTMLInputElement>(`.${SEARCH_INPUT_MARKER_CLASS}`);\n if (!searchInput) return false;\n searchInput.focus();\n return true;\n }, []);\n\n const findTypeaheadMatch = useCallback(\n (key: string, fromIndex: number) => {\n const state = typeaheadRef.current;\n window.clearTimeout(state.timer);\n state.buffer += key.toLowerCase();\n state.timer = window.setTimeout(() => {\n state.buffer = '';\n }, TYPEAHEAD_RESET_MS);\n\n // Repeating one letter cycles through the options that start with it.\n const isCycling = state.buffer.split('').every((char) => char === state.buffer[0]);\n const term = isCycling ? state.buffer[0] : state.buffer;\n const start = isCycling ? fromIndex + 1 : Math.max(fromIndex, 0);\n const total = filteredOptions.length;\n\n for (let offset = 0; offset < total; offset += 1) {\n const index = (start + offset) % total;\n const label = formatLabel(filteredOptions[index]?.label).toLowerCase();\n if (isOptionEnabled(index) && label.startsWith(term)) return index;\n }\n return -1;\n },\n [filteredOptions, formatLabel, isOptionEnabled],\n );\n\n type TOpenTarget = 'selected' | 'first' | 'last' | number;\n\n const openAndFocus = useCallback(\n (target: TOpenTarget) => {\n if (disabled) return;\n if (!isOpen) {\n setIsOpen(true);\n onOpen?.();\n }\n\n if (searchable && target === 'selected') {\n // With a search field the keyboard lands on it; ArrowDown then walks into the options.\n pendingFocusIndexRef.current = -1;\n setFocusRequest((request) => request + 1);\n return;\n }\n\n let index: number;\n if (typeof target === 'number') index = target;\n else if (target === 'first') index = findEnabledIndex(0, 1);\n else if (target === 'last') index = findEnabledIndex(filteredOptions.length - 1, -1);\n else index = getSelectedIndex() >= 0 ? getSelectedIndex() : findEnabledIndex(0, 1);\n focusOptionAt(index);\n },\n [disabled, isOpen, onOpen, searchable, findEnabledIndex, filteredOptions.length, getSelectedIndex, focusOptionAt],\n );\n\n // Moves DOM focus to the requested option once it is rendered: a virtualized row far from\n // the viewport only exists after react-window re-renders at the new scroll offset.\n useEffect(() => {\n const index = pendingFocusIndexRef.current;\n if (!isOpen || index === null) return undefined;\n\n if (index >= 0) virtualListRef.current?.scrollToItem(index);\n\n let attempts = 0;\n let frame = 0;\n const tryFocus = () => {\n if (index < 0) {\n if (focusSearchInput()) {\n pendingFocusIndexRef.current = null;\n return;\n }\n } else {\n const node = document.getElementById(getOptionId(index));\n if (node) {\n pendingFocusIndexRef.current = null;\n node.focus({ preventScroll: Boolean(virtualListRef.current) });\n if (!virtualListRef.current) node.scrollIntoView?.({ block: 'nearest' });\n return;\n }\n }\n attempts += 1;\n if (attempts < FOCUS_RETRY_FRAMES) frame = window.requestAnimationFrame(tryFocus);\n };\n\n tryFocus();\n return () => window.cancelAnimationFrame(frame);\n }, [isOpen, focusRequest]);\n\n // Closing hands focus back to the trigger when it was inside the list (a keyboard or pointer\n // selection, ESC) or was lost with it; a click elsewhere keeps the focus it moved.\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (isOpen) {\n wasOpenRef.current = true;\n return;\n }\n if (!wasOpenRef.current) return;\n wasOpenRef.current = false;\n setActiveIndex(-1);\n pendingFocusIndexRef.current = null;\n\n const active = document.activeElement;\n const focusWasInList = Boolean(active && menuListRef.current?.contains(active));\n if (focusWasInList || active === document.body || active === null) {\n triggerInputRef.current?.focus({ preventScroll: true });\n }\n }, [isOpen]);\n\n useEffect(() => {\n setActiveIndex(-1);\n }, [filteredOptions]);\n\n // A multi-select toggle re-renders the virtualized rows, which replaces the focused node:\n // put focus back on the same option so the keyboard user keeps their place.\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return;\n const active = document.activeElement;\n if (active === null || active === document.body) focusOptionAt(activeIndex);\n }, [selected]);\n\n useEffect(() => () => window.clearTimeout(typeaheadRef.current.timer), []);\n\n // The list is named like its trigger, including a trigger named only by `<label htmlFor>`.\n const listboxLabel =\n triggerAttributes['aria-label'] ??\n ariaLabel ??\n label ??\n (isOpen ? triggerInputRef.current?.labels?.[0]?.textContent?.trim() || undefined : undefined);\n\n const handleTriggerKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return;\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n case 'ArrowDown':\n event.preventDefault();\n openAndFocus(isOpen && event.key === 'ArrowDown' && activeIndex >= 0 ? activeIndex : 'selected');\n return;\n case 'ArrowUp':\n event.preventDefault();\n openAndFocus(getSelectedIndex() >= 0 ? getSelectedIndex() : 'last');\n return;\n case 'Home':\n event.preventDefault();\n openAndFocus('first');\n return;\n case 'End':\n event.preventDefault();\n openAndFocus('last');\n return;\n case 'Escape':\n if (!isOpen) return;\n // Marks it handled so an enclosing dialog does not close too.\n event.preventDefault();\n setIsOpen(false);\n return;\n case 'Tab':\n if (isOpen) setIsOpen(false);\n return;\n default:\n if (!isPrintableKey(event) || searchable) return;\n event.preventDefault();\n openAndFocus(findTypeaheadMatch(event.key, getSelectedIndex()));\n }\n };\n\n const handleListKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n const target = event.target as HTMLElement;\n const isOnSearch = target.classList.contains(SEARCH_INPUT_MARKER_CLASS);\n const optionNode = target.closest<HTMLElement>('[role=\"option\"]');\n const currentIndex = optionNode ? Number(optionNode.dataset.optionIndex ?? -1) : activeIndex;\n\n switch (event.key) {\n case 'ArrowDown': {\n event.preventDefault();\n const next = isOnSearch ? findEnabledIndex(0, 1) : findEnabledIndex(currentIndex + 1, 1);\n focusOptionAt(next);\n return;\n }\n case 'ArrowUp': {\n if (isOnSearch) return;\n event.preventDefault();\n const previous = findEnabledIndex(currentIndex - 1, -1);\n if (previous >= 0) focusOptionAt(previous);\n else if (searchable) focusSearchInput();\n return;\n }\n case 'Home':\n case 'End':\n if (isOnSearch) return;\n event.preventDefault();\n focusOptionAt(event.key === 'Home' ? findEnabledIndex(0, 1) : findEnabledIndex(filteredOptions.length - 1, -1));\n return;\n case 'Escape':\n event.preventDefault();\n setIsOpen(false);\n return;\n case 'Tab':\n event.preventDefault();\n setIsOpen(false);\n triggerInputRef.current?.focus({ preventScroll: true });\n return;\n default:\n if (isOnSearch || !isPrintableKey(event) || event.key === ' ') return;\n event.preventDefault();\n focusOptionAt(findTypeaheadMatch(event.key, currentIndex));\n }\n };\n\n const renderOptionItem = useCallback(\n (option: IFilterOption, index: number, style?: React.CSSProperties) => {\n const isSelected = multiple\n ? Array.isArray(selected) && selected.includes(option.value)\n : option.value === selected;\n\n // A disabled option explains itself on hover over the WHOLE row, not just the info icon.\n const isDisabledWithReason = Boolean(option.disabled && option.tooltip);\n\n const menuItem = (\n <ControlledMenuItem\n key={isDisabledWithReason ? undefined : option.value}\n disabled={option.disabled}\n onClick={(event: React.MouseEvent) => handleSelect(option.value, event)}\n role=\"option\"\n id={getOptionId(index)}\n tabIndex={-1}\n aria-selected={isSelected}\n aria-setsize={filteredOptions.length}\n aria-posinset={index + 1}\n data-option-index={index}\n className={classNames(\n 'relative flex items-center p-2 pl-3 text-foreground',\n 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring',\n {\n // The hover variant has to live inside the selected branch: the menu item's own\n // default hover would otherwise wipe the selected tint.\n 'bg-brand-soft font-medium text-brand-emphasis hover:!bg-brand-soft focus:!bg-brand-soft': isSelected,\n 'hover:!bg-muted': !isSelected,\n },\n )}\n style={{\n ...(isDisabledWithReason ? {} : style),\n height: ITEM_HEIGHT - 1,\n }}\n >\n {isSelected && <span className=\"absolute inset-y-1 left-0 w-0.5 rounded-full bg-brand\" />}\n {multiple && (\n // The option itself carries aria-selected; the checkbox is only its picture.\n <span aria-hidden className=\"pointer-events-none\">\n <ControlledCheckbox checked={isSelected} onChange={() => {}} />\n </span>\n )}\n {option.tooltip && !isDisabledWithReason && (\n <ControlledTooltip content={option.tooltip} className=\"w-full max-w-72\">\n <MaterialSymbol icon=\"info\" size={15} color=\"rgb(var(--color-foreground-subtle))\" className=\"mr-1\" />\n </ControlledTooltip>\n )}\n {option.swatch && (\n <span\n className={classNames(\n 'mr-2 size-3.5 shrink-0 border border-border',\n swatchShape === 'square' ? 'rounded' : 'rounded-full',\n )}\n style={{ backgroundColor: option.swatch }}\n />\n )}\n <span className=\"truncate text-sm\">{formatLabel(option.label)}</span>\n {option.secondaryLabel && option.emphasizeSecondaryLabel && (\n <OutlinedChip\n label={option.secondaryLabel}\n tone=\"purple\"\n variant=\"soft\"\n size=\"xs\"\n preserveLabelCase\n truncate\n className=\"ml-auto max-w-[45%] shrink-0\"\n />\n )}\n {option.secondaryLabel && !option.emphasizeSecondaryLabel && (\n <span className=\"ml-auto max-w-[45%] shrink-0 truncate pl-3 text-xs text-foreground-faint\">\n {option.secondaryLabel}\n </span>\n )}\n </ControlledMenuItem>\n );\n\n // The wrapper div carries the virtualized position because the tooltip clones its child and\n // injects its own ref.\n return isDisabledWithReason ? (\n <ControlledTooltip key={option.value} content={option.tooltip} className=\"z-[9999] max-w-72\">\n <div style={style}>{menuItem}</div>\n </ControlledTooltip>\n ) : (\n menuItem\n );\n },\n [multiple, selected, handleSelect, formatLabel, getOptionId, filteredOptions.length],\n );\n\n const ItemRenderer = useCallback(\n ({ index, style }: { index: number; style: React.CSSProperties }) => {\n const option = filteredOptions[index];\n if (!option) return null;\n\n return renderOptionItem(option, index, style);\n },\n [filteredOptions, renderOptionItem],\n );\n\n const listHeight = useMemo(\n () => Math.min(filteredOptions.length * ITEM_HEIGHT, MAX_LIST_HEIGHT),\n [filteredOptions.length],\n );\n\n const selectedSwatch = useMemo(\n () => (multiple ? undefined : options.find((option) => option.value === selected)?.swatch),\n [multiple, options, selected],\n );\n\n // Com uma opção selecionada, o próprio valor identifica o campo: a label flutuante\n // some (evita duplicar quando já há um rótulo externo acima do select).\n const selectedHasValue = multiple ? (selected as Array<string>).length > 0 : selected !== '';\n\n /**\n * Opção declarada com valor vazio (\"Todas\", \"Nenhum\", \"Sem recorte\"): é uma\n * escolha de verdade, não a ausência de escolha, então o campo precisa exibir\n * o rótulo dela em vez de ficar em branco.\n */\n const hasEmptyValueOption = useMemo(\n () => !multiple && options.some((option) => option.value === ''),\n [multiple, options],\n );\n\n // The dropdown is portaled, so a percentage width would resolve against the\n // page, and a runtime pixel value cannot become a Tailwind arbitrary class.\n // The measured width is written straight onto the node: the floating logic\n // overwrites the MenuList `style` prop with its own position, and React never\n // clears `width` because it is not part of that style object.\n // It runs as a layout effect because the panel also carries a fallback width class:\n // measuring after paint would show that width for one frame, mid enter animation.\n useLayoutEffect(() => {\n const menuList = menuListRef.current;\n const trigger = triggerRef.current;\n if (!matchTriggerWidth || !isOpen || !menuList || !trigger) return undefined;\n\n const applyTriggerWidth = () => {\n menuList.style.width = `${trigger.getBoundingClientRect().width}px`;\n };\n\n applyTriggerWidth();\n\n const resizeObserver = new ResizeObserver(applyTriggerWidth);\n resizeObserver.observe(trigger);\n\n return () => resizeObserver.disconnect();\n }, [matchTriggerWidth, isOpen]);\n\n // Moving the pointer inside the menu makes floating-ui's list navigation pull\n // focus off the search field (it focuses the hovered option, or the menu\n // container on pointer leave). Take focus back whenever the pointer caused it,\n // while leaving keyboard navigation into the options alone.\n useEffect(() => {\n const menuList = menuListRef.current;\n if (!isOpen || !searchable || !menuList) return undefined;\n\n let isKeyboardInteraction = false;\n let restoreFrame = 0;\n\n const markKeyboardInteraction = () => {\n isKeyboardInteraction = true;\n };\n\n const markPointerInteraction = () => {\n isKeyboardInteraction = false;\n };\n\n const restoreSearchFocus = (event: FocusEvent) => {\n const searchInput = menuList.querySelector<HTMLInputElement>(`.${SEARCH_INPUT_MARKER_CLASS}`);\n if (!searchInput || event.target !== searchInput || isKeyboardInteraction) return;\n\n const nextFocused = event.relatedTarget as Node | null;\n if (nextFocused && !menuList.contains(nextFocused)) return;\n\n // The steal happens as this event is dispatched, so reclaim on the next frame.\n restoreFrame = window.requestAnimationFrame(() => searchInput.focus({ preventScroll: true }));\n };\n\n menuList.addEventListener('keydown', markKeyboardInteraction, true);\n menuList.addEventListener('pointermove', markPointerInteraction, true);\n menuList.addEventListener('focusout', restoreSearchFocus);\n\n return () => {\n window.cancelAnimationFrame(restoreFrame);\n menuList.removeEventListener('keydown', markKeyboardInteraction, true);\n menuList.removeEventListener('pointermove', markPointerInteraction, true);\n menuList.removeEventListener('focusout', restoreSearchFocus);\n };\n }, [isOpen, searchable]);\n\n const handleClearSearch = useCallback(() => {\n setCurrentSearchText('');\n\n if (infiniteScroll) {\n if (scrollableContainerRef.current) scrollableContainerRef.current.scrollTop = 0;\n void requestPagedOptions({ search: '', reset: true });\n } else {\n setFilteredOptions(options);\n }\n\n if (onClearSearch) {\n onClearSearch();\n }\n }, [infiniteScroll, requestPagedOptions, onClearSearch, options]);\n\n const getSelectedOptionsLabels = useCallback(() => {\n if (!multiple || !selected || (selected as Array<string>).length === 0) {\n return [];\n }\n\n const selectedArray = selected as Array<string>;\n\n return selectedArray.map((value) => {\n const trimmedValue = value.trim();\n const foundOption = options.find((option) => option.value === trimmedValue);\n return {\n value: trimmedValue,\n label: foundOption?.label || trimmedValue,\n swatch: foundOption?.swatch,\n };\n });\n }, [multiple, selected, options]);\n\n const isLateralPosition = selectedItemsPosition === 'left' || selectedItemsPosition === 'right';\n\n const inFieldChipItems = inFieldChips ? getSelectedOptionsLabels() : [];\n const showInFieldChips = inFieldChips && multiple && inFieldChipItems.length > 0;\n const visibleInFieldChips = inFieldChipItems.slice(0, MAX_IN_FIELD_CHIPS);\n const inFieldOverflow = inFieldChipItems.length - visibleInFieldChips.length;\n const inFieldChipsTooltip = inFieldChipItems.map((option) => formatLabel(option.label)).join(', ');\n\n const selectedItemsChips = showSelectedItems && multiple && getSelectedOptionsLabels().length > 1 && (\n <div className=\"flex flex-wrap gap-1\">\n {getSelectedOptionsLabels().map((option) => (\n <OutlinedChip\n key={option.value}\n label={option.label}\n preserveLabelCase={preserveLabelCase}\n dot={Boolean(option.swatch)}\n dotColor={option.swatch}\n className={classNames('bg-muted-active text-lg', { 'px-4 py-1': isLateralPosition })}\n labelClassName={isLateralPosition ? 'text-sm' : undefined}\n onClose={(event: React.MouseEvent) => handleSelect(option.value, event)}\n canClose={!disabled}\n />\n ))}\n </div>\n );\n\n const showClear =\n clearable &&\n !disabled &&\n Boolean(selected) &&\n (multiple ? (selected as Array<string>).length > 0 : selected !== '');\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n return (\n <ControlledMenuRoot\n placement=\"bottom-start\"\n open={isOpen && !disabled}\n handler={(next) => {\n if (disabled) return;\n setIsOpen(next);\n if (next) onOpen?.();\n }}\n dismiss={{ itemPress: !multiple }}\n >\n <ControlledMenuHandler skipTriggerAria>\n <div\n className={classNames('flex', {\n 'flex-col gap-y-2': selectedItemsPosition === 'bottom' || selectedItemsPosition === 'top',\n 'flex-row items-start gap-x-2': selectedItemsPosition === 'left' || selectedItemsPosition === 'right',\n })}\n >\n {(selectedItemsPosition === 'top' || selectedItemsPosition === 'left') && selectedItemsChips}\n <div ref={triggerRef} className={classNames('relative', cursorClassName, className)}>\n {selectedSwatch && (\n <span\n className={classNames(\n 'pointer-events-none absolute left-3 top-1/2 z-10 size-3.5 -translate-y-1/2 border border-border',\n swatchShape === 'square' ? 'rounded' : 'rounded-full',\n )}\n style={{ backgroundColor: selectedSwatch }}\n />\n )}\n {showInFieldChips && (\n <ControlledTooltip content={inFieldChipsTooltip} className=\"max-w-72\">\n <div\n className={classNames(\n 'absolute inset-y-0 left-2.5 right-14 z-10 flex items-center gap-1 overflow-hidden',\n cursorClassName,\n )}\n >\n {visibleInFieldChips.map((option) => (\n <OutlinedChip\n key={option.value}\n label={option.label}\n preserveLabelCase={preserveLabelCase}\n dot={Boolean(option.swatch)}\n dotColor={option.swatch}\n className=\"min-w-0 shrink-0 bg-muted-active\"\n labelClassName=\"text-xxs\"\n />\n ))}\n {inFieldOverflow > 0 && (\n <OutlinedChip\n label={t('controlledSelect.moreItems', { count: inFieldOverflow })}\n className=\"min-w-0 shrink-0 bg-muted-active\"\n labelClassName=\"text-xxs\"\n />\n )}\n </div>\n </ControlledTooltip>\n )}\n <ControlledInput\n {...triggerAttributes}\n id={id}\n inputRef={triggerInputRef}\n onBlur={onBlur}\n onFocus={onFocus}\n autoFocus={autoFocus}\n readOnly\n role=\"combobox\"\n // eslint-disable-next-line i18n-check/no-literal-jsx-strings -- ARIA token, not user-facing text\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? scrollableContainerId : undefined}\n onKeyDown={handleTriggerKeyDown}\n className={classNames(\n 'controlled-select-input flex w-full min-w-0 justify-between truncate text-left',\n !compact && 'tablet:min-w-52',\n cursorClassName,\n selectedSwatch && '!pl-9',\n // O \"x\" é absoluto SOBRE o input: sem esta reserva o rótulo passa por baixo dele.\n showClear && '!pr-14',\n inputClassName,\n )}\n error={error}\n autoComplete=\"off\"\n rightSlot={<MaterialSymbol className={cursorClassName} icon=\"keyboard_arrow_down\" size={15} />}\n label={selectedHasValue && !persistentLabel ? undefined : label}\n aria-label={triggerAttributes['aria-label'] ?? ariaLabel ?? label}\n aria-required={ariaRequired || required ? true : triggerAttributes['aria-required']}\n value={showInFieldChips ? ' ' : selectedHasValue || hasEmptyValueOption ? getDisplayLabel() : ''}\n disabled={disabled}\n />\n\n {showClear && (\n <ControlledTooltip content={t('dates.clearSelection')}>\n <div\n onClick={handleClearSelection}\n className=\"absolute inset-y-0 right-8 top-0.5 flex cursor-pointer items-center\"\n >\n <MaterialSymbol icon=\"close_small\" size={20} color=\"rgb(var(--color-foreground-subtle))\" />\n </div>\n </ControlledTooltip>\n )}\n </div>\n\n {name &&\n (multiple\n ? (selected as Array<string>).map((value) => (\n <input key={value} type=\"hidden\" name={name} value={value} disabled={disabled} />\n ))\n : selected !== '' && <input type=\"hidden\" name={name} value={selected as string} disabled={disabled} />)}\n\n {(selectedItemsPosition === 'bottom' || selectedItemsPosition === 'right') && selectedItemsChips}\n </div>\n </ControlledMenuHandler>\n\n <ControlledMenuList\n ref={menuListRef}\n role=\"presentation\"\n onKeyDown={handleListKeyDown}\n className={classNames(\n 'zIndexMax overflow-hidden',\n FALLBACK_LIST_WIDTH_CLASS,\n MIN_LIST_WIDTH_CLASS,\n listClassName,\n )}\n >\n {searchable && (\n <SelectSearchSlot>\n <UnifiedSearchBar\n mode=\"default\"\n label={t('actions.search')}\n debounceTime={SEARCH_DEBOUNCE_MS}\n // Em modo infinito quem filtra é o servidor: sem itens, a barra só reporta o\n // termo via onSearchTermChange e nunca escreve na lista local.\n searchableItems={infiniteScroll ? null : options}\n searchKeys={['label', 'secondaryLabel']}\n setFilteredItems={setFilteredOptions}\n onSearchTermChange={handleServerSearch}\n className={classNames('w-full', SEARCH_INPUT_MARKER_CLASS)}\n onClearFilter={handleClearSearch}\n initialValue={currentSearchText}\n />\n </SelectSearchSlot>\n )}\n\n <div\n ref={scrollableContainerRef}\n className={classNames({\n 'max-h-[250px] overflow-y-auto overscroll-contain': infiniteScroll,\n 'overflow-hidden': !infiniteScroll,\n })}\n id={scrollableContainerId}\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n aria-labelledby={triggerAttributes['aria-labelledby']}\n aria-label={triggerAttributes['aria-labelledby'] ? undefined : listboxLabel}\n >\n {infiniteScroll ? (\n <InfiniteScroll\n dataLength={filteredOptions.length}\n // O loader do InfiniteScroll é renderizado sempre que `hasMore` é verdadeiro, ao lado\n // do conteúdo. Com a lista vazia isso empilhava o spinner sobre o estado vazio (ou\n // sobre o próprio spinner de `loading`): sem opções, quem manda é o bloco abaixo.\n hasMore={hasMoreOptions && filteredOptions.length > 0}\n next={handleLoadMoreFromScroll}\n loader={\n <div className=\"flex size-full items-center justify-center py-1\">\n <LoadingSpinner size={4} label={t('controlledSelect.loadingOptions')} />\n </div>\n }\n scrollableTarget={scrollableContainerId}\n // `overflow-hidden` makes this a scroll port the user cannot scroll, so\n // `overscroll-none` here stopped the wheel from ever reaching the container\n // that does scroll: the list only moved by dragging its bar. Containment\n // belongs to that container, which already declares `overscroll-contain`.\n className=\"!overflow-hidden\"\n >\n {filteredOptions.length > 0 ? (\n filteredOptions.map((option, index) => renderOptionItem(option, index))\n ) : loading ? (\n <div className=\"flex w-full items-center justify-center py-4\">\n <LoadingSpinner size={4} label={t('controlledSelect.loadingOptions')} />\n </div>\n ) : (\n <ControlledMenuItem disabled role=\"presentation\">\n <NoDataFound compact message={t('controlledSelect.noDataToShow')} />\n </ControlledMenuItem>\n )}\n </InfiniteScroll>\n ) : filteredOptions.length > 0 ? (\n <List\n ref={virtualListRef}\n className=\"virtualized-select-list\"\n height={listHeight}\n // eslint-disable-next-line i18n-check/no-literal-jsx-strings\n width=\"100%\"\n itemCount={filteredOptions.length}\n itemSize={ITEM_HEIGHT}\n overscanCount={OVERSCAN_COUNT}\n >\n {ItemRenderer}\n </List>\n ) : loading ? (\n <div className=\"flex w-full items-center justify-center py-4\">\n <LoadingSpinner size={4} label={t('controlledSelect.loadingOptions')} />\n </div>\n ) : (\n <ControlledMenuItem disabled role=\"presentation\">\n <NoDataFound compact message={t('controlledSelect.noDataToShow')} />\n </ControlledMenuItem>\n )}\n </div>\n </ControlledMenuList>\n </ControlledMenuRoot>\n );\n}\n"],"names":["label","List"],"mappings":"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"}
|