@fusion.dev/helix-headless 0.103.2 → 0.104.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 (107) hide show
  1. package/custom-elements.json +9259 -712
  2. package/dist/announcement/root/announcement-root.d.ts +9 -2
  3. package/dist/announcement/root/announcement-root.js +9 -6
  4. package/dist/badge/root/badge-root.js +2 -3
  5. package/dist/canvas/edge/canvas-edge.d.ts +112 -0
  6. package/dist/canvas/edge/canvas-edge.js +66 -0
  7. package/dist/canvas/index.d.ts +4 -0
  8. package/dist/canvas/index.js +3 -0
  9. package/dist/canvas/node/canvas-node.d.ts +211 -0
  10. package/dist/canvas/node/canvas-node.js +148 -0
  11. package/dist/canvas/root/canvas-document.d.ts +215 -0
  12. package/dist/canvas/root/canvas-document.js +284 -0
  13. package/dist/canvas/root/canvas-root.d.ts +912 -0
  14. package/dist/canvas/root/canvas-root.js +1814 -0
  15. package/dist/carousel/root/carousel-root.d.ts +53 -16
  16. package/dist/carousel/root/carousel-root.js +46 -11
  17. package/dist/chat/root/chat-root.d.ts +4 -0
  18. package/dist/chat/root/chat-root.js +11 -7
  19. package/dist/checkbox/root/checkbox-root.js +1 -0
  20. package/dist/checkbox-group/root/checkbox-group-root.d.ts +10 -0
  21. package/dist/checkbox-group/root/checkbox-group-root.js +5 -0
  22. package/dist/color-input/root/color-input-root.js +21 -5
  23. package/dist/color-picker/root/color-picker-root.d.ts +55 -0
  24. package/dist/color-picker/root/color-picker-root.js +61 -12
  25. package/dist/combobox/root/combobox-root.d.ts +21 -2
  26. package/dist/combobox/root/combobox-root.js +23 -9
  27. package/dist/command/root/command-root.d.ts +1 -0
  28. package/dist/command/root/command-root.js +1 -1
  29. package/dist/data-table/root/data-table-root.d.ts +43 -42
  30. package/dist/data-table/root/data-table-root.js +35 -34
  31. package/dist/date-input/root/date-input-root.d.ts +27 -0
  32. package/dist/date-input/root/date-input-root.js +38 -9
  33. package/dist/date-picker/root/date-picker-root.d.ts +28 -16
  34. package/dist/date-picker/root/date-picker-root.js +17 -15
  35. package/dist/drilldown/root/drilldown-root.d.ts +1 -0
  36. package/dist/drilldown/root/drilldown-root.js +5 -2
  37. package/dist/element-events.generated.js +15 -0
  38. package/dist/empty/root/empty-root.d.ts +12 -7
  39. package/dist/empty/root/empty-root.js +13 -10
  40. package/dist/file-input/root/file-input-root.d.ts +5 -1
  41. package/dist/file-input/root/file-input-root.js +6 -4
  42. package/dist/filter-input/menu/filter-menu.d.ts +1 -0
  43. package/dist/filter-input/menu/filter-menu.js +1 -1
  44. package/dist/filter-input/root/filter-input-root.js +5 -0
  45. package/dist/index.d.ts +1 -0
  46. package/dist/index.js +1 -0
  47. package/dist/input/root/input-root.js +1 -1
  48. package/dist/lightbox/root/lightbox-root.d.ts +9 -1
  49. package/dist/lightbox/root/lightbox-root.js +17 -7
  50. package/dist/listbox/root/listbox-root.d.ts +16 -14
  51. package/dist/listbox/root/listbox-root.js +24 -15
  52. package/dist/map/root/map-root.d.ts +19 -127
  53. package/dist/map/root/map-root.js +10 -138
  54. package/dist/menu/root/menu-root.d.ts +1 -0
  55. package/dist/menu/root/menu-root.js +1 -1
  56. package/dist/notifications/group/notification-group.js +5 -4
  57. package/dist/notifications/notification/notification.d.ts +10 -10
  58. package/dist/notifications/notification/notification.js +3 -3
  59. package/dist/notifications/root/notifications-root.d.ts +1 -0
  60. package/dist/notifications/root/notifications-root.js +1 -0
  61. package/dist/number-input/root/number-input-root.d.ts +17 -0
  62. package/dist/number-input/root/number-input-root.js +22 -6
  63. package/dist/object-inspector/root/object-inspector-root.d.ts +10 -0
  64. package/dist/object-inspector/root/object-inspector-root.js +10 -2
  65. package/dist/outline/root/outline-root.d.ts +15 -0
  66. package/dist/outline/root/outline-root.js +12 -7
  67. package/dist/pagination/root/pagination-root.d.ts +18 -18
  68. package/dist/pagination/root/pagination-root.js +5 -5
  69. package/dist/pagination/size/pagination-size.d.ts +10 -9
  70. package/dist/pagination/size/pagination-size.js +4 -4
  71. package/dist/pagination/summary/pagination-summary.js +6 -5
  72. package/dist/pin-input/root/pin-input-root.d.ts +5 -0
  73. package/dist/pin-input/root/pin-input-root.js +10 -6
  74. package/dist/rating/root/rating-root.js +3 -2
  75. package/dist/select/root/select-root.d.ts +1 -0
  76. package/dist/select/root/select-root.js +8 -3
  77. package/dist/slider/root/slider-root.d.ts +12 -0
  78. package/dist/slider/root/slider-root.js +13 -1
  79. package/dist/splitter/root/splitter-root.d.ts +44 -35
  80. package/dist/splitter/root/splitter-root.js +27 -22
  81. package/dist/switch/root/switch-root.js +1 -0
  82. package/dist/table/column/table-column.d.ts +17 -0
  83. package/dist/table/column/table-column.js +16 -4
  84. package/dist/table/root/table-root.d.ts +1 -0
  85. package/dist/table/root/table-root.js +1 -1
  86. package/dist/textarea/root/textarea-root.js +1 -1
  87. package/dist/time-input/root/time-input-root.d.ts +29 -0
  88. package/dist/time-input/root/time-input-root.js +31 -10
  89. package/dist/time-picker/root/time-picker-root.d.ts +14 -0
  90. package/dist/time-picker/root/time-picker-root.js +16 -14
  91. package/dist/toast/item/toast-item.d.ts +12 -11
  92. package/dist/toast/item/toast-item.js +11 -5
  93. package/dist/toolbar/root/toolbar-root.js +2 -16
  94. package/dist/tooltip/root/tooltip-root.d.ts +1 -0
  95. package/dist/tooltip/root/tooltip-root.js +6 -0
  96. package/dist/tour/root/tour-root.d.ts +10 -10
  97. package/dist/tour/root/tour-root.js +5 -5
  98. package/dist/tree/root/tree-root.d.ts +1 -0
  99. package/dist/tree/root/tree-root.js +1 -1
  100. package/dist/video/root/video-root.d.ts +84 -0
  101. package/dist/video/root/video-root.js +116 -41
  102. package/dist/video-playlist/menu/video-playlist-menu.d.ts +1 -0
  103. package/dist/video-playlist/menu/video-playlist-menu.js +4 -3
  104. package/package.json +5 -5
  105. package/types/jsx.d.ts +5753 -1076
  106. package/types/svelte.d.ts +3 -0
  107. package/types/vue.d.ts +1668 -282
@@ -55,28 +55,6 @@ import { type PropertyValues, type TemplateResult } from 'lit';
55
55
  * @cssproperty --splitter-position - Where the divider sits, as a percentage of the box.
56
56
  */
57
57
  export declare class HelixHeadlessSplitter extends HelixElement {
58
- /**
59
- * How much of a shut pane is still shown, as a percentage.
60
- *
61
- * Zero by default, which is a pane fully gone. A tab strip or a title bar
62
- * that should survive its own collapse says how much of itself to keep, and
63
- * only whoever put it there knows that, which is the same reason `min` is a
64
- * consumer's to set.
65
- */
66
- collapsedSize: number;
67
- /**
68
- * Where the divider sits, as a percentage of the whole.
69
- *
70
- * Reading gives where it is; writing declares it the consumer's, and
71
- * `default-position` seeds one this element owns. The same accessor pair
72
- * `Pagination.page` and the calendar's `month` carry.
73
- */
74
- get position(): number;
75
- set position(next: number);
76
- /**
77
- * Accessible name for the handle where two dividers cross.
78
- */
79
- cornerLabel: string;
80
58
  /**
81
59
  * Which pane is shut, if either.
82
60
  *
@@ -92,6 +70,28 @@ export declare class HelixHeadlessSplitter extends HelixElement {
92
70
  */
93
71
  get collapsed(): 'end' | 'start' | undefined;
94
72
  set collapsed(next: 'end' | 'start' | undefined);
73
+ /**
74
+ * What the divider says while a pane is shut, in place of a number.
75
+ *
76
+ * **A shut pane is off the scale the divider reports**, which is `min` to
77
+ * `max`, the sliver a drag keeps. The divider said a value outside its own
78
+ * range, 0 against a minimum of 20, which reads as broken rather than as
79
+ * shut. While shut it reports the whole 0 to 100 it sits on and says this.
80
+ */
81
+ collapsedLabel: string;
82
+ /**
83
+ * How much of a shut pane is still shown, as a percentage.
84
+ *
85
+ * Zero by default, which is a pane fully gone. A tab strip or a title bar
86
+ * that should survive its own collapse says how much of itself to keep, and
87
+ * only whoever put it there knows that, which is the same reason `min` is a
88
+ * consumer's to set.
89
+ */
90
+ collapsedSize: number;
91
+ /**
92
+ * Accessible name for the handle where two dividers cross.
93
+ */
94
+ cornerLabel: string;
95
95
  /**
96
96
  * Which pane starts shut, where nothing declared it.
97
97
  */
@@ -108,19 +108,6 @@ export declare class HelixHeadlessSplitter extends HelixElement {
108
108
  * Nearest it may come to the end, on the same terms as `min`.
109
109
  */
110
110
  max: number | string;
111
- /**
112
- * Either kind of bound as a percentage of the box.
113
- *
114
- * Measured rather than cached: a length is only meaningful against the size
115
- * the splitter is right now, and the drag that asks is already reading layout.
116
- * Falls back where there is nothing to measure, which is the server and an
117
- * element that is not displayed, so `aria-valuemin` is a number either way.
118
- */
119
- private toPercent;
120
- /** `min` as a percentage, whichever way it was written. */
121
- private get minPercent();
122
- /** `max` as a percentage, whichever way it was written. */
123
- private get maxPercent();
124
111
  /**
125
112
  * Nearest the divider may come to the start.
126
113
  *
@@ -141,6 +128,19 @@ export declare class HelixHeadlessSplitter extends HelixElement {
141
128
  * passes through.
142
129
  */
143
130
  min: number | string;
131
+ /**
132
+ * Either kind of bound as a percentage of the box.
133
+ *
134
+ * Measured rather than cached: a length is only meaningful against the size
135
+ * the splitter is right now, and the drag that asks is already reading layout.
136
+ * Falls back where there is nothing to measure, which is the server and an
137
+ * element that is not displayed, so `aria-valuemin` is a number either way.
138
+ */
139
+ private toPercent;
140
+ /** `min` as a percentage, whichever way it was written. */
141
+ private get minPercent();
142
+ /** `max` as a percentage, whichever way it was written. */
143
+ private get maxPercent();
144
144
  /**
145
145
  * Which way the panes are laid out.
146
146
  *
@@ -168,6 +168,15 @@ export declare class HelixHeadlessSplitter extends HelixElement {
168
168
  * has an honest answer.
169
169
  */
170
170
  orientation?: 'auto' | 'horizontal' | 'vertical';
171
+ /**
172
+ * Where the divider sits, as a percentage of the whole.
173
+ *
174
+ * Reading gives where it is; writing declares it the consumer's, and
175
+ * `default-position` seeds one this element owns. The same accessor pair
176
+ * `Pagination.page` and the calendar's `month` carry.
177
+ */
178
+ get position(): number;
179
+ set position(next: number);
171
180
  /**
172
181
  * How far one arrow press moves it, as a percentage.
173
182
  */
@@ -6,12 +6,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  var HelixHeadlessSplitter_1;
8
8
  import { capturePointer, closestInstance, customElement, HelixBeforeCollapseEvent, HelixBeforeResizeEvent, HelixElement, inlineStep, isRtl, requestChange, } from '@fusion.dev/helix-core';
9
- import { html } from 'lit';
9
+ import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
11
  const STACK_BELOW = 512;
12
12
  let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitter extends HelixElement {
13
13
  constructor() {
14
14
  super(...arguments);
15
+ this.collapsedLabel = 'Collapsed';
15
16
  this.collapsedSize = 0;
16
17
  this.cornerLabel = 'Resize both';
17
18
  this.defaultPosition = 50;
@@ -181,19 +182,6 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
181
182
  this.leaveSeparator(event);
182
183
  };
183
184
  }
184
- get position() {
185
- const shut = this.collapsed;
186
- if (shut) {
187
- return shut === 'start' ? this.sliver : 100 - this.sliver;
188
- }
189
- return this.clamp(this.positionState ?? this.defaultPosition);
190
- }
191
- set position(next) {
192
- const previous = this.position;
193
- this.positionState = next;
194
- this.reached = undefined;
195
- this.requestUpdate('position', previous);
196
- }
197
185
  get collapsed() {
198
186
  const held = this.collapsedState;
199
187
  if (held === undefined) {
@@ -236,6 +224,19 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
236
224
  get maxPercent() {
237
225
  return this.toPercent(this.max, 100);
238
226
  }
227
+ get position() {
228
+ const shut = this.collapsed;
229
+ if (shut) {
230
+ return shut === 'start' ? this.sliver : 100 - this.sliver;
231
+ }
232
+ return this.clamp(this.positionState ?? this.defaultPosition);
233
+ }
234
+ set position(next) {
235
+ const previous = this.position;
236
+ this.positionState = next;
237
+ this.reached = undefined;
238
+ this.requestUpdate('position', previous);
239
+ }
239
240
  get showing() {
240
241
  return this.reached === undefined ? this.position : this.clamp(this.reached);
241
242
  }
@@ -437,9 +438,10 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
437
438
  tabindex="0"
438
439
  aria-label=${this.label}
439
440
  aria-orientation=${this.vertical ? 'horizontal' : 'vertical'}
440
- aria-valuemax=${this.clamp(this.maxPercent)}
441
- aria-valuemin=${this.clamp(this.minPercent)}
441
+ aria-valuemax=${this.collapsed ? 100 : this.clamp(this.maxPercent)}
442
+ aria-valuemin=${this.collapsed ? 0 : this.clamp(this.minPercent)}
442
443
  aria-valuenow=${Math.round(position)}
444
+ aria-valuetext=${this.collapsed ? this.collapsedLabel : nothing}
443
445
  ?data-dragging=${this.dragging}
444
446
  ?data-flush=${this.flush}
445
447
  @dblclick=${this.handleDoubleClick}
@@ -472,18 +474,18 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
472
474
  ></div>`)}`;
473
475
  }
474
476
  };
477
+ __decorate([
478
+ property()
479
+ ], HelixHeadlessSplitter.prototype, "collapsed", null);
480
+ __decorate([
481
+ property({ attribute: 'collapsed-label' })
482
+ ], HelixHeadlessSplitter.prototype, "collapsedLabel", void 0);
475
483
  __decorate([
476
484
  property({ attribute: 'collapsed-size', type: Number })
477
485
  ], HelixHeadlessSplitter.prototype, "collapsedSize", void 0);
478
- __decorate([
479
- property({ type: Number })
480
- ], HelixHeadlessSplitter.prototype, "position", null);
481
486
  __decorate([
482
487
  property({ attribute: 'corner-label' })
483
488
  ], HelixHeadlessSplitter.prototype, "cornerLabel", void 0);
484
- __decorate([
485
- property()
486
- ], HelixHeadlessSplitter.prototype, "collapsed", null);
487
489
  __decorate([
488
490
  property({ attribute: 'default-collapsed' })
489
491
  ], HelixHeadlessSplitter.prototype, "defaultCollapsed", void 0);
@@ -502,6 +504,9 @@ __decorate([
502
504
  __decorate([
503
505
  property({ reflect: true })
504
506
  ], HelixHeadlessSplitter.prototype, "orientation", void 0);
507
+ __decorate([
508
+ property({ type: Number })
509
+ ], HelixHeadlessSplitter.prototype, "position", null);
505
510
  __decorate([
506
511
  property({ type: Number })
507
512
  ], HelixHeadlessSplitter.prototype, "step", void 0);
@@ -30,6 +30,7 @@ let HelixHeadlessSwitch = class HelixHeadlessSwitch extends MixinControllerCheck
30
30
  this.reportRequired(!this.checked, 'Turn this on to continue.', 'control');
31
31
  }
32
32
  formResetCallback() {
33
+ super.formResetCallback();
33
34
  this.resetChecked();
34
35
  }
35
36
  updated(changed) {
@@ -131,6 +131,14 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
131
131
  * such a column is never sortable however it is marked.
132
132
  */
133
133
  field: string;
134
+ /**
135
+ * What the grip that moves the column is called, with the heading's words as
136
+ * `{name}`.
137
+ *
138
+ * **Every word a column speaks is a property**, so a table in another
139
+ * language hears its own rather than English around its own headings.
140
+ */
141
+ moveLabel: string;
134
142
  /**
135
143
  * Whether a reader may change this column's width.
136
144
  *
@@ -140,6 +148,11 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
140
148
  * stores the widths can take the decision.
141
149
  */
142
150
  resizable: boolean;
151
+ /**
152
+ * What the separator that resizes the column is called, with the heading's
153
+ * words as `{name}`.
154
+ */
155
+ resizeLabel: string;
143
156
  /**
144
157
  * Whether a reader may reorder the set by this column.
145
158
  *
@@ -212,6 +225,10 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
212
225
  * the overflow either way, that being paint, and gets the honest track list.
213
226
  */
214
227
  width: string;
228
+ /**
229
+ * How the separator reads out the column's width, with `{width}` filled in.
230
+ */
231
+ widthLabel: string;
215
232
  /**
216
233
  * @internal Read by a parent to identify its children across the light DOM,
217
234
  * which is cheaper than `instanceof` and is why this is public rather than
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  var HelixHeadlessTableColumn_1;
8
- import { customElement, HelixBeforeResizeEvent, HelixElement, hostAria, inlineStep, isRtl, requestChange, } from '@fusion.dev/helix-core';
8
+ import { customElement, fillTemplate, HelixBeforeResizeEvent, HelixElement, hostAria, inlineStep, isRtl, requestChange, } from '@fusion.dev/helix-core';
9
9
  import { dotsThreeVertical } from '@fusion.dev/helix-icons';
10
10
  import { html, nothing } from 'lit';
11
11
  import { property, state } from 'lit/decorators.js';
@@ -34,9 +34,12 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
34
34
  this.cell = undefined;
35
35
  this.compare = undefined;
36
36
  this.field = '';
37
+ this.moveLabel = 'Move {name}';
37
38
  this.resizable = false;
39
+ this.resizeLabel = 'Resize {name}';
38
40
  this.sortable = false;
39
41
  this.width = '';
42
+ this.widthLabel = '{width} pixels';
40
43
  this.isTableColumn = true;
41
44
  this.sorted = undefined;
42
45
  this.movable = false;
@@ -165,7 +168,7 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
165
168
  render() {
166
169
  const name = this.name;
167
170
  return html `<span part="column">${this.movable
168
- ? html `<button part="grip" type="button" aria-label=${name ? `Move ${name}` : 'Move column'}>
171
+ ? html `<button part="grip" type="button" aria-label=${fillTemplate(this.moveLabel, { name: name || 'column' })}>
169
172
  <svg aria-hidden="true" fill="currentColor" part="grip-mark" viewBox=${dotsThreeVertical.viewBox}>
170
173
  ${unsafeSVG(dotsThreeVertical.content)}
171
174
  </svg>
@@ -177,12 +180,12 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
177
180
  part="resizer"
178
181
  role="separator"
179
182
  tabindex="0"
180
- aria-label=${name ? `Resize ${name}` : 'Resize column'}
183
+ aria-label=${fillTemplate(this.resizeLabel, { name: name || 'column' })}
181
184
  aria-orientation="vertical"
182
185
  aria-valuemin=${HelixHeadlessTableColumn_1.NARROWEST}
183
186
  aria-valuemax="4096"
184
187
  aria-valuenow=${Math.max(HelixHeadlessTableColumn_1.NARROWEST, this.drawn)}
185
- aria-valuetext=${`${this.drawn} pixels`}
188
+ aria-valuetext=${fillTemplate(this.widthLabel, { width: this.drawn })}
186
189
  @keydown=${this.handleResizeKey}
187
190
  @pointerdown=${this.handleResizeStart}
188
191
  @pointermove=${this.handleResizeMove}
@@ -201,9 +204,15 @@ __decorate([
201
204
  __decorate([
202
205
  property()
203
206
  ], HelixHeadlessTableColumn.prototype, "field", void 0);
207
+ __decorate([
208
+ property({ attribute: 'move-label' })
209
+ ], HelixHeadlessTableColumn.prototype, "moveLabel", void 0);
204
210
  __decorate([
205
211
  property({ type: Boolean })
206
212
  ], HelixHeadlessTableColumn.prototype, "resizable", void 0);
213
+ __decorate([
214
+ property({ attribute: 'resize-label' })
215
+ ], HelixHeadlessTableColumn.prototype, "resizeLabel", void 0);
207
216
  __decorate([
208
217
  property({ reflect: true, type: Boolean })
209
218
  ], HelixHeadlessTableColumn.prototype, "sortable", void 0);
@@ -213,6 +222,9 @@ __decorate([
213
222
  __decorate([
214
223
  property()
215
224
  ], HelixHeadlessTableColumn.prototype, "width", void 0);
225
+ __decorate([
226
+ property({ attribute: 'width-label' })
227
+ ], HelixHeadlessTableColumn.prototype, "widthLabel", void 0);
216
228
  __decorate([
217
229
  state()
218
230
  ], HelixHeadlessTableColumn.prototype, "sorted", void 0);
@@ -31,6 +31,7 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
31
31
  *
32
32
  * @csspart empty - Shown when there are no rows to show.
33
33
  * @csspart head - The row the column headings sit in. `display: contents`, so it takes no space.
34
+ * @csspart live - The empty and loading lines again, in a region a screen reader hears when they change. Visually hidden in the styled tier.
34
35
  * @csspart loading - Shown while the rows are still on their way.
35
36
  * @csspart table - The grid.
36
37
  *
@@ -136,7 +136,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
136
136
  }}
137
137
  ></slot>
138
138
  ${this.renderStatus(this.hasRows)}
139
- </div>`;
139
+ </div>${this.renderLive(this.hasRows)}`;
140
140
  }
141
141
  };
142
142
  __decorate([
@@ -108,7 +108,7 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
108
108
  if (!control) {
109
109
  return;
110
110
  }
111
- this.internals.setValidity(control.validity, control.validationMessage, control);
111
+ this.copyValidity(control);
112
112
  this.refreshFeedback();
113
113
  }
114
114
  connectedCallback() {
@@ -56,6 +56,7 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
56
56
  * @csspart picker-column-hint - Help under the list.
57
57
  * @csspart picker-column-items - The list itself.
58
58
  * @csspart picker-column-label - The question, over the list.
59
+ * @csspart picker-column-live - The inner column's `live`, the region a screen reader hears its empty and loading lines from.
59
60
  * @csspart picker-column-loading - Shown while the options are still on their way.
60
61
  * @csspart picker-column-search - The region holding the field that narrows the list.
61
62
  * @csspart picker-column-search-field - The field itself.
@@ -68,6 +69,7 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
68
69
  * @csspart picker-list-hint - Help under the list.
69
70
  * @csspart picker-list-items - The list itself.
70
71
  * @csspart picker-list-label - The question, over the list.
72
+ * @csspart picker-list-live - The inner list's `live`, the region a screen reader hears its empty and loading lines from.
71
73
  * @csspart picker-list-loading - Shown while the options are still on their way.
72
74
  * @csspart picker-list-search - The region holding the field that narrows the list.
73
75
  * @csspart picker-list-search-field - The field itself.
@@ -128,6 +130,31 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
128
130
  * What the field says before a time is in it.
129
131
  */
130
132
  placeholder: string;
133
+ /**
134
+ * What a reader is told when a range holds more than two times.
135
+ *
136
+ * **Every sentence a control raises in the browser's bubble is a property**,
137
+ * so a form in another language speaks it. Absent is the control's own
138
+ * sentence, in English.
139
+ */
140
+ rangeLengthMessage?: string;
141
+ /**
142
+ * What a reader is told when a time is after `max`, with `{max}` filled in
143
+ * as the field writes it.
144
+ */
145
+ rangeOverflowMessage?: string;
146
+ /**
147
+ * What a reader is told when a time is before `min`, with `{min}` filled
148
+ * in as the field writes it.
149
+ */
150
+ rangeUnderflowMessage?: string;
151
+ /**
152
+ * What the control removing one time is called, with `{name}` filled in.
153
+ *
154
+ * **The name goes in**, so a row of them is heard as which one each
155
+ * removes rather than as "Remove" said once per time.
156
+ */
157
+ removeLabel: string;
131
158
  /**
132
159
  * How far apart the offered times are, in minutes.
133
160
  */
@@ -177,6 +204,8 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
177
204
  private get picked();
178
205
  private readonly handleInput;
179
206
  private readonly handlePicked;
207
+ /** Each time, where `mode` holds several, sent one entry each. */
208
+ protected get answers(): readonly string[] | undefined;
180
209
  /** What is wrong with the times, which the text input cannot say. */
181
210
  protected validate(): string;
182
211
  /**
@@ -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, customElement, timeAsValue as fromTime, HelixFormElement, isTimeValue, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinTokens, valueAsMinutes, writeTime, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, valueAsTime as asTime, customElement, fillTemplate, timeAsValue as fromTime, HelixFormElement, isTimeValue, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinTokens, valueAsMinutes, writeTime, } 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';
@@ -24,6 +24,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
24
24
  this.max = '23:59';
25
25
  this.min = '00:00';
26
26
  this.placeholder = 'HH:mm';
27
+ this.removeLabel = 'Remove {name}';
27
28
  this.step = 15;
28
29
  this.timeStyle = 'local';
29
30
  this.triggerLabel = 'Choose a time';
@@ -106,23 +107,31 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
106
107
  const held = this.held;
107
108
  return held.length > 0 && held.every(isTimeValue) ? held.join(',') : '';
108
109
  }
110
+ get answers() {
111
+ return this.mode === undefined ? undefined : this.held;
112
+ }
109
113
  validate() {
110
114
  const held = this.held;
111
115
  const floor = valueAsMinutes(this.min) ?? 0;
112
116
  const ceiling = valueAsMinutes(this.max) ?? 1439;
113
117
  if (held.length > 0 && !held.every(isTimeValue)) {
114
- return this.mode === undefined
115
- ? 'Enter a time as HH:mm.'
116
- : 'Enter times as HH:mm, separated by commas.';
118
+ return (this.badInputMessage ||
119
+ (this.mode === undefined
120
+ ? 'Enter a time as HH:mm.'
121
+ : 'Enter times as HH:mm, separated by commas.'));
117
122
  }
118
123
  if (held.some((one) => (valueAsMinutes(one) ?? 0) < floor)) {
119
- return `Choose a time at or after ${writeTime(this.min, this.locale)}.`;
124
+ return fillTemplate(this.rangeUnderflowMessage || 'Choose a time at or after {min}.', {
125
+ min: writeTime(this.min, this.locale),
126
+ });
120
127
  }
121
128
  if (held.some((one) => (valueAsMinutes(one) ?? 0) > ceiling)) {
122
- return `Choose a time at or before ${writeTime(this.max, this.locale)}.`;
129
+ return fillTemplate(this.rangeOverflowMessage || 'Choose a time at or before {max}.', {
130
+ max: writeTime(this.max, this.locale),
131
+ });
123
132
  }
124
133
  if (this.mode === 'range' && held.length > 2) {
125
- return 'A range is two times.';
134
+ return this.rangeLengthMessage || 'A range is two times.';
126
135
  }
127
136
  return '';
128
137
  }
@@ -139,12 +148,12 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
139
148
  column-feedback: picker-column-feedback, column-filter-icon: picker-column-filter-icon,
140
149
  column-filter-mark: picker-column-filter-mark, column-hint: picker-column-hint,
141
150
  column-items: picker-column-items, column-label: picker-column-label,
142
- column-loading: picker-column-loading, column-search: picker-column-search,
151
+ column-live: picker-column-live, column-loading: picker-column-loading, column-search: picker-column-search,
143
152
  column-search-field: picker-column-search-field, columns: picker-columns, list: picker-list,
144
153
  list-empty: picker-list-empty, list-feedback: picker-list-feedback,
145
154
  list-filter-icon: picker-list-filter-icon, list-filter-mark: picker-list-filter-mark,
146
155
  list-hint: picker-list-hint, list-items: picker-list-items, list-label: picker-list-label,
147
- list-loading: picker-list-loading, list-search: picker-list-search,
156
+ list-live: picker-list-live, list-loading: picker-list-loading, list-search: picker-list-search,
148
157
  list-search-field: picker-list-search-field, option: picker-option,
149
158
  option-between: picker-option-between, option-item-active: picker-option-item-active,
150
159
  option-item-selected: picker-option-item-selected,
@@ -169,7 +178,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
169
178
  part="time"
170
179
  exportparts="dismiss: time-dismiss, dismiss-mark: time-dismiss-mark, start: time-start"
171
180
  dismissible
172
- dismiss-label=${`Remove ${this.written(at)}`}
181
+ dismiss-label=${fillTemplate(this.removeLabel, { name: this.written(at) })}
173
182
  ?disabled=${this.isDisabled}
174
183
  @helix-dismiss=${(event) => {
175
184
  event.stopPropagation();
@@ -256,6 +265,18 @@ __decorate([
256
265
  __decorate([
257
266
  property()
258
267
  ], HelixHeadlessTimeInput.prototype, "placeholder", void 0);
268
+ __decorate([
269
+ property({ attribute: 'range-length-message' })
270
+ ], HelixHeadlessTimeInput.prototype, "rangeLengthMessage", void 0);
271
+ __decorate([
272
+ property({ attribute: 'range-overflow-message' })
273
+ ], HelixHeadlessTimeInput.prototype, "rangeOverflowMessage", void 0);
274
+ __decorate([
275
+ property({ attribute: 'range-underflow-message' })
276
+ ], HelixHeadlessTimeInput.prototype, "rangeUnderflowMessage", void 0);
277
+ __decorate([
278
+ property({ attribute: 'remove-label' })
279
+ ], HelixHeadlessTimeInput.prototype, "removeLabel", void 0);
259
280
  __decorate([
260
281
  property({ type: Number })
261
282
  ], HelixHeadlessTimeInput.prototype, "step", void 0);
@@ -57,6 +57,7 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
57
57
  * @csspart column-hint - Help under the list.
58
58
  * @csspart column-items - The list itself.
59
59
  * @csspart column-label - The question, over the list.
60
+ * @csspart column-live - The inner list's `live`, the region a screen reader hears its empty and loading lines from.
60
61
  * @csspart column-loading - Shown while the options are still on their way.
61
62
  * @csspart column-search - The region holding the field that narrows the list.
62
63
  * @csspart column-search-field - The field itself.
@@ -69,6 +70,7 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
69
70
  * @csspart list-hint - Help under the list.
70
71
  * @csspart list-items - The list itself.
71
72
  * @csspart list-label - The question, over the list.
73
+ * @csspart list-live - The inner list's `live`, the region a screen reader hears its empty and loading lines from.
72
74
  * @csspart list-loading - Shown while the options are still on their way.
73
75
  * @csspart list-search - The region holding the field that narrows the list.
74
76
  * @csspart list-search-field - The field itself.
@@ -82,6 +84,14 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
82
84
  * @csspart option-text - The words and the caption, as one column.
83
85
  */
84
86
  export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_base {
87
+ /**
88
+ * What a reader is told when the value holds something that is not a time.
89
+ *
90
+ * **Every sentence a control raises in the browser's bubble is a property**,
91
+ * named for the validity flag it reports, so a form in another language
92
+ * speaks it. Absent is the control's own sentence, in English.
93
+ */
94
+ badInputMessage?: string;
85
95
  /**
86
96
  * Times that cannot be chosen, comma separated, as `HH:mm`.
87
97
  *
@@ -261,6 +271,10 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
261
271
  step: number;
262
272
  /** Refuses every change while read-only. See `readOnly`. */
263
273
  requestValue(next: string): boolean;
274
+ /**
275
+ * What a reader is told when a time is required and none is chosen.
276
+ */
277
+ valueMissingMessage?: string;
264
278
  /**
265
279
  * Whether the times are one list or a column each.
266
280
  *
@@ -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 { valueAsTime as asTime, customElement, timeAsValue as fromTime, HelixFormElement, MixinControllerValue, minutesAsValue, valueAsMinutes, writeTime, } from '@fusion.dev/helix-core';
7
+ import { valueAsTime as asTime, customElement, timeAsValue as fromTime, HelixFormElement, MixinControllerValue, minutesAsValue, reportValues, valueAsMinutes, writeTime, } 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';
@@ -151,29 +151,25 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
151
151
  reportRequired() {
152
152
  const anchor = this.partNamed('list') ?? undefined;
153
153
  if (this.required && this.value === '') {
154
- this.internals.setValidity({ valueMissing: true }, 'Choose a time.', anchor);
154
+ this.internals.setValidity({ valueMissing: true }, this.valueMissingMessage || 'Choose a time.', anchor);
155
155
  return;
156
156
  }
157
157
  const held = this.held;
158
158
  if (held.length > 0 && held.some((one) => asTime(one) === null)) {
159
- this.internals.setValidity({ badInput: true }, this.mode === undefined
160
- ? 'Enter a time as HH:mm.'
161
- : 'Enter times as HH:mm, separated by commas.', anchor);
159
+ this.internals.setValidity({ badInput: true }, this.badInputMessage ||
160
+ (this.mode === undefined
161
+ ? 'Enter a time as HH:mm.'
162
+ : 'Enter times as HH:mm, separated by commas.'), anchor);
162
163
  return;
163
164
  }
164
165
  this.internals.setValidity({});
165
166
  }
166
167
  report() {
167
- const times = this.held;
168
- if (this.name === '' || this.disabled || times.length === 0) {
168
+ if (this.disabled) {
169
169
  this.internals.setFormValue(null);
170
170
  return;
171
171
  }
172
- const data = new FormData();
173
- for (const time of times) {
174
- data.append(this.name, time);
175
- }
176
- this.internals.setFormValue(data);
172
+ reportValues(this.internals, this.name, this.held);
177
173
  }
178
174
  async revealWhenSettled() {
179
175
  const settling = [
@@ -208,7 +204,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
208
204
  data-column=${part}
209
205
  exportparts="empty: column-empty, feedback: column-feedback, filter-icon: column-filter-icon,
210
206
  filter-mark: column-filter-mark, hint: column-hint, items: column-items, label: column-label,
211
- loading: column-loading, search: column-search, search-field: column-search-field"
207
+ live: column-live, loading: column-loading, search: column-search, search-field: column-search-field"
212
208
  aria-label=${label}
213
209
  ?disabled=${this.isDisabled}
214
210
  .value=${value}
@@ -250,7 +246,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
250
246
  part="list"
251
247
  exportparts="empty: list-empty, feedback: list-feedback, filter-icon: list-filter-icon,
252
248
  filter-mark: list-filter-mark, hint: list-hint, items: list-items, label: list-label,
253
- loading: list-loading, search: list-search, search-field: list-search-field"
249
+ live: list-live, loading: list-loading, search: list-search, search-field: list-search-field"
254
250
  aria-label=${this.label}
255
251
  data-unset=${this.value === '' ? '' : nothing}
256
252
  ?disabled=${this.isDisabled}
@@ -295,6 +291,9 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
295
291
  this.value = Number.isNaN(ms) ? '' : fromTime(new Date(ms));
296
292
  }
297
293
  };
294
+ __decorate([
295
+ property({ attribute: 'bad-input-message' })
296
+ ], HelixHeadlessTimePicker.prototype, "badInputMessage", void 0);
298
297
  __decorate([
299
298
  property({ attribute: 'disable-times' })
300
299
  ], HelixHeadlessTimePicker.prototype, "disableTimes", void 0);
@@ -325,6 +324,9 @@ __decorate([
325
324
  __decorate([
326
325
  property({ type: Number })
327
326
  ], HelixHeadlessTimePicker.prototype, "step", void 0);
327
+ __decorate([
328
+ property({ attribute: 'value-missing-message' })
329
+ ], HelixHeadlessTimePicker.prototype, "valueMissingMessage", void 0);
328
330
  __decorate([
329
331
  property({ reflect: true })
330
332
  ], HelixHeadlessTimePicker.prototype, "variant", void 0);