@fusion.dev/helix-headless 0.146.0 → 0.147.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 (239) hide show
  1. package/custom-elements.json +5266 -785
  2. package/dist/accordion/item/accordion-item.d.ts +38 -19
  3. package/dist/accordion/item/accordion-item.js +31 -9
  4. package/dist/accordion/root/accordion-root.d.ts +8 -2
  5. package/dist/accordion/root/accordion-root.js +3 -3
  6. package/dist/announcement/root/announcement-root.d.ts +13 -4
  7. package/dist/announcement/root/announcement-root.js +34 -6
  8. package/dist/area-chart/root/area-chart-root.d.ts +18 -1
  9. package/dist/area-chart/root/area-chart-root.js +11 -3
  10. package/dist/avatar/root/avatar-root.d.ts +31 -1
  11. package/dist/avatar/root/avatar-root.js +11 -1
  12. package/dist/badge/root/badge-root.d.ts +57 -6
  13. package/dist/badge/root/badge-root.js +88 -5
  14. package/dist/bar-chart/root/bar-chart-root.js +11 -20
  15. package/dist/bar-chart/stack.d.ts +10 -0
  16. package/dist/bar-chart/stack.js +8 -0
  17. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
  18. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
  19. package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -2
  20. package/dist/button/root/button-root.d.ts +24 -38
  21. package/dist/button/root/button-root.js +6 -37
  22. package/dist/button/submitter.d.ts +27 -0
  23. package/dist/button/submitter.js +25 -0
  24. package/dist/card/root/card-root.d.ts +12 -1
  25. package/dist/card/root/card-root.js +11 -4
  26. package/dist/chat/root/chat-root.d.ts +15 -1
  27. package/dist/chat/root/chat-root.js +11 -2
  28. package/dist/checkbox/root/checkbox-root.js +5 -7
  29. package/dist/checkbox-group/root/checkbox-group-root.js +4 -3
  30. package/dist/checkbox-group/select-all.d.ts +0 -6
  31. package/dist/checkbox-group/select-all.js +0 -5
  32. package/dist/code-block/root/code-block-root.d.ts +35 -14
  33. package/dist/code-block/root/code-block-root.js +17 -3
  34. package/dist/color-input/root/color-input-root.d.ts +11 -0
  35. package/dist/color-input/root/color-input-root.js +12 -5
  36. package/dist/color-picker/channels.js +1 -2
  37. package/dist/color-picker/root/color-picker-root.d.ts +32 -24
  38. package/dist/color-picker/root/color-picker-root.js +101 -51
  39. package/dist/color-picker/wheel.d.ts +17 -0
  40. package/dist/color-picker/wheel.js +6 -0
  41. package/dist/combobox/root/combobox-root.d.ts +13 -0
  42. package/dist/combobox/root/combobox-root.js +14 -1
  43. package/dist/command/root/command-root.d.ts +3 -1
  44. package/dist/command/root/command-root.js +2 -19
  45. package/dist/copy-button/root/copy-button-root.d.ts +16 -1
  46. package/dist/copy-button/root/copy-button-root.js +7 -2
  47. package/dist/data-table/keys.d.ts +0 -18
  48. package/dist/data-table/keys.js +1 -11
  49. package/dist/data-table/root/data-table-root.js +13 -7
  50. package/dist/date-input/root/date-input-root.d.ts +8 -1
  51. package/dist/date-input/root/date-input-root.js +8 -5
  52. package/dist/date-picker/root/date-picker-root.d.ts +14 -9
  53. package/dist/date-picker/root/date-picker-root.js +21 -16
  54. package/dist/description-list/item/description-list-item.d.ts +18 -4
  55. package/dist/description-list/item/description-list-item.js +8 -4
  56. package/dist/donut-chart/root/donut-chart-root.js +13 -6
  57. package/dist/donut-chart/slice-label.d.ts +35 -0
  58. package/dist/donut-chart/slice-label.js +11 -0
  59. package/dist/drawer/root/drawer-root.d.ts +4 -2
  60. package/dist/drawer/root/drawer-root.js +15 -3
  61. package/dist/drilldown/item/drilldown-item.d.ts +21 -1
  62. package/dist/drilldown/item/drilldown-item.js +39 -4
  63. package/dist/drilldown/root/drilldown-root.js +3 -2
  64. package/dist/element-events.generated.js +4 -1
  65. package/dist/empty/root/empty-root.d.ts +31 -1
  66. package/dist/empty/root/empty-root.js +26 -5
  67. package/dist/file-input/root/file-input-root.d.ts +34 -6
  68. package/dist/file-input/root/file-input-root.js +54 -19
  69. package/dist/file-input/status.d.ts +24 -0
  70. package/dist/file-input/status.js +10 -0
  71. package/dist/filter-input/chip/filter-chip.d.ts +23 -0
  72. package/dist/filter-input/chip/filter-chip.js +11 -2
  73. package/dist/filter-input/root/filter-input-root.d.ts +8 -0
  74. package/dist/filter-input/root/filter-input-root.js +17 -27
  75. package/dist/format-date/options.d.ts +3 -4
  76. package/dist/format-date/options.js +2 -2
  77. package/dist/format-date/root/format-date-root.d.ts +18 -1
  78. package/dist/format-date/root/format-date-root.js +19 -23
  79. package/dist/heatmap/root/buckets.d.ts +21 -0
  80. package/dist/heatmap/root/buckets.js +34 -0
  81. package/dist/heatmap/root/heatmap-root.d.ts +64 -3
  82. package/dist/heatmap/root/heatmap-root.js +89 -19
  83. package/dist/icon/index.d.ts +1 -1
  84. package/dist/icon/index.js +1 -1
  85. package/dist/icon/registry.d.ts +26 -1
  86. package/dist/icon/registry.js +12 -1
  87. package/dist/icon/root/icon-root.d.ts +13 -0
  88. package/dist/icon/root/icon-root.js +23 -2
  89. package/dist/icon/root/index.d.ts +1 -1
  90. package/dist/icon/root/index.js +1 -1
  91. package/dist/image/root/image-root.d.ts +9 -0
  92. package/dist/image/root/image-root.js +6 -1
  93. package/dist/input/root/input-root.d.ts +23 -2
  94. package/dist/input/root/input-root.js +12 -8
  95. package/dist/kbd/keys.d.ts +29 -0
  96. package/dist/kbd/keys.js +52 -0
  97. package/dist/kbd/root/kbd-root.d.ts +20 -3
  98. package/dist/kbd/root/kbd-root.js +24 -50
  99. package/dist/legend/hidden-series.d.ts +10 -2
  100. package/dist/legend/hidden-series.js +5 -2
  101. package/dist/legend/root/legend-root.d.ts +25 -7
  102. package/dist/legend/root/legend-root.js +22 -10
  103. package/dist/lightbox/root/lightbox-root.d.ts +50 -5
  104. package/dist/lightbox/root/lightbox-root.js +76 -8
  105. package/dist/lightbox/zoom.d.ts +2 -0
  106. package/dist/lightbox/zoom.js +5 -3
  107. package/dist/line-chart/root/line-chart-root.d.ts +16 -0
  108. package/dist/line-chart/root/line-chart-root.js +10 -2
  109. package/dist/list/root/list-root.d.ts +10 -2
  110. package/dist/list/root/list-root.js +26 -5
  111. package/dist/list/selection.d.ts +17 -0
  112. package/dist/list/selection.js +16 -0
  113. package/dist/listbox/root/listbox-root.d.ts +9 -5
  114. package/dist/listbox/root/listbox-root.js +29 -37
  115. package/dist/megamenu/hand-over.d.ts +75 -0
  116. package/dist/megamenu/hand-over.js +67 -0
  117. package/dist/megamenu/root/megamenu-root.d.ts +38 -14
  118. package/dist/megamenu/root/megamenu-root.js +36 -50
  119. package/dist/menu/item/menu-item.js +4 -4
  120. package/dist/menu/root/menu-root.d.ts +3 -0
  121. package/dist/meter/root/meter-root.d.ts +42 -0
  122. package/dist/meter/root/meter-root.js +33 -7
  123. package/dist/notifications/root/notifications-root.d.ts +10 -1
  124. package/dist/notifications/root/notifications-root.js +11 -1
  125. package/dist/number-input/grain.d.ts +28 -0
  126. package/dist/number-input/grain.js +14 -0
  127. package/dist/number-input/root/number-input-root.d.ts +17 -1
  128. package/dist/number-input/root/number-input-root.js +29 -18
  129. package/dist/object-inspector/root/object-inspector-root.d.ts +13 -6
  130. package/dist/object-inspector/root/object-inspector-root.js +18 -17
  131. package/dist/option/index.d.ts +1 -0
  132. package/dist/option/index.js +1 -0
  133. package/dist/option/separator/option-separator.d.ts +30 -0
  134. package/dist/option/separator/option-separator.js +21 -0
  135. package/dist/outline/root/outline-root.d.ts +12 -0
  136. package/dist/outline/root/outline-root.js +5 -19
  137. package/dist/pagination/size/pagination-size.d.ts +5 -0
  138. package/dist/pagination/size/pagination-size.js +4 -2
  139. package/dist/pin-input/code.d.ts +28 -1
  140. package/dist/pin-input/code.js +12 -0
  141. package/dist/pin-input/root/pin-input-root.d.ts +98 -121
  142. package/dist/pin-input/root/pin-input-root.js +157 -148
  143. package/dist/popover/hide-outside.js +2 -9
  144. package/dist/popover/root/popover-root.d.ts +7 -1
  145. package/dist/popover/root/popover-root.js +9 -1
  146. package/dist/progress/root/progress-root.d.ts +27 -0
  147. package/dist/progress/root/progress-root.js +25 -7
  148. package/dist/qr-code/export.d.ts +19 -0
  149. package/dist/qr-code/export.js +14 -0
  150. package/dist/qr-code/name.d.ts +11 -0
  151. package/dist/qr-code/name.js +7 -0
  152. package/dist/qr-code/root/qr-code-root.d.ts +17 -6
  153. package/dist/qr-code/root/qr-code-root.js +10 -12
  154. package/dist/radio/group/radio-group.d.ts +15 -0
  155. package/dist/radio/root/radio-root.js +2 -2
  156. package/dist/rating/root/rating-root.d.ts +22 -9
  157. package/dist/rating/root/rating-root.js +15 -39
  158. package/dist/scatter-chart/root/scatter-chart-root.d.ts +30 -0
  159. package/dist/scatter-chart/root/scatter-chart-root.js +34 -7
  160. package/dist/scroll-area/scrollbar.d.ts +0 -8
  161. package/dist/scroll-area/scrollbar.js +1 -1
  162. package/dist/select/align.d.ts +47 -0
  163. package/dist/select/align.js +7 -0
  164. package/dist/select/root/select-root.d.ts +59 -3
  165. package/dist/select/root/select-root.js +72 -12
  166. package/dist/slider/root/slider-root.d.ts +18 -1
  167. package/dist/slider/root/slider-root.js +22 -0
  168. package/dist/sparkline/readings.d.ts +30 -12
  169. package/dist/sparkline/readings.js +32 -15
  170. package/dist/sparkline/root/sparkline-root.d.ts +46 -3
  171. package/dist/sparkline/root/sparkline-root.js +60 -21
  172. package/dist/speed-dial/item/speed-dial-item.d.ts +1 -1
  173. package/dist/speed-dial/item/speed-dial-item.js +2 -2
  174. package/dist/speed-dial/root/speed-dial-root.d.ts +6 -0
  175. package/dist/speed-dial/root/speed-dial-root.js +9 -1
  176. package/dist/splitter/root/splitter-root.d.ts +3 -0
  177. package/dist/splitter/root/splitter-root.js +2 -0
  178. package/dist/steps/root/steps-root.d.ts +8 -1
  179. package/dist/steps/root/steps-root.js +6 -1
  180. package/dist/steps/step/step.d.ts +1 -0
  181. package/dist/steps/step/step.js +1 -1
  182. package/dist/table/column/table-column.d.ts +6 -0
  183. package/dist/table/column/table-column.js +5 -1
  184. package/dist/table/root/table-root.js +13 -6
  185. package/dist/table/row/table-row.d.ts +24 -0
  186. package/dist/table/row/table-row.js +37 -1
  187. package/dist/tabs/root/tabs-root.d.ts +5 -3
  188. package/dist/tag/group/tag-group.d.ts +16 -4
  189. package/dist/tag/group/tag-group.js +19 -7
  190. package/dist/textarea/root/textarea-root.d.ts +14 -2
  191. package/dist/textarea/root/textarea-root.js +6 -7
  192. package/dist/time-input/root/time-input-root.d.ts +5 -1
  193. package/dist/time-input/root/time-input-root.js +10 -7
  194. package/dist/time-picker/root/time-picker-root.d.ts +11 -14
  195. package/dist/time-picker/root/time-picker-root.js +15 -23
  196. package/dist/toast/item/toast-item.d.ts +3 -3
  197. package/dist/toast/item/toast-item.js +0 -1
  198. package/dist/toast/root/toast-root.d.ts +28 -4
  199. package/dist/toast/root/toast-root.js +58 -12
  200. package/dist/toast/words.d.ts +12 -0
  201. package/dist/toast/words.js +25 -0
  202. package/dist/toggle/group/toggle-group.d.ts +29 -5
  203. package/dist/toggle/group/toggle-group.js +26 -41
  204. package/dist/toggle/root/toggle-root.js +2 -4
  205. package/dist/toolbar/root/toolbar-root.d.ts +21 -5
  206. package/dist/toolbar/root/toolbar-root.js +52 -8
  207. package/dist/tooltip/root/tooltip-root.d.ts +7 -1
  208. package/dist/tooltip/root/tooltip-root.js +10 -1
  209. package/dist/tour/root/tour-root.d.ts +15 -0
  210. package/dist/tour/root/tour-root.js +20 -1
  211. package/dist/tour/stop/tour-stop.d.ts +3 -0
  212. package/dist/tour/stop/tour-stop.js +3 -3
  213. package/dist/tree/root/tree-root.js +2 -2
  214. package/dist/trend/figure.d.ts +16 -0
  215. package/dist/trend/figure.js +8 -0
  216. package/dist/trend/root/trend-root.d.ts +41 -2
  217. package/dist/trend/root/trend-root.js +29 -3
  218. package/dist/video/root/extra-controls.d.ts +12 -0
  219. package/dist/video/root/extra-controls.js +6 -2
  220. package/dist/video/root/video-root.d.ts +5 -1
  221. package/dist/video-playlist/root/video-playlist-root.d.ts +11 -1
  222. package/dist/video-playlist/root/video-playlist-root.js +3 -0
  223. package/dist/virtual-list/fill.d.ts +11 -0
  224. package/dist/virtual-list/fill.js +9 -0
  225. package/dist/virtual-list/keys.d.ts +16 -7
  226. package/dist/virtual-list/keys.js +17 -6
  227. package/dist/virtual-list/plan.d.ts +17 -1
  228. package/dist/virtual-list/plan.js +13 -2
  229. package/dist/virtual-list/root/virtual-list-root.d.ts +25 -3
  230. package/dist/virtual-list/root/virtual-list-root.js +48 -24
  231. package/lint.json +1 -1
  232. package/package.json +5 -5
  233. package/types/jsx.d.ts +2979 -738
  234. package/types/svelte.d.ts +1 -0
  235. package/types/vue.d.ts +619 -202
  236. package/dist/color-picker/swatches.d.ts +0 -12
  237. package/dist/color-picker/swatches.js +0 -26
  238. package/dist/rating/steps.d.ts +0 -7
  239. package/dist/rating/steps.js +0 -9
@@ -4,20 +4,21 @@ 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 { commaList, customElement, deepActiveElement, deepContains, HelixBeforeChangeEvent, HelixElement, hostAria, KeyboardNavigationController, pressedValue, prunedValue, requestChange, rovingStop, slottedWords, typeaheadBy, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { commaList, customElement, deepActiveElement, deepContains, HelixBeforeChangeEvent, HelixElement, hostAria, KeyboardNavigationController, pressedValue, prunedValue, requestChange, rovingStop, slottedWords, typeaheadByWords, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { HelixHeadlessTag } from '../root/tag-root.js';
11
11
  let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
12
12
  constructor() {
13
13
  super(...arguments);
14
+ this.emptyLabel = 'No tags';
14
15
  this.label = '';
15
16
  this.value = '';
16
17
  this.keys = new KeyboardNavigationController(this, {
17
18
  items: () => this.reachable.map((tag) => this.navigable(tag)),
18
19
  origin: 'focus',
19
20
  selects: () => false,
20
- typeahead: typeaheadBy((item) => item.words),
21
+ typeahead: typeaheadByWords(),
21
22
  wrap: false,
22
23
  });
23
24
  this.handleKeydown = (event) => {
@@ -63,8 +64,8 @@ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
63
64
  return;
64
65
  }
65
66
  const left = this.tags.map((one) => this.valueFor(one));
66
- const pruned = prunedValue(this.value, this.valueFor(tag), left);
67
- if (pruned !== this.value) {
67
+ const pruned = prunedValue(this.written, this.valueFor(tag), left);
68
+ if (pruned !== this.written) {
68
69
  this.value = pruned;
69
70
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
70
71
  }
@@ -91,6 +92,14 @@ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
91
92
  }
92
93
  };
93
94
  }
95
+ get written() {
96
+ return typeof this.value === 'string'
97
+ ? this.value
98
+ : this.value
99
+ .map((one) => String(one).trim())
100
+ .filter((one) => one !== '')
101
+ .join(', ');
102
+ }
94
103
  get tags() {
95
104
  return [...(this.children ?? [])].filter((child) => child instanceof HelixHeadlessTag);
96
105
  }
@@ -112,7 +121,7 @@ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
112
121
  }
113
122
  sync() {
114
123
  const mode = this.selectionMode ?? 'none';
115
- const chosen = new Set(commaList(this.value));
124
+ const chosen = new Set(commaList(this.written));
116
125
  const tags = this.tags;
117
126
  const items = tags.map((tag) => ({
118
127
  disabled: tag.disabled,
@@ -144,7 +153,7 @@ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
144
153
  },
145
154
  event: (value) => new HelixBeforeChangeEvent({ value }),
146
155
  host: this,
147
- next: pressedValue(mode, this.value, this.valueFor(tag)),
156
+ next: pressedValue(mode, this.written, this.valueFor(tag)),
148
157
  });
149
158
  }
150
159
  connectedCallback() {
@@ -176,11 +185,14 @@ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
176
185
  }
177
186
  render() {
178
187
  const empty = this.empty
179
- ? html `<div part="empty" tabindex="-1"><slot name="empty"></slot></div>`
188
+ ? html `<div part="empty" tabindex="-1"><slot name="empty">${this.emptyLabel}</slot></div>`
180
189
  : nothing;
181
190
  return html `<slot @slotchange=${this.handleSlotchange}></slot>${empty}`;
182
191
  }
183
192
  };
193
+ __decorate([
194
+ property({ attribute: 'empty-label' })
195
+ ], HelixHeadlessTagGroup.prototype, "emptyLabel", void 0);
184
196
  __decorate([
185
197
  property()
186
198
  ], HelixHeadlessTagGroup.prototype, "label", void 0);
@@ -1,4 +1,4 @@
1
- import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, HelixFormElement, type OwnRule } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessTextarea_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
4
4
  /**
@@ -22,12 +22,22 @@ declare const HelixHeadlessTextarea_base: (new (...args: any[]) => import("@fusi
22
22
  * every change once the browser finds nothing wrong, as React Aria's
23
23
  * TextField `validate` does.
24
24
  *
25
+ * **Keyboard.** The field's own keys are the platform's, and Enter starts a
26
+ * new line. The clear button under `clearable` is a tab stop of its own after
27
+ * the field.
28
+ *
29
+ * The inner textarea is named by `label`, or by a host `aria-label`,
30
+ * `aria-labelledby` or `<label for>`, and is described by the hint and the
31
+ * message, with `aria-invalid` while a message shows. The clear button is
32
+ * named `clear-label`.
33
+ *
25
34
  * @since 0.1.0
26
35
  * @status stable
27
36
  * @category forms
28
37
  * @aliases Multiline, TextArea
29
38
  * @documentation https://fusion.dev/helix/components/textarea
30
39
  *
40
+ * @slot clear-icon - Replaces the cross on the clear button, under `clearable`.
31
41
  * @slot end - After the text, for an icon or an action beside it.
32
42
  * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
33
43
  * @slot hint - Help under the control, for content richer than the `hint` text.
@@ -238,12 +248,14 @@ export declare class HelixHeadlessTextarea extends HelixHeadlessTextarea_base {
238
248
  * nothing wrong. Return a message, or a list of them, to mark the field
239
249
  * invalid, and `true`, `null`, or nothing to accept the value.
240
250
  */
241
- validate?: (value: string) => string | string[] | true | null | undefined;
251
+ validate?: OwnRule;
242
252
  /**
243
253
  * How the browser wraps the text, and whether the breaks are submitted with
244
254
  * it.
245
255
  */
246
256
  wrap: 'hard' | 'off' | 'soft';
257
+ /** The cross on the clear button, behind a seam a tier can move. */
258
+ protected renderClearIcon(): TemplateResult;
247
259
  protected render(): TemplateResult;
248
260
  }
249
261
  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, drawIcon, HelixClearEvent, HelixFormElement, holdCaret, isRtl, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, applyOwnRule, customElement, drawIcon, HelixClearEvent, HelixFormElement, holdCaret, isRtl, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
8
8
  import { x } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -126,11 +126,7 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
126
126
  return;
127
127
  }
128
128
  this.copyValidity(control);
129
- const own = control.validity.valid ? this.validate?.(this.value) : undefined;
130
- const message = Array.isArray(own) ? own.join(' ') : typeof own === 'string' ? own : '';
131
- if (message !== '') {
132
- this.internals.setValidity({ customError: true }, message, control);
133
- }
129
+ applyOwnRule(this.internals, control, this.validate, this.value);
134
130
  this.refreshFeedback();
135
131
  }
136
132
  connectedCallback() {
@@ -175,6 +171,9 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
175
171
  this.sync();
176
172
  this.grow();
177
173
  }
174
+ renderClearIcon() {
175
+ return html `<slot name="clear-icon">${drawIcon(x)}</slot>`;
176
+ }
178
177
  render() {
179
178
  return html `${this.renderLabel()}
180
179
  <div part="field">
@@ -207,7 +206,7 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
207
206
  aria-label=${this.clearLabel}
208
207
  @click=${this.handleClear}
209
208
  >
210
- ${drawIcon(x)}
209
+ ${this.renderClearIcon()}
211
210
  </button>`
212
211
  : nothing}
213
212
  </div>
@@ -74,6 +74,7 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
74
74
  * @csspart picker-column-search - The region that holds the filter field.
75
75
  * @csspart picker-column-search-field - The filter field.
76
76
  * @csspart picker-columns - The row of columns, in `wheels`.
77
+ * @csspart picker-feedback - The picker's own message, under the times, while the picker's `feedback` is set.
77
78
  * @csspart picker-list - The listbox holding the times, in `list`.
78
79
  * @csspart picker-list-empty - The text shown when the filter hides every option.
79
80
  * @csspart picker-list-error - The list's `error` part, which the list never sets: its times do not load.
@@ -142,9 +143,12 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
142
143
  /**
143
144
  * Language tag the times are written in.
144
145
  *
145
- * Absent uses the runtime's own.
146
+ * Absent is the page's: the `lang` of the nearest element with one, as
147
+ * Shoelace and Web Awesome read it, then the runtime's own.
146
148
  */
147
149
  locale: string;
150
+ /** The locale the words are written in: `locale`, or the page's `lang`. */
151
+ private get language();
148
152
  /**
149
153
  * Latest time that can be chosen, as `HH:mm`.
150
154
  */
@@ -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, valueAsTime as asTime, clockLocale, customElement, fillTemplate, timeAsValue as fromTime, HelixFormElement, isClockValue, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinSegmentedField, MixinTokens, timeFault, writeClock, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, valueAsTime as asTime, clockLocale, customElement, fillTemplate, timeAsValue as fromTime, HelixFormElement, isClockValue, localeOf, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinSegmentedField, MixinTokens, timeFault, writeClock, } from '@fusion.dev/helix-core';
8
8
  import { clock } from '@fusion.dev/helix-icons';
9
9
  import { nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -88,6 +88,9 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
88
88
  }
89
89
  };
90
90
  }
91
+ get language() {
92
+ return localeOf(this, this.locale);
93
+ }
91
94
  get held() {
92
95
  return this.value
93
96
  .replace(/\s+[–-]\s+/g, ',')
@@ -102,7 +105,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
102
105
  return 'time';
103
106
  }
104
107
  get segmentLocale() {
105
- return this.locale;
108
+ return this.language;
106
109
  }
107
110
  get segmentOptions() {
108
111
  return { hourCycle: this.hourCycle, seconds: this.seconds };
@@ -113,7 +116,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
113
116
  written(at) {
114
117
  return this.timeStyle === 'iso' || !this.isTime(at)
115
118
  ? at
116
- : writeClock(at, clockLocale(this.locale, this.hourCycle), this.seconds);
119
+ : writeClock(at, clockLocale(this.language, this.hourCycle), this.seconds);
117
120
  }
118
121
  get display() {
119
122
  if (this.mode === 'multiple') {
@@ -155,7 +158,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
155
158
  return [
156
159
  'rangeUnderflow',
157
160
  fillTemplate(this.rangeUnderflowMessage || 'Choose a time at or after {min}.', {
158
- min: writeClock(this.min, clockLocale(this.locale, this.hourCycle), this.seconds),
161
+ min: writeClock(this.min, clockLocale(this.language, this.hourCycle), this.seconds),
159
162
  }),
160
163
  ];
161
164
  }
@@ -163,7 +166,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
163
166
  return [
164
167
  'rangeOverflow',
165
168
  fillTemplate(this.rangeOverflowMessage || 'Choose a time at or before {max}.', {
166
- max: writeClock(this.max, clockLocale(this.locale, this.hourCycle), this.seconds),
169
+ max: writeClock(this.max, clockLocale(this.language, this.hourCycle), this.seconds),
167
170
  }),
168
171
  ];
169
172
  }
@@ -189,7 +192,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
189
192
  column-filter-mark: picker-column-filter-mark, column-hint: picker-column-hint,
190
193
  column-items: picker-column-items, column-label: picker-column-label,
191
194
  column-live: picker-column-live, column-loading: picker-column-loading, column-search: picker-column-search,
192
- column-search-field: picker-column-search-field, columns: picker-columns, list: picker-list,
195
+ column-search-field: picker-column-search-field, columns: picker-columns, feedback: picker-feedback, list: picker-list,
193
196
  list-empty: picker-list-empty, list-error: picker-list-error, list-feedback: picker-list-feedback,
194
197
  list-filter-icon: picker-list-filter-icon, list-filter-mark: picker-list-filter-mark,
195
198
  list-hint: picker-list-hint, list-items: picker-list-items, list-label: picker-list-label,
@@ -206,7 +209,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
206
209
  manual
207
210
  label=${this.label || 'Time'}
208
211
  hour-cycle=${this.hourCycle ?? nothing}
209
- locale=${this.locale || nothing}
212
+ locale=${this.language || nothing}
210
213
  max=${this.max}
211
214
  min=${this.min}
212
215
  ?seconds=${this.seconds}
@@ -2,7 +2,7 @@ import { HelixFormElement, type HourCycle } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import '../../listbox/index.js';
4
4
  import '../../option/index.js';
5
- declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & typeof HelixFormElement;
5
+ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinPickerFeedbackInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & typeof HelixFormElement;
6
6
  /**
7
7
  * @summary A control for choosing a time from a list or from wheels.
8
8
  *
@@ -59,6 +59,7 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
59
59
  * @csspart column-search - The region that holds the filter field.
60
60
  * @csspart column-search-field - The filter field.
61
61
  * @csspart columns - The row of columns, in `wheels`.
62
+ * @csspart feedback - The message under the times, while `feedback` is set.
62
63
  * @csspart list - The listbox holding the times, in `list`.
63
64
  * @csspart list-empty - The text shown when the filter hides every option.
64
65
  * @csspart list-error - The list's `error` part, which Time Picker never sets: its times do not load.
@@ -80,6 +81,8 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
80
81
  * @csspart option-item-selected - The row of a chosen time: the one time, or either end of a range.
81
82
  * @csspart option-label - The time's label.
82
83
  * @csspart option-text - The label and the caption, as one column.
84
+ *
85
+ * @cssstate invalid - While `invalid` is set or `feedback` says what is wrong.
83
86
  */
84
87
  export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_base {
85
88
  /**
@@ -119,16 +122,6 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
119
122
  * English, "Stunde" in German.
120
123
  */
121
124
  hourLabel?: string;
122
- /**
123
- * Whether the current selection fails validation.
124
- *
125
- * A flag rather than a message, the same split Date Picker draws. A flat
126
- * picker has no room of its own for a sentence: the field that wraps one owns
127
- * the label, the hint and the feedback, and a second message inside the panel
128
- * would be the same error said twice. What is left for the picker is the one
129
- * thing the field cannot draw from outside, the mark on the answer itself.
130
- */
131
- invalid: boolean;
132
125
  /**
133
126
  * Accessible name for the list, which has no visible one of its own.
134
127
  *
@@ -136,11 +129,14 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
136
129
  */
137
130
  label: string;
138
131
  /**
139
- * Language tag the times are written in.
132
+ * Language tag the times and the wheels' names are written in.
140
133
  *
141
- * Absent uses the runtime's own.
134
+ * Absent is the page's: the `lang` of the nearest element with one, as
135
+ * Shoelace and Web Awesome read it, then the runtime's own.
142
136
  */
143
137
  locale: string;
138
+ /** The locale the words are written in: `locale`, or the page's `lang`. */
139
+ private get language();
144
140
  /**
145
141
  * Stops the arrow keys in the list from choosing each time they move to.
146
142
  * Enter, Space or a click chooses.
@@ -460,7 +456,8 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
460
456
  private listRevealed;
461
457
  /**
462
458
  * The list's name: the host's `aria-labelledby` read out, then its
463
- * `aria-label`, then `label`.
459
+ * `aria-label`, then `label`, through core's `hostWords`, which Select reads
460
+ * its list's name through too.
464
461
  *
465
462
  * Read out as words, because the list is inside two shadow roots and an id on
466
463
  * the page reaches neither. Measured before this: `<helix-time-picker
@@ -4,18 +4,17 @@ 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 { clockLocale, commaList, customElement, dayPeriod, elementById, fillTemplate, HelixFormElement, inlineStep, isTwelveHour, MixinControllerValue, nearestTime, offeredTimes, reportValues, secondsAsValue, timeBarred, timeFault, valueAsSeconds, wheelParts, wholeHour, writeClock, } from '@fusion.dev/helix-core';
7
+ import { clockLocale, commaList, customElement, dayPeriod, fillTemplate, HelixFormElement, hostWords, inlineStep, isTwelveHour, localeOf, MixinControllerValue, MixinPickerFeedback, nearestTime, offeredTimes, reportValues, secondsAsValue, timeBarred, timeFault, valueAsSeconds, wheelParts, wholeHour, writeClock, } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { html } from 'lit/static-html.js';
11
11
  import { wheelName } from '../wheel-name.js';
12
12
  import '../../listbox/index.js';
13
13
  import '../../option/index.js';
14
- let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControllerValue(HelixFormElement) {
14
+ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerFeedback(MixinControllerValue(HelixFormElement)) {
15
15
  constructor() {
16
16
  super(...arguments);
17
17
  this.disableTimes = '';
18
- this.invalid = false;
19
18
  this.label = 'Time';
20
19
  this.locale = '';
21
20
  this.manual = false;
@@ -94,11 +93,14 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
94
93
  next.focus();
95
94
  };
96
95
  }
96
+ get language() {
97
+ return localeOf(this, this.locale);
98
+ }
97
99
  get times() {
98
100
  return offeredTimes(this.min, this.max, this.step, this.seconds);
99
101
  }
100
102
  get clock() {
101
- return clockLocale(this.locale, this.hourCycle);
103
+ return clockLocale(this.language, this.hourCycle);
102
104
  }
103
105
  valueFor(at) {
104
106
  return secondsAsValue(at, this.seconds);
@@ -239,13 +241,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
239
241
  this.reveal();
240
242
  }
241
243
  get listName() {
242
- const named = (this.getAttribute('aria-labelledby') ?? '')
243
- .split(/\s+/)
244
- .filter(Boolean)
245
- .map((id) => elementById(this, id)?.textContent?.trim() ?? '')
246
- .filter(Boolean)
247
- .join(' ');
248
- return named || this.getAttribute('aria-label') || this.label;
244
+ return hostWords(this, this.label);
249
245
  }
250
246
  connectedCallback() {
251
247
  super.connectedCallback();
@@ -259,7 +255,6 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
259
255
  }
260
256
  willUpdate(changed) {
261
257
  super.willUpdate(changed);
262
- this.internals.ariaInvalid = this.invalid ? 'true' : null;
263
258
  this.report();
264
259
  }
265
260
  updated(changed) {
@@ -282,7 +277,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
282
277
  return html `<${this.tag('listbox')}
283
278
  part="column"
284
279
  data-column=${part}
285
- aria-invalid=${this.invalid ? 'true' : nothing}
280
+ aria-invalid=${this.marked ? 'true' : nothing}
286
281
  exportparts="empty: column-empty, error: column-error, feedback: column-feedback, filter-icon: column-filter-icon,
287
282
  filter-mark: column-filter-mark, hint: column-hint, items: column-items, label: column-label,
288
283
  live: column-live, loading: column-loading, search: column-search, search-field: column-search-field"
@@ -320,20 +315,20 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
320
315
  data-unset=${this.value === '' ? '' : nothing}
321
316
  @keydown=${this.handleColumnsKeydown}
322
317
  >
323
- ${this.renderColumn('hour', this.hourLabel ?? wheelName('hour', this.locale), hours.map(String), (one) => (twelve ? one : one.padStart(2, '0')), String(shown), (one) => this.wholeHourBarred(Number(one), twelve ? meridiem : undefined))}
324
- ${this.renderColumn('minute', this.minuteLabel ?? wheelName('minute', this.locale), this.minutes.map(String), (one) => one.padStart(2, '0'), String(minute), (one) => this.barredAt(hour * 3600 + Number(one) * 60))}
318
+ ${this.renderColumn('hour', this.hourLabel ?? wheelName('hour', this.language), hours.map(String), (one) => (twelve ? one : one.padStart(2, '0')), String(shown), (one) => this.wholeHourBarred(Number(one), twelve ? meridiem : undefined))}
319
+ ${this.renderColumn('minute', this.minuteLabel ?? wheelName('minute', this.language), this.minutes.map(String), (one) => one.padStart(2, '0'), String(minute), (one) => this.barredAt(hour * 3600 + Number(one) * 60))}
325
320
  ${this.seconds
326
- ? this.renderColumn('second', this.secondLabel ?? wheelName('second', this.locale), this.secondsShown.map(String), (one) => one.padStart(2, '0'), String(second), (one) => this.barredAt(hour * 3600 + minute * 60 + Number(one)))
321
+ ? this.renderColumn('second', this.secondLabel ?? wheelName('second', this.language), this.secondsShown.map(String), (one) => one.padStart(2, '0'), String(second), (one) => this.barredAt(hour * 3600 + minute * 60 + Number(one)))
327
322
  : nothing}
328
323
  ${twelve
329
- ? this.renderColumn('meridiem', this.meridiemLabel ?? wheelName('dayPeriod', this.locale), ['AM', 'PM'], (one) => dayPeriod(one, this.clock), meridiem, (one) => this.halfBarred(one))
324
+ ? this.renderColumn('meridiem', this.meridiemLabel ?? wheelName('dayPeriod', this.language), ['AM', 'PM'], (one) => dayPeriod(one, this.clock), meridiem, (one) => this.halfBarred(one))
330
325
  : nothing}
331
326
  </div>`;
332
327
  }
333
328
  renderList() {
334
329
  return html `<${this.tag('listbox')}
335
330
  part="list"
336
- aria-invalid=${this.invalid ? 'true' : nothing}
331
+ aria-invalid=${this.marked ? 'true' : nothing}
337
332
  exportparts="empty: list-empty, error: list-error, feedback: list-feedback, filter-icon: list-filter-icon,
338
333
  filter-mark: list-filter-mark, hint: list-hint, items: list-items, label: list-label,
339
334
  live: list-live, loading: list-loading, search: list-search, search-field: list-search-field"
@@ -365,9 +360,9 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
365
360
  }
366
361
  render() {
367
362
  if (this.variant === 'wheels' && this.mode === undefined) {
368
- return this.renderSpinner();
363
+ return html `${this.renderSpinner()}${this.renderPickerFeedback()}`;
369
364
  }
370
- return html `${this.renderList()}`;
365
+ return html `${this.renderList()}${this.renderPickerFeedback()}`;
371
366
  }
372
367
  get valueAsDate() {
373
368
  const at = valueAsSeconds(this.value);
@@ -398,9 +393,6 @@ __decorate([
398
393
  __decorate([
399
394
  property({ attribute: 'hour-label' })
400
395
  ], HelixHeadlessTimePicker.prototype, "hourLabel", void 0);
401
- __decorate([
402
- property({ reflect: true, type: Boolean })
403
- ], HelixHeadlessTimePicker.prototype, "invalid", void 0);
404
396
  __decorate([
405
397
  property()
406
398
  ], HelixHeadlessTimePicker.prototype, "label", void 0);
@@ -15,9 +15,9 @@ declare const HelixHeadlessToastItem_base: (new (...args: any[]) => import("@fus
15
15
  * **Each message is an `alertdialog` named by its words**, which is how a reader
16
16
  * who moves into the stack hears which message they are on. Give it a
17
17
  * `heading` and a `description`, and the heading names it and the description
18
- * describes it, for a message with a title and a line of detail. A `danger` message
19
- * is its own assertive live region, so it is announced at once; every other one
20
- * is announced politely by the region.
18
+ * describes it, for a message with a title and a line of detail. The region
19
+ * says each message once as it arrives, a `danger` one assertively, so a
20
+ * message is never a live region of its own.
21
21
  *
22
22
  * A touch or a pen swipes a message toward the end of the line, and past
23
23
  * halfway, or quickly, dismisses it through the same `helix-dismiss` as its
@@ -104,7 +104,6 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
104
104
  this.toggleAttribute('hidden', !this.open);
105
105
  hostAria(this.internals, { role: 'alertdialog' });
106
106
  this.internals.ariaModal = 'false';
107
- this.internals.ariaLive = this.tone === 'danger' ? 'assertive' : null;
108
107
  }
109
108
  updated(changed) {
110
109
  super.updated(changed);
@@ -9,10 +9,15 @@ import { type PropertyValues, type TemplateResult } from 'lit';
9
9
  * announce a region that arrives already holding its message. `Radio.Group` is
10
10
  * part of its family for the same reason.
11
11
  *
12
- * **The region is a landmark named by `label`, and a polite live region.** A
13
- * `danger` message is announced assertively, and every other one politely.
14
- * Each message is an `alertdialog` named by its words, so a reader who moves
15
- * into the stack hears which message they are on.
12
+ * **The region is a landmark named by `label`, and it says each message once
13
+ * as it arrives**: a `danger` message assertively, and every other one
14
+ * politely. It says the word for the tone, the heading, the description and
15
+ * the text, and not the actions, through two live regions of its own, the
16
+ * `live` parts, which it empties again a moment later. The stack itself is not
17
+ * a live region, so a message is never said twice, and changing the words of a
18
+ * message already showing says nothing. Each message is an `alertdialog` named
19
+ * by its words, so a reader who moves into the stack hears which message they
20
+ * are on.
16
21
  *
17
22
  * **`hotkey` takes focus to the stack and back**, F8 unless you set it, and
18
23
  * `label` says which key: `{hotkey}` in it is filled in, so the default name
@@ -54,6 +59,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
54
59
  *
55
60
  * @event {HelixDismissEvent} helix-dismiss - A message is being dismissed, by its control or by its timer. The message sends it, and you can listen for it on the region. Cancelable: canceling it keeps the message.
56
61
  *
62
+ * @csspart live - The two regions that say each message as it arrives, a polite `status` and an assertive `alert`, inside the stack. Empty at rest, and hide them with the standard clip, never `display: none`.
57
63
  * @csspart region - The stack the messages are in. It is in the top layer while a message shows, and takes focus from `hotkey` where no message holds a control.
58
64
  */
59
65
  export declare class HelixHeadlessToast extends HelixElement {
@@ -95,6 +101,24 @@ export declare class HelixHeadlessToast extends HelixElement {
95
101
  */
96
102
  placement?: 'bottom-center' | 'bottom-end' | 'bottom-start' | 'top-center' | 'top-end' | 'top-start';
97
103
  protected willUpdate(changed: PropertyValues): void;
104
+ /** What the polite region is saying. */
105
+ private said;
106
+ /** What the assertive region is saying. */
107
+ private urgent;
108
+ private readonly hush;
109
+ /**
110
+ * Says messages that have just arrived, each once, `danger` ones assertively.
111
+ *
112
+ * Emptied first and filled a frame later, so a message with the same words
113
+ * as the one before is still a change, and so a region the stack has just
114
+ * shown is in the accessibility tree before its words land.
115
+ */
116
+ private announce;
117
+ /**
118
+ * Says the messages that have just arrived: through the regions, or through
119
+ * `ariaNotify` where a modal dialog has made them inert.
120
+ */
121
+ private tell;
98
122
  /** The element focus came from when it entered the stack. */
99
123
  private focusOrigin;
100
124
  private readonly scope;