@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
@@ -1,5 +1,5 @@
1
1
  import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
2
- import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
3
3
  /**
4
4
  * @summary Triggers an action, submits a form, or navigates.
5
5
  *
@@ -21,6 +21,17 @@ import { type PropertyValues, type TemplateResult } from 'lit';
21
21
  * it. To submit, the button calls `requestSubmit()` on its form, which runs
22
22
  * validation, unlike `submit()`.
23
23
  *
24
+ * A `submit` listener reads `event.submitter` as `null`, because the platform
25
+ * accepts only a native submit button there. The button's `name` and `value`
26
+ * are in the form data, so read them from `new FormData(form)` to tell two
27
+ * submit buttons apart.
28
+ *
29
+ * As the first submit button in its form, it is the form's default button:
30
+ * Enter in a text field of the form presses it, as it presses a native one.
31
+ *
32
+ * Set `pending` while the action a press started is still running. The button
33
+ * keeps focus and refuses presses, and a reader on it hears `pending-label`.
34
+ *
24
35
  * @since 0.1.0
25
36
  * @status stable
26
37
  * @category actions
@@ -31,10 +42,19 @@ import { type PropertyValues, type TemplateResult } from 'lit';
31
42
  * @slot start - Content before the label, usually an icon.
32
43
  *
33
44
  * @csspart button - The inner control.
45
+ * @csspart live - The live region that says `pending-label` when the button becomes pending under focus. It is rendered from the first time the button is pending, and the styled button clips it out of view.
34
46
  * @csspart text - The button's words, which the styled button trims to their capitals and baseline so the letters sit at the middle in any font.
47
+ *
48
+ * @cssstate pending - The button is pending: `pending` is set.
35
49
  */
36
50
  export declare class HelixHeadlessButton extends HelixFormElement {
37
51
  protected readonly aria: AriaForwardController;
52
+ /**
53
+ * @internal Whether a host `aria-label` names the inner button. A subclass
54
+ * that writes the name itself, as `CopyButton` does while it confirms a
55
+ * copy, says no.
56
+ */
57
+ protected get forwardsLabel(): boolean;
38
58
  /**
39
59
  * What to send when the button is activated, and what to send it to.
40
60
  *
@@ -143,6 +163,24 @@ export declare class HelixHeadlessButton extends HelixFormElement {
143
163
  * "button" and nothing else.
144
164
  */
145
165
  label: string;
166
+ /**
167
+ * Whether the action the button started is still running.
168
+ *
169
+ * A pending button keeps focus and stays in the tab order, and refuses every
170
+ * press: a click, Enter and Space, and Enter in a field of its form. The
171
+ * click does not reach your listeners. The inner control carries
172
+ * `aria-busy` and `aria-disabled`, and when the button becomes pending while
173
+ * it has focus, a reader hears `pending-label`. The styled button draws a
174
+ * turning ring over its words.
175
+ *
176
+ * `disabled` takes the button out of reach. Use `pending` for the wait after
177
+ * a press, so focus stays where the reader left it.
178
+ */
179
+ pending: boolean;
180
+ /**
181
+ * What a reader hears when the button becomes pending while it has focus.
182
+ */
183
+ pendingLabel: string;
146
184
  /**
147
185
  * What kind of panel this button opens, where it opens one: `menu` for a
148
186
  * `Menu`.
@@ -153,6 +191,27 @@ export declare class HelixHeadlessButton extends HelixFormElement {
153
191
  * reported collapsed and expanded and no popup.
154
192
  */
155
193
  popup?: 'dialog' | 'grid' | 'listbox' | 'menu' | 'tree';
194
+ /**
195
+ * The status region, rendered from the first time the button is pending, so
196
+ * a button that never waits carries no live region.
197
+ */
198
+ private readonly status;
199
+ /**
200
+ * Says `pendingLabel` when the button becomes pending under focus, and
201
+ * clears it when the wait ends.
202
+ *
203
+ * **Only under focus**, as React Aria announces it: the reader who pressed
204
+ * the button is the one waiting, and a button elsewhere on the page that
205
+ * starts waiting is not news to them. The region arrives empty and takes its
206
+ * words a frame later, since a region that arrives with its words is read
207
+ * inconsistently.
208
+ */
209
+ private sayPending;
210
+ /**
211
+ * @internal The live region a pending button speaks in, for a subclass that
212
+ * replaces the template, as `CopyButton` does.
213
+ */
214
+ protected renderLive(): TemplateResult | typeof nothing;
156
215
  /** Moves focus to the inner control, so the host is never the focus target. */
157
216
  static shadowRootOptions: ShadowRootInit;
158
217
  private readonly handleClick;
@@ -235,7 +294,31 @@ export declare class HelixHeadlessButton extends HelixFormElement {
235
294
  * fixes and would only appear on the browsers that work.
236
295
  */
237
296
  private sendCommand;
297
+ protected willUpdate(changed: PropertyValues): void;
238
298
  protected updated(changed: PropertyValues): void;
299
+ /** @internal A submit button is what its form's implicit submission presses. */
300
+ protected get submitsForm(): boolean;
301
+ /** @internal Pressed as the form's default button, through the inner control. */
302
+ protected activate(): void;
303
+ /** The form whose Enter key this button listens to, as its default button. */
304
+ private watched;
305
+ /**
306
+ * Presses this button for Enter in a native text field of its form, when it
307
+ * is the form's default button.
308
+ *
309
+ * The platform cannot find a default button in a shadow root, so a form whose
310
+ * only submit button is this one found none: with two fields Enter did
311
+ * nothing, and with one it submitted without this button's name, value or
312
+ * overrides. The event's default is prevented so a later native submit button
313
+ * is not pressed instead.
314
+ */
315
+ private readonly pressOnEnter;
316
+ /** Listens to the form this button now belongs to, and to no other. */
317
+ private watchForm;
318
+ connectedCallback(): void;
319
+ disconnectedCallback(): void;
320
+ /** Called by the browser when the button's form changes. */
321
+ formAssociatedCallback(form: HTMLFormElement | null): void;
239
322
  protected render(): TemplateResult;
240
323
  }
241
324
  declare global {
@@ -4,14 +4,16 @@ 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, elementById, HelixFallbackCommandEvent, HelixFormElement, supportsInvokers, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, drawStatus, elementById, HelixFallbackCommandEvent, HelixFormElement, StatusController, supportsInvokers, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  this.aria = new AriaForwardController(this, {
14
+ label: () => this.forwardsLabel,
14
15
  target: () => this.partNamed('button'),
16
+ unnamed: 'Give it words, a `label`, or an `aria-label`.',
15
17
  });
16
18
  this.command = '';
17
19
  this.commandFor = '';
@@ -22,7 +24,15 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
22
24
  this.formNoValidate = false;
23
25
  this.formTarget = '';
24
26
  this.label = '';
25
- this.handleClick = () => {
27
+ this.pending = false;
28
+ this.pendingLabel = 'Loading';
29
+ this.status = new StatusController(this);
30
+ this.handleClick = (event) => {
31
+ if (this.pending) {
32
+ event.preventDefault();
33
+ event.stopImmediatePropagation();
34
+ return;
35
+ }
26
36
  this.linkCommand();
27
37
  this.sendCommand();
28
38
  if (this.type === 'button') {
@@ -41,6 +51,34 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
41
51
  };
42
52
  this.type = 'button';
43
53
  this.value = '';
54
+ this.watched = null;
55
+ this.pressOnEnter = (event) => {
56
+ const form = this.watched;
57
+ if (event.key !== 'Enter' ||
58
+ event.defaultPrevented ||
59
+ !form ||
60
+ !HelixFormElement.submitsOnEnter(event.composedPath()[0], form) ||
61
+ HelixFormElement.defaultButton(form) !== this) {
62
+ return;
63
+ }
64
+ event.preventDefault();
65
+ if (!this.isDisabled && !this.pending) {
66
+ this.activate();
67
+ }
68
+ };
69
+ }
70
+ get forwardsLabel() {
71
+ return true;
72
+ }
73
+ sayPending() {
74
+ const focused = this.renderRoot?.activeElement != null;
75
+ if (!focused && this.status.said === '') {
76
+ return;
77
+ }
78
+ this.status.say(this.pending && focused ? this.pendingLabel : '', { clear: false });
79
+ }
80
+ renderLive() {
81
+ return drawStatus(this.status);
44
82
  }
45
83
  static { this.shadowRootOptions = {
46
84
  ...HelixFormElement.shadowRootOptions,
@@ -112,9 +150,41 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
112
150
  }
113
151
  this.commandTarget()?.dispatchEvent(new HelixFallbackCommandEvent(this.command, this));
114
152
  }
153
+ willUpdate(changed) {
154
+ super.willUpdate(changed);
155
+ this.toggleState('pending', this.pending);
156
+ }
115
157
  updated(changed) {
116
158
  super.updated(changed);
117
159
  this.linkCommand();
160
+ if (changed.has('pending') && changed.get('pending') !== undefined) {
161
+ this.sayPending();
162
+ }
163
+ }
164
+ get submitsForm() {
165
+ return this.type === 'submit';
166
+ }
167
+ activate() {
168
+ this.partNamed('button')?.click();
169
+ }
170
+ watchForm(form) {
171
+ if (form === this.watched) {
172
+ return;
173
+ }
174
+ this.watched?.removeEventListener('keypress', this.pressOnEnter);
175
+ form?.addEventListener('keypress', this.pressOnEnter);
176
+ this.watched = form;
177
+ }
178
+ connectedCallback() {
179
+ super.connectedCallback();
180
+ this.watchForm(this.form);
181
+ }
182
+ disconnectedCallback() {
183
+ super.disconnectedCallback();
184
+ this.watchForm(null);
185
+ }
186
+ formAssociatedCallback(form) {
187
+ this.watchForm(form);
118
188
  }
119
189
  render() {
120
190
  const label = html `<slot name="start"></slot><slot part="text"></slot><slot name="end"></slot>`;
@@ -124,6 +194,8 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
124
194
  type="button"
125
195
  aria-expanded=${this.expanded === undefined ? nothing : String(this.expanded)}
126
196
  aria-haspopup=${this.popup ?? nothing}
197
+ aria-busy=${this.pending ? 'true' : nothing}
198
+ aria-disabled=${this.pending ? 'true' : nothing}
127
199
  aria-label=${this.label || nothing}
128
200
  command=${this.command || nothing}
129
201
  tabindex=${stop}
@@ -131,7 +203,7 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
131
203
  @click=${this.handleClick}
132
204
  >
133
205
  ${label}
134
- </button>`;
206
+ </button>${this.renderLive()}`;
135
207
  }
136
208
  };
137
209
  __decorate([
@@ -164,6 +236,12 @@ __decorate([
164
236
  __decorate([
165
237
  property()
166
238
  ], HelixHeadlessButton.prototype, "label", void 0);
239
+ __decorate([
240
+ property({ type: Boolean })
241
+ ], HelixHeadlessButton.prototype, "pending", void 0);
242
+ __decorate([
243
+ property({ attribute: 'pending-label' })
244
+ ], HelixHeadlessButton.prototype, "pendingLabel", void 0);
167
245
  __decorate([
168
246
  property({ attribute: false })
169
247
  ], HelixHeadlessButton.prototype, "popup", void 0);
@@ -1,15 +1,22 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
+ declare const HelixHeadlessCallout_base: (new (...args: any[]) => import("@fusion.dev/helix-core").DismissibleElement) & typeof HelixElement;
3
4
  /**
4
5
  * @summary A passage set apart as a note, information, a warning, or an error.
5
6
  *
6
7
  * @description
7
8
  * `tone` is on the headless tier because it carries meaning. It picks the icon
8
- * and the icon's accessible name, so a screen reader announces "Error" for an
9
- * error callout whether or not the color is seen.
9
+ * and the icon region's accessible name, so a screen reader announces "Error"
10
+ * for an error callout whether or not the color is seen. Set `tone-label` to
11
+ * say the name in another language.
10
12
  *
11
13
  * The icon is the fallback content of a slot. Slot your own icon to replace it,
12
- * and the default disappears with no extra check.
14
+ * and the default disappears with no extra check. The tone's name stays on the
15
+ * region around it.
16
+ *
17
+ * Set `dismissible` for a note a reader may put away, as Shoelace's `closable`
18
+ * alert does. The button fires `helix-dismiss` and the callout stays until a
19
+ * listener removes it, so the page decides whether it comes back.
13
20
  *
14
21
  * A callout sets a passage apart inside a document and is read where it sits.
15
22
  * For page-level chrome above the masthead that is a live region and can be
@@ -22,14 +29,19 @@ import { type PropertyValues, type TemplateResult } from 'lit';
22
29
  * @documentation https://fusion.dev/helix/components/callout
23
30
  *
24
31
  * @slot - The callout's content.
32
+ * @slot dismiss-icon - Replaces the cross inside the dismiss button.
25
33
  * @slot heading - A heading above the content.
26
34
  * @slot icon - Replaces the icon chosen by `tone`.
27
35
  *
36
+ * @event {HelixDismissEvent} helix-dismiss - The dismiss button was pressed. The callout does not remove itself, so remove it in response. Cancelable.
37
+ *
28
38
  * @csspart content - The content region.
29
- * @csspart icon - The icon region.
39
+ * @csspart dismiss - The button that dismisses the callout, shown when `dismissible` is set.
40
+ * @csspart dismiss-mark - The cross on the dismiss button, shown when the `dismiss-icon` slot is empty.
41
+ * @csspart icon - The icon region, an image named for the tone.
30
42
  * @csspart icon-mark - The icon for the tone, shown when no icon is slotted.
31
43
  */
32
- export declare class HelixHeadlessCallout extends HelixElement {
44
+ export declare class HelixHeadlessCallout extends HelixHeadlessCallout_base {
33
45
  protected willUpdate(changed: PropertyValues): void;
34
46
  /**
35
47
  * What kind of attention the passage needs.
@@ -40,6 +52,13 @@ export declare class HelixHeadlessCallout extends HelixElement {
40
52
  * is the whole of the registry, which is why there is no `severity` beside it.
41
53
  */
42
54
  tone?: 'danger' | 'info' | 'neutral' | 'success' | 'warning';
55
+ /**
56
+ * What a screen reader is told the tone is, such as "Fehler".
57
+ *
58
+ * Absent is the English for the tone: "Error", "Information", "Note",
59
+ * "Success" or "Warning".
60
+ */
61
+ toneLabel: string;
43
62
  /**
44
63
  * The mark for the callout's tone, behind a seam.
45
64
  *
@@ -56,7 +75,13 @@ export declare class HelixHeadlessCallout extends HelixElement {
56
75
  protected renderIcon(icon: {
57
76
  content: string;
58
77
  viewBox: string;
59
- }, label: string): TemplateResult;
78
+ }, _label: string): TemplateResult;
79
+ /**
80
+ * The cross inside the dismiss button, behind a seam, for the reason
81
+ * `renderIcon` gives: the slot answers the page and the method the tier
82
+ * above.
83
+ */
84
+ protected renderDismissIcon(): TemplateResult;
60
85
  protected render(): TemplateResult;
61
86
  }
62
87
  declare global {
@@ -64,3 +89,4 @@ declare global {
64
89
  'helix-headless-callout': HelixHeadlessCallout;
65
90
  }
66
91
  }
92
+ export {};
@@ -4,35 +4,54 @@ 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, hostAria, TONE_MARKS, toneMark } from '@fusion.dev/helix-core';
8
- import { html } from 'lit';
7
+ import { customElement, drawDismiss, drawDismissGlyph, HelixElement, hostAria, MixinDismissible, TONE_MARKS, toneMark, } from '@fusion.dev/helix-core';
8
+ import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
11
11
  const NOTE = { icon: TONE_MARKS.info.icon, label: 'Note' };
12
- let HelixHeadlessCallout = class HelixHeadlessCallout extends HelixElement {
12
+ let HelixHeadlessCallout = class HelixHeadlessCallout extends MixinDismissible(HelixElement) {
13
+ constructor() {
14
+ super(...arguments);
15
+ this.toneLabel = '';
16
+ }
13
17
  willUpdate(changed) {
14
18
  super.willUpdate(changed);
15
19
  hostAria(this.internals, { role: 'note' });
16
20
  }
17
- renderIcon(icon, label) {
21
+ renderIcon(icon, _label) {
18
22
  return html `<slot name="icon">
19
- <svg part="icon-mark" fill="currentColor" viewBox=${icon.viewBox} role="img" aria-label=${label}>
23
+ <svg part="icon-mark" fill="currentColor" viewBox=${icon.viewBox} aria-hidden="true">
20
24
  ${unsafeSVG(icon.content)}
21
25
  </svg>
22
26
  </slot>`;
23
27
  }
28
+ renderDismissIcon() {
29
+ return html `<slot name="dismiss-icon">
30
+ ${drawDismissGlyph()}
31
+ </slot>`;
32
+ }
24
33
  render() {
25
34
  const { icon, label } = this.tone === 'neutral' ? NOTE : (toneMark(this.tone) ?? TONE_MARKS.info);
26
- return html `<span part="icon">${this.renderIcon(icon, label)}</span>
35
+ const named = this.toneLabel || label;
36
+ return html `<span part="icon" role="img" aria-label=${named}>${this.renderIcon(icon, named)}</span>
27
37
  <div part="content">
28
38
  <slot name="heading"></slot>
29
39
  <slot></slot>
30
- </div>`;
40
+ </div>${this.dismissible
41
+ ? drawDismiss({
42
+ label: this.dismissLabel,
43
+ mark: this.renderDismissIcon(),
44
+ onDismiss: () => this.dismiss(),
45
+ })
46
+ : nothing}`;
31
47
  }
32
48
  };
33
49
  __decorate([
34
50
  property({ reflect: true })
35
51
  ], HelixHeadlessCallout.prototype, "tone", void 0);
52
+ __decorate([
53
+ property({ attribute: 'tone-label' })
54
+ ], HelixHeadlessCallout.prototype, "toneLabel", void 0);
36
55
  HelixHeadlessCallout = __decorate([
37
56
  customElement('helix-headless-callout')
38
57
  ], HelixHeadlessCallout);
@@ -72,6 +72,7 @@ declare const HelixHeadlessCanvas_base: (new (...args: any[]) => import("@fusion
72
72
  * @aliases Board, JSON Canvas, Whiteboard
73
73
  * @documentation https://fusion.dev/helix/components/canvas
74
74
  *
75
+ * @slot - The board's `helix-canvas-node` and `helix-canvas-edge` elements, drawn on the plane.
75
76
  * @slot empty - Content shown when the document has no nodes.
76
77
  * @slot footer - Content below the board.
77
78
  * @slot header - Content above the board.
@@ -1738,7 +1738,6 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1738
1738
  return html `<svg
1739
1739
  part="edges"
1740
1740
  role="none"
1741
- @focusin=${this.handleFocusIn}
1742
1741
  viewBox=${`0 0 ${box.width} ${box.height}`}
1743
1742
  width=${box.width}
1744
1743
  height=${box.height}
@@ -1889,9 +1888,19 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1889
1888
  ruling's own offset is where the document's zero lands, so a line
1890
1889
  falls on every multiple of its spacing in the document's units and
1891
1890
  a card placed on one sits on a line. -->
1891
+ <!-- **Focus is heard here as well as on the host.** Moving from one
1892
+ connection to the next moves focus inside this shadow root, and a
1893
+ browser does not tell the host about a move that starts and ends
1894
+ in its own tree. So the stop stayed on the first of two
1895
+ connections in a row. Heard on the board and never on the edges'
1896
+ SVG element: Chromium makes an SVG element with a focus listener
1897
+ a Tab stop of its own, an unnamed one between the board and the
1898
+ first card. Heard twice from a card, which the handler answers
1899
+ the same way both times. -->
1892
1900
  <div
1893
1901
  part="board"
1894
1902
  style=${`--_canvas-plane-inline-size: ${box.width}px; --_canvas-plane-block-size: ${box.height}px`}
1903
+ @focusin=${this.handleFocusIn}
1895
1904
  >
1896
1905
  ${this.renderEdges(origin, box)} ${this.renderLabels(origin)}
1897
1906
  <slot @slotchange=${this.handleSlotChange}></slot>
@@ -14,7 +14,15 @@ import { type PropertyValues, type TemplateResult } from 'lit';
14
14
  *
15
15
  * Name the card with `aria-label` or `aria-labelledby`. These are the only
16
16
  * names that work with server rendering, because reading a title from the light
17
- * DOM needs a DOM, and the server has none.
17
+ * DOM needs a DOM, and the server has none. **A named card is a group**, so a
18
+ * reader entering it hears its name; an unnamed one has no role, since a group
19
+ * with no name only adds "group" to what a reader says.
20
+ *
21
+ * `header-actions` and `footer-actions` hold controls at the end of the
22
+ * header's and the footer's line, as Web Awesome's card does. While one holds
23
+ * something, its line is a `header-row` or `footer-row` part; otherwise there
24
+ * is no wrapper and every region is a bare slot. A server cannot see slotted
25
+ * content, so served actions sit on their own line until the script runs.
18
26
  *
19
27
  * @since 0.1.0
20
28
  * @status stable
@@ -24,8 +32,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
24
32
  *
25
33
  * @slot - The card's main content.
26
34
  * @slot footer - Actions that conclude the card.
35
+ * @slot footer-actions - Controls at the end of the footer's line, with the footer at its start.
27
36
  * @slot header - Title and any actions for the whole card.
37
+ * @slot header-actions - Controls for the whole card at the end of the header's line, such as a menu.
28
38
  * @slot media - Image, video, or chart that runs edge to edge, outside the inset.
39
+ *
40
+ * @csspart footer-row - The line holding `footer` and `footer-actions`, drawn only while `footer-actions` holds something.
41
+ * @csspart header-row - The line holding `header` and `header-actions`, drawn only while `header-actions` holds something.
29
42
  */
30
43
  export declare class HelixHeadlessCard extends HelixElement {
31
44
  /**
@@ -42,7 +55,23 @@ export declare class HelixHeadlessCard extends HelixElement {
42
55
  * with no attribute on it and the stylesheet only describes the departure.
43
56
  */
44
57
  mediaPlacement?: 'end';
58
+ /**
59
+ * @internal The host's `aria-labelledby`, observed so the card becomes a
60
+ * group once it is named. Not reflected: the attribute is the consumer's.
61
+ */
62
+ protected labelledBy: string | null;
63
+ /**
64
+ * @internal The host's `aria-label`, observed for the same reason as
65
+ * `labelledBy`. Not reflected: the attribute is the consumer's.
66
+ */
67
+ protected namedBy: string | null;
68
+ /** Whether `footer-actions` holds something, read from the slot. */
69
+ private footerActions;
70
+ /** Whether `header-actions` holds something, read from the slot. */
71
+ private headerActions;
45
72
  protected willUpdate(changed: PropertyValues): void;
73
+ protected updated(changed: PropertyValues): void;
74
+ private readonly readActions;
46
75
  protected render(): TemplateResult;
47
76
  }
48
77
  declare global {
@@ -4,26 +4,59 @@ 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, hostAria } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement, hostAria, slotFilled } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
- import { property } from 'lit/decorators.js';
9
+ import { property, state } from 'lit/decorators.js';
10
10
  let HelixHeadlessCard = class HelixHeadlessCard extends HelixElement {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.labelledBy = null;
14
+ this.namedBy = null;
15
+ this.footerActions = false;
16
+ this.headerActions = false;
17
+ this.readActions = () => {
18
+ const filled = (name) => slotFilled(this.renderRoot?.querySelector(`slot[name="${name}"]`));
19
+ this.headerActions = filled('header-actions');
20
+ this.footerActions = filled('footer-actions');
21
+ };
22
+ }
11
23
  willUpdate(changed) {
12
24
  super.willUpdate(changed);
13
- hostAria(this.internals, { role: 'group' });
25
+ const named = Boolean(this.namedBy?.trim() || this.labelledBy?.trim());
26
+ hostAria(this.internals, { role: named ? 'group' : '' });
27
+ }
28
+ updated(changed) {
29
+ super.updated(changed);
30
+ this.readActions();
14
31
  }
15
32
  render() {
33
+ const header = html `<slot name="header"></slot
34
+ ><slot name="header-actions" @slotchange=${this.readActions}></slot>`;
35
+ const footer = html `<slot name="footer"></slot
36
+ ><slot name="footer-actions" @slotchange=${this.readActions}></slot>`;
16
37
  return html `
17
38
  <slot name="media"></slot>
18
- <slot name="header"></slot>
39
+ ${this.headerActions ? html `<div part="header-row">${header}</div>` : header}
19
40
  <slot></slot>
20
- <slot name="footer"></slot>
41
+ ${this.footerActions ? html `<div part="footer-row">${footer}</div>` : footer}
21
42
  `;
22
43
  }
23
44
  };
24
45
  __decorate([
25
46
  property({ attribute: 'media-placement', reflect: true })
26
47
  ], HelixHeadlessCard.prototype, "mediaPlacement", void 0);
48
+ __decorate([
49
+ property({ attribute: 'aria-labelledby' })
50
+ ], HelixHeadlessCard.prototype, "labelledBy", void 0);
51
+ __decorate([
52
+ property({ attribute: 'aria-label' })
53
+ ], HelixHeadlessCard.prototype, "namedBy", void 0);
54
+ __decorate([
55
+ state()
56
+ ], HelixHeadlessCard.prototype, "footerActions", void 0);
57
+ __decorate([
58
+ state()
59
+ ], HelixHeadlessCard.prototype, "headerActions", void 0);
27
60
  HelixHeadlessCard = __decorate([
28
61
  customElement('helix-headless-card')
29
62
  ], HelixHeadlessCard);
@@ -16,7 +16,18 @@ import { type PropertyValues, type TemplateResult } from 'lit';
16
16
  *
17
17
  * **Rotation stops on focus and on hover, and stays stopped** until the user
18
18
  * starts it again, as the APG requires. The rotation control is labeled with
19
- * the action it performs and is first in the tab order.
19
+ * the action it performs and is first in the tab order. Rotation goes on from
20
+ * the last slide to the first, with or without `loop`, which is about the
21
+ * reader's own moves.
22
+ *
23
+ * A move the reader makes is announced, the slide's position read from a
24
+ * polite live region. While the carousel rotates the region is off, so a
25
+ * screen reader is not interrupted every few seconds.
26
+ *
27
+ * The indicators are one tab stop. The arrow keys along the track move between
28
+ * them, Up and Down on a vertical carousel, and Home and End go to the first
29
+ * and the last. Without `loop`, Previous on the first slide and Next on the
30
+ * last are marked `aria-disabled`.
20
31
  *
21
32
  * @since 0.1.0
22
33
  * @status stable
@@ -26,12 +37,14 @@ import { type PropertyValues, type TemplateResult } from 'lit';
26
37
  *
27
38
  * @slot - The slides.
28
39
  *
40
+ * @event {HelixActivateEvent} helix-activate - Fired after the slide in view changes, with the new index as a string in `detail.value`.
29
41
  * @event {HelixSelectEvent} helix-select - Fired before the slide in view changes, with the requested index. Cancelable: cancel it to keep the current slide. Nothing moves, and a drag returns to the slide the index still holds. See `handleScroll`.
30
42
  *
31
43
  * @csspart controls - The row of controls.
32
44
  * @csspart indicator - One indicator. Pressing it moves to its slide.
33
45
  * @csspart indicator-current - The indicator for the slide in view, alongside `indicator`.
34
46
  * @csspart indicators - The row of indicators that shows which slide is in view.
47
+ * @csspart live - The region that announces the slide a move lands on. Visually hidden in the styled tier.
35
48
  * @csspart next - The control that moves to the next slide.
36
49
  * @csspart next-mark - The glyph on the next control.
37
50
  * @csspart previous - The control that moves to the previous slide.
@@ -131,6 +144,8 @@ export declare class HelixHeadlessCarousel extends HelixElement {
131
144
  private indexState;
132
145
  /** How many panes were drawn at the last update, to scroll when the first are. */
133
146
  private scrolledFor;
147
+ /** What the live region says: the position of the slide the last move landed on. */
148
+ private said;
134
149
  /**
135
150
  * The carousel's name, read by screen readers.
136
151
  */
@@ -336,14 +351,24 @@ export declare class HelixHeadlessCarousel extends HelixElement {
336
351
  * **A fitted carousel's last position moves with the window**, which a
337
352
  * declared one's never does: eight slides at one across has eight places to
338
353
  * stand and four across has five, so a track widened while the reader sits on
339
- * the last of them is a track resting somewhere it can no longer be. Through
340
- * `goTo`, so the correction goes out as the same cancelable announcement
341
- * every other index change does and a consumer holding `index` hears it
342
- * rather than being overwritten.
354
+ * the last of them is a track resting somewhere it can no longer be. See
355
+ * `holdIndex` for why the correction is not a request.
343
356
  *
344
357
  * Only on a change, so the observer's own re-render cannot feed itself.
345
358
  */
346
359
  private readonly readFit;
360
+ /**
361
+ * Puts the index back on the last place the track can stand, where fewer
362
+ * places are left than it counted.
363
+ *
364
+ * **Written, with no request.** Nobody asked for this move: a slide was
365
+ * removed, the window widened, or `per-view` went up. It went out as a
366
+ * cancelable `helix-select`, which a consumer reading the event as a reader's
367
+ * request had no reason to expect, and refusing it left the index past the
368
+ * last slide, with no current indicator and no tab stop, and asked again on
369
+ * every update. An index that cannot be refused is not a request.
370
+ */
371
+ private holdIndex;
347
372
  /**
348
373
  * The count handed to the styles, and nothing at all where they work it out.
349
374
  *
@@ -413,6 +438,14 @@ export declare class HelixHeadlessCarousel extends HelixElement {
413
438
  * the right, the left arrow is the one that moves on.
414
439
  */
415
440
  private readonly handleIndicatorKeydown;
441
+ /**
442
+ * Puts a requested slide in view, and says so.
443
+ *
444
+ * `helix-activate` is the notification after `helix-select`, the one Tour
445
+ * and Tabs send once a different member is current. A clamp in `holdIndex`
446
+ * sends neither, being a correction rather than a move anybody asked for.
447
+ */
448
+ private applyIndex;
416
449
  /** Moves to a slide. It wraps past either end only when `loop` is set. */
417
450
  goTo(index: number): void;
418
451
  /**
@@ -663,6 +696,15 @@ export declare class HelixHeadlessCarousel extends HelixElement {
663
696
  * floor.
664
697
  */
665
698
  private runEnd;
699
+ /**
700
+ * Whether Previous or Next has nowhere to go, which is only at an end and
701
+ * without `loop`.
702
+ *
703
+ * Said with `aria-disabled` and not `disabled`, so a reader who pressed Next
704
+ * onto the last slide keeps focus on the control they are on. Not on the
705
+ * server, which knows no slides and so no ends.
706
+ */
707
+ private atEnd;
666
708
  protected render(): TemplateResult;
667
709
  }
668
710
  declare global {