@fusion.dev/helix-headless 0.154.0 → 0.156.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 (104) hide show
  1. package/custom-elements.json +3213 -179
  2. package/dist/accordion/item/accordion-item.d.ts +15 -0
  3. package/dist/accordion/item/accordion-item.js +12 -1
  4. package/dist/accordion/root/accordion-root.d.ts +2 -1
  5. package/dist/accordion/root/accordion-root.js +1 -0
  6. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +36 -3
  7. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +42 -2
  8. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +15 -5
  9. package/dist/breadcrumbs/root/breadcrumbs-root.js +29 -4
  10. package/dist/button-group/root/button-group-root.d.ts +2 -0
  11. package/dist/button-group/root/button-group-root.js +1 -0
  12. package/dist/canvas/node/canvas-node.js +1 -1
  13. package/dist/canvas/root/canvas-root.d.ts +17 -2
  14. package/dist/canvas/root/canvas-root.js +23 -6
  15. package/dist/chat/composer/chat-composer.js +1 -1
  16. package/dist/chat/root/chat-root.d.ts +14 -1
  17. package/dist/chat/root/chat-root.js +14 -4
  18. package/dist/color-input/root/color-input-root.d.ts +9 -3
  19. package/dist/color-input/root/color-input-root.js +3 -1
  20. package/dist/color-picker/channels.d.ts +5 -3
  21. package/dist/color-picker/channels.js +79 -21
  22. package/dist/color-picker/root/color-picker-root.d.ts +58 -5
  23. package/dist/color-picker/root/color-picker-root.js +75 -13
  24. package/dist/combobox/root/combobox-root.d.ts +10 -0
  25. package/dist/combobox/root/combobox-root.js +18 -3
  26. package/dist/command/root/command-root.d.ts +116 -1
  27. package/dist/command/root/command-root.js +124 -15
  28. package/dist/data-table/root/data-table-root.d.ts +25 -0
  29. package/dist/data-table/root/data-table-root.js +13 -3
  30. package/dist/date-input/root/date-input-root.d.ts +33 -1
  31. package/dist/date-input/root/date-input-root.js +9 -2
  32. package/dist/date-picker/root/date-picker-root.d.ts +43 -13
  33. package/dist/date-picker/root/date-picker-root.js +54 -31
  34. package/dist/element-events.generated.js +3 -1
  35. package/dist/graph/root/graph-root.d.ts +13 -0
  36. package/dist/graph/root/graph-root.js +16 -0
  37. package/dist/list/root/list-root.d.ts +74 -1
  38. package/dist/list/root/list-root.js +92 -4
  39. package/dist/list/selection.js +3 -3
  40. package/dist/map/root/map-root.d.ts +6 -0
  41. package/dist/map/root/map-root.js +8 -1
  42. package/dist/navigation/root/navigation-root.d.ts +26 -0
  43. package/dist/navigation/root/navigation-root.js +58 -1
  44. package/dist/number-input/root/number-input-root.d.ts +63 -6
  45. package/dist/number-input/root/number-input-root.js +96 -11
  46. package/dist/object-inspector/root/object-inspector-root.d.ts +36 -1
  47. package/dist/object-inspector/root/object-inspector-root.js +26 -2
  48. package/dist/option/root/option-root.d.ts +32 -0
  49. package/dist/option/root/option-root.js +44 -5
  50. package/dist/outline/root/outline-root.d.ts +6 -2
  51. package/dist/outline/root/outline-root.js +7 -3
  52. package/dist/select/root/select-root.d.ts +29 -3
  53. package/dist/select/root/select-root.js +34 -9
  54. package/dist/slider/root/slider-root.d.ts +71 -9
  55. package/dist/slider/root/slider-root.js +129 -42
  56. package/dist/speed-dial/item/speed-dial-item.d.ts +29 -1
  57. package/dist/speed-dial/item/speed-dial-item.js +48 -7
  58. package/dist/speed-dial/root/speed-dial-root.d.ts +32 -6
  59. package/dist/speed-dial/root/speed-dial-root.js +50 -5
  60. package/dist/splitter/root/splitter-root.d.ts +22 -0
  61. package/dist/splitter/root/splitter-root.js +36 -7
  62. package/dist/steps/reach.d.ts +5 -1
  63. package/dist/steps/reach.js +2 -2
  64. package/dist/steps/root/steps-root.d.ts +37 -2
  65. package/dist/steps/root/steps-root.js +49 -7
  66. package/dist/steps/step/step.d.ts +6 -0
  67. package/dist/steps/step/step.js +4 -0
  68. package/dist/table/root/table-root.d.ts +20 -0
  69. package/dist/table/root/table-root.js +13 -3
  70. package/dist/tabs/root/tabs-root.d.ts +37 -0
  71. package/dist/tabs/root/tabs-root.js +92 -2
  72. package/dist/tabs/tab/tab.d.ts +38 -2
  73. package/dist/tabs/tab/tab.js +45 -4
  74. package/dist/tag/group/tag-group.d.ts +29 -3
  75. package/dist/tag/group/tag-group.js +42 -11
  76. package/dist/time-input/root/time-input-root.d.ts +32 -1
  77. package/dist/time-input/root/time-input-root.js +9 -2
  78. package/dist/time-picker/root/time-picker-root.d.ts +63 -1
  79. package/dist/time-picker/root/time-picker-root.js +58 -7
  80. package/dist/timeline/item/timeline-item.d.ts +25 -0
  81. package/dist/timeline/item/timeline-item.js +27 -2
  82. package/dist/toggle/root/toggle-root.d.ts +2 -0
  83. package/dist/toggle/root/toggle-root.js +1 -1
  84. package/dist/tree/item/tree-item.d.ts +10 -0
  85. package/dist/tree/item/tree-item.js +12 -0
  86. package/dist/tree/root/tree-root.d.ts +40 -1
  87. package/dist/tree/root/tree-root.js +120 -4
  88. package/dist/tree/selection.d.ts +6 -0
  89. package/dist/tree/selection.js +11 -0
  90. package/dist/video/root/keys.d.ts +6 -2
  91. package/dist/video/root/keys.js +18 -1
  92. package/dist/video/root/video-root.d.ts +60 -1
  93. package/dist/video/root/video-root.js +70 -2
  94. package/dist/video-playlist/item/video-playlist-item.d.ts +15 -1
  95. package/dist/video-playlist/item/video-playlist-item.js +7 -0
  96. package/dist/video-playlist/root/video-playlist-root.d.ts +43 -4
  97. package/dist/video-playlist/root/video-playlist-root.js +69 -2
  98. package/dist/virtual-list/root/virtual-list-root.d.ts +8 -0
  99. package/dist/virtual-list/root/virtual-list-root.js +3 -0
  100. package/lint.json +1 -1
  101. package/package.json +5 -5
  102. package/types/jsx.d.ts +3885 -383
  103. package/types/vue.d.ts +1045 -107
  104. package/types/words.d.ts +146 -1
@@ -15,7 +15,7 @@ import { areaAt, hueAt } from '../wheel.js';
15
15
  import '../../button/index.js';
16
16
  import '../../button-group/index.js';
17
17
  import '../../slider/index.js';
18
- const FORMATS = ['hex', 'rgb', 'hsl'];
18
+ const FORMATS = ['hex', 'rgb', 'hsl', 'oklch'];
19
19
  const START = { alpha: 100, brightness: 100, hue: 0, saturation: 100 };
20
20
  let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPickerFeedback(MixinControllerValue(HelixFormElement)) {
21
21
  constructor() {
@@ -26,13 +26,16 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
26
26
  this.blueLabel = 'Blue';
27
27
  this.brightnessLabel = 'Brightness';
28
28
  this.channelFields = false;
29
+ this.chromaLabel = 'Chroma';
29
30
  this.colorWords = {};
30
31
  this.copiedLabel = 'Copied';
31
32
  this.copyLabel = 'Copy {value}';
32
33
  this.eyedropperLabel = 'Sample a color from the screen';
33
34
  this.formatLabel = 'Syntax: {format}. Change it.';
34
35
  this.greenLabel = 'Green';
36
+ this.hint = '';
35
37
  this.hueLabel = 'Hue';
38
+ this.label = '';
36
39
  this.lightnessLabel = 'Lightness';
37
40
  this.noEyedropper = false;
38
41
  this.noFormat = false;
@@ -50,6 +53,11 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
50
53
  this.valueMissingMessage = 'Choose a color.';
51
54
  this.wheel = false;
52
55
  this.sampling = false;
56
+ this.handleNamingSlot = () => {
57
+ this.requestUpdate();
58
+ };
59
+ this.dragging = false;
60
+ this.picking = false;
53
61
  this.owned = false;
54
62
  this.announcesInput = true;
55
63
  this.unsettled = false;
@@ -132,6 +140,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
132
140
  return;
133
141
  }
134
142
  this.dispatchEvent(new HelixSampleStartEvent());
143
+ this.picking = true;
135
144
  try {
136
145
  const { sRGBHex } = await new Dropper().open();
137
146
  const parsed = parseColor(sRGBHex);
@@ -142,6 +151,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
142
151
  }
143
152
  catch {
144
153
  }
154
+ this.picking = false;
145
155
  this.dispatchEvent(new HelixSampleEndEvent());
146
156
  };
147
157
  this.handleGridPointer = (event) => {
@@ -150,12 +160,14 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
150
160
  }
151
161
  const grid = event.currentTarget;
152
162
  if (event.type === 'pointerup' || event.type === 'pointercancel') {
163
+ this.dragging = false;
153
164
  this.settle();
154
165
  return;
155
166
  }
156
167
  if (event.type === 'pointerdown') {
168
+ this.dragging = true;
157
169
  capturePointer(grid, event.pointerId);
158
- this.partNamed('grid-saturation')?.focus();
170
+ this.partNamed('grid-saturation')?.focus({ preventScroll: true });
159
171
  }
160
172
  else if (!grid.hasPointerCapture(event.pointerId)) {
161
173
  return;
@@ -181,7 +193,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
181
193
  }
182
194
  if (event.type === 'pointerdown') {
183
195
  capturePointer(wheel, event.pointerId);
184
- this.partNamed('wheel-hue')?.focus();
196
+ this.partNamed('wheel-hue')?.focus({ preventScroll: true });
185
197
  }
186
198
  else if (!wheel.hasPointerCapture(event.pointerId)) {
187
199
  return;
@@ -232,6 +244,23 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
232
244
  };
233
245
  }
234
246
  static { this.words = 'helix-color-picker'; }
247
+ slottedIn(name) {
248
+ return this.knownChildren.filter((child) => child.slot === name);
249
+ }
250
+ get named() {
251
+ return (this.label ||
252
+ this.slottedIn('label')
253
+ .map((child) => child.textContent ?? '')
254
+ .join(' ')
255
+ .trim());
256
+ }
257
+ get hinted() {
258
+ return this.hint !== '' || this.slottedIn('hint').length > 0;
259
+ }
260
+ get describedBy() {
261
+ const ids = [this.hinted ? 'hint' : '', this.feedback === '' ? '' : 'feedback'].filter(Boolean);
262
+ return ids.length > 0 ? ids.join(' ') : nothing;
263
+ }
235
264
  settle() {
236
265
  if (this.unsettled) {
237
266
  this.unsettled = false;
@@ -299,6 +328,8 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
299
328
  return {
300
329
  alpha: this.opacityLabel,
301
330
  blue: this.blueLabel,
331
+ brightness: this.brightnessLabel,
332
+ chroma: this.chromaLabel,
302
333
  green: this.greenLabel,
303
334
  hue: this.hueLabel,
304
335
  lightness: this.lightnessLabel,
@@ -327,10 +358,10 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
327
358
  <input
328
359
  part="field-input"
329
360
  type="number"
330
- inputmode="numeric"
361
+ inputmode=${field.step < 1 ? 'decimal' : 'numeric'}
331
362
  min=${field.min}
332
363
  max=${field.max}
333
- step="1"
364
+ step=${field.step}
334
365
  .value=${live(String(field.value))}
335
366
  ?disabled=${this.isDisabled}
336
367
  ?readonly=${this.readOnly}
@@ -350,7 +381,8 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
350
381
  exportparts="control: channel-control, feedback: channel-feedback, field: channel-field,
351
382
  hint: channel-hint, label: channel-label, marker: channel-marker,
352
383
  marker-label: channel-marker-label, markers: channel-markers, output: channel-output,
353
- tooltip: channel-tooltip, tooltips: channel-tooltips"
384
+ thumb: channel-thumb, thumbs: channel-thumbs, tooltip: channel-tooltip,
385
+ tooltips: channel-tooltips"
354
386
  data-channel=${channel}
355
387
  aria-invalid=${this.marked ? 'true' : nothing}
356
388
  label=${label}
@@ -391,10 +423,18 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
391
423
  willUpdate(changed) {
392
424
  super.willUpdate(changed);
393
425
  const outside = [...(this.internals.labels ?? [])];
394
- hostAria(this.internals, { labelledBy: outside, role: outside.length > 0 ? 'group' : '' });
426
+ const named = this.named;
427
+ hostAria(this.internals, {
428
+ label: outside.length > 0 ? '' : named,
429
+ labelledBy: outside,
430
+ role: outside.length > 0 || named !== '' ? 'group' : '',
431
+ });
395
432
  if (!this.hydrating) {
396
433
  this.sampling = 'EyeDropper' in globalThis;
397
434
  }
435
+ this.toggleState('copied', this.copier.copied);
436
+ this.toggleState('dragging', this.dragging);
437
+ this.toggleState('sampling', this.picking);
398
438
  }
399
439
  renderTools() {
400
440
  return html `<${this.tag('button-group')} part="actions" label=${this.toolsLabel}>
@@ -471,7 +511,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
471
511
  const reversed = square('brightness');
472
512
  const hue = hueName({ alpha: 100, brightness: 100, hue: color.hue, saturation: 100 }, this.colorWords, locale);
473
513
  const hueSaid = (value) => new Intl.ListFormat(locale, { style: 'short', type: 'unit' }).format([String(value), hue]);
474
- const owner = this.getAttribute('aria-label')?.trim();
514
+ const owner = this.getAttribute('aria-label')?.trim() || this.named;
475
515
  const axisName = (channel) => (owner ? `${owner}, ${channel}` : channel);
476
516
  const area = html `<div
477
517
  part="grid"
@@ -488,7 +528,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
488
528
  min="0"
489
529
  max="100"
490
530
  aria-label=${axisName(this.saturationLabel)}
491
- aria-describedby=${this.feedback === '' ? nothing : 'feedback'}
531
+ aria-describedby=${this.describedBy}
492
532
  aria-valuetext=${both}
493
533
  aria-invalid=${this.marked ? 'true' : nothing}
494
534
  .value=${String(color.saturation)}
@@ -505,7 +545,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
505
545
  tabindex="-1"
506
546
  style="writing-mode: vertical-lr; direction: rtl"
507
547
  aria-label=${axisName(this.brightnessLabel)}
508
- aria-describedby=${this.feedback === '' ? nothing : 'feedback'}
548
+ aria-describedby=${this.describedBy}
509
549
  aria-valuetext=${reversed}
510
550
  aria-invalid=${this.marked ? 'true' : nothing}
511
551
  .value=${String(color.brightness)}
@@ -514,7 +554,10 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
514
554
  @change=${() => this.settle()}
515
555
  />
516
556
  </div>`;
517
- return html `${this.wheel
557
+ return html `<div part="label" ?hidden=${this.named === ''}>
558
+ <slot name="label" @slotchange=${this.handleNamingSlot}>${this.label}</slot>
559
+ </div>
560
+ ${this.wheel
518
561
  ? html `<div
519
562
  part="wheel"
520
563
  style="--color-picker-hue: ${color.hue}"
@@ -531,7 +574,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
531
574
  max="360"
532
575
  dir="ltr"
533
576
  aria-label=${axisName(this.hueLabel)}
534
- aria-describedby=${this.feedback === '' ? nothing : 'feedback'}
577
+ aria-describedby=${this.describedBy}
535
578
  aria-valuetext=${hueSaid(color.hue)}
536
579
  aria-invalid=${this.marked ? 'true' : nothing}
537
580
  .value=${String(color.hue)}
@@ -574,7 +617,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
574
617
  part="value"
575
618
  type="text"
576
619
  aria-label=${this.valueLabel}
577
- aria-describedby=${this.feedback === '' ? nothing : 'feedback'}
620
+ aria-describedby=${this.describedBy}
578
621
  aria-invalid=${this.marked ? 'true' : nothing}
579
622
  autocomplete=${this.autocomplete || nothing}
580
623
  spellcheck="false"
@@ -591,6 +634,9 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
591
634
  </div>
592
635
 
593
636
  ${this.presets.length === 0 ? nothing : this.renderSwatches(painted)}
637
+ <div part="hint" id="hint" ?hidden=${!this.hinted}>
638
+ <slot name="hint" @slotchange=${this.handleNamingSlot}>${this.hint}</slot>
639
+ </div>
594
640
  ${this.renderPickerFeedback()}`;
595
641
  }
596
642
  };
@@ -615,6 +661,10 @@ __decorate([
615
661
  __decorate([
616
662
  property({ attribute: 'channel-fields', type: Boolean })
617
663
  ], HelixHeadlessColorPicker.prototype, "channelFields", void 0);
664
+ __decorate([
665
+ words,
666
+ property({ attribute: 'chroma-label' })
667
+ ], HelixHeadlessColorPicker.prototype, "chromaLabel", void 0);
618
668
  __decorate([
619
669
  property({ attribute: 'color-words', converter: wordsConverter })
620
670
  ], HelixHeadlessColorPicker.prototype, "colorWords", void 0);
@@ -641,10 +691,16 @@ __decorate([
641
691
  words,
642
692
  property({ attribute: 'green-label' })
643
693
  ], HelixHeadlessColorPicker.prototype, "greenLabel", void 0);
694
+ __decorate([
695
+ property()
696
+ ], HelixHeadlessColorPicker.prototype, "hint", void 0);
644
697
  __decorate([
645
698
  words,
646
699
  property({ attribute: 'hue-label' })
647
700
  ], HelixHeadlessColorPicker.prototype, "hueLabel", void 0);
701
+ __decorate([
702
+ property()
703
+ ], HelixHeadlessColorPicker.prototype, "label", void 0);
648
704
  __decorate([
649
705
  words,
650
706
  property({ attribute: 'lightness-label' })
@@ -711,6 +767,12 @@ __decorate([
711
767
  __decorate([
712
768
  state()
713
769
  ], HelixHeadlessColorPicker.prototype, "swatchAt", void 0);
770
+ __decorate([
771
+ state()
772
+ ], HelixHeadlessColorPicker.prototype, "dragging", void 0);
773
+ __decorate([
774
+ state()
775
+ ], HelixHeadlessColorPicker.prototype, "picking", void 0);
714
776
  HelixHeadlessColorPicker = __decorate([
715
777
  customElement('helix-headless-color-picker')
716
778
  ], HelixHeadlessColorPicker);
@@ -198,6 +198,16 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
198
198
  * every keystroke. See Listbox's `filter-delay`.
199
199
  */
200
200
  filterDelay: number;
201
+ /**
202
+ * What the form receives for each chosen option: `key`, its `value`, or
203
+ * `text`, its words, as React Aria's ComboBox `formValue` offers.
204
+ *
205
+ * `text` is for a server that wants what the reader saw, such as a city's
206
+ * name. A value no option carries, typed with `allows-custom-value` or made
207
+ * with `creatable`, is sent as it is either way. Absent is `key`, and the
208
+ * host carries no attribute for it.
209
+ */
210
+ formValue?: 'key' | 'text';
201
211
  /**
202
212
  * The list's name, read by screen readers. The list has no visible name.
203
213
  */
@@ -453,11 +453,23 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
453
453
  return this.partNamed('control') ?? super.focusTarget;
454
454
  }
455
455
  sync() {
456
- if (this.multiple) {
457
- reportValues(this.internals, this.name, this.value === '' ? [] : this.value.split(','));
456
+ const values = this.multiple ? this.values : this.value === '' ? [] : [this.value];
457
+ const words = this.formValue === 'text'
458
+ ? new Map(optionsAmong(this.knownChildren).map((option) => [option.value, option.text]))
459
+ : undefined;
460
+ const answers = words ? values.map((value) => words.get(value) ?? value) : values;
461
+ if (!this.multiple) {
462
+ this.internals.setFormValue(answers[0] ?? null, this.value);
463
+ }
464
+ else if (words && this.name !== '' && answers.length > 0) {
465
+ const data = new FormData();
466
+ for (const answer of answers) {
467
+ data.append(this.name, answer);
468
+ }
469
+ this.internals.setFormValue(data, this.value);
458
470
  }
459
471
  else {
460
- this.internals.setFormValue(this.value === '' ? null : this.value);
472
+ reportValues(this.internals, this.name, answers);
461
473
  }
462
474
  this.reportRequired(this.value === '', this.valueMissingMessage, 'control');
463
475
  }
@@ -677,6 +689,9 @@ __decorate([
677
689
  __decorate([
678
690
  property({ attribute: 'filter-delay', type: Number })
679
691
  ], HelixHeadlessCombobox.prototype, "filterDelay", void 0);
692
+ __decorate([
693
+ property({ attribute: 'form-value' })
694
+ ], HelixHeadlessCombobox.prototype, "formValue", void 0);
680
695
  __decorate([
681
696
  words,
682
697
  property({ attribute: 'list-label' })
@@ -1,4 +1,4 @@
1
- import { HelixElement } from '@fusion.dev/helix-core';
1
+ import { type DataOptionItem, HelixElement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import '../../dialog/index.js';
4
4
  import '../../listbox/index.js';
@@ -22,10 +22,51 @@ declare const HelixHeadlessCommand_base: (new (...args: any[]) => import("@fusio
22
22
  * palette is open. `mod` means Command on a Mac and Control elsewhere, so you
23
23
  * write one binding.
24
24
  *
25
+ * With `inline`, the palette is drawn in the page with no dialog, as a search
26
+ * over a list that is always shown.
27
+ *
28
+ * **Pages.** A command can open a page of commands of its own, as a palette
29
+ * offers "Change theme" and then the themes. Give the option `opens` with a
30
+ * name, and slot the page's commands as `page:` and that name:
31
+ *
32
+ * ```html
33
+ * <helix-command>
34
+ * <helix-option value="theme" opens="theme">Change theme</helix-option>
35
+ * <helix-option value="dark" slot="page:theme">Dark</helix-option>
36
+ * <helix-option value="light" slot="page:theme">Light</helix-option>
37
+ * </helix-command>
38
+ * ```
39
+ *
40
+ * Choosing the opener says `helix-select` with its value, and canceling it
41
+ * keeps the page that is shown. The list then shows the page, named by the
42
+ * opener's words, and Backspace in an empty filter goes back. `page` says
43
+ * which page is shown.
44
+ *
25
45
  * The filter is cleared when the palette closes, so each opening starts from
26
46
  * the full list. Combobox and Select do the same. As typing narrows the list, a
27
47
  * screen reader hears how many commands are left, such as "3 commands".
28
48
  *
49
+ * **Keyboard.** Focus goes to the filter field as the palette opens, and the
50
+ * highlight moves through the commands while you type.
51
+ *
52
+ * | Key | What it does |
53
+ * |---|---|
54
+ * | `hotkey`, Command or Control with K by default | Opens the palette from anywhere on the page, or closes it. With `inline`, puts focus in its filter field. |
55
+ * | Down, Up | Moves the highlight to the next or the previous command, round from the last to the first. |
56
+ * | Page Down, Page Up | Moves the highlight by as many commands as the list shows at once. |
57
+ * | Home, End, Left, Right | Move the caret in the filter field. |
58
+ * | Enter | Runs the highlighted command, or follows it where it is a link, and closes the palette. On a command with `opens`, shows its page. |
59
+ * | Command or Control with Enter | Takes the highlighted command's `alternate` destination, where it has one. |
60
+ * | Backspace | In an empty filter on a page, goes back to the page before. |
61
+ * | Escape | Clears the filter. With the filter empty, closes the palette and puts focus back where it was. |
62
+ * | Tab | Stays in the palette, which is modal. With `inline`, moves on through the page. |
63
+ *
64
+ * **ARIA.** The palette is a modal `dialog` named by `label`, or with
65
+ * `inline` no dialog at all. Inside it the filter field is a `combobox` with
66
+ * `aria-activedescendant` on the highlighted command, and the commands are a
67
+ * `listbox` of `option`s. How many commands typing left, the empty text and
68
+ * the loading text are said in a polite live region.
69
+ *
29
70
  * @since 0.1.0
30
71
  * @status stable
31
72
  * @category navigation
@@ -35,7 +76,9 @@ declare const HelixHeadlessCommand_base: (new (...args: any[]) => import("@fusio
35
76
  * @slot - The commands, and any groups of them.
36
77
  * @slot empty - What the palette shows when typing matches no commands, for content richer than `empty-text`.
37
78
  * @slot error - What the palette shows while `load-error` is set, for content richer than its text.
79
+ * @slot filter-icon - Replaces the magnifying glass in the filter field.
38
80
  * @slot footer - Content under the list, such as the keys that work in the palette.
81
+ * @slot header - Content above the filter field, such as a title or the scope being searched. A heading here does not rename the palette, which `label` names.
39
82
  * @slot loading - What the palette shows while the commands load, for content richer than `loading-text`.
40
83
  * @slot no-results - What the palette shows when typing matches no commands, for content richer than `no-results-text`.
41
84
  *
@@ -67,6 +110,10 @@ declare const HelixHeadlessCommand_base: (new (...args: any[]) => import("@fusio
67
110
  * @csspart listbox-search - The region that holds the filter field.
68
111
  * @csspart listbox-search-field - The filter field.
69
112
  *
113
+ * @cssstate empty - The list shows no commands: there are none, or typing hid every one.
114
+ * @cssstate error - While `load-error` is set.
115
+ * @cssstate loading - While `loading` is set.
116
+ * @cssstate no-results - Typing hid every one of the commands, where there are some.
70
117
  * @cssstate open - While the palette is open.
71
118
  */
72
119
  export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
@@ -95,6 +142,26 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
95
142
  * with: one key, said once.
96
143
  */
97
144
  hotkey: string;
145
+ /**
146
+ * Draws the palette in the page, where it stands, with no dialog: a search
147
+ * over a list of commands, as React Aria's Autocomplete is drawn.
148
+ *
149
+ * The list is always shown, and `hotkey` puts focus in its filter field.
150
+ * Choosing a command says `helix-select` and leaves the list where it is,
151
+ * and `open`, `toggle` and the dialog's parts do nothing.
152
+ */
153
+ inline: boolean;
154
+ /**
155
+ * The commands as data, for a palette too long to draw whole: each a value,
156
+ * which is also its words, or a record with a `value`, a `label` and
157
+ * `disabled`. Handed to the list, which draws only the commands in sight and
158
+ * reads no children while it is set. See Listbox's `items`.
159
+ *
160
+ * Choosing one says `helix-select` with its value, as a child option does.
161
+ * A command that is a link, or that has an `alternate`, is an option you
162
+ * write as a child.
163
+ */
164
+ items: readonly DataOptionItem[] | undefined;
98
165
  /**
99
166
  * Accessible name for the overlay, which has no visible heading.
100
167
  */
@@ -122,6 +189,19 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
122
189
  * some. Absent, `empty-text` shows. See Listbox's `no-results-text`.
123
190
  */
124
191
  noResultsText?: string;
192
+ /**
193
+ * The page of commands shown, by name: empty for the commands you write
194
+ * with no `slot`, or a name for the commands slotted as `page:` and the
195
+ * name, such as `slot="page:theme"`.
196
+ *
197
+ * An option with `opens` set to a name goes to that page when it is chosen,
198
+ * in place of running, and Backspace in an empty filter goes back to the
199
+ * page before. Closing the palette goes back to the first page. Set it to
200
+ * open the palette on a page of your choosing.
201
+ */
202
+ page: string;
203
+ /** The pages gone through to reach this one, which Backspace walks back. */
204
+ private trail;
125
205
  /**
126
206
  * The text shown in the filter field before anything is typed.
127
207
  */
@@ -169,6 +249,8 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
169
249
  * palette the reader never sees.
170
250
  */
171
251
  private readonly handleHotkey;
252
+ /** The list's filter field, where a reader types. */
253
+ private get searchField();
172
254
  /**
173
255
  * Takes what the list announced and says it under this element's name.
174
256
  *
@@ -183,6 +265,18 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
183
265
  * could not be run again: Enter did nothing and the palette stayed open.
184
266
  */
185
267
  private readonly handleChange;
268
+ /**
269
+ * Shows a page of commands, with the trail that leads back from it. The
270
+ * filter starts empty, as it does on opening, and the field keeps focus.
271
+ */
272
+ private goTo;
273
+ /** Backspace in an empty filter, on a page, goes back to the page before. */
274
+ private readonly handleBack;
275
+ /**
276
+ * The list's name: the palette's, or on a page, the words of the command
277
+ * that opens it.
278
+ */
279
+ private get listName();
186
280
  /**
187
281
  * The row under the keyboard, read from the `active` property the listbox
188
282
  * writes on each option.
@@ -217,6 +311,20 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
217
311
  disconnectedCallback(): void;
218
312
  protected willUpdate(changed: PropertyValues): void;
219
313
  protected firstUpdated(changed: PropertyValues): void;
314
+ /**
315
+ * The list's loading, error and empty states on the host too, so a page
316
+ * styles the whole palette from them, as Combobox does. Read once the list
317
+ * has drawn its filter, since `hidden` is what the filter writes onto a
318
+ * command.
319
+ */
320
+ private markStatus;
321
+ /**
322
+ * After the list has filtered on what was typed. The event comes before the
323
+ * filter is applied, so the list's update is waited for a turn later.
324
+ */
325
+ private readonly handleFilter;
326
+ /** Whether a child fills the named slot, so it is handed on to the dialog or the list. */
327
+ private fills;
220
328
  protected updated(changed: PropertyValues): void;
221
329
  /**
222
330
  * The surface the palette opens in, behind a seam the styled tier can move.
@@ -229,6 +337,13 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
229
337
  * from the same template.
230
338
  */
231
339
  protected renderDialog(): TemplateResult;
340
+ /**
341
+ * The filterable list of commands, which the dialog holds, or the page with
342
+ * `inline`, behind a seam the styled tier can move.
343
+ */
344
+ protected renderListbox(): TemplateResult;
345
+ /** The row under the list, in the dialog's footer or, `inline`, under the list itself. */
346
+ private renderFooter;
232
347
  protected render(): TemplateResult;
233
348
  }
234
349
  declare global {