@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,85 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { useComponentCssInjection } from '@salt-ds/styles';
3
+ import { useWindow } from '@salt-ds/window';
4
+ import { clsx } from 'clsx';
5
+ import { forwardRef, cloneElement } from 'react';
6
+ import '../button/Button.js';
7
+ import { useButton } from '../button/useButton.js';
8
+ import { useIcon } from '../semantic-icon-provider/SemanticIconProvider.js';
9
+ import { capitalize } from '../utils/capitalize.js';
10
+ import { makePrefixer } from '../utils/makePrefixer.js';
11
+ import { renderProps } from '../utils/renderProps.js';
12
+ import '../utils/useFloatingUI/useFloatingUI.js';
13
+ import '../utils/useId.js';
14
+ import '../salt-provider/SaltProvider.js';
15
+ import '../viewport/ViewportProvider.js';
16
+ import css_248z from './LinkButton.css.js';
17
+
18
+ const withBaseName = makePrefixer("saltLinkButton");
19
+ const LinkButton = forwardRef(
20
+ function LinkButton2(props, ref) {
21
+ const {
22
+ children,
23
+ className,
24
+ IconComponent,
25
+ onBlur,
26
+ onClick,
27
+ onKeyDown,
28
+ onKeyUp,
29
+ sentiment = "neutral",
30
+ target = "_self",
31
+ underline = "default",
32
+ ...rest
33
+ } = props;
34
+ const { active, buttonProps } = useButton({
35
+ onBlur,
36
+ onClick,
37
+ onKeyDown,
38
+ onKeyUp
39
+ });
40
+ const { tabIndex: _tabIndex, ...activeStateProps } = buttonProps;
41
+ const targetWindow = useWindow();
42
+ useComponentCssInjection({
43
+ testId: "salt-link-button",
44
+ css: css_248z,
45
+ window: targetWindow
46
+ });
47
+ const { ExternalIcon } = useIcon();
48
+ const LinkButtonIconComponent = IconComponent === void 0 ? ExternalIcon : IconComponent;
49
+ const linkButton = renderProps("a", {
50
+ className: clsx(
51
+ withBaseName(),
52
+ withBaseName(sentiment),
53
+ withBaseName(`underline${capitalize(underline)}`),
54
+ { [withBaseName("active")]: active },
55
+ className
56
+ ),
57
+ ...activeStateProps,
58
+ ...rest,
59
+ ref,
60
+ target,
61
+ children
62
+ });
63
+ if (linkButton.props.target !== "_blank") {
64
+ return linkButton;
65
+ }
66
+ return cloneElement(
67
+ linkButton,
68
+ void 0,
69
+ /* @__PURE__ */ jsxs(Fragment, { children: [
70
+ linkButton.props.children,
71
+ LinkButtonIconComponent && /* @__PURE__ */ jsx(
72
+ LinkButtonIconComponent,
73
+ {
74
+ className: withBaseName("icon"),
75
+ "aria-hidden": true
76
+ }
77
+ ),
78
+ /* @__PURE__ */ jsx("span", { className: withBaseName("externalLinkADA"), children: "Opens in a new tab" })
79
+ ] })
80
+ );
81
+ }
82
+ );
83
+
84
+ export { LinkButton };
85
+ //# sourceMappingURL=LinkButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LinkButton.js","sources":["../src/link-button/LinkButton.tsx"],"sourcesContent":["import type { IconProps } from \"@salt-ds/icons\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n type ComponentType,\n cloneElement,\n forwardRef,\n} from \"react\";\nimport { useButton } from \"../button\";\nimport { useIcon } from \"../semantic-icon-provider\";\nimport {\n capitalize,\n makePrefixer,\n type RenderPropsType,\n renderProps,\n} from \"../utils\";\n\nimport linkButtonCss from \"./LinkButton.css\";\n\nconst withBaseName = makePrefixer(\"saltLinkButton\");\n\nexport interface LinkButtonProps extends ComponentPropsWithoutRef<\"a\"> {\n /**\n * Icon component displayed when `target=\"_blank\"`. Defaults to `ExternalIcon` from `SemanticIconProvider`.\n */\n IconComponent?: ComponentType<IconProps> | null;\n /**\n * The sentiment of the button. Options are 'accented' and 'neutral'.\n * 'neutral' is the default value.\n */\n sentiment?: \"accented\" | \"neutral\";\n /**\n * Render prop to enable customisation of anchor element.\n */\n render?: RenderPropsType[\"render\"];\n /**\n * Either \"default\" or \"never\".\n * Determines when underline should be applied to the link button.\n *\n * @default \"default\".\n */\n underline?: \"default\" | \"never\";\n}\n\nexport const LinkButton = forwardRef<HTMLAnchorElement, LinkButtonProps>(\n function LinkButton(props, ref) {\n const {\n children,\n className,\n IconComponent,\n onBlur,\n onClick,\n onKeyDown,\n onKeyUp,\n sentiment = \"neutral\",\n target = \"_self\",\n underline = \"default\",\n ...rest\n } = props;\n\n const { active, buttonProps } = useButton<HTMLAnchorElement>({\n onBlur,\n onClick,\n onKeyDown,\n onKeyUp,\n });\n // Native anchors with an href do not require tabIndex=\"0\".\n const { tabIndex: _tabIndex, ...activeStateProps } = buttonProps;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-link-button\",\n css: linkButtonCss,\n window: targetWindow,\n });\n const { ExternalIcon } = useIcon();\n\n const LinkButtonIconComponent =\n IconComponent === undefined ? ExternalIcon : IconComponent;\n\n const linkButton = renderProps(\"a\", {\n className: clsx(\n withBaseName(),\n withBaseName(sentiment),\n withBaseName(`underline${capitalize(underline)}`),\n { [withBaseName(\"active\")]: active },\n className,\n ),\n ...activeStateProps,\n ...rest,\n ref,\n target,\n children,\n });\n\n if (linkButton.props.target !== \"_blank\") {\n return linkButton;\n }\n\n return cloneElement(\n linkButton,\n undefined,\n <>\n {linkButton.props.children}\n {LinkButtonIconComponent && (\n <LinkButtonIconComponent\n className={withBaseName(\"icon\")}\n aria-hidden\n />\n )}\n <span className={withBaseName(\"externalLinkADA\")}>\n Opens in a new tab\n </span>\n </>,\n );\n },\n);\n"],"names":["LinkButton","linkButtonCss"],"mappings":";;;;;;;;;;;;;;;;;AAqBA,MAAM,YAAA,GAAe,aAAa,gBAAgB,CAAA;AAyB3C,MAAM,UAAA,GAAa,UAAA;AAAA,EACxB,SAASA,WAAAA,CAAW,KAAA,EAAO,GAAA,EAAK;AAC9B,IAAA,MAAM;AAAA,MACJ,QAAA;AAAA,MACA,SAAA;AAAA,MACA,aAAA;AAAA,MACA,MAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA,GAAY,SAAA;AAAA,MACZ,MAAA,GAAS,OAAA;AAAA,MACT,SAAA,GAAY,SAAA;AAAA,MACZ,GAAG;AAAA,KACL,GAAI,KAAA;AAEJ,IAAA,MAAM,EAAE,MAAA,EAAQ,WAAA,EAAY,GAAI,SAAA,CAA6B;AAAA,MAC3D,MAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,MAAM,EAAE,QAAA,EAAU,SAAA,EAAW,GAAG,kBAAiB,GAAI,WAAA;AAErD,IAAA,MAAM,eAAe,SAAA,EAAU;AAC/B,IAAA,wBAAA,CAAyB;AAAA,MACvB,MAAA,EAAQ,kBAAA;AAAA,MACR,GAAA,EAAKC,QAAA;AAAA,MACL,MAAA,EAAQ;AAAA,KACT,CAAA;AACD,IAAA,MAAM,EAAE,YAAA,EAAa,GAAI,OAAA,EAAQ;AAEjC,IAAA,MAAM,uBAAA,GACJ,aAAA,KAAkB,MAAA,GAAY,YAAA,GAAe,aAAA;AAE/C,IAAA,MAAM,UAAA,GAAa,YAAY,GAAA,EAAK;AAAA,MAClC,SAAA,EAAW,IAAA;AAAA,QACT,YAAA,EAAa;AAAA,QACb,aAAa,SAAS,CAAA;AAAA,QACtB,YAAA,CAAa,CAAA,SAAA,EAAY,UAAA,CAAW,SAAS,CAAC,CAAA,CAAE,CAAA;AAAA,QAChD,EAAE,CAAC,YAAA,CAAa,QAAQ,CAAC,GAAG,MAAA,EAAO;AAAA,QACnC;AAAA,OACF;AAAA,MACA,GAAG,gBAAA;AAAA,MACH,GAAG,IAAA;AAAA,MACH,GAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,IAAI,UAAA,CAAW,KAAA,CAAM,MAAA,KAAW,QAAA,EAAU;AACxC,MAAA,OAAO,UAAA;AAAA,IACT;AAEA,IAAA,OAAO,YAAA;AAAA,MACL,UAAA;AAAA,MACA,MAAA;AAAA,sBACA,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,QAAA,UAAA,CAAW,KAAA,CAAM,QAAA;AAAA,QACjB,uBAAA,oBACC,GAAA;AAAA,UAAC,uBAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,aAAa,MAAM,CAAA;AAAA,YAC9B,aAAA,EAAW;AAAA;AAAA,SACb;AAAA,4BAED,MAAA,EAAA,EAAK,SAAA,EAAW,YAAA,CAAa,iBAAiB,GAAG,QAAA,EAAA,oBAAA,EAElD;AAAA,OAAA,EACF;AAAA,KACF;AAAA,EACF;AACF;;;;"}
@@ -1,4 +1,4 @@
1
- var css_248z = "/* Styles applied to LinkCard */\n.saltLinkCard {\n border-radius: var(--saltLinkCard-borderRadius, var(--salt-palette-corner, 0));\n border-style: var(--saltLinkCard-borderStyle, var(--salt-borderStyle-solid));\n border-width: var(--saltLinkCard-borderWidth, var(--salt-size-fixed-100));\n box-shadow: var(--salt-overlayable-shadow);\n display: block;\n overflow: hidden;\n padding: var(--saltLinkCard-padding, var(--card-padding));\n position: relative;\n text-decoration: none;\n transition: box-shadow var(--salt-duration-instant) ease-in-out;\n --linkCard-accent-color: var(--salt-sentiment-accent-background);\n --card-padding: var(--salt-spacing-200);\n}\n\n.saltLinkCard.saltLinkCard-sectioned {\n padding: 0;\n display: flex;\n flex-direction: column;\n}\n\n@supports selector(:has(*)) {\n .saltLinkCard:has(> .saltCardHeader, > .saltCardContent, > .saltCardFooter) {\n padding: 0;\n display: flex;\n flex-direction: column;\n }\n}\n\n/* Styles applied to LinkCard when variant=\"primary\" */\n.saltLinkCard-primary {\n background: var(--saltLinkCard-background, var(--salt-container-primary-background));\n border-color: var(--salt-container-bold-borderColor);\n}\n\n/* Styles applied to LinkCard when variant=\"secondary\" */\n.saltLinkCard-secondary {\n background: var(--saltLinkCard-background, var(--salt-container-secondary-background));\n border-color: var(--salt-container-bold-borderColor);\n}\n\n/* Styles applied to LinkCard when variant=\"tertiary\" */\n.saltLinkCard-tertiary {\n background: var(--saltLinkCard-background, var(--salt-container-tertiary-background));\n border-color: var(--salt-container-bold-borderColor);\n}\n\n/* Styles applied to create accent */\n.saltLinkCard-accent::after {\n content: \"\";\n position: absolute;\n background-color: var(--saltLinkCard-accent-color, var(--linkCard-accent-color));\n}\n\n/* Styles applied to LinkCard if `accent=\"bottom\"` (default) */\n.saltLinkCard-accentBottom::after {\n left: calc(-1 * var(--salt-size-fixed-100));\n bottom: calc(-1 * var(--salt-size-fixed-100));\n height: var(--salt-size-bar);\n width: calc(100% + var(--salt-size-fixed-200));\n}\n\n/* Styles applied to LinkCard if `accent=\"left\"` */\n.saltLinkCard-accentLeft::after {\n left: calc(-1 * var(--salt-size-fixed-100));\n top: calc(-1 * var(--salt-size-fixed-100));\n height: calc(100% + var(--salt-size-fixed-200));\n width: var(--salt-size-bar);\n}\n\n/* Styles applied to LinkCard if `accent=\"top\"` */\n.saltLinkCard-accentTop::after {\n left: calc(-1 * var(--salt-size-fixed-100));\n top: calc(-1 * var(--salt-size-fixed-100));\n height: var(--salt-size-bar);\n width: calc(100% + var(--salt-size-fixed-200));\n}\n\n/* Styles applied to LinkCard if `accent=\"right\"` */\n.saltLinkCard-accentRight::after {\n right: calc(-1 * var(--salt-size-fixed-100));\n top: calc(-1 * var(--salt-size-fixed-100));\n height: calc(100% + var(--salt-size-fixed-200));\n width: var(--salt-size-bar);\n}\n\n/* Styles applied to LinkCard on focus */\n.saltLinkCard:focus-visible {\n cursor: var(--salt-cursor-hover);\n box-shadow: var(--salt-overlayable-shadow-hover);\n outline-color: var(--salt-focused-outlineColor);\n outline-style: var(--salt-focused-outlineStyle);\n outline-width: var(--salt-focused-outlineWidth);\n outline-offset: var(--salt-focused-outlineOffset);\n --linkCard-accent-color: var(--salt-selectable-foreground-hover);\n}\n\n/* Styles applied on hover state to LinkCard */\n@media (hover: hover) {\n .saltLinkCard:hover {\n cursor: var(--salt-cursor-hover);\n box-shadow: var(--salt-overlayable-shadow-hover);\n border-color: var(--salt-actionable-accented-borderColor-hover);\n }\n}\n\n/* Styles applied on active state to LinkCard */\n.saltLinkCard:active {\n cursor: var(--salt-cursor-active);\n border-color: var(--salt-actionable-accented-borderColor-active);\n box-shadow: var(--salt-overlayable-shadow);\n}\n";
1
+ var css_248z = "/* Styles applied to LinkCard */\n.saltLinkCard {\n border-radius: var(--saltLinkCard-borderRadius, var(--salt-palette-corner, 0));\n border-style: var(--saltLinkCard-borderStyle, var(--salt-borderStyle-solid));\n border-width: var(--saltLinkCard-borderWidth, var(--salt-size-fixed-100));\n border-color: var(--saltLinkCard-borderColor, var(--linkCard-borderColor));\n display: block;\n overflow: hidden;\n padding: var(--saltLinkCard-padding, var(--card-padding));\n position: relative;\n text-decoration: none;\n transition: box-shadow var(--salt-duration-instant) ease-in-out;\n --linkCard-accent-color: var(--salt-sentiment-accent-background);\n --linkCard-borderColor: var(--salt-container-borderColor);\n --card-padding: var(--salt-spacing-200);\n}\n\n.saltLinkCard.saltLinkCard-sectioned {\n padding: 0;\n display: flex;\n flex-direction: column;\n}\n\n@supports selector(:has(*)) {\n .saltLinkCard:has(> .saltCardHeader, > .saltCardContent, > .saltCardFooter) {\n padding: 0;\n display: flex;\n flex-direction: column;\n }\n}\n\n/* Styles applied to LinkCard when variant=\"primary\" */\n.saltLinkCard-primary {\n background: var(--saltLinkCard-background, var(--salt-container-primary-background));\n}\n\n/* Styles applied to LinkCard when variant=\"secondary\" */\n.saltLinkCard-secondary {\n background: var(--saltLinkCard-background, var(--salt-container-secondary-background));\n}\n\n/* Styles applied to LinkCard when variant=\"tertiary\" */\n.saltLinkCard-tertiary {\n background: var(--saltLinkCard-background, var(--salt-container-tertiary-background));\n}\n\n/* Styles applied when elevation=\"flat\" */\n.saltLinkCard-flat {\n box-shadow: var(--saltLinkCard-boxShadow-flat, none);\n}\n\n/* Styles applied when elevation=\"raised\" */\n.saltLinkCard-raised {\n box-shadow: var(--saltLinkCard-boxShadow, var(--salt-overlayable-shadow));\n}\n\n/* Styles applied when borderColor=\"strong\" */\n.saltLinkCard-borderColorStrong {\n --linkCard-borderColor: var(--salt-container-bold-borderColor);\n}\n\n/* Styles applied when borderColor=\"subtle\" */\n.saltLinkCard-borderColorSubtle {\n --linkCard-borderColor: var(--salt-container-subtle-borderColor);\n}\n\n/* Styles applied when borderColor=\"none\" */\n.saltLinkCard-borderColorNone {\n --linkCard-borderColor: transparent;\n}\n\n/* Styles applied to create accent */\n.saltLinkCard-accent::after {\n content: \"\";\n position: absolute;\n background-color: var(--saltLinkCard-accent-color, var(--linkCard-accent-color));\n}\n\n/* Styles applied to LinkCard if `accent=\"bottom\"` */\n.saltLinkCard-accentBottom::after {\n left: calc(-1 * var(--salt-size-fixed-100));\n bottom: calc(-1 * var(--salt-size-fixed-100));\n height: var(--salt-size-bar);\n width: calc(100% + var(--salt-size-fixed-200));\n}\n\n/* Styles applied to LinkCard if `accent=\"left\"` */\n.saltLinkCard-accentLeft::after {\n left: calc(-1 * var(--salt-size-fixed-100));\n top: calc(-1 * var(--salt-size-fixed-100));\n height: calc(100% + var(--salt-size-fixed-200));\n width: var(--salt-size-bar);\n}\n\n/* Styles applied to LinkCard if `accent=\"top\"` */\n.saltLinkCard-accentTop::after {\n left: calc(-1 * var(--salt-size-fixed-100));\n top: calc(-1 * var(--salt-size-fixed-100));\n height: var(--salt-size-bar);\n width: calc(100% + var(--salt-size-fixed-200));\n}\n\n/* Styles applied to LinkCard if `accent=\"right\"` */\n.saltLinkCard-accentRight::after {\n right: calc(-1 * var(--salt-size-fixed-100));\n top: calc(-1 * var(--salt-size-fixed-100));\n height: calc(100% + var(--salt-size-fixed-200));\n width: var(--salt-size-bar);\n}\n\n/* Styles applied to LinkCard on focus */\n.saltLinkCard:focus-visible {\n cursor: var(--salt-cursor-hover);\n box-shadow: var(--salt-overlayable-shadow-hover);\n outline-color: var(--salt-focused-outlineColor);\n outline-style: var(--salt-focused-outlineStyle);\n outline-width: var(--salt-focused-outlineWidth);\n outline-offset: var(--salt-focused-outlineOffset);\n --linkCard-accent-color: var(--salt-selectable-foreground-hover);\n}\n\n/* Styles applied on hover state to LinkCard */\n@media (hover: hover) {\n .saltLinkCard:hover {\n cursor: var(--salt-cursor-hover);\n box-shadow: var(--salt-overlayable-shadow-hover);\n border-color: var(--salt-actionable-accented-borderColor-hover);\n }\n}\n\n/* Styles applied on active state to LinkCard */\n.saltLinkCard:active {\n cursor: var(--salt-cursor-active);\n border-color: var(--salt-actionable-accented-borderColor-active);\n box-shadow: var(--salt-overlayable-shadow);\n}\n";
2
2
 
3
3
  export { css_248z as default };
4
4
  //# sourceMappingURL=LinkCard.css.js.map
@@ -17,8 +17,10 @@ const LinkCard = forwardRef(
17
17
  function LinkCard2(props, ref) {
18
18
  const {
19
19
  accent,
20
+ borderColor,
20
21
  children,
21
22
  className,
23
+ elevation = "raised",
22
24
  href,
23
25
  variant = "primary",
24
26
  ...rest
@@ -36,9 +38,11 @@ const LinkCard = forwardRef(
36
38
  className: clsx(
37
39
  withBaseName(),
38
40
  withBaseName(variant),
41
+ borderColor && withBaseName(`borderColor${capitalize(borderColor)}`),
39
42
  {
40
43
  [withBaseName("accent")]: accent,
41
44
  [withBaseName(`accent${capitalize(accent ?? "")}`)]: accent,
45
+ [withBaseName(elevation || "")]: elevation,
42
46
  [withBaseName("sectioned")]: sectioned
43
47
  },
44
48
  className
@@ -1 +1 @@
1
- {"version":3,"file":"LinkCard.js","sources":["../src/link-card/LinkCard.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport { type ComponentPropsWithoutRef, forwardRef } from \"react\";\n\nimport { hasCardSection } from \"../card/hasCardSection\";\nimport { capitalize, makePrefixer } from \"../utils\";\n\nimport linkCardCss from \"./LinkCard.css\";\n\nconst withBaseName = makePrefixer(\"saltLinkCard\");\n\nexport interface LinkCardProps extends ComponentPropsWithoutRef<\"a\"> {\n /**\n * If provided an accent is shown in the specified position.\n */\n accent?: \"bottom\" | \"top\" | \"left\" | \"right\";\n /**\n * Styling variant; defaults to \"primary\".\n */\n variant?: \"primary\" | \"secondary\" | \"tertiary\";\n}\n\nexport const LinkCard = forwardRef<HTMLAnchorElement, LinkCardProps>(\n function LinkCard(props, ref) {\n const {\n accent,\n children,\n className,\n href,\n variant = \"primary\",\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-link-card\",\n css: linkCardCss,\n window: targetWindow,\n });\n\n const sectioned = hasCardSection(children);\n\n return (\n <a\n className={clsx(\n withBaseName(),\n withBaseName(variant),\n {\n [withBaseName(\"accent\")]: accent,\n [withBaseName(`accent${capitalize(accent ?? \"\")}`)]: accent,\n [withBaseName(\"sectioned\")]: sectioned,\n },\n className,\n )}\n href={href}\n {...rest}\n ref={ref}\n >\n {children}\n </a>\n );\n },\n);\n"],"names":["LinkCard","linkCardCss"],"mappings":";;;;;;;;;;;;;;AAUA,MAAM,YAAA,GAAe,aAAa,cAAc,CAAA;AAazC,MAAM,QAAA,GAAW,UAAA;AAAA,EACtB,SAASA,SAAAA,CAAS,KAAA,EAAO,GAAA,EAAK;AAC5B,IAAA,MAAM;AAAA,MACJ,MAAA;AAAA,MACA,QAAA;AAAA,MACA,SAAA;AAAA,MACA,IAAA;AAAA,MACA,OAAA,GAAU,SAAA;AAAA,MACV,GAAG;AAAA,KACL,GAAI,KAAA;AAEJ,IAAA,MAAM,eAAe,SAAA,EAAU;AAC/B,IAAA,wBAAA,CAAyB;AAAA,MACvB,MAAA,EAAQ,gBAAA;AAAA,MACR,GAAA,EAAKC,QAAA;AAAA,MACL,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,MAAM,SAAA,GAAY,eAAe,QAAQ,CAAA;AAEzC,IAAA,uBACE,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,IAAA;AAAA,UACT,YAAA,EAAa;AAAA,UACb,aAAa,OAAO,CAAA;AAAA,UACpB;AAAA,YACE,CAAC,YAAA,CAAa,QAAQ,CAAC,GAAG,MAAA;AAAA,YAC1B,CAAC,aAAa,CAAA,MAAA,EAAS,UAAA,CAAW,UAAU,EAAE,CAAC,CAAA,CAAE,CAAC,GAAG,MAAA;AAAA,YACrD,CAAC,YAAA,CAAa,WAAW,CAAC,GAAG;AAAA,WAC/B;AAAA,UACA;AAAA,SACF;AAAA,QACA,IAAA;AAAA,QACC,GAAG,IAAA;AAAA,QACJ,GAAA;AAAA,QAEC;AAAA;AAAA,KACH;AAAA,EAEJ;AACF;;;;"}
1
+ {"version":3,"file":"LinkCard.js","sources":["../src/link-card/LinkCard.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport { type ComponentPropsWithoutRef, forwardRef } from \"react\";\n\nimport { hasCardSection } from \"../card/hasCardSection\";\nimport { capitalize, makePrefixer } from \"../utils\";\n\nimport linkCardCss from \"./LinkCard.css\";\n\nconst withBaseName = makePrefixer(\"saltLinkCard\");\n\nexport interface LinkCardProps extends ComponentPropsWithoutRef<\"a\"> {\n /**\n * If provided an accent is shown in the specified position.\n */\n accent?: \"bottom\" | \"top\" | \"left\" | \"right\";\n /**\n * Visual elevation.\n */\n elevation?: \"flat\" | \"raised\";\n /**\n * Border color strength.\n */\n borderColor?: \"strong\" | \"subtle\" | \"none\";\n /**\n * Styling variant; defaults to \"primary\".\n */\n variant?: \"primary\" | \"secondary\" | \"tertiary\";\n}\n\nexport const LinkCard = forwardRef<HTMLAnchorElement, LinkCardProps>(\n function LinkCard(props, ref) {\n const {\n accent,\n borderColor,\n children,\n className,\n elevation = \"raised\",\n href,\n variant = \"primary\",\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-link-card\",\n css: linkCardCss,\n window: targetWindow,\n });\n\n const sectioned = hasCardSection(children);\n\n return (\n <a\n className={clsx(\n withBaseName(),\n withBaseName(variant),\n borderColor && withBaseName(`borderColor${capitalize(borderColor)}`),\n {\n [withBaseName(\"accent\")]: accent,\n [withBaseName(`accent${capitalize(accent ?? \"\")}`)]: accent,\n [withBaseName(elevation || \"\")]: elevation,\n [withBaseName(\"sectioned\")]: sectioned,\n },\n className,\n )}\n href={href}\n {...rest}\n ref={ref}\n >\n {children}\n </a>\n );\n },\n);\n"],"names":["LinkCard","linkCardCss"],"mappings":";;;;;;;;;;;;;;AAUA,MAAM,YAAA,GAAe,aAAa,cAAc,CAAA;AAqBzC,MAAM,QAAA,GAAW,UAAA;AAAA,EACtB,SAASA,SAAAA,CAAS,KAAA,EAAO,GAAA,EAAK;AAC5B,IAAA,MAAM;AAAA,MACJ,MAAA;AAAA,MACA,WAAA;AAAA,MACA,QAAA;AAAA,MACA,SAAA;AAAA,MACA,SAAA,GAAY,QAAA;AAAA,MACZ,IAAA;AAAA,MACA,OAAA,GAAU,SAAA;AAAA,MACV,GAAG;AAAA,KACL,GAAI,KAAA;AAEJ,IAAA,MAAM,eAAe,SAAA,EAAU;AAC/B,IAAA,wBAAA,CAAyB;AAAA,MACvB,MAAA,EAAQ,gBAAA;AAAA,MACR,GAAA,EAAKC,QAAA;AAAA,MACL,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,MAAM,SAAA,GAAY,eAAe,QAAQ,CAAA;AAEzC,IAAA,uBACE,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,IAAA;AAAA,UACT,YAAA,EAAa;AAAA,UACb,aAAa,OAAO,CAAA;AAAA,UACpB,eAAe,YAAA,CAAa,CAAA,WAAA,EAAc,UAAA,CAAW,WAAW,CAAC,CAAA,CAAE,CAAA;AAAA,UACnE;AAAA,YACE,CAAC,YAAA,CAAa,QAAQ,CAAC,GAAG,MAAA;AAAA,YAC1B,CAAC,aAAa,CAAA,MAAA,EAAS,UAAA,CAAW,UAAU,EAAE,CAAC,CAAA,CAAE,CAAC,GAAG,MAAA;AAAA,YACrD,CAAC,YAAA,CAAa,SAAA,IAAa,EAAE,CAAC,GAAG,SAAA;AAAA,YACjC,CAAC,YAAA,CAAa,WAAW,CAAC,GAAG;AAAA,WAC/B;AAAA,UACA;AAAA,SACF;AAAA,QACA,IAAA;AAAA,QACC,GAAG,IAAA;AAAA,QACJ,GAAA;AAAA,QAEC;AAAA;AAAA,KACH;AAAA,EAEJ;AACF;;;;"}
@@ -3,7 +3,8 @@ import { useComponentCssInjection } from '@salt-ds/styles';
3
3
  import { useWindow } from '@salt-ds/window';
4
4
  import { clsx } from 'clsx';
5
5
  import { forwardRef, useRef } from 'react';
6
- import { ListControlContext } from '../list-control/ListControlContext.js';
6
+ import { isModifiedListControlNavigationKey, isListControlNavigationKey, getListControlNavigationTarget } from '../list-control/ListControlNavigationKeys.js';
7
+ import { ListControlProvider } from '../list-control/ListControlProvider.js';
7
8
  import { useListControl, defaultValueToString } from '../list-control/ListControlState.js';
8
9
  import { makePrefixer } from '../utils/makePrefixer.js';
9
10
  import '../utils/useFloatingUI/useFloatingUI.js';
@@ -73,10 +74,7 @@ const ListBox = forwardRef(function ListBox2(props, ref) {
73
74
  typeaheadTimeout.current = window.setTimeout(() => {
74
75
  typeaheadString.current = "";
75
76
  }, 500);
76
- let newOption = getOptionFromSearch(typeaheadString.current, activeState);
77
- if (!newOption) {
78
- newOption = getOptionFromSearch(typeaheadString.current);
79
- }
77
+ const newOption = getOptionFromSearch(typeaheadString.current, activeState);
80
78
  if (newOption) {
81
79
  setActive(newOption);
82
80
  setFocusVisibleState(true);
@@ -85,6 +83,9 @@ const ListBox = forwardRef(function ListBox2(props, ref) {
85
83
  const handleKeyDown = (event) => {
86
84
  var _a;
87
85
  onKeyDown == null ? void 0 : onKeyDown(event);
86
+ if (isModifiedListControlNavigationKey(event)) {
87
+ return;
88
+ }
88
89
  if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
89
90
  event.preventDefault();
90
91
  event.stopPropagation();
@@ -94,26 +95,19 @@ const ListBox = forwardRef(function ListBox2(props, ref) {
94
95
  if (activeOption === void 0) {
95
96
  return;
96
97
  }
97
- let newActive;
98
+ const isNavigationKey = isListControlNavigationKey(event.key);
99
+ if (isNavigationKey) {
100
+ event.preventDefault();
101
+ }
102
+ const newActive = isNavigationKey ? getListControlNavigationTarget(event.key, activeOption, {
103
+ getFirstOption,
104
+ getLastOption,
105
+ getOptionAfter,
106
+ getOptionBefore,
107
+ getOptionPageAbove,
108
+ getOptionPageBelow
109
+ }) : void 0;
98
110
  switch (event.key) {
99
- case "ArrowDown":
100
- newActive = getOptionAfter(activeOption) ?? getLastOption();
101
- break;
102
- case "ArrowUp":
103
- newActive = getOptionBefore(activeOption) ?? getFirstOption();
104
- break;
105
- case "Home":
106
- newActive = getFirstOption();
107
- break;
108
- case "End":
109
- newActive = getLastOption();
110
- break;
111
- case "PageUp":
112
- newActive = getOptionPageAbove(activeOption);
113
- break;
114
- case "PageDown":
115
- newActive = getOptionPageBelow(activeOption);
116
- break;
117
111
  case "Enter":
118
112
  case " ":
119
113
  if ((activeState == null ? void 0 : activeState.disabled) || typeaheadString.current.trim().length > 0 && event.key === " ") {
@@ -128,7 +122,6 @@ const ListBox = forwardRef(function ListBox2(props, ref) {
128
122
  break;
129
123
  }
130
124
  if (newActive && newActive.data.id !== (activeState == null ? void 0 : activeState.id)) {
131
- event.preventDefault();
132
125
  setActive(newActive.data);
133
126
  setFocusVisibleState(true);
134
127
  }
@@ -171,7 +164,7 @@ const ListBox = forwardRef(function ListBox2(props, ref) {
171
164
  setActive(void 0);
172
165
  };
173
166
  const handleRef = useForkRef(setListRef, ref);
174
- return /* @__PURE__ */ jsx(ListControlContext.Provider, { value: listControl, children: /* @__PURE__ */ jsx(
167
+ return /* @__PURE__ */ jsx(ListControlProvider, { value: listControl, children: /* @__PURE__ */ jsx(
175
168
  "div",
176
169
  {
177
170
  className: clsx(
@@ -1 +1 @@
1
- {"version":3,"file":"ListBox.js","sources":["../src/list-box/ListBox.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n type FocusEvent,\n type ForwardedRef,\n forwardRef,\n type KeyboardEvent,\n type ReactNode,\n type Ref,\n useRef,\n} from \"react\";\nimport {\n ListControlContext,\n type OptionValue,\n} from \"../list-control/ListControlContext\";\nimport {\n defaultValueToString,\n type ListControlProps,\n useListControl,\n} from \"../list-control/ListControlState\";\nimport { makePrefixer, useForkRef } from \"../utils\";\n\nimport listBoxCss from \"./ListBox.css\";\n\nexport type ListBoxProps<Item = string> = {\n /**\n * If `true`, the list box will be disabled.\n */\n disabled?: boolean;\n /**\n * If `false`, the list box will have not a border.\n */\n bordered?: boolean;\n /**\n * The options to display in the list box.\n */\n children?: ReactNode;\n /**\n * If `true`, the list box will be multiselect.\n */\n multiselect?: boolean;\n} & ComponentPropsWithoutRef<\"div\"> &\n Omit<ListControlProps<Item>, \"onOpenChange\">;\n\nconst withBaseName = makePrefixer(\"saltListBox\");\n\nexport const ListBox = forwardRef(function ListBox<Item>(\n props: ListBoxProps<Item>,\n ref: ForwardedRef<HTMLDivElement>,\n) {\n const {\n bordered,\n className,\n children,\n defaultSelected,\n disabled,\n selected,\n onSelectionChange,\n multiselect,\n valueToString = defaultValueToString,\n onKeyDown,\n onFocus,\n onBlur,\n ...rest\n } = props;\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-list-box\",\n css: listBoxCss,\n window: targetWindow,\n });\n\n const listControl = useListControl<Item>({\n multiselect,\n defaultSelected,\n selected,\n onSelectionChange,\n valueToString,\n disabled,\n });\n\n const {\n activeState,\n setActive,\n getOptionAtIndex,\n getIndexOfOption,\n getOptionsMatching,\n getOptionFromSearch,\n getFirstOption,\n getLastOption,\n getOptionAfter,\n getOptionBefore,\n getOptionPageAbove,\n getOptionPageBelow,\n selectedState,\n select,\n setFocusVisibleState,\n setFocusedState,\n setListRef,\n } = listControl;\n\n const typeaheadString = useRef(\"\");\n const typeaheadTimeout = useRef<number | undefined>();\n\n const handleTypeahead = (event: KeyboardEvent<HTMLDivElement>) => {\n if (typeaheadTimeout.current) {\n clearTimeout(typeaheadTimeout.current);\n }\n typeaheadString.current += event.key;\n typeaheadTimeout.current = window.setTimeout(() => {\n typeaheadString.current = \"\";\n }, 500);\n\n let newOption = getOptionFromSearch(typeaheadString.current, activeState);\n\n if (!newOption) {\n newOption = getOptionFromSearch(typeaheadString.current);\n }\n\n if (newOption) {\n setActive(newOption);\n setFocusVisibleState(true);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (\n event.key.length === 1 &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.altKey\n ) {\n event.preventDefault();\n event.stopPropagation();\n handleTypeahead(event);\n }\n\n const activeOption = activeState ?? getFirstOption()?.data;\n\n if (activeOption === undefined) {\n return;\n }\n\n let newActive:\n | { data: OptionValue<Item>; element: HTMLElement }\n | undefined;\n switch (event.key) {\n case \"ArrowDown\":\n newActive = getOptionAfter(activeOption) ?? getLastOption();\n break;\n case \"ArrowUp\":\n newActive = getOptionBefore(activeOption) ?? getFirstOption();\n break;\n case \"Home\":\n newActive = getFirstOption();\n break;\n case \"End\":\n newActive = getLastOption();\n break;\n case \"PageUp\":\n newActive = getOptionPageAbove(activeOption);\n break;\n case \"PageDown\":\n newActive = getOptionPageBelow(activeOption);\n break;\n case \"Enter\":\n case \" \":\n if (\n activeState?.disabled ||\n (typeaheadString.current.trim().length > 0 && event.key === \" \")\n ) {\n event.preventDefault();\n return;\n }\n\n if (!activeState) {\n return;\n }\n\n event.preventDefault();\n select(event, activeState);\n\n break;\n }\n\n if (newActive && newActive.data.id !== activeState?.id) {\n event.preventDefault();\n setActive(newActive.data);\n setFocusVisibleState(true);\n }\n };\n\n const wasMouseDown = useRef(false);\n\n const handleMouseDown = () => {\n wasMouseDown.current = true;\n };\n\n const handleFocus = (event: FocusEvent<HTMLDivElement>) => {\n if (wasMouseDown.current) {\n wasMouseDown.current = false;\n return;\n }\n\n setFocusVisibleState(true);\n wasMouseDown.current = false;\n\n // We check the active index because the active item may have been removed\n const activeIndex = activeState ? getIndexOfOption(activeState) : -1;\n let newActive: ReturnType<typeof getOptionAtIndex>;\n\n // If the active item is still in the list, we don't need to do anything\n if (activeIndex > 0) {\n return;\n }\n\n // If we have selected an item, we should make that the active item\n if (selectedState.length > 0) {\n newActive = getOptionsMatching(\n (option) => option.value === selectedState[0],\n ).pop();\n }\n\n // If we still don't have an active item, we should just select the first item\n if (!newActive) {\n newActive = getOptionAtIndex(0);\n }\n\n setActive(newActive?.data);\n setFocusedState(true);\n onFocus?.(event);\n };\n\n const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n setFocusedState(false);\n setActive(undefined);\n onBlur?.(event);\n };\n\n const handleListMouseOver = () => {\n setFocusVisibleState(false);\n setActive(undefined);\n };\n\n const handleRef = useForkRef(setListRef, ref);\n\n return (\n <ListControlContext.Provider value={listControl}>\n <div\n className={clsx(\n withBaseName(),\n { [withBaseName(\"bordered\")]: bordered },\n className,\n )}\n role=\"listbox\"\n aria-activedescendant={activeState?.id}\n aria-disabled={disabled || undefined}\n aria-multiselectable={multiselect}\n tabIndex={disabled ? -1 : 0}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onFocus={handleFocus}\n onMouseOver={handleListMouseOver}\n onMouseDown={handleMouseDown}\n ref={handleRef}\n {...rest}\n >\n {children}\n </div>\n </ListControlContext.Provider>\n );\n}) as <Item = string>(\n props: ListBoxProps<Item> & { ref?: Ref<HTMLDivElement> },\n) => JSX.Element;\n"],"names":["ListBox","listBoxCss"],"mappings":";;;;;;;;;;;;;;;AA8CA,MAAM,YAAA,GAAe,aAAa,aAAa,CAAA;AAExC,MAAM,OAAA,GAAU,UAAA,CAAW,SAASA,QAAAA,CACzC,OACA,GAAA,EACA;AACA,EAAA,MAAM;AAAA,IACJ,QAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,eAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,iBAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA,GAAgB,oBAAA;AAAA,IAChB,SAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,IACA,GAAG;AAAA,GACL,GAAI,KAAA;AACJ,EAAA,MAAM,eAAe,SAAA,EAAU;AAC/B,EAAA,wBAAA,CAAyB;AAAA,IACvB,MAAA,EAAQ,eAAA;AAAA,IACR,GAAA,EAAKC,QAAA;AAAA,IACL,MAAA,EAAQ;AAAA,GACT,CAAA;AAED,EAAA,MAAM,cAAc,cAAA,CAAqB;AAAA,IACvC,WAAA;AAAA,IACA,eAAA;AAAA,IACA,QAAA;AAAA,IACA,iBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM;AAAA,IACJ,WAAA;AAAA,IACA,SAAA;AAAA,IACA,gBAAA;AAAA,IACA,gBAAA;AAAA,IACA,kBAAA;AAAA,IACA,mBAAA;AAAA,IACA,cAAA;AAAA,IACA,aAAA;AAAA,IACA,cAAA;AAAA,IACA,eAAA;AAAA,IACA,kBAAA;AAAA,IACA,kBAAA;AAAA,IACA,aAAA;AAAA,IACA,MAAA;AAAA,IACA,oBAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF,GAAI,WAAA;AAEJ,EAAA,MAAM,eAAA,GAAkB,OAAO,EAAE,CAAA;AACjC,EAAA,MAAM,mBAAmB,MAAA,EAA2B;AAEpD,EAAA,MAAM,eAAA,GAAkB,CAAC,KAAA,KAAyC;AAChE,IAAA,IAAI,iBAAiB,OAAA,EAAS;AAC5B,MAAA,YAAA,CAAa,iBAAiB,OAAO,CAAA;AAAA,IACvC;AACA,IAAA,eAAA,CAAgB,WAAW,KAAA,CAAM,GAAA;AACjC,IAAA,gBAAA,CAAiB,OAAA,GAAU,MAAA,CAAO,UAAA,CAAW,MAAM;AACjD,MAAA,eAAA,CAAgB,OAAA,GAAU,EAAA;AAAA,IAC5B,GAAG,GAAG,CAAA;AAEN,IAAA,IAAI,SAAA,GAAY,mBAAA,CAAoB,eAAA,CAAgB,OAAA,EAAS,WAAW,CAAA;AAExE,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,SAAA,GAAY,mBAAA,CAAoB,gBAAgB,OAAO,CAAA;AAAA,IACzD;AAEA,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,SAAA,CAAU,SAAS,CAAA;AACnB,MAAA,oBAAA,CAAqB,IAAI,CAAA;AAAA,IAC3B;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAyC;AA/HlE,IAAA,IAAA,EAAA;AAgII,IAAA,SAAA,IAAA,IAAA,GAAA,MAAA,GAAA,SAAA,CAAY,KAAA,CAAA;AAEZ,IAAA,IACE,KAAA,CAAM,GAAA,CAAI,MAAA,KAAW,CAAA,IACrB,CAAC,KAAA,CAAM,OAAA,IACP,CAAC,KAAA,CAAM,OAAA,IACP,CAAC,KAAA,CAAM,MAAA,EACP;AACA,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,KAAA,CAAM,eAAA,EAAgB;AACtB,MAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,IACvB;AAEA,IAAA,MAAM,YAAA,GAAe,WAAA,KAAA,CAAe,EAAA,GAAA,cAAA,EAAe,KAAf,IAAA,GAAA,MAAA,GAAA,EAAA,CAAkB,IAAA,CAAA;AAEtD,IAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,SAAA;AAGJ,IAAA,QAAQ,MAAM,GAAA;AAAK,MACjB,KAAK,WAAA;AACH,QAAA,SAAA,GAAY,cAAA,CAAe,YAAY,CAAA,IAAK,aAAA,EAAc;AAC1D,QAAA;AAAA,MACF,KAAK,SAAA;AACH,QAAA,SAAA,GAAY,eAAA,CAAgB,YAAY,CAAA,IAAK,cAAA,EAAe;AAC5D,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,SAAA,GAAY,cAAA,EAAe;AAC3B,QAAA;AAAA,MACF,KAAK,KAAA;AACH,QAAA,SAAA,GAAY,aAAA,EAAc;AAC1B,QAAA;AAAA,MACF,KAAK,QAAA;AACH,QAAA,SAAA,GAAY,mBAAmB,YAAY,CAAA;AAC3C,QAAA;AAAA,MACF,KAAK,UAAA;AACH,QAAA,SAAA,GAAY,mBAAmB,YAAY,CAAA;AAC3C,QAAA;AAAA,MACF,KAAK,OAAA;AAAA,MACL,KAAK,GAAA;AACH,QAAA,IAAA,CACE,WAAA,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,CAAa,QAAA,KACZ,eAAA,CAAgB,OAAA,CAAQ,IAAA,GAAO,MAAA,GAAS,CAAA,IAAK,KAAA,CAAM,GAAA,KAAQ,GAAA,EAC5D;AACA,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA;AAAA,QACF;AAEA,QAAA,IAAI,CAAC,WAAA,EAAa;AAChB,UAAA;AAAA,QACF;AAEA,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,MAAA,CAAO,OAAO,WAAW,CAAA;AAEzB,QAAA;AAAA;AAGJ,IAAA,IAAI,SAAA,IAAa,SAAA,CAAU,IAAA,CAAK,EAAA,MAAO,2CAAa,EAAA,CAAA,EAAI;AACtD,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,SAAA,CAAU,UAAU,IAAI,CAAA;AACxB,MAAA,oBAAA,CAAqB,IAAI,CAAA;AAAA,IAC3B;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,OAAO,KAAK,CAAA;AAEjC,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,YAAA,CAAa,OAAA,GAAU,IAAA;AAAA,EACzB,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,KAAA,KAAsC;AACzD,IAAA,IAAI,aAAa,OAAA,EAAS;AACxB,MAAA,YAAA,CAAa,OAAA,GAAU,KAAA;AACvB,MAAA;AAAA,IACF;AAEA,IAAA,oBAAA,CAAqB,IAAI,CAAA;AACzB,IAAA,YAAA,CAAa,OAAA,GAAU,KAAA;AAGvB,IAAA,MAAM,WAAA,GAAc,WAAA,GAAc,gBAAA,CAAiB,WAAW,CAAA,GAAI,EAAA;AAClE,IAAA,IAAI,SAAA;AAGJ,IAAA,IAAI,cAAc,CAAA,EAAG;AACnB,MAAA;AAAA,IACF;AAGA,IAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC5B,MAAA,SAAA,GAAY,kBAAA;AAAA,QACV,CAAC,MAAA,KAAW,MAAA,CAAO,KAAA,KAAU,cAAc,CAAC;AAAA,QAC5C,GAAA,EAAI;AAAA,IACR;AAGA,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,SAAA,GAAY,iBAAiB,CAAC,CAAA;AAAA,IAChC;AAEA,IAAA,SAAA,CAAU,uCAAW,IAAI,CAAA;AACzB,IAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,IAAA,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAU,KAAA,CAAA;AAAA,EACZ,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,CAAC,KAAA,KAAsC;AACxD,IAAA,eAAA,CAAgB,KAAK,CAAA;AACrB,IAAA,SAAA,CAAU,MAAS,CAAA;AACnB,IAAA,MAAA,IAAA,IAAA,GAAA,MAAA,GAAA,MAAA,CAAS,KAAA,CAAA;AAAA,EACX,CAAA;AAEA,EAAA,MAAM,sBAAsB,MAAM;AAChC,IAAA,oBAAA,CAAqB,KAAK,CAAA;AAC1B,IAAA,SAAA,CAAU,MAAS,CAAA;AAAA,EACrB,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,UAAA,CAAW,UAAA,EAAY,GAAG,CAAA;AAE5C,EAAA,uBACE,GAAA,CAAC,kBAAA,CAAmB,QAAA,EAAnB,EAA4B,OAAO,WAAA,EAClC,QAAA,kBAAA,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,IAAA;AAAA,QACT,YAAA,EAAa;AAAA,QACb,EAAE,CAAC,YAAA,CAAa,UAAU,CAAC,GAAG,QAAA,EAAS;AAAA,QACvC;AAAA,OACF;AAAA,MACA,IAAA,EAAK,SAAA;AAAA,MACL,yBAAuB,WAAA,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,CAAa,EAAA;AAAA,MACpC,iBAAe,QAAA,IAAY,MAAA;AAAA,MAC3B,sBAAA,EAAsB,WAAA;AAAA,MACtB,QAAA,EAAU,WAAW,EAAA,GAAK,CAAA;AAAA,MAC1B,SAAA,EAAW,aAAA;AAAA,MACX,MAAA,EAAQ,UAAA;AAAA,MACR,OAAA,EAAS,WAAA;AAAA,MACT,WAAA,EAAa,mBAAA;AAAA,MACb,WAAA,EAAa,eAAA;AAAA,MACb,GAAA,EAAK,SAAA;AAAA,MACJ,GAAG,IAAA;AAAA,MAEH;AAAA;AAAA,GACH,EACF,CAAA;AAEJ,CAAC;;;;"}
1
+ {"version":3,"file":"ListBox.js","sources":["../src/list-box/ListBox.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n type FocusEvent,\n type ForwardedRef,\n forwardRef,\n type KeyboardEvent,\n type ReactNode,\n type Ref,\n useRef,\n} from \"react\";\nimport {\n getListControlNavigationTarget,\n isListControlNavigationKey,\n isModifiedListControlNavigationKey,\n type OptionAndElement,\n} from \"../list-control/ListControlNavigationKeys\";\nimport { ListControlProvider } from \"../list-control/ListControlProvider\";\nimport {\n defaultValueToString,\n type ListControlProps,\n useListControl,\n} from \"../list-control/ListControlState\";\nimport { makePrefixer, useForkRef } from \"../utils\";\n\nimport listBoxCss from \"./ListBox.css\";\n\nexport type ListBoxProps<Item = string> = {\n /**\n * If `true`, the list box will be disabled.\n */\n disabled?: boolean;\n /**\n * If `false`, the list box will have not a border.\n */\n bordered?: boolean;\n /**\n * The options to display in the list box.\n */\n children?: ReactNode;\n /**\n * If `true`, the list box will be multiselect.\n */\n multiselect?: boolean;\n} & ComponentPropsWithoutRef<\"div\"> &\n Omit<ListControlProps<Item>, \"onOpenChange\">;\n\nconst withBaseName = makePrefixer(\"saltListBox\");\n\nexport const ListBox = forwardRef(function ListBox<Item>(\n props: ListBoxProps<Item>,\n ref: ForwardedRef<HTMLDivElement>,\n) {\n const {\n bordered,\n className,\n children,\n defaultSelected,\n disabled,\n selected,\n onSelectionChange,\n multiselect,\n valueToString = defaultValueToString,\n onKeyDown,\n onFocus,\n onBlur,\n ...rest\n } = props;\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-list-box\",\n css: listBoxCss,\n window: targetWindow,\n });\n\n const listControl = useListControl<Item>({\n multiselect,\n defaultSelected,\n selected,\n onSelectionChange,\n valueToString,\n disabled,\n });\n\n const {\n activeState,\n setActive,\n getOptionAtIndex,\n getIndexOfOption,\n getOptionsMatching,\n getOptionFromSearch,\n getFirstOption,\n getLastOption,\n getOptionAfter,\n getOptionBefore,\n getOptionPageAbove,\n getOptionPageBelow,\n selectedState,\n select,\n setFocusVisibleState,\n setFocusedState,\n setListRef,\n } = listControl;\n\n const typeaheadString = useRef(\"\");\n const typeaheadTimeout = useRef<number | undefined>();\n\n const handleTypeahead = (event: KeyboardEvent<HTMLDivElement>) => {\n if (typeaheadTimeout.current) {\n clearTimeout(typeaheadTimeout.current);\n }\n typeaheadString.current += event.key;\n typeaheadTimeout.current = window.setTimeout(() => {\n typeaheadString.current = \"\";\n }, 500);\n\n const newOption = getOptionFromSearch(typeaheadString.current, activeState);\n\n if (newOption) {\n setActive(newOption);\n setFocusVisibleState(true);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (isModifiedListControlNavigationKey(event)) {\n return;\n }\n\n if (\n event.key.length === 1 &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.altKey\n ) {\n event.preventDefault();\n event.stopPropagation();\n handleTypeahead(event);\n }\n\n const activeOption = activeState ?? getFirstOption()?.data;\n\n if (activeOption === undefined) {\n return;\n }\n\n const isNavigationKey = isListControlNavigationKey(event.key);\n if (isNavigationKey) {\n event.preventDefault();\n }\n\n const newActive: OptionAndElement<Item> | undefined = isNavigationKey\n ? getListControlNavigationTarget(event.key, activeOption, {\n getFirstOption,\n getLastOption,\n getOptionAfter,\n getOptionBefore,\n getOptionPageAbove,\n getOptionPageBelow,\n })\n : undefined;\n\n switch (event.key) {\n case \"Enter\":\n case \" \":\n if (\n activeState?.disabled ||\n (typeaheadString.current.trim().length > 0 && event.key === \" \")\n ) {\n event.preventDefault();\n return;\n }\n\n if (!activeState) {\n return;\n }\n\n event.preventDefault();\n select(event, activeState);\n\n break;\n }\n\n if (newActive && newActive.data.id !== activeState?.id) {\n setActive(newActive.data);\n setFocusVisibleState(true);\n }\n };\n\n const wasMouseDown = useRef(false);\n\n const handleMouseDown = () => {\n wasMouseDown.current = true;\n };\n\n const handleFocus = (event: FocusEvent<HTMLDivElement>) => {\n if (wasMouseDown.current) {\n wasMouseDown.current = false;\n return;\n }\n\n setFocusVisibleState(true);\n wasMouseDown.current = false;\n\n // We check the active index because the active item may have been removed\n const activeIndex = activeState ? getIndexOfOption(activeState) : -1;\n let newActive: ReturnType<typeof getOptionAtIndex>;\n\n // If the active item is still in the list, we don't need to do anything\n if (activeIndex > 0) {\n return;\n }\n\n // If we have selected an item, we should make that the active item\n if (selectedState.length > 0) {\n newActive = getOptionsMatching(\n (option) => option.value === selectedState[0],\n ).pop();\n }\n\n // If we still don't have an active item, we should just select the first item\n if (!newActive) {\n newActive = getOptionAtIndex(0);\n }\n\n setActive(newActive?.data);\n setFocusedState(true);\n onFocus?.(event);\n };\n\n const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n setFocusedState(false);\n setActive(undefined);\n onBlur?.(event);\n };\n\n const handleListMouseOver = () => {\n setFocusVisibleState(false);\n setActive(undefined);\n };\n\n const handleRef = useForkRef(setListRef, ref);\n\n return (\n <ListControlProvider value={listControl}>\n <div\n className={clsx(\n withBaseName(),\n { [withBaseName(\"bordered\")]: bordered },\n className,\n )}\n role=\"listbox\"\n aria-activedescendant={activeState?.id}\n aria-disabled={disabled || undefined}\n aria-multiselectable={multiselect}\n tabIndex={disabled ? -1 : 0}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onFocus={handleFocus}\n onMouseOver={handleListMouseOver}\n onMouseDown={handleMouseDown}\n ref={handleRef}\n {...rest}\n >\n {children}\n </div>\n </ListControlProvider>\n );\n}) as <Item = string>(\n props: ListBoxProps<Item> & { ref?: Ref<HTMLDivElement> },\n) => JSX.Element;\n"],"names":["ListBox","listBoxCss"],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ const LIST_CONTROL_NAVIGATION_KEYS = /* @__PURE__ */ new Set([
2
+ "ArrowDown",
3
+ "ArrowUp",
4
+ "Home",
5
+ "End",
6
+ "PageUp",
7
+ "PageDown"
8
+ ]);
9
+ function isListControlNavigationKey(key) {
10
+ return LIST_CONTROL_NAVIGATION_KEYS.has(key);
11
+ }
12
+ function isModifiedListControlNavigationKey(event) {
13
+ if (!isListControlNavigationKey(event.key)) {
14
+ return false;
15
+ }
16
+ if (event.ctrlKey || event.metaKey) {
17
+ return true;
18
+ }
19
+ return event.altKey && event.key !== "ArrowUp" && event.key !== "ArrowDown";
20
+ }
21
+ function getListControlNavigationTarget(key, activeOption, getters) {
22
+ switch (key) {
23
+ case "ArrowDown":
24
+ return getters.getOptionAfter(activeOption) ?? getters.getLastOption();
25
+ case "ArrowUp":
26
+ return getters.getOptionBefore(activeOption) ?? getters.getFirstOption();
27
+ case "Home":
28
+ return getters.getFirstOption();
29
+ case "End":
30
+ return getters.getLastOption();
31
+ case "PageUp":
32
+ return getters.getOptionPageAbove(activeOption);
33
+ case "PageDown":
34
+ return getters.getOptionPageBelow(activeOption);
35
+ default:
36
+ return void 0;
37
+ }
38
+ }
39
+ function getComboBoxNavigationTarget(key, activeOption, getters) {
40
+ switch (key) {
41
+ case "ArrowDown":
42
+ return activeOption ? getters.getOptionAfter(activeOption) : getters.getFirstOption();
43
+ case "ArrowUp":
44
+ return activeOption ? getters.getOptionBefore(activeOption) : getters.getLastOption();
45
+ case "Home":
46
+ return getters.getFirstOption();
47
+ case "End":
48
+ return getters.getLastOption();
49
+ case "PageUp": {
50
+ if (activeOption) {
51
+ return getters.getOptionPageAbove(activeOption);
52
+ }
53
+ const lastOption = getters.getLastOption();
54
+ return lastOption ? getters.getOptionPageAbove(lastOption.data) : void 0;
55
+ }
56
+ case "PageDown": {
57
+ if (activeOption) {
58
+ return getters.getOptionPageBelow(activeOption);
59
+ }
60
+ const firstOption = getters.getFirstOption();
61
+ return firstOption ? getters.getOptionPageBelow(firstOption.data) : void 0;
62
+ }
63
+ default:
64
+ return void 0;
65
+ }
66
+ }
67
+
68
+ export { getComboBoxNavigationTarget, getListControlNavigationTarget, isListControlNavigationKey, isModifiedListControlNavigationKey };
69
+ //# sourceMappingURL=ListControlNavigationKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListControlNavigationKeys.js","sources":["../src/list-control/ListControlNavigationKeys.ts"],"sourcesContent":["import type { OptionValue } from \"./ListControlContext\";\n\n/**\n * Keys that move between options while the list is shown. When no list is\n * shown, Dropdown and ComboBox pass the keys they don't use to open the list\n * to the browser.\n */\nconst LIST_CONTROL_NAVIGATION_KEYS: ReadonlySet<string> = new Set([\n \"ArrowDown\",\n \"ArrowUp\",\n \"Home\",\n \"End\",\n \"PageUp\",\n \"PageDown\",\n]);\n\nexport function isListControlNavigationKey(key: string): boolean {\n return LIST_CONTROL_NAVIGATION_KEYS.has(key);\n}\n\n/**\n * Navigation keys pressed with Ctrl or Meta (e.g. Ctrl+End, Cmd+ArrowDown,\n * Ctrl+PageDown) are browser or OS shortcuts, so list controls leave them to\n * the browser. Alt is only used with ArrowUp and ArrowDown, as in the ARIA\n * combobox pattern.\n */\nexport function isModifiedListControlNavigationKey(event: {\n key: string;\n altKey: boolean;\n ctrlKey: boolean;\n metaKey: boolean;\n}): boolean {\n if (!isListControlNavigationKey(event.key)) {\n return false;\n }\n if (event.ctrlKey || event.metaKey) {\n return true;\n }\n return event.altKey && event.key !== \"ArrowUp\" && event.key !== \"ArrowDown\";\n}\n\nexport interface OptionAndElement<Item> {\n data: OptionValue<Item>;\n element: HTMLElement;\n}\n\nexport interface ListControlNavigationGetters<Item> {\n getFirstOption: () => OptionAndElement<Item> | undefined;\n getLastOption: () => OptionAndElement<Item> | undefined;\n getOptionAfter: (\n option: OptionValue<Item>,\n ) => OptionAndElement<Item> | undefined;\n getOptionBefore: (\n option: OptionValue<Item>,\n ) => OptionAndElement<Item> | undefined;\n getOptionPageAbove: (\n option: OptionValue<Item>,\n ) => OptionAndElement<Item> | undefined;\n getOptionPageBelow: (\n option: OptionValue<Item>,\n ) => OptionAndElement<Item> | undefined;\n}\n\n/** Shared by Dropdown and ListBox, which always have an active option. */\nexport function getListControlNavigationTarget<Item>(\n key: string,\n activeOption: OptionValue<Item>,\n getters: ListControlNavigationGetters<Item>,\n): OptionAndElement<Item> | undefined {\n switch (key) {\n case \"ArrowDown\":\n return getters.getOptionAfter(activeOption) ?? getters.getLastOption();\n case \"ArrowUp\":\n return getters.getOptionBefore(activeOption) ?? getters.getFirstOption();\n case \"Home\":\n return getters.getFirstOption();\n case \"End\":\n return getters.getLastOption();\n case \"PageUp\":\n return getters.getOptionPageAbove(activeOption);\n case \"PageDown\":\n return getters.getOptionPageBelow(activeOption);\n default:\n return undefined;\n }\n}\n\n/** For ComboBox, where the active option may be undefined. */\nexport function getComboBoxNavigationTarget<Item>(\n key: string,\n activeOption: OptionValue<Item> | undefined,\n getters: ListControlNavigationGetters<Item>,\n): OptionAndElement<Item> | undefined {\n switch (key) {\n case \"ArrowDown\":\n return activeOption\n ? getters.getOptionAfter(activeOption)\n : getters.getFirstOption();\n case \"ArrowUp\":\n return activeOption\n ? getters.getOptionBefore(activeOption)\n : getters.getLastOption();\n case \"Home\":\n return getters.getFirstOption();\n case \"End\":\n return getters.getLastOption();\n case \"PageUp\": {\n if (activeOption) {\n return getters.getOptionPageAbove(activeOption);\n }\n const lastOption = getters.getLastOption();\n return lastOption\n ? getters.getOptionPageAbove(lastOption.data)\n : undefined;\n }\n case \"PageDown\": {\n if (activeOption) {\n return getters.getOptionPageBelow(activeOption);\n }\n const firstOption = getters.getFirstOption();\n return firstOption\n ? getters.getOptionPageBelow(firstOption.data)\n : undefined;\n }\n default:\n return undefined;\n }\n}\n"],"names":[],"mappings":"AAOA,MAAM,4BAAA,uBAAwD,GAAA,CAAI;AAAA,EAChE,WAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAC,CAAA;AAEM,SAAS,2BAA2B,GAAA,EAAsB;AAC/D,EAAA,OAAO,4BAAA,CAA6B,IAAI,GAAG,CAAA;AAC7C;AAQO,SAAS,mCAAmC,KAAA,EAKvC;AACV,EAAA,IAAI,CAAC,0BAAA,CAA2B,KAAA,CAAM,GAAG,CAAA,EAAG;AAC1C,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,IAAI,KAAA,CAAM,OAAA,IAAW,KAAA,CAAM,OAAA,EAAS;AAClC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAM,MAAA,IAAU,KAAA,CAAM,GAAA,KAAQ,SAAA,IAAa,MAAM,GAAA,KAAQ,WAAA;AAClE;AAyBO,SAAS,8BAAA,CACd,GAAA,EACA,YAAA,EACA,OAAA,EACoC;AACpC,EAAA,QAAQ,GAAA;AAAK,IACX,KAAK,WAAA;AACH,MAAA,OAAO,OAAA,CAAQ,cAAA,CAAe,YAAY,CAAA,IAAK,QAAQ,aAAA,EAAc;AAAA,IACvE,KAAK,SAAA;AACH,MAAA,OAAO,OAAA,CAAQ,eAAA,CAAgB,YAAY,CAAA,IAAK,QAAQ,cAAA,EAAe;AAAA,IACzE,KAAK,MAAA;AACH,MAAA,OAAO,QAAQ,cAAA,EAAe;AAAA,IAChC,KAAK,KAAA;AACH,MAAA,OAAO,QAAQ,aAAA,EAAc;AAAA,IAC/B,KAAK,QAAA;AACH,MAAA,OAAO,OAAA,CAAQ,mBAAmB,YAAY,CAAA;AAAA,IAChD,KAAK,UAAA;AACH,MAAA,OAAO,OAAA,CAAQ,mBAAmB,YAAY,CAAA;AAAA,IAChD;AACE,MAAA,OAAO,MAAA;AAAA;AAEb;AAGO,SAAS,2BAAA,CACd,GAAA,EACA,YAAA,EACA,OAAA,EACoC;AACpC,EAAA,QAAQ,GAAA;AAAK,IACX,KAAK,WAAA;AACH,MAAA,OAAO,eACH,OAAA,CAAQ,cAAA,CAAe,YAAY,CAAA,GACnC,QAAQ,cAAA,EAAe;AAAA,IAC7B,KAAK,SAAA;AACH,MAAA,OAAO,eACH,OAAA,CAAQ,eAAA,CAAgB,YAAY,CAAA,GACpC,QAAQ,aAAA,EAAc;AAAA,IAC5B,KAAK,MAAA;AACH,MAAA,OAAO,QAAQ,cAAA,EAAe;AAAA,IAChC,KAAK,KAAA;AACH,MAAA,OAAO,QAAQ,aAAA,EAAc;AAAA,IAC/B,KAAK,QAAA,EAAU;AACb,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,OAAO,OAAA,CAAQ,mBAAmB,YAAY,CAAA;AAAA,MAChD;AACA,MAAA,MAAM,UAAA,GAAa,QAAQ,aAAA,EAAc;AACzC,MAAA,OAAO,UAAA,GACH,OAAA,CAAQ,kBAAA,CAAmB,UAAA,CAAW,IAAI,CAAA,GAC1C,MAAA;AAAA,IACN;AAAA,IACA,KAAK,UAAA,EAAY;AACf,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,OAAO,OAAA,CAAQ,mBAAmB,YAAY,CAAA;AAAA,MAChD;AACA,MAAA,MAAM,WAAA,GAAc,QAAQ,cAAA,EAAe;AAC3C,MAAA,OAAO,WAAA,GACH,OAAA,CAAQ,kBAAA,CAAmB,WAAA,CAAY,IAAI,CAAA,GAC3C,MAAA;AAAA,IACN;AAAA,IACA;AACE,MAAA,OAAO,MAAA;AAAA;AAEb;;;;"}
@@ -0,0 +1,44 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useContext } from 'react';
3
+ import { createContext } from '../utils/createContext.js';
4
+ import 'clsx';
5
+ import '../utils/useFloatingUI/useFloatingUI.js';
6
+ import '../utils/useId.js';
7
+ import '../salt-provider/SaltProvider.js';
8
+ import '../viewport/ViewportProvider.js';
9
+ import { ListControlOptionStore } from './ListControlOptionStore.js';
10
+
11
+ const fallbackOptionStateStore = new ListControlOptionStore();
12
+ const defaultListControlOptionContext = {
13
+ disabled: false,
14
+ listRef: void 0,
15
+ multiselect: false,
16
+ optionStateStore: fallbackOptionStateStore,
17
+ register: () => () => void 0,
18
+ select: () => void 0,
19
+ setActive: () => void 0,
20
+ valueToString: (item) => String(item)
21
+ };
22
+ const ListControlOptionContext = createContext(
23
+ "ListControlOptionContext",
24
+ defaultListControlOptionContext
25
+ );
26
+ function ListControlOptionContextProvider({
27
+ children,
28
+ value
29
+ }) {
30
+ return /* @__PURE__ */ jsx(
31
+ ListControlOptionContext.Provider,
32
+ {
33
+ value,
34
+ children
35
+ }
36
+ );
37
+ }
38
+ function useListControlOptionContext() {
39
+ const context = useContext(ListControlOptionContext);
40
+ return context;
41
+ }
42
+
43
+ export { ListControlOptionContextProvider, useListControlOptionContext };
44
+ //# sourceMappingURL=ListControlOptionContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListControlOptionContext.js","sources":["../src/list-control/ListControlOptionContext.tsx"],"sourcesContent":["import {\n type ReactNode,\n type RefObject,\n type SyntheticEvent,\n useContext,\n} from \"react\";\nimport { createContext } from \"../utils\";\nimport type { OptionValue } from \"./ListControlContext\";\nimport { ListControlOptionStore } from \"./ListControlOptionStore\";\n\nexport interface ListControlOptionContextValue<Item> {\n disabled?: boolean;\n listRef?: RefObject<HTMLDivElement>;\n multiselect: boolean;\n optionStateStore: ListControlOptionStore<Item>;\n register: (\n optionValue: OptionValue<Item>,\n element: HTMLElement,\n ) => () => void;\n select: (event: SyntheticEvent, option: OptionValue<Item>) => void;\n setActive: (option: OptionValue<Item>) => void;\n valueToString: (item: Item) => string;\n}\n\nconst fallbackOptionStateStore = new ListControlOptionStore<unknown>();\n\nconst defaultListControlOptionContext: ListControlOptionContextValue<unknown> =\n {\n disabled: false,\n listRef: undefined,\n multiselect: false,\n optionStateStore: fallbackOptionStateStore,\n register: () => () => undefined,\n select: () => undefined,\n setActive: () => undefined,\n valueToString: (item) => String(item),\n };\n\nconst ListControlOptionContext = createContext(\n \"ListControlOptionContext\",\n defaultListControlOptionContext,\n);\n\nexport function ListControlOptionContextProvider<Item>({\n children,\n value,\n}: {\n children: ReactNode;\n value: ListControlOptionContextValue<Item>;\n}) {\n return (\n <ListControlOptionContext.Provider\n value={value as unknown as ListControlOptionContextValue<unknown>}\n >\n {children}\n </ListControlOptionContext.Provider>\n );\n}\n\nexport function useListControlOptionContext<Item>() {\n const context = useContext(ListControlOptionContext);\n return context as unknown as ListControlOptionContextValue<Item>;\n}\n"],"names":[],"mappings":";;;;;;;;;;AAwBA,MAAM,wBAAA,GAA2B,IAAI,sBAAA,EAAgC;AAErE,MAAM,+BAAA,GACJ;AAAA,EACE,QAAA,EAAU,KAAA;AAAA,EACV,OAAA,EAAS,MAAA;AAAA,EACT,WAAA,EAAa,KAAA;AAAA,EACb,gBAAA,EAAkB,wBAAA;AAAA,EAClB,QAAA,EAAU,MAAM,MAAM,MAAA;AAAA,EACtB,QAAQ,MAAM,MAAA;AAAA,EACd,WAAW,MAAM,MAAA;AAAA,EACjB,aAAA,EAAe,CAAC,IAAA,KAAS,MAAA,CAAO,IAAI;AACtC,CAAA;AAEF,MAAM,wBAAA,GAA2B,aAAA;AAAA,EAC/B,0BAAA;AAAA,EACA;AACF,CAAA;AAEO,SAAS,gCAAA,CAAuC;AAAA,EACrD,QAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,uBACE,GAAA;AAAA,IAAC,wBAAA,CAAyB,QAAA;AAAA,IAAzB;AAAA,MACC,KAAA;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ;AAEO,SAAS,2BAAA,GAAoC;AAClD,EAAA,MAAM,OAAA,GAAU,WAAW,wBAAwB,CAAA;AACnD,EAAA,OAAO,OAAA;AACT;;;;"}
@@ -0,0 +1,153 @@
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 __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
9
+ var __privateWrapper = (obj, member, setter, getter) => ({
10
+ set _(value) {
11
+ __privateSet(obj, member, value);
12
+ },
13
+ get _() {
14
+ return __privateGet(obj, member, getter);
15
+ }
16
+ });
17
+ var _listeners, _options, _optionIdsByValue, _activeId, _focusVisible, _nextGeneration, _selected, _ListControlOptionStore_instances, notify_fn, deleteValueId_fn;
18
+ const OPTION_STATE_ACTIVE = 1;
19
+ const OPTION_STATE_SELECTED = 2;
20
+ const OPTION_STATE_FOCUS_VISIBLE = 4;
21
+ function hasOptionState(snapshot, state) {
22
+ return (snapshot & state) !== 0;
23
+ }
24
+ class ListControlOptionStore {
25
+ constructor(selected = []) {
26
+ __privateAdd(this, _ListControlOptionStore_instances);
27
+ __privateAdd(this, _listeners, /* @__PURE__ */ new Map());
28
+ __privateAdd(this, _options, /* @__PURE__ */ new Map());
29
+ __privateAdd(this, _optionIdsByValue, /* @__PURE__ */ new Map());
30
+ __privateAdd(this, _activeId);
31
+ __privateAdd(this, _focusVisible, false);
32
+ __privateAdd(this, _nextGeneration, 0);
33
+ __privateAdd(this, _selected);
34
+ __privateSet(this, _selected, new Set(selected));
35
+ }
36
+ subscribe(id, listener) {
37
+ let listeners = __privateGet(this, _listeners).get(id);
38
+ if (!listeners) {
39
+ listeners = /* @__PURE__ */ new Set();
40
+ __privateGet(this, _listeners).set(id, listeners);
41
+ }
42
+ listeners.add(listener);
43
+ return () => {
44
+ const currentListeners = __privateGet(this, _listeners).get(id);
45
+ currentListeners == null ? void 0 : currentListeners.delete(listener);
46
+ if ((currentListeners == null ? void 0 : currentListeners.size) === 0) {
47
+ __privateGet(this, _listeners).delete(id);
48
+ }
49
+ };
50
+ }
51
+ register(option) {
52
+ const previousEntry = __privateGet(this, _options).get(option.id);
53
+ const previousSnapshot = this.getSnapshot(option.id);
54
+ if (previousEntry) {
55
+ __privateMethod(this, _ListControlOptionStore_instances, deleteValueId_fn).call(this, previousEntry.option.value, option.id);
56
+ }
57
+ const entry = {
58
+ generation: __privateWrapper(this, _nextGeneration)._++,
59
+ option
60
+ };
61
+ __privateGet(this, _options).set(option.id, entry);
62
+ const valueIds = __privateGet(this, _optionIdsByValue).get(option.value);
63
+ if (valueIds === void 0) {
64
+ __privateGet(this, _optionIdsByValue).set(option.value, option.id);
65
+ } else if (typeof valueIds === "string") {
66
+ __privateGet(this, _optionIdsByValue).set(option.value, /* @__PURE__ */ new Set([valueIds, option.id]));
67
+ } else {
68
+ valueIds.add(option.id);
69
+ }
70
+ if (previousEntry !== void 0 || previousSnapshot !== this.getSnapshot(option.id)) {
71
+ __privateMethod(this, _ListControlOptionStore_instances, notify_fn).call(this, option.id);
72
+ }
73
+ return () => {
74
+ const current = __privateGet(this, _options).get(option.id);
75
+ if ((current == null ? void 0 : current.generation) !== entry.generation) return;
76
+ const previousSnapshot2 = this.getSnapshot(option.id);
77
+ __privateGet(this, _options).delete(option.id);
78
+ __privateMethod(this, _ListControlOptionStore_instances, deleteValueId_fn).call(this, option.value, option.id);
79
+ if (previousSnapshot2 !== 0) __privateMethod(this, _ListControlOptionStore_instances, notify_fn).call(this, option.id);
80
+ };
81
+ }
82
+ getSnapshot(id, currentOption) {
83
+ var _a;
84
+ const option = currentOption ?? ((_a = __privateGet(this, _options).get(id)) == null ? void 0 : _a.option);
85
+ if (!option) return 0;
86
+ let snapshot = 0;
87
+ if (id === __privateGet(this, _activeId)) {
88
+ snapshot |= OPTION_STATE_ACTIVE;
89
+ if (__privateGet(this, _focusVisible)) snapshot |= OPTION_STATE_FOCUS_VISIBLE;
90
+ }
91
+ if (__privateGet(this, _selected).has(option.value)) {
92
+ snapshot |= OPTION_STATE_SELECTED;
93
+ }
94
+ return snapshot;
95
+ }
96
+ setActiveId(id) {
97
+ if (id === __privateGet(this, _activeId)) return;
98
+ const previousId = __privateGet(this, _activeId);
99
+ __privateSet(this, _activeId, id);
100
+ if (previousId !== void 0) __privateMethod(this, _ListControlOptionStore_instances, notify_fn).call(this, previousId);
101
+ if (id !== void 0) __privateMethod(this, _ListControlOptionStore_instances, notify_fn).call(this, id);
102
+ }
103
+ setFocusVisible(focusVisible) {
104
+ if (focusVisible === __privateGet(this, _focusVisible)) return;
105
+ __privateSet(this, _focusVisible, focusVisible);
106
+ if (__privateGet(this, _activeId) !== void 0) __privateMethod(this, _ListControlOptionStore_instances, notify_fn).call(this, __privateGet(this, _activeId));
107
+ }
108
+ setSelected(selected) {
109
+ const previous = __privateGet(this, _selected);
110
+ const nextSelected = new Set(selected);
111
+ __privateSet(this, _selected, nextSelected);
112
+ const candidateValues = /* @__PURE__ */ new Set([...previous, ...nextSelected]);
113
+ for (const value of candidateValues) {
114
+ if (previous.has(value) !== nextSelected.has(value)) {
115
+ const ids = __privateGet(this, _optionIdsByValue).get(value);
116
+ if (typeof ids === "string") {
117
+ __privateMethod(this, _ListControlOptionStore_instances, notify_fn).call(this, ids);
118
+ } else if (ids !== void 0) {
119
+ for (const id of ids) __privateMethod(this, _ListControlOptionStore_instances, notify_fn).call(this, id);
120
+ }
121
+ }
122
+ }
123
+ }
124
+ }
125
+ _listeners = new WeakMap();
126
+ _options = new WeakMap();
127
+ _optionIdsByValue = new WeakMap();
128
+ _activeId = new WeakMap();
129
+ _focusVisible = new WeakMap();
130
+ _nextGeneration = new WeakMap();
131
+ _selected = new WeakMap();
132
+ _ListControlOptionStore_instances = new WeakSet();
133
+ notify_fn = function(id) {
134
+ const listeners = __privateGet(this, _listeners).get(id);
135
+ if (!listeners) return;
136
+ for (const listener of [...listeners]) listener();
137
+ };
138
+ deleteValueId_fn = function(value, id) {
139
+ const ids = __privateGet(this, _optionIdsByValue).get(value);
140
+ if (typeof ids === "string") {
141
+ if (ids === id) __privateGet(this, _optionIdsByValue).delete(value);
142
+ return;
143
+ }
144
+ ids == null ? void 0 : ids.delete(id);
145
+ if ((ids == null ? void 0 : ids.size) === 1) {
146
+ __privateGet(this, _optionIdsByValue).set(value, ids.values().next().value);
147
+ } else if ((ids == null ? void 0 : ids.size) === 0) {
148
+ __privateGet(this, _optionIdsByValue).delete(value);
149
+ }
150
+ };
151
+
152
+ export { ListControlOptionStore, OPTION_STATE_ACTIVE, OPTION_STATE_FOCUS_VISIBLE, OPTION_STATE_SELECTED, hasOptionState };
153
+ //# sourceMappingURL=ListControlOptionStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListControlOptionStore.js","sources":["../src/list-control/ListControlOptionStore.ts"],"sourcesContent":["import type { OptionValue } from \"./ListControlContext\";\n\nexport const OPTION_STATE_ACTIVE = 1;\nexport const OPTION_STATE_SELECTED = 2;\nexport const OPTION_STATE_FOCUS_VISIBLE = 4;\n\nexport type OptionStateSnapshot = number;\n\nexport function hasOptionState(\n snapshot: OptionStateSnapshot,\n state: OptionStateSnapshot,\n): boolean {\n return (snapshot & state) !== 0;\n}\n\ninterface OptionEntry<Item> {\n generation: number;\n option: OptionValue<Item>;\n}\n\n/** Internal per-list store used to target updates at affected Options. */\nexport class ListControlOptionStore<Item> {\n readonly #listeners = new Map<string, Set<() => void>>();\n readonly #options = new Map<string, OptionEntry<Item>>();\n readonly #optionIdsByValue = new Map<Item, string | Set<string>>();\n #activeId: string | undefined;\n #focusVisible = false;\n #nextGeneration = 0;\n #selected: ReadonlySet<Item>;\n\n constructor(selected: readonly Item[] = []) {\n this.#selected = new Set(selected);\n }\n\n subscribe(id: string, listener: () => void): () => void {\n let listeners = this.#listeners.get(id);\n if (!listeners) {\n listeners = new Set();\n this.#listeners.set(id, listeners);\n }\n listeners.add(listener);\n\n return () => {\n const currentListeners = this.#listeners.get(id);\n currentListeners?.delete(listener);\n if (currentListeners?.size === 0) {\n this.#listeners.delete(id);\n }\n };\n }\n\n register(option: OptionValue<Item>): () => void {\n const previousEntry = this.#options.get(option.id);\n const previousSnapshot = this.getSnapshot(option.id);\n if (previousEntry) {\n this.#deleteValueId(previousEntry.option.value, option.id);\n }\n const entry = {\n generation: this.#nextGeneration++,\n option,\n };\n this.#options.set(option.id, entry);\n const valueIds = this.#optionIdsByValue.get(option.value);\n if (valueIds === undefined) {\n this.#optionIdsByValue.set(option.value, option.id);\n } else if (typeof valueIds === \"string\") {\n this.#optionIdsByValue.set(option.value, new Set([valueIds, option.id]));\n } else {\n valueIds.add(option.id);\n }\n\n if (\n previousEntry !== undefined ||\n previousSnapshot !== this.getSnapshot(option.id)\n ) {\n this.#notify(option.id);\n }\n\n return () => {\n const current = this.#options.get(option.id);\n if (current?.generation !== entry.generation) return;\n const previousSnapshot = this.getSnapshot(option.id);\n this.#options.delete(option.id);\n this.#deleteValueId(option.value, option.id);\n if (previousSnapshot !== 0) this.#notify(option.id);\n };\n }\n\n getSnapshot(\n id: string,\n currentOption?: OptionValue<Item>,\n ): OptionStateSnapshot {\n const option = currentOption ?? this.#options.get(id)?.option;\n if (!option) return 0;\n\n let snapshot = 0;\n if (id === this.#activeId) {\n snapshot |= OPTION_STATE_ACTIVE;\n if (this.#focusVisible) snapshot |= OPTION_STATE_FOCUS_VISIBLE;\n }\n if (this.#selected.has(option.value)) {\n snapshot |= OPTION_STATE_SELECTED;\n }\n return snapshot;\n }\n\n setActiveId(id: string | undefined): void {\n if (id === this.#activeId) return;\n const previousId = this.#activeId;\n this.#activeId = id;\n if (previousId !== undefined) this.#notify(previousId);\n if (id !== undefined) this.#notify(id);\n }\n\n setFocusVisible(focusVisible: boolean): void {\n if (focusVisible === this.#focusVisible) return;\n this.#focusVisible = focusVisible;\n if (this.#activeId !== undefined) this.#notify(this.#activeId);\n }\n\n setSelected(selected: readonly Item[]): void {\n const previous = this.#selected;\n const nextSelected = new Set(selected);\n this.#selected = nextSelected;\n\n const candidateValues = new Set([...previous, ...nextSelected]);\n for (const value of candidateValues) {\n if (previous.has(value) !== nextSelected.has(value)) {\n const ids = this.#optionIdsByValue.get(value);\n if (typeof ids === \"string\") {\n this.#notify(ids);\n } else if (ids !== undefined) {\n for (const id of ids) this.#notify(id);\n }\n }\n }\n }\n\n #notify(id: string): void {\n const listeners = this.#listeners.get(id);\n if (!listeners) return;\n for (const listener of [...listeners]) listener();\n }\n\n #deleteValueId(value: Item, id: string): void {\n const ids = this.#optionIdsByValue.get(value);\n if (typeof ids === \"string\") {\n if (ids === id) this.#optionIdsByValue.delete(value);\n return;\n }\n ids?.delete(id);\n if (ids?.size === 1) {\n this.#optionIdsByValue.set(value, ids.values().next().value as string);\n } else if (ids?.size === 0) {\n this.#optionIdsByValue.delete(value);\n }\n }\n}\n"],"names":["previousSnapshot"],"mappings":"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"}