@fusion.dev/helix-headless 0.103.3 → 0.104.1

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 +9260 -880
  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 +924 -0
  14. package/dist/canvas/root/canvas-root.js +1831 -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 +6 -3
  53. package/dist/map/root/map-root.js +8 -2
  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 +5419 -716
  106. package/types/svelte.d.ts +3 -0
  107. package/types/vue.d.ts +1607 -213
@@ -54,6 +54,7 @@ import '../../menu/index.js';
54
54
  * @csspart captions-menu-back-mark - The glyph on the back control of a submenu.
55
55
  * @csspart captions-menu-empty - Shown when there are no items to show.
56
56
  * @csspart captions-menu-header - The bar above a submenu, holding the way back and its name.
57
+ * @csspart captions-menu-live - The inner menu's `live`, the region a screen reader hears its empty and loading lines from.
57
58
  * @csspart captions-menu-loading - Shown while the items are still on their way.
58
59
  * @csspart captions-menu-surface - The floating panel the menu is drawn on.
59
60
  * @csspart captions-menu-title - The name of the submenu that is showing.
@@ -68,6 +69,7 @@ import '../../menu/index.js';
68
69
  * @csspart forward - The control that goes on ten seconds.
69
70
  * @csspart fullscreen - The whole screen, and back.
70
71
  * @csspart header - The region top left, for a heading and a way out of a set.
72
+ * @csspart live - What the loading line says, in a region a screen reader hears when it changes. Visually hidden in the styled tier.
71
73
  * @csspart loading - What is said while the picture waits for more of itself.
72
74
  * The part of that which spins is drawn on it, which is `::part(loading)::before`
73
75
  * from a consumer's sheet: this tier ships no CSS, so a box it renders for one to
@@ -81,6 +83,7 @@ import '../../menu/index.js';
81
83
  * @csspart overflow-back-mark - The glyph on the back control of a submenu.
82
84
  * @csspart overflow-empty - Shown when there are no items to show.
83
85
  * @csspart overflow-header - The bar above a submenu, holding the way back and its name.
86
+ * @csspart overflow-live - The inner menu's `live`, the region a screen reader hears its empty and loading lines from.
84
87
  * @csspart overflow-loading - Shown while the items are still on their way.
85
88
  * @csspart overflow-surface - The floating panel the menu is drawn on.
86
89
  * @csspart overflow-title - The name of the submenu that is showing.
@@ -115,6 +118,18 @@ export declare class HelixHeadlessVideo extends HelixElement {
115
118
  * start control, which is the correct thing to be looking at.
116
119
  */
117
120
  autoplay: boolean;
121
+ /**
122
+ * What the captions control is called where the video has one track, which it switches on and off.
123
+ *
124
+ * **Every word this player speaks is a property**, so a page in another
125
+ * language hears its own: the play, pause, loading and error labels were,
126
+ * and the rest of the bar read out in English beside them.
127
+ */
128
+ captionsLabel: string;
129
+ /**
130
+ * The row that turns captions off, where the video has several tracks to choose from.
131
+ */
132
+ captionsOffLabel: string;
118
133
  /**
119
134
  * Whether the browser draws the controls instead of this element.
120
135
  *
@@ -146,6 +161,10 @@ export declare class HelixHeadlessVideo extends HelixElement {
146
161
  * Whether the browser may offer playback on a remote device.
147
162
  */
148
163
  disableRemotePlayback: boolean;
164
+ /**
165
+ * What the control that saves the file is called.
166
+ */
167
+ downloadLabel: string;
149
168
  /**
150
169
  * And what they are told when it will not play at all.
151
170
  */
@@ -182,6 +201,18 @@ export declare class HelixHeadlessVideo extends HelixElement {
182
201
  * and not something a player can work around.
183
202
  */
184
203
  extraControls: string;
204
+ /**
205
+ * What the control that skips ahead is called, with `{seconds}` filled in.
206
+ */
207
+ forwardLabel: string;
208
+ /**
209
+ * What the control that fills the screen is called.
210
+ *
211
+ * **One name, pressed or not**, since the button says which with
212
+ * `aria-pressed`: a name that changed as well read out "Exit fullscreen,
213
+ * pressed", which is two answers to one question.
214
+ */
215
+ fullscreenLabel: string;
185
216
  /**
186
217
  * How long the bar waits after the pointer stops before it goes, in ms.
187
218
  *
@@ -206,6 +237,18 @@ export declare class HelixHeadlessVideo extends HelixElement {
206
237
  * Whether it starts again at the end.
207
238
  */
208
239
  loop: boolean;
240
+ /**
241
+ * What the button that opens `overflow-controls` is called.
242
+ */
243
+ moreLabel: string;
244
+ /**
245
+ * What the control that silences the video is called, pressed while it is silent.
246
+ */
247
+ muteLabel: string;
248
+ /**
249
+ * What the control that asks for the next video is called.
250
+ */
251
+ nextLabel: string;
209
252
  /**
210
253
  * Controls that go behind one button instead of onto the bar, named the same
211
254
  * way.
@@ -228,6 +271,14 @@ export declare class HelixHeadlessVideo extends HelixElement {
228
271
  * And while it would stop it.
229
272
  */
230
273
  pauseLabel: string;
274
+ /**
275
+ * How the volume is read out, with `{percent}` filled in.
276
+ */
277
+ percentLabel: string;
278
+ /**
279
+ * What the control that floats the video over other windows is called.
280
+ */
281
+ pipLabel: string;
231
282
  /**
232
283
  * What the play control is called while it would start the video.
233
284
  */
@@ -244,6 +295,26 @@ export declare class HelixHeadlessVideo extends HelixElement {
244
295
  * How much to fetch before anything is asked for.
245
296
  */
246
297
  preload: 'auto' | 'metadata' | 'none';
298
+ /**
299
+ * What the control that asks for the previous video is called.
300
+ */
301
+ previousLabel: string;
302
+ /**
303
+ * What the control that casts the video to another device is called.
304
+ */
305
+ remoteLabel: string;
306
+ /**
307
+ * What the control that skips back is called, with `{seconds}` filled in.
308
+ */
309
+ rewindLabel: string;
310
+ /**
311
+ * What the scrubber is called.
312
+ */
313
+ seekLabel: string;
314
+ /**
315
+ * What the control that changes the speed is called.
316
+ */
317
+ speedLabel: string;
247
318
  /**
248
319
  * The speeds offered, slowest first, as multipliers of normal.
249
320
  */
@@ -270,6 +341,19 @@ export declare class HelixHeadlessVideo extends HelixElement {
270
341
  * negation.
271
342
  */
272
343
  startControl?: 'none';
344
+ /**
345
+ * What the menu of tracks is called, where the video has several.
346
+ */
347
+ subtitlesLabel: string;
348
+ /**
349
+ * How the scrubber reads out where the video is, with `{position}` and
350
+ * `{duration}` filled in.
351
+ */
352
+ timeLabel: string;
353
+ /**
354
+ * What the volume slider is called.
355
+ */
356
+ volumeLabel: string;
273
357
  /**
274
358
  * Whether playback has stopped to wait for data.
275
359
  *
@@ -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 { activeCue, adoptTrack, CueController, captionsAmong, captionTracks, copiesOf, customElement, drawIcon, FullscreenController, HelixElement, HelixNextEvent, HelixPreviousEvent, IdleController, MediaSessionController, onUnlessFalse, RemotePlaybackController, SKIP_SECONDS, sameCopies, showCaption, writtenList, writtenNumbers, } from '@fusion.dev/helix-core';
7
+ import { activeCue, adoptTrack, CueController, captionsAmong, captionTracks, copiesOf, customElement, drawIcon, FullscreenController, fillTemplate, HelixElement, HelixNextEvent, HelixPreviousEvent, IdleController, MediaSessionController, onUnlessFalse, RemotePlaybackController, SKIP_SECONDS, sameCopies, showCaption, writtenList, writtenNumbers, } from '@fusion.dev/helix-core';
8
8
  import { airplay, arrowClockwise, arrowCounterClockwise, closedCaptioning, cornersIn, cornersOut, dotsThreeVertical, download, gauge, pause, pictureInPicture, play, skipBack, skipForward, speakerHigh, speakerX, } from '@fusion.dev/helix-icons';
9
9
  import { nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -29,25 +29,43 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
29
29
  constructor() {
30
30
  super(...arguments);
31
31
  this.autoplay = false;
32
+ this.captionsLabel = 'Captions';
33
+ this.captionsOffLabel = 'Off';
32
34
  this.controls = false;
33
35
  this.crossOrigin = null;
34
36
  this.defaultMuted = false;
35
37
  this.disablePictureInPicture = false;
36
38
  this.disableRemotePlayback = false;
39
+ this.downloadLabel = 'Download';
37
40
  this.errorLabel = 'This video could not be played';
38
41
  this.extraControls = '';
42
+ this.forwardLabel = 'Forward {seconds} seconds';
43
+ this.fullscreenLabel = 'Fullscreen';
39
44
  this.idleDelay = 2500;
40
45
  this.label = '';
41
46
  this.loadingLabel = 'Loading';
42
47
  this.loop = false;
48
+ this.moreLabel = 'More controls';
49
+ this.muteLabel = 'Mute';
50
+ this.nextLabel = 'Next';
43
51
  this.overflowControls = '';
44
52
  this.pauseLabel = 'Pause';
53
+ this.percentLabel = '{percent} percent';
54
+ this.pipLabel = 'Picture in picture';
45
55
  this.playLabel = 'Play';
46
56
  this.playsInline = true;
47
57
  this.poster = '';
48
58
  this.preload = 'metadata';
59
+ this.previousLabel = 'Previous';
60
+ this.remoteLabel = 'Play on another device';
61
+ this.rewindLabel = 'Back {seconds} seconds';
62
+ this.seekLabel = 'Seek';
63
+ this.speedLabel = 'Playback speed';
49
64
  this.speeds = '0.5 1 1.5 2';
50
65
  this.src = '';
66
+ this.subtitlesLabel = 'Subtitles';
67
+ this.timeLabel = '{position} of {duration}';
68
+ this.volumeLabel = 'Volume';
51
69
  this.buffering = false;
52
70
  this.failed = false;
53
71
  this.playing = false;
@@ -400,7 +418,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
400
418
  return html `<button
401
419
  part="remote${this.remoteConnected ? ' remote-pressed' : ''}"
402
420
  type="button"
403
- aria-label="Play on another device"
421
+ aria-label=${this.remoteLabel}
404
422
  aria-pressed=${this.remoteConnected ? 'true' : 'false'}
405
423
  @click=${() => void this.remote.prompt()}
406
424
  >
@@ -411,7 +429,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
411
429
  return html `<button
412
430
  part="rewind"
413
431
  type="button"
414
- aria-label=${`Back ${SKIP_SECONDS} seconds`}
432
+ aria-label=${fillTemplate(this.rewindLabel, { seconds: SKIP_SECONDS })}
415
433
  @click=${() => this.skipBy(-SKIP_SECONDS)}
416
434
  >
417
435
  ${drawIcon(arrowCounterClockwise)}
@@ -421,7 +439,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
421
439
  return html `<button
422
440
  part="forward"
423
441
  type="button"
424
- aria-label=${`Forward ${SKIP_SECONDS} seconds`}
442
+ aria-label=${fillTemplate(this.forwardLabel, { seconds: SKIP_SECONDS })}
425
443
  @click=${() => this.skipBy(SKIP_SECONDS)}
426
444
  >
427
445
  ${drawIcon(arrowClockwise)}
@@ -431,7 +449,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
431
449
  return html `<button
432
450
  part="speed"
433
451
  type="button"
434
- aria-label="Playback speed"
452
+ aria-label=${this.speedLabel}
435
453
  @click=${() => this.cycleSpeed()}
436
454
  >
437
455
  ${this.rate}x
@@ -441,7 +459,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
441
459
  return html `<button
442
460
  part="previous"
443
461
  type="button"
444
- aria-label="Previous"
462
+ aria-label=${this.previousLabel}
445
463
  @click=${() => this.skip(true)}
446
464
  >
447
465
  ${drawIcon(skipBack)}
@@ -451,7 +469,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
451
469
  return html `<button
452
470
  part="next"
453
471
  type="button"
454
- aria-label="Next"
472
+ aria-label=${this.nextLabel}
455
473
  @click=${() => this.skip(false)}
456
474
  >
457
475
  ${drawIcon(skipForward)}
@@ -465,7 +483,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
465
483
  href=${this.src}
466
484
  target=${local ? nothing : '_blank'}
467
485
  rel=${local ? nothing : 'noreferrer'}
468
- aria-label="Download"
486
+ aria-label=${this.downloadLabel}
469
487
  >
470
488
  ${drawIcon(download)}
471
489
  </a>`;
@@ -473,7 +491,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
473
491
  return html `<button
474
492
  part="pip"
475
493
  type="button"
476
- aria-label="Picture in picture"
494
+ aria-label=${this.pipLabel}
477
495
  @click=${() => void this.togglePip()}
478
496
  >
479
497
  ${drawIcon(pictureInPicture)}
@@ -488,7 +506,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
488
506
  return html `<button
489
507
  part="captions"
490
508
  type="button"
491
- aria-label="Captions"
509
+ aria-label=${this.captionsLabel}
492
510
  aria-pressed=${this.captioned ? 'true' : 'false'}
493
511
  @click=${() => this.toggleCaptions()}
494
512
  >
@@ -497,26 +515,28 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
497
515
  }
498
516
  return html `<${this.tag('menu')} part="captions-menu"
499
517
  exportparts="back: captions-menu-back, back-mark: captions-menu-back-mark, empty: captions-menu-empty,
500
- header: captions-menu-header, loading: captions-menu-loading, surface: captions-menu-surface,
501
- title: captions-menu-title" label="Subtitles" placement="top-end">
502
- <button part="captions" slot="trigger" type="button" aria-label="Subtitles">
518
+ header: captions-menu-header, live: captions-menu-live, loading: captions-menu-loading, surface: captions-menu-surface,
519
+ title: captions-menu-title" label=${this.subtitlesLabel} placement="top-end">
520
+ <button part="captions" slot="trigger" type="button" aria-label=${this.subtitlesLabel}>
503
521
  ${drawIcon(closedCaptioning)}
504
522
  </button>
505
523
  <${this.tag('menu-item')}
506
524
  part="entry"
507
525
  exportparts="item: entry-item, mark: entry-mark, start: entry-start"
508
526
  value="off"
509
- aria-checked=${this.captionIndex < 0 ? 'true' : 'false'}
510
- role="menuitemradio"
527
+ checkable
528
+ exclusive
529
+ ?checked=${this.captionIndex < 0}
511
530
  @helix-select=${() => this.showCaption(-1)}
512
531
  >
513
- Off
532
+ ${this.captionsOffLabel}
514
533
  </${this.tag('menu-item')}>
515
534
  ${tracks.map((track, at) => html `<${this.tag('menu-item')} part="entry"
516
535
  exportparts="item: entry-item, mark: entry-mark, start: entry-start"
517
536
  value=${track.language || String(at)}
518
- aria-checked=${this.captionIndex === at ? 'true' : 'false'}
519
- role="menuitemradio"
537
+ checkable
538
+ exclusive
539
+ ?checked=${this.captionIndex === at}
520
540
  @helix-select=${() => this.showCaption(at)}
521
541
  >
522
542
  ${track.label || track.language}
@@ -531,14 +551,14 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
531
551
  @helix-select=${() => void this.remote.prompt()}
532
552
  >
533
553
  ${drawIcon(airplay, { slot: 'start' })}
534
- Play on another device
554
+ ${this.remoteLabel}
535
555
  </${this.tag('menu-item')}>`;
536
556
  }
537
557
  if (one === 'speed') {
538
558
  return html `<${this.tag('menu-item')} part="entry"
539
559
  exportparts="item: entry-item, mark: entry-mark, start: entry-start" value="speed" @helix-select=${() => this.cycleSpeed()}>
540
560
  ${drawIcon(gauge, { slot: 'start' })}
541
- Playback speed: ${this.rate}x
561
+ ${this.speedLabel}: ${this.rate}x
542
562
  </${this.tag('menu-item')}>`;
543
563
  }
544
564
  if (one === 'rewind' || one === 'forward') {
@@ -549,21 +569,21 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
549
569
  @helix-select=${() => this.skipBy(back ? -SKIP_SECONDS : SKIP_SECONDS)}
550
570
  >
551
571
  ${drawIcon(back ? arrowCounterClockwise : arrowClockwise, { slot: 'start' })}
552
- ${back ? `Back ${SKIP_SECONDS} seconds` : `Forward ${SKIP_SECONDS} seconds`}
572
+ ${fillTemplate(back ? this.rewindLabel : this.forwardLabel, { seconds: SKIP_SECONDS })}
553
573
  </${this.tag('menu-item')}>`;
554
574
  }
555
575
  if (one === 'previous') {
556
576
  return html `<${this.tag('menu-item')} part="entry"
557
577
  exportparts="item: entry-item, mark: entry-mark, start: entry-start" value="previous" @helix-select=${() => this.skip(true)}>
558
578
  ${drawIcon(skipBack, { slot: 'start' })}
559
- Previous
579
+ ${this.previousLabel}
560
580
  </${this.tag('menu-item')}>`;
561
581
  }
562
582
  if (one === 'next') {
563
583
  return html `<${this.tag('menu-item')} part="entry"
564
584
  exportparts="item: entry-item, mark: entry-mark, start: entry-start" value="next" @helix-select=${() => this.skip(false)}>
565
585
  ${drawIcon(skipForward, { slot: 'start' })}
566
- Next
586
+ ${this.nextLabel}
567
587
  </${this.tag('menu-item')}>`;
568
588
  }
569
589
  if (one === 'download') {
@@ -577,13 +597,13 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
577
597
  value="download"
578
598
  >
579
599
  ${drawIcon(download, { slot: 'start' })}
580
- Download
600
+ ${this.downloadLabel}
581
601
  </${this.tag('menu-item')}>`;
582
602
  }
583
603
  return html `<${this.tag('menu-item')} part="entry"
584
604
  exportparts="item: entry-item, mark: entry-mark, start: entry-start" value="pip" @helix-select=${() => void this.togglePip()}>
585
605
  ${drawIcon(pictureInPicture, { slot: 'start' })}
586
- Picture in picture
606
+ ${this.pipLabel}
587
607
  </${this.tag('menu-item')}>`;
588
608
  }
589
609
  renderBar() {
@@ -612,8 +632,11 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
612
632
  max=${Number.isFinite(this.knownDuration) && this.knownDuration > 0 ? this.knownDuration : 0}
613
633
  step="0.01"
614
634
  .value=${String(this.position)}
615
- aria-label="Seek"
616
- aria-valuetext=${`${clock(this.position)} of ${clock(this.knownDuration)}`}
635
+ aria-label=${this.seekLabel}
636
+ aria-valuetext=${fillTemplate(this.timeLabel, {
637
+ duration: clock(this.knownDuration),
638
+ position: clock(this.position),
639
+ })}
617
640
  style=${`--video-progress: ${done}`}
618
641
  @input=${this.takeScrub}
619
642
  />
@@ -621,7 +644,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
621
644
  <button
622
645
  part="mute"
623
646
  type="button"
624
- aria-label=${this.silent ? 'Unmute' : 'Mute'}
647
+ aria-label=${this.muteLabel}
625
648
  aria-pressed=${this.silent ? 'true' : 'false'}
626
649
  @click=${() => {
627
650
  const video = this.video;
@@ -639,8 +662,10 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
639
662
  max="1"
640
663
  step="0.05"
641
664
  .value=${String(this.silent ? 0 : this.loudness)}
642
- aria-label="Volume"
643
- aria-valuetext=${`${Math.round((this.silent ? 0 : this.loudness) * 100)} percent`}
665
+ aria-label=${this.volumeLabel}
666
+ aria-valuetext=${fillTemplate(this.percentLabel, {
667
+ percent: Math.round((this.silent ? 0 : this.loudness) * 100),
668
+ })}
644
669
  style=${`--video-level: ${this.silent ? 0 : this.loudness}`}
645
670
  @input=${this.takeVolume}
646
671
  />
@@ -651,9 +676,9 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
651
676
  ? nothing
652
677
  : html `<${this.tag('menu')} part="overflow"
653
678
  exportparts="back: overflow-back, back-mark: overflow-back-mark, empty: overflow-empty,
654
- header: overflow-header, loading: overflow-loading, surface: overflow-surface,
655
- title: overflow-title" label="More controls" placement="top-end">
656
- <button part="more" slot="trigger" type="button" aria-label="More controls">
679
+ header: overflow-header, live: overflow-live, loading: overflow-loading, surface: overflow-surface,
680
+ title: overflow-title" label=${this.moreLabel} placement="top-end">
681
+ <button part="more" slot="trigger" type="button" aria-label=${this.moreLabel}>
657
682
  ${drawIcon(dotsThreeVertical)}
658
683
  </button>
659
684
  ${this.overflow.map((one) => this.renderOverflowItem(one))}
@@ -663,7 +688,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
663
688
  <button
664
689
  part="fullscreen"
665
690
  type="button"
666
- aria-label=${this.full ? 'Exit fullscreen' : 'Fullscreen'}
691
+ aria-label=${this.fullscreenLabel}
667
692
  aria-pressed=${this.full ? 'true' : 'false'}
668
693
  @click=${() => void this.fullscreen.toggle()}
669
694
  >
@@ -737,14 +762,10 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
737
762
  <div part="header"><slot name="header"></slot></div>
738
763
  <slot name="poster" part="poster"></slot>
739
764
  ${this.buffering && !this.failed
740
- ? html `<div
741
- part="loading"
742
- role="status"
743
- aria-live="polite"
744
- >
745
- ${this.loadingLabel}
746
- </div>`
765
+ ? html `<div part="loading">${this.loadingLabel}</div>`
747
766
  : nothing}
767
+ ${''}
768
+ <span part="live" role="status">${this.buffering && !this.failed ? this.loadingLabel : ''}</span>
748
769
  ${this.failed
749
770
  ? html `<div
750
771
  part="failure"
@@ -774,6 +795,12 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
774
795
  __decorate([
775
796
  property({ reflect: true, type: Boolean })
776
797
  ], HelixHeadlessVideo.prototype, "autoplay", void 0);
798
+ __decorate([
799
+ property({ attribute: 'captions-label' })
800
+ ], HelixHeadlessVideo.prototype, "captionsLabel", void 0);
801
+ __decorate([
802
+ property({ attribute: 'captions-off-label' })
803
+ ], HelixHeadlessVideo.prototype, "captionsOffLabel", void 0);
777
804
  __decorate([
778
805
  property({ reflect: true, type: Boolean })
779
806
  ], HelixHeadlessVideo.prototype, "controls", void 0);
@@ -789,12 +816,21 @@ __decorate([
789
816
  __decorate([
790
817
  property({ attribute: 'disableremoteplayback', reflect: true, type: Boolean })
791
818
  ], HelixHeadlessVideo.prototype, "disableRemotePlayback", void 0);
819
+ __decorate([
820
+ property({ attribute: 'download-label' })
821
+ ], HelixHeadlessVideo.prototype, "downloadLabel", void 0);
792
822
  __decorate([
793
823
  property({ attribute: 'error-label' })
794
824
  ], HelixHeadlessVideo.prototype, "errorLabel", void 0);
795
825
  __decorate([
796
826
  property({ attribute: 'extra-controls' })
797
827
  ], HelixHeadlessVideo.prototype, "extraControls", void 0);
828
+ __decorate([
829
+ property({ attribute: 'forward-label' })
830
+ ], HelixHeadlessVideo.prototype, "forwardLabel", void 0);
831
+ __decorate([
832
+ property({ attribute: 'fullscreen-label' })
833
+ ], HelixHeadlessVideo.prototype, "fullscreenLabel", void 0);
798
834
  __decorate([
799
835
  property({ attribute: 'idle-delay', type: Number })
800
836
  ], HelixHeadlessVideo.prototype, "idleDelay", void 0);
@@ -807,12 +843,27 @@ __decorate([
807
843
  __decorate([
808
844
  property({ reflect: true, type: Boolean })
809
845
  ], HelixHeadlessVideo.prototype, "loop", void 0);
846
+ __decorate([
847
+ property({ attribute: 'more-label' })
848
+ ], HelixHeadlessVideo.prototype, "moreLabel", void 0);
849
+ __decorate([
850
+ property({ attribute: 'mute-label' })
851
+ ], HelixHeadlessVideo.prototype, "muteLabel", void 0);
852
+ __decorate([
853
+ property({ attribute: 'next-label' })
854
+ ], HelixHeadlessVideo.prototype, "nextLabel", void 0);
810
855
  __decorate([
811
856
  property({ attribute: 'overflow-controls' })
812
857
  ], HelixHeadlessVideo.prototype, "overflowControls", void 0);
813
858
  __decorate([
814
859
  property({ attribute: 'pause-label' })
815
860
  ], HelixHeadlessVideo.prototype, "pauseLabel", void 0);
861
+ __decorate([
862
+ property({ attribute: 'percent-label' })
863
+ ], HelixHeadlessVideo.prototype, "percentLabel", void 0);
864
+ __decorate([
865
+ property({ attribute: 'pip-label' })
866
+ ], HelixHeadlessVideo.prototype, "pipLabel", void 0);
816
867
  __decorate([
817
868
  property({ attribute: 'play-label' })
818
869
  ], HelixHeadlessVideo.prototype, "playLabel", void 0);
@@ -825,6 +876,21 @@ __decorate([
825
876
  __decorate([
826
877
  property()
827
878
  ], HelixHeadlessVideo.prototype, "preload", void 0);
879
+ __decorate([
880
+ property({ attribute: 'previous-label' })
881
+ ], HelixHeadlessVideo.prototype, "previousLabel", void 0);
882
+ __decorate([
883
+ property({ attribute: 'remote-label' })
884
+ ], HelixHeadlessVideo.prototype, "remoteLabel", void 0);
885
+ __decorate([
886
+ property({ attribute: 'rewind-label' })
887
+ ], HelixHeadlessVideo.prototype, "rewindLabel", void 0);
888
+ __decorate([
889
+ property({ attribute: 'seek-label' })
890
+ ], HelixHeadlessVideo.prototype, "seekLabel", void 0);
891
+ __decorate([
892
+ property({ attribute: 'speed-label' })
893
+ ], HelixHeadlessVideo.prototype, "speedLabel", void 0);
828
894
  __decorate([
829
895
  property({ attribute: 'speeds' })
830
896
  ], HelixHeadlessVideo.prototype, "speeds", void 0);
@@ -834,6 +900,15 @@ __decorate([
834
900
  __decorate([
835
901
  property({ attribute: 'start-control' })
836
902
  ], HelixHeadlessVideo.prototype, "startControl", void 0);
903
+ __decorate([
904
+ property({ attribute: 'subtitles-label' })
905
+ ], HelixHeadlessVideo.prototype, "subtitlesLabel", void 0);
906
+ __decorate([
907
+ property({ attribute: 'time-label' })
908
+ ], HelixHeadlessVideo.prototype, "timeLabel", void 0);
909
+ __decorate([
910
+ property({ attribute: 'volume-label' })
911
+ ], HelixHeadlessVideo.prototype, "volumeLabel", void 0);
837
912
  __decorate([
838
913
  state()
839
914
  ], HelixHeadlessVideo.prototype, "buffering", void 0);
@@ -34,6 +34,7 @@ import '../../menu/index.js';
34
34
  * @csspart menu-back-mark - The glyph on the back control of a submenu.
35
35
  * @csspart menu-empty - Shown when there are no items to show.
36
36
  * @csspart menu-header - The bar above a submenu, holding the way back and its name.
37
+ * @csspart menu-live - The inner menu's `live`, the region a screen reader hears its empty and loading lines from.
37
38
  * @csspart menu-loading - Shown while the items are still on their way.
38
39
  * @csspart menu-surface - The floating panel the menu is drawn on.
39
40
  * @csspart menu-title - The name of the submenu that is showing.
@@ -61,7 +61,7 @@ let HelixHeadlessVideoPlaylistMenu = class HelixHeadlessVideoPlaylistMenu extend
61
61
  const active = this.playlist?.active;
62
62
  return html `<${this.tag('menu')} part="menu"
63
63
  exportparts="back: menu-back, back-mark: menu-back-mark, empty: menu-empty, header: menu-header,
64
- loading: menu-loading, surface: menu-surface, title: menu-title" label=${this.label} placement=${this.placement}>
64
+ live: menu-live, loading: menu-loading, surface: menu-surface, title: menu-title" label=${this.label} placement=${this.placement}>
65
65
  <slot name="trigger" slot="trigger">
66
66
  <button part="trigger" type="button" aria-label=${this.label}>${drawIcon(list)}</button>
67
67
  </slot>
@@ -69,9 +69,10 @@ let HelixHeadlessVideoPlaylistMenu = class HelixHeadlessVideoPlaylistMenu extend
69
69
  part="entry"
70
70
  exportparts="item: entry-item, mark: entry-mark, start: entry-start"
71
71
  value=${entry.value}
72
- aria-checked=${entry.value === active ? 'true' : 'false'}
72
+ checkable
73
+ ?checked=${entry.value === active}
73
74
  ?disabled=${entry.disabled}
74
- role="menuitemradio"
75
+ exclusive
75
76
  @helix-select=${(event) => {
76
77
  event.stopPropagation();
77
78
  this.choose(entry.value);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fusion.dev/helix-headless",
3
3
  "description": "Headless component tier. Structure, accessibility, state, and form participation. No styling.",
4
- "version": "0.103.3",
4
+ "version": "0.104.1",
5
5
  "license": "MIT",
6
6
  "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
7
  "repository": {
@@ -46,13 +46,13 @@
46
46
  },
47
47
  "bugs": "https://github.com/project-fusion/fusion/issues",
48
48
  "dependencies": {
49
- "@fusion.dev/helix-core": "0.103.3",
50
- "@fusion.dev/helix-icons": "0.103.3",
49
+ "@fusion.dev/helix-core": "0.104.1",
50
+ "@fusion.dev/helix-icons": "0.104.1",
51
51
  "uqr": "^0.1.3"
52
52
  },
53
53
  "devDependencies": {
54
- "@fusion.dev/helix-cem": "0.103.3",
55
- "@fusion.dev/helix-testing": "0.103.3",
54
+ "@fusion.dev/helix-cem": "0.104.1",
55
+ "@fusion.dev/helix-testing": "0.104.1",
56
56
  "@fusion.dev/scripts": "0.0.0-dev",
57
57
  "@happy-dom/global-registrator": "^20.0.0",
58
58
  "@lit-labs/ssr": "^4.1.0",