@salt-ds/core 1.70.0 → 1.72.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 (315) hide show
  1. package/CHANGELOG.md +144 -0
  2. package/css/salt-core.css +466 -106
  3. package/dist-cjs/accordion/AccordionHeader.css.js +1 -1
  4. package/dist-cjs/aria-announcer/AriaAnnouncerProvider.js +8 -0
  5. package/dist-cjs/aria-announcer/AriaAnnouncerProvider.js.map +1 -1
  6. package/dist-cjs/avatar/Avatar.css.js +1 -1
  7. package/dist-cjs/badge/Badge.css.js +1 -1
  8. package/dist-cjs/banner/Banner.css.js +1 -1
  9. package/dist-cjs/breadcrumbs/Breadcrumb.css.js +1 -1
  10. package/dist-cjs/breadcrumbs/Breadcrumbs.css.js +1 -1
  11. package/dist-cjs/card/Card.css.js +1 -1
  12. package/dist-cjs/card/Card.js +4 -0
  13. package/dist-cjs/card/Card.js.map +1 -1
  14. package/dist-cjs/checkbox/Checkbox.css.js +1 -1
  15. package/dist-cjs/checkbox/CheckboxIcon.css.js +1 -1
  16. package/dist-cjs/combo-box/ComboBox.js +18 -36
  17. package/dist-cjs/combo-box/ComboBox.js.map +1 -1
  18. package/dist-cjs/combo-box/useComboBox.js +21 -21
  19. package/dist-cjs/combo-box/useComboBox.js.map +1 -1
  20. package/dist-cjs/drawer/Drawer.css.js +1 -1
  21. package/dist-cjs/drawer/Drawer.js +30 -5
  22. package/dist-cjs/drawer/Drawer.js.map +1 -1
  23. package/dist-cjs/drawer/DrawerCloseButton.js +1 -1
  24. package/dist-cjs/drawer/DrawerCloseButton.js.map +1 -1
  25. package/dist-cjs/drawer/DrawerContent.css.js +6 -0
  26. package/dist-cjs/drawer/DrawerContent.css.js.map +1 -0
  27. package/dist-cjs/drawer/DrawerContent.js +75 -0
  28. package/dist-cjs/drawer/DrawerContent.js.map +1 -0
  29. package/dist-cjs/drawer/DrawerContext.js +30 -0
  30. package/dist-cjs/drawer/DrawerContext.js.map +1 -0
  31. package/dist-cjs/drawer/DrawerFooter.css.js +6 -0
  32. package/dist-cjs/drawer/DrawerFooter.css.js.map +1 -0
  33. package/dist-cjs/drawer/DrawerFooter.js +30 -0
  34. package/dist-cjs/drawer/DrawerFooter.js.map +1 -0
  35. package/dist-cjs/drawer/DrawerHeader.css.js +6 -0
  36. package/dist-cjs/drawer/DrawerHeader.css.js.map +1 -0
  37. package/dist-cjs/drawer/DrawerHeader.js +95 -0
  38. package/dist-cjs/drawer/DrawerHeader.js.map +1 -0
  39. package/dist-cjs/drawer/hasDrawerSection.js +22 -0
  40. package/dist-cjs/drawer/hasDrawerSection.js.map +1 -0
  41. package/dist-cjs/dropdown/Dropdown.js +29 -30
  42. package/dist-cjs/dropdown/Dropdown.js.map +1 -1
  43. package/dist-cjs/file-drop-zone/FileDropZone.css.js +1 -1
  44. package/dist-cjs/form-field/FormField.css.js +1 -1
  45. package/dist-cjs/form-field/FormField.js +15 -0
  46. package/dist-cjs/form-field/FormField.js.map +1 -1
  47. package/dist-cjs/form-field/FormFieldHelperText.css.js +1 -1
  48. package/dist-cjs/form-field/FormFieldLabel.css.js +1 -1
  49. package/dist-cjs/form-field/FormFieldLabel.js +1 -1
  50. package/dist-cjs/form-field/FormFieldLabel.js.map +1 -1
  51. package/dist-cjs/index.js +10 -0
  52. package/dist-cjs/index.js.map +1 -1
  53. package/dist-cjs/input/Input.css.js +1 -1
  54. package/dist-cjs/interactable-card/InteractableCard.css.js +1 -1
  55. package/dist-cjs/interactable-card/InteractableCard.js +23 -7
  56. package/dist-cjs/interactable-card/InteractableCard.js.map +1 -1
  57. package/dist-cjs/interactable-card/InteractableCardGroup.js +71 -39
  58. package/dist-cjs/interactable-card/InteractableCardGroup.js.map +1 -1
  59. package/dist-cjs/interactable-card/InteractableCardGroupContext.js.map +1 -1
  60. package/dist-cjs/interactable-card/useInteractableCard.js +2 -3
  61. package/dist-cjs/interactable-card/useInteractableCard.js.map +1 -1
  62. package/dist-cjs/kbd/Kbd.css.js +1 -1
  63. package/dist-cjs/link/Link.css.js +1 -1
  64. package/dist-cjs/link-button/LinkButton.css.js +6 -0
  65. package/dist-cjs/link-button/LinkButton.css.js.map +1 -0
  66. package/dist-cjs/link-button/LinkButton.js +87 -0
  67. package/dist-cjs/link-button/LinkButton.js.map +1 -0
  68. package/dist-cjs/link-card/LinkCard.css.js +1 -1
  69. package/dist-cjs/link-card/LinkCard.js +4 -0
  70. package/dist-cjs/link-card/LinkCard.js.map +1 -1
  71. package/dist-cjs/list-box/ListBox.js +19 -26
  72. package/dist-cjs/list-box/ListBox.js.map +1 -1
  73. package/dist-cjs/list-control/ListControlNavigationKeys.js +74 -0
  74. package/dist-cjs/list-control/ListControlNavigationKeys.js.map +1 -0
  75. package/dist-cjs/list-control/ListControlOptionContext.js +47 -0
  76. package/dist-cjs/list-control/ListControlOptionContext.js.map +1 -0
  77. package/dist-cjs/list-control/ListControlOptionStore.js +159 -0
  78. package/dist-cjs/list-control/ListControlOptionStore.js.map +1 -0
  79. package/dist-cjs/list-control/ListControlProvider.js +39 -0
  80. package/dist-cjs/list-control/ListControlProvider.js.map +1 -0
  81. package/dist-cjs/list-control/ListControlRegistry.js +161 -0
  82. package/dist-cjs/list-control/ListControlRegistry.js.map +1 -0
  83. package/dist-cjs/list-control/ListControlState.js +137 -109
  84. package/dist-cjs/list-control/ListControlState.js.map +1 -1
  85. package/dist-cjs/mega-menu/MegaMenuGroupHeading.css.js +1 -1
  86. package/dist-cjs/mega-menu/MegaMenuListItem.css.js +1 -1
  87. package/dist-cjs/menu/MenuGroup.css.js +1 -1
  88. package/dist-cjs/menu/MenuItem.css.js +1 -1
  89. package/dist-cjs/menu/MenuItem.js +0 -1
  90. package/dist-cjs/menu/MenuItem.js.map +1 -1
  91. package/dist-cjs/navigation-item/NavigationItem.css.js +1 -1
  92. package/dist-cjs/number-input/NumberInput.js +2 -2
  93. package/dist-cjs/number-input/NumberInput.js.map +1 -1
  94. package/dist-cjs/option/Option.js +58 -39
  95. package/dist-cjs/option/Option.js.map +1 -1
  96. package/dist-cjs/option/OptionGroup.css.js +1 -1
  97. package/dist-cjs/overlay/Overlay.js +12 -2
  98. package/dist-cjs/overlay/Overlay.js.map +1 -1
  99. package/dist-cjs/overlay/OverlayContext.js +6 -0
  100. package/dist-cjs/overlay/OverlayContext.js.map +1 -1
  101. package/dist-cjs/overlay/OverlayFooter.css.js +6 -0
  102. package/dist-cjs/overlay/OverlayFooter.css.js.map +1 -0
  103. package/dist-cjs/overlay/OverlayFooter.js +30 -0
  104. package/dist-cjs/overlay/OverlayFooter.js.map +1 -0
  105. package/dist-cjs/overlay/OverlayHeader.css.js +1 -1
  106. package/dist-cjs/overlay/OverlayHeader.js +51 -11
  107. package/dist-cjs/overlay/OverlayHeader.js.map +1 -1
  108. package/dist-cjs/overlay/OverlayPanel.css.js +1 -1
  109. package/dist-cjs/overlay/OverlayPanel.js +20 -7
  110. package/dist-cjs/overlay/OverlayPanel.js.map +1 -1
  111. package/dist-cjs/overlay/OverlayPanelContent.css.js +1 -1
  112. package/dist-cjs/overlay/OverlayPanelContent.js +11 -13
  113. package/dist-cjs/overlay/OverlayPanelContent.js.map +1 -1
  114. package/dist-cjs/overlay/hasOverlaySection.js +24 -0
  115. package/dist-cjs/overlay/hasOverlaySection.js.map +1 -0
  116. package/dist-cjs/panel/Panel.css.js +1 -1
  117. package/dist-cjs/panel/Panel.js +13 -2
  118. package/dist-cjs/panel/Panel.js.map +1 -1
  119. package/dist-cjs/pill-input/PillInput.css.js +1 -1
  120. package/dist-cjs/pill-input/PillInput.js +2 -2
  121. package/dist-cjs/pill-input/PillInput.js.map +1 -1
  122. package/dist-cjs/radio-button/RadioButton.css.js +1 -1
  123. package/dist-cjs/radio-button/RadioButtonIcon.css.js +1 -1
  124. package/dist-cjs/rating/Rating.css.js +1 -1
  125. package/dist-cjs/slider/internal/SliderTrack.css.js +1 -1
  126. package/dist-cjs/stepper/internal/StepText.css.js +1 -1
  127. package/dist-cjs/switch/Switch.css.js +1 -1
  128. package/dist-cjs/table/Table.css.js +1 -1
  129. package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js +10 -2
  130. package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -1
  131. package/dist-cjs/tag/Tag.css.js +1 -1
  132. package/dist-cjs/text/Text.css.js +1 -1
  133. package/dist-cjs/toast/Toast.css.js +1 -1
  134. package/dist-cjs/toggle-button/ToggleButton.js +8 -2
  135. package/dist-cjs/toggle-button/ToggleButton.js.map +1 -1
  136. package/dist-cjs/toggle-button-group/ToggleButtonGroup.js +71 -8
  137. package/dist-cjs/toggle-button-group/ToggleButtonGroup.js.map +1 -1
  138. package/dist-cjs/toggle-button-group/ToggleButtonGroupContext.js.map +1 -1
  139. package/dist-cjs/toggletip/ToggletipPanel.css.js +1 -1
  140. package/dist-cjs/tooltip/Tooltip.css.js +1 -1
  141. package/dist-cjs/vertical-navigation/VerticalNavigationItemContent.css.js +1 -1
  142. package/dist-cjs/vertical-navigation/VerticalNavigationSubMenu.css.js +1 -1
  143. package/dist-es/accordion/AccordionHeader.css.js +1 -1
  144. package/dist-es/aria-announcer/AriaAnnouncerProvider.js +8 -0
  145. package/dist-es/aria-announcer/AriaAnnouncerProvider.js.map +1 -1
  146. package/dist-es/avatar/Avatar.css.js +1 -1
  147. package/dist-es/badge/Badge.css.js +1 -1
  148. package/dist-es/banner/Banner.css.js +1 -1
  149. package/dist-es/breadcrumbs/Breadcrumb.css.js +1 -1
  150. package/dist-es/breadcrumbs/Breadcrumbs.css.js +1 -1
  151. package/dist-es/card/Card.css.js +1 -1
  152. package/dist-es/card/Card.js +4 -0
  153. package/dist-es/card/Card.js.map +1 -1
  154. package/dist-es/checkbox/Checkbox.css.js +1 -1
  155. package/dist-es/checkbox/CheckboxIcon.css.js +1 -1
  156. package/dist-es/combo-box/ComboBox.js +18 -36
  157. package/dist-es/combo-box/ComboBox.js.map +1 -1
  158. package/dist-es/combo-box/useComboBox.js +21 -21
  159. package/dist-es/combo-box/useComboBox.js.map +1 -1
  160. package/dist-es/drawer/Drawer.css.js +1 -1
  161. package/dist-es/drawer/Drawer.js +31 -6
  162. package/dist-es/drawer/Drawer.js.map +1 -1
  163. package/dist-es/drawer/DrawerCloseButton.js +1 -1
  164. package/dist-es/drawer/DrawerCloseButton.js.map +1 -1
  165. package/dist-es/drawer/DrawerContent.css.js +4 -0
  166. package/dist-es/drawer/DrawerContent.css.js.map +1 -0
  167. package/dist-es/drawer/DrawerContent.js +73 -0
  168. package/dist-es/drawer/DrawerContent.js.map +1 -0
  169. package/dist-es/drawer/DrawerContext.js +27 -0
  170. package/dist-es/drawer/DrawerContext.js.map +1 -0
  171. package/dist-es/drawer/DrawerFooter.css.js +4 -0
  172. package/dist-es/drawer/DrawerFooter.css.js.map +1 -0
  173. package/dist-es/drawer/DrawerFooter.js +28 -0
  174. package/dist-es/drawer/DrawerFooter.js.map +1 -0
  175. package/dist-es/drawer/DrawerHeader.css.js +4 -0
  176. package/dist-es/drawer/DrawerHeader.css.js.map +1 -0
  177. package/dist-es/drawer/DrawerHeader.js +93 -0
  178. package/dist-es/drawer/DrawerHeader.js.map +1 -0
  179. package/dist-es/drawer/hasDrawerSection.js +20 -0
  180. package/dist-es/drawer/hasDrawerSection.js.map +1 -0
  181. package/dist-es/dropdown/Dropdown.js +29 -30
  182. package/dist-es/dropdown/Dropdown.js.map +1 -1
  183. package/dist-es/file-drop-zone/FileDropZone.css.js +1 -1
  184. package/dist-es/form-field/FormField.css.js +1 -1
  185. package/dist-es/form-field/FormField.js +16 -1
  186. package/dist-es/form-field/FormField.js.map +1 -1
  187. package/dist-es/form-field/FormFieldHelperText.css.js +1 -1
  188. package/dist-es/form-field/FormFieldLabel.css.js +1 -1
  189. package/dist-es/form-field/FormFieldLabel.js +1 -1
  190. package/dist-es/form-field/FormFieldLabel.js.map +1 -1
  191. package/dist-es/index.js +5 -0
  192. package/dist-es/index.js.map +1 -1
  193. package/dist-es/input/Input.css.js +1 -1
  194. package/dist-es/interactable-card/InteractableCard.css.js +1 -1
  195. package/dist-es/interactable-card/InteractableCard.js +23 -7
  196. package/dist-es/interactable-card/InteractableCard.js.map +1 -1
  197. package/dist-es/interactable-card/InteractableCardGroup.js +72 -40
  198. package/dist-es/interactable-card/InteractableCardGroup.js.map +1 -1
  199. package/dist-es/interactable-card/InteractableCardGroupContext.js.map +1 -1
  200. package/dist-es/interactable-card/useInteractableCard.js +2 -3
  201. package/dist-es/interactable-card/useInteractableCard.js.map +1 -1
  202. package/dist-es/kbd/Kbd.css.js +1 -1
  203. package/dist-es/link/Link.css.js +1 -1
  204. package/dist-es/link-button/LinkButton.css.js +4 -0
  205. package/dist-es/link-button/LinkButton.css.js.map +1 -0
  206. package/dist-es/link-button/LinkButton.js +85 -0
  207. package/dist-es/link-button/LinkButton.js.map +1 -0
  208. package/dist-es/link-card/LinkCard.css.js +1 -1
  209. package/dist-es/link-card/LinkCard.js +4 -0
  210. package/dist-es/link-card/LinkCard.js.map +1 -1
  211. package/dist-es/list-box/ListBox.js +19 -26
  212. package/dist-es/list-box/ListBox.js.map +1 -1
  213. package/dist-es/list-control/ListControlNavigationKeys.js +69 -0
  214. package/dist-es/list-control/ListControlNavigationKeys.js.map +1 -0
  215. package/dist-es/list-control/ListControlOptionContext.js +44 -0
  216. package/dist-es/list-control/ListControlOptionContext.js.map +1 -0
  217. package/dist-es/list-control/ListControlOptionStore.js +153 -0
  218. package/dist-es/list-control/ListControlOptionStore.js.map +1 -0
  219. package/dist-es/list-control/ListControlProvider.js +37 -0
  220. package/dist-es/list-control/ListControlProvider.js.map +1 -0
  221. package/dist-es/list-control/ListControlRegistry.js +158 -0
  222. package/dist-es/list-control/ListControlRegistry.js.map +1 -0
  223. package/dist-es/list-control/ListControlState.js +137 -110
  224. package/dist-es/list-control/ListControlState.js.map +1 -1
  225. package/dist-es/mega-menu/MegaMenuGroupHeading.css.js +1 -1
  226. package/dist-es/mega-menu/MegaMenuListItem.css.js +1 -1
  227. package/dist-es/menu/MenuGroup.css.js +1 -1
  228. package/dist-es/menu/MenuItem.css.js +1 -1
  229. package/dist-es/menu/MenuItem.js +0 -1
  230. package/dist-es/menu/MenuItem.js.map +1 -1
  231. package/dist-es/navigation-item/NavigationItem.css.js +1 -1
  232. package/dist-es/number-input/NumberInput.js +2 -2
  233. package/dist-es/number-input/NumberInput.js.map +1 -1
  234. package/dist-es/option/Option.js +59 -40
  235. package/dist-es/option/Option.js.map +1 -1
  236. package/dist-es/option/OptionGroup.css.js +1 -1
  237. package/dist-es/overlay/Overlay.js +13 -3
  238. package/dist-es/overlay/Overlay.js.map +1 -1
  239. package/dist-es/overlay/OverlayContext.js +6 -0
  240. package/dist-es/overlay/OverlayContext.js.map +1 -1
  241. package/dist-es/overlay/OverlayFooter.css.js +4 -0
  242. package/dist-es/overlay/OverlayFooter.css.js.map +1 -0
  243. package/dist-es/overlay/OverlayFooter.js +28 -0
  244. package/dist-es/overlay/OverlayFooter.js.map +1 -0
  245. package/dist-es/overlay/OverlayHeader.css.js +1 -1
  246. package/dist-es/overlay/OverlayHeader.js +51 -11
  247. package/dist-es/overlay/OverlayHeader.js.map +1 -1
  248. package/dist-es/overlay/OverlayPanel.css.js +1 -1
  249. package/dist-es/overlay/OverlayPanel.js +20 -7
  250. package/dist-es/overlay/OverlayPanel.js.map +1 -1
  251. package/dist-es/overlay/OverlayPanelContent.css.js +1 -1
  252. package/dist-es/overlay/OverlayPanelContent.js +11 -13
  253. package/dist-es/overlay/OverlayPanelContent.js.map +1 -1
  254. package/dist-es/overlay/hasOverlaySection.js +22 -0
  255. package/dist-es/overlay/hasOverlaySection.js.map +1 -0
  256. package/dist-es/panel/Panel.css.js +1 -1
  257. package/dist-es/panel/Panel.js +13 -2
  258. package/dist-es/panel/Panel.js.map +1 -1
  259. package/dist-es/pill-input/PillInput.css.js +1 -1
  260. package/dist-es/pill-input/PillInput.js +2 -2
  261. package/dist-es/pill-input/PillInput.js.map +1 -1
  262. package/dist-es/radio-button/RadioButton.css.js +1 -1
  263. package/dist-es/radio-button/RadioButtonIcon.css.js +1 -1
  264. package/dist-es/rating/Rating.css.js +1 -1
  265. package/dist-es/slider/internal/SliderTrack.css.js +1 -1
  266. package/dist-es/stepper/internal/StepText.css.js +1 -1
  267. package/dist-es/switch/Switch.css.js +1 -1
  268. package/dist-es/table/Table.css.js +1 -1
  269. package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js +10 -2
  270. package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -1
  271. package/dist-es/tag/Tag.css.js +1 -1
  272. package/dist-es/text/Text.css.js +1 -1
  273. package/dist-es/toast/Toast.css.js +1 -1
  274. package/dist-es/toggle-button/ToggleButton.js +8 -2
  275. package/dist-es/toggle-button/ToggleButton.js.map +1 -1
  276. package/dist-es/toggle-button-group/ToggleButtonGroup.js +71 -8
  277. package/dist-es/toggle-button-group/ToggleButtonGroup.js.map +1 -1
  278. package/dist-es/toggle-button-group/ToggleButtonGroupContext.js.map +1 -1
  279. package/dist-es/toggletip/ToggletipPanel.css.js +1 -1
  280. package/dist-es/tooltip/Tooltip.css.js +1 -1
  281. package/dist-es/vertical-navigation/VerticalNavigationItemContent.css.js +1 -1
  282. package/dist-es/vertical-navigation/VerticalNavigationSubMenu.css.js +1 -1
  283. package/dist-types/card/Card.d.ts +10 -0
  284. package/dist-types/combo-box/useComboBox.d.ts +3 -6
  285. package/dist-types/drawer/Drawer.d.ts +1 -1
  286. package/dist-types/drawer/DrawerCloseButton.d.ts +3 -0
  287. package/dist-types/drawer/DrawerContent.d.ts +3 -0
  288. package/dist-types/drawer/DrawerContext.d.ts +9 -0
  289. package/dist-types/drawer/DrawerFooter.d.ts +3 -0
  290. package/dist-types/drawer/DrawerHeader.d.ts +24 -0
  291. package/dist-types/drawer/hasDrawerSection.d.ts +2 -0
  292. package/dist-types/drawer/index.d.ts +3 -0
  293. package/dist-types/index.d.ts +1 -0
  294. package/dist-types/interactable-card/InteractableCard.d.ts +9 -1
  295. package/dist-types/interactable-card/InteractableCardGroupContext.d.ts +2 -0
  296. package/dist-types/interactable-card/useInteractableCard.d.ts +1 -2
  297. package/dist-types/link-button/LinkButton.d.ts +26 -0
  298. package/dist-types/link-button/index.d.ts +1 -0
  299. package/dist-types/link-card/LinkCard.d.ts +8 -0
  300. package/dist-types/list-control/ListControlNavigationKeys.d.ts +30 -0
  301. package/dist-types/list-control/ListControlOptionContext.d.ts +18 -0
  302. package/dist-types/list-control/ListControlOptionStore.d.ts +17 -0
  303. package/dist-types/list-control/ListControlProvider.d.ts +11 -0
  304. package/dist-types/list-control/ListControlRegistry.d.ts +22 -0
  305. package/dist-types/list-control/ListControlState.d.ts +6 -6
  306. package/dist-types/option/Option.d.ts +3 -1
  307. package/dist-types/overlay/Overlay.d.ts +2 -1
  308. package/dist-types/overlay/OverlayContext.d.ts +4 -0
  309. package/dist-types/overlay/OverlayFooter.d.ts +4 -0
  310. package/dist-types/overlay/hasOverlaySection.d.ts +2 -0
  311. package/dist-types/overlay/index.d.ts +1 -0
  312. package/dist-types/panel/Panel.d.ts +4 -0
  313. package/dist-types/toggle-button-group/ToggleButtonGroupContext.d.ts +2 -1
  314. package/dist-types/utils/useIsomorphicLayoutEffect.d.ts +2 -2
  315. package/package.json +14 -10
@@ -0,0 +1,37 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useMemo } from 'react';
3
+ import { ListControlContext } from './ListControlContext.js';
4
+ import { ListControlOptionContextProvider } from './ListControlOptionContext.js';
5
+
6
+ function ListControlProvider({
7
+ children,
8
+ value
9
+ }) {
10
+ const { optionStateStore, ...publicValue } = value;
11
+ const optionValue = useMemo(
12
+ () => ({
13
+ disabled: value.disabled,
14
+ listRef: value.listRef,
15
+ multiselect: value.multiselect,
16
+ optionStateStore,
17
+ register: value.register,
18
+ select: value.select,
19
+ setActive: value.setActive,
20
+ valueToString: value.valueToString
21
+ }),
22
+ [
23
+ optionStateStore,
24
+ value.disabled,
25
+ value.listRef,
26
+ value.multiselect,
27
+ value.register,
28
+ value.select,
29
+ value.setActive,
30
+ value.valueToString
31
+ ]
32
+ );
33
+ return /* @__PURE__ */ jsx(ListControlContext.Provider, { value: publicValue, children: /* @__PURE__ */ jsx(ListControlOptionContextProvider, { value: optionValue, children }) });
34
+ }
35
+
36
+ export { ListControlProvider };
37
+ //# sourceMappingURL=ListControlProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListControlProvider.js","sources":["../src/list-control/ListControlProvider.tsx"],"sourcesContent":["import { type ReactNode, useMemo } from \"react\";\nimport {\n ListControlContext,\n type ListControlContextValue,\n} from \"./ListControlContext\";\nimport {\n ListControlOptionContextProvider,\n type ListControlOptionContextValue,\n} from \"./ListControlOptionContext\";\nimport type { ListControlOptionStore } from \"./ListControlOptionStore\";\n\ntype ListControlProviderValue<Item> = ListControlContextValue<Item> & {\n optionStateStore: ListControlOptionStore<Item>;\n};\n\nexport function ListControlProvider<Item>({\n children,\n value,\n}: {\n children: ReactNode;\n value: ListControlProviderValue<Item>;\n}) {\n const { optionStateStore, ...publicValue } = value;\n const optionValue = useMemo<ListControlOptionContextValue<Item>>(\n () => ({\n disabled: value.disabled,\n listRef: value.listRef,\n multiselect: value.multiselect,\n optionStateStore,\n register: value.register,\n select: value.select,\n setActive: value.setActive,\n valueToString: value.valueToString,\n }),\n [\n optionStateStore,\n value.disabled,\n value.listRef,\n value.multiselect,\n value.register,\n value.select,\n value.setActive,\n value.valueToString,\n ],\n );\n\n return (\n <ListControlContext.Provider value={publicValue}>\n <ListControlOptionContextProvider value={optionValue}>\n {children}\n </ListControlOptionContextProvider>\n </ListControlContext.Provider>\n );\n}\n"],"names":[],"mappings":";;;;;AAeO,SAAS,mBAAA,CAA0B;AAAA,EACxC,QAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,MAAM,EAAE,gBAAA,EAAkB,GAAG,WAAA,EAAY,GAAI,KAAA;AAC7C,EAAA,MAAM,WAAA,GAAc,OAAA;AAAA,IAClB,OAAO;AAAA,MACL,UAAU,KAAA,CAAM,QAAA;AAAA,MAChB,SAAS,KAAA,CAAM,OAAA;AAAA,MACf,aAAa,KAAA,CAAM,WAAA;AAAA,MACnB,gBAAA;AAAA,MACA,UAAU,KAAA,CAAM,QAAA;AAAA,MAChB,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,WAAW,KAAA,CAAM,SAAA;AAAA,MACjB,eAAe,KAAA,CAAM;AAAA,KACvB,CAAA;AAAA,IACA;AAAA,MACE,gBAAA;AAAA,MACA,KAAA,CAAM,QAAA;AAAA,MACN,KAAA,CAAM,OAAA;AAAA,MACN,KAAA,CAAM,WAAA;AAAA,MACN,KAAA,CAAM,QAAA;AAAA,MACN,KAAA,CAAM,MAAA;AAAA,MACN,KAAA,CAAM,SAAA;AAAA,MACN,KAAA,CAAM;AAAA;AACR,GACF;AAEA,EAAA,uBACE,GAAA,CAAC,kBAAA,CAAmB,QAAA,EAAnB,EAA4B,KAAA,EAAO,WAAA,EAClC,QAAA,kBAAA,GAAA,CAAC,gCAAA,EAAA,EAAiC,KAAA,EAAO,WAAA,EACtC,QAAA,EACH,CAAA,EACF,CAAA;AAEJ;;;;"}
@@ -0,0 +1,158 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
8
+ var __privateWrapper = (obj, member, setter, getter) => ({
9
+ set _(value) {
10
+ __privateSet(obj, member, value);
11
+ },
12
+ get _() {
13
+ return __privateGet(obj, member, getter);
14
+ }
15
+ });
16
+ var _entries, _ordered, _indexById, _nextGeneration, _hasGaps;
17
+ function createCoalescedRebuild(rebuild, enqueue = (callback) => {
18
+ Promise.resolve().then(callback);
19
+ }) {
20
+ let pending = false;
21
+ let cancelled = false;
22
+ return {
23
+ schedule() {
24
+ if (pending || cancelled) return;
25
+ pending = true;
26
+ enqueue(() => {
27
+ pending = false;
28
+ if (!cancelled) rebuild();
29
+ });
30
+ },
31
+ cancel() {
32
+ cancelled = true;
33
+ pending = false;
34
+ }
35
+ };
36
+ }
37
+ class ListControlRegistry {
38
+ constructor() {
39
+ __privateAdd(this, _entries, /* @__PURE__ */ new Map());
40
+ __privateAdd(this, _ordered, []);
41
+ __privateAdd(this, _indexById, /* @__PURE__ */ new Map());
42
+ __privateAdd(this, _nextGeneration, 0);
43
+ __privateAdd(this, _hasGaps, false);
44
+ }
45
+ register(option, element) {
46
+ const entry = {
47
+ data: option,
48
+ element,
49
+ generation: __privateWrapper(this, _nextGeneration)._++
50
+ };
51
+ __privateGet(this, _entries).set(option.id, entry);
52
+ const currentIndex = __privateGet(this, _indexById).get(option.id);
53
+ if (currentIndex === void 0) {
54
+ __privateGet(this, _indexById).set(option.id, __privateGet(this, _ordered).length);
55
+ __privateGet(this, _ordered).push(entry);
56
+ } else {
57
+ __privateGet(this, _ordered)[currentIndex] = entry;
58
+ }
59
+ return () => {
60
+ const current = __privateGet(this, _entries).get(option.id);
61
+ if ((current == null ? void 0 : current.generation) !== entry.generation) {
62
+ return;
63
+ }
64
+ __privateGet(this, _entries).delete(option.id);
65
+ const index = __privateGet(this, _indexById).get(option.id);
66
+ if (index !== void 0 && __privateGet(this, _ordered)[index] === entry) {
67
+ __privateGet(this, _ordered)[index] = void 0;
68
+ __privateGet(this, _indexById).delete(option.id);
69
+ __privateSet(this, _hasGaps, true);
70
+ }
71
+ };
72
+ }
73
+ rebuild(listElement) {
74
+ const ordered = [];
75
+ const indexById = /* @__PURE__ */ new Map();
76
+ for (const element of listElement.querySelectorAll(
77
+ '[role="option"]'
78
+ )) {
79
+ const entry = __privateGet(this, _entries).get(element.id);
80
+ if ((entry == null ? void 0 : entry.element) === element && element.isConnected) {
81
+ indexById.set(entry.data.id, ordered.length);
82
+ ordered.push(entry);
83
+ }
84
+ }
85
+ for (const id of __privateGet(this, _entries).keys()) {
86
+ if (!indexById.has(id)) {
87
+ __privateGet(this, _entries).delete(id);
88
+ }
89
+ }
90
+ __privateSet(this, _ordered, ordered);
91
+ __privateSet(this, _indexById, indexById);
92
+ __privateSet(this, _hasGaps, false);
93
+ }
94
+ getAt(index) {
95
+ if (!__privateGet(this, _hasGaps)) {
96
+ return __privateGet(this, _ordered)[index];
97
+ }
98
+ let currentIndex = 0;
99
+ for (const entry of __privateGet(this, _ordered)) {
100
+ if (entry && __privateGet(this, _entries).get(entry.data.id) === entry) {
101
+ if (currentIndex === index) return entry;
102
+ currentIndex++;
103
+ }
104
+ }
105
+ return void 0;
106
+ }
107
+ get length() {
108
+ return __privateGet(this, _hasGaps) ? __privateGet(this, _entries).size : __privateGet(this, _ordered).length;
109
+ }
110
+ indexOfId(id) {
111
+ const physicalIndex = __privateGet(this, _indexById).get(id);
112
+ if (physicalIndex === void 0 || !__privateGet(this, _hasGaps)) {
113
+ return physicalIndex ?? -1;
114
+ }
115
+ let logicalIndex = 0;
116
+ for (let index = 0; index < physicalIndex; index++) {
117
+ const entry = __privateGet(this, _ordered)[index];
118
+ if (entry && __privateGet(this, _entries).get(entry.data.id) === entry) logicalIndex++;
119
+ }
120
+ return logicalIndex;
121
+ }
122
+ indexOfValue(value) {
123
+ let logicalIndex = 0;
124
+ for (const entry of __privateGet(this, _ordered)) {
125
+ if (entry && __privateGet(this, _entries).get(entry.data.id) === entry) {
126
+ if (entry.data.value === value) return logicalIndex;
127
+ logicalIndex++;
128
+ }
129
+ }
130
+ return -1;
131
+ }
132
+ findByData(option) {
133
+ const entry = __privateGet(this, _entries).get(option.id);
134
+ return (entry == null ? void 0 : entry.data) === option ? entry : void 0;
135
+ }
136
+ matching(predicate) {
137
+ const matches = [];
138
+ for (const entry of __privateGet(this, _ordered)) {
139
+ if (entry !== void 0 && __privateGet(this, _entries).get(entry.data.id) === entry && predicate(entry.data)) {
140
+ matches.push(entry);
141
+ }
142
+ }
143
+ return matches;
144
+ }
145
+ snapshot() {
146
+ return __privateGet(this, _ordered).filter(
147
+ (entry) => entry !== void 0
148
+ );
149
+ }
150
+ }
151
+ _entries = new WeakMap();
152
+ _ordered = new WeakMap();
153
+ _indexById = new WeakMap();
154
+ _nextGeneration = new WeakMap();
155
+ _hasGaps = new WeakMap();
156
+
157
+ export { ListControlRegistry, createCoalescedRebuild };
158
+ //# sourceMappingURL=ListControlRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListControlRegistry.js","sources":["../src/list-control/ListControlRegistry.ts"],"sourcesContent":["import type { OptionValue } from \"./ListControlContext\";\n\nexport interface RegisteredOption<Item> {\n data: OptionValue<Item>;\n element: HTMLElement;\n}\n\ninterface RegistryEntry<Item> extends RegisteredOption<Item> {\n generation: number;\n}\n\nexport function createCoalescedRebuild(\n rebuild: () => void,\n enqueue: (callback: () => void) => void = (callback) => {\n // Promise jobs are supported by Chrome 86.\n Promise.resolve().then(callback);\n },\n): { schedule: () => void; cancel: () => void } {\n let pending = false;\n let cancelled = false;\n\n return {\n schedule() {\n if (pending || cancelled) return;\n pending = true;\n enqueue(() => {\n pending = false;\n if (!cancelled) rebuild();\n });\n },\n cancel() {\n cancelled = true;\n pending = false;\n },\n };\n}\n\n/** Internal option registry optimized for large, non-virtualized lists. */\nexport class ListControlRegistry<Item> {\n readonly #entries = new Map<string, RegistryEntry<Item>>();\n #ordered: (RegistryEntry<Item> | undefined)[] = [];\n #indexById = new Map<string, number>();\n #nextGeneration = 0;\n #hasGaps = false;\n\n register(option: OptionValue<Item>, element: HTMLElement): () => void {\n const entry: RegistryEntry<Item> = {\n data: option,\n element,\n generation: this.#nextGeneration++,\n };\n this.#entries.set(option.id, entry);\n\n const currentIndex = this.#indexById.get(option.id);\n if (currentIndex === undefined) {\n this.#indexById.set(option.id, this.#ordered.length);\n this.#ordered.push(entry);\n } else {\n this.#ordered[currentIndex] = entry;\n }\n\n return () => {\n const current = this.#entries.get(option.id);\n if (current?.generation !== entry.generation) {\n return;\n }\n this.#entries.delete(option.id);\n\n const index = this.#indexById.get(option.id);\n if (index !== undefined && this.#ordered[index] === entry) {\n // Rebuild compacts the snapshot after the corresponding DOM removal.\n this.#ordered[index] = undefined;\n this.#indexById.delete(option.id);\n this.#hasGaps = true;\n }\n };\n }\n\n rebuild(listElement: Pick<HTMLElement, \"querySelectorAll\">): void {\n const ordered: RegistryEntry<Item>[] = [];\n const indexById = new Map<string, number>();\n\n for (const element of listElement.querySelectorAll<HTMLElement>(\n '[role=\"option\"]',\n )) {\n const entry = this.#entries.get(element.id);\n if (entry?.element === element && element.isConnected) {\n indexById.set(entry.data.id, ordered.length);\n ordered.push(entry);\n }\n }\n\n for (const id of this.#entries.keys()) {\n if (!indexById.has(id)) {\n this.#entries.delete(id);\n }\n }\n\n this.#ordered = ordered;\n this.#indexById = indexById;\n this.#hasGaps = false;\n }\n\n getAt(index: number): RegisteredOption<Item> | undefined {\n if (!this.#hasGaps) {\n return this.#ordered[index];\n }\n\n let currentIndex = 0;\n for (const entry of this.#ordered) {\n if (entry && this.#entries.get(entry.data.id) === entry) {\n if (currentIndex === index) return entry;\n currentIndex++;\n }\n }\n return undefined;\n }\n\n get length(): number {\n return this.#hasGaps ? this.#entries.size : this.#ordered.length;\n }\n\n indexOfId(id: string): number {\n const physicalIndex = this.#indexById.get(id);\n if (physicalIndex === undefined || !this.#hasGaps) {\n return physicalIndex ?? -1;\n }\n\n let logicalIndex = 0;\n for (let index = 0; index < physicalIndex; index++) {\n const entry = this.#ordered[index];\n if (entry && this.#entries.get(entry.data.id) === entry) logicalIndex++;\n }\n return logicalIndex;\n }\n\n indexOfValue(value: Item): number {\n let logicalIndex = 0;\n for (const entry of this.#ordered) {\n if (entry && this.#entries.get(entry.data.id) === entry) {\n if (entry.data.value === value) return logicalIndex;\n logicalIndex++;\n }\n }\n return -1;\n }\n\n findByData(option: OptionValue<Item>): RegisteredOption<Item> | undefined {\n const entry = this.#entries.get(option.id);\n return entry?.data === option ? entry : undefined;\n }\n\n matching(\n predicate: (option: OptionValue<Item>) => boolean,\n ): RegisteredOption<Item>[] {\n const matches: RegistryEntry<Item>[] = [];\n for (const entry of this.#ordered) {\n if (\n entry !== undefined &&\n this.#entries.get(entry.data.id) === entry &&\n predicate(entry.data)\n ) {\n matches.push(entry);\n }\n }\n return matches;\n }\n\n snapshot(): readonly RegisteredOption<Item>[] {\n return this.#ordered.filter(\n (entry): entry is RegistryEntry<Item> => entry !== undefined,\n );\n }\n}\n"],"names":[],"mappings":"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"}
@@ -2,15 +2,53 @@ import { useRef, useState, useEffect, useCallback } from 'react';
2
2
  import 'clsx';
3
3
  import 'react/jsx-runtime';
4
4
  import { useControlled } from '../utils/useControlled.js';
5
+ import { useEventCallback } from '../utils/useEventCallback.js';
5
6
  import '../utils/useFloatingUI/useFloatingUI.js';
6
7
  import { useForkRef } from '../utils/useForkRef.js';
7
8
  import '../utils/useId.js';
9
+ import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect.js';
8
10
  import '../salt-provider/SaltProvider.js';
9
11
  import '../viewport/ViewportProvider.js';
12
+ import { ListControlOptionStore } from './ListControlOptionStore.js';
13
+ import { ListControlRegistry, createCoalescedRebuild } from './ListControlRegistry.js';
10
14
 
11
15
  function defaultValueToString(item) {
12
16
  return String(item);
13
17
  }
18
+ function findOptionFromSearch(options, search, valueToString, startFrom) {
19
+ var _a;
20
+ const collator = new Intl.Collator("en", {
21
+ usage: "search",
22
+ sensitivity: "base"
23
+ });
24
+ const startFromIndex = startFrom ? options.findIndex((item) => item.data.value === startFrom.value) : -1;
25
+ const startIndex = startFrom ? startFromIndex + 1 : 0;
26
+ const firstIndexByValue = /* @__PURE__ */ new Map();
27
+ for (let index = 0; index < options.length; index++) {
28
+ const value = options[index].data.value;
29
+ if ((typeof value !== "number" || !Number.isNaN(value)) && !firstIndexByValue.has(value)) {
30
+ firstIndexByValue.set(value, index);
31
+ }
32
+ }
33
+ const letters = search.split("");
34
+ const allSameLetter = letters.length > 0 && letters.every((letter) => collator.compare(letter, letters[0]) === 0);
35
+ let repeatedCharacterMatch;
36
+ for (let offset = 0; offset < options.length; offset++) {
37
+ const index = (startIndex + offset) % options.length;
38
+ const option = options[index].data;
39
+ if (firstIndexByValue.get(option.value) !== index) {
40
+ continue;
41
+ }
42
+ const optionText = valueToString(option.value);
43
+ if (collator.compare(optionText.substring(0, search.length), search) === 0) {
44
+ return option;
45
+ }
46
+ if (repeatedCharacterMatch === void 0 && allSameLetter && collator.compare((_a = optionText[0]) == null ? void 0 : _a.toLowerCase(), letters[0]) === 0) {
47
+ repeatedCharacterMatch = option;
48
+ }
49
+ }
50
+ return repeatedCharacterMatch;
51
+ }
14
52
  function useListControl(props) {
15
53
  const {
16
54
  open: openProp,
@@ -24,6 +62,13 @@ function useListControl(props) {
24
62
  readOnly,
25
63
  valueToString = defaultValueToString
26
64
  } = props;
65
+ const optionStateStoreRef = useRef(null);
66
+ if (optionStateStoreRef.current === null) {
67
+ optionStateStoreRef.current = new ListControlOptionStore(
68
+ selectedProp ?? defaultSelected ?? []
69
+ );
70
+ }
71
+ const optionStateStore = optionStateStoreRef.current;
27
72
  const listRef = useRef(null);
28
73
  const [listElement, setListElement] = useState(null);
29
74
  const setListRef = useForkRef(listRef, setListElement);
@@ -35,16 +80,9 @@ function useListControl(props) {
35
80
  setFocusVisibleState(false);
36
81
  }
37
82
  }, [disabled, focusedState]);
38
- const [activeState, setActiveState] = useState(
83
+ const [activeState, setActive] = useState(
39
84
  void 0
40
85
  );
41
- const setActive = useCallback((option) => {
42
- if (option) {
43
- setActiveState(option);
44
- } else {
45
- setActiveState(void 0);
46
- }
47
- }, []);
48
86
  const [openState, setOpenState] = useControlled({
49
87
  controlled: openProp,
50
88
  default: Boolean(defaultOpen),
@@ -68,152 +106,143 @@ function useListControl(props) {
68
106
  name: "ListControl",
69
107
  state: "selected"
70
108
  });
71
- const select = (event, option) => {
72
- if (option.disabled || readOnly || disabled) {
73
- return;
74
- }
75
- let newSelected = [option.value];
76
- if (multiselect) {
77
- if (selectedState.includes(option.value)) {
78
- newSelected = selectedState.filter((item) => item !== option.value);
79
- } else {
80
- newSelected = selectedState.concat([option.value]);
109
+ const select = useEventCallback(
110
+ (event, option) => {
111
+ if (option.disabled || readOnly || disabled) {
112
+ return;
113
+ }
114
+ let newSelected = [option.value];
115
+ if (multiselect) {
116
+ if (selectedState.includes(option.value)) {
117
+ newSelected = selectedState.filter((item) => item !== option.value);
118
+ } else {
119
+ newSelected = selectedState.concat([option.value]);
120
+ }
121
+ }
122
+ setSelectedState(newSelected);
123
+ onSelectionChange == null ? void 0 : onSelectionChange(event, newSelected);
124
+ if (!multiselect) {
125
+ setOpen(false);
81
126
  }
82
127
  }
83
- setSelectedState(newSelected);
84
- onSelectionChange == null ? void 0 : onSelectionChange(event, newSelected);
85
- if (!multiselect) {
86
- setOpen(false);
87
- }
88
- };
128
+ );
89
129
  const clear = (event) => {
90
130
  setSelectedState([]);
91
131
  if (selectedState.length !== 0) {
92
132
  onSelectionChange == null ? void 0 : onSelectionChange(event, []);
93
133
  }
94
134
  };
95
- const optionsRef = useRef([]);
135
+ const registryRef = useRef(null);
136
+ if (registryRef.current === null) {
137
+ registryRef.current = new ListControlRegistry();
138
+ }
139
+ const registry = registryRef.current;
140
+ const scheduleRebuildRef = useRef(void 0);
141
+ useIsomorphicLayoutEffect(() => {
142
+ optionStateStore.setActiveId(activeState == null ? void 0 : activeState.id);
143
+ }, [activeState == null ? void 0 : activeState.id, optionStateStore]);
144
+ useIsomorphicLayoutEffect(() => {
145
+ optionStateStore.setFocusVisible(focusVisibleState);
146
+ }, [focusVisibleState, optionStateStore]);
147
+ useIsomorphicLayoutEffect(() => {
148
+ optionStateStore.setSelected(selectedState);
149
+ }, [optionStateStore, selectedState]);
96
150
  const register = useCallback(
97
151
  (optionValue, element) => {
98
- const { id } = optionValue;
99
- const existingIndex = optionsRef.current.findIndex(
100
- (item) => item.data.id === id
101
- );
102
- if (existingIndex !== -1) {
103
- optionsRef.current.splice(existingIndex, 1);
104
- }
105
- optionsRef.current.push({ data: optionValue, element });
152
+ var _a;
153
+ const unregisterOptionState = optionStateStore.register(optionValue);
154
+ const unregisterRegistry = registry.register(optionValue, element);
155
+ (_a = scheduleRebuildRef.current) == null ? void 0 : _a.call(scheduleRebuildRef);
106
156
  return () => {
107
- optionsRef.current = optionsRef.current.filter(
108
- (item) => item.data.id !== id
109
- );
157
+ var _a2;
158
+ unregisterRegistry();
159
+ unregisterOptionState();
160
+ (_a2 = scheduleRebuildRef.current) == null ? void 0 : _a2.call(scheduleRebuildRef);
110
161
  };
111
162
  },
112
- []
163
+ [optionStateStore, registry]
113
164
  );
114
165
  useEffect(() => {
115
- const sortOptions = () => {
116
- optionsRef.current = optionsRef.current.filter((a) => a.element.isConnected).sort(({ element: a }, { element: b }) => {
117
- if (a === b) return 0;
118
- const pos = a.compareDocumentPosition(b);
119
- if (pos & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
120
- if (pos & Node.DOCUMENT_POSITION_PRECEDING) return 1;
121
- return 0;
122
- });
166
+ if (!listElement) return;
167
+ const rebuild = () => {
168
+ mutationObserver.takeRecords();
169
+ registry.rebuild(listElement);
123
170
  };
171
+ const coalescedRebuild = createCoalescedRebuild(rebuild);
172
+ scheduleRebuildRef.current = coalescedRebuild.schedule;
173
+ const containsOption = (node) => node.nodeType === Node.ELEMENT_NODE && (node.matches('[role="option"]') || node.querySelector('[role="option"]') !== null);
124
174
  const mutationObserver = new MutationObserver((mutations) => {
125
- const optionsChanged = mutations.some(
126
- (mutation) => Array.from(mutation.addedNodes).some(
127
- (node) => {
128
- var _a;
129
- return node instanceof HTMLElement && ((_a = node.matches) == null ? void 0 : _a.call(node, '[role="option"]'));
130
- }
131
- )
132
- );
133
- if (optionsChanged) {
134
- sortOptions();
175
+ if (mutations.some(
176
+ ({ addedNodes, removedNodes }) => Array.from(addedNodes).some(containsOption) || Array.from(removedNodes).some(containsOption)
177
+ )) {
178
+ coalescedRebuild.schedule();
135
179
  }
136
180
  });
137
- if (!listElement) return;
138
181
  mutationObserver.observe(listElement, {
139
182
  childList: true,
140
183
  subtree: true
141
184
  });
142
- sortOptions();
143
- return () => mutationObserver.disconnect();
144
- }, [listElement]);
185
+ rebuild();
186
+ return () => {
187
+ scheduleRebuildRef.current = void 0;
188
+ coalescedRebuild.cancel();
189
+ mutationObserver.disconnect();
190
+ };
191
+ }, [listElement, registry]);
145
192
  const getOptionAtIndex = useCallback(
146
193
  (index) => {
147
- return optionsRef.current[index];
194
+ return registry.getAt(index);
148
195
  },
149
- []
196
+ [registry]
197
+ );
198
+ const getIndexOfOption = useCallback(
199
+ (option) => {
200
+ return registry.indexOfValue(option.value);
201
+ },
202
+ [registry]
150
203
  );
151
- const getIndexOfOption = useCallback((option) => {
152
- return optionsRef.current.findIndex(
153
- (item) => item.data.value === option.value
154
- );
155
- }, []);
156
204
  const getOptionsMatching = useCallback(
157
205
  (predicate) => {
158
- return optionsRef.current.filter((item) => predicate(item.data));
206
+ return registry.matching(predicate);
159
207
  },
160
- []
208
+ [registry]
161
209
  );
162
210
  const getOptionFromSearch = useCallback(
163
211
  (search, startFrom) => {
164
- const collator = new Intl.Collator("en", {
165
- usage: "search",
166
- sensitivity: "base"
167
- });
168
- const startIndex = startFrom ? getIndexOfOption(startFrom) + 1 : 0;
169
- const searchList = optionsRef.current.map((item) => item.data);
170
- let matches = searchList.filter(
171
- (option) => collator.compare(
172
- valueToString(option.value).substring(0, search.length),
173
- search
174
- ) === 0
212
+ return findOptionFromSearch(
213
+ registry.snapshot(),
214
+ search,
215
+ valueToString,
216
+ startFrom
175
217
  );
176
- if (matches.length === 0) {
177
- const letters = search.split("");
178
- const allSameLetter = letters.length > 0 && letters.every((letter) => collator.compare(letter, letters[0]) === 0);
179
- if (allSameLetter) {
180
- matches = searchList.filter(
181
- (option) => collator.compare(
182
- valueToString(option.value)[0].toLowerCase(),
183
- letters[0]
184
- ) === 0
185
- );
186
- }
187
- }
188
- return matches.find((option) => getIndexOfOption(option) >= startIndex);
189
218
  },
190
- [getIndexOfOption, valueToString]
219
+ [registry, valueToString]
191
220
  );
192
221
  const getFirstOption = useCallback(() => {
193
222
  return getOptionAtIndex(0);
194
223
  }, [getOptionAtIndex]);
195
224
  const getLastOption = useCallback(() => {
196
- return getOptionAtIndex(optionsRef.current.length - 1);
197
- }, [getOptionAtIndex]);
225
+ return getOptionAtIndex(registry.length - 1);
226
+ }, [getOptionAtIndex, registry]);
198
227
  const getOptionBefore = useCallback(
199
228
  (option) => {
200
- const index = getIndexOfOption(option);
229
+ const index = registry.indexOfId(option.id);
201
230
  return getOptionAtIndex(index - 1);
202
231
  },
203
- [getIndexOfOption, getOptionAtIndex]
232
+ [getOptionAtIndex, registry]
204
233
  );
205
234
  const getOptionAfter = useCallback(
206
235
  (option) => {
207
- const index = getIndexOfOption(option);
236
+ const index = registry.indexOfId(option.id);
208
237
  return getOptionAtIndex(index + 1);
209
238
  },
210
- [getIndexOfOption, getOptionAtIndex]
239
+ [getOptionAtIndex, registry]
211
240
  );
212
241
  const getOptionPageAbove = useCallback(
213
242
  (start) => {
214
243
  var _a;
215
244
  const list = listRef.current;
216
- let option = optionsRef.current.find((option2) => option2.data === start);
245
+ let option = registry.findByData(start);
217
246
  if (!list || !option) {
218
247
  return void 0;
219
248
  }
@@ -230,12 +259,12 @@ function useListControl(props) {
230
259
  }
231
260
  return option ?? getFirstOption();
232
261
  },
233
- [getFirstOption, getOptionBefore]
262
+ [getFirstOption, getOptionBefore, registry]
234
263
  );
235
264
  const getOptionPageBelow = useCallback(
236
265
  (start) => {
237
266
  const list = listRef.current;
238
- let option = optionsRef.current.find((option2) => option2.data === start);
267
+ let option = registry.findByData(start);
239
268
  if (!list || !option) {
240
269
  return void 0;
241
270
  }
@@ -252,14 +281,12 @@ function useListControl(props) {
252
281
  }
253
282
  return option ?? getLastOption();
254
283
  },
255
- [getLastOption, getOptionAfter]
284
+ [getLastOption, getOptionAfter, registry]
256
285
  );
257
286
  useEffect(() => {
258
287
  var _a;
259
288
  if (listRef.current) {
260
- const activeElement = (_a = optionsRef.current.find(
261
- (option) => option.data === activeState
262
- )) == null ? void 0 : _a.element;
289
+ const activeElement = activeState ? (_a = registry.findByData(activeState)) == null ? void 0 : _a.element : void 0;
263
290
  if (!activeElement) {
264
291
  return;
265
292
  }
@@ -268,7 +295,7 @@ function useListControl(props) {
268
295
  inline: "nearest"
269
296
  });
270
297
  }
271
- }, [activeState]);
298
+ }, [activeState, registry]);
272
299
  return {
273
300
  multiselect: Boolean(multiselect),
274
301
  openState,
@@ -286,7 +313,6 @@ function useListControl(props) {
286
313
  setFocusedState,
287
314
  setListRef,
288
315
  listRef,
289
- options: optionsRef.current.map((option) => option.element),
290
316
  register,
291
317
  getOptionAtIndex,
292
318
  getIndexOfOption,
@@ -299,9 +325,10 @@ function useListControl(props) {
299
325
  getFirstOption,
300
326
  getLastOption,
301
327
  valueToString,
302
- disabled
328
+ disabled,
329
+ optionStateStore
303
330
  };
304
331
  }
305
332
 
306
- export { defaultValueToString, useListControl };
333
+ export { defaultValueToString, findOptionFromSearch, useListControl };
307
334
  //# sourceMappingURL=ListControlState.js.map