@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,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 { addDays, addMonths, valueAsDate as asDate, barredBy, calendarLocale, customElement, formatWords, dateAsValue as fromDate, HelixFormElement, HelixNavigateEvent, handedLocale, hostAria, inlineStep, commaList as list, MixinControllerValue, MixinPickerFeedback, MONTH_CALENDARS, monthOf, monthOut, monthSystem, periodCells, periodKey, reportValues, requestChange, todayIn, weekendOf, weekStartOf, words, wordsLocale, YEARS_SHOWN, yearOut, yearPageOf, } from '@fusion.dev/helix-core';
7
+ import { addDays, addMonths, valueAsDate as asDate, barredBy, calendarLocale, customElement, formatWords, dateAsValue as fromDate, HelixFormElement, HelixNavigateEvent, handedLocale, hostAria, inlineStep, commaList as list, MixinControllerValue, MixinPickerFeedback, monthOut, monthSystem, periodCells, periodKey, reportValues, requestChange, todayIn, weekendOf, weekStartOf, words, wordsLocale, YEARS_SHOWN, yearOut, yearPageOf, } from '@fusion.dev/helix-core';
8
8
  import { caretLeft, caretRight } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -34,6 +34,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
34
34
  this.max = '';
35
35
  this.min = '';
36
36
  this.monthState = undefined;
37
+ this.browsed = false;
37
38
  this.months = 1;
38
39
  this.monthViewLabel = '{heading}. Choose a month';
39
40
  this.nextLabel = 'Next month';
@@ -45,8 +46,12 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
45
46
  this.rangeOverflowMessage = 'Choose a date on or before {max}.';
46
47
  this.focused = '';
47
48
  this.choosing = false;
49
+ this.previewed = '';
50
+ this.handleGridLeave = () => {
51
+ this.previewed = '';
52
+ };
48
53
  this.handleKeydown = (event) => {
49
- if (this.view !== 'day' && !this.ownMonths) {
54
+ if (this.view !== 'day') {
50
55
  this.handlePeriodKeydown(event);
51
56
  return;
52
57
  }
@@ -80,7 +85,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
80
85
  }
81
86
  else {
82
87
  const step = event.key === 'PageUp' ? -1 : 1;
83
- this.moveTo(this.system.add(from, event.shiftKey ? step * 12 : step));
88
+ this.moveTo(event.shiftKey ? this.system.addYears(from, step) : this.system.add(from, step));
84
89
  }
85
90
  event.preventDefault();
86
91
  };
@@ -91,8 +96,9 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
91
96
  return;
92
97
  }
93
98
  if (this.view === 'day') {
94
- this.pageYear = this.shown.getUTCFullYear();
95
- this.periodFocus = this.shown.getUTCMonth();
99
+ const { month, year } = this.system.parts(this.shown);
100
+ this.pageYear = year;
101
+ this.periodFocus = month - 1;
96
102
  this.zoom('month');
97
103
  }
98
104
  else if (this.view === 'month' && this.maxView === 'year') {
@@ -103,6 +109,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
103
109
  this.rangeUnderflowMessage = 'Choose a date on or after {min}.';
104
110
  this.readOnly = false;
105
111
  this.required = false;
112
+ this.selectionLabel = '{kind, select, date {Selected date: {start}} start {Range starts {start}. Choose the day it ends.} range {Selected range: {start} to {end}} other {{count, plural, one {# date selected} other {# dates selected}}}}';
106
113
  this.step = 1;
107
114
  this.stepMismatchMessage = 'Choose one of the dates the calendar offers.';
108
115
  this.timeZone = '';
@@ -120,6 +127,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
120
127
  }
121
128
  set month(next) {
122
129
  const previous = this.month;
130
+ this.browsed = false;
123
131
  this.monthState = next;
124
132
  this.requestUpdate('month', previous);
125
133
  }
@@ -143,6 +151,30 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
143
151
  const [first, second] = [dates[0], dates[1]];
144
152
  return first <= second ? [first, second] : [second, first];
145
153
  }
154
+ get pending() {
155
+ return this.mode === 'range' && this.selected.length === 1;
156
+ }
157
+ get drawnRange() {
158
+ const range = this.range;
159
+ if (range) {
160
+ return { ends: range, preview: false };
161
+ }
162
+ const end = this.previewed || this.focused;
163
+ const start = this.selected[0];
164
+ if (!this.pending ||
165
+ start === undefined ||
166
+ end === '' ||
167
+ end === start ||
168
+ asDate(end) === null) {
169
+ return null;
170
+ }
171
+ return { ends: start <= end ? [start, end] : [end, start], preview: true };
172
+ }
173
+ preview(iso) {
174
+ if (this.pending && iso !== this.previewed) {
175
+ this.previewed = iso;
176
+ }
177
+ }
146
178
  isSelected(iso) {
147
179
  const range = this.range;
148
180
  if (range) {
@@ -161,9 +193,6 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
161
193
  get system() {
162
194
  return monthSystem(this.calendar);
163
195
  }
164
- get ownMonths() {
165
- return MONTH_CALENDARS.includes(this.calendar ?? '');
166
- }
167
196
  get derivedMonth() {
168
197
  const from = asDate(this.selected[0] ?? '') ?? asDate(todayIn(this.timeZone)) ?? new Date();
169
198
  return this.system.start(from);
@@ -226,6 +255,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
226
255
  requestChange({
227
256
  apply: (month) => {
228
257
  const previous = this.month;
258
+ this.browsed = true;
229
259
  this.monthState = month;
230
260
  this.requestUpdate('month', previous);
231
261
  },
@@ -237,6 +267,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
237
267
  moveTo(wanted) {
238
268
  const date = this.clamp(wanted);
239
269
  this.focused = fromDate(date);
270
+ this.previewed = '';
240
271
  this.show(date);
241
272
  this.updateComplete.then(() => {
242
273
  this.renderRoot.querySelector('[part~="cell"][tabindex="0"]')?.focus();
@@ -262,23 +293,25 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
262
293
  next = [iso];
263
294
  }
264
295
  this.focused = iso;
296
+ this.previewed = '';
265
297
  this.choosing = true;
266
298
  this.requestValue(next.join(','));
267
299
  }
268
300
  get periodYear() {
269
- return this.pageYear ?? this.shown.getUTCFullYear();
301
+ return this.pageYear ?? this.system.parts(this.shown).year;
270
302
  }
271
303
  get periodStop() {
272
- if (this.periodFocus !== undefined) {
273
- return this.periodFocus;
304
+ if (this.view === 'year') {
305
+ return this.periodFocus ?? this.periodYear;
274
306
  }
275
- return this.view === 'year' ? this.periodYear : this.shown.getUTCMonth();
307
+ const index = this.periodFocus ?? this.system.parts(this.shown).month - 1;
308
+ return Math.min(index, this.system.months(this.periodYear) - 1);
276
309
  }
277
310
  monthOut(first) {
278
- return monthOut(first, this.min, this.max);
311
+ return monthOut(first, this.min, this.max, this.system);
279
312
  }
280
313
  yearOut(year) {
281
- return yearOut(year, this.min, this.max);
314
+ return yearOut(year, this.min, this.max, this.system);
282
315
  }
283
316
  zoom(view) {
284
317
  this.view = view;
@@ -293,8 +326,8 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
293
326
  return;
294
327
  }
295
328
  this.pageYear = at;
296
- const month = this.shown.getUTCMonth();
297
- const open = Array.from({ length: 12 }, (_, index) => index).filter((index) => !this.monthOut(firstOf(at, index)));
329
+ const month = this.system.parts(this.shown).month - 1;
330
+ const open = Array.from({ length: this.system.months(at) }, (_, index) => index).filter((index) => !this.monthOut(this.system.from(at, index + 1, 1)));
298
331
  this.periodFocus = open.includes(month)
299
332
  ? month
300
333
  : ([...open].sort((left, right) => Math.abs(left - month) - Math.abs(right - month))[0] ??
@@ -302,12 +335,12 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
302
335
  this.zoom('month');
303
336
  return;
304
337
  }
305
- const first = firstOf(this.periodYear, at);
338
+ const first = this.system.from(this.periodYear, at + 1, 1);
306
339
  if (this.monthOut(first)) {
307
340
  return;
308
341
  }
309
342
  this.show(first);
310
- if (this.month !== monthOf(first)) {
343
+ if (this.month !== this.system.key(first)) {
311
344
  return;
312
345
  }
313
346
  this.pageYear = undefined;
@@ -344,7 +377,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
344
377
  this.choosePeriod(stop);
345
378
  return;
346
379
  }
347
- const moved = periodKey(this.view === 'year' ? 'year' : 'month', stop, this.periodYear, event.key, inlineStep(this, event.key));
380
+ const moved = periodKey(this.view === 'year' ? 'year' : 'month', stop, this.periodYear, event.key, inlineStep(this, event.key), (year) => this.system.months(year));
348
381
  if (moved === null) {
349
382
  return;
350
383
  }
@@ -354,10 +387,26 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
354
387
  void this.updateComplete.then(() => this.focus());
355
388
  }
356
389
  focus(options) {
390
+ if (this.isUpdatePending) {
391
+ void this.updateComplete.then(() => this.focus(options));
392
+ return;
393
+ }
357
394
  this.renderRoot
358
395
  ?.querySelector('[part~="cell"][tabindex="0"], [part~="period"][tabindex="0"]')
359
396
  ?.focus(options);
360
397
  }
398
+ showChosen() {
399
+ this.focused = '';
400
+ this.pageYear = undefined;
401
+ this.periodFocus = undefined;
402
+ this.view = 'day';
403
+ if (this.browsed) {
404
+ this.browsed = false;
405
+ const previous = this.month;
406
+ this.monthState = undefined;
407
+ this.requestUpdate('month', previous);
408
+ }
409
+ }
361
410
  connectedCallback() {
362
411
  super.connectedCallback();
363
412
  this.addEventListener('keydown', this.handleKeydown);
@@ -372,6 +421,28 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
372
421
  }
373
422
  return super.requestValue(next);
374
423
  }
424
+ get selectionWords() {
425
+ const dates = this.selected.map((one) => asDate(one));
426
+ const first = dates[0];
427
+ if (!first || dates.some((one) => one === null)) {
428
+ return '';
429
+ }
430
+ const { long } = this.formats;
431
+ const range = this.range;
432
+ const kind = range
433
+ ? 'range'
434
+ : this.pending
435
+ ? 'start'
436
+ : this.mode === 'multiple'
437
+ ? 'dates'
438
+ : 'date';
439
+ return formatWords(this, 'selectionLabel', {
440
+ count: dates.length,
441
+ end: range ? long.format(asDate(range[1])) : '',
442
+ kind,
443
+ start: long.format(range ? asDate(range[0]) : first),
444
+ });
445
+ }
375
446
  spoken(iso) {
376
447
  const date = asDate(iso);
377
448
  return date ? this.formats.long.format(date) : iso;
@@ -399,24 +470,38 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
399
470
  : ['stepMismatch', this.stepMismatchMessage];
400
471
  }
401
472
  reportRequired() {
402
- const anchor = this.partNamed('grid') ?? undefined;
403
- if (this.required && this.value === '') {
404
- this.internals.setValidity({ valueMissing: true }, this.valueMissingMessage, anchor);
473
+ const problem = this.problem;
474
+ if (problem) {
475
+ this.internals.setValidity(problem[0], problem[1], this.partNamed('grid') ?? undefined);
405
476
  return;
406
477
  }
478
+ this.internals.setValidity({});
479
+ }
480
+ get problem() {
481
+ if (this.required && this.value === '') {
482
+ return [{ valueMissing: true }, this.valueMissingMessage];
483
+ }
407
484
  const held = this.selected;
408
485
  if (held.length > 0 && held.some((one) => asDate(one) === null)) {
409
- this.internals.setValidity({ badInput: true }, formatWords(this, 'badInputMessage', { mode: this.mode ?? 'single' }), anchor);
410
- return;
486
+ return [
487
+ { badInput: true },
488
+ formatWords(this, 'badInputMessage', { mode: this.mode ?? 'single' }),
489
+ ];
411
490
  }
412
491
  for (const one of held) {
413
492
  const fault = this.fault(one);
414
493
  if (fault) {
415
- this.internals.setValidity({ [fault[0]]: true }, fault[1], anchor);
416
- return;
494
+ return [{ [fault[0]]: true }, fault[1]];
417
495
  }
418
496
  }
419
- this.internals.setValidity({});
497
+ return undefined;
498
+ }
499
+ get failure() {
500
+ const problem = this.problem;
501
+ if (!problem) {
502
+ return undefined;
503
+ }
504
+ return problem[0].valueMissing ? 'missing' : 'refused';
420
505
  }
421
506
  willUpdate(changed) {
422
507
  super.willUpdate(changed);
@@ -431,6 +516,10 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
431
516
  role: 'group',
432
517
  });
433
518
  this.internals.ariaDisabled = this.isDisabled ? 'true' : null;
519
+ this.toggleState('blank', this.value === '');
520
+ this.toggleState('range-pending', this.pending);
521
+ this.toggleState('month-view', this.view === 'month');
522
+ this.toggleState('year-view', this.view === 'year');
434
523
  this.report();
435
524
  }
436
525
  updated(changed) {
@@ -448,9 +537,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
448
537
  return Math.max(1, Math.floor(this.months) || 1);
449
538
  }
450
539
  get formats() {
451
- const language = this.ownMonths
452
- ? `${new Intl.Locale(this.language || new Intl.DateTimeFormat().resolvedOptions().locale, { calendar: this.calendar ?? 'gregory' })}`
453
- : calendarLocale(this.language, this.calendar);
540
+ const language = calendarLocale(this.language, this.calendar);
454
541
  if (this.cachedFormats?.locale === language) {
455
542
  return this.cachedFormats;
456
543
  }
@@ -489,7 +576,9 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
489
576
  const weeks = this.weeksOf(month);
490
577
  const anchor = fromDate(this.anchor);
491
578
  const today = todayIn(this.timeZone);
492
- const range = this.range;
579
+ const drawn = this.drawnRange;
580
+ const range = drawn?.ends ?? null;
581
+ const preview = drawn?.preview === true;
493
582
  const weekend = this.weekend;
494
583
  const first = index === 0;
495
584
  const last = index === this.monthCount - 1;
@@ -526,8 +615,11 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
526
615
  part="grid"
527
616
  role="grid"
528
617
  aria-label=${heading}
618
+ aria-describedby=${this.selectionWords === '' ? nothing : 'selection'}
619
+ aria-multiselectable=${this.mode === undefined ? nothing : 'true'}
529
620
  aria-readonly=${this.readOnly ? 'true' : nothing}
530
621
  data-unset=${this.value === '' ? '' : nothing}
622
+ @pointerleave=${this.handleGridLeave}
531
623
  >
532
624
  <div part="week" role="row">
533
625
  ${weeks[0]?.map((date) => html `<span part="weekday" role="columnheader" aria-label=${weekdayName.format(date)}
@@ -553,11 +645,13 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
553
645
  data-outside=${outside ? '' : nothing}
554
646
  data-range-end=${end ? '' : nothing}
555
647
  data-range-middle=${middle ? '' : nothing}
648
+ data-range-preview=${preview && (start || middle || end) ? '' : nothing}
556
649
  data-range-start=${start ? '' : nothing}
557
650
  data-today=${iso === today ? '' : nothing}
558
651
  data-weekend=${weekend.includes(date.getUTCDay()) ? '' : nothing}
559
652
  tabindex=${!outside && iso === anchor && !this.isDisabled ? '0' : '-1'}
560
653
  @click=${outside ? nothing : () => this.select(date)}
654
+ @pointerenter=${outside ? nothing : () => this.preview(iso)}
561
655
  ><span
562
656
  part="day${!outside && selected && !middle ? ' day-selected' : ''}${iso === today ? ' day-today' : ''}${outside ? ' day-outside' : ''}${disabled ? ' day-disabled' : ''}${weekend.includes(date.getUTCDay()) ? ' day-weekend' : ''}"
563
657
  >${this.renderDay(date, outside)}</span
@@ -573,7 +667,6 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
573
667
  }
574
668
  renderHeadingText(text, label) {
575
669
  const steps = this.maxView !== undefined &&
576
- !this.ownMonths &&
577
670
  (this.view === 'day' || (this.view === 'month' && this.maxView === 'year'));
578
671
  if (!steps) {
579
672
  return text;
@@ -591,14 +684,15 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
591
684
  const years = this.view === 'year';
592
685
  const page = years ? yearPageOf(this.periodYear) : this.periodYear;
593
686
  const heading = years
594
- ? `${yearName.format(firstOf(page, 0))} – ${yearName.format(firstOf(page + YEARS_SHOWN - 1, 0))}`
595
- : yearName.format(firstOf(page, 0));
687
+ ? `${yearName.format(this.system.from(page, 1, 1))} – ${yearName.format(this.system.from(page + YEARS_SHOWN - 1, 1, 1))}`
688
+ : yearName.format(this.system.from(page, 1, 1));
596
689
  const stop = this.periodStop;
597
690
  const cells = periodCells({
598
691
  max: this.max,
599
692
  min: this.min,
600
693
  page: this.periodYear,
601
694
  shown: this.shown,
695
+ system: this.system,
602
696
  today: todayIn(this.timeZone),
603
697
  view: years ? 'year' : 'month',
604
698
  }).map(({ at, chosen, current, first, out }) => {
@@ -615,7 +709,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
615
709
  >${words}</span
616
710
  >`;
617
711
  });
618
- const rows = [0, 3, 6, 9].map((from) => html `<div part="period-row" role="row">${cells.slice(from, from + 3)}</div>`);
712
+ const rows = Array.from({ length: Math.ceil(cells.length / 3) }, (_, row) => row * 3).map((from) => html `<div part="period-row" role="row">${cells.slice(from, from + 3)}</div>`);
619
713
  return html `<div part="month">
620
714
  <div part="header">
621
715
  <button
@@ -644,7 +738,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
644
738
  </div>`;
645
739
  }
646
740
  render() {
647
- if (this.view !== 'day' && !this.ownMonths) {
741
+ if (this.view !== 'day') {
648
742
  return html `<slot name="header"></slot>
649
743
  <div part="months" style="--date-picker-column-count: 1">${this.renderPeriods()}</div>
650
744
  <slot name="footer"></slot>${this.renderPickerFeedback()}`;
@@ -655,6 +749,9 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
655
749
  <div part="months" style="--date-picker-column-count: ${Math.min(count, 2)}">
656
750
  ${Array.from({ length: count }, (_, index) => this.renderMonth(this.system.add(shown, index), index))}
657
751
  </div>
752
+ <span part="selection" id="selection" data-spoken aria-live="polite"
753
+ >${this.selectionWords}</span
754
+ >
658
755
  <slot name="footer"></slot>${this.renderPickerFeedback()}`;
659
756
  }
660
757
  get valueAsDate() {
@@ -755,6 +852,9 @@ __decorate([
755
852
  __decorate([
756
853
  state()
757
854
  ], HelixHeadlessDatePicker.prototype, "focused", void 0);
855
+ __decorate([
856
+ state()
857
+ ], HelixHeadlessDatePicker.prototype, "previewed", void 0);
758
858
  __decorate([
759
859
  state()
760
860
  ], HelixHeadlessDatePicker.prototype, "pageYear", void 0);
@@ -771,6 +871,10 @@ __decorate([
771
871
  __decorate([
772
872
  property({ reflect: true, type: Boolean })
773
873
  ], HelixHeadlessDatePicker.prototype, "required", void 0);
874
+ __decorate([
875
+ words,
876
+ property({ attribute: 'selection-label' })
877
+ ], HelixHeadlessDatePicker.prototype, "selectionLabel", void 0);
774
878
  __decorate([
775
879
  property({ type: Number })
776
880
  ], HelixHeadlessDatePicker.prototype, "step", void 0);
@@ -36,6 +36,7 @@ registerElementEvents({
36
36
  'helix-headless-chat-message': ['helix-send'],
37
37
  'helix-headless-checkbox': ['change', 'helix-before-toggle', 'input'],
38
38
  'helix-headless-checkbox-group': ['change', 'helix-before-change', 'input'],
39
+ 'helix-headless-code-block': ['helix-before-toggle', 'helix-toggle'],
39
40
  'helix-headless-color-input': [
40
41
  'change',
41
42
  'helix-before-change',
@@ -92,6 +93,7 @@ registerElementEvents({
92
93
  'helix-before-change',
93
94
  'helix-before-close',
94
95
  'helix-before-open',
96
+ 'helix-clear',
95
97
  'input',
96
98
  'toggle',
97
99
  ],
@@ -252,11 +254,14 @@ registerElementEvents({
252
254
  'helix-headless-tab-panel': ['helix-load'],
253
255
  'helix-headless-table': [
254
256
  'helix-before-reorder',
257
+ 'helix-before-toggle',
258
+ 'helix-load-more',
255
259
  'helix-reorder',
256
260
  'helix-select',
257
261
  'helix-selected',
258
262
  'helix-sort',
259
263
  'helix-sorted',
264
+ 'helix-toggle',
260
265
  ],
261
266
  'helix-headless-table-column': ['helix-before-resize', 'helix-resized'],
262
267
  'helix-headless-tabs': ['helix-activate', 'helix-before-activate', 'helix-select'],
@@ -268,6 +273,7 @@ registerElementEvents({
268
273
  'helix-before-change',
269
274
  'helix-before-close',
270
275
  'helix-before-open',
276
+ 'helix-clear',
271
277
  'input',
272
278
  'toggle',
273
279
  ],
@@ -3,6 +3,7 @@ export const FIELD = {
3
3
  day: (value) => html `<span part="day">${value}</span>`,
4
4
  dayPeriod: (value) => html `<span part="day-period">${value}</span>`,
5
5
  era: (value) => html `<span part="era">${value}</span>`,
6
+ fractionalSecond: (value) => html `<span part="fractional-second">${value}</span>`,
6
7
  hour: (value) => html `<span part="hour">${value}</span>`,
7
8
  minute: (value) => html `<span part="minute">${value}</span>`,
8
9
  month: (value) => html `<span part="month">${value}</span>`,
@@ -5,7 +5,9 @@
5
5
  export interface Asked {
6
6
  dateStyle?: 'full' | 'long' | 'medium' | 'short' | undefined;
7
7
  day?: 'numeric' | '2-digit' | undefined;
8
+ dayPeriod?: 'long' | 'narrow' | 'short' | undefined;
8
9
  era?: 'long' | 'narrow' | 'short' | undefined;
10
+ fractionalSecondDigits?: 1 | 2 | 3 | undefined;
9
11
  hour?: 'numeric' | '2-digit' | undefined;
10
12
  hourCycle?: 'h11' | 'h12' | 'h23' | 'h24' | undefined;
11
13
  minute?: 'numeric' | '2-digit' | undefined;
@@ -13,7 +15,7 @@ export interface Asked {
13
15
  second?: 'numeric' | '2-digit' | undefined;
14
16
  timeStyle?: 'full' | 'long' | 'medium' | 'short' | undefined;
15
17
  timeZone?: string | undefined;
16
- timeZoneName?: 'long' | 'short' | undefined;
18
+ timeZoneName?: 'long' | 'longGeneric' | 'longOffset' | 'short' | 'shortGeneric' | 'shortOffset' | undefined;
17
19
  weekday?: 'long' | 'short' | 'narrow' | undefined;
18
20
  year?: 'numeric' | '2-digit' | undefined;
19
21
  }
@@ -1,5 +1,8 @@
1
1
  import { FIELD } from './fields.js';
2
- const FIELDS = Object.keys(FIELD);
2
+ const FIELDS = [
3
+ ...Object.keys(FIELD).filter((one) => one !== 'fractionalSecond'),
4
+ 'fractionalSecondDigits',
5
+ ];
3
6
  export const formatOptions = (asked, dateOnly = false) => {
4
7
  const options = {
5
8
  hourCycle: asked.hourCycle,
@@ -1,4 +1,4 @@
1
- import { type DateCalendar, HelixElement } from '@fusion.dev/helix-core';
1
+ import { type DateCalendar, HelixElement, type MonthCalendar } from '@fusion.dev/helix-core';
2
2
  import { nothing, type PropertyValues, type TemplateResult } from 'lit';
3
3
  /**
4
4
  * @summary A timestamp, formatted for the user's locale.
@@ -45,8 +45,8 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
45
45
  *
46
46
  * **A date is written in a calendar Date Picker draws**: the locale's own
47
47
  * where its months are the Gregorian months, as `th-TH` writes 2569 for 2026,
48
- * and `gregory` where they are not, as for `fa-IR`. `calendar` picks one of
49
- * the five.
48
+ * and `gregory` where they are not, as for `fa-IR`. `calendar` picks any of
49
+ * them, `persian` and `hebrew` included.
50
50
  *
51
51
  * @since 0.1.0
52
52
  * @status stable
@@ -57,6 +57,7 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
57
57
  * @csspart day - The day of the month, with `fields`.
58
58
  * @csspart day-period - AM or PM, or the locale's word for the part of the day, with `fields`.
59
59
  * @csspart era - The era, such as AD, with `fields` and `era`.
60
+ * @csspart fractional-second - The fraction of a second, with `fields` and `fractional-second-digits`.
60
61
  * @csspart hour - The hour, with `fields`.
61
62
  * @csspart minute - The minute, with `fields`.
62
63
  * @csspart month - The month, with `fields`.
@@ -72,14 +73,16 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
72
73
  export declare class HelixHeadlessFormatDate extends HelixElement {
73
74
  /**
74
75
  * The calendar a date is written in: `gregory`, `buddhist`, `japanese`,
75
- * `roc`, or `iso8601`, the calendars Date Picker and Date Input draw.
76
+ * `roc`, or `iso8601`, or a calendar with months of its own, such as
77
+ * `persian`, `hebrew`, `islamic-umalqura`, `ethiopic`, or `chinese`: every
78
+ * calendar Date Picker and Date Input draw.
76
79
  *
77
- * Absent is the locale's own where it is one of the five, such as
78
- * `buddhist` for `th-TH`, and `gregory` for every other, such as `persian`
79
- * for `fa-IR`, so a date written here reads as the same date a Date Picker
80
- * beside it shows.
80
+ * Absent is the locale's own where its months are the Gregorian months,
81
+ * such as `buddhist` for `th-TH`, and `gregory` for every other, such as
82
+ * `persian` for `fa-IR`, so a date written here reads as the same date a
83
+ * Date Picker beside it shows. Write `calendar="persian"` for Mehr 14, 1405.
81
84
  */
82
- calendar?: DateCalendar;
85
+ calendar?: DateCalendar | MonthCalendar;
83
86
  /**
84
87
  * The timestamp, in any format `Date` can parse.
85
88
  *
@@ -107,6 +110,12 @@ export declare class HelixHeadlessFormatDate extends HelixElement {
107
110
  * How the day of the month is written, where a date is shown.
108
111
  */
109
112
  day?: 'numeric' | '2-digit';
113
+ /**
114
+ * Writes the part of the day in words, such as "in the morning" or "at
115
+ * night", in its `long`, `short`, or `narrow` form, where `hour` is on a
116
+ * twelve-hour clock.
117
+ */
118
+ dayPeriod?: 'long' | 'narrow' | 'short';
110
119
  /**
111
120
  * Shows how long ago the timestamp was, in a compact form such as "3h", in
112
121
  * place of the date.
@@ -130,6 +139,11 @@ export declare class HelixHeadlessFormatDate extends HelixElement {
130
139
  * way.
131
140
  */
132
141
  fields?: boolean;
142
+ /**
143
+ * How many digits of a fraction of a second to write after `second`: 1, 2,
144
+ * or 3, as in 09:41:07.250.
145
+ */
146
+ fractionalSecondDigits?: 1 | 2 | 3;
133
147
  /**
134
148
  * Draws an `elapsed` or `relative` reading once and leaves it, where it
135
149
  * would otherwise move on as it goes stale.
@@ -206,9 +220,11 @@ export declare class HelixHeadlessFormatDate extends HelixElement {
206
220
  */
207
221
  timeZone?: string;
208
222
  /**
209
- * Shows the name of the time zone, in its `long` or `short` form.
223
+ * Shows the name of the time zone: `long` or `short`, as Pacific Daylight
224
+ * Time or PDT, `longOffset` or `shortOffset`, as GMT-07:00 or GMT-7, or
225
+ * `longGeneric` or `shortGeneric`, as Pacific Time or PT.
210
226
  */
211
- timeZoneName?: 'long' | 'short';
227
+ timeZoneName?: 'long' | 'longGeneric' | 'longOffset' | 'short' | 'shortGeneric' | 'shortOffset';
212
228
  /**
213
229
  * How the weekday is written, where one is shown.
214
230
  */
@@ -132,6 +132,9 @@ __decorate([
132
132
  __decorate([
133
133
  property()
134
134
  ], HelixHeadlessFormatDate.prototype, "day", void 0);
135
+ __decorate([
136
+ property({ attribute: 'day-period' })
137
+ ], HelixHeadlessFormatDate.prototype, "dayPeriod", void 0);
135
138
  __decorate([
136
139
  property({ reflect: true, type: Boolean })
137
140
  ], HelixHeadlessFormatDate.prototype, "elapsed", void 0);
@@ -141,6 +144,9 @@ __decorate([
141
144
  __decorate([
142
145
  property({ type: Boolean })
143
146
  ], HelixHeadlessFormatDate.prototype, "fields", void 0);
147
+ __decorate([
148
+ property({ attribute: 'fractional-second-digits', type: Number })
149
+ ], HelixHeadlessFormatDate.prototype, "fractionalSecondDigits", void 0);
144
150
  __decorate([
145
151
  property({ type: Boolean })
146
152
  ], HelixHeadlessFormatDate.prototype, "frozen", void 0);
@@ -98,6 +98,11 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
98
98
  }
99
99
  else if (event.key === ' ') {
100
100
  event.preventDefault();
101
+ const at = this.currentValue || shown.find((option) => !option.disabled)?.value;
102
+ if (at) {
103
+ this.activeValue = at;
104
+ this.choose(at);
105
+ }
101
106
  }
102
107
  return;
103
108
  }
@@ -56,6 +56,7 @@ declare const HelixHeadlessNotification_base: (new (...args: any[]) => import("@
56
56
  * @csspart time-day - Format Date's `day`, forwarded for a time drawn as fields. An elapsed time draws none.
57
57
  * @csspart time-day-period - Format Date's `day-period`, forwarded for a time drawn as fields. An elapsed time draws none.
58
58
  * @csspart time-era - Format Date's `era`, forwarded for a time drawn as fields. An elapsed time draws none.
59
+ * @csspart time-fractional-second - Format Date's `fractional-second`, forwarded for a time drawn as fields. An elapsed time draws none.
59
60
  * @csspart time-hour - Format Date's `hour`, forwarded for a time drawn as fields. An elapsed time draws none.
60
61
  * @csspart time-minute - Format Date's `minute`, forwarded for a time drawn as fields. An elapsed time draws none.
61
62
  * @csspart time-month - Format Date's `month`, forwarded for a time drawn as fields. An elapsed time draws none.
@@ -104,7 +104,8 @@ let HelixHeadlessNotification = class HelixHeadlessNotification extends MixinDis
104
104
  renderTime() {
105
105
  const stamp = this.tag('format-date');
106
106
  return html `<${stamp}
107
- exportparts="time, day: time-day, day-period: time-day-period, era: time-era, hour: time-hour,
107
+ exportparts="time, day: time-day, day-period: time-day-period, era: time-era,
108
+ fractional-second: time-fractional-second, hour: time-hour,
108
109
  minute: time-minute, month: time-month, second: time-second,
109
110
  time-zone-name: time-time-zone-name, weekday: time-weekday, year: time-year"
110
111
  elapsed