@mortenbrudvik/waveui 0.15.0 → 0.17.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 (188) hide show
  1. package/README.md +339 -40
  2. package/dist/components/data-display/List.cjs +1 -1
  3. package/dist/components/data-display/List.cjs.map +1 -1
  4. package/dist/components/data-display/List.mjs +405 -219
  5. package/dist/components/data-display/List.mjs.map +1 -1
  6. package/dist/components/data-display/List.registry.cjs +1 -1
  7. package/dist/components/data-display/List.registry.cjs.map +1 -1
  8. package/dist/components/data-display/List.registry.mjs +12 -6
  9. package/dist/components/data-display/List.registry.mjs.map +1 -1
  10. package/dist/components/input/Combobox.cjs +1 -1
  11. package/dist/components/input/Combobox.cjs.map +1 -1
  12. package/dist/components/input/Combobox.mjs +163 -148
  13. package/dist/components/input/Combobox.mjs.map +1 -1
  14. package/dist/components/input/Dropdown.cjs +1 -1
  15. package/dist/components/input/Dropdown.cjs.map +1 -1
  16. package/dist/components/input/Dropdown.mjs +132 -117
  17. package/dist/components/input/Dropdown.mjs.map +1 -1
  18. package/dist/components/input/Label.cjs +1 -1
  19. package/dist/components/input/Label.cjs.map +1 -1
  20. package/dist/components/input/Label.mjs +1 -0
  21. package/dist/components/input/Label.mjs.map +1 -1
  22. package/dist/components/input/Listbox.cjs +1 -1
  23. package/dist/components/input/Listbox.cjs.map +1 -1
  24. package/dist/components/input/Listbox.mjs +90 -78
  25. package/dist/components/input/Listbox.mjs.map +1 -1
  26. package/dist/components/input/Option.cjs +1 -1
  27. package/dist/components/input/Option.cjs.map +1 -1
  28. package/dist/components/input/Option.data.cjs +2 -0
  29. package/dist/components/input/Option.data.cjs.map +1 -0
  30. package/dist/components/input/Option.data.mjs +114 -0
  31. package/dist/components/input/Option.data.mjs.map +1 -0
  32. package/dist/components/input/Option.mjs +21 -17
  33. package/dist/components/input/Option.mjs.map +1 -1
  34. package/dist/components/layout/FlatTree.cjs +2 -0
  35. package/dist/components/layout/FlatTree.cjs.map +1 -0
  36. package/dist/components/layout/FlatTree.context.cjs +2 -0
  37. package/dist/components/layout/FlatTree.context.cjs.map +1 -0
  38. package/dist/components/layout/FlatTree.context.mjs +20 -0
  39. package/dist/components/layout/FlatTree.context.mjs.map +1 -0
  40. package/dist/components/layout/FlatTree.item.cjs +2 -0
  41. package/dist/components/layout/FlatTree.item.cjs.map +1 -0
  42. package/dist/components/layout/FlatTree.item.mjs +90 -0
  43. package/dist/components/layout/FlatTree.item.mjs.map +1 -0
  44. package/dist/components/layout/FlatTree.mjs +276 -0
  45. package/dist/components/layout/FlatTree.mjs.map +1 -0
  46. package/dist/components/layout/Tree.core.cjs +1 -1
  47. package/dist/components/layout/Tree.core.cjs.map +1 -1
  48. package/dist/components/layout/Tree.core.mjs +166 -165
  49. package/dist/components/layout/Tree.core.mjs.map +1 -1
  50. package/dist/components/layout/Tree.selection.cjs +1 -1
  51. package/dist/components/layout/Tree.selection.cjs.map +1 -1
  52. package/dist/components/layout/Tree.selection.mjs +11 -57
  53. package/dist/components/layout/Tree.selection.mjs.map +1 -1
  54. package/dist/components/layout/useFlatTree.cjs +2 -0
  55. package/dist/components/layout/useFlatTree.cjs.map +1 -0
  56. package/dist/components/layout/useFlatTree.mjs +83 -0
  57. package/dist/components/layout/useFlatTree.mjs.map +1 -0
  58. package/dist/components/portal/Portal.cjs +1 -1
  59. package/dist/components/portal/Portal.cjs.map +1 -1
  60. package/dist/components/portal/Portal.mjs +12 -11
  61. package/dist/components/portal/Portal.mjs.map +1 -1
  62. package/dist/components/provider/WaveProvider.cjs +1 -1
  63. package/dist/components/provider/WaveProvider.cjs.map +1 -1
  64. package/dist/components/provider/WaveProvider.mjs +59 -35
  65. package/dist/components/provider/WaveProvider.mjs.map +1 -1
  66. package/dist/components/table/DataGrid.cjs +1 -1
  67. package/dist/components/table/DataGrid.cjs.map +1 -1
  68. package/dist/components/table/DataGrid.context.cjs +2 -0
  69. package/dist/components/table/DataGrid.context.cjs.map +1 -0
  70. package/dist/components/table/DataGrid.context.mjs +74 -0
  71. package/dist/components/table/DataGrid.context.mjs.map +1 -0
  72. package/dist/components/table/DataGrid.header.cjs +2 -0
  73. package/dist/components/table/DataGrid.header.cjs.map +1 -0
  74. package/dist/components/table/DataGrid.header.mjs +168 -0
  75. package/dist/components/table/DataGrid.header.mjs.map +1 -0
  76. package/dist/components/table/DataGrid.mjs +488 -591
  77. package/dist/components/table/DataGrid.mjs.map +1 -1
  78. package/dist/components/table/DataGrid.sizing.cjs +2 -0
  79. package/dist/components/table/DataGrid.sizing.cjs.map +1 -0
  80. package/dist/components/table/DataGrid.sizing.mjs +187 -0
  81. package/dist/components/table/DataGrid.sizing.mjs.map +1 -0
  82. package/dist/components/table/DataGrid.store.cjs +2 -0
  83. package/dist/components/table/DataGrid.store.cjs.map +1 -0
  84. package/dist/components/table/DataGrid.store.mjs +108 -0
  85. package/dist/components/table/DataGrid.store.mjs.map +1 -0
  86. package/dist/components/table/DataGrid.window.cjs +2 -0
  87. package/dist/components/table/DataGrid.window.cjs.map +1 -0
  88. package/dist/components/table/DataGrid.window.mjs +165 -0
  89. package/dist/components/table/DataGrid.window.mjs.map +1 -0
  90. package/dist/components/table/Table.cjs +1 -1
  91. package/dist/components/table/Table.cjs.map +1 -1
  92. package/dist/components/table/Table.mjs +74 -72
  93. package/dist/components/table/Table.mjs.map +1 -1
  94. package/dist/components/table/Table.resize.cjs +2 -0
  95. package/dist/components/table/Table.resize.cjs.map +1 -0
  96. package/dist/components/table/Table.resize.mjs +98 -0
  97. package/dist/components/table/Table.resize.mjs.map +1 -0
  98. package/dist/components/table/useGridNavigation.cjs +1 -1
  99. package/dist/components/table/useGridNavigation.cjs.map +1 -1
  100. package/dist/components/table/useGridNavigation.mjs +343 -140
  101. package/dist/components/table/useGridNavigation.mjs.map +1 -1
  102. package/dist/components/table/useTableColumnSizing.cjs +2 -0
  103. package/dist/components/table/useTableColumnSizing.cjs.map +1 -0
  104. package/dist/components/table/useTableColumnSizing.mjs +76 -0
  105. package/dist/components/table/useTableColumnSizing.mjs.map +1 -0
  106. package/dist/components/table/useTableFeatures.cjs +2 -0
  107. package/dist/components/table/useTableFeatures.cjs.map +1 -0
  108. package/dist/components/table/useTableFeatures.mjs +110 -0
  109. package/dist/components/table/useTableFeatures.mjs.map +1 -0
  110. package/dist/components/table/useTableSelection.cjs +2 -0
  111. package/dist/components/table/useTableSelection.cjs.map +1 -0
  112. package/dist/components/table/useTableSelection.mjs +39 -0
  113. package/dist/components/table/useTableSelection.mjs.map +1 -0
  114. package/dist/components/table/useTableSort.cjs +2 -0
  115. package/dist/components/table/useTableSort.cjs.map +1 -0
  116. package/dist/components/table/useTableSort.mjs +58 -0
  117. package/dist/components/table/useTableSort.mjs.map +1 -0
  118. package/dist/components/typography/Text.cjs +1 -1
  119. package/dist/components/typography/Text.cjs.map +1 -1
  120. package/dist/components/typography/Text.mjs +11 -7
  121. package/dist/components/typography/Text.mjs.map +1 -1
  122. package/dist/hooks/useActiveDescendant.cjs +1 -1
  123. package/dist/hooks/useActiveDescendant.cjs.map +1 -1
  124. package/dist/hooks/useActiveDescendant.mjs +33 -25
  125. package/dist/hooks/useActiveDescendant.mjs.map +1 -1
  126. package/dist/hooks/useListbox.cjs +1 -1
  127. package/dist/hooks/useListbox.cjs.map +1 -1
  128. package/dist/hooks/useListbox.mjs +140 -130
  129. package/dist/hooks/useListbox.mjs.map +1 -1
  130. package/dist/hooks/useRovingTabIndex.cjs +1 -1
  131. package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
  132. package/dist/hooks/useRovingTabIndex.mjs +1 -1
  133. package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
  134. package/dist/hooks/useSelection.cjs +2 -0
  135. package/dist/hooks/useSelection.cjs.map +1 -0
  136. package/dist/hooks/useSelection.mjs +57 -0
  137. package/dist/hooks/useSelection.mjs.map +1 -0
  138. package/dist/hooks/useVirtualWindow.cjs +2 -0
  139. package/dist/hooks/useVirtualWindow.cjs.map +1 -0
  140. package/dist/hooks/useVirtualWindow.mjs +102 -0
  141. package/dist/hooks/useVirtualWindow.mjs.map +1 -0
  142. package/dist/index.cjs +1 -1
  143. package/dist/index.d.cts +1799 -63
  144. package/dist/index.d.ts +1799 -63
  145. package/dist/index.mjs +150 -136
  146. package/dist/lib/brand.cjs +2 -0
  147. package/dist/lib/brand.cjs.map +1 -0
  148. package/dist/lib/brand.mjs +358 -0
  149. package/dist/lib/brand.mjs.map +1 -0
  150. package/dist/lib/classNames.cjs +1 -1
  151. package/dist/lib/classNames.cjs.map +1 -1
  152. package/dist/lib/classNames.mjs +68 -49
  153. package/dist/lib/classNames.mjs.map +1 -1
  154. package/dist/lib/cn.cjs +1 -1
  155. package/dist/lib/cn.cjs.map +1 -1
  156. package/dist/lib/cn.mjs +5 -1
  157. package/dist/lib/cn.mjs.map +1 -1
  158. package/dist/lib/columnSizing.cjs +2 -0
  159. package/dist/lib/columnSizing.cjs.map +1 -0
  160. package/dist/lib/columnSizing.mjs +27 -0
  161. package/dist/lib/columnSizing.mjs.map +1 -0
  162. package/dist/lib/flatTree.cjs +2 -0
  163. package/dist/lib/flatTree.cjs.map +1 -0
  164. package/dist/lib/flatTree.mjs +118 -0
  165. package/dist/lib/flatTree.mjs.map +1 -0
  166. package/dist/lib/selection.cjs +2 -0
  167. package/dist/lib/selection.cjs.map +1 -0
  168. package/dist/lib/selection.mjs +28 -0
  169. package/dist/lib/selection.mjs.map +1 -0
  170. package/dist/lib/tokens.cjs +2 -0
  171. package/dist/lib/tokens.cjs.map +1 -0
  172. package/dist/lib/tokens.mjs +43 -0
  173. package/dist/lib/tokens.mjs.map +1 -0
  174. package/dist/lib/treeCascade.cjs +2 -0
  175. package/dist/lib/treeCascade.cjs.map +1 -0
  176. package/dist/lib/treeCascade.mjs +52 -0
  177. package/dist/lib/treeCascade.mjs.map +1 -0
  178. package/dist/lib/virtual.cjs +2 -0
  179. package/dist/lib/virtual.cjs.map +1 -0
  180. package/dist/lib/virtual.mjs +54 -0
  181. package/dist/lib/virtual.mjs.map +1 -0
  182. package/dist/lib/waveTokens.cjs +2 -0
  183. package/dist/lib/waveTokens.cjs.map +1 -0
  184. package/dist/lib/waveTokens.mjs +24 -0
  185. package/dist/lib/waveTokens.mjs.map +1 -0
  186. package/dist/styles.css +1 -1
  187. package/package.json +3 -1
  188. package/src/styles/tokens.css +210 -10
@@ -1 +1 @@
1
- {"version":3,"file":"Option.mjs","names":["useId","_Fragment","useId$1","React","OptionCheckContext","OPTION_CLASSES","cn","OptionGroupMembers","listener","value","count","store","OptionGroupContext","OptionGroupHiddenContext","useOptionGroupMembership","groups","removes","group","remove","DISABLED_BOX_FORCED_COLORS","DISABLED_GLYPH_FORCED_COLORS","renderCheck","multiselect","classes","optionClassNames","selected","glyph","CheckIcon","renderSlot","boxClasses","disabled","forcedColors","glyphClasses","OptionImpl","rest","props","showCheck","groupHidden","useListboxOption","hidden","ref","optionRef","selectOption","pressOption","highlightOption","optionAttributes","optionProps","checkIconRenders","checkIcon","slotRendersContent","checkIconEmpty","warnOnce","composeEventHandlers","onClick","onMouseDown","onPointerMove","className","children","MemoOption","Option","ELEMENT_NODE","TEXT_NODE","nameText","node","element","ownLabel","text","child","groupHasName","labelledBy","labelId","ariaLabel","label","heading","UNNAMED_GROUP_WARNING","OptionGroupImpl","ariaLabelledBy","ListboxContext","parentGroups","hiddenByConsumer","members","subscribe","unsubscribeMembers","unsubscribeStore","empty","hasLabel","headingRef","isDev","optionGroupClassNames","materialiseSlotContent","OptionGroup","ListboxProvider","useListboxPopup","options","surfaceElementRef","usePopupPosition","surfaceOpen","resolvePositioning","positioning","useDismiss","onDismiss","reason","rootRef","useMergedRefs","setFloating","preventMouseDown","ListboxSurface","listRefProp","listMouseDown","listRest","listProps","listboxProps","listbox","listRef","list","expanded","listboxSurfaceClassNames","listClassName","emptyContent","Fragment","Portal","surfaceRef","floatingProps","surfaceClassName"],"sources":["../../../src/components/input/Option.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n listboxSurfaceClassNames,\n optionClassNames,\n optionGroupClassNames,\n} from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { hasWarned, isDev, warnOnce } from '../../lib/dev';\nimport { CheckIcon } from '../../lib/icons';\nimport { materialiseSlotContent, renderSlot, slotRendersContent, type Slot } from '../../lib/slot';\nimport { forcedColors } from '../../lib/styles';\nimport type { PopupPositioningOptions } from '../../lib/types';\nimport { useId } from '../../hooks/useId';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useDismiss } from '../../hooks/useDismiss';\nimport type { DismissReason } from '../../hooks/useDismiss';\nimport { resolvePositioning, usePopupPosition } from '../../hooks/usePopupPosition';\nimport {\n ListboxContext,\n markListboxElement,\n useListboxOption,\n type ListboxContextValue,\n type ListboxStore,\n type UseListboxResult,\n} from '../../hooks/useListbox';\nimport { Portal } from '../portal/Portal';\n\n/* ------------------------------------------------------------------ */\n/* Option */\n/* ------------------------------------------------------------------ */\n\n/**\n * Props of {@link Option}, an option of a listbox (Listbox, Combobox, Dropdown or a custom\n * picker's list).\n */\nexport interface OptionProps extends Omit<React.LiHTMLAttributes<HTMLLIElement>, 'value'> {\n /** Value associated with this option. Unique within its listbox. */\n value: string;\n /**\n * Text shown in the combobox (Combobox input, Dropdown trigger) when this option is selected.\n * Defaults to `textValue`, then the option's text content, then `value`. Pass it when the\n * children are not plain text (icons, custom components).\n */\n label?: string;\n /** Text matched by typeahead and filtering instead of the label. */\n textValue?: string;\n /**\n * Whether the option is disabled: it stays in the list but can never be selected (a click, Enter\n * and Space do nothing). Keyboard navigation and typeahead skip it, unless the listbox keeps\n * disabled options focusable (`disabledOptionsFocusable`), where they reach it. It is drawn in\n * the muted text colour, its check included: in a multi-select list the checkbox square takes\n * that colour instead of the brand colour, checked or not.\n * @default false\n */\n disabled?: boolean;\n /**\n * Replaces the check glyph that marks the option while it is selected (decorative,\n * `aria-hidden`); in a multi-select list the glyph is drawn inside the option's 16px checkbox\n * square. The check is a required indicator, the sign of the selection that does not rely on\n * colour: `null` and `undefined` keep the default glyph, and so does a value that renders\n * nothing (`false`, `''`, an empty array), which also logs a development warning. Unlike\n * `Combobox.expandIcon`, a value that renders nothing does not hide the indicator (Fluent's\n * `checkIcon={null}` removes it).\n * @default a check mark\n */\n checkIcon?: Slot<'span'>;\n /**\n * Hides the option, like a native `<option hidden>`: it is not shown, keyboard navigation and\n * typeahead skip it, and it never becomes the active option. Its label stays known, so a\n * selected hidden option (a placeholder) still shows in the combobox. The options of a hidden\n * `OptionGroup` are hidden the same way.\n * @default false\n */\n hidden?: boolean;\n /** Ref to the option `<li>` element. */\n ref?: React.Ref<HTMLLIElement>;\n}\n\n/** Whether options draw the selected check mark (P05-internal; TagPicker lists no selected options). */\nconst OptionCheckContext = React.createContext(true);\nOptionCheckContext.displayName = 'OptionCheckContext';\n\n/*\n * State is exposed as data attributes (C-CLASS): `data-active` (keyboard/pointer highlight),\n * `data-selected`, `data-disabled`. State classes come before the consumer's `className` in `cn()`.\n *\n * Backgrounds (input-pickers#20): one unconditional `bg-(--option-bg)` paints the option, and the\n * hover/selected/active variants only set `--option-bg`. A variant that set `background-color`\n * itself (class + attribute or pseudo-class) would out-specify a consumer's plain `bg-*` class in\n * the cascade even though `cn()` keeps it; instead tailwind-merge replaces `bg-(--option-bg)` with\n * the consumer's class, which is then the only background declaration on the option. A consumer\n * `data-[active]:bg-…` / `data-[selected]:bg-…` restyles a single state (it out-specifies the\n * unconditional reader). The active outline is the focus indicator and stays a state variant.\n *\n * A filtered-out option carries the `hidden` attribute; base.css's scoped `[hidden]` rule hides\n * it over `flex` and over a consumer's display class.\n */\nconst OPTION_CLASSES = cn(\n 'flex cursor-pointer select-none items-center gap-2 px-3 py-1.5 text-body-1 text-foreground',\n 'bg-(--option-bg) [--option-bg:transparent]',\n 'not-disabled:not-aria-disabled:hover:[--option-bg:var(--wave-subtle-hover)]',\n 'data-[selected]:[--option-bg:var(--wave-subtle-selected)]',\n 'data-[active]:[--option-bg:var(--wave-subtle-hover)]',\n 'data-[active]:outline-2 data-[active]:-outline-offset-2 data-[active]:outline-ring',\n 'aria-disabled:cursor-not-allowed aria-disabled:text-muted-foreground',\n);\n\n/**\n * The values of the options rendered inside an `OptionGroup`, whatever wraps them (custom\n * components, Fragments, nested groups): each option adds its value from a layout effect.\n */\nclass OptionGroupMembers {\n private readonly counts = new Map<string, number>();\n private readonly listeners = new Set<() => void>();\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n add(value: string): () => void {\n this.counts.set(value, (this.counts.get(value) ?? 0) + 1);\n this.notify();\n return () => {\n const count = (this.counts.get(value) ?? 1) - 1;\n if (count > 0) this.counts.set(value, count);\n else this.counts.delete(value);\n this.notify();\n };\n }\n\n /** At least one option, and every one of them is hidden (filtered out, or by the consumer). */\n allHidden(store: ListboxStore | undefined): boolean {\n if (store === undefined || this.counts.size === 0) return false;\n for (const value of this.counts.keys()) if (!store.isHidden(value)) return false;\n return true;\n }\n\n private notify(): void {\n for (const listener of [...this.listeners]) listener();\n }\n}\n\n/** The groups around an option, outermost first (P05-internal). */\nconst OptionGroupContext = React.createContext<readonly OptionGroupMembers[]>([]);\nOptionGroupContext.displayName = 'OptionGroupContext';\n\n/** A group around the option has the consumer's `hidden` attribute (P05-internal). */\nconst OptionGroupHiddenContext = React.createContext(false);\nOptionGroupHiddenContext.displayName = 'OptionGroupHiddenContext';\n\n/** Adds an option's value to every group around it while the option is mounted. */\nfunction useOptionGroupMembership(value: string): void {\n const groups = React.useContext(OptionGroupContext);\n React.useLayoutEffect(() => {\n if (groups.length === 0) return;\n const removes = groups.map((group) => group.add(value));\n return () => {\n for (const remove of removes) remove();\n };\n }, [groups, value]);\n}\n\n/*\n * Forced colours of a disabled option's box, as Checkbox draws a disabled box: GrayText on Canvas\n * for the square and its glyph, without the Highlight background of `forcedColors.selectedLeaf`.\n */\nconst DISABLED_BOX_FORCED_COLORS = 'forced-colors:border-[GrayText] forced-colors:bg-[Canvas]';\nconst DISABLED_GLYPH_FORCED_COLORS =\n 'forced-colors:text-[GrayText] forced-colors:forced-color-adjust-none';\n\n/** What the check column of an option draws (see {@link renderCheck}). */\ninterface CheckState {\n selected: boolean;\n multiselect: boolean;\n disabled: boolean;\n}\n\n/**\n * The check column of an option. Single-select: the check glyph, kept in its place but not drawn\n * while the option is not selected, so the option texts line up. Multi-select: a 16px checkbox\n * square in Checkbox's colours, with the glyph inside only while selected; as a leaf indicator it\n * takes `forcedColors.selectedLeaf` while checked. A disabled option's square follows the row, as\n * the single-select glyph does: its muted text colour draws the square and the glyph, in place of\n * the brand colour. `glyph` is the consumer's `checkIcon` when it renders content, else\n * `undefined` for the default glyph.\n */\nfunction renderCheck(\n glyph: Slot<'span'> | undefined,\n { selected, multiselect, disabled }: CheckState,\n): React.ReactNode {\n if (!multiselect) {\n const classes = cn(optionClassNames.checkIcon, 'shrink-0', !selected && 'invisible');\n return glyph === undefined ? (\n <CheckIcon className={classes} />\n ) : (\n renderSlot(glyph, 'span', cn('inline-flex', classes), { 'aria-hidden': true })\n );\n }\n // One class set per state, so a disabled box never carries the brand classes it replaces.\n let boxClasses: string;\n if (disabled) {\n boxClasses = cn('border-current bg-transparent', DISABLED_BOX_FORCED_COLORS);\n } else if (selected) {\n boxClasses = cn('border-primary bg-primary text-primary-foreground', forcedColors.selectedLeaf);\n } else {\n boxClasses = cn('border-stroke-accessible bg-transparent', forcedColors.control);\n }\n const glyphClasses = disabled ? DISABLED_GLYPH_FORCED_COLORS : undefined;\n return (\n <span\n aria-hidden=\"true\"\n data-wave-option-box=\"\"\n className={cn(\n optionClassNames.indicator,\n 'flex h-4 w-4 shrink-0 items-center justify-center rounded-xs border',\n boxClasses,\n )}\n >\n {selected &&\n (glyph === undefined ? (\n <CheckIcon size={12} className={cn(optionClassNames.checkIcon, glyphClasses)} />\n ) : (\n renderSlot(\n glyph,\n 'span',\n cn(optionClassNames.checkIcon, 'inline-flex shrink-0', glyphClasses),\n {\n 'aria-hidden': true,\n },\n )\n ))}\n </span>\n );\n}\n\nfunction OptionImpl(props: OptionProps) {\n const {\n value,\n label,\n textValue,\n disabled = false,\n hidden = false,\n checkIcon,\n className,\n children,\n onClick,\n onMouseDown,\n onPointerMove,\n ref,\n ...rest\n } = props;\n const showCheck = React.useContext(OptionCheckContext);\n const groupHidden = React.useContext(OptionGroupHiddenContext);\n // A consumer-hidden option is not navigable; optionProps renders `hidden`.\n const { selected, multiselect, optionProps } = useListboxOption<HTMLLIElement>(\n { value, label, textValue, disabled, hidden: hidden || groupHidden },\n ref,\n );\n useOptionGroupMembership(value);\n const {\n ref: optionRef,\n onClick: selectOption,\n // Standalone mode only: the pointer press that focuses the list.\n onMouseDown: pressOption,\n onPointerMove: highlightOption,\n ...optionAttributes\n } = optionProps;\n\n // The check is a required indicator (C-SLOTS): a `checkIcon` that renders nothing keeps the\n // default glyph and warns once.\n const checkIconRenders = checkIcon != null && slotRendersContent(checkIcon);\n const checkIconEmpty = checkIcon != null && !checkIconRenders;\n React.useEffect(() => {\n if (checkIconEmpty) {\n warnOnce(\n 'Option:checkIcon-empty',\n 'Option: `checkIcon` renders nothing, so the default check shows: a selected option must show its state. Pass a glyph, or leave it unset.',\n );\n }\n }, [checkIconEmpty]);\n\n return (\n <li\n data-value={value}\n {...rest}\n {...optionAttributes}\n ref={optionRef}\n onClick={composeEventHandlers(onClick, selectOption)}\n onMouseDown={composeEventHandlers(onMouseDown, pressOption)}\n onPointerMove={composeEventHandlers(onPointerMove, highlightOption)}\n className={cn(\n optionClassNames.root,\n OPTION_CLASSES,\n // While a multi-select option draws its box, the box carries the state, and\n // `forcedColors.selectedContainer` would draw every selected option like the active one.\n selected && !(multiselect && showCheck) && forcedColors.selectedContainer,\n className,\n )}\n >\n {showCheck &&\n renderCheck(checkIconRenders ? checkIcon : undefined, { selected, multiselect, disabled })}\n <span className={cn(optionClassNames.content, 'min-w-0 flex-1')}>{children ?? value}</span>\n </li>\n );\n}\nOptionImpl.displayName = 'Option';\n\nconst MemoOption = /* @__PURE__ */ React.memo(OptionImpl);\nMemoOption.displayName = 'Option';\n\n/**\n * An option of a listbox: a `Listbox`, `Combobox` or `Dropdown` (and `TagPicker`'s generated\n * list), or a custom picker's list, rendered through `ListboxSurface` or under a\n * `ListboxProvider`. Renders `<li role=\"option\">` with a stable id (`aria-activedescendant`\n * target), `aria-selected`, a check mark while selected (`checkIcon` replaces it; in a\n * multi-select list it sits in a checkbox square) and `data-active`/`data-selected`/\n * `data-disabled` attributes for styling.\n *\n * Options register with the surrounding listbox (in DOM order, groups included), so they can be\n * wrapped, grouped or rendered conditionally. The option is memoized: moving the highlight\n * re-renders only the previously and the newly active option.\n *\n * Styling: `className` comes last. A plain background class (`className=\"bg-primary\"`) replaces\n * the built-in hover, selected and active backgrounds in every state. To restyle one state only,\n * use its data variant (`data-[active]:bg-…`, `data-[selected]:bg-…`). The active option keeps\n * its focus outline.\n *\n * Use it inside a listbox only; it throws in development elsewhere.\n */\nexport const Option: React.NamedExoticComponent<OptionProps> = /* @__PURE__ */ markListboxElement(\n MemoOption,\n 'option',\n);\n\n/* ------------------------------------------------------------------ */\n/* OptionGroup */\n/* ------------------------------------------------------------------ */\n\n/**\n * Props of {@link OptionGroup}. `aria-label` and `aria-labelledby` go to the group's\n * `role=\"group\"` list; the other props go to its `<li role=\"presentation\">` item.\n */\nexport interface OptionGroupProps extends React.LiHTMLAttributes<HTMLLIElement> {\n /**\n * The group's heading, which names the group. Keep it text (an icon next to the text is fine): a\n * label cannot be interactive, since nothing in it is reachable inside a listbox. Without a\n * label no heading renders; name the group with `aria-label` or `aria-labelledby` then. A group\n * without a name logs a development warning.\n */\n label?: React.ReactNode;\n /**\n * Names the group's list in place of the label (the heading still shows). A prop that holds\n * `undefined`, as from a wrapper that forwards it, leaves the label in charge.\n */\n 'aria-label'?: string;\n /**\n * Ids of the elements that name the group's list, in place of the label (the heading still\n * shows). A prop that holds `undefined` leaves the label in charge.\n */\n 'aria-labelledby'?: string;\n /**\n * Hides the group and every option in it (see `Option`'s `hidden`): keyboard navigation and\n * typeahead skip its options.\n * @default false\n */\n hidden?: boolean;\n /** Ref to the group's `<li role=\"presentation\">` element. */\n ref?: React.Ref<HTMLLIElement>;\n}\n\nconst ELEMENT_NODE = 1;\nconst TEXT_NODE = 3;\n\n/**\n * The text a heading gives the name of its group, for the development check of `OptionGroup`: its\n * text without `aria-hidden` or `hidden` parts, where an element's `aria-label` or an image's `alt`\n * stands for its content.\n */\nfunction nameText(node: Node | null): string {\n if (node === null) return '';\n if (node.nodeType === TEXT_NODE) return node.textContent ?? '';\n if (node.nodeType !== ELEMENT_NODE) return '';\n const element = node as Element;\n if (element.getAttribute('aria-hidden') === 'true' || element.hasAttribute('hidden')) return '';\n const ownLabel = element.getAttribute('aria-label')?.trim();\n if (ownLabel) return ownLabel;\n if (element.localName === 'img') return element.getAttribute('alt') ?? '';\n let text = '';\n for (const child of Array.from(element.childNodes)) text += nameText(child);\n return text;\n}\n\n/**\n * Whether a group's list has a name, for the development check of `OptionGroup`, in the order the\n * name is computed: a consumer `aria-labelledby` that is not blank (its presence counts; the\n * elements it names are not read), else a non-blank `aria-label`, else the heading that labels the\n * list. A string or number label is its own text; only an element label is read from the rendered\n * heading ({@link nameText}).\n */\nfunction groupHasName(\n label: React.ReactNode,\n ariaLabel: string | undefined,\n labelledBy: string | undefined,\n labelId: string,\n heading: HTMLElement | null,\n): boolean {\n if (labelledBy !== undefined && labelledBy !== labelId && labelledBy.trim() !== '') return true;\n if (ariaLabel !== undefined && ariaLabel.trim() !== '') return true;\n if (labelledBy !== labelId) return false;\n if (typeof label === 'string' || typeof label === 'number') return String(label).trim() !== '';\n return nameText(heading).trim() !== '';\n}\n\nconst UNNAMED_GROUP_WARNING = 'OptionGroup:unnamed';\n\nfunction OptionGroupImpl({\n label,\n className,\n children,\n hidden,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ref,\n ...rest\n}: OptionGroupProps) {\n const labelId = useId('option-group');\n const store = React.useContext(ListboxContext)?.store;\n const parentGroups = React.useContext(OptionGroupContext);\n const hiddenByConsumer = React.useContext(OptionGroupHiddenContext) || !!hidden;\n const [members] = React.useState(() => new OptionGroupMembers());\n const groups = React.useMemo(() => [...parentGroups, members], [parentGroups, members]);\n const subscribe = React.useCallback(\n (listener: () => void) => {\n const unsubscribeMembers = members.subscribe(listener);\n const unsubscribeStore = store?.subscribe(listener);\n return () => {\n unsubscribeMembers();\n unsubscribeStore?.();\n };\n },\n [members, store],\n );\n // Hidden while every option inside it is filtered out or hidden, also options wrapped in a\n // component (the options register with the group; re-read when they do and when the listbox\n // state changes).\n // The server render and the first client render show the group: no option has registered yet.\n const empty = React.useSyncExternalStore(\n subscribe,\n () => members.allHidden(store),\n () => false,\n );\n\n // The heading renders only for a label that renders content, so the list never points at an\n // empty heading. A consumer name wins over the heading; a prop that holds `undefined` (a wrapper\n // forwarding it) is no name of the consumer's.\n const hasLabel = slotRendersContent(label);\n const labelledBy = ariaLabelledBy ?? (ariaLabel === undefined && hasLabel ? labelId : undefined);\n\n // C-DEV: warn once when nothing names the group, checked again whenever the label, the\n // consumer `aria-label` or the resolved `aria-labelledby` changes.\n const headingRef = React.useRef<HTMLDivElement | null>(null);\n React.useEffect(() => {\n if (!isDev || hasWarned(UNNAMED_GROUP_WARNING)) return;\n if (groupHasName(label, ariaLabel, labelledBy, labelId, headingRef.current)) return;\n warnOnce(\n UNNAMED_GROUP_WARNING,\n 'OptionGroup: the group has no name. Give it a text `label`, `aria-label` or `aria-labelledby`.',\n );\n }, [label, ariaLabel, labelledBy, labelId]);\n\n return (\n <li\n {...rest}\n ref={ref}\n role=\"presentation\"\n hidden={hidden || empty || undefined}\n className={cn(optionGroupClassNames.root, className)}\n >\n {hasLabel && (\n <div\n ref={headingRef}\n id={labelId}\n role=\"presentation\"\n className={cn(\n optionGroupClassNames.label,\n 'px-3 py-1 text-caption-1 font-semibold text-muted-foreground',\n )}\n >\n {materialiseSlotContent(label)}\n </div>\n )}\n <ul\n role=\"group\"\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n className={optionGroupClassNames.list}\n >\n <OptionGroupHiddenContext.Provider value={hiddenByConsumer}>\n <OptionGroupContext.Provider value={groups}>{children}</OptionGroupContext.Provider>\n </OptionGroupHiddenContext.Provider>\n </ul>\n </li>\n );\n}\nOptionGroupImpl.displayName = 'OptionGroup';\n\n/**\n * Groups options under an optional heading: `<li role=\"presentation\">` with the heading and a\n * `<ul role=\"group\">` of the options, named by the heading (`label`) or by your `aria-label` or\n * `aria-labelledby`, which win over it. Hidden while a filter (or their own `hidden`) hides all\n * its options, also options wrapped in a component or in nested groups. Use it inside a listbox,\n * as `Option`.\n */\nexport const OptionGroup: React.FC<OptionGroupProps> = /* @__PURE__ */ markListboxElement(\n OptionGroupImpl,\n 'group',\n);\n\n/* ------------------------------------------------------------------ */\n/* ListboxProvider */\n/* ------------------------------------------------------------------ */\n\n/** Props of {@link ListboxProvider}. */\nexport interface ListboxProviderProps {\n /** The context of a listbox: `useListbox(...).context`. */\n value: ListboxContextValue;\n /** The options (`Option`, `OptionGroup` or options of your own on `useListboxOption`). */\n children?: React.ReactNode;\n}\n\n/**\n * Provides a listbox's context to its options, for a custom picker that renders its list without\n * `ListboxSurface`: `<ListboxProvider value={listbox.context}><ul {...listbox.getListboxProps()}>…</ul></ListboxProvider>`.\n */\nexport function ListboxProvider({ value, children }: ListboxProviderProps) {\n return <ListboxContext.Provider value={value}>{children}</ListboxContext.Provider>;\n}\nListboxProvider.displayName = 'ListboxProvider';\n\n/* ------------------------------------------------------------------ */\n/* Listbox popup: useListboxPopup and ListboxSurface */\n/* ------------------------------------------------------------------ */\n\n/** Options of {@link useListboxPopup}. */\nexport interface UseListboxPopupOptions {\n /**\n * The listbox is open (your open state). While it is, a press outside your picker and its\n * surface, and focus leaving them, dismiss it.\n */\n open: boolean;\n /**\n * The surface is shown (the list, or the empty content of {@link ListboxSurface}): it is\n * positioned, and Escape dismisses it. While the listbox is open with nothing shown (no options\n * to show), Escape is left to an enclosing layer, such as a Dialog around the picker.\n */\n surfaceOpen: boolean;\n /**\n * Called when the popup should close: set your open state to `false`. `reason` is `'escape'`,\n * `'outside-press'` or `'focus-outside'`.\n */\n onDismiss: (reason: DismissReason) => void;\n /** Your picker's root element: presses and focus inside it are not outside the popup. */\n rootRef: React.RefObject<HTMLElement | null>;\n /**\n * The combobox element, which anchors the popup's dismiss layer. Pass the element to\n * `setReference` too (merged into its ref), which places the surface against it.\n */\n anchorRef: React.RefObject<HTMLElement | null>;\n /**\n * Advanced positioning: `offset`, `fitViewport`, `matchReferenceWidth` and `fallbackPlacements`.\n * @default `{ matchReferenceWidth: true, fitViewport: true }`\n */\n positioning?: PopupPositioningOptions;\n}\n\n/**\n * Result of {@link useListboxPopup}. Destructure it: `eslint-plugin-react-hooks` treats an object\n * with a member passed to a `ref` prop as a ref, and rejects reading its other members during\n * render (`react-hooks/refs`).\n */\nexport interface UseListboxPopupResult {\n /** The popup's dismiss layer: pass it to {@link ListboxSurface}. */\n layerId: string;\n /**\n * Ref callback for the element the surface is placed against: merge it into your combobox's ref.\n */\n setReference: (el: HTMLElement | null) => void;\n /** Ref callback for the surface: pass it to {@link ListboxSurface}. */\n surfaceRef: React.RefCallback<HTMLElement>;\n /** The surface's `data-side`, `data-align` and position style: pass them to {@link ListboxSurface}. */\n floatingProps: { 'data-side': string; 'data-align': string; style: React.CSSProperties };\n}\n\n/**\n * Dismissal and positioning of a custom picker's listbox popup, for {@link ListboxSurface}. The\n * popup is dismissed by Escape, by a press outside your picker and its surface, and by focus\n * leaving them (`onDismiss` says which). The surface opens below the anchor and as wide as it,\n * flips above it when there is no room below, and is limited to the space available; its\n * `data-side` and `data-align` attributes give the final placement.\n *\n * While the listbox is open with nothing to show (`surfaceOpen` is `false`), Escape is left to an\n * enclosing layer, such as a Dialog around the picker. Let your combobox's key handler leave it\n * too: on such an Escape, set your open state to `false` without calling `listbox.onKeyDown`,\n * which handles Escape (and prevents its default) whenever the listbox is open. Do so only when\n * `!event.nativeEvent.isComposing`, as Dropdown, Combobox and TagPicker do: an Escape that only\n * cancels an IME composition must not close the listbox, and `listbox.onKeyDown` ignores such\n * keys too.\n *\n * @example\n * const expanded = open && listbox.items.length > 0;\n * const { layerId, setReference, surfaceRef, floatingProps } = useListboxPopup({\n * open,\n * surfaceOpen: expanded,\n * onDismiss: () => setOpen(false),\n * rootRef,\n * anchorRef: buttonRef,\n * });\n * const buttonMergedRef = useMergedRefs(buttonRef, setReference);\n */\nexport function useListboxPopup(options: UseListboxPopupOptions): UseListboxPopupResult {\n const { open, surfaceOpen, onDismiss, rootRef, anchorRef, positioning } = options;\n const surfaceElementRef = React.useRef<HTMLElement | null>(null);\n const { setReference, setFloating, floatingProps } = usePopupPosition({\n open: surfaceOpen,\n side: 'bottom',\n align: 'start',\n ...resolvePositioning(positioning, { matchReferenceWidth: true, fitViewport: true }),\n });\n const { layerId } = useDismiss({\n open,\n onDismiss: (reason) => onDismiss(reason),\n refs: [rootRef, surfaceElementRef],\n anchorRef,\n kind: 'listbox',\n escape: surfaceOpen,\n focusOutside: true,\n });\n const surfaceRef = useMergedRefs<HTMLElement>(surfaceElementRef, setFloating);\n return { layerId, setReference, surfaceRef, floatingProps };\n}\n\n/**\n * Attributes of the list element that ListboxSurface renders (see `listProps`). Its content is the\n * surface's `children`.\n */\nexport type ListboxSurfaceListProps = Omit<\n React.HTMLAttributes<HTMLUListElement>,\n | 'role'\n | 'id'\n | 'hidden'\n | 'tabIndex'\n | 'className'\n | 'aria-label'\n | 'aria-labelledby'\n | 'aria-multiselectable'\n | 'aria-activedescendant'\n | 'children'\n | 'dangerouslySetInnerHTML'\n> & {\n /** Ref to the `role=\"listbox\"` element (it moves between the picker and the popup). */\n ref?: React.Ref<HTMLUListElement>;\n};\n\n/**\n * Props of {@link ListboxSurface}. The options of one listbox live in one list at a time, and this\n * surface renders that list: render every option of the listbox inside it, never in a second list\n * of your own, not even for an exit animation.\n */\nexport interface ListboxSurfaceProps {\n /** The listbox: the result of `useListbox` in select-only or editable mode. */\n listbox: UseListboxResult;\n /** `layerId` from {@link useListboxPopup}: the surface joins the popup's dismiss layer. */\n layerId: string;\n /** `surfaceRef` from {@link useListboxPopup}. */\n surfaceRef: React.RefCallback<HTMLElement>;\n /** `floatingProps` from {@link useListboxPopup}: the surface's placement. */\n floatingProps: UseListboxPopupResult['floatingProps'];\n /** The listbox is open (your open state). `emptyContent` shows only while it is. */\n open: boolean;\n /**\n * The list is shown: the listbox is open and has options to show (`open &&\n * listbox.items.length > 0`). The list then renders in the surface, and otherwise `hidden`, in\n * place inside your picker. Set your combobox's `aria-expanded` to this value after spreading\n * `getComboboxProps()`, which reports `open`, so the combobox is not announced as expanded while\n * nothing is shown.\n */\n expanded: boolean;\n /**\n * Shown in the surface while the listbox is open but not expanded, such as a \"No matches\"\n * message. `undefined` and `null` show no surface; any other value shows one, so `false` and\n * `''` show an empty surface.\n */\n emptyContent?: React.ReactNode;\n /** Names the list. Name it with this or `aria-labelledby`, usually your picker's label. */\n 'aria-label'?: string;\n /** Ids of the elements that name the list, usually your picker's label. */\n 'aria-labelledby'?: string;\n /**\n * Options draw a check while selected (in a multi-select list, a checkbox square). Turn it off\n * for a list that never shows selected options, such as the suggestions of a tag picker.\n * @default true\n */\n showCheck?: boolean;\n /**\n * Classes merged last onto the list: they replace the list's own classes they conflict with,\n * its maximum height included.\n */\n listClassName?: string;\n /**\n * Classes merged last onto the surface, the popup around the list: they replace its own\n * classes they conflict with.\n */\n surfaceClassName?: string;\n /**\n * Attributes spread onto the list element before the listbox's own (`role`, `id`, `tabIndex`,\n * `aria-multiselectable`, `aria-activedescendant` and `hidden` win, also where the listbox\n * renders none of the last two): `data-*` and other `aria-*` attributes, `style`, and handlers,\n * composed before the listbox's own `onMouseDown`. `ref` is merged with the list's. Name the list\n * with `aria-label`/`aria-labelledby` (the props above), not here.\n */\n listProps?: ListboxSurfaceListProps;\n /** The options (`Option`, `OptionGroup` or options of your own on `useListboxOption`). */\n children?: React.ReactNode;\n}\n\nfunction preventMouseDown(event: React.MouseEvent) {\n event.preventDefault();\n}\n\n/**\n * The option list of a custom picker and the popup it opens in: a `<ul role=\"listbox\">` with the\n * options (spread from `listbox.getListboxProps()`), rendered `hidden` in place inside your\n * picker while the list is not shown, so the options register and their ids exist from the first\n * render, and in a portaled surface placed by {@link useListboxPopup} while it is, never in both.\n * While the listbox is open with nothing to show, the surface shows `emptyContent` instead, if\n * any. A press on the surface keeps focus on your combobox. It provides the listbox's context to\n * the options, so it needs no {@link ListboxProvider}.\n *\n * @example\n * <ListboxSurface\n * listbox={listbox}\n * layerId={layerId}\n * surfaceRef={surfaceRef}\n * floatingProps={floatingProps}\n * open={open}\n * expanded={expanded}\n * aria-labelledby={labelId}\n * >\n * <Option value=\"georgia\">Georgia</Option>\n * </ListboxSurface>\n */\nexport function ListboxSurface(props: ListboxSurfaceProps) {\n const {\n listbox,\n layerId,\n surfaceRef,\n floatingProps,\n open,\n expanded,\n emptyContent,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n showCheck = true,\n listClassName,\n surfaceClassName,\n listProps,\n children,\n } = props;\n\n // The consumer's list attributes go first, so the listbox's own win; its `onMouseDown` runs\n // before the list's (which keeps focus on the combobox) and its `ref` is merged with the list's.\n const { ref: listRefProp, onMouseDown: listMouseDown, ...listRest } = listProps ?? {};\n const listboxProps = listbox.getListboxProps();\n const listRef = useMergedRefs<HTMLUListElement>(listRefProp, listboxProps.ref);\n\n const list = (\n <OptionCheckContext.Provider value={showCheck}>\n <ListboxProvider value={listbox.context}>\n <ul\n {...listRest}\n {...listboxProps}\n // Absent from `listboxProps` when not set: a caller's value never survives the spread.\n aria-multiselectable={listboxProps['aria-multiselectable']}\n aria-activedescendant={listboxProps['aria-activedescendant']}\n onMouseDown={composeEventHandlers(listMouseDown, listboxProps.onMouseDown)}\n ref={listRef}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n hidden={!expanded || undefined}\n className={cn(\n listboxSurfaceClassNames.list,\n 'min-h-0 max-h-60 overflow-auto',\n listClassName,\n )}\n >\n {children}\n </ul>\n </ListboxProvider>\n </OptionCheckContext.Provider>\n );\n\n // A closed listbox never leaves a surface behind: the text typed before closing survives it.\n const showEmpty = open && !expanded && emptyContent !== undefined && emptyContent !== null;\n if (!expanded && !showEmpty) return list;\n\n return (\n <>\n {!expanded && list}\n <Portal layerId={layerId}>\n <div\n ref={surfaceRef}\n {...floatingProps}\n data-wave-listbox-surface=\"\"\n onMouseDown={preventMouseDown}\n className={cn(\n listboxSurfaceClassNames.root,\n 'flex flex-col overflow-hidden rounded border border-border bg-background py-1 text-foreground shadow-4',\n surfaceClassName,\n )}\n >\n {expanded ? list : emptyContent}\n </div>\n </Portal>\n </>\n );\n}\nListboxSurface.displayName = 'ListboxSurface';\n"],"mappings":"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"}
1
+ {"version":3,"file":"Option.mjs","names":["useId","_Fragment","useId$1","React","OptionCheckContext","OPTION_CLASSES","cn","OptionGroupMembers","listener","value","count","store","OptionGroupContext","OptionGroupHiddenContext","useOptionGroupMembership","groups","removes","group","remove","DISABLED_BOX_FORCED_COLORS","DISABLED_GLYPH_FORCED_COLORS","renderCheck","multiselect","classes","optionClassNames","selected","glyph","CheckIcon","renderSlot","boxClasses","disabled","forcedColors","glyphClasses","OptionImpl","rest","props","showCheck","groupHidden","useListboxOption","hidden","ref","optionRef","selectOption","pressOption","highlightOption","windowStyle","optionAttributes","optionProps","checkIconRenders","checkIcon","slotRendersContent","checkIconEmpty","warnOnce","style","composeEventHandlers","onClick","onMouseDown","onPointerMove","className","children","MemoOption","Option","ELEMENT_NODE","TEXT_NODE","nameText","node","element","ownLabel","text","child","groupHasName","labelledBy","labelId","ariaLabel","label","heading","UNNAMED_GROUP_WARNING","OptionGroupImpl","ariaLabelledBy","ListboxContext","parentGroups","hiddenByConsumer","members","subscribe","unsubscribeMembers","unsubscribeStore","empty","hasLabel","headingRef","isDev","optionGroupClassNames","materialiseSlotContent","OptionGroup","ListboxProvider","useListboxPopup","options","surfaceElementRef","usePopupPosition","surfaceOpen","resolvePositioning","positioning","useDismiss","onDismiss","reason","rootRef","useMergedRefs","setFloating","preventMouseDown","ListboxSurface","listRefProp","listMouseDown","listRest","listProps","listboxProps","listbox","listRef","list","expanded","listboxSurfaceClassNames","listClassName","emptyContent","Fragment","Portal","surfaceRef","floatingProps","surfaceClassName"],"sources":["../../../src/components/input/Option.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n listboxSurfaceClassNames,\n optionClassNames,\n optionGroupClassNames,\n} from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { hasWarned, isDev, warnOnce } from '../../lib/dev';\nimport { CheckIcon } from '../../lib/icons';\nimport { materialiseSlotContent, renderSlot, slotRendersContent, type Slot } from '../../lib/slot';\nimport { forcedColors } from '../../lib/styles';\nimport type { PopupPositioningOptions } from '../../lib/types';\nimport { useId } from '../../hooks/useId';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useDismiss } from '../../hooks/useDismiss';\nimport type { DismissReason } from '../../hooks/useDismiss';\nimport { resolvePositioning, usePopupPosition } from '../../hooks/usePopupPosition';\nimport {\n ListboxContext,\n markListboxElement,\n useListboxOption,\n type ListboxContextValue,\n type ListboxStore,\n type UseListboxResult,\n} from '../../hooks/useListbox';\nimport { Portal } from '../portal/Portal';\n\n/* ------------------------------------------------------------------ */\n/* Option */\n/* ------------------------------------------------------------------ */\n\n/**\n * Props of {@link Option}, an option of a listbox (Listbox, Combobox, Dropdown or a custom\n * picker's list).\n */\nexport interface OptionProps extends Omit<React.LiHTMLAttributes<HTMLLIElement>, 'value'> {\n /** Value associated with this option. Unique within its listbox. */\n value: string;\n /**\n * Text shown in the combobox (Combobox input, Dropdown trigger) when this option is selected.\n * Defaults to `textValue`, then the option's text content, then `value`. Pass it when the\n * children are not plain text (icons, custom components).\n */\n label?: string;\n /** Text matched by typeahead and filtering instead of the label. */\n textValue?: string;\n /**\n * Whether the option is disabled: it stays in the list but can never be selected (a click, Enter\n * and Space do nothing). Keyboard navigation and typeahead skip it, unless the listbox keeps\n * disabled options focusable (`disabledOptionsFocusable`), where they reach it. It is drawn in\n * the muted text colour, its check included: in a multi-select list the checkbox square takes\n * that colour instead of the brand colour, checked or not.\n * @default false\n */\n disabled?: boolean;\n /**\n * Replaces the check glyph that marks the option while it is selected (decorative,\n * `aria-hidden`); in a multi-select list the glyph is drawn inside the option's 16px checkbox\n * square. The check is a required indicator, the sign of the selection that does not rely on\n * colour: `null` and `undefined` keep the default glyph, and so does a value that renders\n * nothing (`false`, `''`, an empty array), which also logs a development warning. Unlike\n * `Combobox.expandIcon`, a value that renders nothing does not hide the indicator (Fluent's\n * `checkIcon={null}` removes it).\n * @default a check mark\n */\n checkIcon?: Slot<'span'>;\n /**\n * Hides the option, like a native `<option hidden>`: it is not shown, keyboard navigation and\n * typeahead skip it, and it never becomes the active option. Its label stays known, so a\n * selected hidden option (a placeholder) still shows in the combobox. The options of a hidden\n * `OptionGroup` are hidden the same way.\n * @default false\n */\n hidden?: boolean;\n /** Ref to the option `<li>` element. */\n ref?: React.Ref<HTMLLIElement>;\n}\n\n/**\n * The state of an item's option, which `renderOption` of Listbox, Combobox and Dropdown receives\n * with the item (data mode, `items`).\n */\nexport interface ListboxOptionRenderState {\n /** The item's value is selected. */\n selected: boolean;\n /**\n * The option is the active one, which `aria-activedescendant` points at: in a Listbox while the\n * list has focus, in a Combobox or Dropdown while the list is open.\n */\n active: boolean;\n /**\n * The option's index among the shown options, from 0 (its `aria-posinset` minus one): items a\n * filter leaves out and hidden items are not counted.\n */\n index: number;\n}\n\n/** Whether options draw the selected check mark (P05-internal; TagPicker lists no selected options). */\nconst OptionCheckContext = React.createContext(true);\nOptionCheckContext.displayName = 'OptionCheckContext';\n\n/*\n * State is exposed as data attributes (C-CLASS): `data-active` (keyboard/pointer highlight),\n * `data-selected`, `data-disabled`. State classes come before the consumer's `className` in `cn()`.\n *\n * Backgrounds (input-pickers#20): one unconditional `bg-(--option-bg)` paints the option, and the\n * hover/selected/active variants only set `--option-bg`. A variant that set `background-color`\n * itself (class + attribute or pseudo-class) would out-specify a consumer's plain `bg-*` class in\n * the cascade even though `cn()` keeps it; instead tailwind-merge replaces `bg-(--option-bg)` with\n * the consumer's class, which is then the only background declaration on the option. A consumer\n * `data-[active]:bg-…` / `data-[selected]:bg-…` restyles a single state (it out-specifies the\n * unconditional reader). The active outline is the focus indicator and stays a state variant.\n *\n * A filtered-out option carries the `hidden` attribute; base.css's scoped `[hidden]` rule hides\n * it over `flex` and over a consumer's display class.\n */\nconst OPTION_CLASSES = cn(\n 'flex cursor-pointer select-none items-center gap-2 px-3 py-1.5 text-body-1 text-foreground',\n 'bg-(--option-bg) [--option-bg:transparent]',\n 'not-disabled:not-aria-disabled:hover:[--option-bg:var(--wave-subtle-hover)]',\n 'data-[selected]:[--option-bg:var(--wave-subtle-selected)]',\n 'data-[active]:[--option-bg:var(--wave-subtle-hover)]',\n 'data-[active]:outline-2 data-[active]:-outline-offset-2 data-[active]:outline-ring',\n 'aria-disabled:cursor-not-allowed aria-disabled:text-muted-foreground',\n);\n\n/**\n * The values of the options rendered inside an `OptionGroup`, whatever wraps them (custom\n * components, Fragments, nested groups): each option adds its value from a layout effect.\n */\nclass OptionGroupMembers {\n private readonly counts = new Map<string, number>();\n private readonly listeners = new Set<() => void>();\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n add(value: string): () => void {\n this.counts.set(value, (this.counts.get(value) ?? 0) + 1);\n this.notify();\n return () => {\n const count = (this.counts.get(value) ?? 1) - 1;\n if (count > 0) this.counts.set(value, count);\n else this.counts.delete(value);\n this.notify();\n };\n }\n\n /** At least one option, and every one of them is hidden (filtered out, or by the consumer). */\n allHidden(store: ListboxStore | undefined): boolean {\n if (store === undefined || this.counts.size === 0) return false;\n for (const value of this.counts.keys()) if (!store.isHidden(value)) return false;\n return true;\n }\n\n private notify(): void {\n for (const listener of [...this.listeners]) listener();\n }\n}\n\n/** The groups around an option, outermost first (P05-internal). */\nconst OptionGroupContext = React.createContext<readonly OptionGroupMembers[]>([]);\nOptionGroupContext.displayName = 'OptionGroupContext';\n\n/** A group around the option has the consumer's `hidden` attribute (P05-internal). */\nconst OptionGroupHiddenContext = React.createContext(false);\nOptionGroupHiddenContext.displayName = 'OptionGroupHiddenContext';\n\n/** Adds an option's value to every group around it while the option is mounted. */\nfunction useOptionGroupMembership(value: string): void {\n const groups = React.useContext(OptionGroupContext);\n React.useLayoutEffect(() => {\n if (groups.length === 0) return;\n const removes = groups.map((group) => group.add(value));\n return () => {\n for (const remove of removes) remove();\n };\n }, [groups, value]);\n}\n\n/*\n * Forced colours of a disabled option's box, as Checkbox draws a disabled box: GrayText on Canvas\n * for the square and its glyph, without the Highlight background of `forcedColors.selectedLeaf`.\n */\nconst DISABLED_BOX_FORCED_COLORS = 'forced-colors:border-[GrayText] forced-colors:bg-[Canvas]';\nconst DISABLED_GLYPH_FORCED_COLORS =\n 'forced-colors:text-[GrayText] forced-colors:forced-color-adjust-none';\n\n/** What the check column of an option draws (see {@link renderCheck}). */\ninterface CheckState {\n selected: boolean;\n multiselect: boolean;\n disabled: boolean;\n}\n\n/**\n * The check column of an option. Single-select: the check glyph, kept in its place but not drawn\n * while the option is not selected, so the option texts line up. Multi-select: a 16px checkbox\n * square in Checkbox's colours, with the glyph inside only while selected; as a leaf indicator it\n * takes `forcedColors.selectedLeaf` while checked. A disabled option's square follows the row, as\n * the single-select glyph does: its muted text colour draws the square and the glyph, in place of\n * the brand colour. `glyph` is the consumer's `checkIcon` when it renders content, else\n * `undefined` for the default glyph.\n */\nfunction renderCheck(\n glyph: Slot<'span'> | undefined,\n { selected, multiselect, disabled }: CheckState,\n): React.ReactNode {\n if (!multiselect) {\n const classes = cn(optionClassNames.checkIcon, 'shrink-0', !selected && 'invisible');\n return glyph === undefined ? (\n <CheckIcon className={classes} />\n ) : (\n renderSlot(glyph, 'span', cn('inline-flex', classes), { 'aria-hidden': true })\n );\n }\n // One class set per state, so a disabled box never carries the brand classes it replaces.\n let boxClasses: string;\n if (disabled) {\n boxClasses = cn('border-current bg-transparent', DISABLED_BOX_FORCED_COLORS);\n } else if (selected) {\n boxClasses = cn('border-primary bg-primary text-primary-foreground', forcedColors.selectedLeaf);\n } else {\n boxClasses = cn('border-stroke-accessible bg-transparent', forcedColors.control);\n }\n const glyphClasses = disabled ? DISABLED_GLYPH_FORCED_COLORS : undefined;\n return (\n <span\n aria-hidden=\"true\"\n data-wave-option-box=\"\"\n className={cn(\n optionClassNames.indicator,\n 'flex h-4 w-4 shrink-0 items-center justify-center rounded-xs border',\n boxClasses,\n )}\n >\n {selected &&\n (glyph === undefined ? (\n <CheckIcon size={12} className={cn(optionClassNames.checkIcon, glyphClasses)} />\n ) : (\n renderSlot(\n glyph,\n 'span',\n cn(optionClassNames.checkIcon, 'inline-flex shrink-0', glyphClasses),\n {\n 'aria-hidden': true,\n },\n )\n ))}\n </span>\n );\n}\n\nfunction OptionImpl(props: OptionProps) {\n const {\n value,\n label,\n textValue,\n disabled = false,\n hidden = false,\n checkIcon,\n className,\n style,\n children,\n onClick,\n onMouseDown,\n onPointerMove,\n ref,\n ...rest\n } = props;\n const showCheck = React.useContext(OptionCheckContext);\n const groupHidden = React.useContext(OptionGroupHiddenContext);\n // A consumer-hidden option is not navigable; optionProps renders `hidden`.\n const { selected, multiselect, optionProps } = useListboxOption<HTMLLIElement>(\n { value, label, textValue, disabled, hidden: hidden || groupHidden },\n ref,\n );\n useOptionGroupMembership(value);\n const {\n ref: optionRef,\n onClick: selectOption,\n // Standalone mode only: the pointer press that focuses the list.\n onMouseDown: pressOption,\n onPointerMove: highlightOption,\n // A windowed list only: the option's height, which wins over the consumer's.\n style: windowStyle,\n ...optionAttributes\n } = optionProps;\n\n // The check is a required indicator (C-SLOTS): a `checkIcon` that renders nothing keeps the\n // default glyph and warns once.\n const checkIconRenders = checkIcon != null && slotRendersContent(checkIcon);\n const checkIconEmpty = checkIcon != null && !checkIconRenders;\n React.useEffect(() => {\n if (checkIconEmpty) {\n warnOnce(\n 'Option:checkIcon-empty',\n 'Option: `checkIcon` renders nothing, so the default check shows: a selected option must show its state. Pass a glyph, or leave it unset.',\n );\n }\n }, [checkIconEmpty]);\n\n return (\n <li\n data-value={value}\n {...rest}\n {...optionAttributes}\n style={windowStyle ? { ...style, ...windowStyle } : style}\n ref={optionRef}\n onClick={composeEventHandlers(onClick, selectOption)}\n onMouseDown={composeEventHandlers(onMouseDown, pressOption)}\n onPointerMove={composeEventHandlers(onPointerMove, highlightOption)}\n className={cn(\n optionClassNames.root,\n OPTION_CLASSES,\n // While a multi-select option draws its box, the box carries the state, and\n // `forcedColors.selectedContainer` would draw every selected option like the active one.\n selected && !(multiselect && showCheck) && forcedColors.selectedContainer,\n className,\n )}\n >\n {showCheck &&\n renderCheck(checkIconRenders ? checkIcon : undefined, { selected, multiselect, disabled })}\n <span className={cn(optionClassNames.content, 'min-w-0 flex-1')}>{children ?? value}</span>\n </li>\n );\n}\nOptionImpl.displayName = 'Option';\n\nconst MemoOption = /* @__PURE__ */ React.memo(OptionImpl);\nMemoOption.displayName = 'Option';\n\n/**\n * An option of a listbox: a `Listbox`, `Combobox` or `Dropdown` (and `TagPicker`'s generated\n * list), or a custom picker's list, rendered through `ListboxSurface` or under a\n * `ListboxProvider`. Renders `<li role=\"option\">` with a stable id (`aria-activedescendant`\n * target), `aria-selected`, a check mark while selected (`checkIcon` replaces it; in a\n * multi-select list it sits in a checkbox square) and `data-active`/`data-selected`/\n * `data-disabled` attributes for styling.\n *\n * Options register with the surrounding listbox (in DOM order, groups included), so they can be\n * wrapped, grouped or rendered conditionally. The option is memoized: moving the highlight\n * re-renders only the previously and the newly active option. In a windowed list (the\n * `virtualWindow` of Listbox, Combobox or Dropdown) the option is exactly the window's `itemSize`\n * tall, a height set after its own `style`, so its content must fit in it.\n *\n * Styling: `className` comes last. A plain background class (`className=\"bg-primary\"`) replaces\n * the built-in hover, selected and active backgrounds in every state. To restyle one state only,\n * use its data variant (`data-[active]:bg-…`, `data-[selected]:bg-…`). The active option keeps\n * its focus outline.\n *\n * Use it inside a listbox only; it throws in development elsewhere.\n */\nexport const Option: React.NamedExoticComponent<OptionProps> = /* @__PURE__ */ markListboxElement(\n MemoOption,\n 'option',\n);\n\n/* ------------------------------------------------------------------ */\n/* OptionGroup */\n/* ------------------------------------------------------------------ */\n\n/**\n * Props of {@link OptionGroup}. `aria-label` and `aria-labelledby` go to the group's\n * `role=\"group\"` list; the other props go to its `<li role=\"presentation\">` item.\n */\nexport interface OptionGroupProps extends React.LiHTMLAttributes<HTMLLIElement> {\n /**\n * The group's heading, which names the group. Keep it text (an icon next to the text is fine): a\n * label cannot be interactive, since nothing in it is reachable inside a listbox. Without a\n * label no heading renders; name the group with `aria-label` or `aria-labelledby` then. A group\n * without a name logs a development warning.\n */\n label?: React.ReactNode;\n /**\n * Names the group's list in place of the label (the heading still shows). A prop that holds\n * `undefined`, as from a wrapper that forwards it, leaves the label in charge.\n */\n 'aria-label'?: string;\n /**\n * Ids of the elements that name the group's list, in place of the label (the heading still\n * shows). A prop that holds `undefined` leaves the label in charge.\n */\n 'aria-labelledby'?: string;\n /**\n * Hides the group and every option in it (see `Option`'s `hidden`): keyboard navigation and\n * typeahead skip its options.\n * @default false\n */\n hidden?: boolean;\n /** Ref to the group's `<li role=\"presentation\">` element. */\n ref?: React.Ref<HTMLLIElement>;\n}\n\nconst ELEMENT_NODE = 1;\nconst TEXT_NODE = 3;\n\n/**\n * The text a heading gives the name of its group, for the development check of `OptionGroup`: its\n * text without `aria-hidden` or `hidden` parts, where an element's `aria-label` or an image's `alt`\n * stands for its content.\n */\nfunction nameText(node: Node | null): string {\n if (node === null) return '';\n if (node.nodeType === TEXT_NODE) return node.textContent ?? '';\n if (node.nodeType !== ELEMENT_NODE) return '';\n const element = node as Element;\n if (element.getAttribute('aria-hidden') === 'true' || element.hasAttribute('hidden')) return '';\n const ownLabel = element.getAttribute('aria-label')?.trim();\n if (ownLabel) return ownLabel;\n if (element.localName === 'img') return element.getAttribute('alt') ?? '';\n let text = '';\n for (const child of Array.from(element.childNodes)) text += nameText(child);\n return text;\n}\n\n/**\n * Whether a group's list has a name, for the development check of `OptionGroup`, in the order the\n * name is computed: a consumer `aria-labelledby` that is not blank (its presence counts; the\n * elements it names are not read), else a non-blank `aria-label`, else the heading that labels the\n * list. A string or number label is its own text; only an element label is read from the rendered\n * heading ({@link nameText}).\n */\nfunction groupHasName(\n label: React.ReactNode,\n ariaLabel: string | undefined,\n labelledBy: string | undefined,\n labelId: string,\n heading: HTMLElement | null,\n): boolean {\n if (labelledBy !== undefined && labelledBy !== labelId && labelledBy.trim() !== '') return true;\n if (ariaLabel !== undefined && ariaLabel.trim() !== '') return true;\n if (labelledBy !== labelId) return false;\n if (typeof label === 'string' || typeof label === 'number') return String(label).trim() !== '';\n return nameText(heading).trim() !== '';\n}\n\nconst UNNAMED_GROUP_WARNING = 'OptionGroup:unnamed';\n\nfunction OptionGroupImpl({\n label,\n className,\n children,\n hidden,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ref,\n ...rest\n}: OptionGroupProps) {\n const labelId = useId('option-group');\n const store = React.useContext(ListboxContext)?.store;\n const parentGroups = React.useContext(OptionGroupContext);\n const hiddenByConsumer = React.useContext(OptionGroupHiddenContext) || !!hidden;\n const [members] = React.useState(() => new OptionGroupMembers());\n const groups = React.useMemo(() => [...parentGroups, members], [parentGroups, members]);\n const subscribe = React.useCallback(\n (listener: () => void) => {\n const unsubscribeMembers = members.subscribe(listener);\n const unsubscribeStore = store?.subscribe(listener);\n return () => {\n unsubscribeMembers();\n unsubscribeStore?.();\n };\n },\n [members, store],\n );\n // Hidden while every option inside it is filtered out or hidden, also options wrapped in a\n // component (the options register with the group; re-read when they do and when the listbox\n // state changes).\n // The server render and the first client render show the group: no option has registered yet.\n const empty = React.useSyncExternalStore(\n subscribe,\n () => members.allHidden(store),\n () => false,\n );\n\n // The heading renders only for a label that renders content, so the list never points at an\n // empty heading. A consumer name wins over the heading; a prop that holds `undefined` (a wrapper\n // forwarding it) is no name of the consumer's.\n const hasLabel = slotRendersContent(label);\n const labelledBy = ariaLabelledBy ?? (ariaLabel === undefined && hasLabel ? labelId : undefined);\n\n // C-DEV: warn once when nothing names the group, checked again whenever the label, the\n // consumer `aria-label` or the resolved `aria-labelledby` changes.\n const headingRef = React.useRef<HTMLDivElement | null>(null);\n React.useEffect(() => {\n if (!isDev || hasWarned(UNNAMED_GROUP_WARNING)) return;\n if (groupHasName(label, ariaLabel, labelledBy, labelId, headingRef.current)) return;\n warnOnce(\n UNNAMED_GROUP_WARNING,\n 'OptionGroup: the group has no name. Give it a text `label`, `aria-label` or `aria-labelledby`.',\n );\n }, [label, ariaLabel, labelledBy, labelId]);\n\n return (\n <li\n {...rest}\n ref={ref}\n role=\"presentation\"\n hidden={hidden || empty || undefined}\n className={cn(optionGroupClassNames.root, className)}\n >\n {hasLabel && (\n <div\n ref={headingRef}\n id={labelId}\n role=\"presentation\"\n className={cn(\n optionGroupClassNames.label,\n 'px-3 py-1 text-caption-1 font-semibold text-muted-foreground',\n )}\n >\n {materialiseSlotContent(label)}\n </div>\n )}\n <ul\n role=\"group\"\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n className={optionGroupClassNames.list}\n >\n <OptionGroupHiddenContext.Provider value={hiddenByConsumer}>\n <OptionGroupContext.Provider value={groups}>{children}</OptionGroupContext.Provider>\n </OptionGroupHiddenContext.Provider>\n </ul>\n </li>\n );\n}\nOptionGroupImpl.displayName = 'OptionGroup';\n\n/**\n * Groups options under an optional heading: `<li role=\"presentation\">` with the heading and a\n * `<ul role=\"group\">` of the options, named by the heading (`label`) or by your `aria-label` or\n * `aria-labelledby`, which win over it. Hidden while a filter (or their own `hidden`) hides all\n * its options, also options wrapped in a component or in nested groups. Use it inside a listbox,\n * as `Option`.\n */\nexport const OptionGroup: React.FC<OptionGroupProps> = /* @__PURE__ */ markListboxElement(\n OptionGroupImpl,\n 'group',\n);\n\n/* ------------------------------------------------------------------ */\n/* ListboxProvider */\n/* ------------------------------------------------------------------ */\n\n/** Props of {@link ListboxProvider}. */\nexport interface ListboxProviderProps {\n /** The context of a listbox: `useListbox(...).context`. */\n value: ListboxContextValue;\n /** The options (`Option`, `OptionGroup` or options of your own on `useListboxOption`). */\n children?: React.ReactNode;\n}\n\n/**\n * Provides a listbox's context to its options, for a custom picker that renders its list without\n * `ListboxSurface`: `<ListboxProvider value={listbox.context}><ul {...listbox.getListboxProps()}>…</ul></ListboxProvider>`.\n */\nexport function ListboxProvider({ value, children }: ListboxProviderProps) {\n return <ListboxContext.Provider value={value}>{children}</ListboxContext.Provider>;\n}\nListboxProvider.displayName = 'ListboxProvider';\n\n/* ------------------------------------------------------------------ */\n/* Listbox popup: useListboxPopup and ListboxSurface */\n/* ------------------------------------------------------------------ */\n\n/** Options of {@link useListboxPopup}. */\nexport interface UseListboxPopupOptions {\n /**\n * The listbox is open (your open state). While it is, a press outside your picker and its\n * surface, and focus leaving them, dismiss it.\n */\n open: boolean;\n /**\n * The surface is shown (the list, or the empty content of {@link ListboxSurface}): it is\n * positioned, and Escape dismisses it. While the listbox is open with nothing shown (no options\n * to show), Escape is left to an enclosing layer, such as a Dialog around the picker.\n */\n surfaceOpen: boolean;\n /**\n * Called when the popup should close: set your open state to `false`. `reason` is `'escape'`,\n * `'outside-press'` or `'focus-outside'`.\n */\n onDismiss: (reason: DismissReason) => void;\n /** Your picker's root element: presses and focus inside it are not outside the popup. */\n rootRef: React.RefObject<HTMLElement | null>;\n /**\n * The combobox element, which anchors the popup's dismiss layer. Pass the element to\n * `setReference` too (merged into its ref), which places the surface against it.\n */\n anchorRef: React.RefObject<HTMLElement | null>;\n /**\n * Advanced positioning: `offset`, `fitViewport`, `matchReferenceWidth` and `fallbackPlacements`.\n * @default `{ matchReferenceWidth: true, fitViewport: true }`\n */\n positioning?: PopupPositioningOptions;\n}\n\n/**\n * Result of {@link useListboxPopup}. Destructure it: `eslint-plugin-react-hooks` treats an object\n * with a member passed to a `ref` prop as a ref, and rejects reading its other members during\n * render (`react-hooks/refs`).\n */\nexport interface UseListboxPopupResult {\n /** The popup's dismiss layer: pass it to {@link ListboxSurface}. */\n layerId: string;\n /**\n * Ref callback for the element the surface is placed against: merge it into your combobox's ref.\n */\n setReference: (el: HTMLElement | null) => void;\n /** Ref callback for the surface: pass it to {@link ListboxSurface}. */\n surfaceRef: React.RefCallback<HTMLElement>;\n /** The surface's `data-side`, `data-align` and position style: pass them to {@link ListboxSurface}. */\n floatingProps: { 'data-side': string; 'data-align': string; style: React.CSSProperties };\n}\n\n/**\n * Dismissal and positioning of a custom picker's listbox popup, for {@link ListboxSurface}. The\n * popup is dismissed by Escape, by a press outside your picker and its surface, and by focus\n * leaving them (`onDismiss` says which). The surface opens below the anchor and as wide as it,\n * flips above it when there is no room below, and is limited to the space available; its\n * `data-side` and `data-align` attributes give the final placement.\n *\n * While the listbox is open with nothing to show (`surfaceOpen` is `false`), Escape is left to an\n * enclosing layer, such as a Dialog around the picker. Let your combobox's key handler leave it\n * too: on such an Escape, set your open state to `false` without calling `listbox.onKeyDown`,\n * which handles Escape (and prevents its default) whenever the listbox is open. Do so only when\n * `!event.nativeEvent.isComposing`, as Dropdown, Combobox and TagPicker do: an Escape that only\n * cancels an IME composition must not close the listbox, and `listbox.onKeyDown` ignores such\n * keys too.\n *\n * @example\n * const expanded = open && listbox.items.length > 0;\n * const { layerId, setReference, surfaceRef, floatingProps } = useListboxPopup({\n * open,\n * surfaceOpen: expanded,\n * onDismiss: () => setOpen(false),\n * rootRef,\n * anchorRef: buttonRef,\n * });\n * const buttonMergedRef = useMergedRefs(buttonRef, setReference);\n */\nexport function useListboxPopup(options: UseListboxPopupOptions): UseListboxPopupResult {\n const { open, surfaceOpen, onDismiss, rootRef, anchorRef, positioning } = options;\n const surfaceElementRef = React.useRef<HTMLElement | null>(null);\n const { setReference, setFloating, floatingProps } = usePopupPosition({\n open: surfaceOpen,\n side: 'bottom',\n align: 'start',\n ...resolvePositioning(positioning, { matchReferenceWidth: true, fitViewport: true }),\n });\n const { layerId } = useDismiss({\n open,\n onDismiss: (reason) => onDismiss(reason),\n refs: [rootRef, surfaceElementRef],\n anchorRef,\n kind: 'listbox',\n escape: surfaceOpen,\n focusOutside: true,\n });\n const surfaceRef = useMergedRefs<HTMLElement>(surfaceElementRef, setFloating);\n return { layerId, setReference, surfaceRef, floatingProps };\n}\n\n/**\n * Attributes of the list element that ListboxSurface renders (see `listProps`). Its content is the\n * surface's `children`.\n */\nexport type ListboxSurfaceListProps = Omit<\n React.HTMLAttributes<HTMLUListElement>,\n | 'role'\n | 'id'\n | 'hidden'\n | 'tabIndex'\n | 'className'\n | 'aria-label'\n | 'aria-labelledby'\n | 'aria-multiselectable'\n | 'aria-activedescendant'\n | 'children'\n | 'dangerouslySetInnerHTML'\n> & {\n /** Ref to the `role=\"listbox\"` element (it moves between the picker and the popup). */\n ref?: React.Ref<HTMLUListElement>;\n};\n\n/**\n * Props of {@link ListboxSurface}. The options of one listbox live in one list at a time, and this\n * surface renders that list: render every option of the listbox inside it, never in a second list\n * of your own, not even for an exit animation.\n */\nexport interface ListboxSurfaceProps {\n /** The listbox: the result of `useListbox` in select-only or editable mode. */\n listbox: UseListboxResult;\n /** `layerId` from {@link useListboxPopup}: the surface joins the popup's dismiss layer. */\n layerId: string;\n /** `surfaceRef` from {@link useListboxPopup}. */\n surfaceRef: React.RefCallback<HTMLElement>;\n /** `floatingProps` from {@link useListboxPopup}: the surface's placement. */\n floatingProps: UseListboxPopupResult['floatingProps'];\n /** The listbox is open (your open state). `emptyContent` shows only while it is. */\n open: boolean;\n /**\n * The list is shown: the listbox is open and has options to show (`open &&\n * listbox.items.length > 0`). The list then renders in the surface, and otherwise `hidden`, in\n * place inside your picker. Set your combobox's `aria-expanded` to this value after spreading\n * `getComboboxProps()`, which reports `open`, so the combobox is not announced as expanded while\n * nothing is shown.\n */\n expanded: boolean;\n /**\n * Shown in the surface while the listbox is open but not expanded, such as a \"No matches\"\n * message. `undefined` and `null` show no surface; any other value shows one, so `false` and\n * `''` show an empty surface.\n */\n emptyContent?: React.ReactNode;\n /** Names the list. Name it with this or `aria-labelledby`, usually your picker's label. */\n 'aria-label'?: string;\n /** Ids of the elements that name the list, usually your picker's label. */\n 'aria-labelledby'?: string;\n /**\n * Options draw a check while selected (in a multi-select list, a checkbox square). Turn it off\n * for a list that never shows selected options, such as the suggestions of a tag picker.\n * @default true\n */\n showCheck?: boolean;\n /**\n * Classes merged last onto the list: they replace the list's own classes they conflict with,\n * its maximum height included.\n */\n listClassName?: string;\n /**\n * Classes merged last onto the surface, the popup around the list: they replace its own\n * classes they conflict with.\n */\n surfaceClassName?: string;\n /**\n * Attributes spread onto the list element before the listbox's own (`role`, `id`, `tabIndex`,\n * `aria-multiselectable`, `aria-activedescendant` and `hidden` win, also where the listbox\n * renders none of the last two): `data-*` and other `aria-*` attributes, `style`, and handlers,\n * composed before the listbox's own `onMouseDown`. `ref` is merged with the list's. Name the list\n * with `aria-label`/`aria-labelledby` (the props above), not here.\n */\n listProps?: ListboxSurfaceListProps;\n /** The options (`Option`, `OptionGroup` or options of your own on `useListboxOption`). */\n children?: React.ReactNode;\n}\n\nfunction preventMouseDown(event: React.MouseEvent) {\n event.preventDefault();\n}\n\n/**\n * The option list of a custom picker and the popup it opens in: a `<ul role=\"listbox\">` with the\n * options (spread from `listbox.getListboxProps()`), rendered `hidden` in place inside your\n * picker while the list is not shown, so the options register and their ids exist from the first\n * render, and in a portaled surface placed by {@link useListboxPopup} while it is, never in both.\n * While the listbox is open with nothing to show, the surface shows `emptyContent` instead, if\n * any. A press on the surface keeps focus on your combobox. It provides the listbox's context to\n * the options, so it needs no {@link ListboxProvider}.\n *\n * @example\n * <ListboxSurface\n * listbox={listbox}\n * layerId={layerId}\n * surfaceRef={surfaceRef}\n * floatingProps={floatingProps}\n * open={open}\n * expanded={expanded}\n * aria-labelledby={labelId}\n * >\n * <Option value=\"georgia\">Georgia</Option>\n * </ListboxSurface>\n */\nexport function ListboxSurface(props: ListboxSurfaceProps) {\n const {\n listbox,\n layerId,\n surfaceRef,\n floatingProps,\n open,\n expanded,\n emptyContent,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n showCheck = true,\n listClassName,\n surfaceClassName,\n listProps,\n children,\n } = props;\n\n // The consumer's list attributes go first, so the listbox's own win; its `onMouseDown` runs\n // before the list's (which keeps focus on the combobox) and its `ref` is merged with the list's.\n const { ref: listRefProp, onMouseDown: listMouseDown, ...listRest } = listProps ?? {};\n const listboxProps = listbox.getListboxProps();\n const listRef = useMergedRefs<HTMLUListElement>(listRefProp, listboxProps.ref);\n\n const list = (\n <OptionCheckContext.Provider value={showCheck}>\n <ListboxProvider value={listbox.context}>\n <ul\n {...listRest}\n {...listboxProps}\n // Absent from `listboxProps` when not set: a caller's value never survives the spread.\n aria-multiselectable={listboxProps['aria-multiselectable']}\n aria-activedescendant={listboxProps['aria-activedescendant']}\n onMouseDown={composeEventHandlers(listMouseDown, listboxProps.onMouseDown)}\n ref={listRef}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n hidden={!expanded || undefined}\n className={cn(\n listboxSurfaceClassNames.list,\n 'min-h-0 max-h-60 overflow-auto',\n listClassName,\n )}\n >\n {children}\n </ul>\n </ListboxProvider>\n </OptionCheckContext.Provider>\n );\n\n // A closed listbox never leaves a surface behind: the text typed before closing survives it.\n const showEmpty = open && !expanded && emptyContent !== undefined && emptyContent !== null;\n if (!expanded && !showEmpty) return list;\n\n return (\n <>\n {!expanded && list}\n <Portal layerId={layerId}>\n <div\n ref={surfaceRef}\n {...floatingProps}\n data-wave-listbox-surface=\"\"\n onMouseDown={preventMouseDown}\n className={cn(\n listboxSurfaceClassNames.root,\n 'flex flex-col overflow-hidden rounded border border-border bg-background py-1 text-foreground shadow-4',\n surfaceClassName,\n )}\n >\n {expanded ? list : emptyContent}\n </div>\n </Portal>\n </>\n );\n}\nListboxSurface.displayName = 'ListboxSurface';\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/composeEventHandlers.cjs"),i=require("../../lib/classNames.cjs"),a=require("../../hooks/useEventCallback.cjs"),o=require("../../lib/direction.cjs"),s=require("../../hooks/useTypeahead.cjs"),c=require("../../hooks/useMergedRefs.cjs"),l=require("../../lib/events.cjs"),u=require("./FlatTree.context.cjs"),d=require("./FlatTree.item.cjs");let f=require("react");f=e.__toESM(f,1);let p=require("react/jsx-runtime");var m={focused:null,pending:null},ee=class{state=m;listeners=new Set;subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)});getSnapshot=()=>this.state;getServerSnapshot=()=>m;update(e){let t={...this.state,...e};if(t.focused!==this.state.focused||t.pending!==this.state.pending){this.state=t;for(let e of this.listeners)e()}}};function h({size:e}){return(0,p.jsx)(`div`,{role:`none`,"aria-hidden":`true`,"data-virtual-spacer":``,className:i.flatTreeClassNames.spacer,style:{height:e}})}h.displayName=`FlatTreeSpacer`;function g(e,t){let n=t instanceof Element?t:null;for(;n&&n.parentElement!==e;)n=n.parentElement;return n instanceof HTMLElement&&n.getAttribute(`role`)===`treeitem`?n:null}function _(e){let t=e.getAttribute(`data-index`);return t!==null&&/^\d+$/.test(t)?Number(t):null}function v(e,t){return e.querySelector(`:scope > [data-index="${t}"]`)}function y(e,t,n){for(let r=t+n;r>=0&&r<e.length;r+=n)if(!e[r].item.disabled)return r}function te(e,t){let{level:n}=e[t];for(let r=t+1;r<e.length&&e[r].level>n;r+=1)if(e[r].level===n+1&&!e[r].item.disabled)return r}var ne="FlatTree: a tree needs an accessible name. Pass `aria-label` or `aria-labelledby`.",re="FlatTree: selectionMode=\"multiple\" needs a model that holds the check states: pass `selectionMode: 'multiple'` to `useFlatTree` as well; until then every item shows unchecked.",ie='FlatTree: `selected` has no effect with selectionMode="multiple"; use the model\'s `checkedItems`, and `current` for the item the user is on.',ae='FlatTree: selectionMode="single" draws a radio on every item for `selected`; pass `selected` (null while nothing is selected) and update it from `onItemSelect`.',b=({model:e,virtualWindow:m,renderItem:b,selectionMode:x,selected:S,current:C,onItemSelect:oe,className:se,onKeyDown:ce,onFocus:le,onBlur:ue,onPointerDownCapture:w,ref:de,...T})=>{let E=e.getTreeProps().selectionMode,D=x??E,O=e.visibleItems,k=O.length,A=m!==void 0,j=D===`multiple`?void 0:D===`single`?S??null:S,[M]=f.useState(()=>new ee),{focused:N,pending:P}=f.useSyncExternalStore(M.subscribe,M.getSnapshot,M.getServerSnapshot),fe=f.useMemo(()=>O.find(e=>!e.item.disabled),[O]),pe=N===null?void 0:e.getItem(N),F=j==null?void 0:e.getItem(j),I=pe??(F&&!F.item.disabled?F:fe),L=I?.index,R=P===null?void 0:e.getItem(P)?.index,z=f.useMemo(()=>[L,R].filter(e=>e!==void 0),[L,R]),B=a.useEventCallback(t=>{t.item.disabled||(t.isBranch&&e.toggle(t.item.value),oe?.(t.item.value))}),V=a.useEventCallback((t,n)=>{t.item.disabled||e.setChecked(t.item.value,t.checked!==`checked`,n)}),H=m?.itemSize,U=I?.item.value??null,me=f.useMemo(()=>({selectionMode:D,selected:j,current:C,tabStop:U,itemSize:H,activate:B,toggleChecked:V}),[D,j,C,U,H,B,V]),W=f.useRef(null),he=c.useMergedRefs(de,W,m?.scrollRef),G=(e,t)=>{let n=O[t];if(!n)return;m?.scrollToIndex(t,{align:`auto`});let r=v(e,t);r?(M.update({pending:null}),r.focus()):M.update({pending:n.item.value})},{onTypeahead:ge,isSearching:_e}=s.useTypeahead({getItems:()=>O.map(e=>({value:e.item.value,text:e.item.label??e.item.value,disabled:e.item.disabled})),onMatch:t=>{let n=W.current,r=e.getItem(t);n&&r&&G(n,r.index)}}),K=f.useRef(null),q=f.useRef(!1),ve=a.useEventCallback(e=>{A&&l.isOwnEvent(e)&&(q.current=!0)});f.useEffect(()=>{let e=W.current?.ownerDocument;if(!A||!e)return;let t=()=>{q.current=!1};return e.addEventListener(`keydown`,t,!0),()=>e.removeEventListener(`keydown`,t,!0)},[A]);let J=f.useRef(!1),ye=a.useEventCallback(t=>{let n=q.current;q.current=!1,J.current=!t.currentTarget.contains(t.target);let r=g(t.currentTarget,t.target),i=r?_(r):null,a=i===null?void 0:O[i];if(!a||i===null)return;M.update({focused:a.item.value,pending:null});let o=[];for(let t=a.parentValue;t!==void 0;)o.push(t),t=e.getItem(t)?.parentValue;K.current={path:o,index:i},m&&!n&&m.scrollToIndex(i,{align:`auto`})}),Y=a.useEventCallback(e=>{let t=e.currentTarget,n=e.relatedTarget;if(n&&t.contains(n))return;J.current=!1;let r=e.target;queueMicrotask(()=>{if(!t.isConnected||J.current)return;let e=t.ownerDocument.activeElement;e&&t.contains(e)||r.isConnected&&M.update({focused:null})})}),be=a.useEventCallback(t=>{let n=t.currentTarget,r=g(n,t.target),i=r?_(r):null;if(i===null||i>=k||l.isEditableTarget(t.target))return;let a=O[i],s=M.getSnapshot().pending,c=(s===null?void 0:e.getItem(s)?.index)??i;if(t.key.length===1&&(t.key!==`*`||_e())&&ge(t,O[c].item.value)){t.preventDefault();return}if(t.altKey||t.ctrlKey||t.metaKey)return;let u;switch(t.key){case`ArrowDown`:u=y(O,c,1);break;case`ArrowUp`:u=y(O,c,-1);break;case`Home`:u=y(O,-1,1);break;case`End`:u=y(O,k,-1);break;case`Enter`:t.preventDefault(),B(a);return;case` `:t.preventDefault(),D===`multiple`?V(a,t.nativeEvent):B(a);return;case`*`:{t.preventDefault();let n=O.filter(e=>e.parentValue===a.parentValue&&e.isBranch&&!e.expanded&&!e.item.disabled).map(e=>e.item.value);n.length>0&&e.expand(n);return}default:{let r=o.getArrowIntent(t.key,{orientation:`horizontal`,dir:o.getDirection(n)});if(r===null)return;if(r===`next`){if(a.isBranch&&!a.expanded){t.preventDefault(),a.item.disabled||e.expand(a.item.value);return}a.expanded&&(u=te(O,i))}else{if(a.isBranch&&a.expanded&&!a.item.disabled){t.preventDefault(),e.collapse(a.item.value);return}for(let t=a.parentValue;t!==void 0&&u===void 0;){let n=e.getItem(t);if(!n)break;n.item.disabled||(u=n.index),t=n.parentValue}}if(u===void 0){t.preventDefault();return}}}t.preventDefault();let d=u??c;if(d===i){M.update({pending:null}),m?.scrollToIndex(d,{align:`auto`});return}G(n,d)}),X=f.useRef(null);f.useLayoutEffect(()=>{let t=W.current,n=M.getSnapshot().focused,r=n===null?void 0:e.getItem(n)?.index,i=X.current;if(X.current=null,!m||!t||n===null||r===void 0)return;let a=m.itemSize,o=t.scrollTop;if(i?.value===n&&r!==i.index&&t.contains(t.ownerDocument.activeElement)){let e=Math.floor(o/a)===Math.floor(i.top/a)?o:i.top,n=i.index*a;n+a>e&&n<e+t.clientHeight&&(t.scrollTop=e+(r-i.index)*a,m.scrollToIndex(r,{align:`auto`}),o=t.scrollTop)}X.current={value:n,index:r,top:o}}),f.useLayoutEffect(()=>{let t=W.current;if(!t)return;let n=t.ownerDocument,r=n.activeElement,i=!r||r===n.body||!r.isConnected,a=M.getSnapshot();if(a.pending!==null){M.update({pending:null});let n=e.getItem(a.pending),o=n?v(t,n.index):null;o&&(i||t.contains(r))&&o.focus();return}if(a.focused===null||e.getItem(a.focused)||(M.update({focused:null}),!i||k===0))return;let o=K.current,s=o?.path.map(t=>e.getItem(t)).find(e=>e)?.index;s??=Math.min(o?.index??0,k-1),G(t,s)});let Z=!T[`aria-label`]&&!T[`aria-labelledby`];f.useEffect(()=>{Z&&n.warnOnce(`FlatTree:name`,ne)},[Z]);let Q=D===`multiple`&&E!==`multiple`;f.useEffect(()=>{Q&&n.warnOnce(`FlatTree:selection-mode`,re)},[Q]),f.useEffect(()=>{D===`multiple`&&S!==void 0&&n.warnOnce(`FlatTree:selected-with-multiple`,ie),D===`single`&&S===void 0&&n.warnOnce(`FlatTree:single-without-selected`,ae)},[D,S]);let $=e=>(0,p.jsx)(d.FlatTreeItem,{item:e,children:b?b(e):e.item.label??e.item.value},`item:${e.item.value}`),xe=m?m.layout(k,{keep:z}).map(e=>e.kind===`item`?$(O[e.index]):(0,p.jsx)(h,{size:e.size},`spacer:${e.key}`)):O.map($);return(0,p.jsx)(u.FlatTreeContext.Provider,{value:me,children:(0,p.jsx)(`div`,{role:`tree`,"aria-multiselectable":D===`multiple`||void 0,"data-selection-mode":D,tabIndex:A&&U!==null?-1:void 0,className:t.cn(i.flatTreeClassNames.root,`text-body-1`,A&&`overflow-y-auto [overflow-anchor:none]`,se),...T,onKeyDown:r.composeEventHandlers(ce,be),onFocus:r.composeEventHandlers(le,ye,{checkDefaultPrevented:!1}),onBlur:r.composeEventHandlers(ue,Y,{checkDefaultPrevented:!1}),onPointerDownCapture:r.composeEventHandlers(w,ve),ref:he,children:xe})})};b.displayName=`FlatTree`;var x=Object.assign(b,{Item:d.FlatTreeItem});exports.FlatTree=x,exports.FlatTreeItem=d.FlatTreeItem;
2
+ //# sourceMappingURL=FlatTree.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlatTree.cjs","names":["flatTreeClassNames","React","useEventCallback","useMergedRefs","useTypeahead","isOwnEvent","isEditableTarget","getArrowIntent","getDirection","FlatTreeItem","FlatTreeContext","cn","composeEventHandlers","require_runtime","require_cn","require_dev","require_composeEventHandlers","require_classNames","require_useEventCallback","require_direction","require_useTypeahead","require_useMergedRefs","require_events","require_FlatTree_context","require_FlatTree_item","react","react_jsx_runtime","NO_FOCUS","FlatTreeFocusStore","listener","state","next","FlatTreeSpacer","size","getOwnItem","el","target","root","getIndex","value","getRenderedItem","index","nextEnabled","at","from","step","rows","firstEnabledChild","level","NAME_MESSAGE","SELECTION_MODE_MESSAGE","SELECTED_WITH_MULTIPLE_MESSAGE","SINGLE_WITHOUT_SELECTED_MESSAGE","FlatTreeRoot","selectionModeProp","rest","modelMode","model","selectionMode","count","windowed","virtualWindow","effectiveSelected","selected","focusStore","firstEnabled","row","focusedRow","focused","selectedRow","tabStopRow","tabStopIndex","pendingIndex","pending","keep","activate","onItemSelect","toggleChecked","event","itemSize","tabStop","context","current","rootRef","mergedRef","ref","moveTo","focusPathRef","pointerPressRef","handlePointerDownCapture","doc","clear","focusInPopupRef","handleFocus","pointerFocus","path","parent","handleBlur","blurred","active","handleKeyDown","awaited","isSearching","onTypeahead","siblings","other","intent","parentRow","goal","focusPlaceRef","last","top","before","lastTop","lost","snapshot","record","unnamed","missingChecks","renderRow","renderItem","content","entry","className","onKeyDown","onFocus","onBlur","onPointerDownCapture","FlatTree"],"sources":["../../../src/components/layout/FlatTree.tsx"],"sourcesContent":["import * as React from 'react';\nimport { flatTreeClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnOnce } from '../../lib/dev';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { isEditableTarget, isOwnEvent } from '../../lib/events';\nimport type { VisibleFlatItem } from '../../lib/flatTree';\nimport type { CheckState } from '../../lib/treeCascade';\nimport type { SelectionMode } from '../../lib/types';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useTypeahead } from '../../hooks/useTypeahead';\nimport type { VirtualWindow } from '../../hooks/useVirtualWindow';\nimport { FlatTreeContext, type FlatTreeContextValue, type FlatTreeRow } from './FlatTree.context';\nimport { FlatTreeItem } from './FlatTree.item';\nimport type { FlatTreeModel } from './useFlatTree';\n\nexport type { FlatTreeItemProps } from './FlatTree.item';\n\n/** Properties for the FlatTree component. */\nexport interface FlatTreeProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children' | 'onSelect'\n> {\n /** The tree's model, from `useFlatTree`: the visible rows, the expanded and the checked state. */\n model: FlatTreeModel;\n /**\n * Renders only the items in view (and a few beyond), from `useVirtualWindow({ itemSize })`. The\n * tree is then the scrolling element: give it a bounded height (a class or a style). Every item\n * is exactly `itemSize` pixels tall, so its content must fit in one row. Without it every visible\n * item is rendered.\n *\n * The tree element is then no tab stop of its own while an item is (`tabIndex` -1, as Firefox\n * would stop on a scroller; a `tabIndex` you pass wins), and the browser's scroll anchoring is\n * off on it (the window lays the items out): when rows are inserted or removed above the focused\n * item while it is in view (`*`, or a change of the model from code), the tree moves the view\n * with it, so it stays where it was.\n */\n virtualWindow?: VirtualWindow;\n /**\n * The content of an item, from its row: the item data with its level, position, set size,\n * expanded state and, in multiple mode, its check state. Called for the rendered items only.\n * @default the item's `label`, else its `value`\n */\n renderItem?: (item: VisibleFlatItem & { checked?: CheckState }) => React.ReactNode;\n /**\n * How items are selected, as the nested `Tree`'s `selectionMode`. `'multiple'` draws a checkbox\n * on every item, bound to the model's checked items (create the model with\n * `selectionMode: 'multiple'`); `'single'` draws a radio for `selected`. Spread\n * `model.getTreeProps()` on the tree to pass the model's mode.\n * @default the model's mode (`model.getTreeProps().selectionMode`)\n */\n selectionMode?: 'none' | SelectionMode;\n /**\n * Value of the selected item. When set (also to `null`), every item carries `aria-selected`, and\n * the selected item is where keyboard focus enters the tree while it is visible. It has no effect\n * with `selectionMode=\"multiple\"` (a development warning). With `selectionMode=\"single\"` every\n * item carries `aria-selected` even while it is not set (a development warning: the radios need\n * it).\n */\n selected?: string | null;\n /** Value of the current item (for example the open page): it gets `aria-current=\"true\"`. */\n current?: string | null;\n /**\n * Called with an item's value every time it is activated (a click on its row, Enter, or Space\n * unless the tree has checkboxes), also when the same item is activated again.\n */\n onItemSelect?: (value: string) => void;\n /** Ref to the `role=\"tree\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** The focused and the awaited item of a FlatTree, by value (see {@link FlatTreeFocusStore}). */\ninterface FlatTreeFocus {\n /** The item that has focus while focus is inside the tree: kept rendered, and the tab stop. */\n focused: string | null;\n /** The item a key moved to that was not rendered: kept rendered, focused after the commit. */\n pending: string | null;\n}\n\nconst NO_FOCUS: FlatTreeFocus = { focused: null, pending: null };\n\n/**\n * The focused and the awaited item of a FlatTree, read during render through\n * `useSyncExternalStore` and written by the tree's handlers and layout effect (C-HOOKS: no state\n * set in an effect, no ref read during render).\n */\nclass FlatTreeFocusStore {\n private state: FlatTreeFocus = NO_FOCUS;\n private readonly listeners = new Set<() => void>();\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n getSnapshot = (): FlatTreeFocus => this.state;\n\n getServerSnapshot = (): FlatTreeFocus => NO_FOCUS;\n\n /** Changes the given fields; notifies only when one of them changed. */\n update(next: Partial<FlatTreeFocus>): void {\n const state = { ...this.state, ...next };\n if (state.focused === this.state.focused && state.pending === this.state.pending) return;\n this.state = state;\n for (const listener of this.listeners) listener();\n }\n}\n\n/** The element that stands in for the items of a windowed tree that are not rendered. */\nfunction FlatTreeSpacer({ size }: { size: number }) {\n return (\n <div\n role=\"none\"\n aria-hidden=\"true\"\n data-virtual-spacer=\"\"\n className={flatTreeClassNames.spacer}\n style={{ height: size }}\n />\n );\n}\nFlatTreeSpacer.displayName = 'FlatTreeSpacer';\n\n/** The item element (a treeitem child of `root`) that holds `target`; `null` for a portal's. */\nfunction getOwnItem(root: Element, target: EventTarget | null): HTMLElement | null {\n let el = target instanceof Element ? target : null;\n while (el && el.parentElement !== root) el = el.parentElement;\n return el instanceof HTMLElement && el.getAttribute('role') === 'treeitem' ? el : null;\n}\n\n/** The place of an item element in the visible rows (`data-index`). */\nfunction getIndex(el: Element): number | null {\n const value = el.getAttribute('data-index');\n return value !== null && /^\\d+$/.test(value) ? Number(value) : null;\n}\n\n/** The rendered item at `index` of the visible rows, or `null` while it is not rendered. */\nfunction getRenderedItem(root: Element, index: number): HTMLElement | null {\n return root.querySelector<HTMLElement>(`:scope > [data-index=\"${index}\"]`);\n}\n\n/** The next enabled row from `from` (exclusive) in the direction of `step`, or `undefined`. */\nfunction nextEnabled(rows: readonly FlatTreeRow[], from: number, step: 1 | -1): number | undefined {\n for (let at = from + step; at >= 0 && at < rows.length; at += step) {\n if (!rows[at].item.disabled) return at;\n }\n return undefined;\n}\n\n/** The first enabled child row of the expanded row at `index`, or `undefined`. */\nfunction firstEnabledChild(rows: readonly FlatTreeRow[], index: number): number | undefined {\n const { level } = rows[index];\n for (let at = index + 1; at < rows.length && rows[at].level > level; at += 1) {\n if (rows[at].level === level + 1 && !rows[at].item.disabled) return at;\n }\n return undefined;\n}\n\nconst NAME_MESSAGE =\n 'FlatTree: a tree needs an accessible name. Pass `aria-label` or `aria-labelledby`.';\n\nconst SELECTION_MODE_MESSAGE =\n 'FlatTree: selectionMode=\"multiple\" needs a model that holds the check states: pass ' +\n \"`selectionMode: 'multiple'` to `useFlatTree` as well; until then every item shows unchecked.\";\n\nconst SELECTED_WITH_MULTIPLE_MESSAGE =\n 'FlatTree: `selected` has no effect with selectionMode=\"multiple\"; use the model\\'s ' +\n '`checkedItems`, and `current` for the item the user is on.';\n\nconst SINGLE_WITHOUT_SELECTED_MESSAGE =\n 'FlatTree: selectionMode=\"single\" draws a radio on every item for `selected`; pass `selected` ' +\n '(null while nothing is selected) and update it from `onItemSelect`.';\n\n// The FlatTree root, documented on the exported `FlatTree` const.\nconst FlatTreeRoot = ({\n model,\n virtualWindow,\n renderItem,\n selectionMode: selectionModeProp,\n selected,\n current,\n onItemSelect,\n className,\n onKeyDown,\n onFocus,\n onBlur,\n onPointerDownCapture,\n ref,\n ...rest\n}: FlatTreeProps) => {\n const modelMode = model.getTreeProps().selectionMode;\n const selectionMode = selectionModeProp ?? modelMode;\n const rows = model.visibleItems;\n const count = rows.length;\n const windowed = virtualWindow !== undefined;\n\n // An item carries aria-checked or aria-selected, never both (APG); in single mode every item\n // carries aria-selected from the first render, so the radios and the state agree.\n const effectiveSelected =\n selectionMode === 'multiple'\n ? undefined\n : selectionMode === 'single'\n ? (selected ?? null)\n : selected;\n\n const [focusStore] = React.useState(() => new FlatTreeFocusStore());\n const { focused, pending } = React.useSyncExternalStore(\n focusStore.subscribe,\n focusStore.getSnapshot,\n focusStore.getServerSnapshot,\n );\n\n // The tab stop follows the model, not the DOM (most items are not rendered): the focused item,\n // else the selected item while it is visible and enabled, else the first enabled item.\n const firstEnabled = React.useMemo(() => rows.find((row) => !row.item.disabled), [rows]);\n const focusedRow = focused === null ? undefined : model.getItem(focused);\n const selectedRow =\n effectiveSelected === undefined || effectiveSelected === null\n ? undefined\n : model.getItem(effectiveSelected);\n const tabStopRow =\n focusedRow ?? (selectedRow && !selectedRow.item.disabled ? selectedRow : firstEnabled);\n const tabStopIndex = tabStopRow?.index;\n const pendingIndex = pending === null ? undefined : model.getItem(pending)?.index;\n // The tab stop and the awaited item stay rendered outside the window (a focused item scrolled\n // away keeps focus and its tab stop).\n const keep = React.useMemo(\n () => [tabStopIndex, pendingIndex].filter((index): index is number => index !== undefined),\n [tabStopIndex, pendingIndex],\n );\n\n const activate = useEventCallback((row: FlatTreeRow) => {\n if (row.item.disabled) return;\n if (row.isBranch) model.toggle(row.item.value);\n onItemSelect?.(row.item.value);\n });\n const toggleChecked = useEventCallback((row: FlatTreeRow, event: Event) => {\n if (row.item.disabled) return;\n model.setChecked(row.item.value, row.checked !== 'checked', event);\n });\n\n const itemSize = virtualWindow?.itemSize;\n const tabStop = tabStopRow?.item.value ?? null;\n const context = React.useMemo<FlatTreeContextValue>(\n () => ({\n selectionMode,\n selected: effectiveSelected,\n current,\n tabStop,\n itemSize,\n activate,\n toggleChecked,\n }),\n [selectionMode, effectiveSelected, current, tabStop, itemSize, activate, toggleChecked],\n );\n\n const rootRef = React.useRef<HTMLDivElement | null>(null);\n // The tree is the window's scroller.\n const mergedRef = useMergedRefs<HTMLDivElement>(ref, rootRef, virtualWindow?.scrollRef);\n\n /**\n * Focuses the row at `index`, moving the window to it first (in the same update, so no frame\n * shows the spacer); a row that is not rendered is awaited and focused after the commit that\n * renders it.\n */\n const moveTo = (root: HTMLElement, index: number) => {\n const row = rows[index];\n if (!row) return;\n virtualWindow?.scrollToIndex(index, { align: 'auto' });\n const el = getRenderedItem(root, index);\n if (el) {\n focusStore.update({ pending: null });\n el.focus();\n } else {\n focusStore.update({ pending: row.item.value });\n }\n };\n\n // Typeahead over the visible items' labels (disabled items are skipped).\n const { onTypeahead, isSearching } = useTypeahead({\n getItems: () =>\n rows.map((row) => ({\n value: row.item.value,\n text: row.item.label ?? row.item.value,\n disabled: row.item.disabled,\n })),\n onMatch: (value) => {\n const root = rootRef.current;\n const row = model.getItem(value);\n if (root && row) moveTo(root, row.index);\n },\n });\n\n /** The visible item, its ancestors from the parent up, and its place, of the focused item. */\n const focusPathRef = React.useRef<{ path: string[]; index: number } | null>(null);\n\n /**\n * Set by a pointer press in a windowed tree until the focus it gives, or until a key press:\n * keyboard focus always follows one, so a press that gave no focus never keeps a later keyboard\n * focus from being scrolled into view. A press in a popup an item opened is the popup's.\n */\n const pointerPressRef = React.useRef(false);\n const handlePointerDownCapture = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n if (windowed && isOwnEvent(event)) pointerPressRef.current = true;\n });\n React.useEffect(() => {\n const doc = rootRef.current?.ownerDocument;\n if (!windowed || !doc) return;\n const clear = () => {\n pointerPressRef.current = false;\n };\n doc.addEventListener('keydown', clear, true);\n return () => doc.removeEventListener('keydown', clear, true);\n }, [windowed]);\n\n /**\n * Whether focus is in a popup that an item opened (an element outside the tree's DOM whose focus\n * React bubbles through the tree): the focused item stays kept. Written by the focus and blur\n * handlers.\n */\n const focusInPopupRef = React.useRef(false);\n\n // Focus moving onto an item makes it the focused item (the tab stop, kept rendered). Unless a\n // pointer press gave the focus, the window moves to it in the same update (a browser's own focus\n // scrolling moves the view a frame before the window would follow).\n const handleFocus = useEventCallback((event: React.FocusEvent<HTMLDivElement>) => {\n const pointerFocus = pointerPressRef.current;\n pointerPressRef.current = false;\n focusInPopupRef.current = !event.currentTarget.contains(event.target as Node);\n const el = getOwnItem(event.currentTarget, event.target);\n const index = el ? getIndex(el) : null;\n const row = index === null ? undefined : rows[index];\n if (!row || index === null) return;\n focusStore.update({ focused: row.item.value, pending: null });\n const path: string[] = [];\n for (let parent = row.parentValue; parent !== undefined;) {\n path.push(parent);\n parent = model.getItem(parent)?.parentValue;\n }\n focusPathRef.current = { path, index };\n if (virtualWindow && !pointerFocus) virtualWindow.scrollToIndex(index, { align: 'auto' });\n });\n\n // Focus leaving the tree (for an element outside it, or for nothing) ends the focused item; the\n // tab stop then returns to the selected or the first item. Decided once focus has landed: a\n // popup an item opened takes focus in the same task (`focusInPopupRef`).\n const handleBlur = useEventCallback((event: React.FocusEvent<HTMLDivElement>) => {\n const root = event.currentTarget;\n const next = event.relatedTarget as Node | null;\n if (next && root.contains(next)) return;\n focusInPopupRef.current = false;\n const blurred = event.target as Node;\n queueMicrotask(() => {\n if (!root.isConnected || focusInPopupRef.current) return;\n const active = root.ownerDocument.activeElement;\n if (active && root.contains(active)) return;\n // A focused item that left the document (a branch collapsed around it): the commit's check\n // below has moved focus, or decided that it cannot.\n if (!blurred.isConnected) return;\n focusStore.update({ focused: null });\n });\n });\n\n const handleKeyDown = useEventCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n const root = event.currentTarget;\n // A key from a portal is the portal's; a text field in the content keeps its keys.\n const el = getOwnItem(root, event.target);\n const current = el ? getIndex(el) : null;\n if (current === null || current >= count || isEditableTarget(event.target)) return;\n const row = rows[current];\n // Keys pressed before an awaited item renders move from it (possible only within one task).\n const awaited = focusStore.getSnapshot().pending;\n const from = (awaited === null ? undefined : model.getItem(awaited)?.index) ?? current;\n\n // Typeahead; a Space continues a search, and `*` starts none.\n if (event.key.length === 1 && (event.key !== '*' || isSearching())) {\n if (onTypeahead(event, rows[from].item.value)) {\n event.preventDefault();\n return;\n }\n }\n if (event.altKey || event.ctrlKey || event.metaKey) return;\n\n let target: number | undefined;\n switch (event.key) {\n case 'ArrowDown':\n target = nextEnabled(rows, from, 1);\n break;\n case 'ArrowUp':\n target = nextEnabled(rows, from, -1);\n break;\n case 'Home':\n target = nextEnabled(rows, -1, 1);\n break;\n case 'End':\n target = nextEnabled(rows, count, -1);\n break;\n case 'Enter':\n event.preventDefault();\n activate(row);\n return;\n case ' ':\n event.preventDefault();\n // A checkbox tree toggles the focused item's check (APG); the other modes activate.\n if (selectionMode === 'multiple') toggleChecked(row, event.nativeEvent);\n else activate(row);\n return;\n case '*': {\n event.preventDefault();\n // The siblings of a visible item are all visible (their parent is expanded).\n const siblings = rows\n .filter(\n (other) =>\n other.parentValue === row.parentValue &&\n other.isBranch &&\n !other.expanded &&\n !other.item.disabled,\n )\n .map((other) => other.item.value);\n if (siblings.length > 0) model.expand(siblings);\n return;\n }\n default: {\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(root),\n });\n if (intent === null) return;\n if (intent === 'next') {\n // Expand a collapsed branch (focus stays), else move to the first child.\n if (row.isBranch && !row.expanded) {\n event.preventDefault();\n if (!row.item.disabled) model.expand(row.item.value);\n return;\n }\n if (row.expanded) target = firstEnabledChild(rows, current);\n } else {\n // Collapse an expanded branch (focus stays), else move to the nearest enabled ancestor.\n if (row.isBranch && row.expanded && !row.item.disabled) {\n event.preventDefault();\n model.collapse(row.item.value);\n return;\n }\n for (let parent = row.parentValue; parent !== undefined && target === undefined;) {\n const parentRow = model.getItem(parent);\n if (!parentRow) break;\n if (!parentRow.item.disabled) target = parentRow.index;\n parent = parentRow.parentValue;\n }\n }\n if (target === undefined) {\n event.preventDefault();\n return;\n }\n }\n }\n event.preventDefault();\n // No item to move to: the focused item stays, and is brought into view.\n const goal = target ?? from;\n if (goal === current) {\n focusStore.update({ pending: null });\n virtualWindow?.scrollToIndex(goal, { align: 'auto' });\n return;\n }\n moveTo(root, goal);\n });\n\n /**\n * The focused item of a windowed tree, its place in the visible rows and the scroll offset, at\n * the last commit (written by the layout effect below).\n */\n const focusPlaceRef = React.useRef<{ value: string; index: number; top: number } | null>(null);\n\n // After every commit of a windowed tree: rows inserted or removed above the focused item while\n // it was in view (`*`, a model change from code) move the view with it, so it stays where it\n // was, and the window follows in the same update. The browser's scroll anchoring would do the\n // same a frame before the window follows; it is off (the window lays the rows out).\n React.useLayoutEffect(() => {\n const root = rootRef.current;\n const value = focusStore.getSnapshot().focused;\n const index = value === null ? undefined : model.getItem(value)?.index;\n const last = focusPlaceRef.current;\n focusPlaceRef.current = null;\n if (!virtualWindow || !root || value === null || index === undefined) return;\n const size = virtualWindow.itemSize;\n let top = root.scrollTop;\n if (\n last?.value === value &&\n index !== last.index &&\n root.contains(root.ownerDocument.activeElement)\n ) {\n // Rows removed above may leave less content than the offset, which the browser has clamped\n // by now: an offset in another row than the one recorded (the tree commits at every row the\n // view enters) stands for that, and the recorded one is where the view was.\n const before = Math.floor(top / size) === Math.floor(last.top / size) ? top : last.top;\n const lastTop = last.index * size;\n if (lastTop + size > before && lastTop < before + root.clientHeight) {\n root.scrollTop = before + (index - last.index) * size;\n virtualWindow.scrollToIndex(index, { align: 'auto' });\n top = root.scrollTop;\n }\n }\n focusPlaceRef.current = { value, index, top };\n });\n\n // After every commit: focus the awaited item, which the commit rendered (it is kept), unless\n // focus went outside the tree meanwhile; and when the focused item is no longer visible (a\n // branch collapsed around it, or the items changed) while focus is lost with it, move focus to\n // its nearest visible ancestor, else to the visible item nearest to its place. Never to the body.\n React.useLayoutEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const doc = root.ownerDocument;\n const active = doc.activeElement;\n const lost = !active || active === doc.body || !active.isConnected;\n const snapshot = focusStore.getSnapshot();\n if (snapshot.pending !== null) {\n focusStore.update({ pending: null });\n const row = model.getItem(snapshot.pending);\n const el = row ? getRenderedItem(root, row.index) : null;\n if (el && (lost || root.contains(active))) el.focus();\n return;\n }\n if (snapshot.focused === null || model.getItem(snapshot.focused)) return;\n focusStore.update({ focused: null });\n if (!lost || count === 0) return;\n const record = focusPathRef.current;\n let target = record?.path.map((value) => model.getItem(value)).find((row) => row)?.index;\n target ??= Math.min(record?.index ?? 0, count - 1);\n moveTo(root, target);\n });\n\n // Development diagnostics (C-DEV): emitted from effects, once per page.\n const unnamed = !rest['aria-label'] && !rest['aria-labelledby'];\n React.useEffect(() => {\n if (unnamed) warnOnce('FlatTree:name', NAME_MESSAGE);\n }, [unnamed]);\n const missingChecks = selectionMode === 'multiple' && modelMode !== 'multiple';\n React.useEffect(() => {\n if (missingChecks) warnOnce('FlatTree:selection-mode', SELECTION_MODE_MESSAGE);\n }, [missingChecks]);\n React.useEffect(() => {\n if (selectionMode === 'multiple' && selected !== undefined) {\n warnOnce('FlatTree:selected-with-multiple', SELECTED_WITH_MULTIPLE_MESSAGE);\n }\n if (selectionMode === 'single' && selected === undefined) {\n warnOnce('FlatTree:single-without-selected', SINGLE_WITHOUT_SELECTED_MESSAGE);\n }\n }, [selectionMode, selected]);\n\n const renderRow = (row: FlatTreeRow) => (\n <FlatTreeItem key={`item:${row.item.value}`} item={row}>\n {renderItem ? renderItem(row) : (row.item.label ?? row.item.value)}\n </FlatTreeItem>\n );\n const content = virtualWindow\n ? virtualWindow\n .layout(count, { keep })\n .map((entry) =>\n entry.kind === 'item' ? (\n renderRow(rows[entry.index])\n ) : (\n <FlatTreeSpacer key={`spacer:${entry.key}`} size={entry.size} />\n ),\n )\n : rows.map(renderRow);\n\n return (\n <FlatTreeContext.Provider value={context}>\n <div\n role=\"tree\"\n aria-multiselectable={selectionMode === 'multiple' ? true : undefined}\n data-selection-mode={selectionMode}\n // A windowed tree's tab stop is an item: the scroller is none of its own (Firefox makes a\n // scroller a tab stop). The consumer's `tabIndex` wins.\n tabIndex={windowed && tabStop !== null ? -1 : undefined}\n className={cn(\n flatTreeClassNames.root,\n 'text-body-1',\n // The window lays the rows out: the browser's scroll anchoring only fights it.\n windowed && 'overflow-y-auto [overflow-anchor:none]',\n className,\n )}\n {...rest}\n onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}\n onFocus={composeEventHandlers(onFocus, handleFocus, { checkDefaultPrevented: false })}\n onBlur={composeEventHandlers(onBlur, handleBlur, { checkDefaultPrevented: false })}\n onPointerDownCapture={composeEventHandlers(onPointerDownCapture, handlePointerDownCapture)}\n ref={mergedRef}\n >\n {content}\n </div>\n </FlatTreeContext.Provider>\n );\n};\nFlatTreeRoot.displayName = 'FlatTree';\n\n/**\n * A tree built from flat data (WAI-ARIA Tree View pattern) that can render only the items in\n * view, for trees of thousands of items. Its model comes from `useFlatTree(items, options)`: items\n * listed with a `parentValue`, in any order, the expanded and the checked state. The tree renders\n * the visible items (the roots and the children of every expanded branch) as sibling\n * `role=\"treeitem\"` elements with `aria-level`, `aria-setsize` and `aria-posinset` from the data,\n * `aria-expanded` on branches, and the nested `Tree`'s chevron, checkbox and radio.\n *\n * ```tsx\n * const model = useFlatTree(items, { defaultExpandedItems: ['docs'] });\n * const virtualWindow = useVirtualWindow({ itemSize: 28 });\n * <FlatTree aria-label=\"Files\" model={model} {...model.getTreeProps()} virtualWindow={virtualWindow} style={{ height: 400 }} />\n * ```\n *\n * Windowing: with `virtualWindow` the tree is the scrolling element (it needs a bounded height),\n * renders the items in view plus the window's overscan and spacers for the others, and every item\n * is exactly the window's `itemSize` tall. The server renders the first window. Keys move over the\n * whole visible list, scrolling an item that is not rendered into view before focusing it, and the\n * focused item stays rendered (and focused) while it is scrolled away.\n *\n * Keyboard: a single tab stop, on the focused item while focus is inside, else on the `selected`\n * item while it is visible, else on the first enabled item; Tab leaves the tree. Up/Down move\n * between the visible items, Home/End to the first and last, Right expands a collapsed branch or\n * moves to its first child, Left collapses an expanded branch or moves to the parent (both\n * mirrored in right-to-left layouts), Enter activates (and toggles a branch), and so does Space\n * unless the tree has checkboxes, `*` expands the sibling branches, and typing moves to the next\n * visible item whose label starts with the typed text (items under a collapsed branch are not\n * searched). The focused item stays the focused item (rendered, and the tab stop) while focus is\n * in a popup that its content opened, such as a menu in a portal, so the popup can return focus\n * to it.\n *\n * Selection, as the nested `Tree`: `selected` and `onItemSelect` (single selection and activation,\n * with radios in `selectionMode=\"single\"`), `current`, and with `selectionMode=\"multiple\"` a\n * checkbox on every item bound to the model's `checkedItems` (Space or a click on the checkbox\n * toggles it, and checks cascade). An item whose data is `disabled` is `aria-disabled`, is skipped\n * by the keys and typeahead, never holds the tab stop (except while a pointer press has focused\n * it), and is neither activated, expanded nor checked by the user (a check of its parent still\n * includes it).\n *\n * When a branch collapses around the focused item (from code), focus moves to that branch, so it\n * never falls to the page. Items expand and collapse at once, without motion: there is no child\n * group to animate. A selected item under a collapsed branch is not the tab stop until it is\n * visible again.\n *\n * `FlatTree.Item` is the row the tree renders for each visible item (it is not written by hand);\n * it is also exported as `FlatTreeItem` for React Server Components, which cannot use the dotted\n * form.\n */\nexport const FlatTree = /* @__PURE__ */ Object.assign(FlatTreeRoot, { Item: FlatTreeItem });\n\nexport { FlatTreeItem };\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/dev.cjs");let n=require("react");n=e.__toESM(n,1);var r=n.createContext(null),i={selectionMode:`none`,selected:void 0,current:void 0,tabStop:null,itemSize:void 0,activate:()=>{},toggleChecked:()=>{}};function a(e){return n.useContext(r)||(t.reportMissingContext(e,`<FlatTree>`),i)}exports.FlatTreeContext=r,exports.useFlatTreeContext=a;
2
+ //# sourceMappingURL=FlatTree.context.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlatTree.context.cjs","names":["React","require_runtime","require_dev","react","FlatTreeContext","INERT_CONTEXT","useFlatTreeContext","component"],"sources":["../../../src/components/layout/FlatTree.context.ts"],"sourcesContent":["import * as React from 'react';\nimport { reportMissingContext } from '../../lib/dev';\nimport type { VisibleFlatItem } from '../../lib/flatTree';\nimport type { CheckState } from '../../lib/treeCascade';\nimport type { SelectionMode } from '../../lib/types';\n\n/** One row of a FlatTree: a visible item of its model, with its check state in multiple mode. */\nexport type FlatTreeRow = VisibleFlatItem & { checked?: CheckState };\n\n/** What a FlatTree gives each of its items. */\nexport interface FlatTreeContextValue {\n /** The resolved selection mode. */\n selectionMode: 'none' | SelectionMode;\n /** The selected value; `undefined` while no item carries `aria-selected` (multiple mode). */\n selected: string | null | undefined;\n /** The value of the current item, which gets `aria-current`. */\n current: string | null | undefined;\n /** The value of the item that holds the tab stop; `null` while no item can take it. */\n tabStop: string | null;\n /** The height of every item of a windowed tree, in pixels; `undefined` without a window. */\n itemSize: number | undefined;\n /** Activates a row (a click, Enter): a branch expands or collapses, and `onItemSelect` runs. */\n activate: (row: FlatTreeRow) => void;\n /** Toggles a row's check (multiple mode); `event` becomes `details.event`. */\n toggleChecked: (row: FlatTreeRow, event: Event) => void;\n}\n\nexport const FlatTreeContext = React.createContext<FlatTreeContextValue | null>(null);\n\nconst INERT_CONTEXT: FlatTreeContextValue = {\n selectionMode: 'none',\n selected: undefined,\n current: undefined,\n tabStop: null,\n itemSize: undefined,\n activate: () => {},\n toggleChecked: () => {},\n};\n\n/** C-CONTEXT: throws in development, logs once and returns an inert value in production. */\nexport function useFlatTreeContext(component: string): FlatTreeContextValue {\n const context = React.useContext(FlatTreeContext);\n if (context) return context;\n reportMissingContext(component, '<FlatTree>');\n return INERT_CONTEXT;\n}\n"],"mappings":"4IA2BA,IAAaI,EAAkBJ,EAAM,cAA2C,IAAI,EAE9EK,EAAsC,CAC1C,cAAe,OACf,SAAU,IAAA,GACV,QAAS,IAAA,GACT,QAAS,KACT,SAAU,IAAA,GACV,aAAgB,CAAC,EACjB,kBAAqB,CAAC,CACxB,EAGA,SAAgBC,EAAmB,EAAyC,CAI1E,OAHgBN,EAAM,WAAWI,CAC7B,IACJF,EAAA,qBAAqBK,EAAW,YAAY,EACrCF,EACT"}
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import { reportMissingContext as e } from "../../lib/dev.mjs";
3
+ import * as t from "react";
4
+ //#region src/components/layout/FlatTree.context.ts
5
+ var n = t.createContext(null), r = {
6
+ selectionMode: "none",
7
+ selected: void 0,
8
+ current: void 0,
9
+ tabStop: null,
10
+ itemSize: void 0,
11
+ activate: () => {},
12
+ toggleChecked: () => {}
13
+ };
14
+ function i(i) {
15
+ return t.useContext(n) || (e(i, "<FlatTree>"), r);
16
+ }
17
+ //#endregion
18
+ export { n as FlatTreeContext, i as useFlatTreeContext };
19
+
20
+ //# sourceMappingURL=FlatTree.context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlatTree.context.mjs","names":["React","FlatTreeContext","INERT_CONTEXT","useFlatTreeContext","reportMissingContext","component"],"sources":["../../../src/components/layout/FlatTree.context.ts"],"sourcesContent":["import * as React from 'react';\nimport { reportMissingContext } from '../../lib/dev';\nimport type { VisibleFlatItem } from '../../lib/flatTree';\nimport type { CheckState } from '../../lib/treeCascade';\nimport type { SelectionMode } from '../../lib/types';\n\n/** One row of a FlatTree: a visible item of its model, with its check state in multiple mode. */\nexport type FlatTreeRow = VisibleFlatItem & { checked?: CheckState };\n\n/** What a FlatTree gives each of its items. */\nexport interface FlatTreeContextValue {\n /** The resolved selection mode. */\n selectionMode: 'none' | SelectionMode;\n /** The selected value; `undefined` while no item carries `aria-selected` (multiple mode). */\n selected: string | null | undefined;\n /** The value of the current item, which gets `aria-current`. */\n current: string | null | undefined;\n /** The value of the item that holds the tab stop; `null` while no item can take it. */\n tabStop: string | null;\n /** The height of every item of a windowed tree, in pixels; `undefined` without a window. */\n itemSize: number | undefined;\n /** Activates a row (a click, Enter): a branch expands or collapses, and `onItemSelect` runs. */\n activate: (row: FlatTreeRow) => void;\n /** Toggles a row's check (multiple mode); `event` becomes `details.event`. */\n toggleChecked: (row: FlatTreeRow, event: Event) => void;\n}\n\nexport const FlatTreeContext = React.createContext<FlatTreeContextValue | null>(null);\n\nconst INERT_CONTEXT: FlatTreeContextValue = {\n selectionMode: 'none',\n selected: undefined,\n current: undefined,\n tabStop: null,\n itemSize: undefined,\n activate: () => {},\n toggleChecked: () => {},\n};\n\n/** C-CONTEXT: throws in development, logs once and returns an inert value in production. */\nexport function useFlatTreeContext(component: string): FlatTreeContextValue {\n const context = React.useContext(FlatTreeContext);\n if (context) return context;\n reportMissingContext(component, '<FlatTree>');\n return INERT_CONTEXT;\n}\n"],"mappings":";;;;AA2BA,IAAaC,IAAkBD,EAAM,cAA2C,IAAI,GAE9EE,IAAsC;CAC1C,eAAe;CACf,UAAU,KAAA;CACV,SAAS,KAAA;CACT,SAAS;CACT,UAAU,KAAA;CACV,gBAAgB,CAAC;CACjB,qBAAqB,CAAC;AACxB;AAGA,SAAgBC,EAAmB,GAAyC;CAI1E,OAHgBH,EAAM,WAAWC,CAC7B,MACJG,EAAqBC,GAAW,YAAY,GACrCH;AACT"}
@@ -0,0 +1,2 @@
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/classNames.cjs"),r=require("../../hooks/useId.cjs"),i=require("../../hooks/useMergedRefs.cjs"),a=require("../../lib/styles.cjs"),o=require("../../lib/icons.cjs"),s=require("../../lib/events.cjs"),c=require("./FlatTree.context.cjs");let l=require("react");l=e.__toESM(l,1);let u=require("react/jsx-runtime");function d(e){return e.target?.closest?.(`[data-flat-tree-checkbox]`)!=null}var f=({item:e,children:f,className:p,style:m,onClick:h,ref:g,..._})=>{let v=c.useFlatTreeContext(`FlatTree.Item`),{item:y,level:b,position:x,setSize:S,isBranch:C,expanded:w,index:T}=e,{value:E}=y,D=y.disabled===!0,O=r.useId(`flat-tree-item-label`),k=l.useRef(null),A=i.useMergedRefs(g,k),j=v.selectionMode===`multiple`?e.checked??`unchecked`:void 0,M=v.selected===void 0?void 0:v.selected===E,N=v.current!==void 0&&v.current!==null&&v.current===E,P=t=>{s.isOwnEvent(t)&&!d(t)&&(h?.(t),t.defaultPrevented||v.activate(e))},F=e=>{e.preventDefault(),k.current?.focus({preventScroll:!0})},I=t=>{v.toggleChecked(e,t.nativeEvent)},L=C?(0,u.jsx)(o.ChevronRightIcon,{className:t.cn(n.flatTreeItemClassNames.expandIcon,`shrink-0 transition-transform motion-reduce:transition-none`,w?`rotate-90`:`wave-rtl:-scale-x-100`)}):(0,u.jsx)(`span`,{className:`w-3 shrink-0`,"aria-hidden":`true`}),R=j===void 0?null:(0,u.jsx)(`span`,{role:`checkbox`,"aria-checked":j===`mixed`?`mixed`:j===`checked`,"aria-labelledby":O,"aria-disabled":D?!0:void 0,tabIndex:-1,"data-flat-tree-checkbox":``,onMouseDown:F,onClick:I,className:t.cn(n.flatTreeItemClassNames.indicator,`relative inline-flex size-4 shrink-0 items-center justify-center rounded-xs border transition-colors motion-reduce:transition-none`,`before:absolute before:-inset-1`,j===`unchecked`?t.cn(`border-stroke-accessible bg-transparent`,a.forcedColors.control):`border-primary bg-primary text-primary-foreground forced-colors:border-[Highlight] forced-colors:bg-[Highlight]`),children:j===`mixed`?(0,u.jsx)(o.SubtractIcon,{size:12,className:a.forcedColors.selectedLeaf}):j===`checked`?(0,u.jsx)(o.CheckIcon,{size:12,className:a.forcedColors.selectedLeaf}):null}),z=v.selectionMode===`single`?(0,u.jsx)(`span`,{"aria-hidden":`true`,className:t.cn(n.flatTreeItemClassNames.indicator,`inline-flex size-4 shrink-0 items-center justify-center rounded-full border transition-colors motion-reduce:transition-none`,M?`border-2 border-primary forced-colors:border-[Highlight]`:t.cn(`border-stroke-accessible`,a.forcedColors.control)),children:M&&(0,u.jsx)(`span`,{className:t.cn(`block size-2 rounded-full bg-primary`,a.forcedColors.selectedLeaf)})}):null,B={...m};return b>1&&(B.paddingInlineStart=`${b-1}rem`),v.itemSize!==void 0&&(B.height=v.itemSize),(0,u.jsx)(`div`,{role:`treeitem`,"aria-selected":M,"aria-current":N?!0:void 0,"aria-disabled":D?!0:void 0,"data-selected":M?``:void 0,"data-current":N?``:void 0,"data-checked":j===`checked`?``:void 0,"data-mixed":j===`mixed`?``:void 0,"data-disabled":D?``:void 0,className:t.cn(n.flatTreeItemClassNames.root,`box-border block outline-none`,`[&:focus-visible>[data-flat-tree-row]]:outline-2 [&:focus-visible>[data-flat-tree-row]]:-outline-offset-2 [&:focus-visible>[data-flat-tree-row]]:outline-ring`,a.disabledStyles,p),..._,"aria-labelledby":_[`aria-labelledby`]??(_[`aria-label`]===void 0?O:void 0),"aria-level":b,"aria-setsize":S,"aria-posinset":x,"aria-expanded":C?w:void 0,"aria-checked":j===void 0?void 0:j===`mixed`?`mixed`:j===`checked`,"data-index":T,tabIndex:v.tabStop===E?0:-1,style:B,onClick:P,ref:A,children:(0,u.jsxs)(`div`,{"data-flat-tree-row":``,className:t.cn(n.flatTreeItemClassNames.row,`box-border flex items-center gap-1.5 rounded px-2 py-1`,v.itemSize!==void 0&&`h-full`,D?`cursor-not-allowed`:`cursor-pointer hover:bg-subtle-hover`,M&&t.cn(`bg-subtle-selected font-semibold`,a.forcedColors.selectedContainer)),children:[L,R??z,(0,u.jsx)(`span`,{id:O,className:t.cn(n.flatTreeItemClassNames.label,`min-w-0 truncate`),children:f})]})})};f.displayName=`FlatTreeItem`,exports.FlatTreeItem=f;
2
+ //# sourceMappingURL=FlatTree.item.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlatTree.item.cjs","names":["useFlatTreeContext","useId","React","useMergedRefs","isOwnEvent","ChevronRightIcon","cn","flatTreeItemClassNames","forcedColors","SubtractIcon","CheckIcon","disabledStyles","require_runtime","require_cn","require_classNames","require_useId","require_useMergedRefs","require_styles","require_icons","require_events","require_FlatTree_context","react","react_jsx_runtime","isCheckboxClick","event","FlatTreeItem","row","rest","ctx","item","disabled","labelId","itemRef","mergedRef","ref","checkState","isSelected","value","isCurrent","handleClick","onClick","keepFocusOnItem","handleCheckboxClick","chevron","isBranch","expanded","checkbox","radio","itemStyle","style","level","className","setSize","position","index"],"sources":["../../../src/components/layout/FlatTree.item.tsx"],"sourcesContent":["import * as React from 'react';\nimport { flatTreeItemClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { isOwnEvent } from '../../lib/events';\nimport type { VisibleFlatItem } from '../../lib/flatTree';\nimport { CheckIcon, ChevronRightIcon, SubtractIcon } from '../../lib/icons';\nimport { disabledStyles, forcedColors } from '../../lib/styles';\nimport type { CheckState } from '../../lib/treeCascade';\nimport { useId } from '../../hooks/useId';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useFlatTreeContext } from './FlatTree.context';\n\n/** Properties for the FlatTreeItem sub-component. */\nexport interface FlatTreeItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n /** The row the item shows: a visible item of the tree's model (`model.visibleItems`). */\n item: VisibleFlatItem & { checked?: CheckState };\n /** The item's content: what the tree's `renderItem` returns, else the item's label. */\n children?: React.ReactNode;\n /** Ref to the `role=\"treeitem\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Whether a click landed on the item's checkbox, which has a click of its own. */\nfunction isCheckboxClick(event: React.MouseEvent<HTMLElement>): boolean {\n const target = event.target as Element | null;\n return target?.closest?.('[data-flat-tree-checkbox]') != null;\n}\n\n/**\n * One row of a FlatTree, rendered by the tree for each visible item of its model (it is not\n * written by hand): a `role=\"treeitem\"` element with the item's level, set size and position,\n * `aria-expanded` on a branch, and the expand chevron, the checkbox (multiple mode) or the radio\n * (single mode) of the nested `Tree`'s items, before the content. Levels are drawn by indenting\n * the row, since the items are siblings. In a windowed tree it is exactly the window's `itemSize`\n * tall.\n *\n * `ref`, `className` and the other props land on the treeitem element; its `onClick` receives the\n * clicks on the row, not those on the checkbox, and runs before the built-in activation (call\n * `event.preventDefault()` to skip it).\n */\nexport const FlatTreeItem = ({\n item: row,\n children,\n className,\n style,\n onClick,\n ref,\n ...rest\n}: FlatTreeItemProps) => {\n const ctx = useFlatTreeContext('FlatTree.Item');\n const { item, level, position, setSize, isBranch, expanded, index } = row;\n const { value } = item;\n const disabled = item.disabled === true;\n const labelId = useId('flat-tree-item-label');\n const itemRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(ref, itemRef);\n\n const checkState: CheckState | undefined =\n ctx.selectionMode === 'multiple' ? (row.checked ?? 'unchecked') : undefined;\n const isSelected = ctx.selected !== undefined ? ctx.selected === value : undefined;\n const isCurrent = ctx.current !== undefined && ctx.current !== null && ctx.current === value;\n\n const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {\n // A click from a portal opened in the content, or on the checkbox, is not the row's.\n if (!isOwnEvent(event) || isCheckboxClick(event)) return;\n onClick?.(event);\n if (!event.defaultPrevented) ctx.activate(row);\n };\n\n // The checkbox never takes focus (APG: focus stays on tree items): a press on it focuses its\n // item instead, and its click toggles the check without activating the item.\n const keepFocusOnItem = (event: React.MouseEvent<HTMLSpanElement>) => {\n event.preventDefault();\n itemRef.current?.focus({ preventScroll: true });\n };\n const handleCheckboxClick = (event: React.MouseEvent<HTMLSpanElement>) => {\n ctx.toggleChecked(row, event.nativeEvent);\n };\n\n const chevron = isBranch ? (\n <ChevronRightIcon\n className={cn(\n flatTreeItemClassNames.expandIcon,\n 'shrink-0 transition-transform motion-reduce:transition-none',\n expanded ? 'rotate-90' : 'wave-rtl:-scale-x-100',\n )}\n />\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden=\"true\" />\n );\n\n const checkbox =\n checkState === undefined ? null : (\n <span\n role=\"checkbox\"\n aria-checked={checkState === 'mixed' ? 'mixed' : checkState === 'checked'}\n aria-labelledby={labelId}\n aria-disabled={disabled ? true : undefined}\n tabIndex={-1}\n data-flat-tree-checkbox=\"\"\n onMouseDown={keepFocusOnItem}\n onClick={handleCheckboxClick}\n className={cn(\n flatTreeItemClassNames.indicator,\n // Checkbox's box: 16px inside a 24px target (the pseudo-element), WCAG 2.5.8.\n 'relative inline-flex size-4 shrink-0 items-center justify-center rounded-xs border transition-colors motion-reduce:transition-none',\n 'before:absolute before:-inset-1',\n checkState === 'unchecked'\n ? cn('border-stroke-accessible bg-transparent', forcedColors.control)\n : 'border-primary bg-primary text-primary-foreground forced-colors:border-[Highlight] forced-colors:bg-[Highlight]',\n )}\n >\n {checkState === 'mixed' ? (\n <SubtractIcon size={12} className={forcedColors.selectedLeaf} />\n ) : checkState === 'checked' ? (\n <CheckIcon size={12} className={forcedColors.selectedLeaf} />\n ) : null}\n </span>\n );\n\n // Single mode: a decorative radio (the treeitem's aria-selected carries the state). A click on\n // it is a click on the row, so it activates the item.\n const radio =\n ctx.selectionMode === 'single' ? (\n <span\n aria-hidden=\"true\"\n className={cn(\n flatTreeItemClassNames.indicator,\n 'inline-flex size-4 shrink-0 items-center justify-center rounded-full border transition-colors motion-reduce:transition-none',\n isSelected\n ? 'border-2 border-primary forced-colors:border-[Highlight]'\n : cn('border-stroke-accessible', forcedColors.control),\n )}\n >\n {isSelected && (\n <span className={cn('block size-2 rounded-full bg-primary', forcedColors.selectedLeaf)} />\n )}\n </span>\n ) : null;\n\n // The level is drawn as indentation (one step per level, as a nested group's), and a windowed\n // item is exactly the window's item height: the window's arithmetic counts on it.\n const itemStyle: React.CSSProperties = { ...style };\n if (level > 1) itemStyle.paddingInlineStart = `${level - 1}rem`;\n if (ctx.itemSize !== undefined) itemStyle.height = ctx.itemSize;\n\n return (\n <div\n role=\"treeitem\"\n aria-selected={isSelected}\n aria-current={isCurrent ? true : undefined}\n aria-disabled={disabled ? true : undefined}\n data-selected={isSelected ? '' : undefined}\n data-current={isCurrent ? '' : undefined}\n data-checked={checkState === 'checked' ? '' : undefined}\n data-mixed={checkState === 'mixed' ? '' : undefined}\n data-disabled={disabled ? '' : undefined}\n className={cn(\n flatTreeItemClassNames.root,\n // The focus ring is drawn on the row, inside the item's box.\n 'box-border block outline-none',\n '[&:focus-visible>[data-flat-tree-row]]:outline-2 [&:focus-visible>[data-flat-tree-row]]:-outline-offset-2 [&:focus-visible>[data-flat-tree-row]]:outline-ring',\n disabledStyles,\n className,\n )}\n {...rest}\n // Named by its content only: the treeitem also holds the chevron and the checkbox. A consumer\n // aria-labelledby or aria-label replaces it.\n aria-labelledby={\n rest['aria-labelledby'] ?? (rest['aria-label'] === undefined ? labelId : undefined)\n }\n // From the model, after the rest props: the positions and states are the data's.\n aria-level={level}\n aria-setsize={setSize}\n aria-posinset={position}\n aria-expanded={isBranch ? expanded : undefined}\n aria-checked={\n checkState === undefined\n ? undefined\n : checkState === 'mixed'\n ? 'mixed'\n : checkState === 'checked'\n }\n data-index={index}\n tabIndex={ctx.tabStop === value ? 0 : -1}\n style={itemStyle}\n onClick={handleClick}\n ref={mergedRef}\n >\n <div\n data-flat-tree-row=\"\"\n className={cn(\n flatTreeItemClassNames.row,\n 'box-border flex items-center gap-1.5 rounded px-2 py-1',\n ctx.itemSize !== undefined && 'h-full',\n disabled ? 'cursor-not-allowed' : 'cursor-pointer hover:bg-subtle-hover',\n isSelected && cn('bg-subtle-selected font-semibold', forcedColors.selectedContainer),\n )}\n >\n {chevron}\n {checkbox ?? radio}\n <span id={labelId} className={cn(flatTreeItemClassNames.label, 'min-w-0 truncate')}>\n {children}\n </span>\n </div>\n </div>\n );\n};\nFlatTreeItem.displayName = 'FlatTreeItem';\n"],"mappings":"2aAuBA,SAASuB,EAAgB,EAA+C,CAEtE,OADeC,EAAM,QACN,UAAU,2BAA2B,GAAK,IAC3D,CAcA,IAAaC,GAAgB,CAC3B,KAAMC,EACN,WACA,YACA,QACA,UACA,MACA,GAAGC,KACoB,CACvB,IAAMC,EAAM5B,EAAAA,mBAAmB,eAAe,EACxC,CAAE,OAAM,QAAO,WAAU,UAAS,WAAU,WAAU,SAAU0B,EAChE,CAAE,SAAUG,EACZC,EAAWD,EAAK,WAAa,GAC7BE,EAAU9B,EAAAA,MAAM,sBAAsB,EACtC+B,EAAU9B,EAAM,OAAuB,IAAI,EAC3C+B,EAAY9B,EAAAA,cAA8B+B,EAAKF,CAAO,EAEtDG,EACJP,EAAI,gBAAkB,WAAcF,EAAI,SAAW,YAAe,IAAA,GAC9DU,EAAaR,EAAI,WAAa,IAAA,GAAqC,IAAA,GAAzBA,EAAI,WAAaS,EAC3DC,EAAYV,EAAI,UAAY,IAAA,IAAaA,EAAI,UAAY,MAAQA,EAAI,UAAYS,EAEjFE,EAAe,GAA4C,CAE1DnC,EAAAA,WAAWoB,CAAK,GAAK,GAAgBA,CAAK,IAC/CgB,IAAUhB,CAAK,EACVA,EAAM,kBAAkBI,EAAI,SAASF,CAAG,EAC/C,EAIMe,EAAmB,GAA6C,CACpEjB,EAAM,eAAe,EACrBQ,EAAQ,SAAS,MAAM,CAAE,cAAe,EAAK,CAAC,CAChD,EACMU,EAAuB,GAA6C,CACxEd,EAAI,cAAcF,EAAKF,EAAM,WAAW,CAC1C,EAEMmB,EAAUC,GACd,EAAAtB,EAAA,IAAA,CAACjB,EAAAA,iBAAD,CACE,UAAWC,EAAAA,GACTC,EAAAA,uBAAuB,WACvB,8DACAsC,EAAW,YAAc,uBAC3B,CACD,CAAA,GAED,EAAAvB,EAAA,IAAA,CAAC,OAAD,CAAM,UAAU,eAAe,cAAY,MAAQ,CAAA,EAG/CwB,EACJX,IAAe,IAAA,GAAY,MACzB,EAAAb,EAAA,IAAA,CAAC,OAAD,CACE,KAAK,WACL,eAAca,IAAe,QAAU,QAAUA,IAAe,UAChE,kBAAiBJ,EACjB,gBAAeD,EAAW,GAAO,IAAA,GACjC,SAAU,GACV,0BAAwB,GACxB,YAAaW,EACb,QAASC,EACT,UAAWpC,EAAAA,GACTC,EAAAA,uBAAuB,UAEvB,qIACA,kCACA4B,IAAe,YACX7B,EAAAA,GAAG,0CAA2CE,EAAAA,aAAa,OAAO,EAClE,iHACN,EAEC,SAAA2B,IAAe,SACd,EAAAb,EAAA,IAAA,CAACb,EAAAA,aAAD,CAAc,KAAM,GAAI,UAAWD,EAAAA,aAAa,YAAe,CAAA,EAC7D2B,IAAe,WACjB,EAAAb,EAAA,IAAA,CAACZ,EAAAA,UAAD,CAAW,KAAM,GAAI,UAAWF,EAAAA,aAAa,YAAe,CAAA,EAC1D,IACA,CAAA,EAKJuC,EACJnB,EAAI,gBAAkB,UACpB,EAAAN,EAAA,IAAA,CAAC,OAAD,CACE,cAAY,OACZ,UAAWhB,EAAAA,GACTC,EAAAA,uBAAuB,UACvB,8HACA6B,EACI,2DACA9B,EAAAA,GAAG,2BAA4BE,EAAAA,aAAa,OAAO,CACzD,EAEC,SAAA4B,IACC,EAAAd,EAAA,IAAA,CAAC,OAAD,CAAM,UAAWhB,EAAAA,GAAG,uCAAwCE,EAAAA,aAAa,YAAY,CAAI,CAAA,CAEvF,CAAA,EACJ,KAIAwC,EAAiC,CAAE,GAAGC,CAAM,EAIlD,OAHIC,EAAQ,IAAG,EAAU,mBAAqB,GAAGA,EAAQ,EAAE,MACvDtB,EAAI,WAAa,IAAA,KAAW,EAAU,OAASA,EAAI,WAGrD,EAAAN,EAAA,IAAA,CAAC,MAAD,CACE,KAAK,WACL,gBAAec,EACf,eAAcE,EAAY,GAAO,IAAA,GACjC,gBAAeR,EAAW,GAAO,IAAA,GACjC,gBAAeM,EAAa,GAAK,IAAA,GACjC,eAAcE,EAAY,GAAK,IAAA,GAC/B,eAAcH,IAAe,UAAY,GAAK,IAAA,GAC9C,aAAYA,IAAe,QAAU,GAAK,IAAA,GAC1C,gBAAeL,EAAW,GAAK,IAAA,GAC/B,UAAWxB,EAAAA,GACTC,EAAAA,uBAAuB,KAEvB,gCACA,gKACAI,EAAAA,eACAwC,CACF,EACA,GAAIxB,EAGJ,kBACEA,EAAK,qBAAuBA,EAAK,gBAAkB,IAAA,GAAYI,EAAU,IAAA,IAG3E,aAAYmB,EACZ,eAAcE,EACd,gBAAeC,EACf,gBAAeT,EAAWC,EAAW,IAAA,GACrC,eACEV,IAAe,IAAA,GACX,IAAA,GACAA,IAAe,QACb,QACAA,IAAe,UAEvB,aAAYmB,EACZ,SAAU1B,EAAI,UAAYS,EAAQ,EAAI,GACtC,MAAOW,EACP,QAAST,EACT,IAAKN,EAEL,UAAA,EAAAX,EAAA,KAAA,CAAC,MAAD,CACE,qBAAmB,GACnB,UAAWhB,EAAAA,GACTC,EAAAA,uBAAuB,IACvB,yDACAqB,EAAI,WAAa,IAAA,IAAa,SAC9BE,EAAW,qBAAuB,uCAClCM,GAAc9B,EAAAA,GAAG,mCAAoCE,EAAAA,aAAa,iBAAiB,CACrF,EARF,SAAA,CAUGmC,EACAG,GAAYC,GACb,EAAAzB,EAAA,IAAA,CAAC,OAAD,CAAM,GAAIS,EAAS,UAAWzB,EAAAA,GAAGC,EAAAA,uBAAuB,MAAO,kBAAkB,EAC9E,UACG,CAAA,CACH,GACF,CAAA,CAET,EACA,EAAa,YAAc"}
@@ -0,0 +1,90 @@
1
+ "use client";
2
+ import { cn as e } from "../../lib/cn.mjs";
3
+ import { flatTreeItemClassNames as t } from "../../lib/classNames.mjs";
4
+ import { useId as n } from "../../hooks/useId.mjs";
5
+ import { useMergedRefs as r } from "../../hooks/useMergedRefs.mjs";
6
+ import { disabledStyles as i, forcedColors as a } from "../../lib/styles.mjs";
7
+ import { CheckIcon as o, ChevronRightIcon as s, SubtractIcon as c } from "../../lib/icons.mjs";
8
+ import { isOwnEvent as l } from "../../lib/events.mjs";
9
+ import { useFlatTreeContext as u } from "./FlatTree.context.mjs";
10
+ import * as d from "react";
11
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
12
+ //#region src/components/layout/FlatTree.item.tsx
13
+ function m(e) {
14
+ return e.target?.closest?.("[data-flat-tree-checkbox]") != null;
15
+ }
16
+ var h = ({ item: h, children: g, className: _, style: v, onClick: y, ref: b, ...x }) => {
17
+ let S = u("FlatTree.Item"), { item: C, level: w, position: T, setSize: E, isBranch: D, expanded: O, index: k } = h, { value: A } = C, j = C.disabled === !0, M = n("flat-tree-item-label"), N = d.useRef(null), P = r(b, N), F = S.selectionMode === "multiple" ? h.checked ?? "unchecked" : void 0, I = S.selected === void 0 ? void 0 : S.selected === A, L = S.current !== void 0 && S.current !== null && S.current === A, R = (e) => {
18
+ l(e) && !m(e) && (y?.(e), e.defaultPrevented || S.activate(h));
19
+ }, z = (e) => {
20
+ e.preventDefault(), N.current?.focus({ preventScroll: !0 });
21
+ }, B = (e) => {
22
+ S.toggleChecked(h, e.nativeEvent);
23
+ }, V = D ? /* @__PURE__ */ f(s, { className: e(t.expandIcon, "shrink-0 transition-transform motion-reduce:transition-none", O ? "rotate-90" : "wave-rtl:-scale-x-100") }) : /* @__PURE__ */ f("span", {
24
+ className: "w-3 shrink-0",
25
+ "aria-hidden": "true"
26
+ }), H = F === void 0 ? null : /* @__PURE__ */ f("span", {
27
+ role: "checkbox",
28
+ "aria-checked": F === "mixed" ? "mixed" : F === "checked",
29
+ "aria-labelledby": M,
30
+ "aria-disabled": j ? !0 : void 0,
31
+ tabIndex: -1,
32
+ "data-flat-tree-checkbox": "",
33
+ onMouseDown: z,
34
+ onClick: B,
35
+ className: e(t.indicator, "relative inline-flex size-4 shrink-0 items-center justify-center rounded-xs border transition-colors motion-reduce:transition-none", "before:absolute before:-inset-1", F === "unchecked" ? e("border-stroke-accessible bg-transparent", a.control) : "border-primary bg-primary text-primary-foreground forced-colors:border-[Highlight] forced-colors:bg-[Highlight]"),
36
+ children: F === "mixed" ? /* @__PURE__ */ f(c, {
37
+ size: 12,
38
+ className: a.selectedLeaf
39
+ }) : F === "checked" ? /* @__PURE__ */ f(o, {
40
+ size: 12,
41
+ className: a.selectedLeaf
42
+ }) : null
43
+ }), U = S.selectionMode === "single" ? /* @__PURE__ */ f("span", {
44
+ "aria-hidden": "true",
45
+ className: e(t.indicator, "inline-flex size-4 shrink-0 items-center justify-center rounded-full border transition-colors motion-reduce:transition-none", I ? "border-2 border-primary forced-colors:border-[Highlight]" : e("border-stroke-accessible", a.control)),
46
+ children: I && /* @__PURE__ */ f("span", { className: e("block size-2 rounded-full bg-primary", a.selectedLeaf) })
47
+ }) : null, W = { ...v };
48
+ return w > 1 && (W.paddingInlineStart = `${w - 1}rem`), S.itemSize !== void 0 && (W.height = S.itemSize), /* @__PURE__ */ f("div", {
49
+ role: "treeitem",
50
+ "aria-selected": I,
51
+ "aria-current": L ? !0 : void 0,
52
+ "aria-disabled": j ? !0 : void 0,
53
+ "data-selected": I ? "" : void 0,
54
+ "data-current": L ? "" : void 0,
55
+ "data-checked": F === "checked" ? "" : void 0,
56
+ "data-mixed": F === "mixed" ? "" : void 0,
57
+ "data-disabled": j ? "" : void 0,
58
+ className: e(t.root, "box-border block outline-none", "[&:focus-visible>[data-flat-tree-row]]:outline-2 [&:focus-visible>[data-flat-tree-row]]:-outline-offset-2 [&:focus-visible>[data-flat-tree-row]]:outline-ring", i, _),
59
+ ...x,
60
+ "aria-labelledby": x["aria-labelledby"] ?? (x["aria-label"] === void 0 ? M : void 0),
61
+ "aria-level": w,
62
+ "aria-setsize": E,
63
+ "aria-posinset": T,
64
+ "aria-expanded": D ? O : void 0,
65
+ "aria-checked": F === void 0 ? void 0 : F === "mixed" ? "mixed" : F === "checked",
66
+ "data-index": k,
67
+ tabIndex: S.tabStop === A ? 0 : -1,
68
+ style: W,
69
+ onClick: R,
70
+ ref: P,
71
+ children: /* @__PURE__ */ p("div", {
72
+ "data-flat-tree-row": "",
73
+ className: e(t.row, "box-border flex items-center gap-1.5 rounded px-2 py-1", S.itemSize !== void 0 && "h-full", j ? "cursor-not-allowed" : "cursor-pointer hover:bg-subtle-hover", I && e("bg-subtle-selected font-semibold", a.selectedContainer)),
74
+ children: [
75
+ V,
76
+ H ?? U,
77
+ /* @__PURE__ */ f("span", {
78
+ id: M,
79
+ className: e(t.label, "min-w-0 truncate"),
80
+ children: g
81
+ })
82
+ ]
83
+ })
84
+ });
85
+ };
86
+ h.displayName = "FlatTreeItem";
87
+ //#endregion
88
+ export { h as FlatTreeItem };
89
+
90
+ //# sourceMappingURL=FlatTree.item.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlatTree.item.mjs","names":["useId","useId$1","React","isCheckboxClick","event","FlatTreeItem","row","rest","ctx","useFlatTreeContext","item","disabled","labelId","itemRef","mergedRef","useMergedRefs","ref","checkState","isSelected","value","isCurrent","handleClick","isOwnEvent","onClick","keepFocusOnItem","handleCheckboxClick","chevron","isBranch","ChevronRightIcon","cn","flatTreeItemClassNames","expanded","checkbox","forcedColors","SubtractIcon","CheckIcon","radio","itemStyle","style","level","disabledStyles","className","setSize","position","index"],"sources":["../../../src/components/layout/FlatTree.item.tsx"],"sourcesContent":["import * as React from 'react';\nimport { flatTreeItemClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { isOwnEvent } from '../../lib/events';\nimport type { VisibleFlatItem } from '../../lib/flatTree';\nimport { CheckIcon, ChevronRightIcon, SubtractIcon } from '../../lib/icons';\nimport { disabledStyles, forcedColors } from '../../lib/styles';\nimport type { CheckState } from '../../lib/treeCascade';\nimport { useId } from '../../hooks/useId';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useFlatTreeContext } from './FlatTree.context';\n\n/** Properties for the FlatTreeItem sub-component. */\nexport interface FlatTreeItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n /** The row the item shows: a visible item of the tree's model (`model.visibleItems`). */\n item: VisibleFlatItem & { checked?: CheckState };\n /** The item's content: what the tree's `renderItem` returns, else the item's label. */\n children?: React.ReactNode;\n /** Ref to the `role=\"treeitem\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Whether a click landed on the item's checkbox, which has a click of its own. */\nfunction isCheckboxClick(event: React.MouseEvent<HTMLElement>): boolean {\n const target = event.target as Element | null;\n return target?.closest?.('[data-flat-tree-checkbox]') != null;\n}\n\n/**\n * One row of a FlatTree, rendered by the tree for each visible item of its model (it is not\n * written by hand): a `role=\"treeitem\"` element with the item's level, set size and position,\n * `aria-expanded` on a branch, and the expand chevron, the checkbox (multiple mode) or the radio\n * (single mode) of the nested `Tree`'s items, before the content. Levels are drawn by indenting\n * the row, since the items are siblings. In a windowed tree it is exactly the window's `itemSize`\n * tall.\n *\n * `ref`, `className` and the other props land on the treeitem element; its `onClick` receives the\n * clicks on the row, not those on the checkbox, and runs before the built-in activation (call\n * `event.preventDefault()` to skip it).\n */\nexport const FlatTreeItem = ({\n item: row,\n children,\n className,\n style,\n onClick,\n ref,\n ...rest\n}: FlatTreeItemProps) => {\n const ctx = useFlatTreeContext('FlatTree.Item');\n const { item, level, position, setSize, isBranch, expanded, index } = row;\n const { value } = item;\n const disabled = item.disabled === true;\n const labelId = useId('flat-tree-item-label');\n const itemRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(ref, itemRef);\n\n const checkState: CheckState | undefined =\n ctx.selectionMode === 'multiple' ? (row.checked ?? 'unchecked') : undefined;\n const isSelected = ctx.selected !== undefined ? ctx.selected === value : undefined;\n const isCurrent = ctx.current !== undefined && ctx.current !== null && ctx.current === value;\n\n const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {\n // A click from a portal opened in the content, or on the checkbox, is not the row's.\n if (!isOwnEvent(event) || isCheckboxClick(event)) return;\n onClick?.(event);\n if (!event.defaultPrevented) ctx.activate(row);\n };\n\n // The checkbox never takes focus (APG: focus stays on tree items): a press on it focuses its\n // item instead, and its click toggles the check without activating the item.\n const keepFocusOnItem = (event: React.MouseEvent<HTMLSpanElement>) => {\n event.preventDefault();\n itemRef.current?.focus({ preventScroll: true });\n };\n const handleCheckboxClick = (event: React.MouseEvent<HTMLSpanElement>) => {\n ctx.toggleChecked(row, event.nativeEvent);\n };\n\n const chevron = isBranch ? (\n <ChevronRightIcon\n className={cn(\n flatTreeItemClassNames.expandIcon,\n 'shrink-0 transition-transform motion-reduce:transition-none',\n expanded ? 'rotate-90' : 'wave-rtl:-scale-x-100',\n )}\n />\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden=\"true\" />\n );\n\n const checkbox =\n checkState === undefined ? null : (\n <span\n role=\"checkbox\"\n aria-checked={checkState === 'mixed' ? 'mixed' : checkState === 'checked'}\n aria-labelledby={labelId}\n aria-disabled={disabled ? true : undefined}\n tabIndex={-1}\n data-flat-tree-checkbox=\"\"\n onMouseDown={keepFocusOnItem}\n onClick={handleCheckboxClick}\n className={cn(\n flatTreeItemClassNames.indicator,\n // Checkbox's box: 16px inside a 24px target (the pseudo-element), WCAG 2.5.8.\n 'relative inline-flex size-4 shrink-0 items-center justify-center rounded-xs border transition-colors motion-reduce:transition-none',\n 'before:absolute before:-inset-1',\n checkState === 'unchecked'\n ? cn('border-stroke-accessible bg-transparent', forcedColors.control)\n : 'border-primary bg-primary text-primary-foreground forced-colors:border-[Highlight] forced-colors:bg-[Highlight]',\n )}\n >\n {checkState === 'mixed' ? (\n <SubtractIcon size={12} className={forcedColors.selectedLeaf} />\n ) : checkState === 'checked' ? (\n <CheckIcon size={12} className={forcedColors.selectedLeaf} />\n ) : null}\n </span>\n );\n\n // Single mode: a decorative radio (the treeitem's aria-selected carries the state). A click on\n // it is a click on the row, so it activates the item.\n const radio =\n ctx.selectionMode === 'single' ? (\n <span\n aria-hidden=\"true\"\n className={cn(\n flatTreeItemClassNames.indicator,\n 'inline-flex size-4 shrink-0 items-center justify-center rounded-full border transition-colors motion-reduce:transition-none',\n isSelected\n ? 'border-2 border-primary forced-colors:border-[Highlight]'\n : cn('border-stroke-accessible', forcedColors.control),\n )}\n >\n {isSelected && (\n <span className={cn('block size-2 rounded-full bg-primary', forcedColors.selectedLeaf)} />\n )}\n </span>\n ) : null;\n\n // The level is drawn as indentation (one step per level, as a nested group's), and a windowed\n // item is exactly the window's item height: the window's arithmetic counts on it.\n const itemStyle: React.CSSProperties = { ...style };\n if (level > 1) itemStyle.paddingInlineStart = `${level - 1}rem`;\n if (ctx.itemSize !== undefined) itemStyle.height = ctx.itemSize;\n\n return (\n <div\n role=\"treeitem\"\n aria-selected={isSelected}\n aria-current={isCurrent ? true : undefined}\n aria-disabled={disabled ? true : undefined}\n data-selected={isSelected ? '' : undefined}\n data-current={isCurrent ? '' : undefined}\n data-checked={checkState === 'checked' ? '' : undefined}\n data-mixed={checkState === 'mixed' ? '' : undefined}\n data-disabled={disabled ? '' : undefined}\n className={cn(\n flatTreeItemClassNames.root,\n // The focus ring is drawn on the row, inside the item's box.\n 'box-border block outline-none',\n '[&:focus-visible>[data-flat-tree-row]]:outline-2 [&:focus-visible>[data-flat-tree-row]]:-outline-offset-2 [&:focus-visible>[data-flat-tree-row]]:outline-ring',\n disabledStyles,\n className,\n )}\n {...rest}\n // Named by its content only: the treeitem also holds the chevron and the checkbox. A consumer\n // aria-labelledby or aria-label replaces it.\n aria-labelledby={\n rest['aria-labelledby'] ?? (rest['aria-label'] === undefined ? labelId : undefined)\n }\n // From the model, after the rest props: the positions and states are the data's.\n aria-level={level}\n aria-setsize={setSize}\n aria-posinset={position}\n aria-expanded={isBranch ? expanded : undefined}\n aria-checked={\n checkState === undefined\n ? undefined\n : checkState === 'mixed'\n ? 'mixed'\n : checkState === 'checked'\n }\n data-index={index}\n tabIndex={ctx.tabStop === value ? 0 : -1}\n style={itemStyle}\n onClick={handleClick}\n ref={mergedRef}\n >\n <div\n data-flat-tree-row=\"\"\n className={cn(\n flatTreeItemClassNames.row,\n 'box-border flex items-center gap-1.5 rounded px-2 py-1',\n ctx.itemSize !== undefined && 'h-full',\n disabled ? 'cursor-not-allowed' : 'cursor-pointer hover:bg-subtle-hover',\n isSelected && cn('bg-subtle-selected font-semibold', forcedColors.selectedContainer),\n )}\n >\n {chevron}\n {checkbox ?? radio}\n <span id={labelId} className={cn(flatTreeItemClassNames.label, 'min-w-0 truncate')}>\n {children}\n </span>\n </div>\n </div>\n );\n};\nFlatTreeItem.displayName = 'FlatTreeItem';\n"],"mappings":"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"}