@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
@@ -69,6 +69,15 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
69
69
  * consumer to ask for it.
70
70
  */
71
71
  autocomplete: string;
72
+ /**
73
+ * What a reader is told when the field holds something that is not a number.
74
+ *
75
+ * **Every sentence a control raises in the browser's bubble is a property**,
76
+ * named for the validity flag it reports, so a form in another language
77
+ * speaks it: `feedback` replaces the message under the field and does not
78
+ * reach the bubble. Absent is the control's own sentence, in English.
79
+ */
80
+ badInputMessage?: string;
72
81
  /**
73
82
  * Accessible name for the control that steps down.
74
83
  */
@@ -103,6 +112,14 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
103
112
  * Not a label: it goes when typing starts.
104
113
  */
105
114
  placeholder: string;
115
+ /**
116
+ * What a reader is told when the number is above `max`, with `{max}` filled in.
117
+ */
118
+ rangeOverflowMessage?: string;
119
+ /**
120
+ * What a reader is told when the number is below `min`, with `{min}` filled in.
121
+ */
122
+ rangeUnderflowMessage?: string;
106
123
  /**
107
124
  * Whether the field refuses input while still submitting its value.
108
125
  */
@@ -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, valueAsNumber as asNumber, customElement, numberAsValue as fromNumber, HelixFormElement, holdCaret, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, valueAsNumber as asNumber, customElement, fillTemplate, numberAsValue as fromNumber, HelixFormElement, holdCaret, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
8
8
  import { minus, plus } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -193,17 +193,24 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
193
193
  return;
194
194
  }
195
195
  const parsed = this.numeric;
196
- if (this.required && this.value.trim() === '') {
197
- this.internals.setValidity({ valueMissing: true }, 'Please fill in this field.', control);
196
+ if (this.readOnly) {
197
+ this.internals.setValidity({});
198
+ }
199
+ else if (this.required && this.value.trim() === '') {
200
+ this.internals.setValidity({ valueMissing: true }, this.valueMissingMessage || 'Please fill in this field.', control);
198
201
  }
199
202
  else if (this.value.trim() !== '' && parsed === null) {
200
- this.internals.setValidity({ badInput: true }, 'Please enter a number.', control);
203
+ this.internals.setValidity({ badInput: true }, this.badInputMessage || 'Please enter a number.', control);
201
204
  }
202
205
  else if (parsed !== null && this.min !== undefined && parsed < this.min) {
203
- this.internals.setValidity({ rangeUnderflow: true }, `Value must be ${this.min} or more.`, control);
206
+ this.internals.setValidity({ rangeUnderflow: true }, fillTemplate(this.rangeUnderflowMessage || 'Value must be {min} or more.', {
207
+ min: this.min,
208
+ }), control);
204
209
  }
205
210
  else if (parsed !== null && this.max !== undefined && parsed > this.max) {
206
- this.internals.setValidity({ rangeOverflow: true }, `Value must be ${this.max} or less.`, control);
211
+ this.internals.setValidity({ rangeOverflow: true }, fillTemplate(this.rangeOverflowMessage || 'Value must be {max} or less.', {
212
+ max: this.max,
213
+ }), control);
207
214
  }
208
215
  else {
209
216
  this.internals.setValidity({}, '', control);
@@ -300,6 +307,9 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
300
307
  __decorate([
301
308
  property()
302
309
  ], HelixHeadlessNumberInput.prototype, "autocomplete", void 0);
310
+ __decorate([
311
+ property({ attribute: 'bad-input-message' })
312
+ ], HelixHeadlessNumberInput.prototype, "badInputMessage", void 0);
303
313
  __decorate([
304
314
  property({ attribute: 'decrement-label' })
305
315
  ], HelixHeadlessNumberInput.prototype, "decrementLabel", void 0);
@@ -318,6 +328,12 @@ __decorate([
318
328
  __decorate([
319
329
  property()
320
330
  ], HelixHeadlessNumberInput.prototype, "placeholder", void 0);
331
+ __decorate([
332
+ property({ attribute: 'range-overflow-message' })
333
+ ], HelixHeadlessNumberInput.prototype, "rangeOverflowMessage", void 0);
334
+ __decorate([
335
+ property({ attribute: 'range-underflow-message' })
336
+ ], HelixHeadlessNumberInput.prototype, "rangeUnderflowMessage", void 0);
321
337
  __decorate([
322
338
  property({ attribute: 'readonly', reflect: true, type: Boolean })
323
339
  ], HelixHeadlessNumberInput.prototype, "readOnly", void 0);
@@ -94,6 +94,16 @@ interface Row {
94
94
  * @cssproperty --object-inspector-level - How deep a row is, from 0 at the root, for indenting it.
95
95
  */
96
96
  export declare class HelixHeadlessObjectInspector extends HelixElement {
97
+ /**
98
+ * What the copy control is called on a row with a key, with the key as
99
+ * `{name}`.
100
+ *
101
+ * **Every word the inspector speaks is a property**, so a page in another
102
+ * language hears its own rather than English around its own keys.
103
+ */
104
+ copyLabel: string;
105
+ /** What the copy control is called where there is no key, on the value itself. */
106
+ copyValueLabel: string;
97
107
  /**
98
108
  * How many levels start open.
99
109
  *
@@ -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 HelixHeadlessObjectInspector_1;
8
- import { CopyController, customElement, elementById, HelixElement, inlineStep, scrollItemIntoView, searchableById, VirtualizeController, } from '@fusion.dev/helix-core';
8
+ import { CopyController, customElement, elementById, fillTemplate, HelixElement, inlineStep, scrollItemIntoView, searchableById, VirtualizeController, } from '@fusion.dev/helix-core';
9
9
  import { caretDown, caretRight } from '@fusion.dev/helix-icons';
10
10
  import { html, nothing } from 'lit';
11
11
  import { property, state } from 'lit/decorators.js';
@@ -18,6 +18,8 @@ const child = (path, key) => `${path}/${key.replaceAll('~', '~0').replaceAll('/'
18
18
  let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends HelixElement {
19
19
  constructor() {
20
20
  super(...arguments);
21
+ this.copyLabel = 'Copy {name}';
22
+ this.copyValueLabel = 'Copy value';
21
23
  this.defaultDepth = 1;
22
24
  this.for = '';
23
25
  this.label = '';
@@ -291,7 +293,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
291
293
  tooltip-arrow-left: copy-tooltip-arrow-left, tooltip-arrow-right: copy-tooltip-arrow-right,
292
294
  tooltip-arrow-top: copy-tooltip-arrow-top, tooltip-bottom: copy-tooltip-bottom,
293
295
  tooltip-left: copy-tooltip-left, tooltip-right: copy-tooltip-right, tooltip-top: copy-tooltip-top"
294
- label=${row?.key === undefined ? 'Copy value' : `Copy ${row.key}`}
296
+ label=${row?.key === undefined ? this.copyValueLabel : fillTemplate(this.copyLabel, { name: row.key })}
295
297
  .value=${this.copyable(row)}
296
298
  ></${this.tag('copy-button')}>`;
297
299
  }
@@ -321,6 +323,12 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
321
323
  </div>`;
322
324
  }
323
325
  };
326
+ __decorate([
327
+ property({ attribute: 'copy-label' })
328
+ ], HelixHeadlessObjectInspector.prototype, "copyLabel", void 0);
329
+ __decorate([
330
+ property({ attribute: 'copy-value-label' })
331
+ ], HelixHeadlessObjectInspector.prototype, "copyValueLabel", void 0);
324
332
  __decorate([
325
333
  property({ attribute: 'default-depth', type: Number })
326
334
  ], HelixHeadlessObjectInspector.prototype, "defaultDepth", void 0);
@@ -79,6 +79,11 @@ export declare class HelixHeadlessOutline extends HelixElement {
79
79
  get current(): string;
80
80
  /**
81
81
  * What `current` reports, which only `mark` writes.
82
+ *
83
+ * **A field, not state.** Nothing renders it: the links carry `aria-current`
84
+ * and the mark is placed by measuring them, so a render on its change drew
85
+ * the same template again. It also made the first measurement, which can only
86
+ * happen after the first render, schedule a second one from `firstUpdated`.
82
87
  */
83
88
  private reading;
84
89
  private observer;
@@ -146,6 +151,8 @@ export declare class HelixHeadlessOutline extends HelixElement {
146
151
  private landing;
147
152
  /** The guard behind `scrollend`, in case it never comes. */
148
153
  private landed;
154
+ /** What `scrollend` calls when the scroll a click started lands, while it is awaited. */
155
+ private arrive;
149
156
  /**
150
157
  * The two things an `IntersectionObserver` cannot see, and one listener for
151
158
  * both.
@@ -221,6 +228,14 @@ export declare class HelixHeadlessOutline extends HelixElement {
221
228
  */
222
229
  private readonly handleSlotChange;
223
230
  disconnectedCallback(): void;
231
+ /**
232
+ * Stops waiting for a scroll to land, both halves of the wait.
233
+ *
234
+ * The `scrollend` listener is on the document, so it is taken off as well as
235
+ * the timer: left on, every click that did not wait for the last landing
236
+ * added one more.
237
+ */
238
+ private unland;
224
239
  connectedCallback(): void;
225
240
  protected firstUpdated(changed: PropertyValues): void;
226
241
  protected updated(changed: PropertyValues): void;
@@ -6,7 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { customElement, elementById, HelixActivateEvent, HelixElement, IndicatorController, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
- import { property, state } from 'lit/decorators.js';
9
+ import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
11
11
  constructor() {
12
12
  super(...arguments);
@@ -43,13 +43,13 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
43
43
  }
44
44
  this.landing = section;
45
45
  this.markTo(section);
46
- clearTimeout(this.landed);
46
+ this.unland();
47
47
  const arrive = () => {
48
- clearTimeout(this.landed);
48
+ this.unland();
49
49
  this.landing = undefined;
50
- document.removeEventListener('scrollend', arrive, true);
51
50
  this.mark();
52
51
  };
52
+ this.arrive = arrive;
53
53
  document.addEventListener('scrollend', arrive, { capture: true, once: true });
54
54
  this.landed = setTimeout(arrive, 1200);
55
55
  if (this.behavior === 'auto') {
@@ -115,6 +115,7 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
115
115
  const next = active?.target.id ?? '';
116
116
  if (next !== this.reading) {
117
117
  this.reading = next;
118
+ this.indicator.place();
118
119
  this.dispatchEvent(new HelixActivateEvent({ value: next }));
119
120
  }
120
121
  }
@@ -168,8 +169,15 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
168
169
  }
169
170
  this.observer?.disconnect();
170
171
  this.observer = undefined;
172
+ this.unland();
173
+ }
174
+ unland() {
171
175
  clearTimeout(this.landed);
172
176
  this.landed = undefined;
177
+ if (this.arrive) {
178
+ document.removeEventListener('scrollend', this.arrive, true);
179
+ this.arrive = undefined;
180
+ }
173
181
  }
174
182
  connectedCallback() {
175
183
  super.connectedCallback();
@@ -213,9 +221,6 @@ __decorate([
213
221
  __decorate([
214
222
  property({ type: Number })
215
223
  ], HelixHeadlessOutline.prototype, "offset", void 0);
216
- __decorate([
217
- state()
218
- ], HelixHeadlessOutline.prototype, "reading", void 0);
219
224
  HelixHeadlessOutline = __decorate([
220
225
  customElement('helix-headless-outline')
221
226
  ], HelixHeadlessOutline);
@@ -97,24 +97,6 @@ export declare class HelixHeadlessPagination extends HelixElement {
97
97
  * written onto a host at upgrade that a server's output never had.
98
98
  */
99
99
  ends: boolean;
100
- /**
101
- * The page on show, one-based.
102
- *
103
- * An accessor pair, the same shape as the calendar's `month`. Reading gives
104
- * the page on show; writing sets it, and `default-page` seeds one the element
105
- * keeps until somebody does.
106
- *
107
- * **Clamped on the way out, because "the page on show" is what it says it
108
- * gives.** Returning whatever was written means `default-page="99"` on a
109
- * ten-page result renders page 10, marks page 10 with `aria-current`, and
110
- * reports 99, so a consumer syncing their query from this reads a page that
111
- * does not exist while the control in front of them says otherwise. Not a
112
- * far-fetched value: it is a bookmarked link after the result shrank.
113
- *
114
- * Rounded here too, so `2.7` reads as the 2 it renders.
115
- */
116
- get page(): number;
117
- set page(next: number);
118
100
  /**
119
101
  * Accessible name for the control that jumps to the first page.
120
102
  */
@@ -157,6 +139,24 @@ export declare class HelixHeadlessPagination extends HelixElement {
157
139
  * Accessible name for the control that moves forward.
158
140
  */
159
141
  nextLabel: string;
142
+ /**
143
+ * The page on show, one-based.
144
+ *
145
+ * An accessor pair, the same shape as the calendar's `month`. Reading gives
146
+ * the page on show; writing sets it, and `default-page` seeds one the element
147
+ * keeps until somebody does.
148
+ *
149
+ * **Clamped on the way out, because "the page on show" is what it says it
150
+ * gives.** Returning whatever was written means `default-page="99"` on a
151
+ * ten-page result renders page 10, marks page 10 with `aria-current`, and
152
+ * reports 99, so a consumer syncing their query from this reads a page that
153
+ * does not exist while the control in front of them says otherwise. Not a
154
+ * far-fetched value: it is a bookmarked link after the result shrank.
155
+ *
156
+ * Rounded here too, so `2.7` reads as the 2 it renders.
157
+ */
158
+ get page(): number;
159
+ set page(next: number);
160
160
  /**
161
161
  * Accessible name for one page, with `{page}` and `{pages}` filled in.
162
162
  */
@@ -4,12 +4,12 @@ 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, formatNumbers, HelixElement, HelixNavigateEvent, hostAria, requestChange, } from '@fusion.dev/helix-core';
7
+ import { customElement, fillTemplate, formatNumbers, HelixElement, HelixNavigateEvent, hostAria, requestChange, } from '@fusion.dev/helix-core';
8
8
  import { caretDoubleLeft, caretDoubleRight, caretLeft, caretRight, } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
11
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
12
- const fill = (template, page, pages, format = String) => template.replaceAll('{page}', format(page)).replaceAll('{pages}', format(pages));
12
+ const fill = (template, page, pages, format = String) => fillTemplate(template, { page: format(page), pages: format(pages) });
13
13
  let HelixHeadlessPagination = class HelixHeadlessPagination extends HelixElement {
14
14
  constructor() {
15
15
  super(...arguments);
@@ -273,9 +273,6 @@ __decorate([
273
273
  __decorate([
274
274
  property({ type: Boolean })
275
275
  ], HelixHeadlessPagination.prototype, "ends", void 0);
276
- __decorate([
277
- property({ type: Number })
278
- ], HelixHeadlessPagination.prototype, "page", null);
279
276
  __decorate([
280
277
  property({ attribute: 'first-label' })
281
278
  ], HelixHeadlessPagination.prototype, "firstLabel", void 0);
@@ -297,6 +294,9 @@ __decorate([
297
294
  __decorate([
298
295
  property({ attribute: 'next-label' })
299
296
  ], HelixHeadlessPagination.prototype, "nextLabel", void 0);
297
+ __decorate([
298
+ property({ type: Number })
299
+ ], HelixHeadlessPagination.prototype, "page", null);
300
300
  __decorate([
301
301
  property({ attribute: 'page-label' })
302
302
  ], HelixHeadlessPagination.prototype, "pageLabel", void 0);
@@ -53,6 +53,7 @@ import '../../select/index.js';
53
53
  * @csspart control-listbox-hint - Help under the list.
54
54
  * @csspart control-listbox-items - The list itself.
55
55
  * @csspart control-listbox-label - The question, over the list.
56
+ * @csspart control-listbox-live - The inner listbox's `live`, the region a screen reader hears its empty and loading lines from.
56
57
  * @csspart control-listbox-loading - Shown while the options are still on their way.
57
58
  * @csspart control-listbox-search - The region holding the field that narrows the list.
58
59
  * @csspart control-listbox-search-field - The field itself.
@@ -74,15 +75,6 @@ export declare class HelixHeadlessPaginationSize extends HelixElement {
74
75
  * Size to start on, where nothing declared one.
75
76
  */
76
77
  defaultValue: number;
77
- /**
78
- * The size in force.
79
- *
80
- * Reading gives the real one; writing declares it the consumer's, and
81
- * `default-value` seeds one this element owns. Same accessor pair as
82
- * `Pagination.page` and the calendar's `month`.
83
- */
84
- get value(): number;
85
- set value(next: number);
86
78
  /**
87
79
  * The words beside the control.
88
80
  */
@@ -101,6 +93,15 @@ export declare class HelixHeadlessPaginationSize extends HelixElement {
101
93
  * is dropped rather than rendered as an option that cannot mean anything.
102
94
  */
103
95
  sizes: string;
96
+ /**
97
+ * The size in force.
98
+ *
99
+ * Reading gives the real one; writing declares it the consumer's, and
100
+ * `default-value` seeds one this element owns. Same accessor pair as
101
+ * `Pagination.page` and the calendar's `month`.
102
+ */
103
+ get value(): number;
104
+ set value(next: number);
104
105
  /** The size, whoever set it, and `undefined` until somebody has. */
105
106
  private valueState;
106
107
  /** Held across every component asking for the same locale. */
@@ -77,7 +77,7 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
77
77
  listbox-feedback: control-listbox-feedback, listbox-filter-icon: control-listbox-filter-icon,
78
78
  listbox-filter-mark: control-listbox-filter-mark, listbox-hint: control-listbox-hint,
79
79
  listbox-items: control-listbox-items, listbox-label: control-listbox-label,
80
- listbox-loading: control-listbox-loading, listbox-search: control-listbox-search,
80
+ listbox-live: control-listbox-live, listbox-loading: control-listbox-loading, listbox-search: control-listbox-search,
81
81
  listbox-search-field: control-listbox-search-field, surface: control-surface,
82
82
  trigger: control-trigger, value: control-value"
83
83
  label=${this.label}
@@ -104,9 +104,6 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
104
104
  __decorate([
105
105
  property({ attribute: 'default-value', type: Number })
106
106
  ], HelixHeadlessPaginationSize.prototype, "defaultValue", void 0);
107
- __decorate([
108
- property({ type: Number })
109
- ], HelixHeadlessPaginationSize.prototype, "value", null);
110
107
  __decorate([
111
108
  property()
112
109
  ], HelixHeadlessPaginationSize.prototype, "label", void 0);
@@ -116,6 +113,9 @@ __decorate([
116
113
  __decorate([
117
114
  property()
118
115
  ], HelixHeadlessPaginationSize.prototype, "sizes", void 0);
116
+ __decorate([
117
+ property({ type: Number })
118
+ ], HelixHeadlessPaginationSize.prototype, "value", null);
119
119
  HelixHeadlessPaginationSize = __decorate([
120
120
  customElement('helix-headless-pagination-size')
121
121
  ], HelixHeadlessPaginationSize);
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, formatNumbers, HelixElement } from '@fusion.dev/helix-core';
7
+ import { customElement, fillTemplate, formatNumbers, HelixElement } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessPaginationSummary = class HelixHeadlessPaginationSummary extends HelixElement {
@@ -28,10 +28,11 @@ let HelixHeadlessPaginationSummary = class HelixHeadlessPaginationSummary extend
28
28
  const page = Math.min(pages, Math.max(1, Math.floor(this.page) || 1));
29
29
  const from = (page - 1) * size + 1;
30
30
  const to = Math.min(this.total, from + size - 1);
31
- return html `${this.format
32
- .replaceAll('{from}', this.numbers(from))
33
- .replaceAll('{to}', this.numbers(to))
34
- .replaceAll('{total}', this.numbers(this.total))}`;
31
+ return html `${fillTemplate(this.format, {
32
+ from: this.numbers(from),
33
+ to: this.numbers(to),
34
+ total: this.numbers(this.total),
35
+ })}`;
35
36
  }
36
37
  };
37
38
  __decorate([
@@ -93,6 +93,11 @@ export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
93
93
  * Whether the boxes refuse input while still submitting their value.
94
94
  */
95
95
  readOnly: boolean;
96
+ /**
97
+ * What a reader is told when the code is started and not finished, with
98
+ * `{length}` filled in. Absent is the control's own sentence, in English.
99
+ */
100
+ tooShortMessage?: string;
96
101
  /**
97
102
  * What a box accepts, which decides the keyboard a phone offers.
98
103
  *
@@ -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, HelixCompleteEvent, HelixFormElement, MixinControllerValue, MixinField, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, fillTemplate, HelixCompleteEvent, HelixFormElement, MixinControllerValue, MixinField, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerValue(MixinField(HelixFormElement)) {
@@ -165,10 +165,12 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
165
165
  return;
166
166
  }
167
167
  if (this.required && this.value === '') {
168
- this.internals.setValidity({ valueMissing: true }, 'Please fill in this field.', first);
168
+ this.internals.setValidity({ valueMissing: true }, this.valueMissingMessage || 'Please fill in this field.', first);
169
169
  }
170
170
  else if (this.value !== '' && this.value.length < this.count) {
171
- this.internals.setValidity({ tooShort: true }, `Please enter all ${this.count} characters.`, first);
171
+ this.internals.setValidity({ tooShort: true }, fillTemplate(this.tooShortMessage || 'Please enter all {length} characters.', {
172
+ length: this.count,
173
+ }), first);
172
174
  }
173
175
  else {
174
176
  this.internals.setValidity({}, '', first);
@@ -204,6 +206,7 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
204
206
  part="field"
205
207
  role="group"
206
208
  aria-describedby=${this.describedBy ?? nothing}
209
+ aria-labelledby=${this.labeled ? this.labelId : nothing}
207
210
  @focusin=${this.handleFocusIn}
208
211
  @focusout=${this.handleFocusOut}
209
212
  >
@@ -214,9 +217,7 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
214
217
  placeholder=${this.placeholder || nothing}
215
218
  inputmode=${this.type === 'numeric' ? 'numeric' : 'text'}
216
219
  autocomplete=${at === 0 ? this.autocomplete || nothing : 'off'}
217
- aria-label=${this.cellLabel
218
- .replaceAll('{index}', String(at + 1))
219
- .replaceAll('{length}', String(this.count))}
220
+ aria-label=${fillTemplate(this.cellLabel, { index: at + 1, length: this.count })}
220
221
  ?disabled=${this.isDisabled}
221
222
  ?readonly=${this.readOnly}
222
223
  @focus=${this.handleFocus}
@@ -246,6 +247,9 @@ __decorate([
246
247
  __decorate([
247
248
  property({ attribute: 'readonly', reflect: true, type: Boolean })
248
249
  ], HelixHeadlessPinInput.prototype, "readOnly", void 0);
250
+ __decorate([
251
+ property({ attribute: 'too-short-message' })
252
+ ], HelixHeadlessPinInput.prototype, "tooShortMessage", void 0);
249
253
  __decorate([
250
254
  property()
251
255
  ], HelixHeadlessPinInput.prototype, "type", void 0);
@@ -153,7 +153,7 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
153
153
  return nearest;
154
154
  }
155
155
  sync() {
156
- this.internals.setFormValue(this.value);
156
+ this.internals.setFormValue(this.value === '' ? null : this.value);
157
157
  this.reportRequired(this.value === '', 'Choose a rating to continue.', 'marks');
158
158
  }
159
159
  connectedCallback() {
@@ -198,7 +198,8 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
198
198
  <div
199
199
  part="marks"
200
200
  role=${this.readOnly ? 'img' : 'radiogroup'}
201
- aria-label=${this.readOnly ? said : this.label || nothing}
201
+ aria-label=${this.readOnly ? said : nothing}
202
+ aria-labelledby=${!this.readOnly && this.labeled ? this.labelId : nothing}
202
203
  aria-describedby=${this.describedBy ?? nothing}
203
204
  aria-required=${this.required && !this.readOnly ? 'true' : nothing}
204
205
  data-slotted=${this.markSource ? '' : nothing}
@@ -52,6 +52,7 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
52
52
  * @csspart listbox-hint - Help under the list.
53
53
  * @csspart listbox-items - The list itself.
54
54
  * @csspart listbox-label - The question, over the list.
55
+ * @csspart listbox-live - The inner list's `live`, the region a screen reader hears its empty and loading lines from.
55
56
  * @csspart listbox-loading - Shown while the options are still on their way.
56
57
  * @csspart listbox-search - The region holding the field that narrows the list.
57
58
  * @csspart listbox-search-field - The field itself.
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { AriaForwardController, customElement, HelixFormElement, hostAria, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, HelixFormElement, hostAria, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, reportValues, } from '@fusion.dev/helix-core';
8
8
  import { caretDown } from '@fusion.dev/helix-icons';
9
9
  import { nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -87,7 +87,12 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
87
87
  this.partNamed('trigger')?.focus();
88
88
  }
89
89
  sync() {
90
- this.internals.setFormValue(this.value === '' ? null : this.value);
90
+ if (this.multiple) {
91
+ reportValues(this.internals, this.name, this.value === '' ? [] : this.value.split(','));
92
+ }
93
+ else {
94
+ this.internals.setFormValue(this.value === '' ? null : this.value);
95
+ }
91
96
  this.reportRequired(this.value === '', 'Choose one to continue.', 'trigger');
92
97
  }
93
98
  willUpdate(changed) {
@@ -119,7 +124,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
119
124
  part="listbox"
120
125
  exportparts="empty: listbox-empty, feedback: listbox-feedback, filter-icon: listbox-filter-icon,
121
126
  filter-mark: listbox-filter-mark, hint: listbox-hint, items: listbox-items,
122
- label: listbox-label, loading: listbox-loading, search: listbox-search,
127
+ label: listbox-label, live: listbox-live, loading: listbox-loading, search: listbox-search,
123
128
  search-field: listbox-search-field"
124
129
  .value=${this.value}
125
130
  ?multiple=${this.multiple}
@@ -85,10 +85,22 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
85
85
  * The largest value the reader can choose.
86
86
  */
87
87
  max: number;
88
+ /**
89
+ * What the upper thumb of a range is called, after the slider's own label.
90
+ *
91
+ * **Named with the label rather than instead of it.** Each thumb was
92
+ * `aria-label="${label} maximum"`, which overrode the `<label>` and read the
93
+ * `label` string only, so a slider named by a slotted label or `aria-label`
94
+ * had thumbs called "minimum" and "maximum" and nothing else. The word is a
95
+ * property, like every other word a control speaks.
96
+ */
97
+ maximumLabel: string;
88
98
  /**
89
99
  * The smallest value the reader can choose.
90
100
  */
91
101
  min: number;
102
+ /** What the lower thumb of a range is called, after the slider's own label. */
103
+ minimumLabel: string;
92
104
  /**
93
105
  * Which way the track runs, `vertical` standing it on end.
94
106
  *
@@ -17,7 +17,9 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
17
17
  this.markerLabels = false;
18
18
  this.markers = 0;
19
19
  this.max = 100;
20
+ this.maximumLabel = 'maximum';
20
21
  this.min = 0;
22
+ this.minimumLabel = 'minimum';
21
23
  this.range = false;
22
24
  this.showValue = false;
23
25
  this.handleInput = (event) => {
@@ -127,13 +129,17 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
127
129
  max=${this.max}
128
130
  step=${this.step}
129
131
  .value=${String(at)}
130
- aria-label=${`${this.label} ${which === 'start' ? 'minimum' : 'maximum'}`}
132
+ aria-labelledby=${this.labeled ? `${this.labelId} ${which}-name` : `${which}-name`}
131
133
  aria-describedby=${this.describedBy ?? nothing}
132
134
  ?disabled=${this.isDisabled}
133
135
  @input=${this.handleInput}
134
136
  @change=${this.handleChange}
135
137
  />`;
136
138
  return html `${this.renderLabel()}
139
+ ${this.range
140
+ ? html `<span id="start-name" hidden>${this.minimumLabel}</span
141
+ ><span id="end-name" hidden>${this.maximumLabel}</span>`
142
+ : nothing}
137
143
  <div
138
144
  part="field"
139
145
  data-markers=${this.markerValues.length > 0 ? '' : nothing}
@@ -190,9 +196,15 @@ __decorate([
190
196
  __decorate([
191
197
  property({ type: Number })
192
198
  ], HelixHeadlessSlider.prototype, "max", void 0);
199
+ __decorate([
200
+ property({ attribute: 'maximum-label' })
201
+ ], HelixHeadlessSlider.prototype, "maximumLabel", void 0);
193
202
  __decorate([
194
203
  property({ type: Number })
195
204
  ], HelixHeadlessSlider.prototype, "min", void 0);
205
+ __decorate([
206
+ property({ attribute: 'minimum-label' })
207
+ ], HelixHeadlessSlider.prototype, "minimumLabel", void 0);
196
208
  __decorate([
197
209
  property({ reflect: true })
198
210
  ], HelixHeadlessSlider.prototype, "orientation", void 0);