@fusion.dev/helix-headless 0.103.2 → 0.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/custom-elements.json +9259 -712
  2. package/dist/announcement/root/announcement-root.d.ts +9 -2
  3. package/dist/announcement/root/announcement-root.js +9 -6
  4. package/dist/badge/root/badge-root.js +2 -3
  5. package/dist/canvas/edge/canvas-edge.d.ts +112 -0
  6. package/dist/canvas/edge/canvas-edge.js +66 -0
  7. package/dist/canvas/index.d.ts +4 -0
  8. package/dist/canvas/index.js +3 -0
  9. package/dist/canvas/node/canvas-node.d.ts +211 -0
  10. package/dist/canvas/node/canvas-node.js +148 -0
  11. package/dist/canvas/root/canvas-document.d.ts +215 -0
  12. package/dist/canvas/root/canvas-document.js +284 -0
  13. package/dist/canvas/root/canvas-root.d.ts +912 -0
  14. package/dist/canvas/root/canvas-root.js +1814 -0
  15. package/dist/carousel/root/carousel-root.d.ts +53 -16
  16. package/dist/carousel/root/carousel-root.js +46 -11
  17. package/dist/chat/root/chat-root.d.ts +4 -0
  18. package/dist/chat/root/chat-root.js +11 -7
  19. package/dist/checkbox/root/checkbox-root.js +1 -0
  20. package/dist/checkbox-group/root/checkbox-group-root.d.ts +10 -0
  21. package/dist/checkbox-group/root/checkbox-group-root.js +5 -0
  22. package/dist/color-input/root/color-input-root.js +21 -5
  23. package/dist/color-picker/root/color-picker-root.d.ts +55 -0
  24. package/dist/color-picker/root/color-picker-root.js +61 -12
  25. package/dist/combobox/root/combobox-root.d.ts +21 -2
  26. package/dist/combobox/root/combobox-root.js +23 -9
  27. package/dist/command/root/command-root.d.ts +1 -0
  28. package/dist/command/root/command-root.js +1 -1
  29. package/dist/data-table/root/data-table-root.d.ts +43 -42
  30. package/dist/data-table/root/data-table-root.js +35 -34
  31. package/dist/date-input/root/date-input-root.d.ts +27 -0
  32. package/dist/date-input/root/date-input-root.js +38 -9
  33. package/dist/date-picker/root/date-picker-root.d.ts +28 -16
  34. package/dist/date-picker/root/date-picker-root.js +17 -15
  35. package/dist/drilldown/root/drilldown-root.d.ts +1 -0
  36. package/dist/drilldown/root/drilldown-root.js +5 -2
  37. package/dist/element-events.generated.js +15 -0
  38. package/dist/empty/root/empty-root.d.ts +12 -7
  39. package/dist/empty/root/empty-root.js +13 -10
  40. package/dist/file-input/root/file-input-root.d.ts +5 -1
  41. package/dist/file-input/root/file-input-root.js +6 -4
  42. package/dist/filter-input/menu/filter-menu.d.ts +1 -0
  43. package/dist/filter-input/menu/filter-menu.js +1 -1
  44. package/dist/filter-input/root/filter-input-root.js +5 -0
  45. package/dist/index.d.ts +1 -0
  46. package/dist/index.js +1 -0
  47. package/dist/input/root/input-root.js +1 -1
  48. package/dist/lightbox/root/lightbox-root.d.ts +9 -1
  49. package/dist/lightbox/root/lightbox-root.js +17 -7
  50. package/dist/listbox/root/listbox-root.d.ts +16 -14
  51. package/dist/listbox/root/listbox-root.js +24 -15
  52. package/dist/map/root/map-root.d.ts +19 -127
  53. package/dist/map/root/map-root.js +10 -138
  54. package/dist/menu/root/menu-root.d.ts +1 -0
  55. package/dist/menu/root/menu-root.js +1 -1
  56. package/dist/notifications/group/notification-group.js +5 -4
  57. package/dist/notifications/notification/notification.d.ts +10 -10
  58. package/dist/notifications/notification/notification.js +3 -3
  59. package/dist/notifications/root/notifications-root.d.ts +1 -0
  60. package/dist/notifications/root/notifications-root.js +1 -0
  61. package/dist/number-input/root/number-input-root.d.ts +17 -0
  62. package/dist/number-input/root/number-input-root.js +22 -6
  63. package/dist/object-inspector/root/object-inspector-root.d.ts +10 -0
  64. package/dist/object-inspector/root/object-inspector-root.js +10 -2
  65. package/dist/outline/root/outline-root.d.ts +15 -0
  66. package/dist/outline/root/outline-root.js +12 -7
  67. package/dist/pagination/root/pagination-root.d.ts +18 -18
  68. package/dist/pagination/root/pagination-root.js +5 -5
  69. package/dist/pagination/size/pagination-size.d.ts +10 -9
  70. package/dist/pagination/size/pagination-size.js +4 -4
  71. package/dist/pagination/summary/pagination-summary.js +6 -5
  72. package/dist/pin-input/root/pin-input-root.d.ts +5 -0
  73. package/dist/pin-input/root/pin-input-root.js +10 -6
  74. package/dist/rating/root/rating-root.js +3 -2
  75. package/dist/select/root/select-root.d.ts +1 -0
  76. package/dist/select/root/select-root.js +8 -3
  77. package/dist/slider/root/slider-root.d.ts +12 -0
  78. package/dist/slider/root/slider-root.js +13 -1
  79. package/dist/splitter/root/splitter-root.d.ts +44 -35
  80. package/dist/splitter/root/splitter-root.js +27 -22
  81. package/dist/switch/root/switch-root.js +1 -0
  82. package/dist/table/column/table-column.d.ts +17 -0
  83. package/dist/table/column/table-column.js +16 -4
  84. package/dist/table/root/table-root.d.ts +1 -0
  85. package/dist/table/root/table-root.js +1 -1
  86. package/dist/textarea/root/textarea-root.js +1 -1
  87. package/dist/time-input/root/time-input-root.d.ts +29 -0
  88. package/dist/time-input/root/time-input-root.js +31 -10
  89. package/dist/time-picker/root/time-picker-root.d.ts +14 -0
  90. package/dist/time-picker/root/time-picker-root.js +16 -14
  91. package/dist/toast/item/toast-item.d.ts +12 -11
  92. package/dist/toast/item/toast-item.js +11 -5
  93. package/dist/toolbar/root/toolbar-root.js +2 -16
  94. package/dist/tooltip/root/tooltip-root.d.ts +1 -0
  95. package/dist/tooltip/root/tooltip-root.js +6 -0
  96. package/dist/tour/root/tour-root.d.ts +10 -10
  97. package/dist/tour/root/tour-root.js +5 -5
  98. package/dist/tree/root/tree-root.d.ts +1 -0
  99. package/dist/tree/root/tree-root.js +1 -1
  100. package/dist/video/root/video-root.d.ts +84 -0
  101. package/dist/video/root/video-root.js +116 -41
  102. package/dist/video-playlist/menu/video-playlist-menu.d.ts +1 -0
  103. package/dist/video-playlist/menu/video-playlist-menu.js +4 -3
  104. package/package.json +5 -5
  105. package/types/jsx.d.ts +5753 -1076
  106. package/types/svelte.d.ts +3 -0
  107. package/types/vue.d.ts +1668 -282
@@ -12,8 +12,9 @@ declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusio
12
12
  * what filters it, not in what the list is.
13
13
  *
14
14
  * **`value` is comma separated when `multiple` is set**, the way
15
- * `Checkbox.Group`'s is. It stays a string because that is what a form submits
16
- * and what `MixinControllerValue` holds.
15
+ * `Checkbox.Group`'s is, and a string because that is what `MixinControllerValue`
16
+ * holds. The form is sent one entry per answer, as a native `<select multiple>`
17
+ * sends it, so a server never has to know to split on a comma.
17
18
  *
18
19
  * **Chosen and active are two different things.** Chosen is the answer; active
19
20
  * is where the keyboard is. Only the second moves with the arrows, and
@@ -42,6 +43,7 @@ declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusio
42
43
  * @csspart hint - Help under the list.
43
44
  * @csspart items - The list itself.
44
45
  * @csspart label - The question, over the list.
46
+ * @csspart live - The empty and loading lines again, in a region a screen reader hears when they change. Visually hidden in the styled tier.
45
47
  * @csspart loading - Shown while the options are still on their way.
46
48
  * @csspart search - The region holding the field that narrows the list.
47
49
  * @csspart search-field - The field itself.
@@ -59,22 +61,10 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
59
61
  * keystrokes as the listbox. A consumer who wants autofill can still ask.
60
62
  */
61
63
  autocomplete: string;
62
- /**
63
- * What the list is narrowed to, if anything.
64
- *
65
- * Filtering hides rather than removes, so nothing about the value changes and
66
- * the list is still the consumer's own elements in their own order. Reading
67
- * gives what is being filtered on; writing declares it theirs, and
68
- * `default-filter` seeds one the list owns.
69
- */
70
- get filter(): string;
71
- set filter(next: string);
72
64
  /**
73
65
  * What to start narrowed to, where nothing declared it.
74
66
  */
75
67
  defaultFilter: string;
76
- /** What the list is narrowed to, whoever set it. */
77
- private filterState;
78
68
  /**
79
69
  * What is shown when a filter has hidden every option.
80
70
  *
@@ -84,6 +74,18 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
84
74
  * never given anything.
85
75
  */
86
76
  emptyText: string;
77
+ /** What the list is narrowed to, whoever set it. */
78
+ private filterState;
79
+ /**
80
+ * What the list is narrowed to, if anything.
81
+ *
82
+ * Filtering hides rather than removes, so nothing about the value changes and
83
+ * the list is still the consumer's own elements in their own order. Reading
84
+ * gives what is being filtered on; writing declares it theirs, and
85
+ * `default-filter` seeds one the list owns.
86
+ */
87
+ get filter(): string;
88
+ set filter(next: string);
87
89
  /**
88
90
  * Whether the list renders a field for narrowing itself.
89
91
  *
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { AriaForwardController, customElement, DisabledCascadeController, HelixFilterEvent, HelixFormElement, hostAria, MixinCollection, MixinControllerValue, MixinField, requestChange, scrollItemIntoView, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, DisabledCascadeController, HelixFilterEvent, HelixFormElement, hostAria, MixinCollection, MixinControllerValue, MixinField, reportValues, requestChange, scrollItemIntoView, } from '@fusion.dev/helix-core';
8
8
  import { magnifyingGlass } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -63,8 +63,8 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
63
63
  });
64
64
  this.autocomplete = 'off';
65
65
  this.defaultFilter = '';
66
- this.filterState = undefined;
67
66
  this.emptyText = 'No matches';
67
+ this.filterState = undefined;
68
68
  this.filterable = false;
69
69
  this.filterLabel = 'Filter';
70
70
  this.multiple = false;
@@ -286,7 +286,12 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
286
286
  }
287
287
  }
288
288
  sync() {
289
- this.internals.setFormValue(this.value === '' ? null : this.value);
289
+ if (this.multiple) {
290
+ reportValues(this.internals, this.name, this.value === '' ? [] : this.value.split(','));
291
+ }
292
+ else {
293
+ this.internals.setFormValue(this.value === '' ? null : this.value);
294
+ }
290
295
  this.reportRequired(this.value === '', 'Choose one to continue.', 'items');
291
296
  }
292
297
  connectedCallback() {
@@ -303,8 +308,7 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
303
308
  }
304
309
  willUpdate(changed) {
305
310
  super.willUpdate(changed);
306
- hostAria(this.internals, { label: this.label, role: 'listbox' });
307
- this.internals.ariaMultiSelectable = this.multiple ? 'true' : null;
311
+ hostAria(this.internals, { role: '' });
308
312
  if (this.childrenKnown) {
309
313
  this.place();
310
314
  }
@@ -324,7 +328,6 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
324
328
  super.updated(changed);
325
329
  this.followActive();
326
330
  this.sync();
327
- this.linkHost();
328
331
  this.linkActive();
329
332
  }
330
333
  requestFilter(next) {
@@ -354,6 +357,11 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
354
357
  </slot>`;
355
358
  }
356
359
  render() {
360
+ const shown = this.counted && !this.loading
361
+ ? this.filter === ''
362
+ ? this.options.length > 0
363
+ : this.hasMatches
364
+ : true;
357
365
  return html `${this.renderGroupLabel()}
358
366
  ${this.filterable
359
367
  ? html `<div part="search">
@@ -378,32 +386,33 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
378
386
  <div
379
387
  part="items"
380
388
  id="items"
389
+ role="listbox"
381
390
  aria-busy=${this.loading ? 'true' : nothing}
391
+ aria-describedby=${this.describedBy ?? nothing}
392
+ aria-labelledby=${this.labeled ? this.labelId : nothing}
393
+ aria-multiselectable=${this.multiple ? 'true' : nothing}
394
+ aria-required=${this.required ? 'true' : nothing}
382
395
  ${''}
383
396
  tabindex=${this.isDisabled ? -1 : 0}
384
397
  >
385
398
  <slot @slotchange=${() => this.place()}></slot>
386
- ${this.renderStatus(this.counted && !this.loading
387
- ? this.filter === ''
388
- ? this.options.length > 0
389
- : this.hasMatches
390
- : true)}
399
+ ${this.renderStatus(shown)}
391
400
  </div>
392
- ${this.renderHint()}${this.renderFeedback()}`;
401
+ ${this.renderLive(shown)}${this.renderHint()}${this.renderFeedback()}`;
393
402
  }
394
403
  };
395
404
  __decorate([
396
405
  property()
397
406
  ], HelixHeadlessListbox.prototype, "autocomplete", void 0);
398
- __decorate([
399
- property()
400
- ], HelixHeadlessListbox.prototype, "filter", null);
401
407
  __decorate([
402
408
  property({ attribute: 'default-filter' })
403
409
  ], HelixHeadlessListbox.prototype, "defaultFilter", void 0);
404
410
  __decorate([
405
411
  property({ attribute: 'empty-text' })
406
412
  ], HelixHeadlessListbox.prototype, "emptyText", void 0);
413
+ __decorate([
414
+ property()
415
+ ], HelixHeadlessListbox.prototype, "filter", null);
407
416
  __decorate([
408
417
  property({ attribute: 'filterable', reflect: true, type: Boolean })
409
418
  ], HelixHeadlessListbox.prototype, "filterable", void 0);
@@ -1,9 +1,13 @@
1
- import { HelixElement } from '@fusion.dev/helix-core';
1
+ import { HelixElement, type ViewportControlsPlacement, type ViewportPanDetail, type ViewportZoomDetail } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
- /** Which way a press or a key asked the map to go. */
4
- type Way = 'up' | 'down' | 'start' | 'end';
5
- /** Where the controls sit, in the corner words the rest of the library uses. */
6
- export type MapControlsPlacement = 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end';
3
+ /**
4
+ * What `ViewportControlsPlacement` is called for a map.
5
+ *
6
+ * The corners are the surface's and the name is the family's, so a consumer who
7
+ * imported this before the surface was shared still has it.
8
+ */
9
+ export type MapControlsPlacement = ViewportControlsPlacement;
10
+ declare const HelixHeadlessMap_base: (new (...args: any[]) => import("@fusion.dev/helix-core").ViewportElement) & typeof HelixElement;
7
11
  /**
8
12
  * @summary A frame around somebody else's map.
9
13
  *
@@ -33,7 +37,7 @@ export type MapControlsPlacement = 'top-start' | 'top-end' | 'bottom-start' | 'b
33
37
  * A frame that moved the map would have to know whose map it was.
34
38
  *
35
39
  * @since 0.100.0
36
- * @status stable
40
+ * @status experimental
37
41
  * @category media
38
42
  * @aliases Map frame, Map container, Geo
39
43
  * @documentation https://fusion.dev/helix/components/map
@@ -63,57 +67,7 @@ export type MapControlsPlacement = 'top-start' | 'top-end' | 'bottom-start' | 'b
63
67
  * @cssstate fullscreen - While the frame fills the screen.
64
68
  * @cssstate idle - While the reader has been still long enough to hide the chrome.
65
69
  */
66
- export declare class HelixHeadlessMap extends HelixElement {
67
- /**
68
- * Which of the controls this frame draws, as a list of what to keep.
69
- *
70
- * **A list rather than a switch, because the overlap is not symmetric.**
71
- * Every map library draws zoom controls and none of them draws pan buttons:
72
- * MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
73
- * Google's is zoom. So a consumer slotting one of those has our zoom twice
74
- * over and our pan pad not at all, and a single switch would make them choose
75
- * between a duplicate and nothing.
76
- *
77
- * `none` draws none of them, which is the right answer where the slotted map
78
- * already has controls a reader can find: what this family argues for is that
79
- * *a* findable control exists, never that it is ours. The methods stay public
80
- * either way, so a consumer drawing their own chrome can still drive the
81
- * frame.
82
- *
83
- * Absent is all three, which is this library's rule that a resting value is an
84
- * attribute's absence, and it is what the stylesheet asks about: the layout
85
- * rules are written against `[controls]:not([controls~="zoom"])` rather than
86
- * the bare negation, or a frame that named no list at all would be laid out as
87
- * though it had dropped everything.
88
- */
89
- controls?: string;
90
- /**
91
- * Which corner the controls sit in.
92
- *
93
- * **Configurable because there is no safe default**, and this is a collision
94
- * rather than a taste: MapLibre puts its own controls at the top end, Leaflet
95
- * and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
96
- * corner this took would land on somebody's, which is why every one of those
97
- * libraries made it a setting too.
98
- *
99
- * Logical corners rather than left and right, so a right-to-left page moves
100
- * them without a consumer writing a second rule.
101
- *
102
- * Absent is the top end, which is this library's rule that a resting value is
103
- * an attribute's absence: a default that reflected would write an attribute
104
- * onto every host that no server sent and nobody asked for.
105
- */
106
- controlsPlacement?: MapControlsPlacement;
107
- /** What the control that fills the screen is called. */
108
- fullscreenLabel: string;
109
- /**
110
- * How long the reader may be still before the chrome hides, in milliseconds.
111
- *
112
- * Zero keeps it up, which is the default: a map's controls are how a keyboard
113
- * reader operates it, and chrome that hides itself by default would be this
114
- * component undoing its own argument. Set it for a display map nobody drives.
115
- */
116
- idleDelay: number;
70
+ export declare class HelixHeadlessMap extends HelixHeadlessMap_base {
117
71
  /**
118
72
  * Accessible name for the map, which is the one thing a consumer must write.
119
73
  *
@@ -129,80 +83,18 @@ export declare class HelixHeadlessMap extends HelixElement {
129
83
  * at every encounter.
130
84
  */
131
85
  label: string;
86
+ /** The events this family names, the surface naming none of its own. */
87
+ protected panEvent(detail: ViewportPanDetail): Event;
88
+ protected zoomEvent(detail: ViewportZoomDetail): Event;
132
89
  /**
133
- * What the controls are called, for a page not in English.
134
- */
135
- panLabel: string;
136
- /**
137
- * How far one press moves the map, as a fraction of what is on screen.
138
- *
139
- * A fraction rather than a distance, because this frame does not know the
140
- * scale of what is inside it: a quarter of the viewport is the same gesture at
141
- * street level and at country level, and a consumer who wants metres can
142
- * multiply by their own.
143
- */
144
- panStep: number;
145
- /** What the zoom controls are called. */
146
- zoomInLabel: string;
147
- /** What the zoom control that goes the other way is called. */
148
- zoomOutLabel: string;
149
- /** Whether the reader has been still long enough to hide the chrome. */
150
- private resting;
151
- /** Whether the frame is filling the screen. */
152
- private filled;
153
- private readonly fullscreen;
154
- private readonly idle;
155
- /** Whether a named group of controls is one this frame draws. */
156
- private draws;
157
- /** Fills the screen with the frame, or comes back. */
158
- toggleFullscreen(): void;
159
- /** Asks for the map to move, which the consumer answers. */
160
- pan(to: Way): void;
161
- /** Asks for the map to zoom, `1` in and `-1` out. */
162
- zoom(by: number): void;
163
- /**
164
- * The arrow keys, which are the second way rather than the only one.
165
- *
166
- * `inlineStep` rather than a test against `ArrowLeft`, so the reader on a
167
- * right-to-left page gets `end` from the key that points the way their text
168
- * runs, which is what the pan buttons say too.
90
+ * What the group of controls is called.
169
91
  *
170
- * **Only from this frame's own chrome, and that is the difference between one
171
- * move and two.** MapLibre and Leaflet both answer the arrow keys themselves,
172
- * so a press inside a slotted map moves it once on its own and once more on
173
- * the event this would have sent: every press moving twice, and the consumer
174
- * with no way to tell which half to turn off. A press that started in the
175
- * shadow root is this frame's to relay; anything from the map belongs to the
176
- * map.
92
+ * The surface is shared and this is the half that is a map: a reader meeting
93
+ * the group hears what it drives rather than "view controls", which names the
94
+ * mechanism.
177
95
  */
178
- private readonly handleKeydown;
179
- /**
180
- * Starts the wait, so a map nobody has touched counts as still.
181
- *
182
- * Without this the timer only ever starts on a pointer or a focus, and a frame
183
- * rendered on a page the reader never reaches stays awake for as long as the
184
- * page is open: the chrome a consumer asked to hide would hide only after
185
- * being used once, which is the opposite of what an idle delay is for.
186
- */
187
- protected firstUpdated(changed: PropertyValues): void;
96
+ protected get restingControlsLabel(): string;
188
97
  protected willUpdate(changed: PropertyValues): void;
189
- /**
190
- * What one pan button is called, with the way it goes filled in.
191
- *
192
- * Left and right rather than start and end, because the label is read aloud
193
- * and a reader knows which way left is. The event keeps the reading-order
194
- * name, which is the one a right-to-left page needs.
195
- */
196
- private named;
197
- /**
198
- * The controls, or nothing where a consumer kept none of them.
199
- *
200
- * **Written out rather than generated**, because a part name behind an
201
- * interpolation is a part the manifest cannot see: it would publish `pan-`
202
- * and a consumer's `::part(pan-up)` would match nothing. The same cost
203
- * `drawIcon` names for `Trend`.
204
- */
205
- private renderControls;
206
98
  /**
207
99
  * The frame, with each region in a box of its own.
208
100
  *
@@ -4,73 +4,22 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, FullscreenController, HelixElement, HelixMapPanEvent, HelixMapZoomEvent, hostAria, IdleController, inlineStep, } from '@fusion.dev/helix-core';
8
- import { html, nothing } from 'lit';
9
- import { property, state } from 'lit/decorators.js';
10
- let HelixHeadlessMap = class HelixHeadlessMap extends HelixElement {
7
+ import { customElement, HelixElement, HelixMapPanEvent, HelixMapZoomEvent, hostAria, MixinViewport, } from '@fusion.dev/helix-core';
8
+ import { html } from 'lit';
9
+ import { property } from 'lit/decorators.js';
10
+ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement) {
11
11
  constructor() {
12
12
  super(...arguments);
13
- this.fullscreenLabel = 'Fill the screen';
14
- this.idleDelay = 0;
15
13
  this.label = '';
16
- this.panLabel = 'Pan {way}';
17
- this.panStep = 0.25;
18
- this.zoomInLabel = 'Zoom in';
19
- this.zoomOutLabel = 'Zoom out';
20
- this.resting = false;
21
- this.filled = false;
22
- this.fullscreen = new FullscreenController(this, (full) => {
23
- this.filled = full;
24
- });
25
- this.idle = new IdleController(this, () => this.idleDelay, (resting) => {
26
- this.resting = resting;
27
- });
28
- this.handleKeydown = (event) => {
29
- if (!this.renderRoot.contains(event.target)) {
30
- return;
31
- }
32
- const along = inlineStep(this, event.key);
33
- if (along === 1) {
34
- event.preventDefault();
35
- this.pan('end');
36
- }
37
- else if (along === -1) {
38
- event.preventDefault();
39
- this.pan('start');
40
- }
41
- else if (event.key === 'ArrowUp') {
42
- event.preventDefault();
43
- this.pan('up');
44
- }
45
- else if (event.key === 'ArrowDown') {
46
- event.preventDefault();
47
- this.pan('down');
48
- }
49
- else if (event.key === '+' || event.key === '=') {
50
- event.preventDefault();
51
- this.zoom(1);
52
- }
53
- else if (event.key === '-' || event.key === '_') {
54
- event.preventDefault();
55
- this.zoom(-1);
56
- }
57
- };
58
14
  }
59
- draws(group) {
60
- return this.controls === undefined ? true : this.controls.split(/\s+/).includes(group);
15
+ panEvent(detail) {
16
+ return new HelixMapPanEvent(detail);
61
17
  }
62
- toggleFullscreen() {
63
- void this.fullscreen.toggle();
18
+ zoomEvent(detail) {
19
+ return new HelixMapZoomEvent(detail);
64
20
  }
65
- pan(to) {
66
- this.dispatchEvent(new HelixMapPanEvent({ by: this.panStep, to }));
67
- }
68
- zoom(by) {
69
- this.dispatchEvent(new HelixMapZoomEvent({ by }));
70
- }
71
- firstUpdated(changed) {
72
- super.firstUpdated(changed);
73
- this.idle.stir();
21
+ get restingControlsLabel() {
22
+ return 'Map controls';
74
23
  }
75
24
  willUpdate(changed) {
76
25
  super.willUpdate(changed);
@@ -78,53 +27,6 @@ let HelixHeadlessMap = class HelixHeadlessMap extends HelixElement {
78
27
  this.toggleState('fullscreen', this.filled);
79
28
  this.toggleState('idle', this.resting);
80
29
  }
81
- named(way) {
82
- const spoken = way === 'start' ? 'left' : way === 'end' ? 'right' : way;
83
- return this.panLabel.replace('{way}', spoken);
84
- }
85
- renderControls() {
86
- const pan = this.draws('pan');
87
- const zoom = this.draws('zoom');
88
- const fullscreen = this.draws('fullscreen');
89
- if (!pan && !zoom && !fullscreen) {
90
- return nothing;
91
- }
92
- return html `<div part="controls" role="group" aria-label="Map controls">
93
- ${pan
94
- ? html `<button part="pan-up" aria-label=${this.named('up')} type="button" @click=${() => this.pan('up')}>
95
- ↑
96
- </button>
97
- <button part="pan-start" aria-label=${this.named('start')} type="button" @click=${() => this.pan('start')}>
98
- ←
99
- </button>
100
- <button part="pan-end" aria-label=${this.named('end')} type="button" @click=${() => this.pan('end')}>
101
- →
102
- </button>
103
- <button part="pan-down" aria-label=${this.named('down')} type="button" @click=${() => this.pan('down')}>
104
- ↓
105
- </button>`
106
- : nothing}
107
- ${zoom
108
- ? html `<button part="zoom-in" aria-label=${this.zoomInLabel} type="button" @click=${() => this.zoom(1)}>
109
- +
110
- </button>
111
- <button part="zoom-out" aria-label=${this.zoomOutLabel} type="button" @click=${() => this.zoom(-1)}>
112
- −
113
- </button>`
114
- : nothing}
115
- ${fullscreen
116
- ? html `<button
117
- part="fullscreen"
118
- aria-label=${this.fullscreenLabel}
119
- aria-pressed=${this.filled ? 'true' : 'false'}
120
- type="button"
121
- @click=${this.toggleFullscreen}
122
- >
123
- ⤢
124
- </button>`
125
- : nothing}
126
- </div>`;
127
- }
128
30
  render() {
129
31
  return html `<div
130
32
  part="region"
@@ -153,39 +55,9 @@ let HelixHeadlessMap = class HelixHeadlessMap extends HelixElement {
153
55
  </div>`;
154
56
  }
155
57
  };
156
- __decorate([
157
- property({ reflect: true })
158
- ], HelixHeadlessMap.prototype, "controls", void 0);
159
- __decorate([
160
- property({ attribute: 'controls-placement', reflect: true })
161
- ], HelixHeadlessMap.prototype, "controlsPlacement", void 0);
162
- __decorate([
163
- property({ attribute: 'fullscreen-label' })
164
- ], HelixHeadlessMap.prototype, "fullscreenLabel", void 0);
165
- __decorate([
166
- property({ attribute: 'idle-delay', type: Number })
167
- ], HelixHeadlessMap.prototype, "idleDelay", void 0);
168
58
  __decorate([
169
59
  property()
170
60
  ], HelixHeadlessMap.prototype, "label", void 0);
171
- __decorate([
172
- property({ attribute: 'pan-label' })
173
- ], HelixHeadlessMap.prototype, "panLabel", void 0);
174
- __decorate([
175
- property({ attribute: 'pan-step', type: Number })
176
- ], HelixHeadlessMap.prototype, "panStep", void 0);
177
- __decorate([
178
- property({ attribute: 'zoom-in-label' })
179
- ], HelixHeadlessMap.prototype, "zoomInLabel", void 0);
180
- __decorate([
181
- property({ attribute: 'zoom-out-label' })
182
- ], HelixHeadlessMap.prototype, "zoomOutLabel", void 0);
183
- __decorate([
184
- state()
185
- ], HelixHeadlessMap.prototype, "resting", void 0);
186
- __decorate([
187
- state()
188
- ], HelixHeadlessMap.prototype, "filled", void 0);
189
61
  HelixHeadlessMap = __decorate([
190
62
  customElement('helix-headless-map')
191
63
  ], HelixHeadlessMap);
@@ -40,6 +40,7 @@ declare const HelixHeadlessMenu_base: (new (...args: any[]) => import("@fusion.d
40
40
  * @csspart back-mark - The glyph on the back control of a submenu.
41
41
  * @csspart empty - Shown when there are no items to show.
42
42
  * @csspart header - The bar above a submenu, holding the way back and its name.
43
+ * @csspart live - The empty and loading lines again, in a region a screen reader hears when they change. Visually hidden in the styled tier.
43
44
  * @csspart loading - Shown while the items are still on their way.
44
45
  * @csspart surface - The floating panel the menu is drawn on.
45
46
  * @csspart title - The name of the submenu that is showing.
@@ -204,7 +204,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
204
204
  </div>`}
205
205
  <slot @slotchange=${(event) => this.countRows(event)}></slot>
206
206
  ${this.renderStatus(this.hasRows)}
207
- </div>`;
207
+ </div>${this.renderLive(this.hasRows)}`;
208
208
  }
209
209
  };
210
210
  __decorate([
@@ -9,6 +9,7 @@ import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  const TRIGGER_ID = 'trigger';
11
11
  const ITEMS_ID = 'items';
12
+ const LABEL_ID = 'label';
12
13
  let HelixHeadlessNotificationGroup = class HelixHeadlessNotificationGroup extends MixinControllerOpen(HelixElement) {
13
14
  constructor() {
14
15
  super(...arguments);
@@ -34,7 +35,7 @@ let HelixHeadlessNotificationGroup = class HelixHeadlessNotificationGroup extend
34
35
  }
35
36
  willUpdate(changed) {
36
37
  super.willUpdate(changed);
37
- hostAria(this.internals, this.label === '' ? { role: 'group' } : { label: this.label, role: 'group' });
38
+ hostAria(this.internals, { role: 'listitem' });
38
39
  }
39
40
  firstUpdated(changed) {
40
41
  super.firstUpdated(changed);
@@ -76,14 +77,14 @@ let HelixHeadlessNotificationGroup = class HelixHeadlessNotificationGroup extend
76
77
  type="button"
77
78
  @click=${this.handleToggle}
78
79
  >
79
- <span part="label"><slot name="label">${this.label}</slot></span>
80
+ <span part="label" id=${LABEL_ID}><slot name="label">${this.label}</slot></span>
80
81
  ${count}
81
82
  </button>`
82
- : html `<span part="label"><slot name="label">${this.label}</slot></span>
83
+ : html `<span part="label" id=${LABEL_ID}><slot name="label">${this.label}</slot></span>
83
84
  ${count}`}
84
85
  <span part="actions"><slot name="actions"></slot></span>
85
86
  </div>
86
- <div id=${ITEMS_ID} part="items">
87
+ <div id=${ITEMS_ID} part="items" role="list" aria-labelledby=${LABEL_ID}>
87
88
  <slot></slot>
88
89
  </div>`;
89
90
  }
@@ -77,6 +77,16 @@ export declare class HelixHeadlessNotification extends HelixHeadlessNotification
77
77
  * empty string would give.
78
78
  */
79
79
  at: string;
80
+ /**
81
+ * State to open with, where nothing declared one.
82
+ */
83
+ defaultRead: boolean;
84
+ /**
85
+ * Locale for the timestamp.
86
+ *
87
+ * Empty is the runtime's own.
88
+ */
89
+ locale: string;
80
90
  /**
81
91
  * Whether the reader has seen it.
82
92
  *
@@ -94,16 +104,6 @@ export declare class HelixHeadlessNotification extends HelixHeadlessNotification
94
104
  */
95
105
  get read(): boolean;
96
106
  set read(next: boolean);
97
- /**
98
- * State to open with, where nothing declared one.
99
- */
100
- defaultRead: boolean;
101
- /**
102
- * Locale for the timestamp.
103
- *
104
- * Empty is the runtime's own.
105
- */
106
- locale: string;
107
107
  /**
108
108
  * @internal Read by the list to identify its children across the light DOM,
109
109
  * which is cheaper than `instanceof` and is why this is public rather than
@@ -120,15 +120,15 @@ let HelixHeadlessNotification = class HelixHeadlessNotification extends MixinDis
120
120
  __decorate([
121
121
  property()
122
122
  ], HelixHeadlessNotification.prototype, "at", void 0);
123
- __decorate([
124
- property({ type: Boolean })
125
- ], HelixHeadlessNotification.prototype, "read", null);
126
123
  __decorate([
127
124
  property({ attribute: 'default-read', type: Boolean })
128
125
  ], HelixHeadlessNotification.prototype, "defaultRead", void 0);
129
126
  __decorate([
130
127
  property()
131
128
  ], HelixHeadlessNotification.prototype, "locale", void 0);
129
+ __decorate([
130
+ property({ type: Boolean })
131
+ ], HelixHeadlessNotification.prototype, "read", null);
132
132
  HelixHeadlessNotification = __decorate([
133
133
  customElement('helix-headless-notification')
134
134
  ], HelixHeadlessNotification);
@@ -41,6 +41,7 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
41
41
  * @csspart footer - The region below the list.
42
42
  * @csspart header - The region above the list.
43
43
  * @csspart list - The list itself.
44
+ * @csspart live - The empty and loading lines again, in a region a screen reader hears when they change. Visually hidden in the styled tier.
44
45
  * @csspart loading - Shown while the feed is still on its way.
45
46
  * @csspart mark-all - The control that marks everything read.
46
47
  *
@@ -139,6 +139,7 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
139
139
  <slot name="items" @slotchange=${this.handleSlotChange}></slot>
140
140
  ${this.renderStatus(hasItems)}
141
141
  </div>
142
+ ${this.renderLive(hasItems)}
142
143
  <div part="footer"><slot name="footer"></slot></div>`;
143
144
  }
144
145
  };