@fusion.dev/helix-headless 0.144.0 → 0.146.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/custom-elements.json +15195 -4240
  2. package/dist/accordion/item/accordion-item.d.ts +62 -12
  3. package/dist/accordion/item/accordion-item.js +41 -10
  4. package/dist/accordion/root/accordion-root.d.ts +14 -5
  5. package/dist/accordion/root/accordion-root.js +7 -1
  6. package/dist/announcement/root/announcement-root.d.ts +24 -3
  7. package/dist/announcement/root/announcement-root.js +39 -2
  8. package/dist/app-header/root/app-header-root.d.ts +12 -0
  9. package/dist/app-header/root/app-header-root.js +13 -1
  10. package/dist/app-header/sectioning.d.ts +9 -0
  11. package/dist/app-header/sectioning.js +27 -0
  12. package/dist/avatar/group/avatar-group.d.ts +20 -14
  13. package/dist/avatar/group/avatar-group.js +17 -19
  14. package/dist/badge/root/badge-root.d.ts +3 -1
  15. package/dist/badge/root/badge-root.js +2 -2
  16. package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
  17. package/dist/bar-chart/root/bar-chart-root.js +52 -15
  18. package/dist/bar-chart/stack.d.ts +15 -0
  19. package/dist/bar-chart/stack.js +19 -0
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +57 -1
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +73 -3
  22. package/dist/button/root/button-root.d.ts +26 -0
  23. package/dist/button/root/button-root.js +38 -18
  24. package/dist/button-group/root/button-group-root.d.ts +2 -1
  25. package/dist/button-group/root/button-group-root.js +5 -1
  26. package/dist/canvas/node/canvas-node.d.ts +4 -3
  27. package/dist/canvas/node/canvas-node.js +3 -2
  28. package/dist/canvas/root/canvas-root.d.ts +38 -3
  29. package/dist/canvas/root/canvas-root.js +123 -42
  30. package/dist/card/root/card-root.d.ts +24 -3
  31. package/dist/card/root/card-root.js +20 -8
  32. package/dist/carousel/root/carousel-root.d.ts +133 -4
  33. package/dist/carousel/root/carousel-root.js +174 -24
  34. package/dist/carousel/stops.d.ts +20 -0
  35. package/dist/carousel/stops.js +30 -0
  36. package/dist/chat/composer/chat-composer.d.ts +38 -6
  37. package/dist/chat/composer/chat-composer.js +42 -9
  38. package/dist/chat/message/chat-message.d.ts +32 -1
  39. package/dist/chat/message/chat-message.js +27 -10
  40. package/dist/chat/naming.d.ts +26 -0
  41. package/dist/chat/naming.js +14 -0
  42. package/dist/chat/root/chat-root.d.ts +58 -0
  43. package/dist/chat/root/chat-root.js +43 -3
  44. package/dist/checkbox/root/checkbox-root.d.ts +20 -0
  45. package/dist/checkbox/root/checkbox-root.js +14 -1
  46. package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
  47. package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
  48. package/dist/checkbox-group/select-all.d.ts +27 -0
  49. package/dist/checkbox-group/select-all.js +12 -0
  50. package/dist/code-block/highlight.d.ts +15 -0
  51. package/dist/code-block/highlight.js +4 -0
  52. package/dist/code-block/root/code-block-root.d.ts +57 -2
  53. package/dist/code-block/root/code-block-root.js +63 -8
  54. package/dist/color-input/root/color-input-root.d.ts +3 -0
  55. package/dist/color-input/root/color-input-root.js +6 -3
  56. package/dist/color-picker/root/color-picker-root.d.ts +33 -4
  57. package/dist/color-picker/root/color-picker-root.js +80 -21
  58. package/dist/color-picker/swatches.d.ts +12 -0
  59. package/dist/color-picker/swatches.js +26 -0
  60. package/dist/combobox/root/combobox-root.d.ts +43 -0
  61. package/dist/combobox/root/combobox-root.js +79 -15
  62. package/dist/command/root/command-root.d.ts +16 -1
  63. package/dist/command/root/command-root.js +22 -4
  64. package/dist/copy-button/root/copy-button-root.d.ts +26 -1
  65. package/dist/copy-button/root/copy-button-root.js +12 -5
  66. package/dist/data-table/index.d.ts +1 -1
  67. package/dist/data-table/index.js +1 -1
  68. package/dist/data-table/keys.d.ts +24 -0
  69. package/dist/data-table/keys.js +24 -0
  70. package/dist/data-table/root/data-table-root.d.ts +170 -13
  71. package/dist/data-table/root/data-table-root.js +294 -52
  72. package/dist/data-table/tree.d.ts +55 -0
  73. package/dist/data-table/tree.js +54 -0
  74. package/dist/date-input/root/date-input-root.d.ts +3 -1
  75. package/dist/date-input/root/date-input-root.js +18 -7
  76. package/dist/date-picker/root/date-picker-root.js +12 -6
  77. package/dist/description-list/item/description-list-item.d.ts +17 -2
  78. package/dist/description-list/item/description-list-item.js +15 -2
  79. package/dist/description-list/root/description-list-root.d.ts +27 -1
  80. package/dist/description-list/root/description-list-root.js +26 -1
  81. package/dist/dialog/description.js +15 -1
  82. package/dist/dialog/root/dialog-root.d.ts +8 -2
  83. package/dist/dialog/root/dialog-root.js +16 -1
  84. package/dist/divider/root/divider-root.d.ts +3 -0
  85. package/dist/divider/root/divider-root.js +2 -1
  86. package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
  87. package/dist/donut-chart/root/donut-chart-root.js +48 -1
  88. package/dist/drawer/reveal.d.ts +8 -0
  89. package/dist/drawer/reveal.js +1 -0
  90. package/dist/drawer/root/drawer-root.d.ts +59 -0
  91. package/dist/drawer/root/drawer-root.js +63 -4
  92. package/dist/drilldown/item/drilldown-item.d.ts +11 -6
  93. package/dist/drilldown/item/drilldown-item.js +8 -5
  94. package/dist/drilldown/root/drilldown-root.d.ts +29 -0
  95. package/dist/drilldown/root/drilldown-root.js +28 -5
  96. package/dist/element-events.generated.js +83 -12
  97. package/dist/empty/root/empty-root.d.ts +3 -1
  98. package/dist/empty/root/empty-root.js +3 -2
  99. package/dist/file-input/root/file-input-root.d.ts +69 -6
  100. package/dist/file-input/root/file-input-root.js +82 -19
  101. package/dist/file-input/screen.d.ts +2 -1
  102. package/dist/filter-input/menu/filter-menu.d.ts +5 -0
  103. package/dist/filter-input/menu/filter-menu.js +16 -4
  104. package/dist/filter-input/root/filter-input-root.d.ts +30 -6
  105. package/dist/filter-input/root/filter-input-root.js +1 -1
  106. package/dist/filter-input/suggest.d.ts +28 -3
  107. package/dist/filter-input/suggest.js +18 -8
  108. package/dist/format-date/root/format-date-root.d.ts +9 -16
  109. package/dist/format-date/root/format-date-root.js +10 -27
  110. package/dist/heatmap/root/heatmap-root.d.ts +24 -13
  111. package/dist/heatmap/root/heatmap-root.js +34 -12
  112. package/dist/icon/root/icon-root.d.ts +12 -1
  113. package/dist/icon/root/icon-root.js +21 -10
  114. package/dist/icon/settle.d.ts +7 -0
  115. package/dist/icon/settle.js +10 -0
  116. package/dist/icon-button/root/icon-button-root.d.ts +2 -0
  117. package/dist/image/root/image-root.d.ts +5 -1
  118. package/dist/image/root/image-root.js +10 -2
  119. package/dist/input/root/input-root.d.ts +13 -3
  120. package/dist/input/root/input-root.js +12 -3
  121. package/dist/kbd/root/kbd-root.d.ts +35 -1
  122. package/dist/kbd/root/kbd-root.js +23 -4
  123. package/dist/legend/root/legend-root.d.ts +55 -8
  124. package/dist/legend/root/legend-root.js +55 -13
  125. package/dist/lightbox/root/lightbox-root.d.ts +49 -6
  126. package/dist/lightbox/root/lightbox-root.js +86 -19
  127. package/dist/lightbox/zoom-controller.d.ts +59 -0
  128. package/dist/lightbox/zoom-controller.js +128 -0
  129. package/dist/lightbox/zoom.d.ts +22 -0
  130. package/dist/lightbox/zoom.js +16 -0
  131. package/dist/line-chart/root/line-chart-root.d.ts +22 -1
  132. package/dist/line-chart/root/line-chart-root.js +21 -1
  133. package/dist/list/item/list-item.d.ts +70 -1
  134. package/dist/list/item/list-item.js +77 -6
  135. package/dist/list/numbering.d.ts +14 -0
  136. package/dist/list/numbering.js +8 -0
  137. package/dist/list/root/list-root.d.ts +155 -9
  138. package/dist/list/root/list-root.js +246 -4
  139. package/dist/list/selection.d.ts +49 -0
  140. package/dist/list/selection.js +30 -0
  141. package/dist/listbox/root/listbox-root.d.ts +37 -1
  142. package/dist/listbox/root/listbox-root.js +49 -4
  143. package/dist/loader/busy.d.ts +10 -0
  144. package/dist/loader/busy.js +11 -0
  145. package/dist/loader/root/loader-root.d.ts +9 -2
  146. package/dist/loader/root/loader-root.js +23 -3
  147. package/dist/map/root/map-root.d.ts +6 -2
  148. package/dist/map/root/map-root.js +5 -2
  149. package/dist/megamenu/root/megamenu-root.d.ts +62 -0
  150. package/dist/megamenu/root/megamenu-root.js +90 -5
  151. package/dist/menu/index.d.ts +1 -0
  152. package/dist/menu/index.js +1 -0
  153. package/dist/menu/item/menu-item.d.ts +87 -11
  154. package/dist/menu/item/menu-item.js +78 -22
  155. package/dist/menu/root/menu-root.d.ts +39 -1
  156. package/dist/menu/root/menu-root.js +65 -8
  157. package/dist/menu/section/menu-section.d.ts +55 -0
  158. package/dist/menu/section/menu-section.js +60 -0
  159. package/dist/meter/root/meter-root.d.ts +20 -1
  160. package/dist/meter/root/meter-root.js +11 -15
  161. package/dist/navigation/root/navigation-root.d.ts +18 -2
  162. package/dist/navigation/root/navigation-root.js +29 -3
  163. package/dist/notifications/root/notifications-root.d.ts +25 -0
  164. package/dist/notifications/root/notifications-root.js +33 -5
  165. package/dist/number-input/root/number-input-root.d.ts +17 -8
  166. package/dist/number-input/root/number-input-root.js +2 -7
  167. package/dist/object-inspector/root/object-inspector-root.d.ts +161 -32
  168. package/dist/object-inspector/root/object-inspector-root.js +264 -123
  169. package/dist/object-inspector/rows.d.ts +75 -0
  170. package/dist/object-inspector/rows.js +119 -0
  171. package/dist/option/root/option-root.d.ts +5 -3
  172. package/dist/outline/levels.d.ts +31 -0
  173. package/dist/outline/levels.js +23 -0
  174. package/dist/outline/root/outline-root.d.ts +86 -3
  175. package/dist/outline/root/outline-root.js +95 -12
  176. package/dist/pagination/size/pagination-size.d.ts +12 -2
  177. package/dist/pagination/size/pagination-size.js +20 -5
  178. package/dist/pin-input/code.d.ts +10 -0
  179. package/dist/pin-input/code.js +13 -0
  180. package/dist/pin-input/root/pin-input-root.d.ts +25 -1
  181. package/dist/pin-input/root/pin-input-root.js +10 -11
  182. package/dist/popover/hide-outside.d.ts +14 -0
  183. package/dist/popover/hide-outside.js +41 -0
  184. package/dist/popover/root/popover-root.d.ts +57 -7
  185. package/dist/popover/root/popover-root.js +58 -3
  186. package/dist/progress/root/progress-root.d.ts +20 -0
  187. package/dist/progress/root/progress-root.js +15 -15
  188. package/dist/qr-code/export.d.ts +26 -1
  189. package/dist/qr-code/export.js +14 -0
  190. package/dist/qr-code/root/qr-code-root.d.ts +19 -5
  191. package/dist/qr-code/root/qr-code-root.js +58 -9
  192. package/dist/quote/marks.d.ts +8 -0
  193. package/dist/quote/marks.js +5 -0
  194. package/dist/quote/root/quote-root.d.ts +14 -2
  195. package/dist/quote/root/quote-root.js +23 -1
  196. package/dist/radio/group/radio-group.d.ts +4 -10
  197. package/dist/radio/group/radio-group.js +5 -10
  198. package/dist/radio/root/radio-root.d.ts +6 -2
  199. package/dist/radio/root/radio-root.js +6 -1
  200. package/dist/rating/root/rating-root.d.ts +10 -5
  201. package/dist/rating/root/rating-root.js +32 -8
  202. package/dist/rating/steps.d.ts +7 -0
  203. package/dist/rating/steps.js +9 -0
  204. package/dist/scatter-chart/fit.d.ts +15 -0
  205. package/dist/scatter-chart/fit.js +35 -0
  206. package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
  207. package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
  208. package/dist/scroll-area/root/scroll-area-root.d.ts +84 -0
  209. package/dist/scroll-area/root/scroll-area-root.js +106 -7
  210. package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
  211. package/dist/scroll-area/scrollbar-controller.js +172 -0
  212. package/dist/scroll-area/scrollbar.d.ts +92 -0
  213. package/dist/scroll-area/scrollbar.js +33 -0
  214. package/dist/select/root/select-root.d.ts +15 -0
  215. package/dist/select/root/select-root.js +18 -6
  216. package/dist/skeleton/root/skeleton-root.d.ts +3 -0
  217. package/dist/skeleton/root/skeleton-root.js +4 -2
  218. package/dist/skip-link/root/skip-link-root.js +2 -2
  219. package/dist/slider/root/slider-root.d.ts +41 -4
  220. package/dist/slider/root/slider-root.js +23 -3
  221. package/dist/sparkline/readings.d.ts +18 -0
  222. package/dist/sparkline/readings.js +19 -0
  223. package/dist/sparkline/root/sparkline-root.d.ts +78 -7
  224. package/dist/sparkline/root/sparkline-root.js +118 -23
  225. package/dist/speed-dial/root/speed-dial-root.js +2 -2
  226. package/dist/splitter/root/splitter-root.d.ts +20 -12
  227. package/dist/splitter/root/splitter-root.js +226 -203
  228. package/dist/splitter/snap.d.ts +9 -0
  229. package/dist/splitter/snap.js +12 -0
  230. package/dist/stat/root/stat-root.d.ts +14 -5
  231. package/dist/stat/root/stat-root.js +21 -5
  232. package/dist/steps/reach.d.ts +20 -0
  233. package/dist/steps/reach.js +15 -0
  234. package/dist/steps/root/steps-root.d.ts +76 -0
  235. package/dist/steps/root/steps-root.js +93 -1
  236. package/dist/steps/step/step.d.ts +45 -2
  237. package/dist/steps/step/step.js +33 -6
  238. package/dist/switch/root/switch-root.d.ts +10 -0
  239. package/dist/table/column/table-column.d.ts +11 -10
  240. package/dist/table/column/table-column.js +8 -19
  241. package/dist/table/root/table-root.d.ts +126 -4
  242. package/dist/table/root/table-root.js +156 -6
  243. package/dist/table/row/table-row.d.ts +47 -1
  244. package/dist/table/row/table-row.js +39 -2
  245. package/dist/tabs/panel/tab-panel.d.ts +22 -5
  246. package/dist/tabs/panel/tab-panel.js +34 -6
  247. package/dist/tabs/root/tabs-root.d.ts +37 -1
  248. package/dist/tabs/root/tabs-root.js +22 -4
  249. package/dist/tabs/tab/tab.d.ts +41 -4
  250. package/dist/tabs/tab/tab.js +49 -3
  251. package/dist/tag/group/tag-group.d.ts +31 -4
  252. package/dist/tag/group/tag-group.js +46 -7
  253. package/dist/tag/root/tag-root.js +9 -2
  254. package/dist/textarea/root/textarea-root.d.ts +28 -1
  255. package/dist/textarea/root/textarea-root.js +40 -1
  256. package/dist/time-input/root/time-input-root.d.ts +5 -1
  257. package/dist/time-input/root/time-input-root.js +16 -8
  258. package/dist/time-picker/root/time-picker-root.d.ts +18 -4
  259. package/dist/time-picker/root/time-picker-root.js +7 -10
  260. package/dist/time-picker/wheel-name.d.ts +9 -0
  261. package/dist/time-picker/wheel-name.js +15 -0
  262. package/dist/timeline/group/timeline-group.d.ts +46 -0
  263. package/dist/timeline/group/timeline-group.js +37 -0
  264. package/dist/timeline/index.d.ts +1 -0
  265. package/dist/timeline/index.js +1 -0
  266. package/dist/timeline/root/timeline-root.d.ts +10 -3
  267. package/dist/toast/item/toast-item.d.ts +24 -18
  268. package/dist/toast/item/toast-item.js +36 -40
  269. package/dist/toast/root/toast-root.d.ts +6 -0
  270. package/dist/toast/root/toast-root.js +16 -1
  271. package/dist/toggle/group/toggle-group.d.ts +24 -3
  272. package/dist/toggle/group/toggle-group.js +34 -5
  273. package/dist/toolbar/root/toolbar-root.d.ts +13 -0
  274. package/dist/toolbar/root/toolbar-root.js +15 -5
  275. package/dist/tooltip/root/tooltip-root.d.ts +13 -2
  276. package/dist/tooltip/root/tooltip-root.js +9 -1
  277. package/dist/tour/back.d.ts +10 -0
  278. package/dist/tour/back.js +8 -0
  279. package/dist/tour/root/tour-root.d.ts +30 -2
  280. package/dist/tour/root/tour-root.js +34 -8
  281. package/dist/tree/item/tree-item.d.ts +61 -4
  282. package/dist/tree/item/tree-item.js +92 -20
  283. package/dist/tree/root/tree-root.d.ts +58 -0
  284. package/dist/tree/root/tree-root.js +80 -16
  285. package/dist/tree/selection.d.ts +24 -0
  286. package/dist/tree/selection.js +13 -0
  287. package/dist/trend/root/trend-root.d.ts +43 -18
  288. package/dist/trend/root/trend-root.js +31 -6
  289. package/dist/video/media-events.d.ts +44 -0
  290. package/dist/video/media-events.js +35 -0
  291. package/dist/video/root/video-root.d.ts +117 -18
  292. package/dist/video/root/video-root.js +93 -47
  293. package/dist/video-playlist/menu/video-playlist-menu.d.ts +5 -0
  294. package/dist/video-playlist/menu/video-playlist-menu.js +3 -1
  295. package/dist/video-playlist/order.d.ts +41 -0
  296. package/dist/video-playlist/order.js +34 -0
  297. package/dist/video-playlist/root/video-playlist-root.d.ts +77 -3
  298. package/dist/video-playlist/root/video-playlist-root.js +60 -16
  299. package/dist/virtual-list/controls.d.ts +4 -0
  300. package/dist/virtual-list/controls.js +30 -0
  301. package/dist/virtual-list/fill.d.ts +22 -0
  302. package/dist/virtual-list/fill.js +23 -0
  303. package/dist/virtual-list/keys.d.ts +15 -0
  304. package/dist/virtual-list/keys.js +24 -0
  305. package/dist/virtual-list/plan.d.ts +49 -0
  306. package/dist/virtual-list/plan.js +16 -0
  307. package/dist/virtual-list/root/virtual-list-root.d.ts +259 -26
  308. package/dist/virtual-list/root/virtual-list-root.js +333 -49
  309. package/lint.json +1 -1
  310. package/package.json +8 -8
  311. package/types/jsx.d.ts +8113 -1394
  312. package/types/svelte.d.ts +2 -0
  313. package/types/vue.d.ts +1678 -353
  314. package/dist/data-table/root/order.d.ts +0 -141
  315. package/dist/data-table/root/order.js +0 -76
  316. package/dist/listbox/range.d.ts +0 -17
  317. package/dist/listbox/range.js +0 -5
  318. package/dist/tag/selection.d.ts +0 -10
  319. package/dist/tag/selection.js +0 -12
@@ -21,7 +21,15 @@ declare const HelixHeadlessTreeItem_base: (new (...args: any[]) => import("@fusi
21
21
  *
22
22
  * Pressing a branch, or Enter or Space on it, opens or closes it. A branch with
23
23
  * a `value` is chosen as well and sends `helix-select`, unless the tree has
24
- * `nesting="heading"`, where a branch names the list under it.
24
+ * `nesting="heading"`, where a branch names the list under it, or
25
+ * `selection-mode="leaf"`, where only the items at the ends are chosen.
26
+ *
27
+ * A `disabled` item is reached by the arrow keys and announced as unavailable,
28
+ * and a press, Enter or Space on it does nothing.
29
+ *
30
+ * A `lazy` item is a branch whose children you load when it opens: opening it
31
+ * sends `helix-load`, the row says it is busy, and the children you add appear
32
+ * in it. Remove `lazy` once they are in.
25
33
  *
26
34
  * @since 0.1.0
27
35
  * @status stable
@@ -29,15 +37,20 @@ declare const HelixHeadlessTreeItem_base: (new (...args: any[]) => import("@fusi
29
37
  * @documentation https://fusion.dev/helix/components/tree
30
38
  *
31
39
  * @slot - The item's label.
40
+ * @slot chevron - Replaces the expand and collapse mark of a branch, such as with your own icon.
32
41
  * @slot children - Nested items, which make this a branch.
33
42
  * @slot end - Content after the label, at the far side of the row, such as a count or a state.
34
43
  * @slot start - Content before the label and after the chevron, such as a mark for the item.
35
44
  *
36
45
  * @event {HelixBeforeCloseEvent} helix-before-close - Fired before a branch closes, and cancelable.
37
46
  * @event {HelixBeforeOpenEvent} helix-before-open - Fired before a branch opens, and cancelable.
47
+ * @event {HelixLoadEvent} helix-load - Fired when a `lazy` item opens, so you can load its children.
38
48
  * @event {HelixSelectEvent} helix-select - Fired when the item is chosen, and cancelable. Canceling it changes nothing.
39
49
  * @event {ToggleEvent} toggle - Sent when the branch opens or closes, with `newState` and `oldState`.
40
50
  *
51
+ * @csspart checkbox - The check mark's box, in a tree with `selection-mode="multiple"`.
52
+ * @csspart checkbox-checked - The check mark's box while the item is checked.
53
+ * @csspart checkbox-mixed - The check mark's box while some of a branch's items are checked.
41
54
  * @csspart group - The container for nested items.
42
55
  * @csspart item - The node, and the focus target unless `href` moves it to the row.
43
56
  * @csspart label - The label text.
@@ -46,14 +59,33 @@ declare const HelixHeadlessTreeItem_base: (new (...args: any[]) => import("@fusi
46
59
  *
47
60
  * @cssproperty --tree-level - How deep this row sits, counting from one as `aria-level` does, for the indent.
48
61
  *
62
+ * @cssstate checked - While it is checked, in a tree with `selection-mode="multiple"`.
63
+ * @cssstate loading - While a `lazy` item is open and its children have not arrived.
64
+ * @cssstate mixed - While some of a branch's items are checked, in a tree with `selection-mode="multiple"`.
49
65
  * @cssstate open - While its children are shown.
50
66
  * @cssstate selected - While it is selected.
51
67
  */
52
68
  export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
69
+ /**
70
+ * @internal Set by the tree: whether the item draws a check mark and is
71
+ * checked rather than selected, as under `selection-mode="multiple"`.
72
+ */
73
+ checkable: boolean;
74
+ /**
75
+ * @internal Set by the tree in `selection-mode="multiple"`: whether the item
76
+ * is checked, `mixed` for a branch some of whose items are.
77
+ */
78
+ checked: boolean | 'mixed';
79
+ /**
80
+ * Whether the item cannot be chosen, opened or followed. The arrow keys still
81
+ * reach it, so a reader knows it is there.
82
+ */
83
+ disabled: boolean;
53
84
  /**
54
85
  * @internal Set by the tree: whether a branch heads the list under it, as
55
- * under `nesting="heading"`. Such a branch only opens and closes when it is
56
- * pressed, because it names a list and is not a destination of its own.
86
+ * under `nesting="heading"`, or is not chosen at all, as under
87
+ * `selection-mode="leaf"`. Such a branch only opens and closes when it is
88
+ * pressed.
57
89
  */
58
90
  heads: boolean;
59
91
  /**
@@ -64,6 +96,13 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
64
96
  * current page on every item a consumer never asked to be one.
65
97
  */
66
98
  href: string;
99
+ /**
100
+ * Whether the item is a branch whose children are loaded when it opens.
101
+ *
102
+ * Opening it sends `helix-load`. Add the children to its `children` slot,
103
+ * and remove `lazy` once they are in, as Web Awesome's tree item does.
104
+ */
105
+ lazy: boolean;
67
106
  /**
68
107
  * The node's depth from the root. The tree counts it, so indentation needs no
69
108
  * nested CSS.
@@ -151,7 +190,7 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
151
190
  * row rather than the wrapper around it.
152
191
  */
153
192
  focusItem(): void;
154
- /** Selects this node and sends `helix-select`. */
193
+ /** Selects this node and sends `helix-select`. A disabled node sends nothing. */
155
194
  select(): void;
156
195
  /**
157
196
  * Chooses this node, as a press or Enter does.
@@ -163,6 +202,13 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
163
202
  * value and nothing listens for it.
164
203
  */
165
204
  activate(): void;
205
+ /**
206
+ * Opens or closes a branch, unless the item is disabled.
207
+ *
208
+ * Every press and key that opens a branch comes through here, so `disabled`
209
+ * holds for all of them. A script can still set `open`.
210
+ */
211
+ toggleOpen(): boolean;
166
212
  /**
167
213
  * Follows a link slotted into the name, if there is one.
168
214
  *
@@ -184,8 +230,17 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
184
230
  * its children.
185
231
  */
186
232
  private follow;
233
+ /** A press on the check mark checks the item and leaves a branch as it is. */
234
+ private readonly handleCheckClick;
187
235
  private readonly handleToggleClick;
188
236
  private readonly handleRowClick;
237
+ /**
238
+ * The expand and collapse mark of a branch, as the `chevron` slot's
239
+ * fallback, so an icon of your own replaces it by being slotted.
240
+ */
241
+ protected renderToggle(): TemplateResult;
242
+ /** The check mark, in a tree with `selection-mode="multiple"`. */
243
+ private renderCheckbox;
189
244
  /** Everything inside the row, which is the same whichever element it is. */
190
245
  private renderRow;
191
246
  /**
@@ -204,6 +259,8 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
204
259
  * a consumer's markup means. What stops is the write back.
205
260
  */
206
261
  protected willUpdate(changed: PropertyValues): void;
262
+ /** Asks for a lazy branch's children when it opens. */
263
+ protected updated(changed: PropertyValues): void;
207
264
  protected render(): TemplateResult;
208
265
  }
209
266
  declare global {
@@ -4,22 +4,31 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixElement, HelixSelectEvent, MixinControllerOpen, } from '@fusion.dev/helix-core';
8
- import { caretDown } from '@fusion.dev/helix-icons';
7
+ import { customElement, HelixElement, HelixLoadEvent, HelixSelectEvent, MixinControllerOpen, } from '@fusion.dev/helix-core';
8
+ import { caretDown, check, minus } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
11
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
12
12
  let HelixHeadlessTreeItem = class HelixHeadlessTreeItem extends MixinControllerOpen(HelixElement) {
13
13
  constructor() {
14
14
  super(...arguments);
15
+ this.checkable = false;
16
+ this.checked = false;
17
+ this.disabled = false;
15
18
  this.heads = false;
16
19
  this.href = '';
20
+ this.lazy = false;
17
21
  this.rel = '';
18
22
  this.selected = false;
19
23
  this.target = '';
20
24
  this.focusable = false;
21
25
  this.value = '';
22
26
  this.branch = false;
27
+ this.handleCheckClick = (event) => {
28
+ event.preventDefault();
29
+ event.stopPropagation();
30
+ this.select();
31
+ };
23
32
  this.handleToggleClick = (event) => {
24
33
  event.preventDefault();
25
34
  event.stopPropagation();
@@ -27,7 +36,11 @@ let HelixHeadlessTreeItem = class HelixHeadlessTreeItem extends MixinControllerO
27
36
  };
28
37
  this.handleRowClick = (event) => {
29
38
  const onLink = event.composedPath().some((node) => node instanceof HTMLAnchorElement);
30
- if (this.branch && this.href === '') {
39
+ if (this.disabled) {
40
+ event.preventDefault();
41
+ return;
42
+ }
43
+ if (this.isBranch && this.href === '') {
31
44
  if (!onLink) {
32
45
  if (this.choosable) {
33
46
  this.select();
@@ -51,10 +64,10 @@ let HelixHeadlessTreeItem = class HelixHeadlessTreeItem extends MixinControllerO
51
64
  });
52
65
  }
53
66
  get choosable() {
54
- return this.value !== '' && !this.heads;
67
+ return this.value !== '' && !this.heads && !this.checkable && !this.disabled;
55
68
  }
56
69
  get isBranch() {
57
- return this.branch;
70
+ return this.branch || this.lazy;
58
71
  }
59
72
  focusItem() {
60
73
  this.renderRoot
@@ -62,12 +75,21 @@ let HelixHeadlessTreeItem = class HelixHeadlessTreeItem extends MixinControllerO
62
75
  ?.focus({ preventScroll: true });
63
76
  }
64
77
  select() {
78
+ if (this.disabled) {
79
+ return;
80
+ }
65
81
  this.dispatchEvent(new HelixSelectEvent({ value: this.value }));
66
82
  }
67
83
  activate() {
84
+ if (this.disabled) {
85
+ return;
86
+ }
68
87
  this.select();
69
88
  this.follow();
70
89
  }
90
+ toggleOpen() {
91
+ return this.disabled ? false : super.toggleOpen();
92
+ }
71
93
  follow() {
72
94
  const own = this.renderRoot?.querySelector('a[part="row"]');
73
95
  if (own) {
@@ -85,18 +107,33 @@ let HelixHeadlessTreeItem = class HelixHeadlessTreeItem extends MixinControllerO
85
107
  }
86
108
  }
87
109
  }
110
+ renderToggle() {
111
+ return html `<slot
112
+ name="chevron"
113
+ aria-hidden="true"
114
+ @click=${this.href === '' ? nothing : this.handleToggleClick}
115
+ ><svg part="toggle" fill="currentColor" viewBox=${caretDown.viewBox} aria-hidden="true">
116
+ ${unsafeSVG(caretDown.content)}
117
+ </svg></slot
118
+ >`;
119
+ }
120
+ renderCheckbox() {
121
+ if (!this.checkable) {
122
+ return nothing;
123
+ }
124
+ const mixed = this.checked === 'mixed';
125
+ const glyph = mixed ? minus : this.checked ? check : undefined;
126
+ return html `<span
127
+ part="checkbox${mixed ? ' checkbox-mixed' : this.checked ? ' checkbox-checked' : ''}"
128
+ aria-hidden="true"
129
+ @click=${this.handleCheckClick}
130
+ >${glyph
131
+ ? html `<svg fill="currentColor" viewBox=${glyph.viewBox}>${unsafeSVG(glyph.content)}</svg>`
132
+ : nothing}</span
133
+ >`;
134
+ }
88
135
  renderRow() {
89
- return html `${this.branch
90
- ? html `<svg
91
- part="toggle"
92
- fill="currentColor"
93
- viewBox=${caretDown.viewBox}
94
- aria-hidden="true"
95
- @click=${this.href === '' ? nothing : this.handleToggleClick}
96
- >
97
- ${unsafeSVG(caretDown.content)}
98
- </svg>`
99
- : nothing}
136
+ return html `${this.isBranch ? this.renderToggle() : nothing}${this.renderCheckbox()}
100
137
  <slot name="start"></slot>
101
138
  <span part="label"><slot></slot></span>
102
139
  <slot name="end"></slot>`;
@@ -104,21 +141,41 @@ let HelixHeadlessTreeItem = class HelixHeadlessTreeItem extends MixinControllerO
104
141
  willUpdate(changed) {
105
142
  super.willUpdate(changed);
106
143
  this.toggleState('selected', this.selected);
144
+ this.toggleState('checked', this.checkable && this.checked === true);
145
+ this.toggleState('mixed', this.checkable && this.checked === 'mixed');
146
+ this.toggleState('loading', this.open && this.lazy);
107
147
  if (this.childrenKnown) {
108
148
  this.branch = this.knownChildren.some((child) => child.slot === 'children');
109
149
  }
110
150
  }
151
+ updated(changed) {
152
+ super.updated(changed);
153
+ if (changed.has('open') && this.open && this.lazy) {
154
+ this.dispatchEvent(new HelixLoadEvent());
155
+ }
156
+ }
111
157
  render() {
112
158
  const linked = this.href !== '';
113
159
  const level = this.level ?? 1;
114
160
  const depth = this.level ?? nothing;
115
- const expanded = this.branch ? (this.open ? 'true' : 'false') : nothing;
161
+ const expanded = this.isBranch ? (this.open ? 'true' : 'false') : nothing;
162
+ const chosen = this.checkable ? undefined : this.selected ? 'true' : 'false';
163
+ const checked = this.checkable
164
+ ? this.checked === 'mixed'
165
+ ? 'mixed'
166
+ : String(this.checked)
167
+ : undefined;
168
+ const busy = this.open && this.lazy ? 'true' : nothing;
169
+ const off = this.disabled ? 'true' : nothing;
116
170
  const tabIndex = this.focusable || !this.childrenKnown ? '0' : '-1';
117
171
  return html `<div
118
172
  part="item"
119
173
  role=${linked ? 'none' : 'treeitem'}
120
174
  aria-expanded=${linked ? nothing : expanded}
121
- aria-selected=${linked ? nothing : this.selected ? 'true' : 'false'}
175
+ aria-selected=${linked ? nothing : (chosen ?? nothing)}
176
+ aria-checked=${linked ? nothing : (checked ?? nothing)}
177
+ aria-disabled=${linked ? nothing : off}
178
+ aria-busy=${linked ? nothing : busy}
122
179
  aria-level=${linked ? nothing : depth}
123
180
  tabindex=${linked ? nothing : tabIndex}
124
181
  >
@@ -126,11 +183,14 @@ let HelixHeadlessTreeItem = class HelixHeadlessTreeItem extends MixinControllerO
126
183
  ? html `<a
127
184
  part="row"
128
185
  role="treeitem"
129
- href=${this.href}
186
+ href=${this.disabled ? nothing : this.href}
130
187
  target=${this.target || nothing}
131
188
  rel=${this.rel || nothing}
132
189
  aria-expanded=${expanded}
133
- aria-selected=${this.selected ? 'true' : 'false'}
190
+ aria-selected=${chosen ?? nothing}
191
+ aria-checked=${checked ?? nothing}
192
+ aria-disabled=${off}
193
+ aria-busy=${busy}
134
194
  aria-level=${depth}
135
195
  tabindex=${tabIndex}
136
196
  style="--tree-level: ${level}"
@@ -152,12 +212,24 @@ let HelixHeadlessTreeItem = class HelixHeadlessTreeItem extends MixinControllerO
152
212
  </div>`;
153
213
  }
154
214
  };
215
+ __decorate([
216
+ property({ attribute: false })
217
+ ], HelixHeadlessTreeItem.prototype, "checkable", void 0);
218
+ __decorate([
219
+ property({ attribute: false })
220
+ ], HelixHeadlessTreeItem.prototype, "checked", void 0);
221
+ __decorate([
222
+ property({ reflect: true, type: Boolean })
223
+ ], HelixHeadlessTreeItem.prototype, "disabled", void 0);
155
224
  __decorate([
156
225
  property({ attribute: false })
157
226
  ], HelixHeadlessTreeItem.prototype, "heads", void 0);
158
227
  __decorate([
159
228
  property()
160
229
  ], HelixHeadlessTreeItem.prototype, "href", void 0);
230
+ __decorate([
231
+ property({ reflect: true, type: Boolean })
232
+ ], HelixHeadlessTreeItem.prototype, "lazy", void 0);
161
233
  __decorate([
162
234
  property({ attribute: false, type: Number })
163
235
  ], HelixHeadlessTreeItem.prototype, "level", void 0);
@@ -16,6 +16,26 @@ declare const HelixHeadlessTree_base: (new (...args: any[]) => import("@fusion.d
16
16
  * Typing a letter moves to the next visible item whose name starts with it,
17
17
  * and `*` opens every branch beside the focused item.
18
18
  *
19
+ * `selection-mode="multiple"` draws a check mark on every row and lets a
20
+ * reader check many, as Web Awesome's and Ark UI's checkbox trees do. Checking
21
+ * a branch checks every item under it, and a branch some of whose items are
22
+ * checked is partly checked. Space or a press on the mark checks the focused
23
+ * row, and Enter or a press on a branch's row opens it. `active` then holds the
24
+ * checked values, comma separated, which `values` also gives as a list, and
25
+ * the tree says `aria-multiselectable`.
26
+ *
27
+ * `selection-mode="leaf"` chooses one item at a time and only the items at the
28
+ * ends: a press, Enter or Space on a branch opens or closes it and chooses
29
+ * nothing, as Web Awesome's `leaf` mode does.
30
+ *
31
+ * Keys: Up and Down Arrow move between the items a reader can see; Right
32
+ * Arrow opens a shut branch and then moves into it, and Left Arrow shuts an
33
+ * open one and then moves to its parent, the two swapping on a right-to-left
34
+ * page. Home and End go to the first and the last item, Enter and Space choose
35
+ * or open, and the tree's one tab stop stays on the item last reached. In a
36
+ * tree of check marks, Control+A (Command+A on an Apple keyboard) checks every
37
+ * item or clears them all, and Shift with Up or Down Arrow moves and checks.
38
+ *
19
39
  * @since 0.1.0
20
40
  * @status stable
21
41
  * @category navigation
@@ -82,6 +102,21 @@ export declare class HelixHeadlessTree extends HelixHeadlessTree_base {
82
102
  * The resting state is the absence of the attribute, which is `peer`.
83
103
  */
84
104
  nesting?: 'heading' | 'peer' | 'subordinate';
105
+ /**
106
+ * Whether a reader can check many items, or choose only the items at the
107
+ * ends. Unset, one item is chosen at a time, branches included.
108
+ *
109
+ * Optional, so a tree of one choice writes no attribute onto the host.
110
+ */
111
+ selectionMode?: 'leaf' | 'multiple';
112
+ /**
113
+ * The checked values, as a list, under `selection-mode="multiple"`, and the
114
+ * chosen value alone otherwise. Writing it sets `active`.
115
+ */
116
+ get values(): string[];
117
+ set values(next: string[]);
118
+ /** Whether many items can be checked. */
119
+ private get multiple();
85
120
  private watcher;
86
121
  /**
87
122
  * Every item, in the order a reader moving down would meet them.
@@ -100,6 +135,20 @@ export declare class HelixHeadlessTree extends HelixHeadlessTree_base {
100
135
  /** Items a reader can actually reach: not inside a collapsed branch. */
101
136
  private get visibleItems();
102
137
  private readonly handleSelection;
138
+ /** Every value in the tree, in the order a reader meets the items. */
139
+ private get order();
140
+ /**
141
+ * Whether an item holds others, read from the tree as well as from the item.
142
+ *
143
+ * **An item hydrating what a server sent has not said it is a branch yet**:
144
+ * it learns that from its children on the render after, and nothing then
145
+ * asks the tree again. Read from its own render alone, a folder served with
146
+ * one of its files checked was counted a leaf and drawn unchecked rather
147
+ * than partly checked, once hydrated.
148
+ */
149
+ private holds;
150
+ /** What the multiple selection reads of an item. */
151
+ private rowOf;
103
152
  /**
104
153
  * Pushes tree-owned state down: which item is selected, which holds the tab
105
154
  * stop, and how deep each one sits.
@@ -117,6 +166,15 @@ export declare class HelixHeadlessTree extends HelixHeadlessTree_base {
117
166
  * Returns whether the press was one of those.
118
167
  */
119
168
  private handleTyping;
169
+ /**
170
+ * The keys of a tree of check marks, as the tree pattern gives them:
171
+ * Control+A (Command+A on an Apple keyboard) checks every item, or clears
172
+ * them all where every one is checked, and Shift with Up or Down Arrow moves
173
+ * to the item before or after and checks or unchecks it.
174
+ *
175
+ * Returns whether the press was one of those.
176
+ */
177
+ private handleMultiple;
120
178
  private move;
121
179
  private focusOn;
122
180
  private readonly handleKeydown;
@@ -4,10 +4,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { AriaForwardController, closestInstance, customElement, HelixElement, inlineStep, keyClaimed, MixinCollection, MixinControllerActive, scrollItemIntoView, slottedWords, Typeahead, typesCharacter, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, closestInstance, commaList, customElement, HelixElement, inlineStep, keyClaimed, MixinCollection, MixinControllerActive, scrollItemIntoView, slottedWords, Typeahead, treeArrow, typesCharacter, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { HelixHeadlessTreeItem } from '../item/tree-item.js';
11
+ import { checkedState, pressRow } from '../selection.js';
11
12
  const KEYS = new Set([
12
13
  'ArrowDown',
13
14
  'ArrowUp',
@@ -33,7 +34,9 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
33
34
  return;
34
35
  }
35
36
  if (!event.defaultPrevented) {
36
- this.requestActive(event.detail.value);
37
+ this.requestActive(this.multiple
38
+ ? pressRow(this.rowOf(origin), this.values, this.order).join(',')
39
+ : event.detail.value);
37
40
  }
38
41
  this.syncItems();
39
42
  };
@@ -42,6 +45,10 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
42
45
  if (!current || !this.items.includes(current)) {
43
46
  return;
44
47
  }
48
+ if (this.multiple && this.handleMultiple(current, event)) {
49
+ event.preventDefault();
50
+ return;
51
+ }
45
52
  if (this.handleTyping(current, event)) {
46
53
  event.preventDefault();
47
54
  return;
@@ -51,6 +58,11 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
51
58
  }
52
59
  this.typeahead.reset();
53
60
  const along = inlineStep(this, event.key);
61
+ if (this.multiple && event.key === ' ') {
62
+ current.select();
63
+ event.preventDefault();
64
+ return;
65
+ }
54
66
  if (event.key === 'ArrowDown') {
55
67
  this.move(current, 1);
56
68
  }
@@ -63,21 +75,16 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
63
75
  else if (event.key === 'End') {
64
76
  this.focusOn(this.visibleItems.at(-1));
65
77
  }
66
- else if (along === 1) {
67
- if (current.isBranch && !current.open) {
68
- current.requestOpen(true);
78
+ else if (along !== 0) {
79
+ const arrow = treeArrow({ branch: current.isBranch, disabled: current.disabled, open: current.open }, along);
80
+ if (arrow === 'open' || arrow === 'close') {
81
+ current.requestOpen(arrow === 'open');
69
82
  this.syncItems();
70
83
  }
71
- else if (current.isBranch) {
84
+ else if (arrow === 'child') {
72
85
  this.move(current, 1);
73
86
  }
74
- }
75
- else if (along === -1) {
76
- if (current.isBranch && current.open) {
77
- current.requestOpen(false);
78
- this.syncItems();
79
- }
80
- else {
87
+ else if (arrow === 'parent') {
81
88
  const parent = closestInstance(current.parentElement, HelixHeadlessTreeItem);
82
89
  this.focusOn(parent instanceof HelixHeadlessTreeItem ? parent : undefined);
83
90
  }
@@ -100,6 +107,15 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
100
107
  this.syncItems();
101
108
  };
102
109
  }
110
+ get values() {
111
+ return this.multiple ? commaList(this.active) : this.active === '' ? [] : [this.active];
112
+ }
113
+ set values(next) {
114
+ this.active = next.join(',');
115
+ }
116
+ get multiple() {
117
+ return this.selectionMode === 'multiple';
118
+ }
103
119
  get items() {
104
120
  return [...this.querySelectorAll('*')].filter((node) => node instanceof HelixHeadlessTreeItem);
105
121
  }
@@ -115,15 +131,37 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
115
131
  return true;
116
132
  });
117
133
  }
134
+ get order() {
135
+ return this.items.map((item) => item.value).filter((value) => value !== '');
136
+ }
137
+ holds(item) {
138
+ return item.isBranch || this.items.some((other) => other !== item && item.contains(other));
139
+ }
140
+ rowOf(item) {
141
+ const branch = this.holds(item);
142
+ const leaves = branch
143
+ ? this.items
144
+ .filter((other) => other !== item &&
145
+ item.contains(other) &&
146
+ !this.holds(other) &&
147
+ !other.disabled &&
148
+ other.value !== '')
149
+ .map((other) => other.value)
150
+ : [];
151
+ return { branch, disabled: item.disabled, leaves, value: item.value };
152
+ }
118
153
  syncItems() {
119
154
  const visible = this.visibleItems;
120
155
  const chosen = this.resolveActive(visible);
121
156
  const held = visible.find((item) => item.focusable) ??
122
157
  this.visibleAncestor(this.items.find((item) => item.focusable));
123
158
  const stop = held ?? chosen;
124
- const heads = this.nesting === 'heading';
159
+ const heads = this.nesting === 'heading' || this.selectionMode === 'leaf';
160
+ const multiple = this.multiple;
161
+ const checked = new Set(this.values);
125
162
  for (const item of this.items) {
126
- const selected = item.value !== '' && item.value === this.active;
163
+ const selected = !multiple && item.value !== '' && item.value === this.active;
164
+ const state = multiple ? checkedState(this.rowOf(item), checked) : false;
127
165
  const focusable = item === stop;
128
166
  let level = 1;
129
167
  let parent = item.parentElement;
@@ -135,6 +173,8 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
135
173
  }
136
174
  whenHydrated(item, () => {
137
175
  item.selected = selected;
176
+ item.checkable = multiple;
177
+ item.checked = state;
138
178
  item.focusable = focusable;
139
179
  item.level = level;
140
180
  item.heads = heads;
@@ -176,6 +216,26 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
176
216
  }
177
217
  return true;
178
218
  }
219
+ handleMultiple(current, event) {
220
+ if ((event.ctrlKey || event.metaKey) && !event.altKey && event.key.toLowerCase() === 'a') {
221
+ const leaves = this.items
222
+ .filter((item) => !this.holds(item) && !item.disabled && item.value !== '')
223
+ .map((item) => item.value);
224
+ this.requestActive(pressRow({ branch: true, disabled: false, leaves, value: '' }, this.values, this.order).join(','));
225
+ this.syncItems();
226
+ return true;
227
+ }
228
+ if (event.shiftKey && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
229
+ const visible = this.visibleItems;
230
+ const next = visible[visible.indexOf(current) + (event.key === 'ArrowDown' ? 1 : -1)];
231
+ if (next) {
232
+ this.focusOn(next);
233
+ next.select();
234
+ }
235
+ return true;
236
+ }
237
+ return false;
238
+ }
179
239
  move(from, delta) {
180
240
  const visible = this.visibleItems;
181
241
  const index = visible.indexOf(from);
@@ -214,7 +274,7 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
214
274
  }
215
275
  updated(changed) {
216
276
  super.updated(changed);
217
- if (changed.has('active') || changed.has('nesting')) {
277
+ if (changed.has('active') || changed.has('nesting') || changed.has('selectionMode')) {
218
278
  this.syncItems();
219
279
  }
220
280
  }
@@ -223,6 +283,7 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
223
283
  part="tree"
224
284
  role="tree"
225
285
  aria-busy=${this.loading ? 'true' : nothing}
286
+ aria-multiselectable=${this.multiple ? 'true' : nothing}
226
287
  aria-label=${this.label}
227
288
  >
228
289
  <slot
@@ -241,6 +302,9 @@ __decorate([
241
302
  __decorate([
242
303
  property({ reflect: true })
243
304
  ], HelixHeadlessTree.prototype, "nesting", void 0);
305
+ __decorate([
306
+ property({ attribute: 'selection-mode', reflect: true })
307
+ ], HelixHeadlessTree.prototype, "selectionMode", void 0);
244
308
  HelixHeadlessTree = __decorate([
245
309
  customElement('helix-headless-tree')
246
310
  ], HelixHeadlessTree);
@@ -0,0 +1,24 @@
1
+ /** What the multiple selection reads of a row. */
2
+ export interface CheckableRow {
3
+ /** Whether the row is a branch, holding rows of its own. */
4
+ branch: boolean;
5
+ /** Whether the row is out of play. Its value is never added or taken away. */
6
+ disabled: boolean;
7
+ /** The values of the leaves under a branch, in order. Empty for a leaf. */
8
+ leaves: readonly string[];
9
+ /** The row's own value. */
10
+ value: string;
11
+ }
12
+ /**
13
+ * Whether a row is checked in a tree of check marks: a leaf by its value, and
14
+ * a branch by its leaves, `mixed` where some of them are.
15
+ */
16
+ export declare const checkedState: (row: CheckableRow, chosen: ReadonlySet<string>) => boolean | 'mixed';
17
+ /**
18
+ * The checked values after a press on `row`, in `order`.
19
+ *
20
+ * A leaf comes in or out. A branch checks every leaf under it, or clears them
21
+ * all where every one is already checked, as Ark UI's and Web Awesome's
22
+ * checkbox trees do. A disabled row changes nothing.
23
+ */
24
+ export declare const pressRow: (row: CheckableRow, chosen: readonly string[], order: readonly string[]) => string[];
@@ -0,0 +1,13 @@
1
+ import { toggleEvery } from '@fusion.dev/helix-core';
2
+ const valuesOf = (row) => row.branch && row.leaves.length > 0 ? [...row.leaves] : row.value === '' ? [] : [row.value];
3
+ export const checkedState = (row, chosen) => {
4
+ const values = valuesOf(row);
5
+ const count = values.filter((value) => chosen.has(value)).length;
6
+ if (count === 0) {
7
+ return false;
8
+ }
9
+ return count === values.length ? true : 'mixed';
10
+ };
11
+ export const pressRow = (row, chosen, order) => {
12
+ return row.disabled ? [...chosen] : toggleEvery(chosen, valuesOf(row), order);
13
+ };