@vonage/vivid 4.27.0 → 4.29.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 (79) hide show
  1. package/custom-elements.json +357 -80
  2. package/lib/audio-player/audio-player.d.ts +4 -3
  3. package/lib/data-grid/data-grid.d.ts +2 -0
  4. package/lib/data-grid/locale.d.ts +1 -0
  5. package/lib/date-picker/date-picker.d.ts +4 -2
  6. package/lib/date-time-picker/date-time-picker.d.ts +6 -3
  7. package/lib/divider/definition.d.ts +1 -0
  8. package/lib/divider/divider.d.ts +5 -1
  9. package/lib/option/option.d.ts +4 -7
  10. package/lib/rich-text-editor/facades/prose-mirror-vivid.schema.d.ts +2 -1
  11. package/lib/rich-text-editor/facades/vivid-prose-mirror.facade.d.ts +2 -2
  12. package/lib/rich-text-editor/image-placeholder/definition.d.ts +2 -0
  13. package/lib/rich-text-editor/image-placeholder/image-placeholder.d.ts +7 -0
  14. package/lib/rich-text-editor/image-placeholder/image-placeholder.template.d.ts +4 -0
  15. package/lib/rich-text-editor/menubar/consts.d.ts +2 -2
  16. package/lib/rich-text-editor/menubar/definition.d.ts +2 -2
  17. package/lib/rich-text-editor/menubar/menubar.d.ts +2 -2
  18. package/lib/rich-text-editor/menubar/menubar.template.d.ts +2 -2
  19. package/lib/rich-text-editor/rich-text-editor.d.ts +1 -0
  20. package/lib/time-picker/time-picker.d.ts +4 -2
  21. package/locales/de-DE.cjs +2 -1
  22. package/locales/de-DE.js +2 -1
  23. package/locales/en-GB.cjs +2 -1
  24. package/locales/en-GB.js +2 -1
  25. package/locales/en-US.cjs +2 -1
  26. package/locales/en-US.js +2 -1
  27. package/locales/ja-JP.cjs +2 -1
  28. package/locales/ja-JP.js +2 -1
  29. package/locales/zh-CN.cjs +2 -1
  30. package/locales/zh-CN.js +2 -1
  31. package/package.json +2 -1
  32. package/shared/calendar-picker.template.cjs +8 -9
  33. package/shared/calendar-picker.template.js +8 -9
  34. package/shared/definition16.cjs +33 -30
  35. package/shared/definition16.js +33 -30
  36. package/shared/definition17.cjs +137 -1
  37. package/shared/definition17.js +138 -2
  38. package/shared/definition23.cjs +12 -7
  39. package/shared/definition23.js +12 -7
  40. package/shared/definition30.cjs +2 -1
  41. package/shared/definition30.js +2 -1
  42. package/shared/definition31.cjs +5 -1
  43. package/shared/definition31.js +5 -1
  44. package/shared/definition36.cjs +1 -1
  45. package/shared/definition36.js +1 -1
  46. package/shared/definition44.cjs +184 -55
  47. package/shared/definition44.js +184 -55
  48. package/shared/definition45.cjs +12 -5
  49. package/shared/definition45.js +12 -5
  50. package/shared/definition5.cjs +86 -30
  51. package/shared/definition5.js +86 -30
  52. package/shared/definition61.cjs +11 -0
  53. package/shared/definition61.js +11 -0
  54. package/shared/definition64.cjs +1 -1
  55. package/shared/definition64.js +1 -1
  56. package/shared/divider.cjs +7 -2
  57. package/shared/divider.js +7 -2
  58. package/shared/option.cjs +36 -38
  59. package/shared/option.js +37 -39
  60. package/shared/picker-field/mixins/inline-time-picker/inline-time-picker.d.ts +1 -0
  61. package/shared/picker-field/mixins/single-date-picker.d.ts +4 -2
  62. package/shared/picker-field/mixins/single-value-picker.d.ts +2 -1
  63. package/shared/picker-field/mixins/time-selection-picker.d.ts +4 -2
  64. package/shared/picker-field/mixins/time-selection-picker.template.d.ts +4 -2
  65. package/shared/single-value-picker.cjs +40 -6
  66. package/shared/single-value-picker.js +40 -6
  67. package/shared/text-field.cjs +1 -1
  68. package/shared/text-field.js +1 -1
  69. package/shared/time-selection-picker.template.cjs +71 -22
  70. package/shared/time-selection-picker.template.js +71 -22
  71. package/shared/vivid-element.cjs +1 -1
  72. package/shared/vivid-element.js +1 -1
  73. package/styles/core/all.css +1 -1
  74. package/styles/core/theme.css +1 -1
  75. package/styles/core/typography.css +1 -1
  76. package/styles/tokens/theme-dark.css +4 -4
  77. package/styles/tokens/theme-light.css +4 -4
  78. package/styles/tokens/vivid-2-compat.css +1 -1
  79. package/vivid.api.json +211 -126
@@ -57,6 +57,8 @@ class AudioPlayer extends localized.Localized(vividElement.VividElement) {
57
57
  this.notime = false;
58
58
  this.playbackRates = null;
59
59
  this.#playerEl = new Audio();
60
+ this.#isProgrammaticSliderUpdate = false;
61
+ this.durationFallback = false;
60
62
  this.#pausedChanged = (pausing) => {
61
63
  if (pausing === this.paused) {
62
64
  this.#setPausedState();
@@ -70,18 +72,28 @@ class AudioPlayer extends localized.Localized(vividElement.VividElement) {
70
72
  }
71
73
  this.#setPausedState();
72
74
  };
73
- this.#currentTimeChanged = false;
74
75
  this.#updateProgress = () => {
75
- this.#currentTimeChanged = true;
76
76
  vividElement.Observable.notify(this, "currentTime");
77
- const percent = this.currentTime / this.duration * 100;
78
- this.#sliderEl.value = percent.toString();
79
- if (percent === 100) {
77
+ const duration = this.duration;
78
+ const currentTime = this.currentTime;
79
+ const isValid = Number.isFinite(duration) && duration > 0 && Number.isFinite(currentTime) && currentTime >= 0;
80
+ const percent = isValid ? currentTime / duration * 100 : 0;
81
+ if (this.#sliderEl) {
82
+ this.#isProgrammaticSliderUpdate = true;
83
+ this.#sliderEl.value = percent.toString();
84
+ this.#isProgrammaticSliderUpdate = false;
85
+ }
86
+ if (isValid && percent === 100) {
80
87
  this.pause();
81
88
  }
82
89
  };
83
90
  this.#updateTotalTime = () => {
84
91
  vividElement.Observable.notify(this, "duration");
92
+ if (!Number.isFinite(this.#playerEl.duration) || this.#playerEl.duration <= 0) {
93
+ if (this.durationFallback) {
94
+ this.#fetchAndCacheAudioBuffer();
95
+ }
96
+ }
85
97
  };
86
98
  this.#updateCurrentTimeOnSliderChange = () => {
87
99
  if (!this.paused && this.#sliderEl.isDragging) {
@@ -93,16 +105,28 @@ class AudioPlayer extends localized.Localized(vividElement.VividElement) {
93
105
  }
94
106
  }, 0);
95
107
  }
96
- if (!this.#currentTimeChanged && this.#playerEl) {
108
+ if (this.#isProgrammaticSliderUpdate) {
109
+ return;
110
+ }
111
+ if (this.#playerEl) {
97
112
  this.currentTime = this.duration * Number(this.#sliderEl.value) / 100;
98
113
  }
99
- this.#currentTimeChanged = false;
100
114
  };
101
115
  this.#setPausedState = () => {
102
116
  vividElement.Observable.notify(this, "paused");
103
117
  };
104
- this.#playerEl.addEventListener("timeupdate", this.#updateProgress);
105
- this.#playerEl.addEventListener("loadedmetadata", this.#updateTotalTime);
118
+ }
119
+ srcChanged() {
120
+ if (this.src === void 0) {
121
+ this.#playerEl.removeAttribute("src");
122
+ } else {
123
+ this.#playerEl.src = this.src;
124
+ }
125
+ this.#audioBuffer = void 0;
126
+ if (this.#fetchAbortController) {
127
+ this.#fetchAbortController.abort();
128
+ }
129
+ this.#fetchAbortController = void 0;
106
130
  }
107
131
  get playbackRate() {
108
132
  vividElement.Observable.track(this, "playbackRate");
@@ -112,22 +136,41 @@ class AudioPlayer extends localized.Localized(vividElement.VividElement) {
112
136
  this.#playerEl.playbackRate = value;
113
137
  vividElement.Observable.notify(this, "playbackRate");
114
138
  }
115
- srcChanged() {
116
- if (this.src === void 0) {
117
- this.#playerEl.removeAttribute("src");
118
- } else {
119
- this.#playerEl.src = this.src;
120
- }
121
- }
122
139
  get paused() {
123
140
  vividElement.Observable.track(this, "paused");
124
141
  return this.#playerEl.paused;
125
142
  }
126
143
  set paused(_) {
127
144
  }
145
+ #audioBuffer;
146
+ #fetchAbortController;
147
+ async #fetchAndCacheAudioBuffer() {
148
+ if (this.#audioBuffer || !this.src) return;
149
+ this.#fetchAbortController = new AbortController();
150
+ const signal = this.#fetchAbortController.signal;
151
+ try {
152
+ const response = await fetch(this.src, { signal });
153
+ const arrayBuffer = await response.arrayBuffer();
154
+ const audioContext = new window.AudioContext();
155
+ const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
156
+ audioContext.close();
157
+ this.#audioBuffer = audioBuffer;
158
+ vividElement.Observable.notify(this, "duration");
159
+ } catch (e) {
160
+ } finally {
161
+ this.#fetchAbortController = void 0;
162
+ }
163
+ }
128
164
  get duration() {
129
165
  vividElement.Observable.track(this, "duration");
130
- return this.#playerEl.duration;
166
+ const duration = this.#playerEl.duration;
167
+ if (Number.isFinite(duration) && duration > 0) {
168
+ return duration;
169
+ }
170
+ if (this.#audioBuffer && this.#audioBuffer.duration > 0) {
171
+ return this.#audioBuffer.duration;
172
+ }
173
+ return duration;
131
174
  }
132
175
  set duration(_) {
133
176
  }
@@ -142,15 +185,23 @@ class AudioPlayer extends localized.Localized(vividElement.VividElement) {
142
185
  return this.shadowRoot.querySelector(".slider");
143
186
  }
144
187
  #playerEl;
188
+ #isProgrammaticSliderUpdate;
145
189
  connectedCallback() {
146
190
  super.connectedCallback();
191
+ this.#playerEl.addEventListener("timeupdate", this.#updateProgress);
192
+ this.#playerEl.addEventListener("loadedmetadata", this.#updateTotalTime);
193
+ this.#playerEl.addEventListener("durationchange", this.#updateTotalTime);
147
194
  this.#setSliderInteractionListeners();
148
195
  this.#setPausedState();
196
+ this.#updateProgress();
149
197
  }
150
198
  disconnectedCallback() {
151
199
  super.disconnectedCallback();
152
200
  this.#setSliderInteractionListeners(false);
153
201
  this.pause();
202
+ this.#playerEl.removeEventListener("timeupdate", this.#updateProgress);
203
+ this.#playerEl.removeEventListener("loadedmetadata", this.#updateTotalTime);
204
+ this.#playerEl.removeEventListener("durationchange", this.#updateTotalTime);
154
205
  }
155
206
  play() {
156
207
  this.#pausedChanged(PLAY);
@@ -165,12 +216,24 @@ class AudioPlayer extends localized.Localized(vividElement.VividElement) {
165
216
  }
166
217
  }
167
218
  #pausedChanged;
168
- #currentTimeChanged;
169
219
  #updateProgress;
170
220
  #updateTotalTime;
171
221
  #dragInterval;
172
222
  #updateCurrentTimeOnSliderChange;
173
223
  #setPausedState;
224
+ /**
225
+ * Skips the current time by the skipBy value
226
+ *
227
+ * @param skipDirection - the direction to skip
228
+ *
229
+ * @internal
230
+ */
231
+ skip(skipDirection) {
232
+ const currentTime = this.currentTime;
233
+ const skipValue = parseInt(this.skipBy) * skipDirection;
234
+ const newTime = currentTime + skipValue;
235
+ this.currentTime = Math.max(0, Math.min(this.duration, newTime));
236
+ }
174
237
  }
175
238
  __decorateClass([
176
239
  vividElement.attr({ attribute: "play-button-aria-label" })
@@ -208,16 +271,10 @@ __decorateClass([
208
271
  __decorateClass([
209
272
  vividElement.attr({ attribute: "playback-rates" })
210
273
  ], AudioPlayer.prototype, "playbackRates");
274
+ __decorateClass([
275
+ vividElement.attr({ mode: "boolean", attribute: "duration-fallback" })
276
+ ], AudioPlayer.prototype, "durationFallback");
211
277
 
212
- function skip(audioElement, skipDirection) {
213
- const currentTime = audioElement.currentTime;
214
- const skipValue = parseInt(audioElement.skipBy) * skipDirection;
215
- const newTime = currentTime + skipValue;
216
- audioElement.currentTime = Math.max(
217
- 0,
218
- Math.min(audioElement.duration, newTime)
219
- );
220
- }
221
278
  const getClasses = ({
222
279
  notime,
223
280
  disabled,
@@ -249,7 +306,7 @@ function renderBackwardSkipButtons(context) {
249
306
  const buttonTag = context.tagFor(definition$1.Button);
250
307
  return vividElement.html`
251
308
  <${buttonTag} class="skip backward"
252
- @click="${(element) => skip(element, SKIP_DIRECTIONS.BACKWARD)}"
309
+ @click="${(element) => element.skip(SKIP_DIRECTIONS.BACKWARD)}"
253
310
  icon="${(x) => x.skipBy == enums.MediaSkipBy.Five ? "5-sec-backward-line" : x.skipBy == enums.MediaSkipBy.Thirty ? "30-sec-backward-line" : "10-sec-backward-line"}"
254
311
  size='condensed'
255
312
  aria-label="${(x) => x.skipBackwardButtonAriaLabel || x.locale.audioPlayer.skipBackwardButton}"
@@ -262,7 +319,7 @@ function renderForwardSkipButtons(context) {
262
319
  const buttonTag = context.tagFor(definition$1.Button);
263
320
  return vividElement.html`
264
321
  <${buttonTag} class="skip forward"
265
- @click="${(element) => skip(element, SKIP_DIRECTIONS.FORWARD)}"
322
+ @click="${(element) => element.skip(SKIP_DIRECTIONS.FORWARD)}"
266
323
  icon="${(x) => x.skipBy == enums.MediaSkipBy.Five ? "5-sec-forward-line" : x.skipBy == enums.MediaSkipBy.Thirty ? "30-sec-forward-line" : "10-sec-forward-line"}"
267
324
  size='condensed'
268
325
  aria-label="${(x) => x.skipForwardButtonAriaLabel || x.locale.audioPlayer.skipForwardButton}"
@@ -276,7 +333,6 @@ function renderSlider(context) {
276
333
  return vividElement.html`
277
334
  <${sliderTag}
278
335
  class="slider"
279
- value="0"
280
336
  aria-label="${(x) => x.sliderAriaLabel || x.locale.audioPlayer.sliderLabel}"
281
337
  max="100"
282
338
  aria-valuetext="${(x) => formatTime(x.currentTime)}"
@@ -55,6 +55,8 @@ class AudioPlayer extends Localized(VividElement) {
55
55
  this.notime = false;
56
56
  this.playbackRates = null;
57
57
  this.#playerEl = new Audio();
58
+ this.#isProgrammaticSliderUpdate = false;
59
+ this.durationFallback = false;
58
60
  this.#pausedChanged = (pausing) => {
59
61
  if (pausing === this.paused) {
60
62
  this.#setPausedState();
@@ -68,18 +70,28 @@ class AudioPlayer extends Localized(VividElement) {
68
70
  }
69
71
  this.#setPausedState();
70
72
  };
71
- this.#currentTimeChanged = false;
72
73
  this.#updateProgress = () => {
73
- this.#currentTimeChanged = true;
74
74
  Observable.notify(this, "currentTime");
75
- const percent = this.currentTime / this.duration * 100;
76
- this.#sliderEl.value = percent.toString();
77
- if (percent === 100) {
75
+ const duration = this.duration;
76
+ const currentTime = this.currentTime;
77
+ const isValid = Number.isFinite(duration) && duration > 0 && Number.isFinite(currentTime) && currentTime >= 0;
78
+ const percent = isValid ? currentTime / duration * 100 : 0;
79
+ if (this.#sliderEl) {
80
+ this.#isProgrammaticSliderUpdate = true;
81
+ this.#sliderEl.value = percent.toString();
82
+ this.#isProgrammaticSliderUpdate = false;
83
+ }
84
+ if (isValid && percent === 100) {
78
85
  this.pause();
79
86
  }
80
87
  };
81
88
  this.#updateTotalTime = () => {
82
89
  Observable.notify(this, "duration");
90
+ if (!Number.isFinite(this.#playerEl.duration) || this.#playerEl.duration <= 0) {
91
+ if (this.durationFallback) {
92
+ this.#fetchAndCacheAudioBuffer();
93
+ }
94
+ }
83
95
  };
84
96
  this.#updateCurrentTimeOnSliderChange = () => {
85
97
  if (!this.paused && this.#sliderEl.isDragging) {
@@ -91,16 +103,28 @@ class AudioPlayer extends Localized(VividElement) {
91
103
  }
92
104
  }, 0);
93
105
  }
94
- if (!this.#currentTimeChanged && this.#playerEl) {
106
+ if (this.#isProgrammaticSliderUpdate) {
107
+ return;
108
+ }
109
+ if (this.#playerEl) {
95
110
  this.currentTime = this.duration * Number(this.#sliderEl.value) / 100;
96
111
  }
97
- this.#currentTimeChanged = false;
98
112
  };
99
113
  this.#setPausedState = () => {
100
114
  Observable.notify(this, "paused");
101
115
  };
102
- this.#playerEl.addEventListener("timeupdate", this.#updateProgress);
103
- this.#playerEl.addEventListener("loadedmetadata", this.#updateTotalTime);
116
+ }
117
+ srcChanged() {
118
+ if (this.src === void 0) {
119
+ this.#playerEl.removeAttribute("src");
120
+ } else {
121
+ this.#playerEl.src = this.src;
122
+ }
123
+ this.#audioBuffer = void 0;
124
+ if (this.#fetchAbortController) {
125
+ this.#fetchAbortController.abort();
126
+ }
127
+ this.#fetchAbortController = void 0;
104
128
  }
105
129
  get playbackRate() {
106
130
  Observable.track(this, "playbackRate");
@@ -110,22 +134,41 @@ class AudioPlayer extends Localized(VividElement) {
110
134
  this.#playerEl.playbackRate = value;
111
135
  Observable.notify(this, "playbackRate");
112
136
  }
113
- srcChanged() {
114
- if (this.src === void 0) {
115
- this.#playerEl.removeAttribute("src");
116
- } else {
117
- this.#playerEl.src = this.src;
118
- }
119
- }
120
137
  get paused() {
121
138
  Observable.track(this, "paused");
122
139
  return this.#playerEl.paused;
123
140
  }
124
141
  set paused(_) {
125
142
  }
143
+ #audioBuffer;
144
+ #fetchAbortController;
145
+ async #fetchAndCacheAudioBuffer() {
146
+ if (this.#audioBuffer || !this.src) return;
147
+ this.#fetchAbortController = new AbortController();
148
+ const signal = this.#fetchAbortController.signal;
149
+ try {
150
+ const response = await fetch(this.src, { signal });
151
+ const arrayBuffer = await response.arrayBuffer();
152
+ const audioContext = new window.AudioContext();
153
+ const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
154
+ audioContext.close();
155
+ this.#audioBuffer = audioBuffer;
156
+ Observable.notify(this, "duration");
157
+ } catch (e) {
158
+ } finally {
159
+ this.#fetchAbortController = void 0;
160
+ }
161
+ }
126
162
  get duration() {
127
163
  Observable.track(this, "duration");
128
- return this.#playerEl.duration;
164
+ const duration = this.#playerEl.duration;
165
+ if (Number.isFinite(duration) && duration > 0) {
166
+ return duration;
167
+ }
168
+ if (this.#audioBuffer && this.#audioBuffer.duration > 0) {
169
+ return this.#audioBuffer.duration;
170
+ }
171
+ return duration;
129
172
  }
130
173
  set duration(_) {
131
174
  }
@@ -140,15 +183,23 @@ class AudioPlayer extends Localized(VividElement) {
140
183
  return this.shadowRoot.querySelector(".slider");
141
184
  }
142
185
  #playerEl;
186
+ #isProgrammaticSliderUpdate;
143
187
  connectedCallback() {
144
188
  super.connectedCallback();
189
+ this.#playerEl.addEventListener("timeupdate", this.#updateProgress);
190
+ this.#playerEl.addEventListener("loadedmetadata", this.#updateTotalTime);
191
+ this.#playerEl.addEventListener("durationchange", this.#updateTotalTime);
145
192
  this.#setSliderInteractionListeners();
146
193
  this.#setPausedState();
194
+ this.#updateProgress();
147
195
  }
148
196
  disconnectedCallback() {
149
197
  super.disconnectedCallback();
150
198
  this.#setSliderInteractionListeners(false);
151
199
  this.pause();
200
+ this.#playerEl.removeEventListener("timeupdate", this.#updateProgress);
201
+ this.#playerEl.removeEventListener("loadedmetadata", this.#updateTotalTime);
202
+ this.#playerEl.removeEventListener("durationchange", this.#updateTotalTime);
152
203
  }
153
204
  play() {
154
205
  this.#pausedChanged(PLAY);
@@ -163,12 +214,24 @@ class AudioPlayer extends Localized(VividElement) {
163
214
  }
164
215
  }
165
216
  #pausedChanged;
166
- #currentTimeChanged;
167
217
  #updateProgress;
168
218
  #updateTotalTime;
169
219
  #dragInterval;
170
220
  #updateCurrentTimeOnSliderChange;
171
221
  #setPausedState;
222
+ /**
223
+ * Skips the current time by the skipBy value
224
+ *
225
+ * @param skipDirection - the direction to skip
226
+ *
227
+ * @internal
228
+ */
229
+ skip(skipDirection) {
230
+ const currentTime = this.currentTime;
231
+ const skipValue = parseInt(this.skipBy) * skipDirection;
232
+ const newTime = currentTime + skipValue;
233
+ this.currentTime = Math.max(0, Math.min(this.duration, newTime));
234
+ }
172
235
  }
173
236
  __decorateClass([
174
237
  attr({ attribute: "play-button-aria-label" })
@@ -206,16 +269,10 @@ __decorateClass([
206
269
  __decorateClass([
207
270
  attr({ attribute: "playback-rates" })
208
271
  ], AudioPlayer.prototype, "playbackRates");
272
+ __decorateClass([
273
+ attr({ mode: "boolean", attribute: "duration-fallback" })
274
+ ], AudioPlayer.prototype, "durationFallback");
209
275
 
210
- function skip(audioElement, skipDirection) {
211
- const currentTime = audioElement.currentTime;
212
- const skipValue = parseInt(audioElement.skipBy) * skipDirection;
213
- const newTime = currentTime + skipValue;
214
- audioElement.currentTime = Math.max(
215
- 0,
216
- Math.min(audioElement.duration, newTime)
217
- );
218
- }
219
276
  const getClasses = ({
220
277
  notime,
221
278
  disabled,
@@ -247,7 +304,7 @@ function renderBackwardSkipButtons(context) {
247
304
  const buttonTag = context.tagFor(Button);
248
305
  return html`
249
306
  <${buttonTag} class="skip backward"
250
- @click="${(element) => skip(element, SKIP_DIRECTIONS.BACKWARD)}"
307
+ @click="${(element) => element.skip(SKIP_DIRECTIONS.BACKWARD)}"
251
308
  icon="${(x) => x.skipBy == MediaSkipBy.Five ? "5-sec-backward-line" : x.skipBy == MediaSkipBy.Thirty ? "30-sec-backward-line" : "10-sec-backward-line"}"
252
309
  size='condensed'
253
310
  aria-label="${(x) => x.skipBackwardButtonAriaLabel || x.locale.audioPlayer.skipBackwardButton}"
@@ -260,7 +317,7 @@ function renderForwardSkipButtons(context) {
260
317
  const buttonTag = context.tagFor(Button);
261
318
  return html`
262
319
  <${buttonTag} class="skip forward"
263
- @click="${(element) => skip(element, SKIP_DIRECTIONS.FORWARD)}"
320
+ @click="${(element) => element.skip(SKIP_DIRECTIONS.FORWARD)}"
264
321
  icon="${(x) => x.skipBy == MediaSkipBy.Five ? "5-sec-forward-line" : x.skipBy == MediaSkipBy.Thirty ? "30-sec-forward-line" : "10-sec-forward-line"}"
265
322
  size='condensed'
266
323
  aria-label="${(x) => x.skipForwardButtonAriaLabel || x.locale.audioPlayer.skipForwardButton}"
@@ -274,7 +331,6 @@ function renderSlider(context) {
274
331
  return html`
275
332
  <${sliderTag}
276
333
  class="slider"
277
- value="0"
278
334
  aria-label="${(x) => x.sliderAriaLabel || x.locale.audioPlayer.sliderLabel}"
279
335
  max="100"
280
336
  aria-valuetext="${(x) => formatTime(x.currentTime)}"
@@ -23,9 +23,11 @@ class Tooltip extends anchored.Anchored(vividElement.VividElement) {
23
23
  this.open = false;
24
24
  this.#show = () => {
25
25
  this.open = true;
26
+ this.#updateAnchorExpanded();
26
27
  };
27
28
  this.#hide = () => {
28
29
  this.open = false;
30
+ this.#updateAnchorExpanded();
29
31
  };
30
32
  this.#closeOnEscape = (e) => {
31
33
  if (e.key === "Escape") this.#hide();
@@ -51,15 +53,24 @@ class Tooltip extends anchored.Anchored(vividElement.VividElement) {
51
53
  a.addEventListener("mouseout", this.#hide);
52
54
  a.addEventListener("focusin", this.#show);
53
55
  a.addEventListener("focusout", this.#hide);
56
+ a.setAttribute("aria-haspopup", "true");
57
+ a.setAttribute("aria-expanded", String(this.open));
54
58
  }
55
59
  #cleanupAnchor(a) {
56
60
  a.removeEventListener("mouseover", this.#show);
57
61
  a.removeEventListener("mouseout", this.#hide);
58
62
  a.removeEventListener("focusin", this.#show);
59
63
  a.removeEventListener("focusout", this.#hide);
64
+ a.removeAttribute("aria-haspopup");
65
+ a.removeAttribute("aria-expanded");
60
66
  }
61
67
  #show;
62
68
  #hide;
69
+ #updateAnchorExpanded() {
70
+ if (this._anchorEl) {
71
+ this._anchorEl.setAttribute("aria-expanded", String(this.open));
72
+ }
73
+ }
63
74
  #updateListeners() {
64
75
  document.removeEventListener("keydown", this.#closeOnEscape);
65
76
  if (this.open && this.isConnected) {
@@ -21,9 +21,11 @@ class Tooltip extends Anchored(VividElement) {
21
21
  this.open = false;
22
22
  this.#show = () => {
23
23
  this.open = true;
24
+ this.#updateAnchorExpanded();
24
25
  };
25
26
  this.#hide = () => {
26
27
  this.open = false;
28
+ this.#updateAnchorExpanded();
27
29
  };
28
30
  this.#closeOnEscape = (e) => {
29
31
  if (e.key === "Escape") this.#hide();
@@ -49,15 +51,24 @@ class Tooltip extends Anchored(VividElement) {
49
51
  a.addEventListener("mouseout", this.#hide);
50
52
  a.addEventListener("focusin", this.#show);
51
53
  a.addEventListener("focusout", this.#hide);
54
+ a.setAttribute("aria-haspopup", "true");
55
+ a.setAttribute("aria-expanded", String(this.open));
52
56
  }
53
57
  #cleanupAnchor(a) {
54
58
  a.removeEventListener("mouseover", this.#show);
55
59
  a.removeEventListener("mouseout", this.#hide);
56
60
  a.removeEventListener("focusin", this.#show);
57
61
  a.removeEventListener("focusout", this.#hide);
62
+ a.removeAttribute("aria-haspopup");
63
+ a.removeAttribute("aria-expanded");
58
64
  }
59
65
  #show;
60
66
  #hide;
67
+ #updateAnchorExpanded() {
68
+ if (this._anchorEl) {
69
+ this._anchorEl.setAttribute("aria-expanded", String(this.open));
70
+ }
71
+ }
61
72
  #updateListeners() {
62
73
  document.removeEventListener("keydown", this.#closeOnEscape);
63
74
  if (this.open && this.isConnected) {