@salt-ds/lab 1.0.0-alpha.14 → 1.0.0-alpha.16

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 (287) hide show
  1. package/dist-cjs/badge/Badge.css.js +1 -1
  2. package/dist-cjs/badge/Badge.js +7 -23
  3. package/dist-cjs/badge/Badge.js.map +1 -1
  4. package/dist-cjs/combo-box-next/ComboBoxNext.css.js +6 -0
  5. package/dist-cjs/combo-box-next/ComboBoxNext.css.js.map +1 -0
  6. package/dist-cjs/combo-box-next/ComboBoxNext.js +177 -0
  7. package/dist-cjs/combo-box-next/ComboBoxNext.js.map +1 -0
  8. package/dist-cjs/combo-box-next/useComboBox.js +137 -0
  9. package/dist-cjs/combo-box-next/useComboBox.js.map +1 -0
  10. package/dist-cjs/combo-box-next/useComboboxPortal.js +69 -0
  11. package/dist-cjs/combo-box-next/useComboboxPortal.js.map +1 -0
  12. package/dist-cjs/combo-box-next/utils.js +40 -0
  13. package/dist-cjs/combo-box-next/utils.js.map +1 -0
  14. package/dist-cjs/content-status/ContentStatus.js +0 -2
  15. package/dist-cjs/content-status/ContentStatus.js.map +1 -1
  16. package/dist-cjs/content-status/internal/StatusIndicator.js +0 -2
  17. package/dist-cjs/content-status/internal/StatusIndicator.js.map +1 -1
  18. package/dist-cjs/dialog/Dialog.css.js +1 -1
  19. package/dist-cjs/dialog/Dialog.js +53 -56
  20. package/dist-cjs/dialog/Dialog.js.map +1 -1
  21. package/dist-cjs/dialog/DialogActions.css.js +1 -1
  22. package/dist-cjs/dialog/DialogActions.js +15 -17
  23. package/dist-cjs/dialog/DialogActions.js.map +1 -1
  24. package/dist-cjs/dialog/DialogCloseButton.css.js +6 -0
  25. package/dist-cjs/dialog/DialogCloseButton.css.js.map +1 -0
  26. package/dist-cjs/dialog/DialogCloseButton.js +39 -0
  27. package/dist-cjs/dialog/DialogCloseButton.js.map +1 -0
  28. package/dist-cjs/dialog/DialogContent.css.js +1 -1
  29. package/dist-cjs/dialog/DialogContent.js +20 -29
  30. package/dist-cjs/dialog/DialogContent.js.map +1 -1
  31. package/dist-cjs/dialog/{internal/DialogContext.js → DialogContext.js} +4 -0
  32. package/dist-cjs/dialog/DialogContext.js.map +1 -0
  33. package/dist-cjs/dialog/DialogTitle.css.js +1 -1
  34. package/dist-cjs/dialog/DialogTitle.js +40 -41
  35. package/dist-cjs/dialog/DialogTitle.js.map +1 -1
  36. package/dist-cjs/dialog/useDialog.js +31 -0
  37. package/dist-cjs/dialog/useDialog.js.map +1 -0
  38. package/dist-cjs/drawer/Drawer.css.js +1 -1
  39. package/dist-cjs/drawer/Drawer.js +39 -45
  40. package/dist-cjs/drawer/Drawer.js.map +1 -1
  41. package/dist-cjs/drawer/useDrawer.js +31 -0
  42. package/dist-cjs/drawer/useDrawer.js.map +1 -0
  43. package/dist-cjs/dropdown-next/DropdownNext.css.js +6 -0
  44. package/dist-cjs/dropdown-next/DropdownNext.css.js.map +1 -0
  45. package/dist-cjs/dropdown-next/DropdownNext.js +181 -0
  46. package/dist-cjs/dropdown-next/DropdownNext.js.map +1 -0
  47. package/dist-cjs/dropdown-next/useDropdownNext.js +169 -0
  48. package/dist-cjs/dropdown-next/useDropdownNext.js.map +1 -0
  49. package/dist-cjs/form-field-legacy/FormFieldLegacy.css.js +1 -1
  50. package/dist-cjs/index.js +19 -13
  51. package/dist-cjs/index.js.map +1 -1
  52. package/dist-cjs/list/Highlighter.js +1 -1
  53. package/dist-cjs/list/Highlighter.js.map +1 -1
  54. package/dist-cjs/list-next/ListItemNext.css.js +1 -1
  55. package/dist-cjs/list-next/ListItemNext.js +17 -6
  56. package/dist-cjs/list-next/ListItemNext.js.map +1 -1
  57. package/dist-cjs/list-next/ListNext.js +21 -10
  58. package/dist-cjs/list-next/ListNext.js.map +1 -1
  59. package/dist-cjs/list-next/ListNextContext.js.map +1 -1
  60. package/dist-cjs/list-next/useList.js +96 -37
  61. package/dist-cjs/list-next/useList.js.map +1 -1
  62. package/dist-cjs/logo/Logo.css.js +1 -1
  63. package/dist-cjs/logo/LogoImage.css.js +6 -0
  64. package/dist-cjs/logo/LogoImage.css.js.map +1 -0
  65. package/dist-cjs/logo/LogoImage.js +9 -0
  66. package/dist-cjs/logo/LogoImage.js.map +1 -1
  67. package/dist-cjs/logo/LogoSeparator.css.js +1 -1
  68. package/dist-cjs/{nav-item/ExpansionButton.js → navigation-item/ExpansionIcon.js} +8 -13
  69. package/dist-cjs/navigation-item/ExpansionIcon.js.map +1 -0
  70. package/dist-cjs/navigation-item/NavigationItem.css.js +6 -0
  71. package/dist-cjs/navigation-item/NavigationItem.css.js.map +1 -0
  72. package/dist-cjs/navigation-item/NavigationItem.js +96 -0
  73. package/dist-cjs/navigation-item/NavigationItem.js.map +1 -0
  74. package/dist-cjs/progress/CircularProgress/CircularProgress.css.js +1 -1
  75. package/dist-cjs/progress/CircularProgress/CircularProgress.js +44 -51
  76. package/dist-cjs/progress/CircularProgress/CircularProgress.js.map +1 -1
  77. package/dist-cjs/progress/LinearProgress/LinearProgress.css.js +1 -1
  78. package/dist-cjs/progress/LinearProgress/LinearProgress.js +9 -49
  79. package/dist-cjs/progress/LinearProgress/LinearProgress.js.map +1 -1
  80. package/dist-cjs/stepped-tracker/StepLabel/StepLabel.css.js +1 -1
  81. package/dist-cjs/stepped-tracker/StepLabel/StepLabel.js +5 -13
  82. package/dist-cjs/stepped-tracker/StepLabel/StepLabel.js.map +1 -1
  83. package/dist-cjs/stepped-tracker/SteppedTracker.css.js +1 -1
  84. package/dist-cjs/stepped-tracker/SteppedTracker.js +0 -5
  85. package/dist-cjs/stepped-tracker/SteppedTracker.js.map +1 -1
  86. package/dist-cjs/stepped-tracker/SteppedTrackerContext.js +1 -7
  87. package/dist-cjs/stepped-tracker/SteppedTrackerContext.js.map +1 -1
  88. package/dist-cjs/stepped-tracker/TrackerConnector/TrackerConnector.css.js +1 -1
  89. package/dist-cjs/stepped-tracker/TrackerStep/TrackerStep.css.js +1 -1
  90. package/dist-cjs/stepped-tracker/TrackerStep/TrackerStep.js +2 -14
  91. package/dist-cjs/stepped-tracker/TrackerStep/TrackerStep.js.map +1 -1
  92. package/dist-cjs/switch/Switch.css.js +1 -1
  93. package/dist-cjs/switch/Switch.js +67 -72
  94. package/dist-cjs/switch/Switch.js.map +1 -1
  95. package/dist-cjs/toast-group/ToastGroup.css.js +6 -0
  96. package/dist-cjs/toast-group/ToastGroup.css.js.map +1 -0
  97. package/dist-cjs/toast-group/ToastGroup.js +32 -0
  98. package/dist-cjs/toast-group/ToastGroup.js.map +1 -0
  99. package/dist-es/badge/Badge.css.js +1 -1
  100. package/dist-es/badge/Badge.js +9 -25
  101. package/dist-es/badge/Badge.js.map +1 -1
  102. package/dist-es/combo-box-next/ComboBoxNext.css.js +4 -0
  103. package/dist-es/combo-box-next/ComboBoxNext.css.js.map +1 -0
  104. package/dist-es/combo-box-next/ComboBoxNext.js +173 -0
  105. package/dist-es/combo-box-next/ComboBoxNext.js.map +1 -0
  106. package/dist-es/combo-box-next/useComboBox.js +133 -0
  107. package/dist-es/combo-box-next/useComboBox.js.map +1 -0
  108. package/dist-es/combo-box-next/useComboboxPortal.js +65 -0
  109. package/dist-es/combo-box-next/useComboboxPortal.js.map +1 -0
  110. package/dist-es/combo-box-next/utils.js +35 -0
  111. package/dist-es/combo-box-next/utils.js.map +1 -0
  112. package/dist-es/content-status/ContentStatus.js +0 -2
  113. package/dist-es/content-status/ContentStatus.js.map +1 -1
  114. package/dist-es/content-status/internal/StatusIndicator.js +0 -2
  115. package/dist-es/content-status/internal/StatusIndicator.js.map +1 -1
  116. package/dist-es/dialog/Dialog.css.js +1 -1
  117. package/dist-es/dialog/Dialog.js +53 -56
  118. package/dist-es/dialog/Dialog.js.map +1 -1
  119. package/dist-es/dialog/DialogActions.css.js +1 -1
  120. package/dist-es/dialog/DialogActions.js +15 -17
  121. package/dist-es/dialog/DialogActions.js.map +1 -1
  122. package/dist-es/dialog/DialogCloseButton.css.js +4 -0
  123. package/dist-es/dialog/DialogCloseButton.css.js.map +1 -0
  124. package/dist-es/dialog/DialogCloseButton.js +31 -0
  125. package/dist-es/dialog/DialogCloseButton.js.map +1 -0
  126. package/dist-es/dialog/DialogContent.css.js +1 -1
  127. package/dist-es/dialog/DialogContent.js +20 -29
  128. package/dist-es/dialog/DialogContent.js.map +1 -1
  129. package/dist-es/dialog/DialogContext.js +9 -0
  130. package/dist-es/dialog/DialogContext.js.map +1 -0
  131. package/dist-es/dialog/DialogTitle.css.js +1 -1
  132. package/dist-es/dialog/DialogTitle.js +37 -42
  133. package/dist-es/dialog/DialogTitle.js.map +1 -1
  134. package/dist-es/dialog/useDialog.js +27 -0
  135. package/dist-es/dialog/useDialog.js.map +1 -0
  136. package/dist-es/drawer/Drawer.css.js +1 -1
  137. package/dist-es/drawer/Drawer.js +40 -46
  138. package/dist-es/drawer/Drawer.js.map +1 -1
  139. package/dist-es/drawer/useDrawer.js +27 -0
  140. package/dist-es/drawer/useDrawer.js.map +1 -0
  141. package/dist-es/dropdown-next/DropdownNext.css.js +4 -0
  142. package/dist-es/dropdown-next/DropdownNext.css.js.map +1 -0
  143. package/dist-es/dropdown-next/DropdownNext.js +177 -0
  144. package/dist-es/dropdown-next/DropdownNext.js.map +1 -0
  145. package/dist-es/dropdown-next/useDropdownNext.js +165 -0
  146. package/dist-es/dropdown-next/useDropdownNext.js.map +1 -0
  147. package/dist-es/form-field-legacy/FormFieldLegacy.css.js +1 -1
  148. package/dist-es/index.js +9 -6
  149. package/dist-es/index.js.map +1 -1
  150. package/dist-es/list/Highlighter.js +1 -1
  151. package/dist-es/list/Highlighter.js.map +1 -1
  152. package/dist-es/list-next/ListItemNext.css.js +1 -1
  153. package/dist-es/list-next/ListItemNext.js +17 -6
  154. package/dist-es/list-next/ListItemNext.js.map +1 -1
  155. package/dist-es/list-next/ListNext.js +21 -10
  156. package/dist-es/list-next/ListNext.js.map +1 -1
  157. package/dist-es/list-next/ListNextContext.js.map +1 -1
  158. package/dist-es/list-next/useList.js +98 -39
  159. package/dist-es/list-next/useList.js.map +1 -1
  160. package/dist-es/logo/Logo.css.js +1 -1
  161. package/dist-es/logo/LogoImage.css.js +4 -0
  162. package/dist-es/logo/LogoImage.css.js.map +1 -0
  163. package/dist-es/logo/LogoImage.js +9 -0
  164. package/dist-es/logo/LogoImage.js.map +1 -1
  165. package/dist-es/logo/LogoSeparator.css.js +1 -1
  166. package/dist-es/navigation-item/ExpansionIcon.js +27 -0
  167. package/dist-es/navigation-item/ExpansionIcon.js.map +1 -0
  168. package/dist-es/navigation-item/NavigationItem.css.js +4 -0
  169. package/dist-es/navigation-item/NavigationItem.css.js.map +1 -0
  170. package/dist-es/navigation-item/NavigationItem.js +92 -0
  171. package/dist-es/navigation-item/NavigationItem.js.map +1 -0
  172. package/dist-es/progress/CircularProgress/CircularProgress.css.js +1 -1
  173. package/dist-es/progress/CircularProgress/CircularProgress.js +45 -52
  174. package/dist-es/progress/CircularProgress/CircularProgress.js.map +1 -1
  175. package/dist-es/progress/LinearProgress/LinearProgress.css.js +1 -1
  176. package/dist-es/progress/LinearProgress/LinearProgress.js +9 -49
  177. package/dist-es/progress/LinearProgress/LinearProgress.js.map +1 -1
  178. package/dist-es/stepped-tracker/StepLabel/StepLabel.css.js +1 -1
  179. package/dist-es/stepped-tracker/StepLabel/StepLabel.js +7 -15
  180. package/dist-es/stepped-tracker/StepLabel/StepLabel.js.map +1 -1
  181. package/dist-es/stepped-tracker/SteppedTracker.css.js +1 -1
  182. package/dist-es/stepped-tracker/SteppedTracker.js +1 -6
  183. package/dist-es/stepped-tracker/SteppedTracker.js.map +1 -1
  184. package/dist-es/stepped-tracker/SteppedTrackerContext.js +1 -7
  185. package/dist-es/stepped-tracker/SteppedTrackerContext.js.map +1 -1
  186. package/dist-es/stepped-tracker/TrackerConnector/TrackerConnector.css.js +1 -1
  187. package/dist-es/stepped-tracker/TrackerStep/TrackerStep.css.js +1 -1
  188. package/dist-es/stepped-tracker/TrackerStep/TrackerStep.js +3 -15
  189. package/dist-es/stepped-tracker/TrackerStep/TrackerStep.js.map +1 -1
  190. package/dist-es/switch/Switch.css.js +1 -1
  191. package/dist-es/switch/Switch.js +70 -75
  192. package/dist-es/switch/Switch.js.map +1 -1
  193. package/dist-es/toast-group/ToastGroup.css.js +4 -0
  194. package/dist-es/toast-group/ToastGroup.css.js.map +1 -0
  195. package/dist-es/toast-group/ToastGroup.js +28 -0
  196. package/dist-es/toast-group/ToastGroup.js.map +1 -0
  197. package/dist-types/badge/Badge.d.ts +5 -16
  198. package/dist-types/combo-box-next/ComboBoxNext.d.ts +70 -0
  199. package/dist-types/combo-box-next/index.d.ts +1 -0
  200. package/dist-types/combo-box-next/useComboBox.d.ts +34 -0
  201. package/dist-types/combo-box-next/useComboboxPortal.d.ts +15 -0
  202. package/dist-types/combo-box-next/utils.d.ts +8 -0
  203. package/dist-types/content-status/internal/StatusIndicator.d.ts +2 -2
  204. package/dist-types/dialog/Dialog.d.ts +17 -12
  205. package/dist-types/dialog/DialogActions.d.ts +1 -3
  206. package/dist-types/dialog/DialogCloseButton.d.ts +3 -0
  207. package/dist-types/dialog/DialogContent.d.ts +1 -3
  208. package/dist-types/dialog/DialogContext.d.ts +9 -0
  209. package/dist-types/dialog/DialogTitle.d.ts +7 -8
  210. package/dist-types/dialog/index.d.ts +4 -2
  211. package/dist-types/dialog/useDialog.d.ts +27 -0
  212. package/dist-types/drawer/Drawer.d.ts +3 -12
  213. package/dist-types/drawer/index.d.ts +1 -0
  214. package/dist-types/drawer/useDrawer.d.ts +27 -0
  215. package/dist-types/dropdown-next/DropdownNext.d.ts +42 -0
  216. package/dist-types/dropdown-next/index.d.ts +1 -0
  217. package/dist-types/dropdown-next/useDropdownNext.d.ts +31 -0
  218. package/dist-types/index.d.ts +4 -3
  219. package/dist-types/list-next/ListItemNext.d.ts +6 -1
  220. package/dist-types/list-next/ListNext.d.ts +7 -2
  221. package/dist-types/list-next/ListNextContext.d.ts +4 -2
  222. package/dist-types/list-next/useList.d.ts +16 -9
  223. package/dist-types/navigation-item/ExpansionIcon.d.ts +3 -0
  224. package/dist-types/navigation-item/NavigationItem.d.ts +36 -0
  225. package/dist-types/navigation-item/index.d.ts +1 -0
  226. package/dist-types/progress/CircularProgress/CircularProgress.d.ts +1 -21
  227. package/dist-types/progress/LinearProgress/LinearProgress.d.ts +1 -26
  228. package/dist-types/stepped-tracker/StepLabel/StepLabel.d.ts +3 -5
  229. package/dist-types/stepped-tracker/SteppedTrackerContext.d.ts +1 -4
  230. package/dist-types/stepped-tracker/TrackerStep/index.d.ts +0 -1
  231. package/dist-types/switch/Switch.d.ts +43 -6
  232. package/dist-types/toast-group/ToastGroup.d.ts +5 -0
  233. package/dist-types/toast-group/index.d.ts +1 -0
  234. package/package.json +5 -5
  235. package/dist-cjs/control-label/ControlLabel.css.js +0 -6
  236. package/dist-cjs/control-label/ControlLabel.css.js.map +0 -1
  237. package/dist-cjs/control-label/ControlLabel.js +0 -48
  238. package/dist-cjs/control-label/ControlLabel.js.map +0 -1
  239. package/dist-cjs/dialog/internal/DialogContext.js.map +0 -1
  240. package/dist-cjs/multiline-input/MultilineInput.css.js +0 -6
  241. package/dist-cjs/multiline-input/MultilineInput.css.js.map +0 -1
  242. package/dist-cjs/multiline-input/MultilineInput.js +0 -162
  243. package/dist-cjs/multiline-input/MultilineInput.js.map +0 -1
  244. package/dist-cjs/nav-item/ExpansionButton.js.map +0 -1
  245. package/dist-cjs/nav-item/NavItem.css.js +0 -6
  246. package/dist-cjs/nav-item/NavItem.css.js.map +0 -1
  247. package/dist-cjs/nav-item/NavItem.js +0 -78
  248. package/dist-cjs/nav-item/NavItem.js.map +0 -1
  249. package/dist-cjs/stepped-tracker/TrackerStep/TrackerStepTooltipContext.js +0 -21
  250. package/dist-cjs/stepped-tracker/TrackerStep/TrackerStepTooltipContext.js.map +0 -1
  251. package/dist-cjs/stepped-tracker/useDetectTruncatedText.js +0 -71
  252. package/dist-cjs/stepped-tracker/useDetectTruncatedText.js.map +0 -1
  253. package/dist-cjs/switch/assets/CheckedIcon.js +0 -34
  254. package/dist-cjs/switch/assets/CheckedIcon.js.map +0 -1
  255. package/dist-es/control-label/ControlLabel.css.js +0 -4
  256. package/dist-es/control-label/ControlLabel.css.js.map +0 -1
  257. package/dist-es/control-label/ControlLabel.js +0 -43
  258. package/dist-es/control-label/ControlLabel.js.map +0 -1
  259. package/dist-es/dialog/internal/DialogContext.js +0 -6
  260. package/dist-es/dialog/internal/DialogContext.js.map +0 -1
  261. package/dist-es/multiline-input/MultilineInput.css.js +0 -4
  262. package/dist-es/multiline-input/MultilineInput.css.js.map +0 -1
  263. package/dist-es/multiline-input/MultilineInput.js +0 -158
  264. package/dist-es/multiline-input/MultilineInput.js.map +0 -1
  265. package/dist-es/nav-item/ExpansionButton.js +0 -32
  266. package/dist-es/nav-item/ExpansionButton.js.map +0 -1
  267. package/dist-es/nav-item/NavItem.css.js +0 -4
  268. package/dist-es/nav-item/NavItem.css.js.map +0 -1
  269. package/dist-es/nav-item/NavItem.js +0 -74
  270. package/dist-es/nav-item/NavItem.js.map +0 -1
  271. package/dist-es/stepped-tracker/TrackerStep/TrackerStepTooltipContext.js +0 -16
  272. package/dist-es/stepped-tracker/TrackerStep/TrackerStepTooltipContext.js.map +0 -1
  273. package/dist-es/stepped-tracker/useDetectTruncatedText.js +0 -69
  274. package/dist-es/stepped-tracker/useDetectTruncatedText.js.map +0 -1
  275. package/dist-es/switch/assets/CheckedIcon.js +0 -30
  276. package/dist-es/switch/assets/CheckedIcon.js.map +0 -1
  277. package/dist-types/control-label/ControlLabel.d.ts +0 -8
  278. package/dist-types/control-label/index.d.ts +0 -1
  279. package/dist-types/dialog/internal/DialogContext.d.ts +0 -6
  280. package/dist-types/multiline-input/MultilineInput.d.ts +0 -40
  281. package/dist-types/multiline-input/index.d.ts +0 -1
  282. package/dist-types/nav-item/ExpansionButton.d.ts +0 -3
  283. package/dist-types/nav-item/NavItem.d.ts +0 -17
  284. package/dist-types/nav-item/index.d.ts +0 -1
  285. package/dist-types/stepped-tracker/TrackerStep/TrackerStepTooltipContext.d.ts +0 -7
  286. package/dist-types/stepped-tracker/useDetectTruncatedText.d.ts +0 -11
  287. package/dist-types/switch/assets/CheckedIcon.d.ts +0 -4
@@ -14,14 +14,17 @@ const ListNext = forwardRef(
14
14
  children,
15
15
  className,
16
16
  disabled,
17
+ disableFocus,
17
18
  id,
18
19
  onSelect,
19
20
  onFocus,
20
21
  onBlur,
21
22
  onKeyDown,
22
- onMouseDown,
23
+ onMouseOver,
24
+ highlightedItem,
23
25
  selected,
24
26
  defaultSelected,
27
+ onChange,
25
28
  ...rest
26
29
  }, ref) {
27
30
  const targetWindow = useWindow();
@@ -37,21 +40,29 @@ const ListNext = forwardRef(
37
40
  focusHandler,
38
41
  keyDownHandler,
39
42
  blurHandler,
40
- mouseDownHandler,
43
+ mouseOverHandler,
41
44
  activeDescendant,
42
- contextValue
45
+ contextValue,
46
+ focusVisibleRef
43
47
  } = useList({
44
48
  disabled,
49
+ highlightedItem,
45
50
  selected,
46
51
  defaultSelected,
52
+ onChange,
47
53
  id: listId,
48
54
  ref: listRef
49
55
  });
56
+ const setListRef = useForkRef(focusVisibleRef, handleRef);
50
57
  const handleFocus = (event) => {
51
- focusHandler();
58
+ focusHandler(event);
52
59
  onFocus == null ? void 0 : onFocus(event);
53
60
  };
54
61
  const handleKeyDown = (event) => {
62
+ if (disableFocus) {
63
+ event.preventDefault();
64
+ return;
65
+ }
55
66
  keyDownHandler(event);
56
67
  onKeyDown == null ? void 0 : onKeyDown(event);
57
68
  };
@@ -59,24 +70,24 @@ const ListNext = forwardRef(
59
70
  blurHandler();
60
71
  onBlur == null ? void 0 : onBlur(event);
61
72
  };
62
- const handleMouseDown = (event) => {
63
- mouseDownHandler();
64
- onMouseDown == null ? void 0 : onMouseDown(event);
73
+ const handleMouseOver = (event) => {
74
+ mouseOverHandler();
75
+ onMouseOver == null ? void 0 : onMouseOver(event);
65
76
  };
66
77
  return /* @__PURE__ */ jsx(ListNextContext.Provider, {
67
78
  value: contextValue,
68
79
  children: /* @__PURE__ */ jsx("ul", {
69
- ref: handleRef,
80
+ ref: setListRef,
70
81
  id: listId,
71
82
  className: clsx(withBaseName(), className),
72
83
  role: "listbox",
73
- tabIndex: disabled ? -1 : 0,
84
+ tabIndex: disabled || disableFocus ? -1 : 0,
74
85
  "aria-activedescendant": disabled ? void 0 : activeDescendant,
75
86
  "aria-disabled": disabled,
76
87
  onFocus: handleFocus,
77
88
  onKeyDown: handleKeyDown,
78
89
  onBlur: handleBlur,
79
- onMouseDown: handleMouseDown,
90
+ onMouseOver: handleMouseOver,
80
91
  ...rest,
81
92
  children
82
93
  })
@@ -1 +1 @@
1
- {"version":3,"file":"ListNext.js","sources":["../src/list-next/ListNext.tsx"],"sourcesContent":["import { makePrefixer, useForkRef, useId } from \"@salt-ds/core\";\nimport {\n FocusEvent,\n forwardRef,\n HTMLAttributes,\n KeyboardEvent,\n MouseEvent,\n useRef,\n} from \"react\";\nimport { clsx } from \"clsx\";\nimport { useList } from \"./useList\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport listNextCss from \"./ListNext.css\";\nimport { ListNextContext } from \"./ListNextContext\";\n\nconst withBaseName = makePrefixer(\"saltListNext\");\n\nexport interface ListNextProps extends HTMLAttributes<HTMLUListElement> {\n /**\n * If true, all items in list will be disabled.\n */\n disabled?: boolean;\n /* Value for the uncontrolled version. */\n selected?: string;\n /* Initial value for the uncontrolled version. */\n defaultSelected?: string;\n}\n\nexport const ListNext = forwardRef<HTMLUListElement, ListNextProps>(\n function ListNext(\n {\n children,\n className,\n disabled,\n id,\n onSelect,\n onFocus,\n onBlur,\n onKeyDown,\n onMouseDown,\n selected,\n defaultSelected,\n ...rest\n },\n ref\n ) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-list-next\",\n css: listNextCss,\n window: targetWindow,\n });\n\n const listId = useId(id);\n const listRef = useRef<HTMLUListElement>(null);\n const handleRef = useForkRef(listRef, ref);\n\n const {\n focusHandler,\n keyDownHandler,\n blurHandler,\n mouseDownHandler,\n activeDescendant,\n contextValue,\n } = useList({\n disabled,\n selected,\n defaultSelected,\n id: listId,\n ref: listRef,\n });\n\n const handleFocus = (event: FocusEvent<HTMLUListElement>) => {\n focusHandler();\n onFocus?.(event);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLUListElement>) => {\n keyDownHandler(event);\n onKeyDown?.(event);\n };\n\n const handleBlur = (event: FocusEvent<HTMLUListElement>) => {\n blurHandler();\n onBlur?.(event);\n };\n\n const handleMouseDown = (event: MouseEvent<HTMLUListElement>) => {\n mouseDownHandler();\n onMouseDown?.(event);\n };\n\n return (\n <ListNextContext.Provider value={contextValue}>\n <ul\n ref={handleRef}\n id={listId}\n className={clsx(withBaseName(), className)}\n role=\"listbox\"\n tabIndex={disabled ? -1 : 0}\n aria-activedescendant={disabled ? undefined : activeDescendant}\n aria-disabled={disabled}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onMouseDown={handleMouseDown}\n {...rest}\n >\n {children}\n </ul>\n </ListNextContext.Provider>\n );\n }\n);\n"],"names":["ListNext","listNextCss"],"mappings":"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"}
1
+ {"version":3,"file":"ListNext.js","sources":["../src/list-next/ListNext.tsx"],"sourcesContent":["import { makePrefixer, useForkRef, useId } from \"@salt-ds/core\";\nimport {\n ComponentPropsWithoutRef,\n FocusEvent,\n forwardRef,\n KeyboardEvent,\n MouseEvent,\n SyntheticEvent,\n useRef,\n} from \"react\";\nimport { clsx } from \"clsx\";\nimport { useList } from \"./useList\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport listNextCss from \"./ListNext.css\";\nimport { ListNextContext } from \"./ListNextContext\";\n\nconst withBaseName = makePrefixer(\"saltListNext\");\n\nexport interface ListNextProps\n extends Omit<ComponentPropsWithoutRef<\"ul\">, \"onChange\"> {\n /**\n * If true, all items in list will be disabled.\n */\n disabled?: boolean;\n /* If `true`, the component will not receive focus. */\n disableFocus?: boolean;\n /* Value for the controlled version. */\n highlightedItem?: string;\n /* Value for the controlled version. */\n selected?: string;\n /* Callback for change event. */\n onChange?: (event: SyntheticEvent, data: { value: string }) => void;\n /* Initial selection. */\n defaultSelected?: string;\n}\n\nexport const ListNext = forwardRef<HTMLUListElement, ListNextProps>(\n function ListNext(\n {\n children,\n className,\n disabled,\n disableFocus,\n id,\n onSelect,\n onFocus,\n onBlur,\n onKeyDown,\n onMouseOver,\n highlightedItem,\n selected,\n defaultSelected,\n onChange,\n ...rest\n },\n ref\n ) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-list-next\",\n css: listNextCss,\n window: targetWindow,\n });\n\n const listId = useId(id);\n const listRef = useRef<HTMLUListElement>(null);\n const handleRef = useForkRef(listRef, ref);\n const {\n focusHandler,\n keyDownHandler,\n blurHandler,\n mouseOverHandler,\n activeDescendant,\n contextValue,\n focusVisibleRef,\n } = useList({\n disabled,\n highlightedItem,\n selected,\n defaultSelected,\n onChange,\n id: listId,\n ref: listRef,\n });\n\n const setListRef = useForkRef(focusVisibleRef, handleRef);\n\n const handleFocus = (event: FocusEvent<HTMLUListElement>) => {\n focusHandler(event);\n onFocus?.(event);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLUListElement>) => {\n if (disableFocus) {\n event.preventDefault();\n return;\n }\n keyDownHandler(event);\n onKeyDown?.(event);\n };\n\n const handleBlur = (event: FocusEvent<HTMLUListElement>) => {\n blurHandler();\n onBlur?.(event);\n };\n\n const handleMouseOver = (event: MouseEvent<HTMLUListElement>) => {\n mouseOverHandler();\n onMouseOver?.(event);\n };\n\n return (\n <ListNextContext.Provider value={contextValue}>\n <ul\n // TODO: fix type from useIsFocusVisible\n // @ts-ignore\n ref={setListRef}\n id={listId}\n className={clsx(withBaseName(), className)}\n role=\"listbox\"\n tabIndex={disabled || disableFocus ? -1 : 0}\n aria-activedescendant={disabled ? undefined : activeDescendant}\n aria-disabled={disabled}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onMouseOver={handleMouseOver}\n {...rest}\n >\n {children}\n </ul>\n </ListNextContext.Provider>\n );\n }\n);\n"],"names":["ListNext","listNextCss"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ListNextContext.js","sources":["../src/list-next/ListNextContext.tsx"],"sourcesContent":["import { createContext } from \"@salt-ds/core\";\nimport { SyntheticEvent, useContext } from \"react\";\n\nexport interface ListNextContextValue {\n disabled?: boolean;\n id?: string;\n select: (event: SyntheticEvent<HTMLLIElement>) => void;\n isSelected: (id: string) => boolean;\n isFocused: (id: string) => boolean;\n}\n\nexport const ListNextContext = createContext<ListNextContextValue | undefined>(\n \"ListNextContext\",\n undefined\n);\n\nexport function useListItem() {\n return useContext(ListNextContext);\n}\n"],"names":[],"mappings":";;;AAWO,MAAM,eAAkB,GAAA,aAAA;AAAA,EAC7B,iBAAA;AAAA,EACA,KAAA,CAAA;AACF,EAAA;AAEO,SAAS,WAAc,GAAA;AAC5B,EAAA,OAAO,WAAW,eAAe,CAAA,CAAA;AACnC;;;;"}
1
+ {"version":3,"file":"ListNextContext.js","sources":["../src/list-next/ListNextContext.tsx"],"sourcesContent":["import { createContext } from \"@salt-ds/core\";\nimport { SyntheticEvent, useContext } from \"react\";\n\nexport interface ListNextContextValue {\n disabled?: boolean;\n id?: string;\n select: (event: SyntheticEvent<HTMLLIElement>) => void;\n isSelected: (value: string) => boolean;\n isFocused: (value: string) => boolean;\n highlight: (event: SyntheticEvent<HTMLLIElement>) => void;\n isHighlighted: (value: string) => boolean;\n}\n\nexport const ListNextContext = createContext<ListNextContextValue | undefined>(\n \"ListNextContext\",\n undefined\n);\n\nexport function useListItem() {\n return useContext(ListNextContext);\n}\n"],"names":[],"mappings":";;;AAaO,MAAM,eAAkB,GAAA,aAAA;AAAA,EAC7B,iBAAA;AAAA,EACA,KAAA,CAAA;AACF,EAAA;AAEO,SAAS,WAAc,GAAA;AAC5B,EAAA,OAAO,WAAW,eAAe,CAAA,CAAA;AACnC;;;;"}
@@ -1,30 +1,43 @@
1
- import { useState, useCallback, useMemo } from 'react';
2
- import { useControlled } from '@salt-ds/core';
1
+ import { useCallback, useState, useEffect, useMemo } from 'react';
2
+ import { useControlled, useIsFocusVisible } from '@salt-ds/core';
3
3
 
4
4
  const useList = ({
5
5
  disabled = false,
6
+ highlightedItem: highLightedItemProp,
6
7
  selected: selectedProp,
7
8
  defaultSelected,
8
9
  onChange,
9
10
  id,
10
11
  ref
11
12
  }) => {
13
+ const getOptions = useCallback(() => {
14
+ var _a, _b;
15
+ return Array.from(
16
+ (_b = (_a = ref.current) == null ? void 0 : _a.querySelectorAll('[role="option"]:not([aria-disabled])')) != null ? _b : []
17
+ );
18
+ }, [ref]);
19
+ const [focusVisible, setFocusVisible] = useState(false);
12
20
  const [activeDescendant, setActiveDescendant] = useState(
13
21
  void 0
14
22
  );
15
- const [showFocusRing, setShowFocusRing] = useState(false);
23
+ const [highlightedItem, setHighlightedItem] = useControlled({
24
+ controlled: highLightedItemProp,
25
+ default: highLightedItemProp,
26
+ name: "ListNext",
27
+ state: "highlighted"
28
+ });
16
29
  const [selectedItem, setSelectedItem] = useControlled({
17
30
  controlled: selectedProp,
18
31
  default: defaultSelected,
19
32
  name: "ListNext",
20
33
  state: "selected"
21
34
  });
22
- const getOptions = useCallback(() => {
23
- var _a, _b;
24
- return Array.from(
25
- (_b = (_a = ref.current) == null ? void 0 : _a.querySelectorAll('[role="option"]:not([aria-disabled])')) != null ? _b : []
26
- );
27
- }, [ref]);
35
+ const {
36
+ isFocusVisibleRef,
37
+ onFocus: handleFocusVisible,
38
+ onBlur: handleBlurVisible,
39
+ ref: focusVisibleRef
40
+ } = useIsFocusVisible();
28
41
  const updateScroll = useCallback(
29
42
  (currentTarget) => {
30
43
  const list = ref.current;
@@ -41,39 +54,47 @@ const useList = ({
41
54
  },
42
55
  [ref]
43
56
  );
44
- const updateActiveDescendant = useCallback(
57
+ const updateHighlighted = useCallback(
45
58
  (element) => {
59
+ setHighlightedItem(element.dataset.value);
46
60
  setActiveDescendant(element.id);
47
61
  updateScroll(element);
48
62
  },
49
- [setActiveDescendant, updateScroll]
63
+ [setHighlightedItem, updateScroll]
50
64
  );
51
65
  const selectItem = useCallback(
52
66
  (element) => {
53
67
  const newValue = element == null ? void 0 : element.dataset.value;
54
68
  if (newValue) {
55
69
  setSelectedItem(newValue);
56
- updateActiveDescendant(element);
70
+ updateHighlighted(element);
57
71
  }
58
72
  },
59
- [setSelectedItem, updateActiveDescendant]
73
+ [setSelectedItem, updateHighlighted]
60
74
  );
61
- const focusAndMoveActive = (element) => {
62
- setShowFocusRing(true);
63
- updateActiveDescendant(element);
64
- };
75
+ useEffect(() => {
76
+ var _a;
77
+ const activeOptions = getOptions();
78
+ const highlightedIndex = activeOptions.findIndex(
79
+ (i) => i.dataset.value === highlightedItem
80
+ );
81
+ if (highlightedIndex) {
82
+ setActiveDescendant((_a = activeOptions[highlightedIndex]) == null ? void 0 : _a.id);
83
+ highlightedItem && updateScroll(activeOptions[highlightedIndex]);
84
+ }
85
+ }, [highlightedItem, getOptions, updateScroll]);
65
86
  const focusFirstItem = () => {
66
87
  const activeOptions = getOptions();
67
88
  const firstItem = activeOptions[0];
68
89
  if (firstItem) {
69
- focusAndMoveActive(firstItem);
90
+ updateHighlighted(firstItem);
70
91
  }
71
92
  };
72
93
  const focusLastItem = () => {
73
94
  const activeOptions = getOptions();
74
95
  const lastItem = activeOptions[activeOptions.length - 1];
75
96
  if (lastItem) {
76
- focusAndMoveActive(lastItem);
97
+ updateHighlighted(lastItem);
77
98
  updateScroll(lastItem);
78
99
  }
79
100
  };
@@ -92,9 +113,6 @@ const useList = ({
92
113
  const select = useCallback(
93
114
  (event) => {
94
115
  const newValue = event.currentTarget.dataset.value;
95
- if (event.type === "click") {
96
- setShowFocusRing(false);
97
- }
98
116
  const activeOptions = getOptions();
99
117
  const isActiveOption = activeOptions.findIndex((i) => i.id === event.currentTarget.id) !== -1;
100
118
  if (newValue && selectedItem !== newValue && isActiveOption) {
@@ -105,44 +123,71 @@ const useList = ({
105
123
  [selectItem, selectedItem, onChange, getOptions]
106
124
  );
107
125
  const isSelected = useCallback(
108
- (id2) => selectedItem === id2,
126
+ (value) => selectedItem === value,
109
127
  [selectedItem]
110
128
  );
129
+ const highlight = useCallback(
130
+ (event) => {
131
+ setHighlightedItem(event.currentTarget.dataset.value);
132
+ },
133
+ [setHighlightedItem]
134
+ );
135
+ const isHighlighted = useCallback(
136
+ (value) => highlightedItem === value,
137
+ [highlightedItem]
138
+ );
111
139
  const isFocused = useCallback(
112
- (id2) => activeDescendant === id2 && showFocusRing,
113
- [activeDescendant, showFocusRing]
140
+ (value) => isHighlighted(value) && focusVisible,
141
+ [focusVisible, isHighlighted]
114
142
  );
115
143
  const getActiveItem = () => {
116
144
  const activeOptions = getOptions();
117
145
  const activeIndex = activeOptions.findIndex(
118
146
  (i) => i.id === activeDescendant
119
147
  );
120
- return activeOptions[activeIndex !== -1 ? activeIndex : 0];
148
+ return activeOptions[activeIndex];
121
149
  };
122
150
  const blurHandler = () => {
123
- setShowFocusRing(false);
151
+ handleBlurVisible();
152
+ if (!isFocusVisibleRef.current) {
153
+ setFocusVisible(false);
154
+ }
124
155
  };
125
- const mouseDownHandler = () => {
126
- setShowFocusRing(false);
156
+ const mouseOverHandler = () => {
157
+ if (focusVisible) {
158
+ setFocusVisible(false);
159
+ }
127
160
  };
128
- const focusHandler = () => {
161
+ const focusHandler = (event) => {
162
+ handleFocusVisible(event);
163
+ if (isFocusVisibleRef.current) {
164
+ setFocusVisible(true);
165
+ }
129
166
  const activeElement = getActiveItem();
130
- focusAndMoveActive(activeElement);
167
+ if (activeElement) {
168
+ updateHighlighted(activeElement);
169
+ } else {
170
+ focusFirstItem();
171
+ }
131
172
  };
132
173
  const keyDownHandler = (event) => {
133
174
  const { key } = event;
134
175
  const currentItem = getActiveItem();
135
176
  let nextItem = currentItem;
136
- if (!currentItem) {
137
- return;
177
+ if (isFocusVisibleRef.current || !focusVisible) {
178
+ setFocusVisible(true);
138
179
  }
139
180
  switch (key) {
140
181
  case "ArrowUp":
141
182
  case "ArrowDown":
183
+ if (!currentItem) {
184
+ focusFirstItem();
185
+ break;
186
+ }
142
187
  nextItem = key === "ArrowUp" ? findPreviousOption(currentItem, 1) : findNextOption(currentItem, 1);
143
188
  if (nextItem && nextItem !== currentItem) {
144
189
  event.preventDefault();
145
- focusAndMoveActive(nextItem);
190
+ updateHighlighted(nextItem);
146
191
  }
147
192
  break;
148
193
  case "Home":
@@ -156,7 +201,14 @@ const useList = ({
156
201
  case " ":
157
202
  case "Enter":
158
203
  event.preventDefault();
159
- nextItem && selectItem(nextItem);
204
+ if (nextItem) {
205
+ selectItem(nextItem);
206
+ onChange == null ? void 0 : onChange(event, { value: nextItem.dataset.value || "" });
207
+ }
208
+ break;
209
+ case "PageDown":
210
+ case "PageUp":
211
+ event.preventDefault();
160
212
  break;
161
213
  }
162
214
  };
@@ -166,17 +218,24 @@ const useList = ({
166
218
  id,
167
219
  select,
168
220
  isSelected,
169
- isFocused
221
+ isFocused,
222
+ highlight,
223
+ isHighlighted
170
224
  }),
171
- [disabled, id, select, isSelected, isFocused]
225
+ [disabled, id, select, isSelected, isFocused, highlight, isHighlighted]
172
226
  );
173
227
  return {
174
228
  focusHandler,
175
229
  keyDownHandler,
176
230
  blurHandler,
177
- mouseDownHandler,
231
+ mouseOverHandler,
178
232
  activeDescendant,
179
- contextValue
233
+ selectedItem,
234
+ highlightedItem,
235
+ setSelectedItem,
236
+ setHighlightedItem,
237
+ contextValue,
238
+ focusVisibleRef
180
239
  };
181
240
  };
182
241
 
@@ -1 +1 @@
1
- {"version":3,"file":"useList.js","sources":["../src/list-next/useList.ts"],"sourcesContent":["import {\n KeyboardEvent,\n RefObject,\n SyntheticEvent,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport { useControlled } from \"@salt-ds/core\";\n\ninterface UseListProps {\n /**\n * If true, all items in list will be disabled.\n */\n disabled?: boolean;\n /* Value for the uncontrolled version. */\n selected?: string;\n /* Initial value for the uncontrolled version. */\n defaultSelected?: string;\n /* Callback for the controlled version. */\n onChange?: (e: SyntheticEvent, data: { value: string }) => void;\n id?: string;\n ref: RefObject<HTMLUListElement>;\n}\n\nexport const useList = ({\n disabled = false,\n selected: selectedProp,\n defaultSelected,\n onChange,\n id,\n ref,\n}: UseListProps) => {\n const [activeDescendant, setActiveDescendant] = useState<string | undefined>(\n undefined\n );\n\n const [showFocusRing, setShowFocusRing] = useState<boolean>(false);\n const [selectedItem, setSelectedItem] = useControlled({\n controlled: selectedProp,\n default: defaultSelected,\n name: \"ListNext\",\n state: \"selected\",\n });\n\n const getOptions: () => HTMLElement[] = useCallback(() => {\n return Array.from(\n ref.current?.querySelectorAll('[role=\"option\"]:not([aria-disabled])') ??\n []\n );\n }, [ref]);\n\n const updateScroll = useCallback(\n (currentTarget: Element) => {\n const list = ref.current;\n if (!list || !currentTarget) return;\n const { offsetTop, offsetHeight } = currentTarget as HTMLLIElement;\n const listHeight = list?.clientHeight;\n const listScrollTop = list?.scrollTop;\n if (offsetTop < listScrollTop) {\n list.scrollTop = offsetTop;\n } else if (offsetTop + offsetHeight > listScrollTop + listHeight) {\n list.scrollTop = offsetTop + offsetHeight - listHeight;\n }\n },\n [ref]\n );\n\n const updateActiveDescendant = useCallback(\n (element: HTMLElement) => {\n setActiveDescendant(element.id);\n updateScroll(element);\n },\n [setActiveDescendant, updateScroll]\n );\n const selectItem = useCallback(\n (element: HTMLElement) => {\n const newValue = element?.dataset.value;\n if (newValue) {\n setSelectedItem(newValue);\n updateActiveDescendant(element);\n }\n },\n [setSelectedItem, updateActiveDescendant]\n );\n\n const focusAndMoveActive = (element: HTMLElement) => {\n setShowFocusRing(true);\n updateActiveDescendant(element);\n };\n\n const focusFirstItem = () => {\n // Find first active item\n const activeOptions = getOptions();\n const firstItem = activeOptions[0];\n if (firstItem) {\n focusAndMoveActive(firstItem);\n }\n };\n const focusLastItem = () => {\n // Find last active item\n const activeOptions = getOptions();\n const lastItem = activeOptions[activeOptions.length - 1];\n if (lastItem) {\n focusAndMoveActive(lastItem);\n updateScroll(lastItem);\n }\n };\n\n const findNextOption = (\n currentOption: HTMLElement | null,\n moves: number\n ): HTMLElement => {\n const activeOptions = getOptions();\n // Returns next item, if no current option it will return 0\n const nextOptionIndex = currentOption\n ? activeOptions.indexOf(currentOption) + moves\n : 0;\n return (\n activeOptions[nextOptionIndex] || activeOptions[activeOptions.length - 1]\n );\n };\n\n const findPreviousOption = (\n currentOption: HTMLElement,\n moves: number\n ): HTMLElement => {\n // Return the previous option if it exists; otherwise, returns first option\n const activeOptions = getOptions();\n const currentOptionIndex = activeOptions.findIndex(\n (i) => i.id === currentOption.id\n );\n return activeOptions[currentOptionIndex - moves] || activeOptions[0];\n };\n\n // CONTEXT CALLBACKS\n const select = useCallback(\n (event: SyntheticEvent<HTMLLIElement>) => {\n const newValue = event.currentTarget.dataset.value;\n if (event.type === \"click\") {\n setShowFocusRing(false);\n }\n const activeOptions = getOptions();\n const isActiveOption =\n activeOptions.findIndex((i) => i.id === event.currentTarget.id) !== -1;\n if (newValue && selectedItem !== newValue && isActiveOption) {\n selectItem(event.currentTarget);\n onChange?.(event, { value: newValue });\n }\n },\n [selectItem, selectedItem, onChange, getOptions]\n );\n\n const isSelected = useCallback(\n (id: string) => selectedItem === id,\n [selectedItem]\n );\n\n const isFocused = useCallback(\n (id: string | undefined) => activeDescendant === id && showFocusRing,\n [activeDescendant, showFocusRing]\n );\n\n const getActiveItem = () => {\n const activeOptions = getOptions();\n const activeIndex = activeOptions.findIndex(\n (i) => i.id === activeDescendant\n );\n return activeOptions[activeIndex !== -1 ? activeIndex : 0];\n };\n\n // HANDLERS\n const blurHandler = () => {\n setShowFocusRing(false);\n };\n\n const mouseDownHandler = () => {\n // When list gets focused, we can't guarantee that focus happens after click event.\n // If first focus (where !activeDescendant) happens from a click, list shouldn't render focus ring in the first element.\n setShowFocusRing(false);\n };\n\n // takes care of focus when using keyboard navigation\n const focusHandler = () => {\n const activeElement = getActiveItem();\n focusAndMoveActive(activeElement);\n };\n\n // takes care of keydown when using keyboard navigation\n const keyDownHandler = (event: KeyboardEvent<HTMLUListElement>) => {\n const { key } = event;\n const currentItem = getActiveItem();\n let nextItem = currentItem;\n if (!currentItem) {\n return;\n }\n switch (key) {\n case \"ArrowUp\":\n case \"ArrowDown\":\n nextItem =\n key === \"ArrowUp\"\n ? findPreviousOption(currentItem, 1)\n : findNextOption(currentItem, 1);\n\n if (nextItem && nextItem !== currentItem) {\n event.preventDefault();\n focusAndMoveActive(nextItem);\n }\n break;\n case \"Home\":\n event.preventDefault();\n focusFirstItem();\n break;\n case \"End\":\n event.preventDefault();\n focusLastItem();\n break;\n case \" \":\n case \"Enter\":\n event.preventDefault();\n nextItem && selectItem(nextItem);\n break;\n default:\n break;\n }\n };\n\n // CONTEXT\n const contextValue = useMemo(\n () => ({\n disabled,\n id,\n select,\n isSelected,\n isFocused,\n }),\n [disabled, id, select, isSelected, isFocused]\n );\n\n return {\n focusHandler,\n keyDownHandler,\n blurHandler,\n mouseDownHandler,\n activeDescendant,\n contextValue,\n };\n};\n"],"names":["id"],"mappings":";;;AAyBO,MAAM,UAAU,CAAC;AAAA,EACtB,QAAW,GAAA,KAAA;AAAA,EACX,QAAU,EAAA,YAAA;AAAA,EACV,eAAA;AAAA,EACA,QAAA;AAAA,EACA,EAAA;AAAA,EACA,GAAA;AACF,CAAoB,KAAA;AAClB,EAAM,MAAA,CAAC,gBAAkB,EAAA,mBAAmB,CAAI,GAAA,QAAA;AAAA,IAC9C,KAAA,CAAA;AAAA,GACF,CAAA;AAEA,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,SAAkB,KAAK,CAAA,CAAA;AACjE,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,aAAc,CAAA;AAAA,IACpD,UAAY,EAAA,YAAA;AAAA,IACZ,OAAS,EAAA,eAAA;AAAA,IACT,IAAM,EAAA,UAAA;AAAA,IACN,KAAO,EAAA,UAAA;AAAA,GACR,CAAA,CAAA;AAED,EAAM,MAAA,UAAA,GAAkC,YAAY,MAAM;AA7C5D,IAAA,IAAA,EAAA,EAAA,EAAA,CAAA;AA8CI,IAAA,OAAO,KAAM,CAAA,IAAA;AAAA,MAAA,CACX,eAAI,OAAJ,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAa,gBAAiB,CAAA,sCAAA,CAAA,KAA9B,YACE,EAAC;AAAA,KACL,CAAA;AAAA,GACF,EAAG,CAAC,GAAG,CAAC,CAAA,CAAA;AAER,EAAA,MAAM,YAAe,GAAA,WAAA;AAAA,IACnB,CAAC,aAA2B,KAAA;AAC1B,MAAA,MAAM,OAAO,GAAI,CAAA,OAAA,CAAA;AACjB,MAAI,IAAA,CAAC,QAAQ,CAAC,aAAA;AAAe,QAAA,OAAA;AAC7B,MAAM,MAAA,EAAE,SAAW,EAAA,YAAA,EAAiB,GAAA,aAAA,CAAA;AACpC,MAAA,MAAM,aAAa,IAAM,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,IAAA,CAAA,YAAA,CAAA;AACzB,MAAA,MAAM,gBAAgB,IAAM,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,IAAA,CAAA,SAAA,CAAA;AAC5B,MAAA,IAAI,YAAY,aAAe,EAAA;AAC7B,QAAA,IAAA,CAAK,SAAY,GAAA,SAAA,CAAA;AAAA,OACR,MAAA,IAAA,SAAA,GAAY,YAAe,GAAA,aAAA,GAAgB,UAAY,EAAA;AAChE,QAAK,IAAA,CAAA,SAAA,GAAY,YAAY,YAAe,GAAA,UAAA,CAAA;AAAA,OAC9C;AAAA,KACF;AAAA,IACA,CAAC,GAAG,CAAA;AAAA,GACN,CAAA;AAEA,EAAA,MAAM,sBAAyB,GAAA,WAAA;AAAA,IAC7B,CAAC,OAAyB,KAAA;AACxB,MAAA,mBAAA,CAAoB,QAAQ,EAAE,CAAA,CAAA;AAC9B,MAAA,YAAA,CAAa,OAAO,CAAA,CAAA;AAAA,KACtB;AAAA,IACA,CAAC,qBAAqB,YAAY,CAAA;AAAA,GACpC,CAAA;AACA,EAAA,MAAM,UAAa,GAAA,WAAA;AAAA,IACjB,CAAC,OAAyB,KAAA;AACxB,MAAM,MAAA,QAAA,GAAW,mCAAS,OAAQ,CAAA,KAAA,CAAA;AAClC,MAAA,IAAI,QAAU,EAAA;AACZ,QAAA,eAAA,CAAgB,QAAQ,CAAA,CAAA;AACxB,QAAA,sBAAA,CAAuB,OAAO,CAAA,CAAA;AAAA,OAChC;AAAA,KACF;AAAA,IACA,CAAC,iBAAiB,sBAAsB,CAAA;AAAA,GAC1C,CAAA;AAEA,EAAM,MAAA,kBAAA,GAAqB,CAAC,OAAyB,KAAA;AACnD,IAAA,gBAAA,CAAiB,IAAI,CAAA,CAAA;AACrB,IAAA,sBAAA,CAAuB,OAAO,CAAA,CAAA;AAAA,GAChC,CAAA;AAEA,EAAA,MAAM,iBAAiB,MAAM;AAE3B,IAAA,MAAM,gBAAgB,UAAW,EAAA,CAAA;AACjC,IAAA,MAAM,YAAY,aAAc,CAAA,CAAA,CAAA,CAAA;AAChC,IAAA,IAAI,SAAW,EAAA;AACb,MAAA,kBAAA,CAAmB,SAAS,CAAA,CAAA;AAAA,KAC9B;AAAA,GACF,CAAA;AACA,EAAA,MAAM,gBAAgB,MAAM;AAE1B,IAAA,MAAM,gBAAgB,UAAW,EAAA,CAAA;AACjC,IAAM,MAAA,QAAA,GAAW,aAAc,CAAA,aAAA,CAAc,MAAS,GAAA,CAAA,CAAA,CAAA;AACtD,IAAA,IAAI,QAAU,EAAA;AACZ,MAAA,kBAAA,CAAmB,QAAQ,CAAA,CAAA;AAC3B,MAAA,YAAA,CAAa,QAAQ,CAAA,CAAA;AAAA,KACvB;AAAA,GACF,CAAA;AAEA,EAAM,MAAA,cAAA,GAAiB,CACrB,aAAA,EACA,KACgB,KAAA;AAChB,IAAA,MAAM,gBAAgB,UAAW,EAAA,CAAA;AAEjC,IAAA,MAAM,kBAAkB,aACpB,GAAA,aAAA,CAAc,OAAQ,CAAA,aAAa,IAAI,KACvC,GAAA,CAAA,CAAA;AACJ,IAAA,OACE,aAAc,CAAA,eAAA,CAAA,IAAoB,aAAc,CAAA,aAAA,CAAc,MAAS,GAAA,CAAA,CAAA,CAAA;AAAA,GAE3E,CAAA;AAEA,EAAM,MAAA,kBAAA,GAAqB,CACzB,aAAA,EACA,KACgB,KAAA;AAEhB,IAAA,MAAM,gBAAgB,UAAW,EAAA,CAAA;AACjC,IAAA,MAAM,qBAAqB,aAAc,CAAA,SAAA;AAAA,MACvC,CAAC,CAAA,KAAM,CAAE,CAAA,EAAA,KAAO,aAAc,CAAA,EAAA;AAAA,KAChC,CAAA;AACA,IAAO,OAAA,aAAA,CAAc,kBAAqB,GAAA,KAAA,CAAA,IAAU,aAAc,CAAA,CAAA,CAAA,CAAA;AAAA,GACpE,CAAA;AAGA,EAAA,MAAM,MAAS,GAAA,WAAA;AAAA,IACb,CAAC,KAAyC,KAAA;AACxC,MAAM,MAAA,QAAA,GAAW,KAAM,CAAA,aAAA,CAAc,OAAQ,CAAA,KAAA,CAAA;AAC7C,MAAI,IAAA,KAAA,CAAM,SAAS,OAAS,EAAA;AAC1B,QAAA,gBAAA,CAAiB,KAAK,CAAA,CAAA;AAAA,OACxB;AACA,MAAA,MAAM,gBAAgB,UAAW,EAAA,CAAA;AACjC,MAAM,MAAA,cAAA,GACJ,aAAc,CAAA,SAAA,CAAU,CAAC,CAAA,KAAM,EAAE,EAAO,KAAA,KAAA,CAAM,aAAc,CAAA,EAAE,CAAM,KAAA,CAAA,CAAA,CAAA;AACtE,MAAI,IAAA,QAAA,IAAY,YAAiB,KAAA,QAAA,IAAY,cAAgB,EAAA;AAC3D,QAAA,UAAA,CAAW,MAAM,aAAa,CAAA,CAAA;AAC9B,QAAW,QAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,QAAA,CAAA,KAAA,EAAO,EAAE,KAAA,EAAO,QAAS,EAAA,CAAA,CAAA;AAAA,OACtC;AAAA,KACF;AAAA,IACA,CAAC,UAAA,EAAY,YAAc,EAAA,QAAA,EAAU,UAAU,CAAA;AAAA,GACjD,CAAA;AAEA,EAAA,MAAM,UAAa,GAAA,WAAA;AAAA,IACjB,CAACA,QAAe,YAAiBA,KAAAA,GAAAA;AAAA,IACjC,CAAC,YAAY,CAAA;AAAA,GACf,CAAA;AAEA,EAAA,MAAM,SAAY,GAAA,WAAA;AAAA,IAChB,CAACA,GAA2B,KAAA,gBAAA,KAAqBA,GAAM,IAAA,aAAA;AAAA,IACvD,CAAC,kBAAkB,aAAa,CAAA;AAAA,GAClC,CAAA;AAEA,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,MAAM,gBAAgB,UAAW,EAAA,CAAA;AACjC,IAAA,MAAM,cAAc,aAAc,CAAA,SAAA;AAAA,MAChC,CAAC,CAAM,KAAA,CAAA,CAAE,EAAO,KAAA,gBAAA;AAAA,KAClB,CAAA;AACA,IAAO,OAAA,aAAA,CAAc,WAAgB,KAAA,CAAA,CAAA,GAAK,WAAc,GAAA,CAAA,CAAA,CAAA;AAAA,GAC1D,CAAA;AAGA,EAAA,MAAM,cAAc,MAAM;AACxB,IAAA,gBAAA,CAAiB,KAAK,CAAA,CAAA;AAAA,GACxB,CAAA;AAEA,EAAA,MAAM,mBAAmB,MAAM;AAG7B,IAAA,gBAAA,CAAiB,KAAK,CAAA,CAAA;AAAA,GACxB,CAAA;AAGA,EAAA,MAAM,eAAe,MAAM;AACzB,IAAA,MAAM,gBAAgB,aAAc,EAAA,CAAA;AACpC,IAAA,kBAAA,CAAmB,aAAa,CAAA,CAAA;AAAA,GAClC,CAAA;AAGA,EAAM,MAAA,cAAA,GAAiB,CAAC,KAA2C,KAAA;AACjE,IAAM,MAAA,EAAE,KAAQ,GAAA,KAAA,CAAA;AAChB,IAAA,MAAM,cAAc,aAAc,EAAA,CAAA;AAClC,IAAA,IAAI,QAAW,GAAA,WAAA,CAAA;AACf,IAAA,IAAI,CAAC,WAAa,EAAA;AAChB,MAAA,OAAA;AAAA,KACF;AACA,IAAQ,QAAA,GAAA;AAAA,MACD,KAAA,SAAA,CAAA;AAAA,MACA,KAAA,WAAA;AACH,QACE,QAAA,GAAA,GAAA,KAAQ,YACJ,kBAAmB,CAAA,WAAA,EAAa,CAAC,CACjC,GAAA,cAAA,CAAe,aAAa,CAAC,CAAA,CAAA;AAEnC,QAAI,IAAA,QAAA,IAAY,aAAa,WAAa,EAAA;AACxC,UAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,UAAA,kBAAA,CAAmB,QAAQ,CAAA,CAAA;AAAA,SAC7B;AACA,QAAA,MAAA;AAAA,MACG,KAAA,MAAA;AACH,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAe,cAAA,EAAA,CAAA;AACf,QAAA,MAAA;AAAA,MACG,KAAA,KAAA;AACH,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAc,aAAA,EAAA,CAAA;AACd,QAAA,MAAA;AAAA,MACG,KAAA,GAAA,CAAA;AAAA,MACA,KAAA,OAAA;AACH,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAA,QAAA,IAAY,WAAW,QAAQ,CAAA,CAAA;AAC/B,QAAA,MAAA;AAEA,KAAA;AAAA,GAEN,CAAA;AAGA,EAAA,MAAM,YAAe,GAAA,OAAA;AAAA,IACnB,OAAO;AAAA,MACL,QAAA;AAAA,MACA,EAAA;AAAA,MACA,MAAA;AAAA,MACA,UAAA;AAAA,MACA,SAAA;AAAA,KACF,CAAA;AAAA,IACA,CAAC,QAAA,EAAU,EAAI,EAAA,MAAA,EAAQ,YAAY,SAAS,CAAA;AAAA,GAC9C,CAAA;AAEA,EAAO,OAAA;AAAA,IACL,YAAA;AAAA,IACA,cAAA;AAAA,IACA,WAAA;AAAA,IACA,gBAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAA;AAAA,GACF,CAAA;AACF;;;;"}
1
+ {"version":3,"file":"useList.js","sources":["../src/list-next/useList.ts"],"sourcesContent":["import {\n FocusEvent,\n KeyboardEvent,\n RefObject,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { useControlled, useIsFocusVisible } from \"@salt-ds/core\";\n\nexport interface UseListProps {\n /**\n * If true, all items in list will be disabled.\n */\n disabled?: boolean;\n /* Highlighted index for when the list is controlled. */\n highlightedItem?: string;\n /* Selected value for when the list is controlled. */\n selected?: string;\n /* Initial selected value for when the list is controlled. */\n defaultSelected?: string;\n /* Callback for when the list is controlled. */\n onChange?: (e: SyntheticEvent, data: { value: string }) => void;\n /* List id. */\n id?: string;\n /* List ref. */\n ref: RefObject<HTMLUListElement>;\n}\n\nexport const useList = ({\n disabled = false,\n highlightedItem: highLightedItemProp,\n selected: selectedProp,\n defaultSelected,\n onChange,\n id,\n ref,\n}: UseListProps) => {\n const getOptions: () => HTMLElement[] = useCallback(() => {\n return Array.from(\n ref.current?.querySelectorAll('[role=\"option\"]:not([aria-disabled])') ??\n []\n );\n }, [ref]);\n\n const [focusVisible, setFocusVisible] = useState(false);\n const [activeDescendant, setActiveDescendant] = useState<string | undefined>(\n undefined\n );\n\n const [highlightedItem, setHighlightedItem] = useControlled({\n controlled: highLightedItemProp,\n default: highLightedItemProp,\n name: \"ListNext\",\n state: \"highlighted\",\n });\n\n const [selectedItem, setSelectedItem] = useControlled({\n controlled: selectedProp,\n default: defaultSelected,\n name: \"ListNext\",\n state: \"selected\",\n });\n\n const {\n isFocusVisibleRef,\n onFocus: handleFocusVisible,\n onBlur: handleBlurVisible,\n ref: focusVisibleRef,\n } = useIsFocusVisible();\n\n const updateScroll = useCallback(\n (currentTarget: Element) => {\n const list = ref.current;\n if (!list || !currentTarget) return;\n const { offsetTop, offsetHeight } = currentTarget as HTMLLIElement;\n const listHeight = list?.clientHeight;\n const listScrollTop = list?.scrollTop;\n if (offsetTop < listScrollTop) {\n list.scrollTop = offsetTop;\n } else if (offsetTop + offsetHeight > listScrollTop + listHeight) {\n list.scrollTop = offsetTop + offsetHeight - listHeight;\n }\n },\n [ref]\n );\n\n const updateHighlighted = useCallback(\n (element: HTMLElement) => {\n setHighlightedItem(element.dataset.value);\n setActiveDescendant(element.id);\n updateScroll(element);\n },\n [setHighlightedItem, updateScroll]\n );\n\n const selectItem = useCallback(\n (element: HTMLElement) => {\n const newValue = element?.dataset.value;\n if (newValue) {\n setSelectedItem(newValue);\n updateHighlighted(element);\n }\n },\n [setSelectedItem, updateHighlighted]\n );\n\n // Effect to move the cursor when items change controlled.\n // this could be following active descendant if there is no better way of doing it when controlled\n useEffect(() => {\n const activeOptions = getOptions();\n const highlightedIndex = activeOptions.findIndex(\n (i) => i.dataset.value === highlightedItem\n );\n if (highlightedIndex) {\n setActiveDescendant(activeOptions[highlightedIndex]?.id);\n highlightedItem && updateScroll(activeOptions[highlightedIndex]);\n }\n }, [highlightedItem, getOptions, updateScroll]);\n\n const focusFirstItem = () => {\n // Find first active item\n const activeOptions = getOptions();\n const firstItem = activeOptions[0];\n if (firstItem) {\n updateHighlighted(firstItem);\n }\n };\n const focusLastItem = () => {\n // Find last active item\n const activeOptions = getOptions();\n const lastItem = activeOptions[activeOptions.length - 1];\n if (lastItem) {\n updateHighlighted(lastItem);\n updateScroll(lastItem);\n }\n };\n\n const findNextOption = (\n currentOption: HTMLElement | null,\n moves: number\n ): HTMLElement => {\n const activeOptions = getOptions();\n // Returns next item, if no current option it will return 0\n const nextOptionIndex = currentOption\n ? activeOptions.indexOf(currentOption) + moves\n : 0;\n return (\n activeOptions[nextOptionIndex] || activeOptions[activeOptions.length - 1]\n );\n };\n\n const findPreviousOption = (\n currentOption: HTMLElement,\n moves: number\n ): HTMLElement => {\n // Return the previous option if it exists; otherwise, returns first option\n const activeOptions = getOptions();\n const currentOptionIndex = activeOptions.findIndex(\n (i) => i.id === currentOption.id\n );\n return activeOptions[currentOptionIndex - moves] || activeOptions[0];\n };\n\n // CONTEXT CALLBACKS\n const select = useCallback(\n (event: SyntheticEvent<HTMLLIElement>) => {\n const newValue = event.currentTarget.dataset.value;\n const activeOptions = getOptions();\n const isActiveOption =\n activeOptions.findIndex((i) => i.id === event.currentTarget.id) !== -1;\n if (newValue && selectedItem !== newValue && isActiveOption) {\n selectItem(event.currentTarget);\n onChange?.(event, { value: newValue });\n }\n },\n [selectItem, selectedItem, onChange, getOptions]\n );\n\n const isSelected = useCallback(\n (value: string) => selectedItem === value,\n [selectedItem]\n );\n\n const highlight = useCallback(\n (event: SyntheticEvent<HTMLLIElement>) => {\n setHighlightedItem(event.currentTarget.dataset.value);\n },\n [setHighlightedItem]\n );\n\n const isHighlighted = useCallback(\n (value: string) => highlightedItem === value,\n [highlightedItem]\n );\n\n const isFocused = useCallback(\n (value: string) => isHighlighted(value) && focusVisible,\n [focusVisible, isHighlighted]\n );\n\n const getActiveItem = () => {\n const activeOptions = getOptions();\n const activeIndex = activeOptions.findIndex(\n (i) => i.id === activeDescendant\n );\n return activeOptions[activeIndex];\n };\n\n // HANDLERS\n const blurHandler = () => {\n handleBlurVisible();\n if (!isFocusVisibleRef.current) {\n setFocusVisible(false);\n }\n };\n\n const mouseOverHandler = () => {\n if (focusVisible) {\n setFocusVisible(false);\n }\n };\n\n // takes care of focus when using keyboard navigation\n const focusHandler = (event: FocusEvent<HTMLUListElement | HTMLElement>) => {\n handleFocusVisible(event);\n if (isFocusVisibleRef.current) {\n setFocusVisible(true);\n }\n const activeElement = getActiveItem();\n if (activeElement) {\n updateHighlighted(activeElement);\n } else {\n focusFirstItem();\n }\n };\n\n // takes care of keydown when using keyboard navigation\n const keyDownHandler = (event: KeyboardEvent<HTMLElement>) => {\n const { key } = event;\n const currentItem = getActiveItem();\n let nextItem = currentItem;\n if (isFocusVisibleRef.current || !focusVisible) {\n setFocusVisible(true);\n }\n switch (key) {\n case \"ArrowUp\":\n case \"ArrowDown\":\n if (!currentItem) {\n focusFirstItem();\n break;\n }\n nextItem =\n key === \"ArrowUp\"\n ? findPreviousOption(currentItem, 1)\n : findNextOption(currentItem, 1);\n\n if (nextItem && nextItem !== currentItem) {\n event.preventDefault();\n updateHighlighted(nextItem);\n }\n break;\n case \"Home\":\n event.preventDefault();\n focusFirstItem();\n break;\n case \"End\":\n event.preventDefault();\n focusLastItem();\n break;\n case \" \":\n case \"Enter\":\n event.preventDefault();\n if (nextItem) {\n selectItem(nextItem);\n onChange?.(event, { value: nextItem.dataset.value || \"\" });\n }\n break;\n case \"PageDown\":\n case \"PageUp\":\n event.preventDefault();\n break;\n default:\n break;\n }\n };\n\n // CONTEXT\n const contextValue = useMemo(\n () => ({\n disabled,\n id,\n select,\n isSelected,\n isFocused,\n highlight,\n isHighlighted,\n }),\n [disabled, id, select, isSelected, isFocused, highlight, isHighlighted]\n );\n\n return {\n focusHandler,\n keyDownHandler,\n blurHandler,\n mouseOverHandler,\n activeDescendant,\n selectedItem,\n highlightedItem,\n setSelectedItem,\n setHighlightedItem,\n contextValue,\n focusVisibleRef,\n };\n};\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- var css_248z = "/* Styles for Logo */\n.saltLogo {\n display: inline-flex;\n position: relative;\n align-items: center;\n justify-content: center;\n height: var(--salt-size-base);\n}\n\n.saltLogo svg {\n fill: var(--salt-text-secondary-foreground);\n stroke: none;\n}\n";
1
+ var css_248z = "/* Styles for Logo */\n.saltLogo {\n display: inline-flex;\n position: relative;\n align-items: center;\n justify-content: center;\n height: var(--salt-size-base);\n gap: var(--salt-spacing-100);\n}\n\n.saltLogo svg {\n fill: var(--salt-text-secondary-foreground);\n stroke: none;\n}\n";
2
2
 
3
3
  export { css_248z as default };
4
4
  //# sourceMappingURL=Logo.css.js.map
@@ -0,0 +1,4 @@
1
+ var css_248z = "/* Styles for LogoImage */\n.saltLogoImage {\n max-height: 100%;\n}\n";
2
+
3
+ export { css_248z as default };
4
+ //# sourceMappingURL=LogoImage.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogoImage.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -2,11 +2,20 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import { forwardRef } from 'react';
3
3
  import { clsx } from 'clsx';
4
4
  import { makePrefixer } from '@salt-ds/core';
5
+ import { useWindow } from '@salt-ds/window';
6
+ import { useComponentCssInjection } from '@salt-ds/styles';
7
+ import css_248z from './LogoImage.css.js';
5
8
 
6
9
  const withBaseName = makePrefixer("saltLogoImage");
7
10
  const LogoImage = forwardRef(
8
11
  function LogoImage2(props, ref) {
9
12
  const { className, alt, ...rest } = props;
13
+ const targetWindow = useWindow();
14
+ useComponentCssInjection({
15
+ testId: "salt-logo-image",
16
+ css: css_248z,
17
+ window: targetWindow
18
+ });
10
19
  return /* @__PURE__ */ jsx("img", {
11
20
  ...rest,
12
21
  alt,
@@ -1 +1 @@
1
- {"version":3,"file":"LogoImage.js","sources":["../src/logo/LogoImage.tsx"],"sourcesContent":["import { ComponentPropsWithoutRef, forwardRef } from \"react\";\nimport { clsx } from \"clsx\";\nimport { makePrefixer } from \"@salt-ds/core\";\n\nexport interface LogoImageProps\n extends Omit<ComponentPropsWithoutRef<\"img\">, \"alt\"> {\n alt: string;\n}\n\nconst withBaseName = makePrefixer(\"saltLogoImage\");\n\nexport const LogoImage = forwardRef<HTMLImageElement, LogoImageProps>(\n function LogoImage(props, ref) {\n const { className, alt, ...rest } = props;\n\n return (\n <img\n {...rest}\n alt={alt}\n className={clsx(withBaseName(), className)}\n ref={ref}\n />\n );\n }\n);\n"],"names":["LogoImage"],"mappings":";;;;;AASA,MAAM,YAAA,GAAe,aAAa,eAAe,CAAA,CAAA;AAE1C,MAAM,SAAY,GAAA,UAAA;AAAA,EACvB,SAASA,UAAU,CAAA,KAAA,EAAO,GAAK,EAAA;AAC7B,IAAA,MAAM,EAAE,SAAA,EAAW,GAAQ,EAAA,GAAA,IAAA,EAAS,GAAA,KAAA,CAAA;AAEpC,IAAA,uBACG,GAAA,CAAA,KAAA,EAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,GAAA;AAAA,MACA,SAAW,EAAA,IAAA,CAAK,YAAa,EAAA,EAAG,SAAS,CAAA;AAAA,MACzC,GAAA;AAAA,KACF,CAAA,CAAA;AAAA,GAEJ;AACF;;;;"}
1
+ {"version":3,"file":"LogoImage.js","sources":["../src/logo/LogoImage.tsx"],"sourcesContent":["import { ComponentPropsWithoutRef, forwardRef } from \"react\";\nimport { clsx } from \"clsx\";\nimport { makePrefixer } from \"@salt-ds/core\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport logoImageCss from \"./LogoImage.css\";\n\nexport interface LogoImageProps\n extends Omit<ComponentPropsWithoutRef<\"img\">, \"alt\"> {\n alt: string;\n}\n\nconst withBaseName = makePrefixer(\"saltLogoImage\");\n\nexport const LogoImage = forwardRef<HTMLImageElement, LogoImageProps>(\n function LogoImage(props, ref) {\n const { className, alt, ...rest } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-logo-image\",\n css: logoImageCss,\n window: targetWindow,\n });\n\n return (\n <img\n {...rest}\n alt={alt}\n className={clsx(withBaseName(), className)}\n ref={ref}\n />\n );\n }\n);\n"],"names":["LogoImage","logoImageCss"],"mappings":";;;;;;;;AAYA,MAAM,YAAA,GAAe,aAAa,eAAe,CAAA,CAAA;AAE1C,MAAM,SAAY,GAAA,UAAA;AAAA,EACvB,SAASA,UAAU,CAAA,KAAA,EAAO,GAAK,EAAA;AAC7B,IAAA,MAAM,EAAE,SAAA,EAAW,GAAQ,EAAA,GAAA,IAAA,EAAS,GAAA,KAAA,CAAA;AAEpC,IAAA,MAAM,eAAe,SAAU,EAAA,CAAA;AAC/B,IAAyB,wBAAA,CAAA;AAAA,MACvB,MAAQ,EAAA,iBAAA;AAAA,MACR,GAAK,EAAAC,QAAA;AAAA,MACL,MAAQ,EAAA,YAAA;AAAA,KACT,CAAA,CAAA;AAED,IAAA,uBACG,GAAA,CAAA,KAAA,EAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,GAAA;AAAA,MACA,SAAW,EAAA,IAAA,CAAK,YAAa,EAAA,EAAG,SAAS,CAAA;AAAA,MACzC,GAAA;AAAA,KACF,CAAA,CAAA;AAAA,GAEJ;AACF;;;;"}
@@ -1,4 +1,4 @@
1
- var css_248z = "/* Styles for LogoSeparator */\n.saltLogoSeparator {\n height: var(--salt-size-separator-height);\n margin: 0 var(--salt-spacing-100);\n border-right: var(--salt-size-border) var(--salt-separable-borderStyle) var(--salt-separable-primary-borderColor);\n}\n";
1
+ var css_248z = "/* Styles for LogoSeparator */\n.saltLogoSeparator {\n height: var(--salt-size-separator-height);\n border-right: var(--salt-size-border) var(--salt-separable-borderStyle) var(--salt-separable-primary-borderColor);\n}\n";
2
2
 
3
3
  export { css_248z as default };
4
4
  //# sourceMappingURL=LogoSeparator.css.js.map
@@ -0,0 +1,27 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { ChevronDownIcon, ChevronRightIcon } from '@salt-ds/icons';
3
+
4
+ const iconExpansionMap = {
5
+ vertical: {
6
+ expanded: ChevronDownIcon,
7
+ collapsed: ChevronRightIcon
8
+ },
9
+ horizontal: {
10
+ expanded: ChevronDownIcon,
11
+ collapsed: ChevronDownIcon
12
+ }
13
+ };
14
+ function ExpansionIcon({
15
+ expanded = false,
16
+ orientation = "horizontal",
17
+ className
18
+ }) {
19
+ const Icon = iconExpansionMap[orientation][expanded ? "expanded" : "collapsed"];
20
+ return /* @__PURE__ */ jsx(Icon, {
21
+ "aria-hidden": "true",
22
+ className
23
+ });
24
+ }
25
+
26
+ export { ExpansionIcon };
27
+ //# sourceMappingURL=ExpansionIcon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpansionIcon.js","sources":["../src/navigation-item/ExpansionIcon.tsx"],"sourcesContent":["import { ChevronDownIcon, ChevronRightIcon } from \"@salt-ds/icons\";\nimport { NavigationItemProps } from \"./NavigationItem\";\n\nconst iconExpansionMap = {\n vertical: {\n expanded: ChevronDownIcon,\n collapsed: ChevronRightIcon,\n },\n horizontal: {\n expanded: ChevronDownIcon,\n collapsed: ChevronDownIcon,\n },\n};\n\nexport function ExpansionIcon({\n expanded = false,\n orientation = \"horizontal\",\n className,\n}: Pick<NavigationItemProps, \"expanded\" | \"orientation\" | \"className\">) {\n const Icon =\n iconExpansionMap[orientation][expanded ? \"expanded\" : \"collapsed\"];\n return <Icon aria-hidden=\"true\" className={className} />;\n}\n"],"names":[],"mappings":";;;AAGA,MAAM,gBAAmB,GAAA;AAAA,EACvB,QAAU,EAAA;AAAA,IACR,QAAU,EAAA,eAAA;AAAA,IACV,SAAW,EAAA,gBAAA;AAAA,GACb;AAAA,EACA,UAAY,EAAA;AAAA,IACV,QAAU,EAAA,eAAA;AAAA,IACV,SAAW,EAAA,eAAA;AAAA,GACb;AACF,CAAA,CAAA;AAEO,SAAS,aAAc,CAAA;AAAA,EAC5B,QAAW,GAAA,KAAA;AAAA,EACX,WAAc,GAAA,YAAA;AAAA,EACd,SAAA;AACF,CAAwE,EAAA;AACtE,EAAA,MAAM,IACJ,GAAA,gBAAA,CAAiB,WAAa,CAAA,CAAA,QAAA,GAAW,UAAa,GAAA,WAAA,CAAA,CAAA;AACxD,EAAA,uBAAQ,GAAA,CAAA,IAAA,EAAA;AAAA,IAAK,aAAY,EAAA,MAAA;AAAA,IAAO,SAAA;AAAA,GAAsB,CAAA,CAAA;AACxD;;;;"}
@@ -0,0 +1,4 @@
1
+ var css_248z = "/* Vars applied to root NavigationItem component */\n.saltNavigationItem {\n --navigationItem-color: var(--salt-text-secondary-foreground);\n --navigationItem-fill: var(--salt-text-secondary-foreground);\n --navigationItem-bar-inset: var(--salt-spacing-25);\n --navigationItem-bar-size: calc(var(--salt-size-bar) / 2);\n --navigationItem-indicator-background: var(--salt-navigable-indicator-active);\n --navigationItem-gap: var(--salt-spacing-100);\n}\n\n/* Vars applied to NavigationItem component when active or selected */\n.saltNavigationItem-active,\n.saltNavigationItem-blurSelected {\n --navigationItem-color: var(--salt-text-primary-foreground);\n --navigationItem-fill: var(--salt-text-primary-foreground);\n}\n\n/* Styles applied to NavigationItem wrapper */\n.saltNavigationItem-wrapper {\n display: flex;\n align-items: center;\n position: relative;\n gap: var(--navigationItem-gap);\n font-weight: var(--salt-text-fontWeight-strong);\n text-decoration: none;\n /* Hover off animation */\n transition: all var(--salt-duration-instant) ease-in-out;\n}\n\n/* Styles applied to NavigationItem link */\n.saltNavigationItem-wrapper.saltLink {\n --link-textDecoration: none;\n}\n\n/* Styles applied to NavigationItem icon */\n.saltNavigationItem-wrapper .saltIcon {\n fill: var(--navigationItem-fill);\n}\n\n/* Styles applied to NavigationItem Badge */\n.saltNavigationItem-label .saltBadge {\n margin-left: auto;\n}\n\n/* Styles applied to root NavigationItem component */\n.saltNavigationItem {\n margin: 0 var(--navigationItem-gap);\n}\n\n/* Styles applied when orientation = \"horizontal\" */\n.saltNavigationItem-wrapper.saltNavigationItem-horizontal {\n min-height: calc(var(--salt-size-base) + var(--navigationItem-gap) + var(--navigationItem-gap));\n padding: calc(var(--navigationItem-gap) + var(--navigationItem-bar-inset)) 0 var(--navigationItem-gap) 0;\n width: fit-content;\n}\n\n/* Styles applied when orientation = \"vertical\" */\n.saltNavigationItem-wrapper.saltNavigationItem-vertical {\n min-height: calc(var(--salt-size-base));\n padding-left: calc(var(--navigationItem-gap) + var(--navigationItem-bar-inset));\n padding-right: var(--navigationItem-gap);\n margin: var(--salt-spacing-50) 0;\n}\n\n/* Styles applied to NavigationItem label */\n.saltNavigationItem-wrapper .saltNavigationItem-label {\n --link-color-visited: var(--navigationItem-color);\n --link-color-hover: var(--navigationItem-color);\n\n color: var(--navigationItem-color);\n line-height: var(--salt-text-lineHeight);\n font-family: var(--salt-text-fontFamily);\n padding-left: calc(var(--saltNavigationItem-level, 0) * var(--navigationItem-gap));\n flex: 1;\n text-align: left;\n display: flex;\n align-items: center;\n gap: var(--navigationItem-gap);\n}\n\n/* Styles applied when level is not 0 */\n.saltNavigationItem-wrapper.saltNavigationItem-nested {\n font-weight: var(--salt-text-fontWeight);\n padding-left: calc(var(--salt-spacing-250) + (var(--saltNavigationItem-level, 0) * var(--navigationItem-gap)));\n}\n\n/* Styles applied to expand button */\n.saltNavigationItem-wrapper.saltNavigationItem-expandButton {\n --saltButton-background-hover: none;\n --saltButton-background-active: none;\n --saltButton-textTransform: none;\n --saltButton-width: 100%;\n --saltButton-letterSpacing: none;\n\n gap: var(--navigationItem-gap);\n /* Required to match link's outline offset */\n outline-offset: var(--salt-size-border);\n}\n\n/* Styles applied to expand icon */\n.saltNavigationItem-wrapper .saltNavigationItem-expandIcon {\n --saltIcon-color: var(--navigationItem-fill);\n}\n\n/* Styles applied to NavigationItem when focus is visible */\n.saltNavigationItem-wrapper:focus-visible {\n outline: var(--salt-focused-outline);\n}\n\n/* Styles applied to NavigationItem when when orientation = \"horizontal\" and focus is visible */\n.saltNavigationItem-horizontal:focus-visible {\n border-right: var(--navigationItem-gap) solid transparent;\n border-left: var(--navigationItem-gap) solid transparent;\n margin: 0 calc(var(--navigationItem-gap) * -1);\n}\n\n/* Styles applied to NavigationItem for non-keyboard focus */\n.saltNavigationItem-wrapper:focus:not(:focus-visible) {\n outline: 0;\n}\n\n/* Styles applied to activation line */\n.saltNavigationItem-wrapper::after {\n content: \"\";\n position: absolute;\n top: 0;\n left: 0;\n display: block;\n}\n\n/* Styles applied to activation line when orientation = \"horizontal\" */\n.saltNavigationItem-horizontal::after {\n width: 100%;\n height: var(--navigationItem-bar-size);\n top: var(--navigationItem-bar-inset);\n}\n\n/* Styles applied to activation line when orientation = \"vertical\" */\n.saltNavigationItem-vertical::after {\n width: var(--navigationItem-bar-size);\n left: var(--navigationItem-bar-inset);\n top: var(--navigationItem-bar-inset);\n height: calc(100% - var(--salt-spacing-50));\n}\n\n/* Styles applied to activation line on hover and on focus */\n.saltNavigationItem-wrapper:hover::after,\n.saltNavigationItem-wrapper:focus::after {\n background: var(--salt-navigable-indicator-hover);\n /* Hover on animation */\n transition: all var(--salt-duration-perceptible) ease-in-out;\n}\n\n/* Styles applied to activation line when item has active children */\n.saltNavigationItem-wrapper.saltNavigationItem-blurSelected::after,\n.saltNavigationItem-wrapper.saltNavigationItem-blurSelected:hover::after,\n.saltNavigationItem-wrapper.saltNavigationItem-blurSelected:focus::after {\n --navigationItem-indicator-background: none;\n}\n\n/* Styles applied to activation line when item is active */\n.saltNavigationItem-wrapper.saltNavigationItem-active::after,\n.saltNavigationItem-wrapper.saltNavigationItem-active:hover::after,\n.saltNavigationItem-wrapper.saltNavigationItem-active:focus::after {\n background: var(--navigationItem-indicator-background);\n /* Hover on animation */\n transition: all var(--salt-duration-perceptible) ease-in-out;\n}\n";
2
+
3
+ export { css_248z as default };
4
+ //# sourceMappingURL=NavigationItem.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavigationItem.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -0,0 +1,92 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { forwardRef } from 'react';
3
+ import { makePrefixer, Button, Link } from '@salt-ds/core';
4
+ import { clsx } from 'clsx';
5
+ import { ExpansionIcon } from './ExpansionIcon.js';
6
+ import css_248z from './NavigationItem.css.js';
7
+ import { useWindow } from '@salt-ds/window';
8
+ import { useComponentCssInjection } from '@salt-ds/styles';
9
+
10
+ const withBaseName = makePrefixer("saltNavigationItem");
11
+ const NavigationItem = forwardRef(
12
+ function NavigationItem2(props, ref) {
13
+ const {
14
+ active,
15
+ blurSelected,
16
+ children,
17
+ className,
18
+ expanded = false,
19
+ orientation = "horizontal",
20
+ parent,
21
+ level = 0,
22
+ onExpand,
23
+ href,
24
+ style: styleProp,
25
+ ...rest
26
+ } = props;
27
+ const targetWindow = useWindow();
28
+ useComponentCssInjection({
29
+ testId: "salt-navigation-item",
30
+ css: css_248z,
31
+ window: targetWindow
32
+ });
33
+ const style = {
34
+ ...styleProp,
35
+ "--saltNavigationItem-level": `${level}`
36
+ };
37
+ const handleExpand = (event) => {
38
+ event.stopPropagation();
39
+ onExpand == null ? void 0 : onExpand(event);
40
+ };
41
+ const ConditionalWrapper = ({
42
+ children: children2,
43
+ className: className2,
44
+ ...rest2
45
+ }) => parent ? /* @__PURE__ */ jsx(Button, {
46
+ "aria-label": "expand",
47
+ variant: "secondary",
48
+ "aria-expanded": expanded,
49
+ className: clsx(withBaseName("expandButton"), className2),
50
+ onClick: handleExpand,
51
+ ...rest2,
52
+ children: children2
53
+ }) : /* @__PURE__ */ jsx(Link, {
54
+ "aria-current": active ? "page" : void 0,
55
+ href,
56
+ className: className2,
57
+ ...rest2,
58
+ children: children2
59
+ });
60
+ return /* @__PURE__ */ jsx("div", {
61
+ ref,
62
+ style,
63
+ className: clsx(withBaseName(), className),
64
+ ...rest,
65
+ children: /* @__PURE__ */ jsxs(ConditionalWrapper, {
66
+ className: clsx(
67
+ withBaseName("wrapper"),
68
+ {
69
+ [withBaseName("active")]: active,
70
+ [withBaseName("blurSelected")]: blurSelected,
71
+ [withBaseName("nested")]: level !== 0
72
+ },
73
+ withBaseName(orientation)
74
+ ),
75
+ children: [
76
+ /* @__PURE__ */ jsx("span", {
77
+ className: withBaseName("label"),
78
+ children
79
+ }),
80
+ parent && /* @__PURE__ */ jsx(ExpansionIcon, {
81
+ expanded,
82
+ orientation,
83
+ className: withBaseName("expandIcon")
84
+ })
85
+ ]
86
+ })
87
+ });
88
+ }
89
+ );
90
+
91
+ export { NavigationItem };
92
+ //# sourceMappingURL=NavigationItem.js.map