@umodeapporg/ui 0.27.0 → 0.29.0

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.
Files changed (153) hide show
  1. package/dist/assets/umode-ui.css +0 -5
  2. package/dist/components/DateTime/DatePicker.d.ts +2 -0
  3. package/dist/components/DateTime/DatePicker.js +5 -2
  4. package/dist/components/DateTime/DatePicker.js.map +1 -1
  5. package/dist/components/DateTime/DateRangePicker.d.ts +2 -0
  6. package/dist/components/DateTime/DateRangePicker.js +3 -0
  7. package/dist/components/DateTime/DateRangePicker.js.map +1 -1
  8. package/dist/components/Form/ControlledButton.d.ts +1 -1
  9. package/dist/components/Form/ControlledButton.js +2 -2
  10. package/dist/components/Form/ControlledButton.js.map +1 -1
  11. package/dist/components/Form/ControlledCheckbox.d.ts +5 -1
  12. package/dist/components/Form/ControlledCheckbox.js +53 -39
  13. package/dist/components/Form/ControlledCheckbox.js.map +1 -1
  14. package/dist/components/Form/ControlledDialogPrimitives.js +17 -5
  15. package/dist/components/Form/ControlledDialogPrimitives.js.map +1 -1
  16. package/dist/components/Form/ControlledDrawer.js +1 -0
  17. package/dist/components/Form/ControlledDrawer.js.map +1 -1
  18. package/dist/components/Form/ControlledImage/index.js +2 -0
  19. package/dist/components/Form/ControlledImage/index.js.map +1 -1
  20. package/dist/components/Form/ControlledInput.d.ts +1 -1
  21. package/dist/components/Form/ControlledInput.js +4 -4
  22. package/dist/components/Form/ControlledInput.js.map +1 -1
  23. package/dist/components/Form/ControlledSelect.js +1 -1
  24. package/dist/components/Form/ControlledSelect.js.map +1 -1
  25. package/dist/components/Form/ControlledTabs.js +17 -3
  26. package/dist/components/Form/ControlledTabs.js.map +1 -1
  27. package/dist/components/Form/ControlledTabsPrimitives.js +6 -6
  28. package/dist/components/Form/ControlledTabsPrimitives.js.map +1 -1
  29. package/dist/components/Form/ControlledTextarea.js +2 -2
  30. package/dist/components/Form/ControlledTextarea.js.map +1 -1
  31. package/dist/components/Form/ControlledTimeline.js +11 -8
  32. package/dist/components/Form/ControlledTimeline.js.map +1 -1
  33. package/dist/components/Form/ControlledVoiceTextarea.d.ts +2 -0
  34. package/dist/components/Form/ControlledVoiceTextarea.js +3 -0
  35. package/dist/components/Form/ControlledVoiceTextarea.js.map +1 -1
  36. package/dist/components/Form/FieldLabel.d.ts +16 -0
  37. package/dist/components/Form/FieldLabel.js +7 -0
  38. package/dist/components/Form/FieldLabel.js.map +1 -0
  39. package/dist/components/Form/RichTextEditor.js +15 -1
  40. package/dist/components/Form/RichTextEditor.js.map +1 -1
  41. package/dist/components/Form/attachments/AttachmentPreviewList.js +3 -0
  42. package/dist/components/Form/attachments/AttachmentPreviewList.js.map +1 -1
  43. package/dist/components/Form/attachments/FileDropzone.js +3 -3
  44. package/dist/components/Form/attachments/FileDropzone.js.map +1 -1
  45. package/dist/components/Navigation/PageTitle.d.ts +6 -0
  46. package/dist/components/Navigation/PageTitle.js +6 -4
  47. package/dist/components/Navigation/PageTitle.js.map +1 -1
  48. package/dist/components/Search/filters/FiltersPanel.js +1 -0
  49. package/dist/components/Search/filters/FiltersPanel.js.map +1 -1
  50. package/dist/components/Search/filters/FiltersSummaryTooltip.js +2 -2
  51. package/dist/components/Search/filters/FiltersSummaryTooltip.js.map +1 -1
  52. package/dist/components/Shell/LanguageToggle.js +1 -1
  53. package/dist/components/Shell/LanguageToggle.js.map +1 -1
  54. package/dist/components/Shell/SidebarMenu.js +9 -1
  55. package/dist/components/Shell/SidebarMenu.js.map +1 -1
  56. package/dist/components/Shell/ThemeToggle.js +2 -1
  57. package/dist/components/Shell/ThemeToggle.js.map +1 -1
  58. package/dist/components/UI/BaseDataCard.d.ts +2 -0
  59. package/dist/components/UI/BaseDataCard.js +6 -0
  60. package/dist/components/UI/BaseDataCard.js.map +1 -1
  61. package/dist/components/UI/BulkActionBar.js +2 -0
  62. package/dist/components/UI/BulkActionBar.js.map +1 -1
  63. package/dist/components/UI/Chips/OutlinedChip.js +13 -6
  64. package/dist/components/UI/Chips/OutlinedChip.js.map +1 -1
  65. package/dist/components/UI/ColorSwatch.js +2 -2
  66. package/dist/components/UI/ColorSwatch.js.map +1 -1
  67. package/dist/components/UI/ControlledAccordion.js +10 -4
  68. package/dist/components/UI/ControlledAccordion.js.map +1 -1
  69. package/dist/components/UI/ControlledCollapse.js +2 -2
  70. package/dist/components/UI/ControlledCollapse.js.map +1 -1
  71. package/dist/components/UI/ControlledMenu.js +3 -3
  72. package/dist/components/UI/ControlledMenu.js.map +1 -1
  73. package/dist/components/UI/ControlledPopover.d.ts +12 -0
  74. package/dist/components/UI/ControlledPopover.js +35 -5
  75. package/dist/components/UI/ControlledPopover.js.map +1 -1
  76. package/dist/components/UI/ControlledProgress.js +3 -3
  77. package/dist/components/UI/ControlledProgress.js.map +1 -1
  78. package/dist/components/UI/ControlledSlider.d.ts +2 -0
  79. package/dist/components/UI/ControlledSlider.js +8 -3
  80. package/dist/components/UI/ControlledSlider.js.map +1 -1
  81. package/dist/components/UI/ControlledTooltip.js +7 -3
  82. package/dist/components/UI/ControlledTooltip.js.map +1 -1
  83. package/dist/components/UI/DataTable/DataTable.js +1 -1
  84. package/dist/components/UI/DataTable/DataTableBody.js +4 -0
  85. package/dist/components/UI/DataTable/DataTableBody.js.map +1 -1
  86. package/dist/components/UI/DataTable/DataTableBulkEditDialog.js +4 -2
  87. package/dist/components/UI/DataTable/DataTableBulkEditDialog.js.map +1 -1
  88. package/dist/components/UI/DataTable/DataTableBulkEditRowsPicker.js +1 -1
  89. package/dist/components/UI/DataTable/DataTableBulkEditValueEditor.d.ts +5 -1
  90. package/dist/components/UI/DataTable/DataTableBulkEditValueEditor.js +19 -4
  91. package/dist/components/UI/DataTable/DataTableBulkEditValueEditor.js.map +1 -1
  92. package/dist/components/UI/DataTable/DataTableColumnToggle.js +3 -1
  93. package/dist/components/UI/DataTable/DataTableColumnToggle.js.map +1 -1
  94. package/dist/components/UI/DataTable/DataTableFilters.js +1 -1
  95. package/dist/components/UI/DataTable/DataTablePagination.js +4 -0
  96. package/dist/components/UI/DataTable/DataTablePagination.js.map +1 -1
  97. package/dist/components/UI/DataTable/DataTableStates.js +2 -2
  98. package/dist/components/UI/DataTable/DataTableStates.js.map +1 -1
  99. package/dist/components/UI/DataTable/DataTableToolbar.js +1 -1
  100. package/dist/components/UI/DataTable/applyDataTableFilters.js +1 -1
  101. package/dist/components/UI/DataTable/cells/DataTableEditableCell.js +2 -1
  102. package/dist/components/UI/DataTable/cells/DataTableEditableCell.js.map +1 -1
  103. package/dist/components/UI/DataTable/types.d.ts +4 -0
  104. package/dist/components/UI/DataTable/types.js.map +1 -1
  105. package/dist/components/UI/Flow/FlowBlockNode.js +1 -0
  106. package/dist/components/UI/Flow/FlowBlockNode.js.map +1 -1
  107. package/dist/components/UI/Flow/FlowCanvas.js +2 -2
  108. package/dist/components/UI/Flow/FlowCanvas.js.map +1 -1
  109. package/dist/components/UI/Flow/FlowConnectionEdge.js +1 -0
  110. package/dist/components/UI/Flow/FlowConnectionEdge.js.map +1 -1
  111. package/dist/components/UI/Flow/FlowInspector.js +3 -2
  112. package/dist/components/UI/Flow/FlowInspector.js.map +1 -1
  113. package/dist/components/UI/Flow/FlowIssueList.js +2 -2
  114. package/dist/components/UI/Flow/FlowIssueList.js.map +1 -1
  115. package/dist/components/UI/Flow/FlowLaneMap.js +2 -2
  116. package/dist/components/UI/Flow/FlowLaneMap.js.map +1 -1
  117. package/dist/components/UI/Flow/FlowResizablePanel.js +3 -2
  118. package/dist/components/UI/Flow/FlowResizablePanel.js.map +1 -1
  119. package/dist/components/UI/Flow/FlowZoomControls.js +1 -0
  120. package/dist/components/UI/Flow/FlowZoomControls.js.map +1 -1
  121. package/dist/components/UI/HorizontalScrollArea.d.ts +1 -1
  122. package/dist/components/UI/HorizontalScrollArea.js +1 -0
  123. package/dist/components/UI/HorizontalScrollArea.js.map +1 -1
  124. package/dist/components/UI/ImageAnnotator/components/AnnotationColorPopover.js +1 -0
  125. package/dist/components/UI/ImageAnnotator/components/AnnotationColorPopover.js.map +1 -1
  126. package/dist/components/UI/ImagePlaceholder.js +5 -2
  127. package/dist/components/UI/ImagePlaceholder.js.map +1 -1
  128. package/dist/components/UI/ImageZoomOverlay.js +1 -0
  129. package/dist/components/UI/ImageZoomOverlay.js.map +1 -1
  130. package/dist/components/UI/MaterialSymbol/index.js +5 -0
  131. package/dist/components/UI/MaterialSymbol/index.js.map +1 -1
  132. package/dist/components/UI/NoDataFound/index.js +3 -3
  133. package/dist/components/UI/NoDataFound/index.js.map +1 -1
  134. package/dist/components/UI/RichTextContent.js +3 -3
  135. package/dist/components/UI/RichTextContent.js.map +1 -1
  136. package/dist/components/UI/ThreeDots.js +15 -11
  137. package/dist/components/UI/ThreeDots.js.map +1 -1
  138. package/dist/helpers/mergeClasses.d.ts +7 -3
  139. package/dist/helpers/mergeClasses.js +23 -1
  140. package/dist/helpers/mergeClasses.js.map +1 -1
  141. package/dist/hooks/useVoiceTranscription.js +5 -2
  142. package/dist/hooks/useVoiceTranscription.js.map +1 -1
  143. package/dist/index.d.ts +2 -0
  144. package/dist/index.js +58 -54
  145. package/dist/index.js.map +1 -1
  146. package/dist/locales/en/ui.json.d.ts +8 -3
  147. package/dist/locales/en/ui.json.js +3 -3
  148. package/dist/locales/index.d.ts +10 -0
  149. package/dist/locales/pt/ui.json.d.ts +8 -3
  150. package/dist/locales/pt/ui.json.js +3 -3
  151. package/package.json +1 -1
  152. package/src/assets/styles/base.css +7 -1
  153. package/tailwind-plugins/glass.js +23 -28
@@ -1 +1 @@
1
- {"version":3,"file":"ControlledDrawer.js","sources":["../../../src/components/Form/ControlledDrawer.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport * as React from 'react';\nimport classNames from 'classnames';\nimport { AnimatePresence, motion } from 'motion/react';\nimport { createPortal } from 'react-dom';\nimport { useTranslation } from 'react-i18next';\n\nimport ControlledButton from '@/components/Form/ControlledButton';\nimport ControlledTooltip from '@/components/UI/ControlledTooltip';\nimport { isPressOnLayeredSurface } from '@/helpers/layeredSurfaces';\nimport { getPortalHost } from '@/helpers/portalHost';\nimport { createDrawerVariants, scrimVariants } from '@/motion';\n\nconst DEFAULT_SIZE = 300;\nconst DEFAULT_MIN_RESIZE_WIDTH = 280;\nconst DEFAULT_MAX_RESIZE_VIEWPORT_RATIO = 0.8;\nconst KEYBOARD_RESIZE_STEP = 24;\n\nexport type TDrawerPlacement = 'left' | 'right' | 'top' | 'bottom';\n\nexport interface IDrawerDismissConfig {\n enabled?: boolean;\n escapeKey?: boolean;\n outsidePress?: boolean | ((event: PointerEvent) => boolean);\n}\n\nexport interface IControlledDrawerProps {\n open?: boolean;\n onClose?: () => void;\n placement?: TDrawerPlacement;\n /** Width for left/right placements, height for top/bottom, in pixels. */\n size?: number;\n className?: string;\n overlayClassName?: string;\n children?: React.ReactNode;\n dismiss?: IDrawerDismissConfig;\n\n /** Defer mounting the subtree until the first time `open` becomes true. */\n lazy?: boolean;\n /** Discard the subtree while closed, so its state resets on the next open. */\n unmountOnClose?: boolean;\n /** Fires once, the first time the drawer opens after this component mounted. */\n onFirstOpen?: () => void;\n /** Fires whenever `open` toggles. Argument is the new value. */\n onOpenChange?: (open: boolean) => void;\n\n resizable?: boolean;\n minResizeWidth?: number;\n maxResizeViewportRatio?: number;\n}\n\nconst PLACEMENT_CLASS: Record<TDrawerPlacement, string> = {\n left: 'inset-y-0 left-0',\n right: 'inset-y-0 right-0',\n top: 'inset-x-0 top-0',\n bottom: 'inset-x-0 bottom-0',\n};\n\n/**\n * The panel is removed from the DOM once its exit transition finishes. The Material\n * Tailwind drawer kept a closed panel mounted off-screen, and its shadow bled back into\n * the viewport: with one drawer that is invisible, with one per list row the bleeds\n * stacked into visible gray lines at the screen edge.\n */\nconst ControlledDrawer: React.FC<IControlledDrawerProps> = ({\n open,\n onClose,\n placement = 'left',\n size = DEFAULT_SIZE,\n className,\n overlayClassName,\n children,\n dismiss,\n lazy,\n unmountOnClose,\n onFirstOpen,\n onOpenChange,\n resizable = true,\n minResizeWidth = DEFAULT_MIN_RESIZE_WIDTH,\n maxResizeViewportRatio = DEFAULT_MAX_RESIZE_VIEWPORT_RATIO,\n}) => {\n const { t } = useTranslation('ui');\n\n const isOpen = Boolean(open);\n const panelRef = useRef<HTMLDivElement>(null);\n const previouslyFocusedRef = useRef<HTMLElement | null>(null);\n\n const [hasEverOpened, setHasEverOpened] = useState(isOpen);\n const [isLeaving, setIsLeaving] = useState(false);\n const prevOpenRef = useRef<boolean | undefined>(open);\n const firstOpenFiredRef = useRef(false);\n\n const isHorizontalPlacement = placement === 'left' || placement === 'right';\n const canResize = resizable && isHorizontalPlacement;\n\n const [resizedWidth, setResizedWidth] = useState<number | null>(null);\n const [isResizing, setIsResizing] = useState(false);\n const resizeStartRef = useRef<{ pointerX: number; width: number } | null>(null);\n const previousBaseSizeRef = useRef(size);\n\n const clampWidth = useCallback(\n (width: number) => {\n const maxWidth = Math.max(minResizeWidth, Math.round(window.innerWidth * maxResizeViewportRatio));\n return Math.min(maxWidth, Math.max(minResizeWidth, Math.round(width)));\n },\n [minResizeWidth, maxResizeViewportRatio],\n );\n\n useEffect(() => {\n if (previousBaseSizeRef.current === size) return;\n previousBaseSizeRef.current = size;\n setResizedWidth(null);\n }, [size]);\n\n useEffect(() => {\n if (!canResize) return undefined;\n\n const handleViewportResize = () => setResizedWidth((current) => (current === null ? null : clampWidth(current)));\n\n window.addEventListener('resize', handleViewportResize);\n return () => window.removeEventListener('resize', handleViewportResize);\n }, [canResize, clampWidth]);\n\n useEffect(() => {\n const previous = prevOpenRef.current;\n if (previous === isOpen) return;\n prevOpenRef.current = isOpen;\n\n if (isOpen && !hasEverOpened) setHasEverOpened(true);\n\n if (isOpen && !firstOpenFiredRef.current) {\n firstOpenFiredRef.current = true;\n onFirstOpen?.();\n }\n\n onOpenChange?.(isOpen);\n }, [isOpen, hasEverOpened, onFirstOpen, onOpenChange]);\n\n useEffect(() => {\n if (isOpen) setIsLeaving(true);\n }, [isOpen]);\n\n /* Held until the exit finishes, not until `open` flips: releasing it early brings the\n page scrollbar back while the panel is still travelling, and the content behind jumps. */\n useEffect(() => {\n if (!isOpen && !isLeaving) return undefined;\n\n const { overflow } = document.body.style;\n document.body.style.overflow = 'hidden';\n return () => {\n document.body.style.overflow = overflow;\n };\n }, [isOpen, isLeaving]);\n\n useEffect(() => {\n if (!isOpen) return undefined;\n\n previouslyFocusedRef.current = document.activeElement as HTMLElement | null;\n const frame = requestAnimationFrame(() => panelRef.current?.focus());\n\n return () => {\n cancelAnimationFrame(frame);\n previouslyFocusedRef.current?.focus?.();\n };\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen || dismiss?.enabled === false) return undefined;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // A layer inside the drawer (a select list) that consumed the ESC marks it handled.\n if (event.key !== 'Escape' || event.defaultPrevented || dismiss?.escapeKey === false) return;\n onClose?.();\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n if (dismiss?.outsidePress === false) return;\n const panel = panelRef.current;\n const target = event.target as Node | null;\n if (!panel || !target || panel.contains(target)) return;\n if (isPressOnLayeredSurface(target, panelRef.current)) return;\n if (typeof dismiss?.outsidePress === 'function' && !dismiss.outsidePress(event)) return;\n onClose?.();\n };\n\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('pointerdown', handlePointerDown, true);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('pointerdown', handlePointerDown, true);\n };\n }, [isOpen, dismiss, onClose]);\n\n const handleResizeStart = (event: React.PointerEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n resizeStartRef.current = { pointerX: event.clientX, width: resizedWidth ?? size };\n setIsResizing(true);\n event.currentTarget.setPointerCapture(event.pointerId);\n };\n\n const handleResizeMove = (event: React.PointerEvent<HTMLButtonElement>) => {\n const resizeStart = resizeStartRef.current;\n if (!resizeStart) return;\n const pointerDelta =\n placement === 'right' ? resizeStart.pointerX - event.clientX : event.clientX - resizeStart.pointerX;\n setResizedWidth(clampWidth(resizeStart.width + pointerDelta));\n };\n\n const handleResizeEnd = (event: React.PointerEvent<HTMLButtonElement>) => {\n if (!resizeStartRef.current) return;\n resizeStartRef.current = null;\n setIsResizing(false);\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n };\n\n const handleResizeKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;\n event.preventDefault();\n const pointerDirection = event.key === 'ArrowLeft' ? -1 : 1;\n const widthDirection = placement === 'right' ? -pointerDirection : pointerDirection;\n setResizedWidth((current) => clampWidth((current ?? size) + widthDirection * KEYBOARD_RESIZE_STEP));\n };\n\n if (lazy && !hasEverOpened) return null;\n\n const resolvedSize = isHorizontalPlacement ? (resizedWidth ?? size) : size;\n const shouldRenderChildren = unmountOnClose ? isOpen : !lazy || hasEverOpened;\n const drawerVariants = createDrawerVariants(placement);\n\n const portalHost = getPortalHost();\n if (portalHost === null) return null;\n\n return createPortal(\n <AnimatePresence onExitComplete={() => setIsLeaving(false)}>\n {isOpen && (\n <motion.div\n key=\"drawer-scrim\"\n variants={scrimVariants}\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"exit\"\n aria-hidden\n onClick={() => {\n if (dismiss?.enabled === false || dismiss?.outsidePress === false) return;\n onClose?.();\n }}\n className={classNames('fixed inset-0 z-[9996] glass-scrim', overlayClassName)}\n />\n )}\n\n {isOpen && (\n <motion.div\n key=\"drawer-panel\"\n ref={panelRef}\n variants={drawerVariants}\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"exit\"\n role=\"dialog\"\n aria-modal={true}\n tabIndex={-1}\n style={isHorizontalPlacement ? { width: resolvedSize } : { height: resolvedSize }}\n className={classNames(\n 'fixed z-[9997] flex max-w-full flex-col overflow-y-auto bg-surface shadow-xl outline-none',\n PLACEMENT_CLASS[placement],\n className,\n )}\n >\n {canResize && isOpen ? (\n <ControlledTooltip\n content={t('controlledDrawer.resizeHandle')}\n placement={placement === 'right' ? 'left' : 'right'}\n className=\"z-[9999]\"\n >\n <ControlledButton\n defaultHtmlButton\n onPointerDown={handleResizeStart}\n onPointerMove={handleResizeMove}\n onPointerUp={handleResizeEnd}\n onPointerCancel={handleResizeEnd}\n onKeyDown={handleResizeKeyDown}\n onDoubleClick={() => setResizedWidth(null)}\n className={classNames(\n 'group/resize absolute inset-y-0 z-10 flex w-3 cursor-col-resize touch-none select-none items-center justify-center focus:outline-none',\n placement === 'right' ? 'left-0' : 'right-0',\n )}\n >\n <span\n className={classNames(\n 'h-full w-0.5 rounded-full transition-colors duration-base',\n isResizing ? 'bg-brand-hover' : 'bg-transparent group-hover/resize:bg-brand-hover',\n )}\n />\n </ControlledButton>\n </ControlledTooltip>\n ) : null}\n\n {shouldRenderChildren ? children : null}\n </motion.div>\n )}\n </AnimatePresence>,\n portalHost,\n );\n};\n\nexport default ControlledDrawer;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ControlledDrawer.js","sources":["../../../src/components/Form/ControlledDrawer.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport * as React from 'react';\nimport classNames from 'classnames';\nimport { AnimatePresence, motion } from 'motion/react';\nimport { createPortal } from 'react-dom';\nimport { useTranslation } from 'react-i18next';\n\nimport ControlledButton from '@/components/Form/ControlledButton';\nimport ControlledTooltip from '@/components/UI/ControlledTooltip';\nimport { isPressOnLayeredSurface } from '@/helpers/layeredSurfaces';\nimport { getPortalHost } from '@/helpers/portalHost';\nimport { createDrawerVariants, scrimVariants } from '@/motion';\n\nconst DEFAULT_SIZE = 300;\nconst DEFAULT_MIN_RESIZE_WIDTH = 280;\nconst DEFAULT_MAX_RESIZE_VIEWPORT_RATIO = 0.8;\nconst KEYBOARD_RESIZE_STEP = 24;\n\nexport type TDrawerPlacement = 'left' | 'right' | 'top' | 'bottom';\n\nexport interface IDrawerDismissConfig {\n enabled?: boolean;\n escapeKey?: boolean;\n outsidePress?: boolean | ((event: PointerEvent) => boolean);\n}\n\nexport interface IControlledDrawerProps {\n open?: boolean;\n onClose?: () => void;\n placement?: TDrawerPlacement;\n /** Width for left/right placements, height for top/bottom, in pixels. */\n size?: number;\n className?: string;\n overlayClassName?: string;\n children?: React.ReactNode;\n dismiss?: IDrawerDismissConfig;\n\n /** Defer mounting the subtree until the first time `open` becomes true. */\n lazy?: boolean;\n /** Discard the subtree while closed, so its state resets on the next open. */\n unmountOnClose?: boolean;\n /** Fires once, the first time the drawer opens after this component mounted. */\n onFirstOpen?: () => void;\n /** Fires whenever `open` toggles. Argument is the new value. */\n onOpenChange?: (open: boolean) => void;\n\n resizable?: boolean;\n minResizeWidth?: number;\n maxResizeViewportRatio?: number;\n}\n\nconst PLACEMENT_CLASS: Record<TDrawerPlacement, string> = {\n left: 'inset-y-0 left-0',\n right: 'inset-y-0 right-0',\n top: 'inset-x-0 top-0',\n bottom: 'inset-x-0 bottom-0',\n};\n\n/**\n * The panel is removed from the DOM once its exit transition finishes. The Material\n * Tailwind drawer kept a closed panel mounted off-screen, and its shadow bled back into\n * the viewport: with one drawer that is invisible, with one per list row the bleeds\n * stacked into visible gray lines at the screen edge.\n */\nconst ControlledDrawer: React.FC<IControlledDrawerProps> = ({\n open,\n onClose,\n placement = 'left',\n size = DEFAULT_SIZE,\n className,\n overlayClassName,\n children,\n dismiss,\n lazy,\n unmountOnClose,\n onFirstOpen,\n onOpenChange,\n resizable = true,\n minResizeWidth = DEFAULT_MIN_RESIZE_WIDTH,\n maxResizeViewportRatio = DEFAULT_MAX_RESIZE_VIEWPORT_RATIO,\n}) => {\n const { t } = useTranslation('ui');\n\n const isOpen = Boolean(open);\n const panelRef = useRef<HTMLDivElement>(null);\n const previouslyFocusedRef = useRef<HTMLElement | null>(null);\n\n const [hasEverOpened, setHasEverOpened] = useState(isOpen);\n const [isLeaving, setIsLeaving] = useState(false);\n const prevOpenRef = useRef<boolean | undefined>(open);\n const firstOpenFiredRef = useRef(false);\n\n const isHorizontalPlacement = placement === 'left' || placement === 'right';\n const canResize = resizable && isHorizontalPlacement;\n\n const [resizedWidth, setResizedWidth] = useState<number | null>(null);\n const [isResizing, setIsResizing] = useState(false);\n const resizeStartRef = useRef<{ pointerX: number; width: number } | null>(null);\n const previousBaseSizeRef = useRef(size);\n\n const clampWidth = useCallback(\n (width: number) => {\n const maxWidth = Math.max(minResizeWidth, Math.round(window.innerWidth * maxResizeViewportRatio));\n return Math.min(maxWidth, Math.max(minResizeWidth, Math.round(width)));\n },\n [minResizeWidth, maxResizeViewportRatio],\n );\n\n useEffect(() => {\n if (previousBaseSizeRef.current === size) return;\n previousBaseSizeRef.current = size;\n setResizedWidth(null);\n }, [size]);\n\n useEffect(() => {\n if (!canResize) return undefined;\n\n const handleViewportResize = () => setResizedWidth((current) => (current === null ? null : clampWidth(current)));\n\n window.addEventListener('resize', handleViewportResize);\n return () => window.removeEventListener('resize', handleViewportResize);\n }, [canResize, clampWidth]);\n\n useEffect(() => {\n const previous = prevOpenRef.current;\n if (previous === isOpen) return;\n prevOpenRef.current = isOpen;\n\n if (isOpen && !hasEverOpened) setHasEverOpened(true);\n\n if (isOpen && !firstOpenFiredRef.current) {\n firstOpenFiredRef.current = true;\n onFirstOpen?.();\n }\n\n onOpenChange?.(isOpen);\n }, [isOpen, hasEverOpened, onFirstOpen, onOpenChange]);\n\n useEffect(() => {\n if (isOpen) setIsLeaving(true);\n }, [isOpen]);\n\n /* Held until the exit finishes, not until `open` flips: releasing it early brings the\n page scrollbar back while the panel is still travelling, and the content behind jumps. */\n useEffect(() => {\n if (!isOpen && !isLeaving) return undefined;\n\n const { overflow } = document.body.style;\n document.body.style.overflow = 'hidden';\n return () => {\n document.body.style.overflow = overflow;\n };\n }, [isOpen, isLeaving]);\n\n useEffect(() => {\n if (!isOpen) return undefined;\n\n previouslyFocusedRef.current = document.activeElement as HTMLElement | null;\n const frame = requestAnimationFrame(() => panelRef.current?.focus());\n\n return () => {\n cancelAnimationFrame(frame);\n previouslyFocusedRef.current?.focus?.();\n };\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen || dismiss?.enabled === false) return undefined;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // A layer inside the drawer (a select list) that consumed the ESC marks it handled.\n if (event.key !== 'Escape' || event.defaultPrevented || dismiss?.escapeKey === false) return;\n onClose?.();\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n if (dismiss?.outsidePress === false) return;\n const panel = panelRef.current;\n const target = event.target as Node | null;\n if (!panel || !target || panel.contains(target)) return;\n if (isPressOnLayeredSurface(target, panelRef.current)) return;\n if (typeof dismiss?.outsidePress === 'function' && !dismiss.outsidePress(event)) return;\n onClose?.();\n };\n\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('pointerdown', handlePointerDown, true);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('pointerdown', handlePointerDown, true);\n };\n }, [isOpen, dismiss, onClose]);\n\n const handleResizeStart = (event: React.PointerEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n resizeStartRef.current = { pointerX: event.clientX, width: resizedWidth ?? size };\n setIsResizing(true);\n event.currentTarget.setPointerCapture(event.pointerId);\n };\n\n const handleResizeMove = (event: React.PointerEvent<HTMLButtonElement>) => {\n const resizeStart = resizeStartRef.current;\n if (!resizeStart) return;\n const pointerDelta =\n placement === 'right' ? resizeStart.pointerX - event.clientX : event.clientX - resizeStart.pointerX;\n setResizedWidth(clampWidth(resizeStart.width + pointerDelta));\n };\n\n const handleResizeEnd = (event: React.PointerEvent<HTMLButtonElement>) => {\n if (!resizeStartRef.current) return;\n resizeStartRef.current = null;\n setIsResizing(false);\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n };\n\n const handleResizeKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;\n event.preventDefault();\n const pointerDirection = event.key === 'ArrowLeft' ? -1 : 1;\n const widthDirection = placement === 'right' ? -pointerDirection : pointerDirection;\n setResizedWidth((current) => clampWidth((current ?? size) + widthDirection * KEYBOARD_RESIZE_STEP));\n };\n\n if (lazy && !hasEverOpened) return null;\n\n const resolvedSize = isHorizontalPlacement ? (resizedWidth ?? size) : size;\n const shouldRenderChildren = unmountOnClose ? isOpen : !lazy || hasEverOpened;\n const drawerVariants = createDrawerVariants(placement);\n\n const portalHost = getPortalHost();\n if (portalHost === null) return null;\n\n return createPortal(\n <AnimatePresence onExitComplete={() => setIsLeaving(false)}>\n {isOpen && (\n <motion.div\n key=\"drawer-scrim\"\n variants={scrimVariants}\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"exit\"\n aria-hidden\n onClick={() => {\n if (dismiss?.enabled === false || dismiss?.outsidePress === false) return;\n onClose?.();\n }}\n className={classNames('fixed inset-0 z-[9996] glass-scrim', overlayClassName)}\n />\n )}\n\n {isOpen && (\n <motion.div\n key=\"drawer-panel\"\n ref={panelRef}\n variants={drawerVariants}\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"exit\"\n role=\"dialog\"\n aria-modal={true}\n tabIndex={-1}\n style={isHorizontalPlacement ? { width: resolvedSize } : { height: resolvedSize }}\n className={classNames(\n 'fixed z-[9997] flex max-w-full flex-col overflow-y-auto bg-surface shadow-xl outline-none',\n PLACEMENT_CLASS[placement],\n className,\n )}\n >\n {canResize && isOpen ? (\n <ControlledTooltip\n content={t('controlledDrawer.resizeHandle')}\n placement={placement === 'right' ? 'left' : 'right'}\n className=\"z-[9999]\"\n >\n <ControlledButton\n defaultHtmlButton\n aria-label={t('controlledDrawer.resizeHandle')}\n onPointerDown={handleResizeStart}\n onPointerMove={handleResizeMove}\n onPointerUp={handleResizeEnd}\n onPointerCancel={handleResizeEnd}\n onKeyDown={handleResizeKeyDown}\n onDoubleClick={() => setResizedWidth(null)}\n className={classNames(\n 'group/resize absolute inset-y-0 z-10 flex w-3 cursor-col-resize touch-none select-none items-center justify-center focus:outline-none',\n placement === 'right' ? 'left-0' : 'right-0',\n )}\n >\n <span\n className={classNames(\n 'h-full w-0.5 rounded-full transition-colors duration-base',\n isResizing ? 'bg-brand-hover' : 'bg-transparent group-hover/resize:bg-brand-hover',\n )}\n />\n </ControlledButton>\n </ControlledTooltip>\n ) : null}\n\n {shouldRenderChildren ? children : null}\n </motion.div>\n )}\n </AnimatePresence>,\n portalHost,\n );\n};\n\nexport default ControlledDrawer;\n"],"names":[],"mappings":"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"}
@@ -50,6 +50,7 @@ const ControlledImageContent = ({
50
50
  showAnnotate && /* @__PURE__ */ jsx(ControlledTooltip, { content: t("imageAnnotator.annotate"), className: "z-[9999]", children: /* @__PURE__ */ jsx(
51
51
  ControlledButton,
52
52
  {
53
+ "aria-label": t("imageAnnotator.annotate"),
53
54
  defaultHtmlButton: true,
54
55
  onClick: (event) => {
55
56
  event.stopPropagation();
@@ -62,6 +63,7 @@ const ControlledImageContent = ({
62
63
  showAiAdjust && /* @__PURE__ */ jsx(ControlledTooltip, { content: t("imageAiAdjust.action"), className: "z-[9999]", children: /* @__PURE__ */ jsx(
63
64
  ControlledButton,
64
65
  {
66
+ "aria-label": t("imageAiAdjust.action"),
65
67
  defaultHtmlButton: true,
66
68
  onClick: (event) => {
67
69
  event.stopPropagation();
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/components/Form/ControlledImage/index.tsx"],"sourcesContent":["import { lazy, Suspense, useState } from 'react';\nimport classNames from 'classnames';\nimport { useTranslation } from 'react-i18next';\n\nimport ControlledTooltip from '@/components/UI/ControlledTooltip';\nimport { TImageAiReviewHandler } from '@/components/UI/ImageAiAdjust/imageAiReview';\nimport { TImageAiAdjuster } from '@/components/UI/ImageAiAdjust/useImageAiAdjust';\nimport ImagePlaceholder from '@/components/UI/ImagePlaceholder';\n\nimport ControlledButton from '../../Form/ControlledButton';\nimport LoadingSpinner from '../../UI/LoadingSpinner';\nimport { MaterialSymbol } from '../../UI/MaterialSymbol';\n\nimport Img from './Img';\n\n/**\n * Lazy por dois motivos: quebra o ciclo de import (o diálogo de IA renderiza um\n * `ControlledImage` no comparativo) e mantém os dois editores fora do bundle de quem só\n * exibe imagem, que é quase toda a aplicação.\n */\nconst ImageAnnotationDialog = lazy(() => import('@/components/UI/ImageAnnotator/ImageAnnotationDialog'));\nconst ImageAiAdjustDialog = lazy(() => import('@/components/UI/ImageAiAdjust/ImageAiAdjustDialog'));\n\nexport interface IControlledImageAiAdjust {\n adjustImage: TImageAiAdjuster;\n /** Receives the adjusted image; resolving closes the dialog, throwing keeps it open. */\n onAdjusted: (file: File) => Promise<void> | void;\n /** Associates the generation with a product when the surface knows one. */\n productId?: string;\n /** Receives approve/discard feedback when the adjuster returns a generationId. */\n onReviewResult?: TImageAiReviewHandler;\n}\n\ninterface IControlledImageProps {\n src: string | null | undefined;\n fallbackSrc?: string;\n className?: string;\n tooltip?: string;\n onClickHook?: () => void;\n /**\n * Opts into the annotation flow (pencil overlay + editor). Hosts own what happens to the\n * annotated file, so enabling it here never conflicts with other image click behaviors.\n */\n annotatable?: boolean;\n /** Receives the annotated image; resolving closes the editor, throwing keeps it open. */\n onAnnotated?: (file: File) => Promise<void> | void;\n annotationFileName?: string;\n /**\n * Opts into the AI adjustment flow. Sibling of `annotatable`, same contract: the host owns the\n * resulting file, and decides whether the feature is available at all.\n */\n aiAdjust?: IControlledImageAiAdjust;\n}\n\nconst ControlledImageContent: React.FC<IControlledImageProps> = ({\n src,\n fallbackSrc,\n className,\n tooltip,\n onClickHook,\n annotatable = false,\n onAnnotated,\n annotationFileName,\n aiAdjust,\n}) => {\n const { t } = useTranslation('ui');\n const [annotatorOpen, setAnnotatorOpen] = useState(false);\n const [aiAdjustOpen, setAiAdjustOpen] = useState(false);\n\n const renderImage = () => {\n if (!src) return <ImagePlaceholder className={className} />;\n\n return (\n <Img\n onClick={onClickHook}\n key={src}\n src={src}\n fallbackSrc={fallbackSrc}\n className={className}\n loader={\n <div className={classNames('flex size-full items-center justify-center bg-muted', className)}>\n <LoadingSpinner size={6} />\n </div>\n }\n unloader={<ImagePlaceholder variant=\"broken\" className={className} />}\n />\n );\n };\n\n const image = tooltip ? <ControlledTooltip content={tooltip}>{renderImage()}</ControlledTooltip> : renderImage();\n\n const showAnnotate = annotatable && Boolean(onAnnotated) && Boolean(src);\n const showAiAdjust = Boolean(aiAdjust) && Boolean(src);\n\n if (!src || (!showAnnotate && !showAiAdjust)) return image;\n\n const overlayButtonClass =\n 'flex size-8 items-center justify-center rounded-full bg-scrim text-white transition-colors glass-tint hover:bg-scrim';\n\n return (\n <span className=\"relative inline-flex max-w-full\">\n {image}\n\n <span className=\"absolute right-2 top-2 flex items-center gap-x-1\">\n {showAnnotate && (\n <ControlledTooltip content={t('imageAnnotator.annotate')} className=\"z-[9999]\">\n <ControlledButton\n defaultHtmlButton\n onClick={(event: React.MouseEvent) => {\n event.stopPropagation();\n setAnnotatorOpen(true);\n }}\n className={overlayButtonClass}\n >\n <MaterialSymbol icon=\"edit\" size={16} color=\"white\" />\n </ControlledButton>\n </ControlledTooltip>\n )}\n\n {showAiAdjust && (\n <ControlledTooltip content={t('imageAiAdjust.action')} className=\"z-[9999]\">\n <ControlledButton\n defaultHtmlButton\n onClick={(event: React.MouseEvent) => {\n event.stopPropagation();\n setAiAdjustOpen(true);\n }}\n className={overlayButtonClass}\n >\n <MaterialSymbol icon=\"auto_fix_high\" size={16} color=\"white\" />\n </ControlledButton>\n </ControlledTooltip>\n )}\n </span>\n\n <Suspense fallback={null}>\n {annotatorOpen && onAnnotated && (\n <ImageAnnotationDialog\n open={annotatorOpen}\n imageUrl={src}\n imageName={annotationFileName}\n onClose={() => setAnnotatorOpen(false)}\n onSave={onAnnotated}\n />\n )}\n\n {aiAdjustOpen && aiAdjust && (\n <ImageAiAdjustDialog\n open={aiAdjustOpen}\n imageUrl={src}\n imageName={annotationFileName}\n productId={aiAdjust.productId}\n adjustImage={aiAdjust.adjustImage}\n onClose={() => setAiAdjustOpen(false)}\n onSave={aiAdjust.onAdjusted}\n onReviewResult={aiAdjust.onReviewResult}\n />\n )}\n </Suspense>\n </span>\n );\n};\n\nconst ControlledImage: React.FC<IControlledImageProps> = (props) => {\n return <ControlledImageContent {...props} />;\n};\n\nexport default ControlledImage;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/Form/ControlledImage/index.tsx"],"sourcesContent":["import { lazy, Suspense, useState } from 'react';\nimport classNames from 'classnames';\nimport { useTranslation } from 'react-i18next';\n\nimport ControlledTooltip from '@/components/UI/ControlledTooltip';\nimport { TImageAiReviewHandler } from '@/components/UI/ImageAiAdjust/imageAiReview';\nimport { TImageAiAdjuster } from '@/components/UI/ImageAiAdjust/useImageAiAdjust';\nimport ImagePlaceholder from '@/components/UI/ImagePlaceholder';\n\nimport ControlledButton from '../../Form/ControlledButton';\nimport LoadingSpinner from '../../UI/LoadingSpinner';\nimport { MaterialSymbol } from '../../UI/MaterialSymbol';\n\nimport Img from './Img';\n\n/**\n * Lazy por dois motivos: quebra o ciclo de import (o diálogo de IA renderiza um\n * `ControlledImage` no comparativo) e mantém os dois editores fora do bundle de quem só\n * exibe imagem, que é quase toda a aplicação.\n */\nconst ImageAnnotationDialog = lazy(() => import('@/components/UI/ImageAnnotator/ImageAnnotationDialog'));\nconst ImageAiAdjustDialog = lazy(() => import('@/components/UI/ImageAiAdjust/ImageAiAdjustDialog'));\n\nexport interface IControlledImageAiAdjust {\n adjustImage: TImageAiAdjuster;\n /** Receives the adjusted image; resolving closes the dialog, throwing keeps it open. */\n onAdjusted: (file: File) => Promise<void> | void;\n /** Associates the generation with a product when the surface knows one. */\n productId?: string;\n /** Receives approve/discard feedback when the adjuster returns a generationId. */\n onReviewResult?: TImageAiReviewHandler;\n}\n\ninterface IControlledImageProps {\n src: string | null | undefined;\n fallbackSrc?: string;\n className?: string;\n tooltip?: string;\n onClickHook?: () => void;\n /**\n * Opts into the annotation flow (pencil overlay + editor). Hosts own what happens to the\n * annotated file, so enabling it here never conflicts with other image click behaviors.\n */\n annotatable?: boolean;\n /** Receives the annotated image; resolving closes the editor, throwing keeps it open. */\n onAnnotated?: (file: File) => Promise<void> | void;\n annotationFileName?: string;\n /**\n * Opts into the AI adjustment flow. Sibling of `annotatable`, same contract: the host owns the\n * resulting file, and decides whether the feature is available at all.\n */\n aiAdjust?: IControlledImageAiAdjust;\n}\n\nconst ControlledImageContent: React.FC<IControlledImageProps> = ({\n src,\n fallbackSrc,\n className,\n tooltip,\n onClickHook,\n annotatable = false,\n onAnnotated,\n annotationFileName,\n aiAdjust,\n}) => {\n const { t } = useTranslation('ui');\n const [annotatorOpen, setAnnotatorOpen] = useState(false);\n const [aiAdjustOpen, setAiAdjustOpen] = useState(false);\n\n const renderImage = () => {\n if (!src) return <ImagePlaceholder className={className} />;\n\n return (\n <Img\n onClick={onClickHook}\n key={src}\n src={src}\n fallbackSrc={fallbackSrc}\n className={className}\n loader={\n <div className={classNames('flex size-full items-center justify-center bg-muted', className)}>\n <LoadingSpinner size={6} />\n </div>\n }\n unloader={<ImagePlaceholder variant=\"broken\" className={className} />}\n />\n );\n };\n\n const image = tooltip ? <ControlledTooltip content={tooltip}>{renderImage()}</ControlledTooltip> : renderImage();\n\n const showAnnotate = annotatable && Boolean(onAnnotated) && Boolean(src);\n const showAiAdjust = Boolean(aiAdjust) && Boolean(src);\n\n if (!src || (!showAnnotate && !showAiAdjust)) return image;\n\n const overlayButtonClass =\n 'flex size-8 items-center justify-center rounded-full bg-scrim text-white transition-colors glass-tint hover:bg-scrim';\n\n return (\n <span className=\"relative inline-flex max-w-full\">\n {image}\n\n <span className=\"absolute right-2 top-2 flex items-center gap-x-1\">\n {showAnnotate && (\n <ControlledTooltip content={t('imageAnnotator.annotate')} className=\"z-[9999]\">\n <ControlledButton\n aria-label={t('imageAnnotator.annotate')}\n defaultHtmlButton\n onClick={(event: React.MouseEvent) => {\n event.stopPropagation();\n setAnnotatorOpen(true);\n }}\n className={overlayButtonClass}\n >\n <MaterialSymbol icon=\"edit\" size={16} color=\"white\" />\n </ControlledButton>\n </ControlledTooltip>\n )}\n\n {showAiAdjust && (\n <ControlledTooltip content={t('imageAiAdjust.action')} className=\"z-[9999]\">\n <ControlledButton\n aria-label={t('imageAiAdjust.action')}\n defaultHtmlButton\n onClick={(event: React.MouseEvent) => {\n event.stopPropagation();\n setAiAdjustOpen(true);\n }}\n className={overlayButtonClass}\n >\n <MaterialSymbol icon=\"auto_fix_high\" size={16} color=\"white\" />\n </ControlledButton>\n </ControlledTooltip>\n )}\n </span>\n\n <Suspense fallback={null}>\n {annotatorOpen && onAnnotated && (\n <ImageAnnotationDialog\n open={annotatorOpen}\n imageUrl={src}\n imageName={annotationFileName}\n onClose={() => setAnnotatorOpen(false)}\n onSave={onAnnotated}\n />\n )}\n\n {aiAdjustOpen && aiAdjust && (\n <ImageAiAdjustDialog\n open={aiAdjustOpen}\n imageUrl={src}\n imageName={annotationFileName}\n productId={aiAdjust.productId}\n adjustImage={aiAdjust.adjustImage}\n onClose={() => setAiAdjustOpen(false)}\n onSave={aiAdjust.onAdjusted}\n onReviewResult={aiAdjust.onReviewResult}\n />\n )}\n </Suspense>\n </span>\n );\n};\n\nconst ControlledImage: React.FC<IControlledImageProps> = (props) => {\n return <ControlledImageContent {...props} />;\n};\n\nexport default ControlledImage;\n"],"names":[],"mappings":";;;;;;;;;;AAoBA,MAAM,wBAAwB,KAAK,MAAM,OAAO,kDAAsD,CAAC;AACvG,MAAM,sBAAsB,KAAK,MAAM,OAAO,+CAAmD,CAAC;AAiClG,MAAM,yBAA0D,CAAC;AAAA,EAC/D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,EAAA,IAAM,eAAe,IAAI;AACjC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AACxD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AAEtD,QAAM,cAAc,MAAM;AACxB,QAAI,CAAC,IAAK,QAAO,oBAAC,oBAAiB,UAAA,CAAsB;AAEzD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS;AAAA,QAET;AAAA,QACA;AAAA,QACA;AAAA,QACA,QACE,oBAAC,OAAA,EAAI,WAAW,WAAW,uDAAuD,SAAS,GACzF,UAAA,oBAAC,gBAAA,EAAe,MAAM,EAAA,CAAG,GAC3B;AAAA,QAEF,UAAU,oBAAC,kBAAA,EAAiB,SAAQ,UAAS,UAAA,CAAsB;AAAA,MAAA;AAAA,MAT9D;AAAA,IAAA;AAAA,EAYX;AAEA,QAAM,QAAQ,UAAU,oBAAC,mBAAA,EAAkB,SAAS,SAAU,UAAA,cAAY,CAAE,IAAuB,YAAA;AAEnG,QAAM,eAAe,eAAe,QAAQ,WAAW,KAAK,QAAQ,GAAG;AACvE,QAAM,eAAe,QAAQ,QAAQ,KAAK,QAAQ,GAAG;AAErD,MAAI,CAAC,OAAQ,CAAC,gBAAgB,CAAC,aAAe,QAAO;AAErD,QAAM,qBACJ;AAEF,SACE,qBAAC,QAAA,EAAK,WAAU,mCACb,UAAA;AAAA,IAAA;AAAA,IAED,qBAAC,QAAA,EAAK,WAAU,oDACb,UAAA;AAAA,MAAA,oCACE,mBAAA,EAAkB,SAAS,EAAE,yBAAyB,GAAG,WAAU,YAClE,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,cAAY,EAAE,yBAAyB;AAAA,UACvC,mBAAiB;AAAA,UACjB,SAAS,CAAC,UAA4B;AACpC,kBAAM,gBAAA;AACN,6BAAiB,IAAI;AAAA,UACvB;AAAA,UACA,WAAW;AAAA,UAEX,8BAAC,gBAAA,EAAe,MAAK,QAAO,MAAM,IAAI,OAAM,QAAA,CAAQ;AAAA,QAAA;AAAA,MAAA,GAExD;AAAA,MAGD,oCACE,mBAAA,EAAkB,SAAS,EAAE,sBAAsB,GAAG,WAAU,YAC/D,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,cAAY,EAAE,sBAAsB;AAAA,UACpC,mBAAiB;AAAA,UACjB,SAAS,CAAC,UAA4B;AACpC,kBAAM,gBAAA;AACN,4BAAgB,IAAI;AAAA,UACtB;AAAA,UACA,WAAW;AAAA,UAEX,8BAAC,gBAAA,EAAe,MAAK,iBAAgB,MAAM,IAAI,OAAM,QAAA,CAAQ;AAAA,QAAA;AAAA,MAAA,EAC/D,CACF;AAAA,IAAA,GAEJ;AAAA,IAEA,qBAAC,UAAA,EAAS,UAAU,MACjB,UAAA;AAAA,MAAA,iBAAiB,eAChB;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAM;AAAA,UACN,UAAU;AAAA,UACV,WAAW;AAAA,UACX,SAAS,MAAM,iBAAiB,KAAK;AAAA,UACrC,QAAQ;AAAA,QAAA;AAAA,MAAA;AAAA,MAIX,gBAAgB,YACf;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAM;AAAA,UACN,UAAU;AAAA,UACV,WAAW;AAAA,UACX,WAAW,SAAS;AAAA,UACpB,aAAa,SAAS;AAAA,UACtB,SAAS,MAAM,gBAAgB,KAAK;AAAA,UACpC,QAAQ,SAAS;AAAA,UACjB,gBAAgB,SAAS;AAAA,QAAA;AAAA,MAAA;AAAA,IAC3B,EAAA,CAEJ;AAAA,EAAA,GACF;AAEJ;AAEA,MAAM,kBAAmD,CAAC,UAAU;AAClE,SAAO,oBAAC,wBAAA,EAAwB,GAAG,MAAA,CAAO;AAC5C;"}
@@ -14,7 +14,7 @@ interface IControlledInputProps extends Omit<React.InputHTMLAttributes<HTMLInput
14
14
  * The label is rendered as the placeholder and as the accessible name, mirroring
15
15
  * ControlledTextarea: a floating label animates onto the border and relies on
16
16
  * pseudo-element border segments to cut a notch, which breaks wherever the border is
17
- * overridden.
17
+ * overridden. A label that stays once the field is filled is `FieldLabel`, written above it.
18
18
  *
19
19
  * Background, border and focus ring come from the form base layer in index.css, so this
20
20
  * component names no colour for them.
@@ -1,6 +1,6 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import classNames from "classnames";
3
- import { twMerge } from "tailwind-merge";
3
+ import { mergeClasses } from "../../helpers/mergeClasses.js";
4
4
  const ControlledInput = ({
5
5
  label,
6
6
  error = false,
@@ -13,7 +13,7 @@ const ControlledInput = ({
13
13
  placeholder,
14
14
  "aria-label": ariaLabel,
15
15
  ...rest
16
- }) => /* @__PURE__ */ jsxs("div", { className: twMerge("w-full min-w-0", containerClassName), children: [
16
+ }) => /* @__PURE__ */ jsxs("div", { className: mergeClasses("w-full min-w-0", containerClassName), children: [
17
17
  /* @__PURE__ */ jsxs("div", { className: "relative", children: [
18
18
  /* @__PURE__ */ jsx(
19
19
  "input",
@@ -22,7 +22,7 @@ const ControlledInput = ({
22
22
  placeholder: placeholder ?? label,
23
23
  "aria-label": ariaLabel ?? label,
24
24
  "aria-invalid": error || void 0,
25
- className: twMerge(
25
+ className: mergeClasses(
26
26
  classNames(
27
27
  "w-full min-w-0 rounded-lg border px-3 py-2.5 text-sm text-foreground transition-colors",
28
28
  "placeholder:text-foreground-faint disabled:cursor-not-allowed disabled:bg-muted",
@@ -36,7 +36,7 @@ const ControlledInput = ({
36
36
  rightSlot && /* @__PURE__ */ jsx(
37
37
  "div",
38
38
  {
39
- className: twMerge(
39
+ className: mergeClasses(
40
40
  "absolute right-3 top-2/4 z-10 flex -translate-y-2/4 items-center gap-x-2",
41
41
  rightSlotClassName
42
42
  ),
@@ -1 +1 @@
1
- {"version":3,"file":"ControlledInput.js","sources":["../../../src/components/Form/ControlledInput.tsx"],"sourcesContent":["import React from 'react';\nimport classNames from 'classnames';\nimport { twMerge } from 'tailwind-merge';\n\ninterface IControlledInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'size'> {\n label?: string;\n error?: boolean;\n errorMessage?: string;\n rightSlot?: React.ReactNode;\n rightSlotClassName?: string;\n className?: string;\n containerClassName?: string;\n /** Reaches the native input, for hosts that must focus or measure it imperatively. */\n inputRef?: React.Ref<HTMLInputElement>;\n}\n\n/**\n * The label is rendered as the placeholder and as the accessible name, mirroring\n * ControlledTextarea: a floating label animates onto the border and relies on\n * pseudo-element border segments to cut a notch, which breaks wherever the border is\n * overridden.\n *\n * Background, border and focus ring come from the form base layer in index.css, so this\n * component names no colour for them.\n */\nconst ControlledInput: React.FC<IControlledInputProps> = ({\n label,\n error = false,\n errorMessage,\n rightSlot,\n rightSlotClassName,\n className,\n containerClassName,\n inputRef,\n placeholder,\n 'aria-label': ariaLabel,\n ...rest\n}) => (\n <div className={twMerge('w-full min-w-0', containerClassName)}>\n <div className=\"relative\">\n <input\n ref={inputRef}\n placeholder={placeholder ?? label}\n aria-label={ariaLabel ?? label}\n aria-invalid={error || undefined}\n className={twMerge(\n classNames(\n 'w-full min-w-0 rounded-lg border px-3 py-2.5 text-sm text-foreground transition-colors',\n 'placeholder:text-foreground-faint disabled:cursor-not-allowed disabled:bg-muted',\n { 'border-danger focus:border-danger': error, 'pr-10': !!rightSlot },\n ),\n className,\n )}\n {...rest}\n />\n\n {rightSlot && (\n <div\n className={twMerge(\n 'absolute right-3 top-2/4 z-10 flex -translate-y-2/4 items-center gap-x-2',\n rightSlotClassName,\n )}\n >\n {rightSlot}\n </div>\n )}\n </div>\n\n {error && errorMessage && <div className=\"mt-1 text-xs text-danger-emphasis\">{errorMessage}</div>}\n </div>\n);\n\nexport default ControlledInput;\n"],"names":[],"mappings":";;;AAyBA,MAAM,kBAAmD,CAAC;AAAA,EACxD;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,GAAG;AACL,2BACG,OAAA,EAAI,WAAW,QAAQ,kBAAkB,kBAAkB,GAC1D,UAAA;AAAA,EAAA,qBAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL,aAAa,eAAe;AAAA,QAC5B,cAAY,aAAa;AAAA,QACzB,gBAAc,SAAS;AAAA,QACvB,WAAW;AAAA,UACT;AAAA,YACE;AAAA,YACA;AAAA,YACA,EAAE,qCAAqC,OAAO,SAAS,CAAC,CAAC,UAAA;AAAA,UAAU;AAAA,UAErE;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,IAGL,aACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAGD,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EACH,GAEJ;AAAA,EAEC,SAAS,gBAAgB,oBAAC,OAAA,EAAI,WAAU,qCAAqC,UAAA,aAAA,CAAa;AAAA,EAAA,CAC7F;"}
1
+ {"version":3,"file":"ControlledInput.js","sources":["../../../src/components/Form/ControlledInput.tsx"],"sourcesContent":["import React from 'react';\nimport classNames from 'classnames';\n\nimport { mergeClasses } from '@/helpers/mergeClasses';\n\ninterface IControlledInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'size'> {\n label?: string;\n error?: boolean;\n errorMessage?: string;\n rightSlot?: React.ReactNode;\n rightSlotClassName?: string;\n className?: string;\n containerClassName?: string;\n /** Reaches the native input, for hosts that must focus or measure it imperatively. */\n inputRef?: React.Ref<HTMLInputElement>;\n}\n\n/**\n * The label is rendered as the placeholder and as the accessible name, mirroring\n * ControlledTextarea: a floating label animates onto the border and relies on\n * pseudo-element border segments to cut a notch, which breaks wherever the border is\n * overridden. A label that stays once the field is filled is `FieldLabel`, written above it.\n *\n * Background, border and focus ring come from the form base layer in index.css, so this\n * component names no colour for them.\n */\nconst ControlledInput: React.FC<IControlledInputProps> = ({\n label,\n error = false,\n errorMessage,\n rightSlot,\n rightSlotClassName,\n className,\n containerClassName,\n inputRef,\n placeholder,\n 'aria-label': ariaLabel,\n ...rest\n}) => (\n <div className={mergeClasses('w-full min-w-0', containerClassName)}>\n <div className=\"relative\">\n <input\n ref={inputRef}\n placeholder={placeholder ?? label}\n aria-label={ariaLabel ?? label}\n aria-invalid={error || undefined}\n className={mergeClasses(\n classNames(\n 'w-full min-w-0 rounded-lg border px-3 py-2.5 text-sm text-foreground transition-colors',\n 'placeholder:text-foreground-faint disabled:cursor-not-allowed disabled:bg-muted',\n { 'border-danger focus:border-danger': error, 'pr-10': !!rightSlot },\n ),\n className,\n )}\n {...rest}\n />\n\n {rightSlot && (\n <div\n className={mergeClasses(\n 'absolute right-3 top-2/4 z-10 flex -translate-y-2/4 items-center gap-x-2',\n rightSlotClassName,\n )}\n >\n {rightSlot}\n </div>\n )}\n </div>\n\n {error && errorMessage && <div className=\"mt-1 text-xs text-danger-emphasis\">{errorMessage}</div>}\n </div>\n);\n\nexport default ControlledInput;\n"],"names":[],"mappings":";;;AA0BA,MAAM,kBAAmD,CAAC;AAAA,EACxD;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,GAAG;AACL,2BACG,OAAA,EAAI,WAAW,aAAa,kBAAkB,kBAAkB,GAC/D,UAAA;AAAA,EAAA,qBAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL,aAAa,eAAe;AAAA,QAC5B,cAAY,aAAa;AAAA,QACzB,gBAAc,SAAS;AAAA,QACvB,WAAW;AAAA,UACT;AAAA,YACE;AAAA,YACA;AAAA,YACA,EAAE,qCAAqC,OAAO,SAAS,CAAC,CAAC,UAAA;AAAA,UAAU;AAAA,UAErE;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,IAGL,aACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAGD,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EACH,GAEJ;AAAA,EAEC,SAAS,gBAAgB,oBAAC,OAAA,EAAI,WAAU,qCAAqC,UAAA,aAAA,CAAa;AAAA,EAAA,CAC7F;"}
@@ -457,7 +457,7 @@ function ControlledSelect({
457
457
  isSelected && /* @__PURE__ */ jsx("span", { className: "absolute inset-y-1 left-0 w-0.5 rounded-full bg-brand" }),
458
458
  multiple && // The option itself carries aria-selected; the checkbox is only its picture.
459
459
  /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "pointer-events-none", children: /* @__PURE__ */ jsx(ControlledCheckbox, { checked: isSelected, onChange: () => {
460
- } }) }),
460
+ }, tabIndex: -1 }) }),
461
461
  option.tooltip && !isDisabledWithReason && /* @__PURE__ */ jsx(ControlledTooltip, { content: option.tooltip, className: "w-full max-w-72", children: /* @__PURE__ */ jsx(MaterialSymbol, { icon: "info", size: 15, color: "rgb(var(--color-foreground-subtle))", className: "mr-1" }) }),
462
462
  option.swatch && /* @__PURE__ */ jsx(
463
463
  "span",
@@ -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';\n\nconst isCoarsePointer = (): boolean =>\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(pointer: coarse)').matches;\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) return;\n onOpen?.();\n // Opening with the pointer lands on the search field too, so typing right away filters\n // instead of being lost. Skipped on touch, where focusing would pop the keyboard over the list.\n if (searchable && !isCoarsePointer()) {\n pendingFocusIndexRef.current = -1;\n setFocusRequest((request) => request + 1);\n }\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';\n\nconst isCoarsePointer = (): boolean =>\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(pointer: coarse)').matches;\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={() => {}} tabIndex={-1} />\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) return;\n onOpen?.();\n // Opening with the pointer lands on the search field too, so typing right away filters\n // instead of being lost. Skipped on touch, where focusing would pop the keyboard over the list.\n if (searchable && !isCoarsePointer()) {\n pendingFocusIndexRef.current = -1;\n setFocusRequest((request) => request + 1);\n }\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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"}