@fusion.dev/helix-headless 0.159.0 → 0.161.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 (61) hide show
  1. package/custom-elements.json +2980 -189
  2. package/dist/canvas/root/canvas-root.d.ts +59 -2
  3. package/dist/canvas/root/canvas-root.js +123 -8
  4. package/dist/chat/message/chat-message.d.ts +8 -0
  5. package/dist/chat/message/chat-message.js +11 -0
  6. package/dist/chat/root/chat-root.d.ts +47 -1
  7. package/dist/chat/root/chat-root.js +130 -4
  8. package/dist/code-block/lines.d.ts +12 -0
  9. package/dist/code-block/lines.js +41 -0
  10. package/dist/code-block/root/code-block-root.d.ts +88 -5
  11. package/dist/code-block/root/code-block-root.js +154 -10
  12. package/dist/date-input/root/date-input-root.d.ts +108 -19
  13. package/dist/date-input/root/date-input-root.js +112 -13
  14. package/dist/date-picker/root/date-picker-root.d.ts +81 -16
  15. package/dist/date-picker/root/date-picker-root.js +140 -36
  16. package/dist/element-events.generated.js +6 -0
  17. package/dist/format-date/fields.js +1 -0
  18. package/dist/format-date/options.d.ts +3 -1
  19. package/dist/format-date/options.js +4 -1
  20. package/dist/format-date/root/format-date-root.d.ts +27 -11
  21. package/dist/format-date/root/format-date-root.js +6 -0
  22. package/dist/listbox/root/listbox-root.js +5 -0
  23. package/dist/notifications/notification/notification.d.ts +1 -0
  24. package/dist/notifications/notification/notification.js +2 -1
  25. package/dist/slider/root/slider-root.d.ts +54 -3
  26. package/dist/slider/root/slider-root.js +124 -2
  27. package/dist/splitter/root/splitter-root.d.ts +15 -0
  28. package/dist/splitter/root/splitter-root.js +16 -2
  29. package/dist/table/grid-controller.d.ts +7 -1
  30. package/dist/table/grid-controller.js +9 -1
  31. package/dist/table/root/table-root.d.ts +122 -0
  32. package/dist/table/root/table-root.js +293 -17
  33. package/dist/table/row/table-row.d.ts +41 -0
  34. package/dist/table/row/table-row.js +56 -2
  35. package/dist/time-input/root/time-input-root.d.ts +55 -7
  36. package/dist/time-input/root/time-input-root.js +70 -10
  37. package/dist/time-picker/root/time-picker-root.d.ts +27 -5
  38. package/dist/time-picker/root/time-picker-root.js +52 -13
  39. package/dist/timeline/item/timeline-item.d.ts +47 -10
  40. package/dist/timeline/item/timeline-item.js +36 -4
  41. package/dist/toggle/group/toggle-group.d.ts +18 -1
  42. package/dist/toggle/group/toggle-group.js +8 -2
  43. package/dist/toggle/root/toggle-root.d.ts +2 -2
  44. package/dist/toggle/root/toggle-root.js +2 -1
  45. package/dist/video-playlist/item/video-playlist-item.d.ts +11 -0
  46. package/dist/video-playlist/item/video-playlist-item.js +5 -0
  47. package/dist/video-playlist/menu/video-playlist-menu.d.ts +6 -0
  48. package/dist/video-playlist/menu/video-playlist-menu.js +11 -0
  49. package/dist/video-playlist/root/video-playlist-root.d.ts +59 -5
  50. package/dist/video-playlist/root/video-playlist-root.js +82 -10
  51. package/dist/virtual-list/fill.d.ts +6 -1
  52. package/dist/virtual-list/fill.js +1 -1
  53. package/dist/virtual-list/keys.d.ts +8 -0
  54. package/dist/virtual-list/keys.js +20 -0
  55. package/dist/virtual-list/root/virtual-list-root.d.ts +98 -13
  56. package/dist/virtual-list/root/virtual-list-root.js +195 -20
  57. package/lint.json +1 -1
  58. package/package.json +5 -5
  59. package/types/jsx.d.ts +1596 -224
  60. package/types/vue.d.ts +404 -49
  61. package/types/words.d.ts +151 -0
@@ -4,14 +4,14 @@ 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, formatWords, HelixElement, words } from '@fusion.dev/helix-core';
7
+ import { customElement, formatWords, HelixBeforeToggleEvent, HelixElement, HelixToggleEvent, requestChange, words, } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
10
  import { unsafeHTML } from 'lit/directives/unsafe-html.js';
11
11
  import { html } from 'lit/static-html.js';
12
12
  import '../../copy-button/index.js';
13
13
  import { highlightedLines } from '../highlight.js';
14
- import { gutterNumbers, lineCount } from '../lines.js';
14
+ import { gutterNumbers, lineCount, lineRuns, lineSpans } from '../lines.js';
15
15
  import { pairLines, parsePatch } from '../patch.js';
16
16
  let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
17
17
  constructor() {
@@ -28,12 +28,17 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
28
28
  this.label = '';
29
29
  this.language = '';
30
30
  this.lineNumbers = false;
31
+ this.markLines = '';
31
32
  this.noCopy = false;
33
+ this.wrap = false;
34
+ this.wrapLabel = 'Wrap lines';
35
+ this.wrappable = false;
32
36
  this.parsed = { files: [], text: '' };
33
37
  this.capped = false;
34
38
  this.expanded = false;
35
39
  this.measure = () => {
36
40
  this.markScrollers();
41
+ this.placeLines();
37
42
  if (!this.expanded) {
38
43
  this.capped =
39
44
  this.expandable &&
@@ -43,6 +48,20 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
43
48
  };
44
49
  }
45
50
  static { this.words = 'helix-code-block'; }
51
+ toggleWrap() {
52
+ const next = !this.wrap;
53
+ const applied = requestChange({
54
+ apply: (checked) => {
55
+ this.wrap = checked;
56
+ },
57
+ event: (checked) => new HelixBeforeToggleEvent({ checked }),
58
+ host: this,
59
+ next,
60
+ });
61
+ if (applied) {
62
+ this.dispatchEvent(new HelixToggleEvent({ checked: next }));
63
+ }
64
+ }
46
65
  get files() {
47
66
  if (!this.diff) {
48
67
  return [];
@@ -85,6 +104,89 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
85
104
  }
86
105
  }
87
106
  }
107
+ lineBoxes(code) {
108
+ const slot = code.querySelector('slot');
109
+ const roots = slot && !slot.hidden ? slot.assignedNodes({ flatten: true }) : [code];
110
+ const texts = [];
111
+ for (const root of roots) {
112
+ if (root.nodeType === Node.TEXT_NODE) {
113
+ texts.push(root);
114
+ continue;
115
+ }
116
+ const walker = (root.ownerDocument ?? document).createTreeWalker(root, NodeFilter.SHOW_TEXT);
117
+ for (let node = walker.nextNode(); node; node = walker.nextNode()) {
118
+ texts.push(node);
119
+ }
120
+ }
121
+ const starts = [];
122
+ let total = 0;
123
+ for (const text of texts) {
124
+ starts.push(total);
125
+ total += text.data.length;
126
+ }
127
+ const at = (offset) => {
128
+ for (let index = texts.length - 1; index >= 0; index -= 1) {
129
+ const start = starts[index] ?? 0;
130
+ if (offset >= start) {
131
+ const text = texts[index];
132
+ return [text, Math.min(offset - start, text.data.length)];
133
+ }
134
+ }
135
+ return undefined;
136
+ };
137
+ const box = code.getBoundingClientRect();
138
+ const origin = box.top + code.clientTop - code.scrollTop;
139
+ const row = Number.parseFloat(getComputedStyle(code).lineHeight) || 0;
140
+ const boxes = [];
141
+ for (const [from, to] of lineSpans(texts.map((text) => text.data).join(''))) {
142
+ const start = at(from);
143
+ const end = at(to === from ? Math.min(to + 1, total) : to);
144
+ const previous = boxes.at(-1);
145
+ let top = previous ? previous.bottom : 0;
146
+ let bottom = top + row;
147
+ if (start && end) {
148
+ const range = (code.ownerDocument ?? document).createRange();
149
+ range.setStart(start[0], start[1]);
150
+ range.setEnd(end[0], end[1]);
151
+ const rects = [...range.getClientRects()].filter((rect) => rect.height > 0);
152
+ if (rects.length > 0) {
153
+ const half = Math.max(0, (row - (rects[0]?.height ?? row)) / 2);
154
+ top = Math.min(...rects.map((rect) => rect.top)) - origin - half;
155
+ bottom = Math.max(...rects.map((rect) => rect.bottom)) - origin + half;
156
+ }
157
+ }
158
+ boxes.push({ bottom, top });
159
+ }
160
+ return boxes;
161
+ }
162
+ placeLines() {
163
+ const code = this.renderRoot.querySelector('[part="code"]');
164
+ const marks = [...this.renderRoot.querySelectorAll('[part="mark"]')];
165
+ const numbers = [
166
+ ...this.renderRoot.querySelectorAll('[part="gutter"] > [part="number"]'),
167
+ ];
168
+ if (!code || (marks.length === 0 && numbers.length === 0)) {
169
+ return;
170
+ }
171
+ const boxes = this.lineBoxes(code);
172
+ for (const mark of marks) {
173
+ const [first, last] = (mark.dataset.lines ?? '').split('-').map(Number);
174
+ const top = boxes[(first ?? 0) - 1];
175
+ const bottom = boxes[Math.min(last ?? 0, boxes.length) - 1];
176
+ mark.hidden = !top || !bottom;
177
+ if (top && bottom) {
178
+ mark.style.setProperty('--code-block-mark-start', `${top.top}px`);
179
+ mark.style.setProperty('--code-block-mark-size', `${bottom.bottom - top.top}px`);
180
+ mark.style.setProperty('--code-block-mark-inline-size', `${code.scrollWidth}px`);
181
+ }
182
+ }
183
+ numbers.forEach((number, index) => {
184
+ const line = boxes[index];
185
+ if (line) {
186
+ number.style.setProperty('--code-block-line-size', `${line.bottom - line.top}px`);
187
+ }
188
+ });
189
+ }
88
190
  updated(changed) {
89
191
  super.updated(changed);
90
192
  if (typeof ResizeObserver !== 'undefined') {
@@ -126,21 +228,29 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
126
228
  catch (error) {
127
229
  globalThis.reportError?.(error);
128
230
  }
231
+ const runs = this.childrenKnown ? lineRuns(this.markLines) : [];
232
+ const marks = runs.map(([first, last]) => html `<span part="mark" aria-hidden="true" data-lines="${first}-${last}"></span>`);
129
233
  const code = highlighted === undefined
130
- ? html `<code part="code"><slot @slotchange=${() => this.requestUpdate()}></slot></code>`
131
- : html `<code part="code">${unsafeHTML(highlighted)}</code><slot
234
+ ? html `<code part="code">${marks}<slot @slotchange=${() => this.requestUpdate()}></slot></code>`
235
+ : html `<code part="code">${marks}${unsafeHTML(highlighted)}</code><slot
132
236
  hidden
133
237
  @slotchange=${() => this.requestUpdate()}
134
238
  ></slot>`;
135
239
  const lines = lineCount(text);
240
+ const numbers = lines === 0
241
+ ? nothing
242
+ : this.wrap
243
+ ? Array.from({ length: lines }, (_, index) => html `<span part="number">${index + 1}
244
+ </span>`)
245
+ : gutterNumbers(lines);
136
246
  const gutter = this.lineNumbers
137
- ? html `<span part="gutter" aria-hidden="true">${lines === 0 ? nothing : gutterNumbers(lines)}</span>`
247
+ ? html `<span part="gutter" aria-hidden="true">${numbers}</span>`
138
248
  : nothing;
139
249
  const name = this.label || this.language;
140
250
  return html `${this.renderHeader(name)}
141
251
  <div part="frame">
142
252
  <pre id="block" part="block" translate="no">${gutter}${code}</pre>
143
- ${name ? nothing : this.renderCopy()}
253
+ ${this.headed(name) ? nothing : this.renderCopy()}
144
254
  </div>${this.renderExpand()}`;
145
255
  }
146
256
  renderExpand() {
@@ -160,11 +270,29 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
160
270
  ${this.expanded ? this.collapseLabel : this.expandLabel}
161
271
  </button>`;
162
272
  }
273
+ headed(name) {
274
+ return name !== '' || (this.wrappable && !this.diff) || this.slotted('actions');
275
+ }
163
276
  renderHeader(name, value) {
164
- return name
165
- ? html `<div part="header"><span part="label">${name}</span>${this.renderCopy(value, name)}</div>`
277
+ const acting = this.slotted('actions');
278
+ return this.headed(name)
279
+ ? html `<div part="header">${name ? html `<span part="label">${name}</span>` : nothing}${acting ? html `<span part="actions"><slot name="actions"></slot></span>` : nothing}${this.renderWrapToggle()}${this.renderCopy(value, name)}</div>`
166
280
  : nothing;
167
281
  }
282
+ renderWrapToggle() {
283
+ if (!this.wrappable || this.diff) {
284
+ return nothing;
285
+ }
286
+ return html `<button
287
+ part="wrap-toggle"
288
+ type="button"
289
+ aria-pressed=${this.wrap ? 'true' : 'false'}
290
+ @click=${() => this.toggleWrap()}
291
+ >${this.wrapLabel}</button>`;
292
+ }
293
+ slotted(name) {
294
+ return this.knownChildren.some((child) => child.getAttribute('slot') === name);
295
+ }
168
296
  renderCopy(value, name) {
169
297
  return this.noCopy ? nothing : this.renderCopyButton(value, name);
170
298
  }
@@ -179,7 +307,10 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
179
307
  copied-label=${this.copiedLabel}
180
308
  label=${name ? formatWords(this, 'copyNameLabel', { copy: this.copyLabel, name }) : this.copyLabel}
181
309
  .value=${value}
182
- ></${this.tag('copy-button')}>`;
310
+ >${this.renderCopyIcons()}</${this.tag('copy-button')}>`;
311
+ }
312
+ renderCopyIcons() {
313
+ return html `${this.slotted('copy-icon') ? html `<slot name="copy-icon"></slot>` : nothing}${this.slotted('copied-icon') ? html `<slot name="copied-icon" slot="copied"></slot>` : nothing}`;
183
314
  }
184
315
  renderNumber(value, width) {
185
316
  return html `<span part="number" aria-hidden="true">${String(value ?? '').padStart(width)} </span>`;
@@ -223,7 +354,7 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
223
354
  ${this.variant === 'split'
224
355
  ? this.renderSplit(file, width)
225
356
  : html `<pre part="block" translate="no"><code part="code">${file.hunks.map((hunk) => html `${this.renderHunk(hunk)}${hunk.lines.map((line) => this.renderLine(line, width))}`)}</code></pre>`}
226
- ${name ? nothing : this.renderCopy(now)}
357
+ ${this.headed(name) ? nothing : this.renderCopy(now)}
227
358
  </div>
228
359
  </div>`;
229
360
  })}<slot hidden @slotchange=${() => this.requestUpdate()}></slot>`;
@@ -275,12 +406,25 @@ __decorate([
275
406
  __decorate([
276
407
  property({ attribute: 'line-numbers', reflect: true, type: Boolean })
277
408
  ], HelixHeadlessCodeBlock.prototype, "lineNumbers", void 0);
409
+ __decorate([
410
+ property({ attribute: 'mark-lines' })
411
+ ], HelixHeadlessCodeBlock.prototype, "markLines", void 0);
278
412
  __decorate([
279
413
  property({ attribute: 'no-copy', reflect: true, type: Boolean })
280
414
  ], HelixHeadlessCodeBlock.prototype, "noCopy", void 0);
281
415
  __decorate([
282
416
  property({ reflect: true })
283
417
  ], HelixHeadlessCodeBlock.prototype, "variant", void 0);
418
+ __decorate([
419
+ property({ reflect: true, type: Boolean })
420
+ ], HelixHeadlessCodeBlock.prototype, "wrap", void 0);
421
+ __decorate([
422
+ words,
423
+ property({ attribute: 'wrap-label' })
424
+ ], HelixHeadlessCodeBlock.prototype, "wrapLabel", void 0);
425
+ __decorate([
426
+ property({ type: Boolean })
427
+ ], HelixHeadlessCodeBlock.prototype, "wrappable", void 0);
284
428
  __decorate([
285
429
  state()
286
430
  ], HelixHeadlessCodeBlock.prototype, "capped", void 0);
@@ -1,4 +1,4 @@
1
- import { AriaForwardController, type DateCalendar, HelixFormElement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, type DateCalendar, HelixFormElement, type MonthCalendar, type MonthSystem } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import '../../date-picker/index.js';
4
4
  import '../../tag/index.js';
@@ -15,17 +15,24 @@ declare const HelixHeadlessDateInput_base: (new (...args: any[]) => import("@fus
15
15
  * gives a picker and locale formatting but allows almost no styling, so the
16
16
  * field is a text field. Typing sends `input` on each keystroke and `change`
17
17
  * when you leave the field, as a text field does. A date picked from the
18
- * calendar sends both.
18
+ * calendar sends both. The field reads ISO, `2026-08-04`, and a date written
19
+ * in the order, the digits, and the month names of `locale`, `8/4/2026` or
20
+ * `Aug 4, 2026` in `en-US` and `4.8.2026` in `de-DE`, which becomes the value
21
+ * as you leave the field.
19
22
  *
20
23
  * The trigger and ArrowDown open the calendar with focus on the selected day,
21
24
  * Tab moves between the calendar's controls without leaving it, and Escape
22
25
  * closes it and returns focus to the field. A press into the field opens the
23
26
  * calendar too. Tab into the field opens nothing, and Tab out of the field
24
- * closes the calendar.
27
+ * closes the calendar. The text field is a `combobox` with
28
+ * `aria-haspopup="dialog"`, `aria-expanded`, and `aria-controls`, as in the
29
+ * APG date picker combobox, since Down opens the calendar from it.
25
30
  *
26
31
  * With `segmented`, the field is a row of segments in place of the text: a
27
32
  * month, a day and a year in the order the locale writes them, each set with
28
- * digits or the arrow keys. Alt+Down opens the calendar from a segment.
33
+ * digits or the arrow keys. Alt+Down opens the calendar from a segment. A
34
+ * `range` is two rows with a dash between them, the start and the end, as
35
+ * React Aria's DateRangePicker draws them, and `multiple` keeps the text.
29
36
  *
30
37
  * Text that is not a date gives the form an empty value, as a native date
31
38
  * field does, and `value` keeps the text so it can be corrected.
@@ -57,6 +64,7 @@ declare const HelixHeadlessDateInput_base: (new (...args: any[]) => import("@fus
57
64
  * @aliases DatePicker, DateField, InputDate
58
65
  * @documentation https://fusion.dev/helix/components/date-input
59
66
  *
67
+ * @slot clear-icon - Replaces the cross on the clear button, under `clearable`.
60
68
  * @slot end - Content after the date, before the trigger, such as a clear button.
61
69
  * @slot feedback - The error message under the field.
62
70
  * @slot hint - The help text under the field.
@@ -72,9 +80,11 @@ declare const HelixHeadlessDateInput_base: (new (...args: any[]) => import("@fus
72
80
  * @event {HelixBeforeChangeEvent} helix-before-change - Fired before the date changes. Cancelable: call `preventDefault()` to keep the current date.
73
81
  * @event {HelixBeforeCloseEvent} helix-before-close - Fired before the calendar closes. Cancelable: call `preventDefault()` to keep it open.
74
82
  * @event {HelixBeforeOpenEvent} helix-before-open - Fired before the calendar opens. Cancelable: call `preventDefault()` to keep it closed.
83
+ * @event {HelixClearEvent} helix-clear - Fired after the clear button has emptied the field, after `input` and `change`.
75
84
  * @event {Event} input - Fired after the value changes.
76
85
  * @event {ToggleEvent} toggle - Fired when the calendar opens or closes, with `newState` and `oldState`.
77
86
  *
87
+ * @csspart clear - The button that empties the field, under `clearable`, while it holds a date.
78
88
  * @csspart control - The text input.
79
89
  * @csspart date - One held date, as a tag, in `multiple`.
80
90
  * @csspart date-cell - The tag's grid cell, which a tag draws only inside a tag group.
@@ -116,8 +126,10 @@ declare const HelixHeadlessDateInput_base: (new (...args: any[]) => import("@fus
116
126
  * @csspart picker-periods - The grid of months or years.
117
127
  * @csspart picker-previous - The control that moves to the previous month.
118
128
  * @csspart picker-previous-mark - The icon on the previous month control.
129
+ * @csspart picker-selection - The chosen date or range in words, which screen readers hear when it changes. Drawn for screen readers only.
119
130
  * @csspart picker-week - One row of days.
120
131
  * @csspart picker-weekday - A column header naming a day of the week.
132
+ * @csspart range-separator - The dash between a range's two rows of segments, in `segmented`, beside `literal`.
121
133
  * @csspart rest - The count of dates beyond the ones shown. It is a `<button>` with `expandable` and a `<span>` without it.
122
134
  * @csspart segment - One part of the date, a year, a month or a day, in `segmented`.
123
135
  * @csspart segment-placeholder - A segment with nothing in it yet. Applied with `segment`.
@@ -127,6 +139,7 @@ declare const HelixHeadlessDateInput_base: (new (...args: any[]) => import("@fus
127
139
  * @csspart trigger - The control that opens the calendar.
128
140
  * @csspart trigger-icon - The icon on the button that opens the calendar.
129
141
  *
142
+ * @cssstate blank - The field holds no date.
130
143
  * @cssstate invalid - The field has an error to show, from the browser's validation or from your `feedback`.
131
144
  * @cssstate open - The calendar is open.
132
145
  */
@@ -138,28 +151,43 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
138
151
  static words: string;
139
152
  protected readonly aria: AriaForwardController;
140
153
  /**
141
- * What the browser may autofill here, as one of the platform's own tokens.
154
+ * What the browser may autofill here, as one of the platform's own tokens,
155
+ * such as `bday`.
142
156
  *
143
157
  * Empty leaves the attribute off, which is the browser's default and is what
144
158
  * lets autofill work at all: hardcoding `off` here means a birthday or a
145
- * postal code can never be filled in for a reader.
159
+ * postal code can never be filled in for a reader. With `segmented`, a
160
+ * hidden native date input carries it, since no browser fills the segments.
146
161
  */
147
162
  autocomplete: string;
148
163
  /**
149
- * The calendar the written date and the calendar's days are in: `gregory`,
150
- * `buddhist`, `japanese`, `roc`, or `iso8601`.
164
+ * The calendar the written date, the segments, and the calendar's days are
165
+ * in: `gregory`, `buddhist`, `japanese`, `roc`, or `iso8601`, or a calendar
166
+ * with months of its own that Date Picker's `calendar` names, such as
167
+ * `persian`, `hebrew`, `islamic-umalqura`, `ethiopic`, or `chinese`.
151
168
  *
152
- * Absent is the locale's own where it is one of the five, and `gregory` for
153
- * every other, as Date Picker's `calendar` is. The value is `YYYY-MM-DD` in
154
- * every calendar, and a focused field is ISO in every calendar. In
155
- * `segmented`, the segments are the Gregorian day, month, and year, in the
156
- * order the locale writes them, or ISO order for `iso8601`.
169
+ * Absent is the locale's own where its months are the Gregorian months, and
170
+ * `gregory` for every other, as Date Picker's `calendar` is. The value is
171
+ * `YYYY-MM-DD` in every calendar, and a focused text field is ISO in every
172
+ * calendar. In `segmented`, the segments are the day, month, and year as
173
+ * the calendar counts them, in the order the locale writes them: Mehr 14,
174
+ * 1405 is month 7 and day 14 of 1405 under `persian`. Under the five with
175
+ * Gregorian months they are the Gregorian day, month, and year, or ISO order
176
+ * for `iso8601`.
157
177
  */
158
- calendar?: DateCalendar;
178
+ calendar?: DateCalendar | MonthCalendar;
159
179
  /**
160
180
  * The name of the calendar's grid of days, read by screen readers.
161
181
  */
162
182
  calendarLabel: string;
183
+ /**
184
+ * Whether the field shows a button that empties it, as Input's `clearable`
185
+ * does. Shown only while the field holds something to clear and is neither
186
+ * disabled nor read-only.
187
+ */
188
+ clearable: boolean;
189
+ /** The accessible name of the clear button, which shows only an icon. */
190
+ clearLabel: string;
163
191
  /** Typed, so a keystroke is announced as `input` alone. See `announcesInput`. */
164
192
  protected readonly announcesInput = true;
165
193
  /**
@@ -168,8 +196,9 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
168
196
  * **The field renders when it is idle and holds the value when it is being
169
197
  * edited.** A written date is a rendering, and a document being edited must
170
198
  * not be a rendering of something else: `Intl.DateTimeFormat` formats and does
171
- * not parse, so `4 August 2026` cannot be typed back, and writing a parser per
172
- * locale is how a field ends up rejecting what it just displayed.
199
+ * not parse, so a rendering such as `Tuesday, August 4, 2026` is no text to
200
+ * edit. The field does read a date typed in the locale's order and digits as
201
+ * you leave it, which covers what a reader types.
173
202
  *
174
203
  * The way out is not to choose between the two but to separate them in time.
175
204
  * Idle, the field shows `4 August 2026`, which is what a date is for reading.
@@ -348,6 +377,12 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
348
377
  * removes rather than as "Remove" said once per date.
349
378
  */
350
379
  removeLabel: string;
380
+ /**
381
+ * What a screen reader hears about the dates chosen in the calendar, with
382
+ * `{kind}`, `{start}`, `{end}` and `{count}` filled in as Date Picker's
383
+ * `selection-label` says.
384
+ */
385
+ selectionLabel: string;
351
386
  /**
352
387
  * How far apart the selectable dates are, in days.
353
388
  *
@@ -361,6 +396,12 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
361
396
  * The message shown when a date is not on `step`.
362
397
  */
363
398
  stepMismatchMessage: string;
399
+ /**
400
+ * The time zone today is read in, such as `America/New_York`, handed to the
401
+ * calendar: the day marked today, and the month an empty field opens on.
402
+ * Empty is the reader's own. Dates are plain `YYYY-MM-DD` and carry no zone.
403
+ */
404
+ timeZone: string;
364
405
  /**
365
406
  * The name of the button that opens the calendar, read by screen readers.
366
407
  */
@@ -375,17 +416,23 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
375
416
  */
376
417
  private get picked();
377
418
  /**
378
- * Segments hold one date, so `range` and `multiple` keep the line of text,
379
- * whose separators and tags are how those modes write several.
419
+ * A row of segments holds one date, and `range` takes two rows with a dash
420
+ * between them, as React Aria's range fields do. `multiple` keeps the line
421
+ * of text, whose tags are how it writes several.
380
422
  */
381
423
  protected get segmentable(): boolean;
424
+ protected get segmentGroups(): number;
382
425
  protected get segmentedKind(): 'date';
383
426
  /**
384
427
  * The segments are the Gregorian day, month and year, which is what they
385
428
  * hold, in ISO order where the calendar is `iso8601`. A year shown as 2569
386
- * or Reiwa 8 would be a year the segment does not hold.
429
+ * or Reiwa 8 would be a year the segment does not hold. Under a calendar
430
+ * with months of its own they hold that calendar's parts, so they are laid
431
+ * out and named in it.
387
432
  */
388
433
  protected get segmentLocale(): string;
434
+ /** The calendar the segments count in, where it has months of its own. */
435
+ protected get segmentSystem(): MonthSystem | undefined;
389
436
  /** One date, written the way `dateStyle` asks for. */
390
437
  private written;
391
438
  protected get display(): string;
@@ -401,6 +448,20 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
401
448
  private draft;
402
449
  /** Relayed under this element's name, so a consumer hears one control. */
403
450
  private readonly handleInput;
451
+ /**
452
+ * A date as the reader wrote it, as `YYYY-MM-DD`: ISO as it is, and the
453
+ * order, the digits, and the month names of the field's locale and calendar
454
+ * read back, so `8/4/2026` in `en-US` is August 4, 2026. Empty where it is
455
+ * no date.
456
+ */
457
+ private read;
458
+ /**
459
+ * The text the reader leaves, read in the field's locale: a date written as
460
+ * the locale writes one becomes the value, as ISO, when the field commits.
461
+ * Not on each key, where `8/4/202` is a date in the year 202 and taking it
462
+ * would move the caret mid-year.
463
+ */
464
+ private readonly handleTextCommit;
404
465
  /** Adds what was typed to the set, or takes the last one back out. */
405
466
  private readonly handleDraftKey;
406
467
  /** The dates that get a tag, which is all of them until the cap says not. */
@@ -423,6 +484,11 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
423
484
  * The message shown when `disable-dates` or `disable-days` bars a date.
424
485
  */
425
486
  unavailableMessage: string;
487
+ /**
488
+ * The message for text that is no date, where `bad-input-message` is not
489
+ * set. `{mode}` is `single`, `range`, or `multiple`.
490
+ */
491
+ unreadableMessage: string;
426
492
  /**
427
493
  * The name of the calendar's heading where it shows a page of years, with
428
494
  * `{heading}` filled in.
@@ -477,6 +543,29 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
477
543
  * and no mark whatsoever.
478
544
  */
479
545
  protected renderTrigger(): TemplateResult;
546
+ /**
547
+ * A native date input a browser's autofill can fill, where the field shows
548
+ * segments: a row of spans that no browser fills. React Aria's
549
+ * `HiddenDateInput` is the same answer for its segmented field.
550
+ *
551
+ * Drawn and never seen, a pixel and see-through, as Select's hidden select
552
+ * is, since Safari skips a field that is `display: none`. `aria-hidden` and
553
+ * out of the tab order, and in this shadow root, so the form still takes
554
+ * the value once, from the host. A fill is taken as a pick, with `input`
555
+ * and `change` from the host.
556
+ */
557
+ private renderAutofill;
558
+ private readonly handleAutofill;
559
+ /** Whether there is a clear button on screen right now. */
560
+ private get showsClear();
561
+ /**
562
+ * Empties the field, through `requestValue` so a consumer who owns the
563
+ * value decides, then says `change` and `helix-clear` and puts focus back
564
+ * in the field, the button having gone.
565
+ */
566
+ private readonly handleClear;
567
+ /** The cross on the clear button, behind a seam a tier can move. */
568
+ protected renderClearIcon(): TemplateResult;
480
569
  /** The line of text the dates are typed into, where the field shows no segments. */
481
570
  private renderControl;
482
571
  protected render(): TemplateResult;