@fusion.dev/helix-headless 0.142.1 → 0.144.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 (285) hide show
  1. package/custom-elements.json +25381 -1202
  2. package/dist/accordion/item/accordion-item.d.ts +38 -2
  3. package/dist/accordion/item/accordion-item.js +38 -6
  4. package/dist/accordion/root/accordion-root.d.ts +23 -1
  5. package/dist/accordion/root/accordion-root.js +39 -3
  6. package/dist/announcement/root/announcement-root.d.ts +11 -7
  7. package/dist/announcement/root/announcement-root.js +1 -1
  8. package/dist/app-header/root/app-header-root.d.ts +21 -0
  9. package/dist/app-header/root/app-header-root.js +31 -5
  10. package/dist/area-chart/root/area-chart-root.d.ts +12 -4
  11. package/dist/area-chart/root/area-chart-root.js +39 -11
  12. package/dist/avatar/group/avatar-group.d.ts +24 -3
  13. package/dist/avatar/group/avatar-group.js +34 -2
  14. package/dist/avatar/root/avatar-root.d.ts +17 -1
  15. package/dist/avatar/root/avatar-root.js +31 -10
  16. package/dist/badge/root/badge-root.d.ts +12 -0
  17. package/dist/badge/root/badge-root.js +1 -1
  18. package/dist/bar-chart/root/bar-chart-root.d.ts +30 -5
  19. package/dist/bar-chart/root/bar-chart-root.js +58 -21
  20. package/dist/blockquote/root/blockquote-root.d.ts +12 -7
  21. package/dist/blockquote/root/blockquote-root.js +6 -4
  22. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
  23. package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
  24. package/dist/button/root/button-root.d.ts +84 -1
  25. package/dist/button/root/button-root.js +81 -3
  26. package/dist/callout/root/callout-root.d.ts +32 -6
  27. package/dist/callout/root/callout-root.js +26 -7
  28. package/dist/canvas/root/canvas-root.d.ts +1 -0
  29. package/dist/canvas/root/canvas-root.js +10 -1
  30. package/dist/card/root/card-root.d.ts +30 -1
  31. package/dist/card/root/card-root.js +38 -5
  32. package/dist/carousel/root/carousel-root.d.ts +47 -5
  33. package/dist/carousel/root/carousel-root.js +53 -21
  34. package/dist/chat/composer/chat-composer.d.ts +13 -11
  35. package/dist/chat/composer/chat-composer.js +6 -12
  36. package/dist/chat/message/chat-message.js +8 -1
  37. package/dist/chat/root/chat-root.d.ts +1 -0
  38. package/dist/chat/root/chat-root.js +2 -1
  39. package/dist/checkbox/root/checkbox-root.d.ts +7 -0
  40. package/dist/checkbox/root/checkbox-root.js +9 -3
  41. package/dist/checkbox-group/root/checkbox-group-root.d.ts +116 -33
  42. package/dist/checkbox-group/root/checkbox-group-root.js +141 -44
  43. package/dist/code/root/code-root.d.ts +1 -1
  44. package/dist/code-block/lines.d.ts +13 -0
  45. package/dist/code-block/lines.js +2 -0
  46. package/dist/code-block/root/code-block-root.d.ts +49 -0
  47. package/dist/code-block/root/code-block-root.js +44 -3
  48. package/dist/color-input/root/color-input-root.d.ts +60 -2
  49. package/dist/color-input/root/color-input-root.js +55 -7
  50. package/dist/color-picker/channels.d.ts +26 -0
  51. package/dist/color-picker/channels.js +84 -0
  52. package/dist/color-picker/root/color-picker-root.d.ts +118 -12
  53. package/dist/color-picker/root/color-picker-root.js +183 -13
  54. package/dist/combobox/root/combobox-root.d.ts +126 -3
  55. package/dist/combobox/root/combobox-root.js +224 -21
  56. package/dist/command/root/command-root.d.ts +47 -10
  57. package/dist/command/root/command-root.js +45 -4
  58. package/dist/copy-button/from.d.ts +22 -0
  59. package/dist/copy-button/from.js +28 -0
  60. package/dist/copy-button/root/copy-button-root.d.ts +48 -7
  61. package/dist/copy-button/root/copy-button-root.js +54 -8
  62. package/dist/data-table/root/data-table-root.d.ts +164 -10
  63. package/dist/data-table/root/data-table-root.js +488 -57
  64. package/dist/date-input/root/date-input-root.d.ts +123 -9
  65. package/dist/date-input/root/date-input-root.js +147 -45
  66. package/dist/date-picker/root/date-picker-root.d.ts +229 -18
  67. package/dist/date-picker/root/date-picker-root.js +342 -46
  68. package/dist/dialog/description.d.ts +9 -0
  69. package/dist/dialog/description.js +14 -0
  70. package/dist/dialog/root/dialog-root.d.ts +101 -10
  71. package/dist/dialog/root/dialog-root.js +83 -4
  72. package/dist/donut-chart/root/donut-chart-root.d.ts +61 -16
  73. package/dist/donut-chart/root/donut-chart-root.js +48 -13
  74. package/dist/drawer/root/drawer-root.d.ts +93 -7
  75. package/dist/drawer/root/drawer-root.js +126 -5
  76. package/dist/drawer/swipe-start.d.ts +9 -0
  77. package/dist/drawer/swipe-start.js +12 -0
  78. package/dist/drilldown/item/drilldown-item.d.ts +16 -13
  79. package/dist/drilldown/item/drilldown-item.js +6 -2
  80. package/dist/drilldown/root/drilldown-root.d.ts +21 -5
  81. package/dist/drilldown/root/drilldown-root.js +26 -10
  82. package/dist/element-events.generated.js +42 -13
  83. package/dist/empty/root/empty-root.d.ts +1 -1
  84. package/dist/file-input/root/file-input-root.d.ts +65 -1
  85. package/dist/file-input/root/file-input-root.js +76 -12
  86. package/dist/file-input/screen.d.ts +35 -0
  87. package/dist/file-input/screen.js +49 -0
  88. package/dist/filter-input/menu/filter-menu.d.ts +9 -0
  89. package/dist/filter-input/menu/filter-menu.js +8 -0
  90. package/dist/filter-input/root/filter-input-root.d.ts +43 -6
  91. package/dist/filter-input/root/filter-input-root.js +89 -10
  92. package/dist/filter-input/suggest.d.ts +17 -0
  93. package/dist/filter-input/suggest.js +23 -0
  94. package/dist/format-date/options.d.ts +33 -0
  95. package/dist/format-date/options.js +42 -0
  96. package/dist/format-date/root/format-date-root.d.ts +62 -3
  97. package/dist/format-date/root/format-date-root.js +78 -37
  98. package/dist/graph/root/graph-root.d.ts +24 -3
  99. package/dist/graph/root/graph-root.js +66 -12
  100. package/dist/heatmap/root/buckets.d.ts +2 -1
  101. package/dist/heatmap/root/buckets.js +5 -1
  102. package/dist/heatmap/root/heatmap-root.d.ts +47 -9
  103. package/dist/heatmap/root/heatmap-root.js +46 -18
  104. package/dist/icon/index.d.ts +2 -0
  105. package/dist/icon/index.js +2 -0
  106. package/dist/icon/registry.d.ts +37 -0
  107. package/dist/icon/registry.js +83 -0
  108. package/dist/icon/root/icon-root.d.ts +53 -6
  109. package/dist/icon/root/icon-root.js +72 -4
  110. package/dist/icon/root/index.d.ts +2 -0
  111. package/dist/icon/root/index.js +2 -0
  112. package/dist/icon/set.d.ts +1 -0
  113. package/dist/icon/set.js +3 -0
  114. package/dist/icon-button/root/icon-button-root.d.ts +1 -1
  115. package/dist/image/root/image-root.d.ts +23 -2
  116. package/dist/image/root/image-root.js +23 -4
  117. package/dist/input/root/input-root.d.ts +62 -9
  118. package/dist/input/root/input-root.js +61 -5
  119. package/dist/kbd/root/kbd-root.d.ts +26 -11
  120. package/dist/kbd/root/kbd-root.js +35 -38
  121. package/dist/kbd/shortcut.d.ts +18 -0
  122. package/dist/kbd/shortcut.js +35 -0
  123. package/dist/legend/hidden-series.d.ts +8 -0
  124. package/dist/legend/hidden-series.js +13 -0
  125. package/dist/legend/root/legend-root.d.ts +63 -0
  126. package/dist/legend/root/legend-root.js +61 -7
  127. package/dist/lightbox/item/lightbox-item.d.ts +17 -1
  128. package/dist/lightbox/item/lightbox-item.js +10 -1
  129. package/dist/lightbox/root/lightbox-root.d.ts +77 -6
  130. package/dist/lightbox/root/lightbox-root.js +116 -5
  131. package/dist/line-chart/root/line-chart-root.d.ts +29 -4
  132. package/dist/line-chart/root/line-chart-root.js +58 -17
  133. package/dist/list/item/list-item.d.ts +11 -5
  134. package/dist/list/item/list-item.js +5 -6
  135. package/dist/listbox/range.d.ts +17 -0
  136. package/dist/listbox/range.js +5 -0
  137. package/dist/listbox/root/listbox-root.d.ts +184 -4
  138. package/dist/listbox/root/listbox-root.js +229 -23
  139. package/dist/loader/busy.d.ts +17 -0
  140. package/dist/loader/busy.js +24 -0
  141. package/dist/loader/root/loader-root.d.ts +37 -0
  142. package/dist/loader/root/loader-root.js +52 -3
  143. package/dist/map/root/map-root.d.ts +19 -4
  144. package/dist/map/root/map-root.js +36 -7
  145. package/dist/megamenu/root/megamenu-root.d.ts +10 -1
  146. package/dist/megamenu/root/megamenu-root.js +10 -1
  147. package/dist/menu/item/menu-item.d.ts +41 -12
  148. package/dist/menu/item/menu-item.js +46 -3
  149. package/dist/menu/root/menu-root.d.ts +32 -2
  150. package/dist/menu/root/menu-root.js +48 -8
  151. package/dist/meter/root/meter-root.d.ts +13 -0
  152. package/dist/meter/root/meter-root.js +24 -5
  153. package/dist/navigation/root/navigation-root.d.ts +10 -2
  154. package/dist/navigation/root/navigation-root.js +13 -2
  155. package/dist/notifications/feed-keys.d.ts +10 -0
  156. package/dist/notifications/feed-keys.js +14 -0
  157. package/dist/notifications/group/notification-group.d.ts +1 -0
  158. package/dist/notifications/notification/notification.d.ts +29 -0
  159. package/dist/notifications/notification/notification.js +51 -3
  160. package/dist/notifications/root/notifications-root.d.ts +49 -0
  161. package/dist/notifications/root/notifications-root.js +76 -2
  162. package/dist/number-input/root/number-input-root.d.ts +109 -7
  163. package/dist/number-input/root/number-input-root.js +109 -21
  164. package/dist/object-inspector/root/object-inspector-root.d.ts +49 -5
  165. package/dist/object-inspector/root/object-inspector-root.js +92 -12
  166. package/dist/option/root/option-root.d.ts +58 -6
  167. package/dist/option/root/option-root.js +35 -5
  168. package/dist/outline/root/outline-root.d.ts +13 -2
  169. package/dist/outline/root/outline-root.js +4 -2
  170. package/dist/pagination/root/pagination-root.d.ts +19 -1
  171. package/dist/pagination/root/pagination-root.js +49 -9
  172. package/dist/pagination/size/pagination-size.d.ts +13 -3
  173. package/dist/pagination/size/pagination-size.js +7 -0
  174. package/dist/pin-input/format.d.ts +7 -0
  175. package/dist/pin-input/format.js +16 -0
  176. package/dist/pin-input/root/pin-input-root.d.ts +37 -0
  177. package/dist/pin-input/root/pin-input-root.js +48 -7
  178. package/dist/popover/root/popover-root.d.ts +78 -3
  179. package/dist/popover/root/popover-root.js +74 -5
  180. package/dist/progress/root/progress-root.d.ts +23 -1
  181. package/dist/progress/root/progress-root.js +40 -10
  182. package/dist/qr-code/export.d.ts +31 -0
  183. package/dist/qr-code/export.js +10 -0
  184. package/dist/qr-code/root/qr-code-root.d.ts +45 -0
  185. package/dist/qr-code/root/qr-code-root.js +78 -3
  186. package/dist/radio/group/radio-group.d.ts +64 -0
  187. package/dist/radio/group/radio-group.js +66 -12
  188. package/dist/radio/root/radio-root.d.ts +8 -5
  189. package/dist/radio/root/radio-root.js +1 -2
  190. package/dist/rating/root/rating-root.d.ts +49 -1
  191. package/dist/rating/root/rating-root.js +69 -10
  192. package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
  193. package/dist/scatter-chart/root/scatter-chart-root.js +40 -14
  194. package/dist/select/root/select-root.d.ts +93 -3
  195. package/dist/select/root/select-root.js +111 -13
  196. package/dist/skeleton/root/skeleton-root.d.ts +39 -3
  197. package/dist/skeleton/root/skeleton-root.js +33 -4
  198. package/dist/skip-link/root/skip-link-root.d.ts +10 -0
  199. package/dist/skip-link/root/skip-link-root.js +15 -1
  200. package/dist/slider/root/slider-root.d.ts +59 -2
  201. package/dist/slider/root/slider-root.js +82 -8
  202. package/dist/sparkline/root/sparkline-root.d.ts +9 -10
  203. package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
  204. package/dist/speed-dial/item/speed-dial-item.js +7 -2
  205. package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
  206. package/dist/speed-dial/root/speed-dial-root.js +19 -5
  207. package/dist/splitter/root/splitter-root.d.ts +28 -6
  208. package/dist/splitter/root/splitter-root.js +35 -1
  209. package/dist/stat/root/stat-root.d.ts +9 -1
  210. package/dist/stat/root/stat-root.js +15 -2
  211. package/dist/steps/root/steps-root.js +1 -1
  212. package/dist/steps/step/step.d.ts +1 -0
  213. package/dist/steps/step/step.js +1 -1
  214. package/dist/switch/root/switch-root.d.ts +14 -2
  215. package/dist/switch/root/switch-root.js +7 -1
  216. package/dist/table/cell/table-cell.d.ts +24 -4
  217. package/dist/table/cell/table-cell.js +21 -1
  218. package/dist/table/column/table-column.d.ts +32 -6
  219. package/dist/table/column/table-column.js +36 -6
  220. package/dist/table/root/table-root.d.ts +94 -3
  221. package/dist/table/root/table-root.js +128 -5
  222. package/dist/table/row/table-row.d.ts +7 -0
  223. package/dist/table/row/table-row.js +9 -1
  224. package/dist/tabs/root/tabs-root.d.ts +6 -1
  225. package/dist/tabs/root/tabs-root.js +6 -2
  226. package/dist/tag/group/tag-group.d.ts +107 -0
  227. package/dist/tag/group/tag-group.js +157 -0
  228. package/dist/tag/index.d.ts +1 -0
  229. package/dist/tag/index.js +1 -0
  230. package/dist/tag/root/tag-root.d.ts +83 -1
  231. package/dist/tag/root/tag-root.js +87 -17
  232. package/dist/tag/selection.d.ts +10 -0
  233. package/dist/tag/selection.js +12 -0
  234. package/dist/textarea/grow.d.ts +22 -0
  235. package/dist/textarea/grow.js +20 -0
  236. package/dist/textarea/root/textarea-root.d.ts +13 -0
  237. package/dist/textarea/root/textarea-root.js +10 -2
  238. package/dist/time-input/root/time-input-root.d.ts +71 -6
  239. package/dist/time-input/root/time-input-root.js +110 -44
  240. package/dist/time-picker/root/time-picker-root.d.ts +155 -26
  241. package/dist/time-picker/root/time-picker-root.js +192 -63
  242. package/dist/toast/hotkey.d.ts +22 -0
  243. package/dist/toast/hotkey.js +23 -0
  244. package/dist/toast/item/toast-item.d.ts +16 -1
  245. package/dist/toast/item/toast-item.js +41 -13
  246. package/dist/toast/root/toast-root.d.ts +105 -8
  247. package/dist/toast/root/toast-root.js +209 -4
  248. package/dist/toggle/group/toggle-group.d.ts +95 -16
  249. package/dist/toggle/group/toggle-group.js +99 -13
  250. package/dist/toggle/root/toggle-root.d.ts +26 -11
  251. package/dist/toggle/root/toggle-root.js +14 -6
  252. package/dist/toolbar/root/toolbar-root.d.ts +55 -15
  253. package/dist/toolbar/root/toolbar-root.js +99 -16
  254. package/dist/tooltip/focus-target.d.ts +6 -0
  255. package/dist/tooltip/focus-target.js +9 -0
  256. package/dist/tooltip/root/tooltip-root.d.ts +73 -15
  257. package/dist/tooltip/root/tooltip-root.js +96 -7
  258. package/dist/tour/naming.d.ts +30 -0
  259. package/dist/tour/naming.js +10 -0
  260. package/dist/tour/root/tour-root.d.ts +67 -3
  261. package/dist/tour/root/tour-root.js +105 -17
  262. package/dist/tour/stop/tour-stop.d.ts +65 -3
  263. package/dist/tour/stop/tour-stop.js +61 -11
  264. package/dist/tour/wait.d.ts +11 -0
  265. package/dist/tour/wait.js +19 -0
  266. package/dist/tree/item/tree-item.d.ts +21 -5
  267. package/dist/tree/item/tree-item.js +14 -4
  268. package/dist/tree/root/tree-root.d.ts +29 -5
  269. package/dist/tree/root/tree-root.js +64 -8
  270. package/dist/trend/root/trend-root.d.ts +36 -1
  271. package/dist/trend/root/trend-root.js +41 -15
  272. package/dist/video/root/keys.d.ts +5 -0
  273. package/dist/video/root/keys.js +13 -1
  274. package/dist/video/root/video-root.d.ts +19 -0
  275. package/dist/video/root/video-root.js +48 -4
  276. package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
  277. package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
  278. package/dist/video-playlist/root/video-playlist-root.js +6 -3
  279. package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
  280. package/dist/virtual-list/root/virtual-list-root.js +103 -21
  281. package/lint.json +1 -1
  282. package/package.json +5 -5
  283. package/types/jsx.d.ts +9140 -1149
  284. package/types/svelte.d.ts +1 -0
  285. package/types/vue.d.ts +2089 -267
@@ -20,6 +20,13 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
20
20
  *
21
21
  * A range with two thumbs is two inputs stacked on one track, because there is
22
22
  * no native two-thumb range. Each thumb keeps its own value.
23
+ * `min-steps-between-thumbs` keeps them that many steps apart.
24
+ *
25
+ * `format-options` writes the value with `Intl.NumberFormat` in `locale`, as a
26
+ * currency, a percent or a unit, and `formatter` writes it with a function of
27
+ * your own, such as words for a scale. Either one is what a screen reader
28
+ * hears, what the readout shows and what the marker labels say. `value-text`
29
+ * still wraps it in a sentence, with the formatted value in its place.
23
30
  *
24
31
  * `required` comes with the field mixin and cannot fail. A range is never
25
32
  * empty: the platform shows its midpoint when no value is set, and `willUpdate`
@@ -33,6 +40,10 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
33
40
  * @aliases Range, Range input
34
41
  * @documentation https://fusion.dev/helix/components/slider
35
42
  *
43
+ * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
44
+ * @slot hint - Help under the control, for content richer than the `hint` text.
45
+ * @slot label - The label, for content richer than the `label` text.
46
+ *
36
47
  * @event {Event} change - Fired when the user releases the thumb.
37
48
  * @event {HelixBeforeChangeEvent} helix-before-change - Fired as the value changes. Cancelable: call `preventDefault()` to keep the current value.
38
49
  * @event {Event} input - Fired after the value changes.
@@ -58,6 +69,27 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
58
69
  protected readonly aria: AriaForwardController;
59
70
  /** Typed or dragged, so every edit is announced. See `announcesInput`. */
60
71
  protected readonly announcesInput = true;
72
+ /**
73
+ * `Intl.NumberFormat` options the value is written with: a currency, a
74
+ * percent, a unit, or a number of decimals. Written as JSON in the
75
+ * attribute.
76
+ *
77
+ * ```html
78
+ * <helix-slider format-options='{"style":"currency","currency":"USD"}'></helix-slider>
79
+ * ```
80
+ */
81
+ formatOptions?: Intl.NumberFormatOptions;
82
+ /**
83
+ * Writes a value as text, in place of `format-options`: words for a scale,
84
+ * or anything `Intl.NumberFormat` cannot say. A property, since a function
85
+ * cannot be written in an attribute.
86
+ */
87
+ formatter?: (value: number) => string;
88
+ /**
89
+ * The locale `format-options` writes the value in, such as `de-DE`. Empty is
90
+ * the reader's own.
91
+ */
92
+ locale: string;
61
93
  /**
62
94
  * Shows the value at each mark.
63
95
  */
@@ -98,6 +130,11 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
98
130
  min: number;
99
131
  /** The name of a range's lower thumb, read after the slider's label. */
100
132
  minimumLabel: string;
133
+ /**
134
+ * How many steps a range's two thumbs stay apart, as Zag's
135
+ * `minStepsBetweenThumbs`. A thumb pushed closer stops there.
136
+ */
137
+ minStepsBetweenThumbs: number;
101
138
  /**
102
139
  * The direction the track runs. `vertical` stands it on end.
103
140
  *
@@ -123,6 +160,8 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
123
160
  * Shows the chosen value beside the track.
124
161
  */
125
162
  showValue: boolean;
163
+ /** How far one press of an arrow key moves the thumb. */
164
+ step: number;
126
165
  /**
127
166
  * How many characters the readout has to be able to hold, widest case.
128
167
  *
@@ -210,9 +249,27 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
210
249
  */
211
250
  private snapped;
212
251
  protected willUpdate(changed: PropertyValues): void;
252
+ /** One number pulled into the bounds and onto the step, as a range does. */
253
+ private settled;
254
+ /**
255
+ * The value as a native range would hold it: a number in the bounds on the
256
+ * step, or for a range, two of them in order.
257
+ */
258
+ private sanitize;
259
+ /** How far apart a range's thumbs stay, in the slider's own units. */
260
+ private get gap();
261
+ /** Whether the value is written by `formatter` or `format-options`. */
262
+ private get formats();
263
+ /** A value as the reader sees it: formatted where asked, the number otherwise. */
264
+ private said;
265
+ /** What a screen reader says for one thumb, where `value-text` asks. */
266
+ private spoken;
213
267
  protected updated(changed: PropertyValues): void;
214
- /** How far one press of an arrow key moves the thumb. */
215
- step: number;
268
+ /**
269
+ * What a screen reader says for a thumb's value, with `{value}` filled in,
270
+ * such as `{value} degrees`. Empty announces the number alone.
271
+ */
272
+ valueText: string;
216
273
  protected render(): TemplateResult;
217
274
  }
218
275
  declare global {
@@ -4,7 +4,7 @@ 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, customElement, HelixFormElement, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, fillTemplate, formatNumber, HelixFormElement, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue(MixinField(HelixFormElement)) {
@@ -14,23 +14,27 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
14
14
  target: () => this.partNamed('control'),
15
15
  });
16
16
  this.announcesInput = true;
17
+ this.locale = '';
17
18
  this.markerLabels = false;
18
19
  this.markers = 0;
19
20
  this.max = 100;
20
21
  this.maximumLabel = 'maximum';
21
22
  this.min = 0;
22
23
  this.minimumLabel = 'minimum';
24
+ this.minStepsBetweenThumbs = 0;
23
25
  this.range = false;
24
26
  this.showValue = false;
27
+ this.step = 1;
25
28
  this.handleInput = (event) => {
26
29
  event.stopPropagation();
27
30
  const control = event.target;
28
31
  if (this.range) {
29
32
  const [start, end] = this.bounds;
30
33
  const moved = Number(control.value);
34
+ const gap = this.gap;
31
35
  const pair = control.dataset.thumb === 'start'
32
- ? [Math.min(moved, end), end]
33
- : [start, Math.max(moved, start)];
36
+ ? [Math.min(moved, end - gap), end]
37
+ : [start, Math.max(moved, start + gap)];
34
38
  this.requestValue(pair.join(','));
35
39
  restoreValue(control, String(control.dataset.thumb === 'start' ? this.bounds[0] : this.bounds[1]));
36
40
  return;
@@ -43,10 +47,10 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
43
47
  event.stopPropagation();
44
48
  this.announceChange();
45
49
  };
46
- this.step = 1;
50
+ this.valueText = '';
47
51
  }
48
52
  get reserve() {
49
- const widest = Math.max(String(this.min).length, String(this.max).length);
53
+ const widest = Math.max(this.said(this.min).length, this.said(this.max).length);
50
54
  return this.range ? widest * 2 + ' to '.length : widest;
51
55
  }
52
56
  get precision() {
@@ -110,8 +114,57 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
110
114
  willUpdate(changed) {
111
115
  super.willUpdate(changed);
112
116
  if (!this.hasUpdated && this.value === '') {
113
- this.defaultValue = String(this.min + (this.max - this.min) / 2);
117
+ this.defaultValue = this.range
118
+ ? `${this.min},${this.max}`
119
+ : String(this.min + (this.max - this.min) / 2);
120
+ }
121
+ const clean = this.sanitize(this.value);
122
+ if (clean !== this.value) {
123
+ this.value = clean;
124
+ }
125
+ }
126
+ settled(at) {
127
+ const low = Math.min(this.min, this.max);
128
+ const high = Math.max(this.min, this.max);
129
+ return Math.min(high, Math.max(low, this.snapped(Math.min(high, Math.max(low, at)))));
130
+ }
131
+ sanitize(text) {
132
+ if (this.range) {
133
+ const [from, to] = text.split(',').map((part) => Number.parseFloat(part));
134
+ if (from === undefined ||
135
+ to === undefined ||
136
+ !Number.isFinite(from) ||
137
+ !Number.isFinite(to)) {
138
+ return `${this.min},${this.max}`;
139
+ }
140
+ const ends = [this.settled(from), this.settled(to)].sort((a, b) => a - b);
141
+ return ends.join(',');
114
142
  }
143
+ const parsed = Number.parseFloat(text);
144
+ const at = Number.isFinite(parsed) ? parsed : this.min + (this.max - this.min) / 2;
145
+ return String(this.settled(at));
146
+ }
147
+ get gap() {
148
+ return Math.max(0, this.minStepsBetweenThumbs) * this.step;
149
+ }
150
+ get formats() {
151
+ return this.formatter !== undefined || this.formatOptions !== undefined;
152
+ }
153
+ said(at) {
154
+ const number = typeof at === 'number' ? at : Number.parseFloat(at);
155
+ if (!Number.isFinite(number)) {
156
+ return String(at);
157
+ }
158
+ if (this.formatter) {
159
+ return this.formatter(number);
160
+ }
161
+ return this.formatOptions ? formatNumber(number, this.locale, this.formatOptions) : String(at);
162
+ }
163
+ spoken(at) {
164
+ if (this.valueText) {
165
+ return fillTemplate(this.valueText, { value: this.said(at) });
166
+ }
167
+ return this.formats ? this.said(at) : nothing;
115
168
  }
116
169
  updated(changed) {
117
170
  super.updated(changed);
@@ -130,6 +183,9 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
130
183
  step=${this.step}
131
184
  .value=${String(at)}
132
185
  aria-labelledby=${this.labeled ? `${this.labelId} ${which}-name` : `${which}-name`}
186
+ aria-valuemin=${which === 'end' ? start + this.gap : nothing}
187
+ aria-valuemax=${which === 'start' ? end - this.gap : nothing}
188
+ aria-valuetext=${this.spoken(at)}
133
189
  aria-describedby=${this.describedBy ?? nothing}
134
190
  aria-invalid=${this.invalidity ?? nothing}
135
191
  ?disabled=${this.isDisabled}
@@ -161,6 +217,7 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
161
217
  step=${this.step}
162
218
  .value=${this.value}
163
219
  name=${this.name || nothing}
220
+ aria-valuetext=${this.spoken(this.value)}
164
221
  aria-describedby=${this.describedBy ?? nothing}
165
222
  aria-invalid=${this.invalidity ?? nothing}
166
223
  ?disabled=${this.isDisabled}
@@ -172,7 +229,9 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
172
229
  ${this.markerValues.map((at) => html `<span
173
230
  part="marker"
174
231
  style="--slider-marker-at: ${((at - this.min) / (this.max - this.min)) * 100}%"
175
- >${this.markerLabels ? html `<span part="marker-label">${at}</span>` : nothing}</span
232
+ >${this.markerLabels
233
+ ? html `<span part="marker-label">${this.said(at)}</span>`
234
+ : nothing}</span
176
235
  >`)}
177
236
  </div>`
178
237
  : nothing}
@@ -182,13 +241,22 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
182
241
  for=${this.range ? 'control control-end' : 'control'}
183
242
  aria-hidden="true"
184
243
  style=${`--_slider-output-reserve: ${this.reserve}ch`}
185
- >${this.range ? `${start} to ${end}` : this.value}</output
244
+ >${this.range ? `${this.said(start)} to ${this.said(end)}` : this.said(this.value)}</output
186
245
  >`
187
246
  : nothing}
188
247
  </div>
189
248
  ${this.renderHint()}${this.renderFeedback()}`;
190
249
  }
191
250
  };
251
+ __decorate([
252
+ property({ attribute: 'format-options', type: Object })
253
+ ], HelixHeadlessSlider.prototype, "formatOptions", void 0);
254
+ __decorate([
255
+ property({ attribute: false })
256
+ ], HelixHeadlessSlider.prototype, "formatter", void 0);
257
+ __decorate([
258
+ property()
259
+ ], HelixHeadlessSlider.prototype, "locale", void 0);
192
260
  __decorate([
193
261
  property({ attribute: 'marker-labels', reflect: true, type: Boolean })
194
262
  ], HelixHeadlessSlider.prototype, "markerLabels", void 0);
@@ -207,6 +275,9 @@ __decorate([
207
275
  __decorate([
208
276
  property({ attribute: 'minimum-label' })
209
277
  ], HelixHeadlessSlider.prototype, "minimumLabel", void 0);
278
+ __decorate([
279
+ property({ attribute: 'min-steps-between-thumbs', type: Number })
280
+ ], HelixHeadlessSlider.prototype, "minStepsBetweenThumbs", void 0);
210
281
  __decorate([
211
282
  property({ reflect: true })
212
283
  ], HelixHeadlessSlider.prototype, "orientation", void 0);
@@ -219,6 +290,9 @@ __decorate([
219
290
  __decorate([
220
291
  property({ type: Number })
221
292
  ], HelixHeadlessSlider.prototype, "step", void 0);
293
+ __decorate([
294
+ property({ attribute: 'value-text' })
295
+ ], HelixHeadlessSlider.prototype, "valueText", void 0);
222
296
  HelixHeadlessSlider = __decorate([
223
297
  customElement('helix-headless-slider')
224
298
  ], HelixHeadlessSlider);
@@ -9,9 +9,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
9
9
  * `values` to the data and `label` to the one sentence a screen reader
10
10
  * announces.
11
11
  *
12
- * This follows the library's rule that a content property is the fallback for
13
- * its slot, as with `Tooltip`'s `content` and `Avatar`'s `name`. Use `for` when
14
- * a sparkline has a real table behind it. `for` wins when both are set.
12
+ * Use `for` when a sparkline has a real table behind it. `for` wins when both
13
+ * are set.
15
14
  *
16
15
  * Without a `label` the sparkline is decorative and `aria-hidden`, for example
17
16
  * beside a stat that already says "Sessions, 1,102". With a `label` it is an
@@ -95,8 +94,8 @@ export declare class HelixHeadlessSparkline extends HelixElement {
95
94
  /**
96
95
  * What the readings are drawn as.
97
96
  *
98
- * Absent is a line, `area` is a line with the region beneath it washed, and
99
- * `bar` is a column per reading.
97
+ * Absent is `area`, a line with the region beneath it washed. `line` is the
98
+ * bare stroke, and `bar` is a column per reading.
100
99
  *
101
100
  * **A bar plot measures from zero and the other two measure from the data's
102
101
  * own range**, which is the one way the plots are not interchangeable. A line
@@ -125,12 +124,12 @@ export declare class HelixHeadlessSparkline extends HelixElement {
125
124
  /**
126
125
  * The numbers, separated by whitespace or by commas.
127
126
  *
128
- * Both separators, so `values="1240 1318"` and an array assigned to the
129
- * property both work: assigning `[1240, 1318]` stringifies to `1240,1318`,
130
- * and a string is what survives React's hydration where an array property
131
- * does not.
127
+ * An array assigned to the property works too, which is what React 19 does
128
+ * with `values={[1240, 1318]}`. The attribute is the form to prefer, because
129
+ * a string is what survives React's hydration where an array property does
130
+ * not.
132
131
  */
133
- values: string;
132
+ values: string | readonly number[];
134
133
  protected readonly source: SourceController;
135
134
  protected willUpdate(changed: PropertyValues<this>): void;
136
135
  /** The series to draw: the table if there is one, the attribute otherwise. */
@@ -52,12 +52,18 @@ export declare class HelixHeadlessSpeedDialItem extends HelixElement {
52
52
  /** Chooses the action, the same as pressing it. */
53
53
  select(): void;
54
54
  /**
55
- * Whether the action has focus, which is what selected means in a speed dial.
55
+ * Whether the action has focus, which makes it the action the keyboard is on.
56
56
  *
57
- * Asked of the document rather than of the shadow root: focus lands on the
58
- * control inside this element and the platform retargets it, so from outside
59
- * `activeElement` already is this element. `Menu.Item` records the same;
60
- * reading it off the shadow root does not survive happy-dom.
57
+ * `Option` calls the same thing `active`. The focused node is found through
58
+ * every shadow root, as `Menu.Item` does, so a dial inside another
59
+ * component's shadow root still knows its current action.
60
+ */
61
+ get active(): boolean;
62
+ /**
63
+ * Whether the action has focus, the same as `active`.
64
+ *
65
+ * @deprecated Read `active`. Everywhere else in the library `selected` means
66
+ * chosen out of a set, and a speed dial's action is never chosen that way.
61
67
  */
62
68
  get selected(): boolean;
63
69
  private choose;
@@ -4,7 +4,7 @@ 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 } from '@fusion.dev/helix-core';
7
+ import { customElement, deepActiveElement, HelixElement, HelixSelectEvent, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessSpeedDialItem = class HelixHeadlessSpeedDialItem extends HelixElement {
@@ -26,8 +26,12 @@ let HelixHeadlessSpeedDialItem = class HelixHeadlessSpeedDialItem extends HelixE
26
26
  select() {
27
27
  this.choose();
28
28
  }
29
+ get active() {
30
+ const active = deepActiveElement();
31
+ return active !== null && active.getRootNode() === this.renderRoot;
32
+ }
29
33
  get selected() {
30
- return this.ownerDocument.activeElement === this;
34
+ return this.active;
31
35
  }
32
36
  choose() {
33
37
  if (this.disabled) {
@@ -42,6 +46,7 @@ let HelixHeadlessSpeedDialItem = class HelixHeadlessSpeedDialItem extends HelixE
42
46
  type="button"
43
47
  aria-disabled=${this.disabled ? 'true' : nothing}
44
48
  ?disabled=${this.disabled}
49
+ tabindex="-1"
45
50
  @click=${this.handleClick}
46
51
  >
47
52
  <span part="icon"><slot name="icon"></slot></span>
@@ -11,8 +11,8 @@ declare const HelixHeadlessSpeedDial_base: (new (...args: any[]) => import("@fus
11
11
  * - `PopoverController` for the panel
12
12
  * - `MixinControllerOpen` for open and closed
13
13
  *
14
- * It is a separate component because a speed dial has no submenus, headers,
15
- * checkable items, or type-ahead.
14
+ * It is a separate component because a speed dial has no submenus, headers, or
15
+ * checkable items.
16
16
  *
17
17
  * You slot the trigger. The usual floating action button is `IconButton` with
18
18
  * `shape="circle"` and `raised`. There is no `helix-fab`, because `IconButton`
@@ -21,7 +21,9 @@ declare const HelixHeadlessSpeedDial_base: (new (...args: any[]) => import("@fus
21
21
  *
22
22
  * All four arrow keys move through the actions, because a speed dial has no
23
23
  * nested levels to reserve the horizontal pair for. This is the default
24
- * behavior of the keyboard controller.
24
+ * behavior of the keyboard controller. Typing a letter moves to the next
25
+ * action whose name starts with it. The actions are one tab stop, and Tab
26
+ * closes the dial and moves on.
25
27
  *
26
28
  * @since 0.1.0
27
29
  * @status stable
@@ -35,7 +37,7 @@ declare const HelixHeadlessSpeedDial_base: (new (...args: any[]) => import("@fus
35
37
  * @event {HelixBeforeCloseEvent} helix-before-close - The actions are about to close. Cancelable: cancel it to keep them open.
36
38
  * @event {HelixBeforeOpenEvent} helix-before-open - The actions are about to open. Cancelable: cancel it to keep them closed.
37
39
  * @event {HelixSelectEvent} helix-select - An action was chosen. The action sends the event, and the dial closes after it. Cancelable: cancel it to keep the dial open.
38
- * @event {Event} toggle - The dial opened or closed. The event carries `newState` and `oldState`.
40
+ * @event {ToggleEvent} toggle - The dial opened or closed. The event carries `newState` and `oldState`.
39
41
  *
40
42
  * @csspart actions - The region the actions are drawn in.
41
43
  * @csspart trigger - The default trigger, drawn when none is slotted.
@@ -60,6 +62,15 @@ export declare class HelixHeadlessSpeedDial extends HelixHeadlessSpeedDial_base
60
62
  */
61
63
  placement: Placement;
62
64
  protected readonly keys: KeyboardNavigationController;
65
+ /**
66
+ * Whether the trigger asked for the open that is under way, which is the one
67
+ * open that moves focus onto the first action.
68
+ *
69
+ * A dial opened by `default-open` or by a script setting `open` leaves focus
70
+ * where it is: on load that is wherever `autofocus` put it, and later it is
71
+ * wherever the reader is typing.
72
+ */
73
+ private focusOnOpen;
63
74
  protected readonly panel: PopoverController;
64
75
  /** Whatever the consumer slotted, or the button rendered in its place. */
65
76
  private get trigger();
@@ -4,7 +4,7 @@ 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 { anchorElement, customElement, drawIcon, HelixElement, KeyboardNavigationController, MixinControllerOpen, PopoverController, tellDisclosure, } from '@fusion.dev/helix-core';
7
+ import { anchorElement, customElement, drawIcon, HelixElement, KeyboardNavigationController, MixinControllerOpen, PopoverController, slottedWords, tellDisclosure, } from '@fusion.dev/helix-core';
8
8
  import { plus } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -15,9 +15,11 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
15
15
  this.offset = 12;
16
16
  this.placement = 'top-end';
17
17
  this.keys = new KeyboardNavigationController(this, {
18
- items: () => this.items,
18
+ items: () => (this.open ? this.items : []),
19
19
  selects: () => false,
20
+ typeahead: (item) => slottedWords(item, ['']),
20
21
  });
22
+ this.focusOnOpen = false;
21
23
  this.panel = new PopoverController(this, {
22
24
  anchor: () => this.trigger,
23
25
  boundary: () => this,
@@ -28,7 +30,11 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
28
30
  surface: () => this.partNamed('actions'),
29
31
  });
30
32
  this.handleTriggerClick = () => {
31
- this.requestOpen(!this.open);
33
+ if (this.open) {
34
+ this.requestOpen(false);
35
+ return;
36
+ }
37
+ this.focusOnOpen = this.requestOpen(true);
32
38
  };
33
39
  this.handleSelect = (event) => {
34
40
  queueMicrotask(() => {
@@ -38,6 +44,13 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
38
44
  });
39
45
  };
40
46
  this.handleKeydown = (event) => {
47
+ if (!this.open) {
48
+ return;
49
+ }
50
+ if (event.key === 'Tab') {
51
+ this.requestOpen(false);
52
+ return;
53
+ }
41
54
  if (event.key !== 'Escape') {
42
55
  return;
43
56
  }
@@ -74,12 +87,13 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
74
87
  if (trigger === this.partNamed('trigger')) {
75
88
  return;
76
89
  }
77
- tellDisclosure(trigger, this.open);
90
+ tellDisclosure(trigger, this.open, 'menu');
78
91
  }
79
92
  updated(changed) {
80
93
  super.updated?.(changed);
81
94
  this.announce();
82
- if (this.open) {
95
+ if (this.open && this.focusOnOpen) {
96
+ this.focusOnOpen = false;
83
97
  this.updateComplete.then(() => {
84
98
  if (this.open) {
85
99
  this.items.find((one) => !one.disabled)?.focusItem();
@@ -1,4 +1,4 @@
1
- import { HelixElement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, HelixElement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  /**
4
4
  * @summary Two panes and a divider that you can move.
@@ -13,9 +13,10 @@ import { type PropertyValues, type TemplateResult } from 'lit';
13
13
  * added at `firstUpdated` and is not in the server markup. Before it appears,
14
14
  * both dividers work on their own.
15
15
  *
16
- * The divider has `role="separator"` and `aria-valuenow`. Drag it with a
17
- * pointer or move it with the arrow keys, and press `Home` or `End` to move it
18
- * to its bounds. A drag in progress is tracked as a state, so both dividers a
16
+ * The divider has `role="separator"` and `aria-valuenow`, and `aria-controls`
17
+ * names the start pane. Drag it with a pointer or move it with the arrow keys,
18
+ * press `Home` or `End` to move it to its bounds, and press `Enter` to collapse
19
+ * the start pane and open it again. A drag in progress is tracked as a state, so both dividers a
19
20
  * corner moves stay lit for as long as they move.
20
21
  *
21
22
  * By default, `min` and `max` let the divider reach either edge, so you can
@@ -39,6 +40,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
39
40
  *
40
41
  * @event {HelixBeforeCollapseEvent} helix-before-collapse - Fired before a pane shuts or reopens, whether or not the resize that caused it was allowed. It carries its own position, because a shut pane sits at `collapsed-size`. Cancelable: canceling it leaves the pane as it was and the divider where the gesture put it.
41
42
  * @event {HelixBeforeResizeEvent} helix-before-resize - Fired before the divider settles, and only when the gesture moved it. A press that moved nothing, a drag that came back, an arrow key with no room left, and a corner that moved only the other divider do not fire it. Cancelable: canceling it leaves the position to you and keeps the rest of the gesture, so a collapse the gesture reached still fires `helix-before-collapse`, which you can also cancel. A dragged divider stays where it was dropped until you set your own `position`.
43
+ * @event {HelixCollapseEvent} helix-collapse - Fired after a pane shuts or reopens, with the side that is shut, or empty where both are open.
44
+ * @event {HelixResizedEvent} helix-resized - Fired after the divider settles somewhere new, with the new position.
42
45
  *
43
46
  * @csspart corner - The handle where two dividers cross, added on the client.
44
47
  * @csspart end - The box that holds the second pane.
@@ -96,8 +99,13 @@ export declare class HelixHeadlessSplitter extends HelixElement {
96
99
  defaultPosition: number;
97
100
  /**
98
101
  * The divider's name, read by screen readers.
102
+ *
103
+ * An `aria-label` or `aria-labelledby` on the host names the divider too,
104
+ * and wins over this.
99
105
  */
100
106
  label: string;
107
+ /** Carries a host `aria-label` and `aria-labelledby` to the divider. */
108
+ protected readonly aria: AriaForwardController;
101
109
  /**
102
110
  * How close the divider can come to the end, in the same units as `min`.
103
111
  */
@@ -453,6 +461,19 @@ export declare class HelixHeadlessSplitter extends HelixElement {
453
461
  * it on every page, which on a right-to-left one sent the divider right.
454
462
  */
455
463
  private travel;
464
+ /**
465
+ * Collapses the start pane, or opens whichever pane is collapsed, which is
466
+ * what `Enter` does on the divider.
467
+ *
468
+ * The window splitter pattern's own key, and the one way the keyboard
469
+ * reaches `collapsed` where `min` keeps `Home` short of the edge. Collapse
470
+ * overrides `min` and `max`, as it does for every other way in.
471
+ *
472
+ * Asked through `helix-before-collapse` alone. The pane opens back to the
473
+ * position it was collapsed from, or to `default-position` where that was
474
+ * the edge itself.
475
+ */
476
+ private toggleCollapse;
456
477
  /** Puts the divider back where the markup put it. */
457
478
  private reset;
458
479
  private readonly handleDoubleClick;
@@ -465,7 +486,8 @@ export declare class HelixHeadlessSplitter extends HelixElement {
465
486
  */
466
487
  private readonly handleCornerDoubleClick;
467
488
  /**
468
- * Records that a nested splitter crosses this one at `at` percent along it.
489
+ * @internal Records that a nested splitter crosses this one at `at` percent
490
+ * along it.
469
491
  *
470
492
  * Public because it is the whole of the channel between the two, and it runs
471
493
  * one way: the child tells the parent where it is, and the parent draws the
@@ -473,7 +495,7 @@ export declare class HelixHeadlessSplitter extends HelixElement {
473
495
  * anything about the other's state.
474
496
  */
475
497
  cross(by: HelixHeadlessSplitter, at: number): void;
476
- /** Forgets a nested splitter that has left the tree. See `cross`. */
498
+ /** @internal Forgets a nested splitter that has left the tree. See `cross`. */
477
499
  uncross(by: HelixHeadlessSplitter): void;
478
500
  /**
479
501
  * Announces this splitter to the one it is nested in, if they cross.
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  var HelixHeadlessSplitter_1;
8
- import { capturePointer, closestInstance, customElement, HelixBeforeCollapseEvent, HelixBeforeResizeEvent, HelixElement, inlineStep, isRtl, requestChange, } from '@fusion.dev/helix-core';
8
+ import { AriaForwardController, capturePointer, closestInstance, customElement, HelixBeforeCollapseEvent, HelixBeforeResizeEvent, HelixCollapseEvent, HelixElement, HelixResizedEvent, inlineStep, isRtl, requestChange, } from '@fusion.dev/helix-core';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
11
  const STACK_BELOW = 512;
@@ -17,6 +17,10 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
17
17
  this.cornerLabel = 'Resize both';
18
18
  this.defaultPosition = 50;
19
19
  this.label = 'Resize panes';
20
+ this.aria = new AriaForwardController(this, {
21
+ label: true,
22
+ target: () => this.partNamed('separator'),
23
+ });
20
24
  this.max = 100;
21
25
  this.min = 0;
22
26
  this.step = 2;
@@ -68,6 +72,11 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
68
72
  this.settle(this.reached ?? this.position);
69
73
  };
70
74
  this.handleKeydown = (event) => {
75
+ if (event.key === 'Enter') {
76
+ this.toggleCollapse();
77
+ event.preventDefault();
78
+ return;
79
+ }
71
80
  const toward = this.travel(event.key);
72
81
  let next;
73
82
  if (toward !== 0) {
@@ -313,6 +322,7 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
313
322
  const previous = this.position;
314
323
  this.positionState = value;
315
324
  this.requestUpdate('position', previous);
325
+ this.dispatchEvent(new HelixResizedEvent({ value: String(value) }));
316
326
  },
317
327
  event: (value) => new HelixBeforeResizeEvent({ value: String(value) }),
318
328
  host: this,
@@ -327,6 +337,7 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
327
337
  }
328
338
  this.collapsedState = value === '' ? 'none' : value;
329
339
  this.requestUpdate('collapsed', previous);
340
+ this.dispatchEvent(new HelixCollapseEvent({ value }));
330
341
  },
331
342
  event: (value) => new HelixBeforeCollapseEvent({ value }),
332
343
  host: this,
@@ -340,6 +351,27 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
340
351
  }
341
352
  return key === 'ArrowDown' ? 1 : key === 'ArrowUp' ? -1 : 0;
342
353
  }
354
+ toggleCollapse() {
355
+ const shut = this.collapsed;
356
+ const opened = shut ? undefined : this.position;
357
+ requestChange({
358
+ apply: (value) => {
359
+ const previous = this.collapsed;
360
+ if (opened !== undefined) {
361
+ this.positionState = opened;
362
+ }
363
+ else if (this.shutAt(this.clamp(this.positionState ?? this.defaultPosition))) {
364
+ this.positionState = this.defaultPosition;
365
+ }
366
+ this.collapsedState = value === '' ? 'none' : value;
367
+ this.requestUpdate('collapsed', previous);
368
+ this.dispatchEvent(new HelixCollapseEvent({ value }));
369
+ },
370
+ event: (value) => new HelixBeforeCollapseEvent({ value }),
371
+ host: this,
372
+ next: shut ? '' : 'start',
373
+ });
374
+ }
343
375
  reset() {
344
376
  const home = this.clamp(this.defaultPosition);
345
377
  this.settle(home);
@@ -427,6 +459,7 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
427
459
  const position = this.showing;
428
460
  return html `<div
429
461
  part="start"
462
+ id="start"
430
463
  ?data-dragging=${this.dragging}
431
464
  style="--splitter-position: ${position}%"
432
465
  >
@@ -436,6 +469,7 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
436
469
  part="separator"
437
470
  role="separator"
438
471
  tabindex="0"
472
+ aria-controls="start"
439
473
  aria-label=${this.label}
440
474
  aria-orientation=${this.vertical ? 'horizontal' : 'vertical'}
441
475
  aria-valuemax=${this.collapsed ? 100 : this.clamp(this.maxPercent)}