@fusion.dev/helix-headless 0.215.3 → 0.216.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 (113) hide show
  1. package/api.json +1 -1
  2. package/custom-elements.json +1 -1
  3. package/dist/area-chart/root/area-chart-root.d.ts +1 -0
  4. package/dist/area-chart/root/area-chart-root.js +1 -1
  5. package/dist/bar-chart/root/bar-chart-root.d.ts +1 -0
  6. package/dist/bar-chart/root/bar-chart-root.js +1 -1
  7. package/dist/button/root/button-root.d.ts +3 -1
  8. package/dist/button/root/button-root.js +2 -1
  9. package/dist/chat/composer/chat-composer.d.ts +18 -1
  10. package/dist/chat/composer/chat-composer.js +8 -3
  11. package/dist/checkbox/root/checkbox-root.d.ts +3 -1
  12. package/dist/checkbox/root/checkbox-root.js +2 -1
  13. package/dist/code-block/highlight.d.ts +9 -0
  14. package/dist/code-block/highlight.js +39 -0
  15. package/dist/code-block/highlighter.d.ts +44 -0
  16. package/dist/code-block/highlighter.js +44 -0
  17. package/dist/code-block/index.d.ts +1 -0
  18. package/dist/code-block/index.js +1 -0
  19. package/dist/code-block/keyed-lines.d.ts +23 -0
  20. package/dist/code-block/keyed-lines.js +75 -0
  21. package/dist/code-block/root/code-block-root.d.ts +6 -23
  22. package/dist/code-block/root/code-block-root.js +8 -25
  23. package/dist/code-editor/index.d.ts +1 -0
  24. package/dist/code-editor/index.js +1 -0
  25. package/dist/code-editor/root/code-editor-root.d.ts +367 -0
  26. package/dist/code-editor/root/code-editor-root.js +746 -0
  27. package/dist/code-input/index.d.ts +1 -0
  28. package/dist/code-input/index.js +1 -0
  29. package/dist/code-input/root/code-input-root.d.ts +119 -0
  30. package/dist/code-input/root/code-input-root.js +142 -0
  31. package/dist/combobox/root/combobox-root.d.ts +6 -1
  32. package/dist/combobox/root/combobox-root.js +4 -2
  33. package/dist/command/root/command-root.d.ts +61 -11
  34. package/dist/command/root/command-root.js +88 -3
  35. package/dist/donut-chart/root/donut-chart-root.d.ts +1 -0
  36. package/dist/donut-chart/root/donut-chart-root.js +1 -1
  37. package/dist/element-events.generated.js +36 -3
  38. package/dist/filter-input/root/filter-input-root.d.ts +9 -1
  39. package/dist/filter-input/root/filter-input-root.js +7 -3
  40. package/dist/heatmap/root/heatmap-root.d.ts +1 -0
  41. package/dist/heatmap/root/heatmap-root.js +1 -1
  42. package/dist/index.d.ts +4 -0
  43. package/dist/index.js +4 -0
  44. package/dist/input/root/input-root.d.ts +14 -2
  45. package/dist/input/root/input-root.js +11 -3
  46. package/dist/kbd/root/kbd-root.js +9 -2
  47. package/dist/line-chart/root/line-chart-root.d.ts +1 -0
  48. package/dist/line-chart/root/line-chart-root.js +1 -1
  49. package/dist/listbox/root/listbox-root.d.ts +8 -1
  50. package/dist/listbox/root/listbox-root.js +7 -4
  51. package/dist/markdown/blocks.d.ts +66 -0
  52. package/dist/markdown/blocks.js +326 -0
  53. package/dist/markdown/index.d.ts +6 -0
  54. package/dist/markdown/index.js +5 -0
  55. package/dist/markdown/inline.d.ts +57 -0
  56. package/dist/markdown/inline.js +483 -0
  57. package/dist/markdown/root/markdown-root.d.ts +99 -0
  58. package/dist/markdown/root/markdown-root.js +93 -0
  59. package/dist/markdown/stream.d.ts +47 -0
  60. package/dist/markdown/stream.js +62 -0
  61. package/dist/markdown/tree.d.ts +57 -0
  62. package/dist/markdown/tree.js +144 -0
  63. package/dist/markdown/writer.d.ts +33 -0
  64. package/dist/markdown/writer.js +139 -0
  65. package/dist/menu/root/menu-root.d.ts +53 -0
  66. package/dist/menu/root/menu-root.js +92 -15
  67. package/dist/pagination/size/pagination-size.d.ts +3 -0
  68. package/dist/pagination/size/pagination-size.js +2 -1
  69. package/dist/scatter-chart/root/scatter-chart-root.d.ts +1 -0
  70. package/dist/scatter-chart/root/scatter-chart-root.js +1 -1
  71. package/dist/select/root/select-root.d.ts +6 -1
  72. package/dist/select/root/select-root.js +4 -2
  73. package/dist/shortcut-overlay/index.d.ts +1 -0
  74. package/dist/shortcut-overlay/index.js +1 -0
  75. package/dist/shortcut-overlay/root/shortcut-overlay-root.d.ts +128 -0
  76. package/dist/shortcut-overlay/root/shortcut-overlay-root.js +275 -0
  77. package/dist/slider/root/slider-root.d.ts +3 -1
  78. package/dist/slider/root/slider-root.js +2 -1
  79. package/dist/spatial-bar-chart/root/spatial-bar-chart-root.d.ts +1 -0
  80. package/dist/spatial-bar-chart/root/spatial-bar-chart-root.js +1 -1
  81. package/dist/spatial-heatmap/root/spatial-heatmap-root.d.ts +1 -0
  82. package/dist/spatial-heatmap/root/spatial-heatmap-root.js +1 -1
  83. package/dist/spatial-ribbon-chart/root/spatial-ribbon-chart-root.d.ts +1 -0
  84. package/dist/spatial-ribbon-chart/root/spatial-ribbon-chart-root.js +1 -1
  85. package/dist/spatial-scatter-chart/root/spatial-scatter-chart-root.d.ts +1 -0
  86. package/dist/spatial-scatter-chart/root/spatial-scatter-chart-root.js +1 -1
  87. package/dist/spatial-surface-chart/root/spatial-surface-chart-root.d.ts +1 -0
  88. package/dist/spatial-surface-chart/root/spatial-surface-chart-root.js +1 -1
  89. package/dist/spatial-treemap/root/spatial-treemap-root.d.ts +1 -0
  90. package/dist/spatial-treemap/root/spatial-treemap-root.js +1 -1
  91. package/dist/switch/root/switch-root.d.ts +3 -1
  92. package/dist/switch/root/switch-root.js +2 -1
  93. package/dist/tabs/tab/tab.d.ts +3 -1
  94. package/dist/tabs/tab/tab.js +2 -1
  95. package/dist/textarea/root/textarea-root.d.ts +20 -4
  96. package/dist/textarea/root/textarea-root.js +31 -23
  97. package/dist/time-input/root/time-input-root.d.ts +6 -0
  98. package/dist/time-input/root/time-input-root.js +4 -2
  99. package/dist/time-picker/root/time-picker-root.d.ts +6 -0
  100. package/dist/time-picker/root/time-picker-root.js +4 -2
  101. package/dist/toast/root/toast-root.d.ts +64 -0
  102. package/dist/toast/root/toast-root.js +128 -3
  103. package/dist/toggle/root/toggle-root.d.ts +3 -1
  104. package/dist/toggle/root/toggle-root.js +2 -1
  105. package/dist/virtual-list/root/virtual-list-root.d.ts +18 -2
  106. package/dist/virtual-list/root/virtual-list-root.js +103 -5
  107. package/examples.json +1 -1
  108. package/lint.json +1 -1
  109. package/package.json +6 -6
  110. package/types/jsx.d.ts +5315 -596
  111. package/types/svelte.d.ts +4 -0
  112. package/types/vue.d.ts +1085 -4
  113. package/types/words.d.ts +491 -0
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from "tslib";
2
- import { AriaForwardController, anchorElement, auditEntry, customElement, DrilldownController, deepActiveElement, deepContains, focusTarget, HelixElement, inlineStep, KeyboardNavigationController, linkDescription, MIRROR_RULE, MixinCollection, MixinControllerOpen, numberConverter, OpenPhaseController, onUnlessFalse, PopoverController, scrollItemIntoView, sideOf, slottedWords, tellDisclosure, typeaheadBy, unlinkDescription, words, } from '@fusion.dev/helix-core';
2
+ import { AriaForwardController, anchorElement, auditEntry, customElement, DrilldownController, deepActiveElement, deepContains, elementById, focusTarget, HelixElement, inlineStep, KeyboardNavigationController, linkDescription, MIRROR_RULE, MixinCollection, MixinControllerOpen, numberConverter, OpenPhaseController, onUnlessFalse, PopoverController, scrollItemIntoView, sideOf, slottedWords, tellDisclosure, typeaheadBy, unlinkDescription, words, } from '@fusion.dev/helix-core';
3
3
  import { caretLeft } from '@fusion.dev/helix-icons';
4
4
  import { html, nothing } from 'lit';
5
5
  import { property } from 'lit/decorators.js';
@@ -32,6 +32,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
32
32
  this.filter = '';
33
33
  this.filterable = false;
34
34
  this.filterLabel = 'Filter';
35
+ this.for = '';
35
36
  this.label = '';
36
37
  this.longPressLabel = 'Long press or press Alt+Down to show the menu';
37
38
  this.noResultsText = 'No matches';
@@ -54,6 +55,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
54
55
  this.placement = 'bottom-start';
55
56
  this.resultsLabel = '{count, plural, one {# result} other {# results}}';
56
57
  this.submenus = 'drill';
58
+ this.targets = '';
57
59
  this.drilldown = new DrilldownController(this, {
58
60
  isRow: (element) => 'isMenuItem' in element && element.isMenuItem === true,
59
61
  root: () => [...this.children]
@@ -80,9 +82,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
80
82
  target: () => this.menuBox,
81
83
  });
82
84
  this.panel = new PopoverController(this, {
83
- anchor: () => this.context && this.point
84
- ? this.renderRoot?.querySelector('#point')
85
- : this.trigger,
85
+ anchor: () => this.point ? this.renderRoot?.querySelector('#point') : this.trigger,
86
86
  boundary: () => this,
87
87
  offset: () => this.offset,
88
88
  onDismiss: () => this.hide(),
@@ -129,21 +129,25 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
129
129
  this.trigger.focus();
130
130
  }
131
131
  };
132
+ this.contextTarget = undefined;
132
133
  this.handleContextMenu = (event) => {
133
134
  if (!this.context) {
134
135
  return;
135
136
  }
136
- const slot = this.renderRoot?.querySelector('slot[name="trigger"]');
137
- const areas = slot?.assignedElements({ flatten: true }) ?? [];
138
- if (!event.composedPath().some((node) => areas.includes(node))) {
137
+ const keyed = event.clientX === 0 && event.clientY === 0;
138
+ if (event.shiftKey && !keyed) {
139
+ return;
140
+ }
141
+ const target = this.targetOf(event);
142
+ if (!target) {
139
143
  return;
140
144
  }
141
145
  event.preventDefault();
142
146
  if (this.open && this.longPress.takeClick()) {
143
147
  return;
144
148
  }
145
- const box = this.trigger.getBoundingClientRect();
146
- const keyed = event.clientX === 0 && event.clientY === 0;
149
+ this.contextTarget = target;
150
+ const box = target.getBoundingClientRect();
147
151
  this.openContextAt(keyed ? { x: box.left, y: box.top } : { x: event.clientX, y: event.clientY });
148
152
  };
149
153
  this.handleSelect = (event) => {
@@ -221,10 +225,14 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
221
225
  }
222
226
  };
223
227
  this.handlePointerDown = (event) => {
224
- if (this.open || !this.fromTrigger(event)) {
228
+ if (this.open) {
225
229
  return;
226
230
  }
227
- if (this.pressHeld || (this.context && event.pointerType !== 'mouse')) {
231
+ const held = this.context && event.pointerType !== 'mouse' ? this.targetOf(event) : undefined;
232
+ if (held) {
233
+ this.contextTarget = held;
234
+ }
235
+ if ((this.pressHeld && this.fromTrigger(event)) || held) {
228
236
  this.heldAt = { x: event.clientX, y: event.clientY };
229
237
  this.longPress.down(event);
230
238
  }
@@ -308,6 +316,11 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
308
316
  until: Date.now() + GRACE,
309
317
  };
310
318
  };
319
+ this.handleAreaKeydown = (event) => {
320
+ if (!this.open) {
321
+ this.handleClosedKeydown(event);
322
+ }
323
+ };
311
324
  this.namedByPage = false;
312
325
  }
313
326
  static { this.markRules = [MIRROR_RULE]; }
@@ -431,11 +444,32 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
431
444
  this.reach(undefined);
432
445
  if (deepContains(this, deepActiveElement())) {
433
446
  ;
434
- (this.context ? (this.returnTo ?? this.trigger) : this.trigger).focus();
447
+ (this.returnTo ?? this.trigger).focus();
435
448
  }
436
449
  this.point = undefined;
437
450
  this.returnTo = undefined;
438
451
  }
452
+ showAt(point, target) {
453
+ this.contextTarget = target;
454
+ this.openContextAt(point);
455
+ }
456
+ get contextAreas() {
457
+ const slot = this.renderRoot?.querySelector('slot[name="trigger"]');
458
+ const named = this.isConnected && this.for !== '' ? elementById(this, this.for) : null;
459
+ return [...(slot?.assignedElements({ flatten: true }) ?? []), ...(named ? [named] : [])];
460
+ }
461
+ targetOf(event) {
462
+ const path = event.composedPath().filter((node) => node instanceof Element);
463
+ const areas = this.contextAreas;
464
+ const area = path.find((node) => areas.includes(node));
465
+ if (!area) {
466
+ return undefined;
467
+ }
468
+ if (this.targets === '') {
469
+ return area;
470
+ }
471
+ return path.slice(0, path.indexOf(area) + 1).find((node) => node.matches(this.targets));
472
+ }
439
473
  openContextAt(point) {
440
474
  this.point = point;
441
475
  if (this.open) {
@@ -512,9 +546,11 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
512
546
  scrollItemIntoView(item, { padding: 4, ...(surface ? { scroller: surface } : {}) });
513
547
  }
514
548
  handleClosedKeydown(event) {
515
- if (this.context && event.shiftKey && event.key === 'F10' && this.fromTrigger(event)) {
549
+ const asked = this.context && event.shiftKey && event.key === 'F10' ? this.targetOf(event) : undefined;
550
+ if (asked) {
516
551
  event.preventDefault();
517
- const box = this.trigger.getBoundingClientRect();
552
+ this.contextTarget = asked;
553
+ const box = asked.getBoundingClientRect();
518
554
  this.openContextAt({ x: box.left, y: box.top });
519
555
  return;
520
556
  }
@@ -574,6 +610,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
574
610
  this.rowWatch = new MutationObserver(this.followRemoved);
575
611
  this.rowWatch.observe(this, { childList: true, subtree: true });
576
612
  void this.whenSettled.then(() => {
613
+ this.watchArea();
577
614
  this.settledOnce = true;
578
615
  if (!this.context) {
579
616
  this.tellTrigger();
@@ -595,6 +632,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
595
632
  this.removeEventListener('pointercancel', this.handlePointerCancel);
596
633
  this.removeEventListener('click', this.handleHeldClick, true);
597
634
  this.removeEventListener('focusin', this.handleTriggerFocusIn);
635
+ this.unwatchArea();
598
636
  this.rowWatch?.disconnect();
599
637
  this.rowWatch = undefined;
600
638
  if (this.described) {
@@ -602,8 +640,41 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
602
640
  this.described = undefined;
603
641
  }
604
642
  }
643
+ watchArea() {
644
+ const area = this.context && this.isConnected && this.for !== '' ? elementById(this, this.for) : null;
645
+ if (area === this.watched) {
646
+ return;
647
+ }
648
+ this.unwatchArea();
649
+ if (!area) {
650
+ return;
651
+ }
652
+ area.addEventListener('contextmenu', this.handleContextMenu);
653
+ area.addEventListener('pointerdown', this.handlePointerDown);
654
+ area.addEventListener('pointermove', this.handlePointerMove);
655
+ area.addEventListener('pointerup', this.handlePointerUp);
656
+ area.addEventListener('pointercancel', this.handlePointerCancel);
657
+ area.addEventListener('keydown', this.handleAreaKeydown);
658
+ this.watched = area;
659
+ }
660
+ unwatchArea() {
661
+ const area = this.watched;
662
+ if (!area) {
663
+ return;
664
+ }
665
+ area.removeEventListener('contextmenu', this.handleContextMenu);
666
+ area.removeEventListener('pointerdown', this.handlePointerDown);
667
+ area.removeEventListener('pointermove', this.handlePointerMove);
668
+ area.removeEventListener('pointerup', this.handlePointerUp);
669
+ area.removeEventListener('pointercancel', this.handlePointerCancel);
670
+ area.removeEventListener('keydown', this.handleAreaKeydown);
671
+ this.watched = undefined;
672
+ }
605
673
  updated(changed) {
606
674
  super.updated(changed);
675
+ if (changed.has('for') || changed.has('context')) {
676
+ this.watchArea();
677
+ }
607
678
  if (changed.has('open') && this.open) {
608
679
  this.toldChecked = this.checkedValues.join('\u0000');
609
680
  }
@@ -699,7 +770,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
699
770
  }
700
771
  }
701
772
  render() {
702
- const point = this.context && this.point;
773
+ const point = this.point;
703
774
  const filters = this.filters;
704
775
  this.announced = '';
705
776
  const none = filters?.status();
@@ -768,6 +839,9 @@ __decorate([
768
839
  __decorate([
769
840
  property({ attribute: false })
770
841
  ], HelixHeadlessMenu.prototype, "filterMatch", void 0);
842
+ __decorate([
843
+ property()
844
+ ], HelixHeadlessMenu.prototype, "for", void 0);
771
845
  __decorate([
772
846
  property()
773
847
  ], HelixHeadlessMenu.prototype, "label", void 0);
@@ -795,6 +869,9 @@ __decorate([
795
869
  __decorate([
796
870
  property()
797
871
  ], HelixHeadlessMenu.prototype, "submenus", void 0);
872
+ __decorate([
873
+ property()
874
+ ], HelixHeadlessMenu.prototype, "targets", void 0);
798
875
  HelixHeadlessMenu = __decorate([
799
876
  customElement('helix-headless-menu')
800
877
  ], HelixHeadlessMenu);
@@ -65,6 +65,9 @@ import '../../select/index.js';
65
65
  * @csspart control-listbox-loading - The text shown while the options load.
66
66
  * @csspart control-listbox-search - The region that holds the filter field.
67
67
  * @csspart control-listbox-search-field - The filter field.
68
+ * @csspart control-listbox-voice - The dictation button in the filter field.
69
+ * @csspart control-listbox-voice-listening - The dictation button while it listens.
70
+ * @csspart control-listbox-voice-status - What a screen reader hears as dictation starts and stops.
68
71
  * @csspart control-live - The select's `live` part, the region a screen reader hears a choice made on the closed trigger from.
69
72
  * @csspart control-surface - The floating panel.
70
73
  * @csspart control-trigger - The closed control, which shows the chosen size.
@@ -94,7 +94,8 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
94
94
  listbox-filter-mark: control-listbox-filter-mark, listbox-hint: control-listbox-hint,
95
95
  listbox-items: control-listbox-items, listbox-label: control-listbox-label,
96
96
  listbox-live: control-listbox-live, listbox-loading: control-listbox-loading, listbox-search: control-listbox-search,
97
- listbox-search-field: control-listbox-search-field, live: control-live, surface: control-surface,
97
+ listbox-search-field: control-listbox-search-field, listbox-voice: control-listbox-voice,
98
+ listbox-voice-listening: control-listbox-voice-listening, listbox-voice-status: control-listbox-voice-status, live: control-live, surface: control-surface,
98
99
  trigger: control-trigger, value: control-value"
99
100
  label=${named ? '' : this.label}
100
101
  aria-label=${named || nothing}
@@ -122,6 +122,7 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
122
122
  * @csspart point-active - The point of the row the reading rests on, one for each series with a point in that row, drawn over the others as an element of its own and placed by `--chart-point-x` and `--chart-point-y`. Under `size-by`, it carries its size as `--chart-point-weight`.
123
123
  * @csspart point-ring - The points of a `point` path again, under it, to stroke a little wider in the page's color, so each point keeps its edge where it overlaps another.
124
124
  * @csspart points - The points of one series that do not overlap one another, as a group of their `point-ring` and `point` paths. Its opacity is each point's, so where points overlap they darken. Carries its series color as `--chart-series`.
125
+ * @csspart sonify - The button that plays the chart as sound, under `sonify`.
125
126
  * @csspart summary - The text that says how strongly the measures relate, for people who cannot see the points.
126
127
  * @csspart svg - The drawing surface the gridlines and the trend lines sit on.
127
128
  * @csspart table - The readings as a table, for a screen reader, rendered only where they were drawn from `data`, a page of them at a time past a few hundred. Hide it visually.
@@ -269,7 +269,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
269
269
  <span aria-hidden="true" dir="auto" part="x-name">${field.xName}</span>
270
270
  <span aria-hidden="true" dir="auto" part="y-name">${field.yNames.join(', ')}</span>
271
271
  </div>
272
- ${this.renderSummary(field)}${this.renderTable()}`;
272
+ ${this.renderSummary(field)}${this.renderSonify()}${this.renderTable()}`;
273
273
  }
274
274
  renderPlot(field, along, up) {
275
275
  const at = this.pointer.at;
@@ -1,4 +1,4 @@
1
- import { AriaForwardController, type DataOptionItem, HelixFormElement, PopoverController, UpgradeController } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, type DataOptionItem, HelixFormElement, ListedController, PopoverController, UpgradeController } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import type { HelixHeadlessOption } from '../../option/root/option-root.js';
4
4
  import '../../listbox/index.js';
@@ -111,6 +111,9 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
111
111
  * @csspart listbox-loading - The text shown while the options load.
112
112
  * @csspart listbox-search - The region that holds the filter field.
113
113
  * @csspart listbox-search-field - The filter field.
114
+ * @csspart listbox-voice - The dictation button in the filter field.
115
+ * @csspart listbox-voice-listening - The dictation button while it listens.
116
+ * @csspart listbox-voice-status - What a screen reader hears as dictation starts and stops.
114
117
  * @csspart live - The region a screen reader announces a choice made on the closed trigger from, drawn once there is one to say. Visually hidden in the styled tier.
115
118
  * @csspart surface - The floating panel.
116
119
  * @csspart trigger - The closed control, which shows the chosen value.
@@ -125,6 +128,8 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
125
128
  * @cssstate placed-top - While the open list sits above the trigger, where there was no room below.
126
129
  */
127
130
  export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
131
+ /** On the page's list of controls, where a command palette and a shortcut overlay find it. */
132
+ protected readonly listed: ListedController;
128
133
  /**
129
134
  * The key this family's words are registered under, its styled tag:
130
135
  * `registerWords('de', { 'helix-select': { placeholder: 'Auswählen' } })`.
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from "tslib";
2
- import { AriaForwardController, afterLinkFollowed, auditChildren, chosenValues, customElement, dataOptions, drawAutofill, drawStatus, HelixFormElement, hostAria, hostWords, inlineStep, isRtl, labelsOf, MixinControllerOpen, MixinControllerValue, MixinField, onApple, PopoverController, reportValues, StatusController, sideOf, typesCharacter, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
2
+ import { AriaForwardController, afterLinkFollowed, auditChildren, chosenValues, customElement, dataOptions, drawAutofill, drawStatus, HelixFormElement, hostAria, hostWords, inlineStep, isRtl, ListedController, labelsOf, MixinControllerOpen, MixinControllerValue, MixinField, onApple, PopoverController, reportValues, StatusController, sideOf, typesCharacter, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
3
3
  import { caretDown } from '@fusion.dev/helix-icons';
4
4
  import { nothing } from 'lit';
5
5
  import { property } from 'lit/decorators.js';
@@ -11,6 +11,7 @@ import { over } from '../align.js';
11
11
  let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(MixinControllerValue(MixinField(HelixFormElement))) {
12
12
  constructor() {
13
13
  super(...arguments);
14
+ this.listed = new ListedController(this, 'focus', () => this.internals?.ariaKeyShortcuts);
14
15
  this.aria = new AriaForwardController(this, {
15
16
  labelledByAfter: () => {
16
17
  const value = this.partNamed('value');
@@ -322,7 +323,8 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
322
323
  exportparts="empty: listbox-empty, error: listbox-error, feedback: listbox-feedback,
323
324
  filter-icon: listbox-filter-icon, filter-mark: listbox-filter-mark, hint: listbox-hint,
324
325
  items: listbox-items, label: listbox-label, live: listbox-live, loading: listbox-loading,
325
- search: listbox-search, search-field: listbox-search-field"
326
+ search: listbox-search, search-field: listbox-search-field,
327
+ voice: listbox-voice, voice-listening: listbox-voice-listening, voice-status: listbox-voice-status"
326
328
  .value=${this.value}
327
329
  ?multiple=${this.multiple}
328
330
  ?filterable=${this.filterable}
@@ -0,0 +1 @@
1
+ export * from './root/shortcut-overlay-root.js';
@@ -0,0 +1 @@
1
+ export * from './root/shortcut-overlay-root.js';
@@ -0,0 +1,128 @@
1
+ import { HelixElement } from '@fusion.dev/helix-core';
2
+ import { type CSSResultGroup, type PropertyValues, type TemplateResult } from 'lit';
3
+ import '../../dialog/index.js';
4
+ /** A key a reader holds to see the badges. */
5
+ type HoldKey = 'alt' | 'ctrl' | 'mod' | 'shift';
6
+ /**
7
+ * @summary Shows every control's shortcut and what it does while a key is held.
8
+ *
9
+ * @description
10
+ * Place one in the app. Hold the platform's modifier, Command on an Apple
11
+ * keyboard and Control elsewhere, for `delay` and a badge appears beside each
12
+ * control on screen that has a shortcut, with its keys and its name. Release
13
+ * the key and the badges go. Pressing any other key during the hold cancels
14
+ * it, so a reader pressing ⌘K never sees them.
15
+ *
16
+ * What a badge says comes from what the controls already carry: the
17
+ * `aria-keyshortcuts` a Kbd's `for` writes onto its control, a Menu Item's
18
+ * `shortcut`, and the hotkeys Command and Toast register. A control's name is
19
+ * its label. A shortcut with no control on screen, such as a palette's ⌘K, is
20
+ * listed in the sheet.
21
+ *
22
+ * Press `?` outside a text field, or call `showSheet()`, to open the sheet: a
23
+ * dialog listing every shortcut on the page by name, which is how a keyboard
24
+ * or screen reader user gets the same list. Set `sheet-keys` to another chord,
25
+ * or to nothing to leave `?` to the page.
26
+ *
27
+ * Many apps, GitHub and Gmail among them, already give `?` to their own help,
28
+ * so a page that answers `?` itself opens both on one press. Such a page sets
29
+ * `sheet-keys` to another chord, or to nothing and calls `showSheet()` from
30
+ * its own handler.
31
+ *
32
+ * The badges are a picture of what the controls already expose, so they are
33
+ * hidden from assistive technology.
34
+ *
35
+ * @since 0.216.0
36
+ * @status experimental
37
+ * @category navigation
38
+ * @aliases Keyboard shortcuts, Shortcut hints, Key tips, Cheat sheet
39
+ * @documentation https://fusion.dev/helix/components/shortcut-overlay
40
+ *
41
+ * @csspart badge - One control's badge.
42
+ * @csspart badge-keys - A badge's keys.
43
+ * @csspart badge-name - A badge's name for the control.
44
+ * @csspart badges - The layer the badges are drawn in.
45
+ * @csspart empty - What the sheet says when the page has no shortcuts.
46
+ * @csspart keys - A row's keys.
47
+ * @csspart list - The sheet's list.
48
+ * @csspart name - A row's name for what the shortcut does.
49
+ * @csspart row - One shortcut in the sheet.
50
+ * @csspart sheet - The dialog listing every shortcut.
51
+ * @csspart sheet-body - The dialog's `body` part.
52
+ * @csspart sheet-dismiss - The dialog's `dismiss` part.
53
+ * @csspart sheet-dismiss-mark - The dialog's `dismiss-mark` part.
54
+ * @csspart sheet-footer - The dialog's `footer` part.
55
+ * @csspart sheet-header - The dialog's `header` part.
56
+ * @csspart sheet-surface - The dialog's `surface` part.
57
+ *
58
+ * @cssstate showing - While the badges are drawn.
59
+ */
60
+ export declare class HelixHeadlessShortcutOverlay extends HelixElement {
61
+ static styles: CSSResultGroup;
62
+ /**
63
+ * The key this family's words are registered under, its styled tag:
64
+ * `registerWords('de', { 'helix-shortcut-overlay': { label: 'Tastenkürzel' } })`.
65
+ */
66
+ static words: string;
67
+ /** How long the key is held before the badges show, in milliseconds or as `0.6s`. */
68
+ delay: number;
69
+ /** What the sheet says when the page has no shortcuts. */
70
+ emptyLabel: string;
71
+ /**
72
+ * The key a reader holds: `mod` (Command on an Apple keyboard, Control
73
+ * elsewhere), `alt`, `ctrl`, or `shift`.
74
+ */
75
+ hold: HoldKey;
76
+ /** The sheet's name and heading. */
77
+ label: string;
78
+ /**
79
+ * The chord that opens the sheet, `?` by default, which a press in a text
80
+ * field never answers. Empty leaves the key to the page, which wants it
81
+ * where the page already answers `?` itself.
82
+ */
83
+ sheetKeys: string;
84
+ /** The badges drawn while the key is held. */
85
+ private badges;
86
+ /** Whether the sheet is open. */
87
+ private sheetOpen;
88
+ /** The sheet's rows, read when it opens. */
89
+ private rows;
90
+ private timer;
91
+ /** Whether the badges are showing. */
92
+ get showing(): boolean;
93
+ connectedCallback(): void;
94
+ disconnectedCallback(): void;
95
+ /** Draws a badge beside every control on screen that has a shortcut. */
96
+ show(): void;
97
+ /** Takes the badges away. */
98
+ hide(): void;
99
+ /** Opens the sheet listing every shortcut on the page. */
100
+ showSheet(): void;
101
+ /** Closes the sheet. */
102
+ hideSheet(): void;
103
+ /** Every shortcut on the page, the controls' first and then the page's own, each once. */
104
+ private sheetRows;
105
+ private readonly cancel;
106
+ private readonly handleKeydown;
107
+ private readonly handleKeyup;
108
+ protected updated(changed: PropertyValues): void;
109
+ /**
110
+ * Places each badge centered under its control, a few pixels below its
111
+ * bottom edge so it hides none of the control's words, on whole pixels
112
+ * and inside the viewport, where it overlaps no badge placed before it.
113
+ *
114
+ * **A badge that would overlap a neighbor drops its name**, keeping the
115
+ * keys, which is what a reader holding the key is looking for; one that
116
+ * still overlaps moves down a row. Controls side by side in a toolbar are
117
+ * narrower than a key and a name together, and badges drawn over each other
118
+ * read as neither.
119
+ */
120
+ private arrange;
121
+ protected render(): TemplateResult;
122
+ }
123
+ declare global {
124
+ interface HTMLElementTagNameMap {
125
+ 'helix-headless-shortcut-overlay': HelixHeadlessShortcutOverlay;
126
+ }
127
+ }
128
+ export {};