@salt-ds/lab 1.0.0-alpha.90 → 1.0.0-alpha.92

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 (362) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/css/salt-lab.css +169 -404
  3. package/dist-cjs/index.js +20 -16
  4. package/dist-cjs/index.js.map +1 -1
  5. package/dist-cjs/mega-menu/MegaMenu.js +82 -0
  6. package/dist-cjs/mega-menu/MegaMenu.js.map +1 -0
  7. package/dist-cjs/mega-menu/MegaMenuContent.css.js +6 -0
  8. package/dist-cjs/mega-menu/MegaMenuContent.css.js.map +1 -0
  9. package/dist-cjs/mega-menu/MegaMenuContent.js +33 -0
  10. package/dist-cjs/mega-menu/MegaMenuContent.js.map +1 -0
  11. package/dist-cjs/mega-menu/MegaMenuContext.js +11 -0
  12. package/dist-cjs/mega-menu/MegaMenuContext.js.map +1 -0
  13. package/dist-cjs/mega-menu/MegaMenuGroup.css.js +6 -0
  14. package/dist-cjs/mega-menu/MegaMenuGroup.css.js.map +1 -0
  15. package/dist-cjs/mega-menu/MegaMenuGroup.js +58 -0
  16. package/dist-cjs/mega-menu/MegaMenuGroup.js.map +1 -0
  17. package/dist-cjs/mega-menu/MegaMenuHeader.css.js +6 -0
  18. package/dist-cjs/mega-menu/MegaMenuHeader.css.js.map +1 -0
  19. package/dist-cjs/mega-menu/MegaMenuHeader.js +26 -0
  20. package/dist-cjs/mega-menu/MegaMenuHeader.js.map +1 -0
  21. package/dist-cjs/mega-menu/MegaMenuItem.css.js +6 -0
  22. package/dist-cjs/mega-menu/MegaMenuItem.css.js.map +1 -0
  23. package/dist-cjs/mega-menu/MegaMenuItem.js +52 -0
  24. package/dist-cjs/mega-menu/MegaMenuItem.js.map +1 -0
  25. package/dist-cjs/mega-menu/MegaMenuItemContent.css.js +6 -0
  26. package/dist-cjs/mega-menu/MegaMenuItemContent.css.js.map +1 -0
  27. package/dist-cjs/mega-menu/MegaMenuItemContent.js +23 -0
  28. package/dist-cjs/mega-menu/MegaMenuItemContent.js.map +1 -0
  29. package/dist-cjs/mega-menu/MegaMenuPanel.css.js +6 -0
  30. package/dist-cjs/mega-menu/MegaMenuPanel.css.js.map +1 -0
  31. package/dist-cjs/mega-menu/MegaMenuPanel.js +108 -0
  32. package/dist-cjs/mega-menu/MegaMenuPanel.js.map +1 -0
  33. package/dist-cjs/mega-menu/MegaMenuSection.css.js +6 -0
  34. package/dist-cjs/mega-menu/MegaMenuSection.css.js.map +1 -0
  35. package/dist-cjs/mega-menu/MegaMenuSection.js +25 -0
  36. package/dist-cjs/mega-menu/MegaMenuSection.js.map +1 -0
  37. package/dist-cjs/mega-menu/MegaMenuTrigger.js +92 -0
  38. package/dist-cjs/mega-menu/MegaMenuTrigger.js.map +1 -0
  39. package/dist-cjs/mega-menu/useMegaMenu.js +15 -0
  40. package/dist-cjs/mega-menu/useMegaMenu.js.map +1 -0
  41. package/dist-cjs/mega-menu/useMegaMenuKeyboard.js +209 -0
  42. package/dist-cjs/mega-menu/useMegaMenuKeyboard.js.map +1 -0
  43. package/dist-cjs/side-panel/SidePanel.css.js +1 -1
  44. package/dist-cjs/side-panel/SidePanel.js +107 -66
  45. package/dist-cjs/side-panel/SidePanel.js.map +1 -1
  46. package/dist-cjs/side-panel/SidePanelCloseButton.js +38 -0
  47. package/dist-cjs/side-panel/SidePanelCloseButton.js.map +1 -0
  48. package/dist-cjs/side-panel/SidePanelContent.css.js +1 -1
  49. package/dist-cjs/side-panel/SidePanelContent.js +3 -23
  50. package/dist-cjs/side-panel/SidePanelContent.js.map +1 -1
  51. package/dist-cjs/side-panel/SidePanelHeader.css.js +1 -1
  52. package/dist-cjs/side-panel/SidePanelHeader.js.map +1 -1
  53. package/dist-cjs/side-panel/SidePanelProvider.js +11 -4
  54. package/dist-cjs/side-panel/SidePanelProvider.js.map +1 -1
  55. package/dist-cjs/side-panel/SidePanelTitle.css.js +1 -1
  56. package/dist-cjs/side-panel/SidePanelTitle.js +1 -0
  57. package/dist-cjs/side-panel/SidePanelTitle.js.map +1 -1
  58. package/dist-cjs/side-panel/SidePanelTrigger.js +4 -4
  59. package/dist-cjs/side-panel/SidePanelTrigger.js.map +1 -1
  60. package/dist-cjs/side-panel/internal/SidePanelContext.js +2 -1
  61. package/dist-cjs/side-panel/internal/SidePanelContext.js.map +1 -1
  62. package/dist-cjs/side-panel/internal/useIsScrollable.js +50 -0
  63. package/dist-cjs/side-panel/internal/useIsScrollable.js.map +1 -0
  64. package/dist-cjs/side-panel/internal/useSidePanelTabOrder.js +214 -0
  65. package/dist-cjs/side-panel/internal/useSidePanelTabOrder.js.map +1 -0
  66. package/dist-cjs/side-panel/useSidePanel.js +9 -7
  67. package/dist-cjs/side-panel/useSidePanel.js.map +1 -1
  68. package/dist-cjs/tree/Tree.js +8 -5
  69. package/dist-cjs/tree/Tree.js.map +1 -1
  70. package/dist-cjs/tree/TreeContext.js.map +1 -1
  71. package/dist-cjs/tree/TreeNode.js +18 -14
  72. package/dist-cjs/tree/TreeNode.js.map +1 -1
  73. package/dist-cjs/tree/TreeNodeTrigger.js +4 -3
  74. package/dist-cjs/tree/TreeNodeTrigger.js.map +1 -1
  75. package/dist-cjs/tree/treeModel.js +61 -0
  76. package/dist-cjs/tree/treeModel.js.map +1 -0
  77. package/dist-cjs/tree/useTree.js +71 -65
  78. package/dist-cjs/tree/useTree.js.map +1 -1
  79. package/dist-es/index.js +10 -8
  80. package/dist-es/index.js.map +1 -1
  81. package/dist-es/mega-menu/MegaMenu.js +80 -0
  82. package/dist-es/mega-menu/MegaMenu.js.map +1 -0
  83. package/dist-es/mega-menu/MegaMenuContent.css.js +4 -0
  84. package/dist-es/mega-menu/MegaMenuContent.css.js.map +1 -0
  85. package/dist-es/mega-menu/MegaMenuContent.js +31 -0
  86. package/dist-es/mega-menu/MegaMenuContent.js.map +1 -0
  87. package/dist-es/mega-menu/MegaMenuContext.js +9 -0
  88. package/dist-es/mega-menu/MegaMenuContext.js.map +1 -0
  89. package/dist-es/mega-menu/MegaMenuGroup.css.js +4 -0
  90. package/dist-es/mega-menu/MegaMenuGroup.css.js.map +1 -0
  91. package/dist-es/mega-menu/MegaMenuGroup.js +56 -0
  92. package/dist-es/mega-menu/MegaMenuGroup.js.map +1 -0
  93. package/dist-es/mega-menu/MegaMenuHeader.css.js +4 -0
  94. package/dist-es/mega-menu/MegaMenuHeader.css.js.map +1 -0
  95. package/dist-es/mega-menu/MegaMenuHeader.js +24 -0
  96. package/dist-es/mega-menu/MegaMenuHeader.js.map +1 -0
  97. package/dist-es/mega-menu/MegaMenuItem.css.js +4 -0
  98. package/dist-es/mega-menu/MegaMenuItem.css.js.map +1 -0
  99. package/dist-es/mega-menu/MegaMenuItem.js +50 -0
  100. package/dist-es/mega-menu/MegaMenuItem.js.map +1 -0
  101. package/dist-es/mega-menu/MegaMenuItemContent.css.js +4 -0
  102. package/dist-es/mega-menu/MegaMenuItemContent.css.js.map +1 -0
  103. package/dist-es/mega-menu/MegaMenuItemContent.js +21 -0
  104. package/dist-es/mega-menu/MegaMenuItemContent.js.map +1 -0
  105. package/dist-es/mega-menu/MegaMenuPanel.css.js +4 -0
  106. package/dist-es/mega-menu/MegaMenuPanel.css.js.map +1 -0
  107. package/dist-es/mega-menu/MegaMenuPanel.js +106 -0
  108. package/dist-es/mega-menu/MegaMenuPanel.js.map +1 -0
  109. package/dist-es/mega-menu/MegaMenuSection.css.js +4 -0
  110. package/dist-es/mega-menu/MegaMenuSection.css.js.map +1 -0
  111. package/dist-es/mega-menu/MegaMenuSection.js +23 -0
  112. package/dist-es/mega-menu/MegaMenuSection.js.map +1 -0
  113. package/dist-es/mega-menu/MegaMenuTrigger.js +90 -0
  114. package/dist-es/mega-menu/MegaMenuTrigger.js.map +1 -0
  115. package/dist-es/mega-menu/useMegaMenu.js +13 -0
  116. package/dist-es/mega-menu/useMegaMenu.js.map +1 -0
  117. package/dist-es/mega-menu/useMegaMenuKeyboard.js +205 -0
  118. package/dist-es/mega-menu/useMegaMenuKeyboard.js.map +1 -0
  119. package/dist-es/side-panel/SidePanel.css.js +1 -1
  120. package/dist-es/side-panel/SidePanel.js +110 -69
  121. package/dist-es/side-panel/SidePanel.js.map +1 -1
  122. package/dist-es/side-panel/SidePanelCloseButton.js +36 -0
  123. package/dist-es/side-panel/SidePanelCloseButton.js.map +1 -0
  124. package/dist-es/side-panel/SidePanelContent.css.js +1 -1
  125. package/dist-es/side-panel/SidePanelContent.js +4 -24
  126. package/dist-es/side-panel/SidePanelContent.js.map +1 -1
  127. package/dist-es/side-panel/SidePanelHeader.css.js +1 -1
  128. package/dist-es/side-panel/SidePanelHeader.js.map +1 -1
  129. package/dist-es/side-panel/SidePanelProvider.js +12 -5
  130. package/dist-es/side-panel/SidePanelProvider.js.map +1 -1
  131. package/dist-es/side-panel/SidePanelTitle.css.js +1 -1
  132. package/dist-es/side-panel/SidePanelTitle.js +1 -0
  133. package/dist-es/side-panel/SidePanelTitle.js.map +1 -1
  134. package/dist-es/side-panel/SidePanelTrigger.js +5 -5
  135. package/dist-es/side-panel/SidePanelTrigger.js.map +1 -1
  136. package/dist-es/side-panel/internal/SidePanelContext.js +2 -1
  137. package/dist-es/side-panel/internal/SidePanelContext.js.map +1 -1
  138. package/dist-es/side-panel/internal/useIsScrollable.js +48 -0
  139. package/dist-es/side-panel/internal/useIsScrollable.js.map +1 -0
  140. package/dist-es/side-panel/internal/useSidePanelTabOrder.js +212 -0
  141. package/dist-es/side-panel/internal/useSidePanelTabOrder.js.map +1 -0
  142. package/dist-es/side-panel/useSidePanel.js +9 -7
  143. package/dist-es/side-panel/useSidePanel.js.map +1 -1
  144. package/dist-es/tree/Tree.js +8 -5
  145. package/dist-es/tree/Tree.js.map +1 -1
  146. package/dist-es/tree/TreeContext.js.map +1 -1
  147. package/dist-es/tree/TreeNode.js +20 -16
  148. package/dist-es/tree/TreeNode.js.map +1 -1
  149. package/dist-es/tree/TreeNodeTrigger.js +4 -3
  150. package/dist-es/tree/TreeNodeTrigger.js.map +1 -1
  151. package/dist-es/tree/treeModel.js +57 -0
  152. package/dist-es/tree/treeModel.js.map +1 -0
  153. package/dist-es/tree/useTree.js +49 -43
  154. package/dist-es/tree/useTree.js.map +1 -1
  155. package/dist-types/index.d.ts +1 -2
  156. package/dist-types/mega-menu/MegaMenu.d.ts +27 -0
  157. package/dist-types/mega-menu/MegaMenuContent.d.ts +8 -0
  158. package/dist-types/mega-menu/MegaMenuContext.d.ts +29 -0
  159. package/dist-types/mega-menu/MegaMenuGroup.d.ts +8 -0
  160. package/dist-types/mega-menu/MegaMenuHeader.d.ts +8 -0
  161. package/dist-types/mega-menu/MegaMenuItem.d.ts +12 -0
  162. package/dist-types/mega-menu/MegaMenuItemContent.d.ts +8 -0
  163. package/dist-types/mega-menu/MegaMenuPanel.d.ts +8 -0
  164. package/dist-types/mega-menu/MegaMenuSection.d.ts +8 -0
  165. package/dist-types/mega-menu/MegaMenuTrigger.d.ts +8 -0
  166. package/dist-types/mega-menu/index.d.ts +9 -0
  167. package/dist-types/mega-menu/useMegaMenu.d.ts +6 -0
  168. package/dist-types/mega-menu/useMegaMenuKeyboard.d.ts +30 -0
  169. package/dist-types/side-panel/SidePanel.d.ts +3 -4
  170. package/dist-types/side-panel/SidePanelCloseButton.d.ts +2 -0
  171. package/dist-types/side-panel/SidePanelContent.d.ts +4 -3
  172. package/dist-types/side-panel/SidePanelHeader.d.ts +4 -3
  173. package/dist-types/side-panel/SidePanelTitle.d.ts +1 -2
  174. package/dist-types/side-panel/SidePanelTrigger.d.ts +3 -5
  175. package/dist-types/side-panel/index.d.ts +1 -0
  176. package/dist-types/side-panel/internal/SidePanelContext.d.ts +4 -0
  177. package/dist-types/side-panel/internal/index.d.ts +2 -0
  178. package/dist-types/side-panel/internal/useIsScrollable.d.ts +2 -0
  179. package/dist-types/side-panel/internal/useSidePanelTabOrder.d.ts +7 -0
  180. package/dist-types/side-panel/useSidePanel.d.ts +32 -6
  181. package/dist-types/tree/TreeContext.d.ts +7 -1
  182. package/dist-types/tree/treeModel.d.ts +24 -0
  183. package/dist-types/tree/useTree.d.ts +3 -14
  184. package/package.json +2 -4
  185. package/dist-cjs/rating/Rating.css.js +0 -6
  186. package/dist-cjs/rating/Rating.css.js.map +0 -1
  187. package/dist-cjs/rating/Rating.js +0 -132
  188. package/dist-cjs/rating/Rating.js.map +0 -1
  189. package/dist-cjs/rating/RatingItem.css.js +0 -6
  190. package/dist-cjs/rating/RatingItem.css.js.map +0 -1
  191. package/dist-cjs/rating/RatingItem.js +0 -70
  192. package/dist-cjs/rating/RatingItem.js.map +0 -1
  193. package/dist-cjs/tabs-next/TabBar.css.js +0 -6
  194. package/dist-cjs/tabs-next/TabBar.css.js.map +0 -1
  195. package/dist-cjs/tabs-next/TabBar.js +0 -41
  196. package/dist-cjs/tabs-next/TabBar.js.map +0 -1
  197. package/dist-cjs/tabs-next/TabListLayoutContext.js +0 -13
  198. package/dist-cjs/tabs-next/TabListLayoutContext.js.map +0 -1
  199. package/dist-cjs/tabs-next/TabListNext.css.js +0 -6
  200. package/dist-cjs/tabs-next/TabListNext.css.js.map +0 -1
  201. package/dist-cjs/tabs-next/TabListNext.js +0 -271
  202. package/dist-cjs/tabs-next/TabListNext.js.map +0 -1
  203. package/dist-cjs/tabs-next/TabNext.css.js +0 -6
  204. package/dist-cjs/tabs-next/TabNext.css.js.map +0 -1
  205. package/dist-cjs/tabs-next/TabNext.js +0 -213
  206. package/dist-cjs/tabs-next/TabNext.js.map +0 -1
  207. package/dist-cjs/tabs-next/TabNextAction.js +0 -58
  208. package/dist-cjs/tabs-next/TabNextAction.js.map +0 -1
  209. package/dist-cjs/tabs-next/TabNextContext.js +0 -23
  210. package/dist-cjs/tabs-next/TabNextContext.js.map +0 -1
  211. package/dist-cjs/tabs-next/TabNextPanel.css.js +0 -6
  212. package/dist-cjs/tabs-next/TabNextPanel.css.js.map +0 -1
  213. package/dist-cjs/tabs-next/TabNextPanel.js +0 -92
  214. package/dist-cjs/tabs-next/TabNextPanel.js.map +0 -1
  215. package/dist-cjs/tabs-next/TabNextTrigger.css.js +0 -6
  216. package/dist-cjs/tabs-next/TabNextTrigger.css.js.map +0 -1
  217. package/dist-cjs/tabs-next/TabNextTrigger.js +0 -180
  218. package/dist-cjs/tabs-next/TabNextTrigger.js.map +0 -1
  219. package/dist-cjs/tabs-next/TabOverflowList.css.js +0 -6
  220. package/dist-cjs/tabs-next/TabOverflowList.css.js.map +0 -1
  221. package/dist-cjs/tabs-next/TabOverflowList.js +0 -237
  222. package/dist-cjs/tabs-next/TabOverflowList.js.map +0 -1
  223. package/dist-cjs/tabs-next/TabSlot.js +0 -30
  224. package/dist-cjs/tabs-next/TabSlot.js.map +0 -1
  225. package/dist-cjs/tabs-next/TabSlotRegistryContext.js +0 -16
  226. package/dist-cjs/tabs-next/TabSlotRegistryContext.js.map +0 -1
  227. package/dist-cjs/tabs-next/TabsNext.css.js +0 -6
  228. package/dist-cjs/tabs-next/TabsNext.css.js.map +0 -1
  229. package/dist-cjs/tabs-next/TabsNext.js +0 -195
  230. package/dist-cjs/tabs-next/TabsNext.js.map +0 -1
  231. package/dist-cjs/tabs-next/TabsNextContext.js +0 -47
  232. package/dist-cjs/tabs-next/TabsNextContext.js.map +0 -1
  233. package/dist-cjs/tabs-next/domUtils.js +0 -13
  234. package/dist-cjs/tabs-next/domUtils.js.map +0 -1
  235. package/dist-cjs/tabs-next/hooks/overflowMath.js +0 -86
  236. package/dist-cjs/tabs-next/hooks/overflowMath.js.map +0 -1
  237. package/dist-cjs/tabs-next/hooks/useCollection.js +0 -197
  238. package/dist-cjs/tabs-next/hooks/useCollection.js.map +0 -1
  239. package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js +0 -64
  240. package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js.map +0 -1
  241. package/dist-cjs/tabs-next/hooks/useOverflow.js +0 -266
  242. package/dist-cjs/tabs-next/hooks/useOverflow.js.map +0 -1
  243. package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js +0 -99
  244. package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js.map +0 -1
  245. package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js +0 -60
  246. package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js.map +0 -1
  247. package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js +0 -92
  248. package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js.map +0 -1
  249. package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js +0 -200
  250. package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js.map +0 -1
  251. package/dist-cjs/tabs-next/hooks/useTabListRecovery.js +0 -76
  252. package/dist-cjs/tabs-next/hooks/useTabListRecovery.js.map +0 -1
  253. package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js +0 -165
  254. package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js.map +0 -1
  255. package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js +0 -80
  256. package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js.map +0 -1
  257. package/dist-cjs/tabs-next/widthMeasurement.js +0 -42
  258. package/dist-cjs/tabs-next/widthMeasurement.js.map +0 -1
  259. package/dist-es/rating/Rating.css.js +0 -4
  260. package/dist-es/rating/Rating.css.js.map +0 -1
  261. package/dist-es/rating/Rating.js +0 -130
  262. package/dist-es/rating/Rating.js.map +0 -1
  263. package/dist-es/rating/RatingItem.css.js +0 -4
  264. package/dist-es/rating/RatingItem.css.js.map +0 -1
  265. package/dist-es/rating/RatingItem.js +0 -68
  266. package/dist-es/rating/RatingItem.js.map +0 -1
  267. package/dist-es/tabs-next/TabBar.css.js +0 -4
  268. package/dist-es/tabs-next/TabBar.css.js.map +0 -1
  269. package/dist-es/tabs-next/TabBar.js +0 -39
  270. package/dist-es/tabs-next/TabBar.js.map +0 -1
  271. package/dist-es/tabs-next/TabListLayoutContext.js +0 -10
  272. package/dist-es/tabs-next/TabListLayoutContext.js.map +0 -1
  273. package/dist-es/tabs-next/TabListNext.css.js +0 -4
  274. package/dist-es/tabs-next/TabListNext.css.js.map +0 -1
  275. package/dist-es/tabs-next/TabListNext.js +0 -269
  276. package/dist-es/tabs-next/TabListNext.js.map +0 -1
  277. package/dist-es/tabs-next/TabNext.css.js +0 -4
  278. package/dist-es/tabs-next/TabNext.css.js.map +0 -1
  279. package/dist-es/tabs-next/TabNext.js +0 -211
  280. package/dist-es/tabs-next/TabNext.js.map +0 -1
  281. package/dist-es/tabs-next/TabNextAction.js +0 -56
  282. package/dist-es/tabs-next/TabNextAction.js.map +0 -1
  283. package/dist-es/tabs-next/TabNextContext.js +0 -20
  284. package/dist-es/tabs-next/TabNextContext.js.map +0 -1
  285. package/dist-es/tabs-next/TabNextPanel.css.js +0 -4
  286. package/dist-es/tabs-next/TabNextPanel.css.js.map +0 -1
  287. package/dist-es/tabs-next/TabNextPanel.js +0 -90
  288. package/dist-es/tabs-next/TabNextPanel.js.map +0 -1
  289. package/dist-es/tabs-next/TabNextTrigger.css.js +0 -4
  290. package/dist-es/tabs-next/TabNextTrigger.css.js.map +0 -1
  291. package/dist-es/tabs-next/TabNextTrigger.js +0 -178
  292. package/dist-es/tabs-next/TabNextTrigger.js.map +0 -1
  293. package/dist-es/tabs-next/TabOverflowList.css.js +0 -4
  294. package/dist-es/tabs-next/TabOverflowList.css.js.map +0 -1
  295. package/dist-es/tabs-next/TabOverflowList.js +0 -235
  296. package/dist-es/tabs-next/TabOverflowList.js.map +0 -1
  297. package/dist-es/tabs-next/TabSlot.js +0 -28
  298. package/dist-es/tabs-next/TabSlot.js.map +0 -1
  299. package/dist-es/tabs-next/TabSlotRegistryContext.js +0 -13
  300. package/dist-es/tabs-next/TabSlotRegistryContext.js.map +0 -1
  301. package/dist-es/tabs-next/TabsNext.css.js +0 -4
  302. package/dist-es/tabs-next/TabsNext.css.js.map +0 -1
  303. package/dist-es/tabs-next/TabsNext.js +0 -193
  304. package/dist-es/tabs-next/TabsNext.js.map +0 -1
  305. package/dist-es/tabs-next/TabsNextContext.js +0 -44
  306. package/dist-es/tabs-next/TabsNextContext.js.map +0 -1
  307. package/dist-es/tabs-next/domUtils.js +0 -11
  308. package/dist-es/tabs-next/domUtils.js.map +0 -1
  309. package/dist-es/tabs-next/hooks/overflowMath.js +0 -82
  310. package/dist-es/tabs-next/hooks/overflowMath.js.map +0 -1
  311. package/dist-es/tabs-next/hooks/useCollection.js +0 -195
  312. package/dist-es/tabs-next/hooks/useCollection.js.map +0 -1
  313. package/dist-es/tabs-next/hooks/useFocusWithRetry.js +0 -62
  314. package/dist-es/tabs-next/hooks/useFocusWithRetry.js.map +0 -1
  315. package/dist-es/tabs-next/hooks/useOverflow.js +0 -264
  316. package/dist-es/tabs-next/hooks/useOverflow.js.map +0 -1
  317. package/dist-es/tabs-next/hooks/useOverflowLayoutState.js +0 -97
  318. package/dist-es/tabs-next/hooks/useOverflowLayoutState.js.map +0 -1
  319. package/dist-es/tabs-next/hooks/useOverflowSelectionState.js +0 -58
  320. package/dist-es/tabs-next/hooks/useOverflowSelectionState.js.map +0 -1
  321. package/dist-es/tabs-next/hooks/useRenderedTabWidth.js +0 -90
  322. package/dist-es/tabs-next/hooks/useRenderedTabWidth.js.map +0 -1
  323. package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js +0 -198
  324. package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js.map +0 -1
  325. package/dist-es/tabs-next/hooks/useTabListRecovery.js +0 -74
  326. package/dist-es/tabs-next/hooks/useTabListRecovery.js.map +0 -1
  327. package/dist-es/tabs-next/hooks/useTabRemovalHandler.js +0 -163
  328. package/dist-es/tabs-next/hooks/useTabRemovalHandler.js.map +0 -1
  329. package/dist-es/tabs-next/hooks/useTabSelectionFocus.js +0 -78
  330. package/dist-es/tabs-next/hooks/useTabSelectionFocus.js.map +0 -1
  331. package/dist-es/tabs-next/widthMeasurement.js +0 -36
  332. package/dist-es/tabs-next/widthMeasurement.js.map +0 -1
  333. package/dist-types/rating/Rating.d.ts +0 -48
  334. package/dist-types/rating/RatingItem.d.ts +0 -47
  335. package/dist-types/rating/index.d.ts +0 -1
  336. package/dist-types/tabs-next/TabBar.d.ts +0 -12
  337. package/dist-types/tabs-next/TabListLayoutContext.d.ts +0 -9
  338. package/dist-types/tabs-next/TabListNext.d.ts +0 -12
  339. package/dist-types/tabs-next/TabNext.d.ts +0 -12
  340. package/dist-types/tabs-next/TabNextAction.d.ts +0 -4
  341. package/dist-types/tabs-next/TabNextContext.d.ts +0 -12
  342. package/dist-types/tabs-next/TabNextPanel.d.ts +0 -9
  343. package/dist-types/tabs-next/TabNextTrigger.d.ts +0 -4
  344. package/dist-types/tabs-next/TabOverflowList.d.ts +0 -10
  345. package/dist-types/tabs-next/TabSlot.d.ts +0 -6
  346. package/dist-types/tabs-next/TabSlotRegistryContext.d.ts +0 -5
  347. package/dist-types/tabs-next/TabsNext.d.ts +0 -18
  348. package/dist-types/tabs-next/TabsNextContext.d.ts +0 -43
  349. package/dist-types/tabs-next/domUtils.d.ts +0 -1
  350. package/dist-types/tabs-next/hooks/overflowMath.d.ts +0 -18
  351. package/dist-types/tabs-next/hooks/useCollection.d.ts +0 -30
  352. package/dist-types/tabs-next/hooks/useFocusWithRetry.d.ts +0 -9
  353. package/dist-types/tabs-next/hooks/useOverflow.d.ts +0 -11
  354. package/dist-types/tabs-next/hooks/useOverflowLayoutState.d.ts +0 -13
  355. package/dist-types/tabs-next/hooks/useOverflowSelectionState.d.ts +0 -13
  356. package/dist-types/tabs-next/hooks/useRenderedTabWidth.d.ts +0 -12
  357. package/dist-types/tabs-next/hooks/useRenderedTabsRegistry.d.ts +0 -12
  358. package/dist-types/tabs-next/hooks/useTabListRecovery.d.ts +0 -12
  359. package/dist-types/tabs-next/hooks/useTabRemovalHandler.d.ts +0 -32
  360. package/dist-types/tabs-next/hooks/useTabSelectionFocus.d.ts +0 -15
  361. package/dist-types/tabs-next/index.d.ts +0 -7
  362. package/dist-types/tabs-next/widthMeasurement.d.ts +0 -5
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ const observedAttributes = ["class", "hidden", "style"];
6
+ function useIsScrollable(ref) {
7
+ const [isScrollable, setIsScrollable] = react.useState(false);
8
+ react.useEffect(() => {
9
+ const element = ref.current;
10
+ const win = element == null ? void 0 : element.ownerDocument.defaultView;
11
+ if (!element || !win) {
12
+ return;
13
+ }
14
+ let animationFrame;
15
+ const checkScrollable = () => {
16
+ animationFrame = void 0;
17
+ const nextIsScrollable = element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
18
+ setIsScrollable(
19
+ (currentIsScrollable) => currentIsScrollable === nextIsScrollable ? currentIsScrollable : nextIsScrollable
20
+ );
21
+ };
22
+ const scheduleCheck = () => {
23
+ if (animationFrame === void 0) {
24
+ animationFrame = win.requestAnimationFrame(checkScrollable);
25
+ }
26
+ };
27
+ scheduleCheck();
28
+ const resizeObserver = win.ResizeObserver ? new win.ResizeObserver(scheduleCheck) : void 0;
29
+ resizeObserver == null ? void 0 : resizeObserver.observe(element);
30
+ const mutationObserver = win.MutationObserver ? new win.MutationObserver(scheduleCheck) : void 0;
31
+ mutationObserver == null ? void 0 : mutationObserver.observe(element, {
32
+ attributeFilter: observedAttributes,
33
+ attributes: true,
34
+ characterData: true,
35
+ childList: true,
36
+ subtree: true
37
+ });
38
+ return () => {
39
+ if (animationFrame !== void 0) {
40
+ win.cancelAnimationFrame(animationFrame);
41
+ }
42
+ resizeObserver == null ? void 0 : resizeObserver.disconnect();
43
+ mutationObserver == null ? void 0 : mutationObserver.disconnect();
44
+ };
45
+ }, [ref]);
46
+ return isScrollable;
47
+ }
48
+
49
+ exports.useIsScrollable = useIsScrollable;
50
+ //# sourceMappingURL=useIsScrollable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useIsScrollable.js","sources":["../src/side-panel/internal/useIsScrollable.ts"],"sourcesContent":["import { type RefObject, useEffect, useState } from \"react\";\n\nconst observedAttributes = [\"class\", \"hidden\", \"style\"];\n\nexport function useIsScrollable(ref: RefObject<HTMLElement>) {\n const [isScrollable, setIsScrollable] = useState(false);\n\n useEffect(() => {\n const element = ref.current;\n const win = element?.ownerDocument.defaultView;\n if (!element || !win) {\n return;\n }\n\n let animationFrame: number | undefined;\n\n const checkScrollable = () => {\n animationFrame = undefined;\n const nextIsScrollable =\n element.scrollHeight > element.clientHeight ||\n element.scrollWidth > element.clientWidth;\n\n setIsScrollable((currentIsScrollable) =>\n currentIsScrollable === nextIsScrollable\n ? currentIsScrollable\n : nextIsScrollable,\n );\n };\n\n const scheduleCheck = () => {\n if (animationFrame === undefined) {\n animationFrame = win.requestAnimationFrame(checkScrollable);\n }\n };\n\n scheduleCheck();\n\n const resizeObserver = win.ResizeObserver\n ? new win.ResizeObserver(scheduleCheck)\n : undefined;\n resizeObserver?.observe(element);\n\n const mutationObserver = win.MutationObserver\n ? new win.MutationObserver(scheduleCheck)\n : undefined;\n mutationObserver?.observe(element, {\n attributeFilter: observedAttributes,\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n\n return () => {\n if (animationFrame !== undefined) {\n win.cancelAnimationFrame(animationFrame);\n }\n resizeObserver?.disconnect();\n mutationObserver?.disconnect();\n };\n }, [ref]);\n\n return isScrollable;\n}\n"],"names":["useState","useEffect"],"mappings":";;;;AAEA,MAAM,kBAAA,GAAqB,CAAC,OAAA,EAAS,QAAA,EAAU,OAAO,CAAA;AAE/C,SAAS,gBAAgB,GAAA,EAA6B;AAC3D,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,eAAS,KAAK,CAAA;AAEtD,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAU,GAAA,CAAI,OAAA;AACpB,IAAA,MAAM,GAAA,GAAM,mCAAS,aAAA,CAAc,WAAA;AACnC,IAAA,IAAI,CAAC,OAAA,IAAW,CAAC,GAAA,EAAK;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,cAAA;AAEJ,IAAA,MAAM,kBAAkB,MAAM;AAC5B,MAAA,cAAA,GAAiB,MAAA;AACjB,MAAA,MAAM,mBACJ,OAAA,CAAQ,YAAA,GAAe,QAAQ,YAAA,IAC/B,OAAA,CAAQ,cAAc,OAAA,CAAQ,WAAA;AAEhC,MAAA,eAAA;AAAA,QAAgB,CAAC,mBAAA,KACf,mBAAA,KAAwB,gBAAA,GACpB,mBAAA,GACA;AAAA,OACN;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,gBAAgB,MAAM;AAC1B,MAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,QAAA,cAAA,GAAiB,GAAA,CAAI,sBAAsB,eAAe,CAAA;AAAA,MAC5D;AAAA,IACF,CAAA;AAEA,IAAA,aAAA,EAAc;AAEd,IAAA,MAAM,iBAAiB,GAAA,CAAI,cAAA,GACvB,IAAI,GAAA,CAAI,cAAA,CAAe,aAAa,CAAA,GACpC,MAAA;AACJ,IAAA,cAAA,IAAA,IAAA,GAAA,MAAA,GAAA,cAAA,CAAgB,OAAA,CAAQ,OAAA,CAAA;AAExB,IAAA,MAAM,mBAAmB,GAAA,CAAI,gBAAA,GACzB,IAAI,GAAA,CAAI,gBAAA,CAAiB,aAAa,CAAA,GACtC,MAAA;AACJ,IAAA,gBAAA,IAAA,IAAA,GAAA,MAAA,GAAA,gBAAA,CAAkB,QAAQ,OAAA,EAAS;AAAA,MACjC,eAAA,EAAiB,kBAAA;AAAA,MACjB,UAAA,EAAY,IAAA;AAAA,MACZ,aAAA,EAAe,IAAA;AAAA,MACf,SAAA,EAAW,IAAA;AAAA,MACX,OAAA,EAAS;AAAA,KACX,CAAA;AAEA,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,QAAA,GAAA,CAAI,qBAAqB,cAAc,CAAA;AAAA,MACzC;AACA,MAAA,cAAA,IAAA,IAAA,GAAA,MAAA,GAAA,cAAA,CAAgB,UAAA,EAAA;AAChB,MAAA,gBAAA,IAAA,IAAA,GAAA,MAAA,GAAA,gBAAA,CAAkB,UAAA,EAAA;AAAA,IACpB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AAER,EAAA,OAAO,YAAA;AACT;;;;"}
@@ -0,0 +1,214 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var tabbable = require('tabbable');
5
+
6
+ const ORIGINAL_TABINDEX_ATTR = "data-salt-original-tabindex";
7
+ function isPlainTabKey(event) {
8
+ return event.key === "Tab" && !event.altKey && !event.ctrlKey && !event.metaKey;
9
+ }
10
+ function getPanelTabbableElements(panel) {
11
+ const win = panel.ownerDocument.defaultView;
12
+ const managed = Array.from(
13
+ panel.querySelectorAll(`[${ORIGINAL_TABINDEX_ATTR}]`)
14
+ ).filter((element) => {
15
+ if (element.hasAttribute("disabled")) return false;
16
+ if (element.getAttribute("aria-hidden") === "true") return false;
17
+ return !(element.offsetParent === null && (win == null ? void 0 : win.getComputedStyle(element).display) === "none");
18
+ });
19
+ if (managed.length > 0) {
20
+ return managed;
21
+ }
22
+ return tabbable.tabbable(panel, { displayCheck: "none" });
23
+ }
24
+ function focusFirstPanelElement(panel) {
25
+ const [firstTabbableElement] = getPanelTabbableElements(panel);
26
+ (firstTabbableElement ?? panel).focus();
27
+ }
28
+ function focusLastPanelElement(panel) {
29
+ const tabbableElements = getPanelTabbableElements(panel);
30
+ (tabbableElements[tabbableElements.length - 1] ?? panel).focus();
31
+ }
32
+ function containsTarget(container, target) {
33
+ const targetWindow = container.ownerDocument.defaultView;
34
+ return Boolean(
35
+ (targetWindow == null ? void 0 : targetWindow.Node) && target instanceof targetWindow.Node && container.contains(target)
36
+ );
37
+ }
38
+ function getNextTabbableAfterReference(reference, panel) {
39
+ const { body } = reference.ownerDocument;
40
+ if (!body) return void 0;
41
+ const tabbableElements = tabbable.tabbable(body).filter(
42
+ (element) => !panel.contains(element)
43
+ );
44
+ const referenceIndex = tabbableElements.findIndex(
45
+ (element) => element === reference || reference.contains(element)
46
+ );
47
+ if (referenceIndex === -1) {
48
+ return void 0;
49
+ }
50
+ return tabbableElements[referenceIndex + 1];
51
+ }
52
+ function detachElement(element) {
53
+ if (!element.hasAttribute(ORIGINAL_TABINDEX_ATTR)) {
54
+ const original = element.getAttribute("tabindex");
55
+ element.setAttribute(ORIGINAL_TABINDEX_ATTR, original ?? "");
56
+ }
57
+ if (element.getAttribute("tabindex") !== "-1") {
58
+ element.setAttribute("tabindex", "-1");
59
+ }
60
+ }
61
+ function reattachElement(element) {
62
+ if (!element.hasAttribute(ORIGINAL_TABINDEX_ATTR)) return;
63
+ const original = element.getAttribute(ORIGINAL_TABINDEX_ATTR);
64
+ element.removeAttribute(ORIGINAL_TABINDEX_ATTR);
65
+ if (original === null || original === "") {
66
+ element.removeAttribute("tabindex");
67
+ } else {
68
+ element.setAttribute("tabindex", original);
69
+ }
70
+ }
71
+ function detachPanelFromTabOrder(panel) {
72
+ const win = panel.ownerDocument.defaultView ?? window;
73
+ const detach = () => {
74
+ for (const element of tabbable.tabbable(panel, { displayCheck: "none" })) {
75
+ detachElement(element);
76
+ }
77
+ const managed = panel.querySelectorAll(
78
+ `[${ORIGINAL_TABINDEX_ATTR}]`
79
+ );
80
+ for (const element of Array.from(managed)) {
81
+ if (element.getAttribute("tabindex") !== "-1") {
82
+ element.setAttribute("tabindex", "-1");
83
+ }
84
+ }
85
+ };
86
+ detach();
87
+ let scheduled = 0;
88
+ const scheduleDetach = () => {
89
+ if (scheduled) return;
90
+ scheduled = win.requestAnimationFrame(() => {
91
+ scheduled = 0;
92
+ detach();
93
+ });
94
+ };
95
+ const observer = new MutationObserver(scheduleDetach);
96
+ observer.observe(panel, {
97
+ subtree: true,
98
+ childList: true,
99
+ attributes: true,
100
+ attributeFilter: ["tabindex", "disabled", "contenteditable", "hidden"]
101
+ });
102
+ return () => {
103
+ if (scheduled) {
104
+ win.cancelAnimationFrame(scheduled);
105
+ }
106
+ observer.disconnect();
107
+ const managed = panel.querySelectorAll(
108
+ `[${ORIGINAL_TABINDEX_ATTR}]`
109
+ );
110
+ for (const element of Array.from(managed)) {
111
+ reattachElement(element);
112
+ }
113
+ };
114
+ }
115
+ function useSidePanelTabOrder(props) {
116
+ const { floating, open, reference } = props;
117
+ react.useEffect(() => {
118
+ if (!open || !reference || !floating) {
119
+ return;
120
+ }
121
+ const { ownerDocument } = reference;
122
+ let redirectTriggerTab = true;
123
+ let programmaticReferenceFocus = false;
124
+ const releaseDetachment = detachPanelFromTabOrder(floating);
125
+ const onReferenceFocus = (event) => {
126
+ if (programmaticReferenceFocus) {
127
+ programmaticReferenceFocus = false;
128
+ return;
129
+ }
130
+ const relatedTarget = event.relatedTarget;
131
+ if (relatedTarget && relatedTarget instanceof Node && !(reference.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_PRECEDING)) {
132
+ redirectTriggerTab = false;
133
+ return;
134
+ }
135
+ redirectTriggerTab = true;
136
+ };
137
+ const onReferenceKeyDown = (event) => {
138
+ if (event.defaultPrevented || !isPlainTabKey(event) || event.shiftKey) {
139
+ return;
140
+ }
141
+ if (!redirectTriggerTab) {
142
+ return;
143
+ }
144
+ event.preventDefault();
145
+ redirectTriggerTab = false;
146
+ focusFirstPanelElement(floating);
147
+ };
148
+ const onFloatingKeyDown = (event) => {
149
+ if (event.defaultPrevented || !isPlainTabKey(event)) {
150
+ return;
151
+ }
152
+ const panelTabbableElements = getPanelTabbableElements(floating);
153
+ const activeElement = floating.ownerDocument.activeElement;
154
+ const currentIndex = activeElement ? panelTabbableElements.indexOf(activeElement) : -1;
155
+ if (event.shiftKey) {
156
+ if (currentIndex <= 0) {
157
+ event.preventDefault();
158
+ redirectTriggerTab = true;
159
+ programmaticReferenceFocus = true;
160
+ reference.focus();
161
+ return;
162
+ }
163
+ event.preventDefault();
164
+ panelTabbableElements[currentIndex - 1].focus();
165
+ return;
166
+ }
167
+ const atLast = currentIndex === panelTabbableElements.length - 1 || currentIndex === -1 && panelTabbableElements.length === 0;
168
+ if (atLast) {
169
+ event.preventDefault();
170
+ const nextElement = getNextTabbableAfterReference(reference, floating);
171
+ if (nextElement) {
172
+ nextElement.focus();
173
+ } else {
174
+ redirectTriggerTab = false;
175
+ programmaticReferenceFocus = true;
176
+ reference.focus();
177
+ }
178
+ return;
179
+ }
180
+ if (currentIndex === -1) {
181
+ event.preventDefault();
182
+ panelTabbableElements[0].focus();
183
+ return;
184
+ }
185
+ event.preventDefault();
186
+ panelTabbableElements[currentIndex + 1].focus();
187
+ };
188
+ const onDocumentKeyDown = (event) => {
189
+ if (event.defaultPrevented || !isPlainTabKey(event) || !event.shiftKey) {
190
+ return;
191
+ }
192
+ const nextElement = getNextTabbableAfterReference(reference, floating);
193
+ if (!nextElement || !containsTarget(nextElement, event.target)) {
194
+ return;
195
+ }
196
+ event.preventDefault();
197
+ focusLastPanelElement(floating);
198
+ };
199
+ reference.addEventListener("focus", onReferenceFocus);
200
+ reference.addEventListener("keydown", onReferenceKeyDown);
201
+ floating.addEventListener("keydown", onFloatingKeyDown);
202
+ ownerDocument.addEventListener("keydown", onDocumentKeyDown);
203
+ return () => {
204
+ reference.removeEventListener("focus", onReferenceFocus);
205
+ reference.removeEventListener("keydown", onReferenceKeyDown);
206
+ floating.removeEventListener("keydown", onFloatingKeyDown);
207
+ ownerDocument.removeEventListener("keydown", onDocumentKeyDown);
208
+ releaseDetachment();
209
+ };
210
+ }, [floating, open, reference]);
211
+ }
212
+
213
+ exports.useSidePanelTabOrder = useSidePanelTabOrder;
214
+ //# sourceMappingURL=useSidePanelTabOrder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSidePanelTabOrder.js","sources":["../src/side-panel/internal/useSidePanelTabOrder.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport { tabbable } from \"tabbable\";\n\ninterface UseSidePanelTabOrderProps {\n floating: HTMLElement | null;\n open: boolean;\n reference: HTMLElement | null;\n}\n\nconst ORIGINAL_TABINDEX_ATTR = \"data-salt-original-tabindex\";\n\nfunction isPlainTabKey(event: KeyboardEvent) {\n return (\n event.key === \"Tab\" && !event.altKey && !event.ctrlKey && !event.metaKey\n );\n}\n\n/**\n * Returns the panel's logical tab sequence. While the panel is open we\n * strip tabindex on descendants, so the sequence is discovered via the\n * data-salt-original-tabindex markers; falls back to a fresh tabbable()\n * scan before detachment runs.\n */\nfunction getPanelTabbableElements(panel: HTMLElement): HTMLElement[] {\n const win = panel.ownerDocument.defaultView;\n const managed = Array.from(\n panel.querySelectorAll<HTMLElement>(`[${ORIGINAL_TABINDEX_ATTR}]`),\n ).filter((element) => {\n if (element.hasAttribute(\"disabled\")) return false;\n if (element.getAttribute(\"aria-hidden\") === \"true\") return false;\n // null offsetParent is also true for fixed/SVG; the display check\n // disambiguates.\n return !(\n element.offsetParent === null &&\n win?.getComputedStyle(element).display === \"none\"\n );\n });\n\n if (managed.length > 0) {\n return managed;\n }\n\n return tabbable(panel, { displayCheck: \"none\" }) as HTMLElement[];\n}\n\nfunction focusFirstPanelElement(panel: HTMLElement) {\n const [firstTabbableElement] = getPanelTabbableElements(panel);\n (firstTabbableElement ?? panel).focus();\n}\n\nfunction focusLastPanelElement(panel: HTMLElement) {\n const tabbableElements = getPanelTabbableElements(panel);\n (tabbableElements[tabbableElements.length - 1] ?? panel).focus();\n}\n\nfunction containsTarget(container: Element, target: EventTarget | null) {\n const targetWindow = container.ownerDocument.defaultView;\n\n return Boolean(\n targetWindow?.Node &&\n target instanceof targetWindow.Node &&\n container.contains(target),\n );\n}\n\n/**\n * Returns the first tabbable element after `reference` in document order,\n * skipping anything inside `panel`.\n */\nfunction getNextTabbableAfterReference(\n reference: HTMLElement,\n panel: HTMLElement,\n) {\n const { body } = reference.ownerDocument;\n if (!body) return undefined;\n const tabbableElements = tabbable(body).filter(\n (element) => !panel.contains(element),\n );\n const referenceIndex = tabbableElements.findIndex(\n (element) => element === reference || reference.contains(element),\n );\n\n if (referenceIndex === -1) {\n return undefined;\n }\n\n return tabbableElements[referenceIndex + 1];\n}\n\n/**\n * Detaches an element from the natural tab sequence, remembering its\n * original tabindex (or its absence) on a data attribute for restoration.\n */\nfunction detachElement(element: HTMLElement) {\n if (!element.hasAttribute(ORIGINAL_TABINDEX_ATTR)) {\n const original = element.getAttribute(\"tabindex\");\n element.setAttribute(ORIGINAL_TABINDEX_ATTR, original ?? \"\");\n }\n // Force re-apply: React may have rewritten the attribute on re-render.\n if (element.getAttribute(\"tabindex\") !== \"-1\") {\n element.setAttribute(\"tabindex\", \"-1\");\n }\n}\n\nfunction reattachElement(element: HTMLElement) {\n if (!element.hasAttribute(ORIGINAL_TABINDEX_ATTR)) return;\n const original = element.getAttribute(ORIGINAL_TABINDEX_ATTR);\n element.removeAttribute(ORIGINAL_TABINDEX_ATTR);\n if (original === null || original === \"\") {\n element.removeAttribute(\"tabindex\");\n } else {\n element.setAttribute(\"tabindex\", original);\n }\n}\n\n/**\n * Removes every tabbable descendant of `panel` from the natural tab order.\n * Returns a cleanup function that restores original tabindex values and\n * disconnects the observer used to track dynamically-added focusables.\n */\nfunction detachPanelFromTabOrder(panel: HTMLElement) {\n const win = panel.ownerDocument.defaultView ?? window;\n\n const detach = () => {\n for (const element of tabbable(panel, { displayCheck: \"none\" })) {\n detachElement(element as HTMLElement);\n }\n // Re-assert tabindex=\"-1\" on already-managed elements (React may\n // have written its prop value back).\n const managed = panel.querySelectorAll<HTMLElement>(\n `[${ORIGINAL_TABINDEX_ATTR}]`,\n );\n for (const element of Array.from(managed)) {\n if (element.getAttribute(\"tabindex\") !== \"-1\") {\n element.setAttribute(\"tabindex\", \"-1\");\n }\n }\n };\n\n detach();\n\n // Coalesce mutation bursts into one frame to avoid a feedback loop\n // between detach()'s tabindex writes and the observer's tabindex filter.\n let scheduled = 0;\n const scheduleDetach = () => {\n if (scheduled) return;\n scheduled = win.requestAnimationFrame(() => {\n scheduled = 0;\n detach();\n });\n };\n\n const observer = new MutationObserver(scheduleDetach);\n\n observer.observe(panel, {\n subtree: true,\n childList: true,\n attributes: true,\n attributeFilter: [\"tabindex\", \"disabled\", \"contenteditable\", \"hidden\"],\n });\n\n return () => {\n if (scheduled) {\n win.cancelAnimationFrame(scheduled);\n }\n observer.disconnect();\n const managed = panel.querySelectorAll<HTMLElement>(\n `[${ORIGINAL_TABINDEX_ATTR}]`,\n );\n for (const element of Array.from(managed)) {\n reattachElement(element);\n }\n };\n}\n\nexport function useSidePanelTabOrder(props: UseSidePanelTabOrderProps) {\n const { floating, open, reference } = props;\n\n useEffect(() => {\n if (!open || !reference || !floating) {\n return;\n }\n\n const { ownerDocument } = reference;\n\n // True when Tab on the trigger should walk into the panel (a \"fresh\n // entry\": focus arrived from before the trigger, or from nowhere).\n // Set false when focus arrives from inside / after the panel, so the\n // user can keep tabbing forward without getting trapped.\n let redirectTriggerTab = true;\n\n // Set true just before we programmatically focus the trigger, so the\n // focusin handler can preserve our explicit redirect intent instead\n // of overwriting it from the relatedTarget heuristic.\n let programmaticReferenceFocus = false;\n\n // Make panel content unreachable via natural Tab — only the trigger\n // flow below can enter.\n const releaseDetachment = detachPanelFromTabOrder(floating);\n\n const onReferenceFocus = (event: FocusEvent) => {\n if (programmaticReferenceFocus) {\n programmaticReferenceFocus = false;\n return;\n }\n\n const relatedTarget = event.relatedTarget as Node | null;\n\n // Focus arrived from inside / after the panel — disable redirect\n // so Tab moves forward naturally and doesn't trap the user.\n if (\n relatedTarget &&\n relatedTarget instanceof Node &&\n !(\n reference.compareDocumentPosition(relatedTarget) &\n Node.DOCUMENT_POSITION_PRECEDING\n )\n ) {\n redirectTriggerTab = false;\n return;\n }\n\n redirectTriggerTab = true;\n };\n\n const onReferenceKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || !isPlainTabKey(event) || event.shiftKey) {\n return;\n }\n\n // Only redirect on a fresh entry; otherwise let the browser advance\n // to the next focusable element naturally.\n if (!redirectTriggerTab) {\n return;\n }\n\n event.preventDefault();\n redirectTriggerTab = false;\n focusFirstPanelElement(floating);\n };\n\n const onFloatingKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || !isPlainTabKey(event)) {\n return;\n }\n\n const panelTabbableElements = getPanelTabbableElements(floating);\n const activeElement = floating.ownerDocument\n .activeElement as HTMLElement | null;\n const currentIndex = activeElement\n ? panelTabbableElements.indexOf(activeElement)\n : -1;\n\n if (event.shiftKey) {\n // At the start of the panel (or on the panel container itself):\n // exit backwards to the trigger and arm the redirect so the next\n // forward Tab walks back in.\n if (currentIndex <= 0) {\n event.preventDefault();\n redirectTriggerTab = true;\n programmaticReferenceFocus = true;\n reference.focus();\n return;\n }\n\n event.preventDefault();\n panelTabbableElements[currentIndex - 1].focus();\n return;\n }\n\n // At the end of the panel: exit forwards to the element after the\n // trigger. Also handles focus on the panel container itself when\n // the panel has no tabbable items.\n const atLast =\n currentIndex === panelTabbableElements.length - 1 ||\n (currentIndex === -1 && panelTabbableElements.length === 0);\n\n if (atLast) {\n event.preventDefault();\n const nextElement = getNextTabbableAfterReference(reference, floating);\n if (nextElement) {\n nextElement.focus();\n } else {\n // Nothing after the trigger — hand focus back to the trigger\n // but disable redirect so the next Tab moves naturally.\n redirectTriggerTab = false;\n programmaticReferenceFocus = true;\n reference.focus();\n }\n return;\n }\n\n // Focus on the panel container or an unmanaged ancestor — route\n // forward into the first managed element.\n if (currentIndex === -1) {\n event.preventDefault();\n panelTabbableElements[0].focus();\n return;\n }\n\n event.preventDefault();\n panelTabbableElements[currentIndex + 1].focus();\n };\n\n const onDocumentKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || !isPlainTabKey(event) || !event.shiftKey) {\n return;\n }\n\n const nextElement = getNextTabbableAfterReference(reference, floating);\n if (!nextElement || !containsTarget(nextElement, event.target)) {\n return;\n }\n\n event.preventDefault();\n focusLastPanelElement(floating);\n };\n\n reference.addEventListener(\"focus\", onReferenceFocus);\n reference.addEventListener(\"keydown\", onReferenceKeyDown);\n floating.addEventListener(\"keydown\", onFloatingKeyDown);\n ownerDocument.addEventListener(\"keydown\", onDocumentKeyDown);\n\n return () => {\n reference.removeEventListener(\"focus\", onReferenceFocus);\n reference.removeEventListener(\"keydown\", onReferenceKeyDown);\n floating.removeEventListener(\"keydown\", onFloatingKeyDown);\n ownerDocument.removeEventListener(\"keydown\", onDocumentKeyDown);\n releaseDetachment();\n };\n }, [floating, open, reference]);\n}\n"],"names":["tabbable","useEffect"],"mappings":"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"}
@@ -1,23 +1,26 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
3
+ var core = require('@salt-ds/core');
4
4
  var SidePanelContext = require('./internal/SidePanelContext.js');
5
+ require('react');
6
+ require('tabbable');
5
7
 
6
8
  function useSidePanel() {
7
9
  const { openState, setOpen, setReference, panelId } = SidePanelContext.useSidePanelContext();
8
- const getTriggerProps = react.useCallback(
10
+ const getTriggerProps = core.useEventCallback(
9
11
  (userProps) => {
10
12
  const userOnClick = userProps == null ? void 0 : userProps.onClick;
13
+ const userRef = userProps == null ? void 0 : userProps.ref;
11
14
  return {
12
15
  "aria-expanded": openState,
13
16
  "aria-controls": openState ? panelId : void 0,
14
17
  ...userProps,
15
- onClick: (e) => {
16
- userOnClick == null ? void 0 : userOnClick(e);
18
+ onClick: (event) => {
19
+ userOnClick == null ? void 0 : userOnClick(event);
20
+ setOpen(!openState);
17
21
  },
18
22
  ref: (node) => {
19
23
  setReference(node);
20
- const userRef = userProps == null ? void 0 : userProps.ref;
21
24
  if (typeof userRef === "function") {
22
25
  userRef(node);
23
26
  } else if (userRef && typeof userRef === "object" && "current" in userRef) {
@@ -25,8 +28,7 @@ function useSidePanel() {
25
28
  }
26
29
  }
27
30
  };
28
- },
29
- [openState, panelId, setReference]
31
+ }
30
32
  );
31
33
  return {
32
34
  openState,
@@ -1 +1 @@
1
- {"version":3,"file":"useSidePanel.js","sources":["../src/side-panel/useSidePanel.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { useSidePanelContext } from \"./internal\";\n\nexport interface SidePanelValue {\n /**\n * Whether the side panel is currently open.\n */\n openState: boolean;\n /**\n * Sets the open state of the panel.\n */\n setOpen: (open: boolean) => void;\n /**\n * Props getter for a single trigger element.\n * Merges `aria-expanded`, `aria-controls`, a `ref` callback (to register\n * the trigger for focus-return), and user-provided props.\n * Best for the common case where one button toggles one panel.\n *\n * For multi-trigger scenarios (e.g. table rows), use `setTriggerRef` and\n * manage ARIA attributes yourself instead.\n */\n getTriggerProps: (\n userProps?: Record<string, unknown>,\n ) => Record<string, unknown>;\n /**\n * Registers the element that should receive focus when the panel closes.\n * Use this in multi-trigger scenarios (e.g. table rows) where each trigger\n * needs explicit control over which element is the reference.\n */\n setTriggerRef: (element: HTMLElement | null) => void;\n /**\n * The panel's DOM id. Use this for `aria-controls` in multi-trigger\n * scenarios where you manage ARIA attributes yourself.\n */\n panelId: string | undefined;\n}\n\nexport function useSidePanel(): SidePanelValue {\n const { openState, setOpen, setReference, panelId } = useSidePanelContext();\n\n const getTriggerProps = useCallback(\n (userProps?: Record<string, unknown>) => {\n const userOnClick = userProps?.onClick as\n | ((e: React.MouseEvent<HTMLElement>) => void)\n | undefined;\n\n return {\n \"aria-expanded\": openState,\n \"aria-controls\": openState ? panelId : undefined,\n ...userProps,\n onClick: (e: React.MouseEvent<HTMLElement>) => {\n userOnClick?.(e);\n },\n ref: (node: HTMLElement | null) => {\n // Register this element as the trigger for focus return\n setReference(node);\n // Forward the consumer's ref if provided\n const userRef = userProps?.ref;\n if (typeof userRef === \"function\") {\n userRef(node);\n } else if (\n userRef &&\n typeof userRef === \"object\" &&\n \"current\" in userRef\n ) {\n (userRef as React.MutableRefObject<HTMLElement | null>).current =\n node;\n }\n },\n };\n },\n [openState, panelId, setReference],\n );\n\n return {\n openState,\n setOpen,\n getTriggerProps,\n setTriggerRef: setReference,\n panelId,\n };\n}\n"],"names":["useSidePanelContext","useCallback"],"mappings":";;;;;AAqCO,SAAS,YAAA,GAA+B;AAC7C,EAAA,MAAM,EAAE,SAAA,EAAW,OAAA,EAAS,YAAA,EAAc,OAAA,KAAYA,oCAAA,EAAoB;AAE1E,EAAA,MAAM,eAAA,GAAkBC,iBAAA;AAAA,IACtB,CAAC,SAAA,KAAwC;AACvC,MAAA,MAAM,cAAc,SAAA,IAAA,IAAA,GAAA,MAAA,GAAA,SAAA,CAAW,OAAA;AAI/B,MAAA,OAAO;AAAA,QACL,eAAA,EAAiB,SAAA;AAAA,QACjB,eAAA,EAAiB,YAAY,OAAA,GAAU,MAAA;AAAA,QACvC,GAAG,SAAA;AAAA,QACH,OAAA,EAAS,CAAC,CAAA,KAAqC;AAC7C,UAAA,WAAA,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,CAAc,CAAA,CAAA;AAAA,QAChB,CAAA;AAAA,QACA,GAAA,EAAK,CAAC,IAAA,KAA6B;AAEjC,UAAA,YAAA,CAAa,IAAI,CAAA;AAEjB,UAAA,MAAM,UAAU,SAAA,IAAA,IAAA,GAAA,MAAA,GAAA,SAAA,CAAW,GAAA;AAC3B,UAAA,IAAI,OAAO,YAAY,UAAA,EAAY;AACjC,YAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,UACd,WACE,OAAA,IACA,OAAO,OAAA,KAAY,QAAA,IACnB,aAAa,OAAA,EACb;AACA,YAAC,QAAuD,OAAA,GACtD,IAAA;AAAA,UACJ;AAAA,QACF;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IACA,CAAC,SAAA,EAAW,OAAA,EAAS,YAAY;AAAA,GACnC;AAEA,EAAA,OAAO;AAAA,IACL,SAAA;AAAA,IACA,OAAA;AAAA,IACA,eAAA;AAAA,IACA,aAAA,EAAe,YAAA;AAAA,IACf;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"useSidePanel.js","sources":["../src/side-panel/useSidePanel.ts"],"sourcesContent":["import { useEventCallback } from \"@salt-ds/core\";\nimport type {\n ComponentPropsWithoutRef,\n MouseEvent,\n MutableRefObject,\n RefCallback,\n} from \"react\";\nimport { useSidePanelContext } from \"./internal\";\n\nexport interface SidePanelTriggerExtraProps {\n /**\n * Optional ref to forward alongside the focus-return registration.\n */\n ref?:\n | RefCallback<HTMLElement | null>\n | MutableRefObject<HTMLElement | null>\n | null;\n /**\n * Click handler. Runs before the built-in toggle so consumers can\n * preventDefault to skip the toggle.\n */\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void;\n}\n\nexport type SidePanelTriggerPropsResult = ComponentPropsWithoutRef<\"button\"> & {\n \"aria-expanded\": boolean;\n \"aria-controls\": string | undefined;\n ref: RefCallback<HTMLElement | null>;\n};\n\nexport interface SidePanelValue {\n /**\n * Whether the side panel is currently open.\n */\n openState: boolean;\n /**\n * Sets the open state of the panel.\n */\n setOpen: (open: boolean) => void;\n /**\n * Props getter for a trigger element outside of `SidePanelTrigger`.\n * Returns `aria-expanded`, `aria-controls`, a `ref` (for focus-return),\n * and an `onClick` that toggles the panel.\n *\n * Spread the result onto a Button to get full trigger behavior:\n * ```tsx\n * <Button {...getTriggerProps()}>Toggle panel</Button>\n * ```\n *\n * You can pass additional props which are merged in. If you provide your\n * own `onClick`, it runs before the built-in toggle. If you provide your\n * own `ref`, it is forwarded alongside the internal focus-return ref.\n *\n * For multi-trigger scenarios (e.g. table rows), use `setTriggerRef` and\n * manage ARIA attributes yourself instead.\n */\n getTriggerProps: (\n userProps?: SidePanelTriggerExtraProps,\n ) => SidePanelTriggerPropsResult;\n /**\n * Registers the element that should receive focus when the panel closes.\n * Use this in multi-trigger scenarios (e.g. table rows) where each trigger\n * needs explicit control over which element is the reference. Pass `null`\n * to clear the previously-registered trigger.\n */\n setTriggerRef: (element: HTMLElement | null) => void;\n /**\n * The panel's DOM id. Use this for `aria-controls` in multi-trigger\n * scenarios where you manage ARIA attributes yourself.\n */\n panelId: string | undefined;\n}\n\nexport function useSidePanel(): SidePanelValue {\n const { openState, setOpen, setReference, panelId } = useSidePanelContext();\n\n // useEventCallback gives a stable identity so consumers can memoise\n // around getTriggerProps without it churning on open/close.\n const getTriggerProps = useEventCallback(\n (userProps?: SidePanelTriggerExtraProps): SidePanelTriggerPropsResult => {\n const userOnClick = userProps?.onClick;\n const userRef = userProps?.ref;\n\n return {\n \"aria-expanded\": openState,\n \"aria-controls\": openState ? panelId : undefined,\n ...userProps,\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n userOnClick?.(event);\n setOpen(!openState);\n },\n ref: (node: HTMLElement | null) => {\n setReference(node);\n if (typeof userRef === \"function\") {\n userRef(node);\n } else if (\n userRef &&\n typeof userRef === \"object\" &&\n \"current\" in userRef\n ) {\n userRef.current = node;\n }\n },\n };\n },\n );\n\n return {\n openState,\n setOpen,\n getTriggerProps,\n setTriggerRef: setReference,\n panelId,\n };\n}\n"],"names":["useSidePanelContext","useEventCallback"],"mappings":";;;;;;;AAyEO,SAAS,YAAA,GAA+B;AAC7C,EAAA,MAAM,EAAE,SAAA,EAAW,OAAA,EAAS,YAAA,EAAc,OAAA,KAAYA,oCAAA,EAAoB;AAI1E,EAAA,MAAM,eAAA,GAAkBC,qBAAA;AAAA,IACtB,CAAC,SAAA,KAAwE;AACvE,MAAA,MAAM,cAAc,SAAA,IAAA,IAAA,GAAA,MAAA,GAAA,SAAA,CAAW,OAAA;AAC/B,MAAA,MAAM,UAAU,SAAA,IAAA,IAAA,GAAA,MAAA,GAAA,SAAA,CAAW,GAAA;AAE3B,MAAA,OAAO;AAAA,QACL,eAAA,EAAiB,SAAA;AAAA,QACjB,eAAA,EAAiB,YAAY,OAAA,GAAU,MAAA;AAAA,QACvC,GAAG,SAAA;AAAA,QACH,OAAA,EAAS,CAAC,KAAA,KAAyC;AACjD,UAAA,WAAA,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,CAAc,KAAA,CAAA;AACd,UAAA,OAAA,CAAQ,CAAC,SAAS,CAAA;AAAA,QACpB,CAAA;AAAA,QACA,GAAA,EAAK,CAAC,IAAA,KAA6B;AACjC,UAAA,YAAA,CAAa,IAAI,CAAA;AACjB,UAAA,IAAI,OAAO,YAAY,UAAA,EAAY;AACjC,YAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,UACd,WACE,OAAA,IACA,OAAO,OAAA,KAAY,QAAA,IACnB,aAAa,OAAA,EACb;AACA,YAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAAA,UACpB;AAAA,QACF;AAAA,OACF;AAAA,IACF;AAAA,GACF;AAEA,EAAA,OAAO;AAAA,IACL,SAAA;AAAA,IACA,OAAA;AAAA,IACA,eAAA;AAAA,IACA,aAAA,EAAe,YAAA;AAAA,IACf;AAAA,GACF;AACF;;;;"}
@@ -54,7 +54,7 @@ const Tree = react.forwardRef(
54
54
  toggleExpanded,
55
55
  select,
56
56
  selectedSet,
57
- setSelectedState,
57
+ setVisibleSelectionState,
58
58
  visibleNodes,
59
59
  getNodeMeta,
60
60
  getElement,
@@ -126,8 +126,10 @@ const Tree = react.forwardRef(
126
126
  if (activeNode) {
127
127
  const nodeMeta = getNodeMeta(activeNode);
128
128
  const isDisabled = disabledIdsSet.has(activeNode);
129
- if (!isDisabled && (nodeMeta == null ? void 0 : nodeMeta.hasChildren)) {
130
- if (!expandedState.has(activeNode)) {
129
+ const hasChildren = Boolean(nodeMeta == null ? void 0 : nodeMeta.hasChildren);
130
+ const isExpanded = expandedState.has(activeNode);
131
+ if (!isDisabled && hasChildren) {
132
+ if (!isExpanded) {
131
133
  toggleExpanded(event, activeNode);
132
134
  } else {
133
135
  const firstChild = visibleNodes.find(
@@ -146,7 +148,8 @@ const Tree = react.forwardRef(
146
148
  if (activeNode) {
147
149
  const isDisabled = disabledIdsSet.has(activeNode);
148
150
  if (!isDisabled) {
149
- if (expandedState.has(activeNode)) {
151
+ const isExpanded = expandedState.has(activeNode);
152
+ if (isExpanded) {
150
153
  toggleExpanded(event, activeNode);
151
154
  } else {
152
155
  const parent = getParent(activeNode);
@@ -243,7 +246,7 @@ const Tree = react.forwardRef(
243
246
  (visible) => selectedSet.has(visible)
244
247
  );
245
248
  const newSelected = allSelected ? [] : allVisibleValues;
246
- setSelectedState(newSelected);
249
+ setVisibleSelectionState(newSelected);
247
250
  onSelectionChange == null ? void 0 : onSelectionChange(event, newSelected);
248
251
  return;
249
252
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Tree.js","sources":["../src/tree/Tree.tsx"],"sourcesContent":["import { makePrefixer, useForkRef } from \"@salt-ds/core\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n type FocusEvent,\n forwardRef,\n type KeyboardEvent,\n type SyntheticEvent,\n useEffect,\n useRef,\n} from \"react\";\nimport treeCss from \"./Tree.css\";\nimport { TreeProvider } from \"./TreeContext\";\nimport { useTree } from \"./useTree\";\n\nexport interface TreeProps extends ComponentPropsWithoutRef<\"ul\"> {\n /**\n * Default expanded nodes (uncontrolled)\n */\n defaultExpanded?: string[];\n /**\n * Expanded nodes (controlled)\n */\n expanded?: string[];\n /**\n * Callback on expanded nodes change\n */\n onExpandedChange?: (event: SyntheticEvent, expanded: string[]) => void;\n /**\n * Default selected nodes (uncontrolled)\n */\n defaultSelected?: string[];\n /**\n * Selected nodes\n */\n selected?: string[];\n /**\n * Callback on selected nodes change\n */\n onSelectionChange?: (event: SyntheticEvent, selected: string[]) => void;\n /**\n * Sets multiselect mode with checkboxes and allows for multiple node selection\n */\n multiselect?: boolean;\n /**\n * Sets tree to disabled state, preventing all interaction\n */\n disabled?: boolean;\n}\n\nconst withBaseName = makePrefixer(\"saltTree\");\n\nexport const Tree = forwardRef<HTMLUListElement, TreeProps>(\n function Tree(props, ref) {\n const {\n children,\n className,\n defaultExpanded,\n expanded,\n onExpandedChange,\n defaultSelected,\n selected,\n onSelectionChange,\n multiselect = false,\n disabled = false,\n onKeyDown,\n onBlur,\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-tree\",\n css: treeCss,\n window: targetWindow,\n });\n\n const treeState = useTree({\n defaultExpanded,\n expanded,\n onExpandedChange,\n defaultSelected,\n selected,\n onSelectionChange,\n multiselect,\n disabled,\n children,\n });\n\n const {\n activeNode,\n setActiveNode,\n expandedArray,\n setExpandedArray,\n expandedState,\n toggleExpanded,\n select,\n selectedSet,\n setSelectedState,\n visibleNodes,\n getNodeMeta,\n getElement,\n getParent,\n getChildren,\n treeModel,\n disabledIdsSet,\n } = treeState;\n\n const lastKeypressRef = useRef<string>(\"\");\n const keypressTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const treeRef = useRef<HTMLUListElement>(null);\n\n useEffect(() => {\n return () => {\n if (keypressTimeoutRef.current) {\n clearTimeout(keypressTimeoutRef.current);\n }\n };\n }, []);\n\n const handleBlur = (event: FocusEvent<HTMLUListElement>) => {\n onBlur?.(event);\n const relatedTarget = event.relatedTarget as Node | null;\n if (!treeRef.current?.contains(relatedTarget)) {\n setActiveNode(undefined);\n }\n };\n\n const focusNode = (\n value: string,\n ): \"focused\" | \"already-focused\" | \"missing\" => {\n const element = getElement(value);\n if (!element) {\n return \"missing\";\n }\n\n const activeEl = targetWindow?.document.activeElement;\n if (activeEl === element) {\n return \"already-focused\";\n }\n\n element.focus();\n element.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n return \"focused\";\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLUListElement>) => {\n onKeyDown?.(event);\n\n if (disabled) return;\n\n if (visibleNodes.length === 0) return;\n\n const currentIndex = activeNode ? visibleNodes.indexOf(activeNode) : -1;\n\n let newActiveNode: string | undefined;\n let handled = false;\n\n switch (event.key) {\n case \"ArrowDown\": {\n handled = true;\n const nextIndex = currentIndex + 1;\n if (nextIndex < visibleNodes.length) {\n newActiveNode = visibleNodes[nextIndex];\n }\n break;\n }\n case \"ArrowUp\": {\n handled = true;\n const prevIndex = currentIndex - 1;\n if (prevIndex >= 0) {\n newActiveNode = visibleNodes[prevIndex];\n }\n break;\n }\n case \"ArrowRight\": {\n handled = true;\n if (activeNode) {\n const nodeMeta = getNodeMeta(activeNode);\n const isDisabled = disabledIdsSet.has(activeNode);\n if (!isDisabled && nodeMeta?.hasChildren) {\n if (!expandedState.has(activeNode)) {\n toggleExpanded(event, activeNode);\n } else {\n const firstChild = visibleNodes.find(\n (visibleNode) => getParent(visibleNode) === activeNode,\n );\n if (firstChild) {\n newActiveNode = firstChild;\n }\n }\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n handled = true;\n if (activeNode) {\n const isDisabled = disabledIdsSet.has(activeNode);\n if (!isDisabled) {\n if (expandedState.has(activeNode)) {\n toggleExpanded(event, activeNode);\n } else {\n const parent = getParent(activeNode);\n if (parent) {\n newActiveNode = parent;\n }\n }\n }\n }\n break;\n }\n case \"Home\": {\n handled = true;\n newActiveNode = visibleNodes[0];\n break;\n }\n case \"End\": {\n handled = true;\n newActiveNode = visibleNodes[visibleNodes.length - 1];\n break;\n }\n case \"Enter\": {\n handled = true;\n if (activeNode) {\n select(event, activeNode);\n }\n break;\n }\n case \" \": {\n handled = true;\n if (activeNode) {\n select(event, activeNode);\n }\n break;\n }\n case \"*\": {\n handled = true;\n if (activeNode) {\n const parent = getParent(activeNode);\n // Get siblings: either children of parent, or root nodes if no parent\n const siblings = parent\n ? getChildren(parent)\n : treeModel.rootValues;\n\n const toExpand = siblings.filter((sibling) => {\n const siblingMeta = getNodeMeta(sibling);\n return (\n siblingMeta?.hasChildren &&\n !expandedState.has(sibling) &&\n !disabledIdsSet.has(sibling)\n );\n });\n\n if (toExpand.length > 0) {\n const newExpanded = [...expandedArray, ...toExpand];\n setExpandedArray(newExpanded);\n onExpandedChange?.(event, newExpanded);\n }\n }\n break;\n }\n default: {\n // Type-ahead\n if (\n event.key.length === 1 &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.altKey\n ) {\n handled = true;\n\n if (keypressTimeoutRef.current) {\n clearTimeout(keypressTimeoutRef.current);\n }\n\n lastKeypressRef.current += event.key.toLowerCase();\n const searchString = lastKeypressRef.current;\n\n keypressTimeoutRef.current = setTimeout(() => {\n lastKeypressRef.current = \"\";\n }, 500);\n\n const currentIndex = activeNode\n ? visibleNodes.indexOf(activeNode)\n : -1;\n let found = false;\n\n for (let i = currentIndex + 1; i < visibleNodes.length; i++) {\n const element = getElement(visibleNodes[i]);\n if (\n element?.textContent?.toLowerCase().startsWith(searchString)\n ) {\n newActiveNode = visibleNodes[i];\n found = true;\n break;\n }\n }\n\n if (!found) {\n for (let i = 0; i <= currentIndex; i++) {\n const element = getElement(visibleNodes[i]);\n if (\n element?.textContent?.toLowerCase().startsWith(searchString)\n ) {\n newActiveNode = visibleNodes[i];\n break;\n }\n }\n }\n }\n break;\n }\n }\n\n if (\n (event.ctrlKey || event.metaKey) &&\n event.key === \"a\" &&\n multiselect\n ) {\n handled = true;\n event.preventDefault();\n\n const allVisibleValues = visibleNodes.filter(\n (visibleNode) => !disabledIdsSet.has(visibleNode),\n );\n const allSelected = allVisibleValues.every((visible) =>\n selectedSet.has(visible),\n );\n\n const newSelected = allSelected ? [] : allVisibleValues;\n\n setSelectedState(newSelected);\n onSelectionChange?.(event, newSelected);\n return;\n }\n\n if (\n event.shiftKey &&\n (event.key === \"ArrowUp\" || event.key === \"ArrowDown\") &&\n multiselect\n ) {\n handled = true;\n const isDown = event.key === \"ArrowDown\";\n const currentIndex = activeNode ? visibleNodes.indexOf(activeNode) : -1;\n const nextIndex = isDown ? currentIndex + 1 : currentIndex - 1;\n\n if (nextIndex >= 0 && nextIndex < visibleNodes.length) {\n const nextValue = visibleNodes[nextIndex];\n\n if (!disabledIdsSet.has(nextValue)) {\n select(event, nextValue);\n newActiveNode = nextValue;\n }\n }\n }\n\n if (handled) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n if (newActiveNode !== undefined) {\n const focusResult = focusNode(newActiveNode);\n if (focusResult !== \"focused\") {\n setActiveNode(newActiveNode);\n }\n }\n };\n\n const handleRef = useForkRef(treeRef, ref);\n\n return (\n <TreeProvider value={treeState}>\n <ul\n ref={handleRef}\n role=\"tree\"\n aria-multiselectable={multiselect ? true : undefined}\n aria-disabled={disabled || undefined}\n className={clsx(\n withBaseName(),\n { [withBaseName(\"disabled\")]: disabled },\n className,\n )}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n {...rest}\n >\n {children}\n </ul>\n </TreeProvider>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","Tree","useWindow","useComponentCssInjection","treeCss","useTree","useRef","useEffect","currentIndex","useForkRef","jsx","TreeProvider","clsx"],"mappings":"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"}
1
+ {"version":3,"file":"Tree.js","sources":["../src/tree/Tree.tsx"],"sourcesContent":["import { makePrefixer, useForkRef } from \"@salt-ds/core\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n type FocusEvent,\n forwardRef,\n type KeyboardEvent,\n type SyntheticEvent,\n useEffect,\n useRef,\n} from \"react\";\nimport treeCss from \"./Tree.css\";\nimport { TreeProvider } from \"./TreeContext\";\nimport { useTree } from \"./useTree\";\n\nexport interface TreeProps extends ComponentPropsWithoutRef<\"ul\"> {\n /**\n * Default expanded nodes (uncontrolled)\n */\n defaultExpanded?: string[];\n /**\n * Expanded nodes (controlled)\n */\n expanded?: string[];\n /**\n * Callback on expanded nodes change\n */\n onExpandedChange?: (event: SyntheticEvent, expanded: string[]) => void;\n /**\n * Default selected nodes (uncontrolled)\n */\n defaultSelected?: string[];\n /**\n * Selected nodes\n */\n selected?: string[];\n /**\n * Callback on selected nodes change\n */\n onSelectionChange?: (event: SyntheticEvent, selected: string[]) => void;\n /**\n * Sets multiselect mode with checkboxes and allows for multiple node selection\n */\n multiselect?: boolean;\n /**\n * Sets tree to disabled state, preventing all interaction\n */\n disabled?: boolean;\n}\n\nconst withBaseName = makePrefixer(\"saltTree\");\n\nexport const Tree = forwardRef<HTMLUListElement, TreeProps>(\n function Tree(props, ref) {\n const {\n children,\n className,\n defaultExpanded,\n expanded,\n onExpandedChange,\n defaultSelected,\n selected,\n onSelectionChange,\n multiselect = false,\n disabled = false,\n onKeyDown,\n onBlur,\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-tree\",\n css: treeCss,\n window: targetWindow,\n });\n\n const treeState = useTree({\n defaultExpanded,\n expanded,\n onExpandedChange,\n defaultSelected,\n selected,\n onSelectionChange,\n multiselect,\n disabled,\n children,\n });\n\n const {\n activeNode,\n setActiveNode,\n expandedArray,\n setExpandedArray,\n expandedState,\n toggleExpanded,\n select,\n selectedSet,\n setVisibleSelectionState,\n visibleNodes,\n getNodeMeta,\n getElement,\n getParent,\n getChildren,\n treeModel,\n disabledIdsSet,\n } = treeState;\n\n const lastKeypressRef = useRef<string>(\"\");\n const keypressTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const treeRef = useRef<HTMLUListElement>(null);\n\n useEffect(() => {\n return () => {\n if (keypressTimeoutRef.current) {\n clearTimeout(keypressTimeoutRef.current);\n }\n };\n }, []);\n\n const handleBlur = (event: FocusEvent<HTMLUListElement>) => {\n onBlur?.(event);\n const relatedTarget = event.relatedTarget as Node | null;\n if (!treeRef.current?.contains(relatedTarget)) {\n setActiveNode(undefined);\n }\n };\n\n const focusNode = (\n value: string,\n ): \"focused\" | \"already-focused\" | \"missing\" => {\n const element = getElement(value);\n if (!element) {\n return \"missing\";\n }\n\n const activeEl = targetWindow?.document.activeElement;\n if (activeEl === element) {\n return \"already-focused\";\n }\n\n element.focus();\n element.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n return \"focused\";\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLUListElement>) => {\n onKeyDown?.(event);\n\n if (disabled) return;\n\n if (visibleNodes.length === 0) return;\n\n const currentIndex = activeNode ? visibleNodes.indexOf(activeNode) : -1;\n\n let newActiveNode: string | undefined;\n let handled = false;\n\n switch (event.key) {\n case \"ArrowDown\": {\n handled = true;\n const nextIndex = currentIndex + 1;\n if (nextIndex < visibleNodes.length) {\n newActiveNode = visibleNodes[nextIndex];\n }\n break;\n }\n case \"ArrowUp\": {\n handled = true;\n const prevIndex = currentIndex - 1;\n if (prevIndex >= 0) {\n newActiveNode = visibleNodes[prevIndex];\n }\n break;\n }\n case \"ArrowRight\": {\n handled = true;\n if (activeNode) {\n const nodeMeta = getNodeMeta(activeNode);\n const isDisabled = disabledIdsSet.has(activeNode);\n const hasChildren = Boolean(nodeMeta?.hasChildren);\n const isExpanded = expandedState.has(activeNode);\n if (!isDisabled && hasChildren) {\n if (!isExpanded) {\n toggleExpanded(event, activeNode);\n } else {\n const firstChild = visibleNodes.find(\n (visibleNode) => getParent(visibleNode) === activeNode,\n );\n if (firstChild) {\n newActiveNode = firstChild;\n }\n }\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n handled = true;\n if (activeNode) {\n const isDisabled = disabledIdsSet.has(activeNode);\n if (!isDisabled) {\n const isExpanded = expandedState.has(activeNode);\n if (isExpanded) {\n toggleExpanded(event, activeNode);\n } else {\n const parent = getParent(activeNode);\n if (parent) {\n newActiveNode = parent;\n }\n }\n }\n }\n break;\n }\n case \"Home\": {\n handled = true;\n newActiveNode = visibleNodes[0];\n break;\n }\n case \"End\": {\n handled = true;\n newActiveNode = visibleNodes[visibleNodes.length - 1];\n break;\n }\n case \"Enter\": {\n handled = true;\n if (activeNode) {\n select(event, activeNode);\n }\n break;\n }\n case \" \": {\n handled = true;\n if (activeNode) {\n select(event, activeNode);\n }\n break;\n }\n case \"*\": {\n handled = true;\n if (activeNode) {\n const parent = getParent(activeNode);\n // Get siblings: either children of parent, or root nodes if no parent\n const siblings = parent\n ? getChildren(parent)\n : treeModel.rootValues;\n\n const toExpand = siblings.filter((sibling) => {\n const siblingMeta = getNodeMeta(sibling);\n return (\n siblingMeta?.hasChildren &&\n !expandedState.has(sibling) &&\n !disabledIdsSet.has(sibling)\n );\n });\n\n if (toExpand.length > 0) {\n const newExpanded = [...expandedArray, ...toExpand];\n setExpandedArray(newExpanded);\n onExpandedChange?.(event, newExpanded);\n }\n }\n break;\n }\n default: {\n // Type-ahead\n if (\n event.key.length === 1 &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.altKey\n ) {\n handled = true;\n\n if (keypressTimeoutRef.current) {\n clearTimeout(keypressTimeoutRef.current);\n }\n\n lastKeypressRef.current += event.key.toLowerCase();\n const searchString = lastKeypressRef.current;\n\n keypressTimeoutRef.current = setTimeout(() => {\n lastKeypressRef.current = \"\";\n }, 500);\n\n const currentIndex = activeNode\n ? visibleNodes.indexOf(activeNode)\n : -1;\n let found = false;\n\n for (let i = currentIndex + 1; i < visibleNodes.length; i++) {\n const element = getElement(visibleNodes[i]);\n if (\n element?.textContent?.toLowerCase().startsWith(searchString)\n ) {\n newActiveNode = visibleNodes[i];\n found = true;\n break;\n }\n }\n\n if (!found) {\n for (let i = 0; i <= currentIndex; i++) {\n const element = getElement(visibleNodes[i]);\n if (\n element?.textContent?.toLowerCase().startsWith(searchString)\n ) {\n newActiveNode = visibleNodes[i];\n break;\n }\n }\n }\n }\n break;\n }\n }\n\n if (\n (event.ctrlKey || event.metaKey) &&\n event.key === \"a\" &&\n multiselect\n ) {\n handled = true;\n event.preventDefault();\n\n const allVisibleValues = visibleNodes.filter(\n (visibleNode) => !disabledIdsSet.has(visibleNode),\n );\n const allSelected = allVisibleValues.every((visible) =>\n selectedSet.has(visible),\n );\n\n const newSelected = allSelected ? [] : allVisibleValues;\n\n setVisibleSelectionState(newSelected);\n onSelectionChange?.(event, newSelected);\n return;\n }\n\n if (\n event.shiftKey &&\n (event.key === \"ArrowUp\" || event.key === \"ArrowDown\") &&\n multiselect\n ) {\n handled = true;\n const isDown = event.key === \"ArrowDown\";\n const currentIndex = activeNode ? visibleNodes.indexOf(activeNode) : -1;\n const nextIndex = isDown ? currentIndex + 1 : currentIndex - 1;\n\n if (nextIndex >= 0 && nextIndex < visibleNodes.length) {\n const nextValue = visibleNodes[nextIndex];\n\n if (!disabledIdsSet.has(nextValue)) {\n select(event, nextValue);\n newActiveNode = nextValue;\n }\n }\n }\n\n if (handled) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n if (newActiveNode !== undefined) {\n const focusResult = focusNode(newActiveNode);\n if (focusResult !== \"focused\") {\n setActiveNode(newActiveNode);\n }\n }\n };\n\n const handleRef = useForkRef(treeRef, ref);\n\n return (\n <TreeProvider value={treeState}>\n <ul\n ref={handleRef}\n role=\"tree\"\n aria-multiselectable={multiselect ? true : undefined}\n aria-disabled={disabled || undefined}\n className={clsx(\n withBaseName(),\n { [withBaseName(\"disabled\")]: disabled },\n className,\n )}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n {...rest}\n >\n {children}\n </ul>\n </TreeProvider>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","Tree","useWindow","useComponentCssInjection","treeCss","useTree","useRef","useEffect","currentIndex","useForkRef","jsx","TreeProvider","clsx"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TreeContext.js","sources":["../src/tree/TreeContext.ts"],"sourcesContent":["import { createContext } from \"@salt-ds/core\";\nimport {\n type Dispatch,\n type ReactNode,\n type SetStateAction,\n type SyntheticEvent,\n useContext,\n} from \"react\";\nimport type { TreeModel, TreeNodeMeta } from \"./useTree\";\n\nexport interface TreeContextValue {\n expandedState: Set<string>;\n /** Toggle a node expansion state */\n toggleExpanded: (event: SyntheticEvent, value: string) => void;\n\n /** Selected node values */\n selectedState: string[];\n /** Selected node values as Set for O(1) lookups */\n selectedSet: Set<string>;\n /** Set selected state directly */\n setSelectedState: Dispatch<SetStateAction<string[]>>;\n /** Select node */\n select: (event: SyntheticEvent, value: string) => void;\n\n /** Whether multiselect mode with checkboxes is enabled */\n multiselect: boolean;\n /** Disabled state of the tree */\n disabled: boolean;\n /** Set of disabled node IDs */\n disabledIdsSet: Set<string>;\n\n /** Tree model for traversal */\n treeModel: TreeModel;\n /** Get node metadata from tree model */\n getNodeMeta: (value: string) => TreeNodeMeta | undefined;\n /** Get parent of a node */\n getParent: (value: string) => string | undefined;\n /** Get children of a node */\n getChildren: (value: string) => string[];\n /** Get all descendants of a node */\n getDescendants: (value: string) => string[];\n /** Get all ancestors of a node */\n getAncestors: (value: string) => string[];\n /** Memoized visible (navigable) nodes in tree order */\n visibleNodes: string[];\n /** Memoized tabbable node ID for roving tabindex (computed once at tree level) */\n tabbableNodeId: string | undefined;\n /** Register a DOM element for focus management */\n registerElement: (value: string, element: HTMLElement) => () => void;\n /** Get DOM element for a node (if mounted) */\n getElement: (value: string) => HTMLElement | undefined;\n /** Active node value */\n activeNode: string | undefined;\n /** Set the active node */\n setActiveNode: Dispatch<SetStateAction<string | undefined>>;\n\n /** Set of indeterminate (partially selected) node IDs */\n indeterminateState: Set<string>;\n}\n\nconst TreeContext = createContext<TreeContextValue | undefined>(\n \"Tree Context\",\n undefined,\n);\n\nexport const TreeProvider = TreeContext.Provider;\n\nexport function useTreeContext(): TreeContextValue {\n const context = useContext(TreeContext);\n if (!context) {\n throw new Error(\"useTreeContext must be used within a TreeProvider\");\n }\n return context;\n}\n\nexport interface TreeNodeContextValue {\n /** Current node value */\n value: string;\n /** Current depth level */\n level: number;\n /** Whether node has children */\n hasChildren: boolean;\n /** Whether node is expanded */\n expanded: boolean;\n /** Whether node is disabled */\n disabled: boolean;\n /** Node id for the li element */\n id: string;\n /** Whether node is selected */\n selected: boolean;\n /** Whether node is in indeterminate state (partially selected children) */\n indeterminate: boolean;\n /** Child TreeNode elements to be rendered inside the group */\n nodeChildren: ReactNode;\n}\n\nconst TreeNodeContext = createContext<TreeNodeContextValue | undefined>(\n \"TreeNodeContext\",\n undefined,\n);\n\nexport const TreeNodeProvider = TreeNodeContext.Provider;\n\nexport function useTreeNodeContext(): TreeNodeContextValue | undefined {\n return useContext(TreeNodeContext);\n}\n"],"names":["createContext","useContext"],"mappings":";;;;;AA4DA,MAAM,WAAA,GAAcA,kBAAA;AAAA,EAClB,cAAA;AAAA,EACA;AACF,CAAA;AAEO,MAAM,eAAe,WAAA,CAAY;AAEjC,SAAS,cAAA,GAAmC;AACjD,EAAA,MAAM,OAAA,GAAUC,iBAAW,WAAW,CAAA;AACtC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,mDAAmD,CAAA;AAAA,EACrE;AACA,EAAA,OAAO,OAAA;AACT;AAuBA,MAAM,eAAA,GAAkBD,kBAAA;AAAA,EACtB,iBAAA;AAAA,EACA;AACF,CAAA;AAEO,MAAM,mBAAmB,eAAA,CAAgB;AAEzC,SAAS,kBAAA,GAAuD;AACrE,EAAA,OAAOC,iBAAW,eAAe,CAAA;AACnC;;;;;;;"}
1
+ {"version":3,"file":"TreeContext.js","sources":["../src/tree/TreeContext.ts"],"sourcesContent":["import { createContext } from \"@salt-ds/core\";\nimport {\n type Dispatch,\n type ReactNode,\n type Ref,\n type RefObject,\n type SetStateAction,\n type SyntheticEvent,\n useContext,\n} from \"react\";\nimport type { TreeModel, TreeNodeMeta } from \"./useTree\";\n\nexport interface TreeContextValue {\n expandedState: Set<string>;\n /** Toggle a node expansion state */\n toggleExpanded: (event: SyntheticEvent, value: string) => void;\n\n /** Selected node values */\n selectedState: string[];\n /** Selected node values as Set for O(1) lookups */\n selectedSet: Set<string>;\n /** Set selected state directly */\n setSelectedState: Dispatch<SetStateAction<string[]>>;\n /** Set selected state without expanding selection through hidden descendants */\n setVisibleSelectionState: (selected: string[]) => void;\n /** Select node */\n select: (event: SyntheticEvent, value: string) => void;\n\n /** Whether multiselect mode with checkboxes is enabled */\n multiselect: boolean;\n /** Disabled state of the tree */\n disabled: boolean;\n /** Set of disabled node IDs */\n disabledIdsSet: Set<string>;\n\n /** Tree model for traversal */\n treeModel: TreeModel;\n /** Get node metadata from tree model */\n getNodeMeta: (value: string) => TreeNodeMeta | undefined;\n /** Get parent of a node */\n getParent: (value: string) => string | undefined;\n /** Get children of a node */\n getChildren: (value: string) => string[];\n /** Get all descendants of a node */\n getDescendants: (value: string) => string[];\n /** Get all ancestors of a node */\n getAncestors: (value: string) => string[];\n /** Memoized visible (navigable) nodes in tree order */\n visibleNodes: string[];\n /** Memoized tabbable node ID for roving tabindex (computed once at tree level) */\n tabbableNodeId: string | undefined;\n /** Register a DOM element for focus management */\n registerElement: (value: string, element: HTMLElement) => () => void;\n /** Get DOM element for a node (if mounted) */\n getElement: (value: string) => HTMLElement | undefined;\n /** Active node value */\n activeNode: string | undefined;\n /** Set the active node */\n setActiveNode: Dispatch<SetStateAction<string | undefined>>;\n\n /** Set of indeterminate (partially selected) node IDs */\n indeterminateState: Set<string>;\n}\n\nconst TreeContext = createContext<TreeContextValue | undefined>(\n \"Tree Context\",\n undefined,\n);\n\nexport const TreeProvider = TreeContext.Provider;\n\nexport function useTreeContext(): TreeContextValue {\n const context = useContext(TreeContext);\n if (!context) {\n throw new Error(\"useTreeContext must be used within a TreeProvider\");\n }\n return context;\n}\n\nexport interface TreeNodeContextValue {\n /** Current node value */\n value: string;\n /** Current depth level */\n level: number;\n /** Whether node has children */\n hasChildren: boolean;\n /** Whether node is expanded */\n expanded: boolean;\n /** Whether node is disabled */\n disabled: boolean;\n /** Node id for the li element */\n id: string;\n /** Ref for the li element rendered by TreeNodeTrigger */\n nodeRef: RefObject<HTMLLIElement>;\n /** Callback ref that connects TreeNode's forwarded ref to the li element */\n setNodeRef: Ref<HTMLLIElement> | null;\n /** Whether node is selected */\n selected: boolean;\n /** Whether node is in indeterminate state (partially selected children) */\n indeterminate: boolean;\n /** Child TreeNode elements to be rendered inside the group */\n nodeChildren: ReactNode;\n}\n\nconst TreeNodeContext = createContext<TreeNodeContextValue | undefined>(\n \"TreeNodeContext\",\n undefined,\n);\n\nexport const TreeNodeProvider = TreeNodeContext.Provider;\n\nexport function useTreeNodeContext(): TreeNodeContextValue | undefined {\n return useContext(TreeNodeContext);\n}\n"],"names":["createContext","useContext"],"mappings":";;;;;AAgEA,MAAM,WAAA,GAAcA,kBAAA;AAAA,EAClB,cAAA;AAAA,EACA;AACF,CAAA;AAEO,MAAM,eAAe,WAAA,CAAY;AAEjC,SAAS,cAAA,GAAmC;AACjD,EAAA,MAAM,OAAA,GAAUC,iBAAW,WAAW,CAAA;AACtC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,mDAAmD,CAAA;AAAA,EACrE;AACA,EAAA,OAAO,OAAA;AACT;AA2BA,MAAM,eAAA,GAAkBD,kBAAA;AAAA,EACtB,iBAAA;AAAA,EACA;AACF,CAAA;AAEO,MAAM,mBAAmB,eAAA,CAAgB;AAEzC,SAAS,kBAAA,GAAuD;AACrE,EAAA,OAAOC,iBAAW,eAAe,CAAA;AACnC;;;;;;;"}
@@ -9,18 +9,19 @@ var TreeContext = require('./TreeContext.js');
9
9
  var TreeNode$1 = require('./TreeNode.css.js');
10
10
  var TreeNodeLabel = require('./TreeNodeLabel.js');
11
11
  var TreeNodeTrigger = require('./TreeNodeTrigger.js');
12
+ var treeModel = require('./treeModel.js');
12
13
 
13
14
  const withBaseName = core.makePrefixer("saltTreeNode");
14
15
  function separateChildren(children) {
15
16
  const contentChildren = [];
16
17
  const nodeChildren = [];
17
- react.Children.forEach(children, (child) => {
18
- if (react.isValidElement(child) && typeof child.props.value === "string") {
18
+ for (const child of treeModel.flattenTreeNodeChildren(children)) {
19
+ if (treeModel.isTreeNodeElement(child)) {
19
20
  nodeChildren.push(child);
20
- } else if (child != null) {
21
+ } else {
21
22
  contentChildren.push(child);
22
23
  }
23
- });
24
+ }
24
25
  return { contentChildren, nodeChildren };
25
26
  }
26
27
  const TreeNode = react.forwardRef(
@@ -38,31 +39,31 @@ const TreeNode = react.forwardRef(
38
39
  css: TreeNode$1,
39
40
  window: targetWindow
40
41
  });
41
- const id = core.useId(value) ?? value;
42
+ const id = core.useIdMemo();
42
43
  const {
43
44
  expandedState,
44
45
  selectedSet,
45
46
  disabled: treeDisabled,
46
47
  disabledIdsSet,
47
- indeterminateState,
48
- getElement
48
+ indeterminateState
49
49
  } = TreeContext.useTreeContext();
50
50
  const parentContext = TreeContext.useTreeNodeContext();
51
51
  const level = ((parentContext == null ? void 0 : parentContext.level) ?? 0) + 1;
52
- const disabled = treeDisabled || disabledProp || disabledIdsSet.has(value);
52
+ const disabled = treeDisabled || (parentContext == null ? void 0 : parentContext.disabled) || disabledProp || disabledIdsSet.has(value);
53
53
  const expanded = expandedState.has(value);
54
54
  const selected = selectedSet.has(value);
55
55
  const indeterminate = indeterminateState.has(value);
56
56
  const usesLabelProp = label !== void 0;
57
57
  const { contentChildren, nodeChildren } = react.useMemo(
58
- () => usesLabelProp ? { contentChildren: [], nodeChildren: react.Children.toArray(children) } : separateChildren(children),
58
+ () => usesLabelProp ? {
59
+ contentChildren: [],
60
+ nodeChildren: treeModel.flattenTreeNodeChildren(children)
61
+ } : separateChildren(children),
59
62
  [children, usesLabelProp]
60
63
  );
61
- const hasChildren = nodeChildren.length > 0;
62
- react.useImperativeHandle(ref, () => getElement(value), [
63
- getElement,
64
- value
65
- ]);
64
+ const hasChildren = nodeChildren.some(treeModel.isTreeNodeElement);
65
+ const nodeRef = react.useRef(null);
66
+ const setNodeRef = core.useForkRef(nodeRef, ref);
66
67
  const nodeContext = react.useMemo(
67
68
  () => ({
68
69
  value,
@@ -71,6 +72,8 @@ const TreeNode = react.forwardRef(
71
72
  expanded,
72
73
  disabled,
73
74
  id,
75
+ nodeRef,
76
+ setNodeRef,
74
77
  selected,
75
78
  indeterminate,
76
79
  nodeChildren
@@ -82,6 +85,7 @@ const TreeNode = react.forwardRef(
82
85
  expanded,
83
86
  disabled,
84
87
  id,
88
+ setNodeRef,
85
89
  selected,
86
90
  indeterminate,
87
91
  nodeChildren