@vonage/vivid 3.57.0 → 3.58.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.
- package/custom-elements.json +285 -126
- package/lib/audio-player/audio-player.d.ts +17 -0
- package/package.json +1 -1
- package/shared/definition16.cjs +1 -1
- package/shared/definition16.js +1 -1
- package/shared/definition35.cjs +1 -1
- package/shared/definition35.js +1 -1
- package/shared/definition42.cjs +1 -1
- package/shared/definition42.js +1 -1
- package/shared/definition43.cjs +2 -2
- package/shared/definition43.js +2 -2
- package/shared/definition46.cjs +1 -1
- package/shared/definition46.js +1 -1
- package/shared/definition5.cjs +138 -120
- package/shared/definition5.js +139 -121
- package/shared/definition50.cjs +1 -1
- package/shared/definition50.js +1 -1
- package/shared/definition58.cjs +1 -1
- package/shared/definition58.js +1 -1
- package/shared/definition61.cjs +23 -9
- package/shared/definition61.js +23 -9
- package/shared/definition7.cjs +1 -1
- package/shared/definition7.js +1 -1
- package/shared/icon.cjs +1 -1
- package/shared/icon.js +1 -1
- package/shared/patterns/anchored.d.ts +4 -4
- package/shared/slider.template.cjs +3 -3
- package/shared/slider.template.js +3 -3
- package/shared/text-field.cjs +1 -1
- package/shared/text-field.js +1 -1
- package/styles/core/all.css +1 -1
- package/styles/core/theme.css +1 -1
- package/styles/core/typography.css +1 -1
- package/styles/tokens/theme-dark.css +4 -4
- package/styles/tokens/theme-light.css +4 -4
- package/styles/tokens/vivid-2-compat.css +1 -1
package/shared/definition5.cjs
CHANGED
|
@@ -9,7 +9,6 @@ require('./index2.cjs');
|
|
|
9
9
|
const localized = require('./localized.cjs');
|
|
10
10
|
const applyMixins = require('./apply-mixins.cjs');
|
|
11
11
|
const when = require('./when.cjs');
|
|
12
|
-
const ref = require('./ref.cjs');
|
|
13
12
|
const classNames = require('./class-names.cjs');
|
|
14
13
|
|
|
15
14
|
const styles = ":host{display:block;max-inline-size:350px}.wrapper{container-type:inline-size}.base{display:inline-flex;box-sizing:border-box;align-items:center;padding:8px;color:var(--vvd-color-canvas-text);gap:16px;inline-size:100%;user-select:none}.base .slider{flex:1;grid-area:slider;min-inline-size:var(--audio-player-min-inline-size, 200px)}.base .controls{display:flex;align-items:center;justify-content:center;gap:8px;grid-area:controls}.base .time-stamp{display:inline-flex}.base .time-stamp .current-time,.base .time-stamp .total-time{margin-inline:6px;min-inline-size:32px}.base .playback{grid-area:playback}@container (max-width: 500px){.base.two-lines{display:inline-grid;grid-template:auto auto/1fr;grid-template-areas:\"slider\" \"controls\";inline-size:100%;row-gap:4px}.base.two-lines .time-stamp{margin-inline:auto 2px}.base.two-lines.playback{grid-template-areas:\"slider slider\" \"controls playback\";grid-template-columns:1fr auto}.base.two-lines.playback .time-stamp{margin-inline:auto}.base .slider{box-sizing:border-box;min-inline-size:auto;padding-inline:2px}}";
|
|
@@ -24,6 +23,20 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
24
23
|
__defProp(target, key, result);
|
|
25
24
|
return result;
|
|
26
25
|
};
|
|
26
|
+
const SKIP_DIRECTIONS = {
|
|
27
|
+
FORWARD: 1,
|
|
28
|
+
BACKWARD: -1
|
|
29
|
+
};
|
|
30
|
+
function formatTime(time) {
|
|
31
|
+
if (!time || Number.isNaN(time)) {
|
|
32
|
+
return "0:00";
|
|
33
|
+
}
|
|
34
|
+
const min = Math.floor(time / 60);
|
|
35
|
+
const sec = Math.floor(time % 60);
|
|
36
|
+
return min + ":" + (sec < 10 ? "0" + sec : sec);
|
|
37
|
+
}
|
|
38
|
+
const PAUSE = true;
|
|
39
|
+
const PLAY = false;
|
|
27
40
|
const validSkipByConverter = {
|
|
28
41
|
toView(value) {
|
|
29
42
|
return value;
|
|
@@ -34,7 +47,7 @@ const validSkipByConverter = {
|
|
|
34
47
|
};
|
|
35
48
|
class AudioPlayer extends index.FoundationElement {
|
|
36
49
|
constructor() {
|
|
37
|
-
super(
|
|
50
|
+
super();
|
|
38
51
|
this.playButtonAriaLabel = null;
|
|
39
52
|
this.pauseButtonAriaLabel = null;
|
|
40
53
|
this.sliderAriaLabel = null;
|
|
@@ -42,106 +55,109 @@ class AudioPlayer extends index.FoundationElement {
|
|
|
42
55
|
this.skipBackwardButtonAriaLabel = null;
|
|
43
56
|
this.disabled = false;
|
|
44
57
|
this.notime = false;
|
|
45
|
-
this
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (this.
|
|
51
|
-
this.
|
|
58
|
+
this.#playerEl = new Audio();
|
|
59
|
+
this.#pausedChanged = (pausing) => {
|
|
60
|
+
if (pausing === this.paused) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!this.paused) {
|
|
64
|
+
this.#playerEl.pause();
|
|
65
|
+
} else {
|
|
66
|
+
this.#updateProgress();
|
|
67
|
+
this.#playerEl.play();
|
|
68
|
+
}
|
|
69
|
+
this.#setPausedState();
|
|
70
|
+
};
|
|
71
|
+
this.#updateProgress = () => {
|
|
72
|
+
index.Observable.notify(this, "currentTime");
|
|
73
|
+
const percent = this.currentTime / this.duration * 100;
|
|
74
|
+
if (percent === 100) {
|
|
75
|
+
this.pause();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
this.#updateTotalTime = () => {
|
|
79
|
+
index.Observable.notify(this, "duration");
|
|
80
|
+
};
|
|
81
|
+
this.#rewind = () => {
|
|
82
|
+
if (this.#playerEl) {
|
|
83
|
+
this.currentTime = this.duration * Number(this.#sliderEl.value) / 100;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
this.#handleSliderEvent = (event) => {
|
|
87
|
+
if (event.target === this.#sliderEl) {
|
|
88
|
+
this.pause();
|
|
89
|
+
this.#rewind();
|
|
52
90
|
}
|
|
91
|
+
return true;
|
|
53
92
|
};
|
|
93
|
+
this.#setPausedState = () => {
|
|
94
|
+
index.Observable.notify(this, "paused");
|
|
95
|
+
};
|
|
96
|
+
this.#playerEl.addEventListener("timeupdate", this.#updateProgress);
|
|
97
|
+
this.#playerEl.addEventListener("loadedmetadata", this.#updateTotalTime);
|
|
98
|
+
}
|
|
99
|
+
srcChanged() {
|
|
100
|
+
if (this.src === void 0) {
|
|
101
|
+
this.#playerEl.removeAttribute("src");
|
|
102
|
+
} else {
|
|
103
|
+
this.#playerEl.src = this.src;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
get paused() {
|
|
107
|
+
index.Observable.track(this, "paused");
|
|
108
|
+
return this.#playerEl.paused;
|
|
109
|
+
}
|
|
110
|
+
set paused(_) {
|
|
111
|
+
}
|
|
112
|
+
get duration() {
|
|
113
|
+
index.Observable.track(this, "duration");
|
|
114
|
+
return this.#playerEl.duration;
|
|
115
|
+
}
|
|
116
|
+
set duration(_) {
|
|
117
|
+
}
|
|
118
|
+
get currentTime() {
|
|
119
|
+
index.Observable.track(this, "currentTime");
|
|
120
|
+
return this.#playerEl.currentTime;
|
|
121
|
+
}
|
|
122
|
+
set currentTime(value) {
|
|
123
|
+
this.#playerEl.currentTime = value;
|
|
124
|
+
}
|
|
125
|
+
get #sliderEl() {
|
|
126
|
+
return this.shadowRoot.querySelector(".slider");
|
|
127
|
+
}
|
|
128
|
+
#playerEl;
|
|
129
|
+
get #baseElement() {
|
|
130
|
+
return this.shadowRoot.querySelector(".base");
|
|
54
131
|
}
|
|
55
132
|
connectedCallback() {
|
|
56
133
|
super.connectedCallback();
|
|
57
|
-
document.addEventListener("mouseup", this
|
|
134
|
+
document.addEventListener("mouseup", this.#rewind);
|
|
135
|
+
this.#setInteractionListeners();
|
|
136
|
+
this.#setPausedState();
|
|
58
137
|
}
|
|
59
138
|
disconnectedCallback() {
|
|
60
139
|
super.disconnectedCallback();
|
|
61
|
-
document.addEventListener("mouseup", this
|
|
140
|
+
document.addEventListener("mouseup", this.#rewind);
|
|
141
|
+
this.#setInteractionListeners(false);
|
|
62
142
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*/
|
|
66
|
-
_togglePlay() {
|
|
67
|
-
if (this.paused) {
|
|
68
|
-
this._updateProgress();
|
|
69
|
-
this._playerEl.play();
|
|
70
|
-
} else {
|
|
71
|
-
this._playerEl.pause();
|
|
72
|
-
}
|
|
73
|
-
this.paused = !this.paused;
|
|
143
|
+
play() {
|
|
144
|
+
this.#pausedChanged(PLAY);
|
|
74
145
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*/
|
|
78
|
-
_onSkipButtonClick(isForward) {
|
|
79
|
-
if (this._playerEl) {
|
|
80
|
-
const currentTime = this._playerEl.currentTime;
|
|
81
|
-
const skipDirection = isForward ? 1 : -1;
|
|
82
|
-
const skipValue = parseInt(this.skipBy) * skipDirection;
|
|
83
|
-
const newTime = currentTime + skipValue;
|
|
84
|
-
this._playerEl.currentTime = Math.max(
|
|
85
|
-
0,
|
|
86
|
-
Math.min(this._playerEl.duration, newTime)
|
|
87
|
-
);
|
|
88
|
-
this._updateProgress();
|
|
89
|
-
}
|
|
146
|
+
pause() {
|
|
147
|
+
this.#pausedChanged(PAUSE);
|
|
90
148
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const current = this._playerEl.currentTime;
|
|
97
|
-
const percent = current / this._playerEl.duration * 100;
|
|
98
|
-
if (this._sliderEl) {
|
|
99
|
-
this._sliderEl.value = percent.toString();
|
|
100
|
-
this._sliderEl.ariaValuetext = this._formatTime(current);
|
|
101
|
-
}
|
|
102
|
-
if (percent === 100) {
|
|
103
|
-
this.paused = true;
|
|
104
|
-
}
|
|
105
|
-
if (this._timeStampEl) {
|
|
106
|
-
currentTime = this._timeStampEl.querySelector(".current-time");
|
|
107
|
-
if (currentTime)
|
|
108
|
-
currentTime.textContent = this._formatTime(current);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* @internal
|
|
113
|
-
*/
|
|
114
|
-
_updateTotalTime() {
|
|
115
|
-
let totalTime;
|
|
116
|
-
if (this._playerEl)
|
|
117
|
-
this.duration = this._playerEl.duration;
|
|
118
|
-
if (this._timeStampEl) {
|
|
119
|
-
totalTime = this._timeStampEl.querySelector(".total-time");
|
|
120
|
-
if (totalTime)
|
|
121
|
-
totalTime.textContent = this._formatTime(this._playerEl.duration);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* @internal
|
|
126
|
-
*/
|
|
127
|
-
_handleSliderEvent(event) {
|
|
128
|
-
if (event.target === this._sliderEl) {
|
|
129
|
-
this.paused = true;
|
|
130
|
-
if (this._playerEl) {
|
|
131
|
-
this._playerEl.pause();
|
|
132
|
-
}
|
|
133
|
-
this._rewind();
|
|
134
|
-
}
|
|
135
|
-
return true;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* @internal
|
|
139
|
-
*/
|
|
140
|
-
_formatTime(time) {
|
|
141
|
-
const min = Math.floor(time / 60);
|
|
142
|
-
const sec = Math.floor(time % 60);
|
|
143
|
-
return min + ":" + (sec < 10 ? "0" + sec : sec);
|
|
149
|
+
#setInteractionListeners(add = true) {
|
|
150
|
+
const action = add ? "addEventListener" : "removeEventListener";
|
|
151
|
+
this.#baseElement[action]("keyup", this.#handleSliderEvent);
|
|
152
|
+
this.#baseElement[action]("keydown", this.#handleSliderEvent);
|
|
153
|
+
this.#baseElement[action]("mousedown", this.#handleSliderEvent);
|
|
144
154
|
}
|
|
155
|
+
#pausedChanged;
|
|
156
|
+
#updateProgress;
|
|
157
|
+
#updateTotalTime;
|
|
158
|
+
#rewind;
|
|
159
|
+
#handleSliderEvent;
|
|
160
|
+
#setPausedState;
|
|
145
161
|
}
|
|
146
162
|
__decorateClass([
|
|
147
163
|
index.attr({ attribute: "play-button-aria-label" })
|
|
@@ -176,18 +192,27 @@ __decorateClass([
|
|
|
176
192
|
converter: validSkipByConverter
|
|
177
193
|
})
|
|
178
194
|
], AudioPlayer.prototype, "skipBy");
|
|
179
|
-
__decorateClass([
|
|
180
|
-
index.observable
|
|
181
|
-
], AudioPlayer.prototype, "paused");
|
|
182
|
-
__decorateClass([
|
|
183
|
-
index.observable
|
|
184
|
-
], AudioPlayer.prototype, "duration");
|
|
185
195
|
applyMixins.applyMixins(AudioPlayer, localized.Localized);
|
|
186
196
|
|
|
197
|
+
function getCurrentTimePercentage(x) {
|
|
198
|
+
if (Number.isNaN(x.currentTime) || Number.isNaN(x.duration)) {
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
return x.currentTime / x.duration * 100;
|
|
202
|
+
}
|
|
203
|
+
function skip(audioElement, skipDirection) {
|
|
204
|
+
const currentTime = audioElement.currentTime;
|
|
205
|
+
const skipValue = parseInt(audioElement.skipBy) * skipDirection;
|
|
206
|
+
const newTime = currentTime + skipValue;
|
|
207
|
+
audioElement.currentTime = Math.max(
|
|
208
|
+
0,
|
|
209
|
+
Math.min(audioElement.duration, newTime)
|
|
210
|
+
);
|
|
211
|
+
}
|
|
187
212
|
const getClasses = ({ disabled, duration }) => classNames.classNames(["disabled", Boolean(disabled) || !duration]);
|
|
188
213
|
function renderButton(context) {
|
|
189
214
|
const buttonTag = context.tagFor(definition.Button);
|
|
190
|
-
return index.html`<${buttonTag} class="pause" @click="${(x) => x.
|
|
215
|
+
return index.html`<${buttonTag} class="pause" @click="${(x) => x.paused ? x.play() : x.pause()}"
|
|
191
216
|
icon="${(x) => x.paused ? "play-solid" : "pause-solid"}"
|
|
192
217
|
aria-label="${(x) => x.paused ? x.playButtonAriaLabel || x.locale.audioPlayer.playButtonLabel : x.pauseButtonAriaLabel || x.locale.audioPlayer.pauseButtonLabel}"
|
|
193
218
|
size='condensed'
|
|
@@ -198,7 +223,8 @@ function renderButton(context) {
|
|
|
198
223
|
function renderBackwardSkipButtons(context) {
|
|
199
224
|
const buttonTag = context.tagFor(definition.Button);
|
|
200
225
|
return index.html`
|
|
201
|
-
<${buttonTag} class="skip backward"
|
|
226
|
+
<${buttonTag} class="skip backward"
|
|
227
|
+
@click="${(element) => skip(element, SKIP_DIRECTIONS.BACKWARD)}"
|
|
202
228
|
icon="${(x) => x.skipBy == enums.MediaSkipBy.Five ? "5-sec-backward-line" : x.skipBy == enums.MediaSkipBy.Thirty ? "30-sec-backward-line" : "10-sec-backward-line"}"
|
|
203
229
|
size='condensed'
|
|
204
230
|
aria-label="${(x) => x.skipBackwardButtonAriaLabel || x.locale.audioPlayer.skipBackwardButton}"
|
|
@@ -210,7 +236,8 @@ function renderBackwardSkipButtons(context) {
|
|
|
210
236
|
function renderForwardSkipButtons(context) {
|
|
211
237
|
const buttonTag = context.tagFor(definition.Button);
|
|
212
238
|
return index.html`
|
|
213
|
-
<${buttonTag} class="skip forward"
|
|
239
|
+
<${buttonTag} class="skip forward"
|
|
240
|
+
@click="${(element) => skip(element, SKIP_DIRECTIONS.FORWARD)}"
|
|
214
241
|
icon="${(x) => x.skipBy == enums.MediaSkipBy.Five ? "5-sec-forward-line" : x.skipBy == enums.MediaSkipBy.Thirty ? "30-sec-forward-line" : "10-sec-forward-line"}"
|
|
215
242
|
size='condensed'
|
|
216
243
|
aria-label="${(x) => x.skipForwardButtonAriaLabel || x.locale.audioPlayer.skipForwardButton}"
|
|
@@ -221,29 +248,26 @@ function renderForwardSkipButtons(context) {
|
|
|
221
248
|
}
|
|
222
249
|
function renderSlider(context) {
|
|
223
250
|
const sliderTag = context.tagFor(definition$1.Slider);
|
|
224
|
-
return index.html
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
251
|
+
return index.html`
|
|
252
|
+
<${sliderTag}
|
|
253
|
+
class="slider"
|
|
254
|
+
aria-label="${(x) => x.sliderAriaLabel || x.locale.audioPlayer.sliderLabel}"
|
|
255
|
+
value="${getCurrentTimePercentage}" max="100"
|
|
256
|
+
ariaValuetext="${(x) => formatTime(x.currentTime)}"
|
|
257
|
+
connotation="${(x) => x.connotation}"
|
|
258
|
+
?disabled="${(x) => x.disabled || !x.duration}">
|
|
230
259
|
</${sliderTag}>`;
|
|
231
260
|
}
|
|
232
261
|
function renderTimestamp() {
|
|
233
|
-
return index.html` <div class="time-stamp"
|
|
234
|
-
<span class="current-time"
|
|
262
|
+
return index.html` <div class="time-stamp">
|
|
263
|
+
<span class="current-time">${(x) => formatTime(x.currentTime)}</span>
|
|
235
264
|
<span>/</span>
|
|
236
|
-
<span class="total-time"
|
|
265
|
+
<span class="total-time">${(x) => formatTime(x.duration)}</span>
|
|
237
266
|
</div>`;
|
|
238
267
|
}
|
|
239
268
|
const AudioPlayerTemplate = (context) => {
|
|
240
269
|
return index.html` <div class="wrapper">
|
|
241
|
-
<div
|
|
242
|
-
class="base ${getClasses}"
|
|
243
|
-
@keyup="${(x, c) => x._handleSliderEvent(c.event)}"
|
|
244
|
-
@keydown="${(x, c) => x._handleSliderEvent(c.event)}"
|
|
245
|
-
@mousedown="${(x, c) => x._handleSliderEvent(c.event)}"
|
|
246
|
-
>
|
|
270
|
+
<div class="base ${getClasses}">
|
|
247
271
|
<div class="controls">
|
|
248
272
|
${when.when(
|
|
249
273
|
(x) => x.skipBy && x.skipBy != enums.MediaSkipBy.Zero,
|
|
@@ -257,12 +281,6 @@ const AudioPlayerTemplate = (context) => {
|
|
|
257
281
|
${when.when((x) => !x.notime, renderTimestamp())}
|
|
258
282
|
</div>
|
|
259
283
|
${renderSlider(context)}
|
|
260
|
-
<audio
|
|
261
|
-
${ref.ref("_playerEl")}
|
|
262
|
-
src="${(x) => x.src}"
|
|
263
|
-
@timeupdate="${(x) => x._updateProgress()}"
|
|
264
|
-
@loadedmetadata="${(x) => x._updateTotalTime()}"
|
|
265
|
-
></audio>
|
|
266
284
|
</div>
|
|
267
285
|
</div>`;
|
|
268
286
|
};
|
package/shared/definition5.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as attr, F as FoundationElement,
|
|
1
|
+
import { a as attr, F as FoundationElement, O as Observable, h as html, r as registerFactory } from './index.js';
|
|
2
2
|
import { B as Button, a as buttonRegistries } from './definition11.js';
|
|
3
3
|
import { S as Slider, a as sliderRegistries } from './definition46.js';
|
|
4
4
|
import { M as MediaSkipBy } from './enums.js';
|
|
@@ -7,7 +7,6 @@ import './index2.js';
|
|
|
7
7
|
import { L as Localized } from './localized.js';
|
|
8
8
|
import { a as applyMixins } from './apply-mixins.js';
|
|
9
9
|
import { w as when } from './when.js';
|
|
10
|
-
import { r as ref } from './ref.js';
|
|
11
10
|
import { c as classNames } from './class-names.js';
|
|
12
11
|
|
|
13
12
|
const styles = ":host{display:block;max-inline-size:350px}.wrapper{container-type:inline-size}.base{display:inline-flex;box-sizing:border-box;align-items:center;padding:8px;color:var(--vvd-color-canvas-text);gap:16px;inline-size:100%;user-select:none}.base .slider{flex:1;grid-area:slider;min-inline-size:var(--audio-player-min-inline-size, 200px)}.base .controls{display:flex;align-items:center;justify-content:center;gap:8px;grid-area:controls}.base .time-stamp{display:inline-flex}.base .time-stamp .current-time,.base .time-stamp .total-time{margin-inline:6px;min-inline-size:32px}.base .playback{grid-area:playback}@container (max-width: 500px){.base.two-lines{display:inline-grid;grid-template:auto auto/1fr;grid-template-areas:\"slider\" \"controls\";inline-size:100%;row-gap:4px}.base.two-lines .time-stamp{margin-inline:auto 2px}.base.two-lines.playback{grid-template-areas:\"slider slider\" \"controls playback\";grid-template-columns:1fr auto}.base.two-lines.playback .time-stamp{margin-inline:auto}.base .slider{box-sizing:border-box;min-inline-size:auto;padding-inline:2px}}";
|
|
@@ -22,6 +21,20 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
22
21
|
__defProp(target, key, result);
|
|
23
22
|
return result;
|
|
24
23
|
};
|
|
24
|
+
const SKIP_DIRECTIONS = {
|
|
25
|
+
FORWARD: 1,
|
|
26
|
+
BACKWARD: -1
|
|
27
|
+
};
|
|
28
|
+
function formatTime(time) {
|
|
29
|
+
if (!time || Number.isNaN(time)) {
|
|
30
|
+
return "0:00";
|
|
31
|
+
}
|
|
32
|
+
const min = Math.floor(time / 60);
|
|
33
|
+
const sec = Math.floor(time % 60);
|
|
34
|
+
return min + ":" + (sec < 10 ? "0" + sec : sec);
|
|
35
|
+
}
|
|
36
|
+
const PAUSE = true;
|
|
37
|
+
const PLAY = false;
|
|
25
38
|
const validSkipByConverter = {
|
|
26
39
|
toView(value) {
|
|
27
40
|
return value;
|
|
@@ -32,7 +45,7 @@ const validSkipByConverter = {
|
|
|
32
45
|
};
|
|
33
46
|
class AudioPlayer extends FoundationElement {
|
|
34
47
|
constructor() {
|
|
35
|
-
super(
|
|
48
|
+
super();
|
|
36
49
|
this.playButtonAriaLabel = null;
|
|
37
50
|
this.pauseButtonAriaLabel = null;
|
|
38
51
|
this.sliderAriaLabel = null;
|
|
@@ -40,106 +53,109 @@ class AudioPlayer extends FoundationElement {
|
|
|
40
53
|
this.skipBackwardButtonAriaLabel = null;
|
|
41
54
|
this.disabled = false;
|
|
42
55
|
this.notime = false;
|
|
43
|
-
this
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (this.
|
|
49
|
-
this.
|
|
56
|
+
this.#playerEl = new Audio();
|
|
57
|
+
this.#pausedChanged = (pausing) => {
|
|
58
|
+
if (pausing === this.paused) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!this.paused) {
|
|
62
|
+
this.#playerEl.pause();
|
|
63
|
+
} else {
|
|
64
|
+
this.#updateProgress();
|
|
65
|
+
this.#playerEl.play();
|
|
66
|
+
}
|
|
67
|
+
this.#setPausedState();
|
|
68
|
+
};
|
|
69
|
+
this.#updateProgress = () => {
|
|
70
|
+
Observable.notify(this, "currentTime");
|
|
71
|
+
const percent = this.currentTime / this.duration * 100;
|
|
72
|
+
if (percent === 100) {
|
|
73
|
+
this.pause();
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
this.#updateTotalTime = () => {
|
|
77
|
+
Observable.notify(this, "duration");
|
|
78
|
+
};
|
|
79
|
+
this.#rewind = () => {
|
|
80
|
+
if (this.#playerEl) {
|
|
81
|
+
this.currentTime = this.duration * Number(this.#sliderEl.value) / 100;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
this.#handleSliderEvent = (event) => {
|
|
85
|
+
if (event.target === this.#sliderEl) {
|
|
86
|
+
this.pause();
|
|
87
|
+
this.#rewind();
|
|
50
88
|
}
|
|
89
|
+
return true;
|
|
51
90
|
};
|
|
91
|
+
this.#setPausedState = () => {
|
|
92
|
+
Observable.notify(this, "paused");
|
|
93
|
+
};
|
|
94
|
+
this.#playerEl.addEventListener("timeupdate", this.#updateProgress);
|
|
95
|
+
this.#playerEl.addEventListener("loadedmetadata", this.#updateTotalTime);
|
|
96
|
+
}
|
|
97
|
+
srcChanged() {
|
|
98
|
+
if (this.src === void 0) {
|
|
99
|
+
this.#playerEl.removeAttribute("src");
|
|
100
|
+
} else {
|
|
101
|
+
this.#playerEl.src = this.src;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
get paused() {
|
|
105
|
+
Observable.track(this, "paused");
|
|
106
|
+
return this.#playerEl.paused;
|
|
107
|
+
}
|
|
108
|
+
set paused(_) {
|
|
109
|
+
}
|
|
110
|
+
get duration() {
|
|
111
|
+
Observable.track(this, "duration");
|
|
112
|
+
return this.#playerEl.duration;
|
|
113
|
+
}
|
|
114
|
+
set duration(_) {
|
|
115
|
+
}
|
|
116
|
+
get currentTime() {
|
|
117
|
+
Observable.track(this, "currentTime");
|
|
118
|
+
return this.#playerEl.currentTime;
|
|
119
|
+
}
|
|
120
|
+
set currentTime(value) {
|
|
121
|
+
this.#playerEl.currentTime = value;
|
|
122
|
+
}
|
|
123
|
+
get #sliderEl() {
|
|
124
|
+
return this.shadowRoot.querySelector(".slider");
|
|
125
|
+
}
|
|
126
|
+
#playerEl;
|
|
127
|
+
get #baseElement() {
|
|
128
|
+
return this.shadowRoot.querySelector(".base");
|
|
52
129
|
}
|
|
53
130
|
connectedCallback() {
|
|
54
131
|
super.connectedCallback();
|
|
55
|
-
document.addEventListener("mouseup", this
|
|
132
|
+
document.addEventListener("mouseup", this.#rewind);
|
|
133
|
+
this.#setInteractionListeners();
|
|
134
|
+
this.#setPausedState();
|
|
56
135
|
}
|
|
57
136
|
disconnectedCallback() {
|
|
58
137
|
super.disconnectedCallback();
|
|
59
|
-
document.addEventListener("mouseup", this
|
|
138
|
+
document.addEventListener("mouseup", this.#rewind);
|
|
139
|
+
this.#setInteractionListeners(false);
|
|
60
140
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
*/
|
|
64
|
-
_togglePlay() {
|
|
65
|
-
if (this.paused) {
|
|
66
|
-
this._updateProgress();
|
|
67
|
-
this._playerEl.play();
|
|
68
|
-
} else {
|
|
69
|
-
this._playerEl.pause();
|
|
70
|
-
}
|
|
71
|
-
this.paused = !this.paused;
|
|
141
|
+
play() {
|
|
142
|
+
this.#pausedChanged(PLAY);
|
|
72
143
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
*/
|
|
76
|
-
_onSkipButtonClick(isForward) {
|
|
77
|
-
if (this._playerEl) {
|
|
78
|
-
const currentTime = this._playerEl.currentTime;
|
|
79
|
-
const skipDirection = isForward ? 1 : -1;
|
|
80
|
-
const skipValue = parseInt(this.skipBy) * skipDirection;
|
|
81
|
-
const newTime = currentTime + skipValue;
|
|
82
|
-
this._playerEl.currentTime = Math.max(
|
|
83
|
-
0,
|
|
84
|
-
Math.min(this._playerEl.duration, newTime)
|
|
85
|
-
);
|
|
86
|
-
this._updateProgress();
|
|
87
|
-
}
|
|
144
|
+
pause() {
|
|
145
|
+
this.#pausedChanged(PAUSE);
|
|
88
146
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const current = this._playerEl.currentTime;
|
|
95
|
-
const percent = current / this._playerEl.duration * 100;
|
|
96
|
-
if (this._sliderEl) {
|
|
97
|
-
this._sliderEl.value = percent.toString();
|
|
98
|
-
this._sliderEl.ariaValuetext = this._formatTime(current);
|
|
99
|
-
}
|
|
100
|
-
if (percent === 100) {
|
|
101
|
-
this.paused = true;
|
|
102
|
-
}
|
|
103
|
-
if (this._timeStampEl) {
|
|
104
|
-
currentTime = this._timeStampEl.querySelector(".current-time");
|
|
105
|
-
if (currentTime)
|
|
106
|
-
currentTime.textContent = this._formatTime(current);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* @internal
|
|
111
|
-
*/
|
|
112
|
-
_updateTotalTime() {
|
|
113
|
-
let totalTime;
|
|
114
|
-
if (this._playerEl)
|
|
115
|
-
this.duration = this._playerEl.duration;
|
|
116
|
-
if (this._timeStampEl) {
|
|
117
|
-
totalTime = this._timeStampEl.querySelector(".total-time");
|
|
118
|
-
if (totalTime)
|
|
119
|
-
totalTime.textContent = this._formatTime(this._playerEl.duration);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* @internal
|
|
124
|
-
*/
|
|
125
|
-
_handleSliderEvent(event) {
|
|
126
|
-
if (event.target === this._sliderEl) {
|
|
127
|
-
this.paused = true;
|
|
128
|
-
if (this._playerEl) {
|
|
129
|
-
this._playerEl.pause();
|
|
130
|
-
}
|
|
131
|
-
this._rewind();
|
|
132
|
-
}
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* @internal
|
|
137
|
-
*/
|
|
138
|
-
_formatTime(time) {
|
|
139
|
-
const min = Math.floor(time / 60);
|
|
140
|
-
const sec = Math.floor(time % 60);
|
|
141
|
-
return min + ":" + (sec < 10 ? "0" + sec : sec);
|
|
147
|
+
#setInteractionListeners(add = true) {
|
|
148
|
+
const action = add ? "addEventListener" : "removeEventListener";
|
|
149
|
+
this.#baseElement[action]("keyup", this.#handleSliderEvent);
|
|
150
|
+
this.#baseElement[action]("keydown", this.#handleSliderEvent);
|
|
151
|
+
this.#baseElement[action]("mousedown", this.#handleSliderEvent);
|
|
142
152
|
}
|
|
153
|
+
#pausedChanged;
|
|
154
|
+
#updateProgress;
|
|
155
|
+
#updateTotalTime;
|
|
156
|
+
#rewind;
|
|
157
|
+
#handleSliderEvent;
|
|
158
|
+
#setPausedState;
|
|
143
159
|
}
|
|
144
160
|
__decorateClass([
|
|
145
161
|
attr({ attribute: "play-button-aria-label" })
|
|
@@ -174,18 +190,27 @@ __decorateClass([
|
|
|
174
190
|
converter: validSkipByConverter
|
|
175
191
|
})
|
|
176
192
|
], AudioPlayer.prototype, "skipBy");
|
|
177
|
-
__decorateClass([
|
|
178
|
-
observable
|
|
179
|
-
], AudioPlayer.prototype, "paused");
|
|
180
|
-
__decorateClass([
|
|
181
|
-
observable
|
|
182
|
-
], AudioPlayer.prototype, "duration");
|
|
183
193
|
applyMixins(AudioPlayer, Localized);
|
|
184
194
|
|
|
195
|
+
function getCurrentTimePercentage(x) {
|
|
196
|
+
if (Number.isNaN(x.currentTime) || Number.isNaN(x.duration)) {
|
|
197
|
+
return 0;
|
|
198
|
+
}
|
|
199
|
+
return x.currentTime / x.duration * 100;
|
|
200
|
+
}
|
|
201
|
+
function skip(audioElement, skipDirection) {
|
|
202
|
+
const currentTime = audioElement.currentTime;
|
|
203
|
+
const skipValue = parseInt(audioElement.skipBy) * skipDirection;
|
|
204
|
+
const newTime = currentTime + skipValue;
|
|
205
|
+
audioElement.currentTime = Math.max(
|
|
206
|
+
0,
|
|
207
|
+
Math.min(audioElement.duration, newTime)
|
|
208
|
+
);
|
|
209
|
+
}
|
|
185
210
|
const getClasses = ({ disabled, duration }) => classNames(["disabled", Boolean(disabled) || !duration]);
|
|
186
211
|
function renderButton(context) {
|
|
187
212
|
const buttonTag = context.tagFor(Button);
|
|
188
|
-
return html`<${buttonTag} class="pause" @click="${(x) => x.
|
|
213
|
+
return html`<${buttonTag} class="pause" @click="${(x) => x.paused ? x.play() : x.pause()}"
|
|
189
214
|
icon="${(x) => x.paused ? "play-solid" : "pause-solid"}"
|
|
190
215
|
aria-label="${(x) => x.paused ? x.playButtonAriaLabel || x.locale.audioPlayer.playButtonLabel : x.pauseButtonAriaLabel || x.locale.audioPlayer.pauseButtonLabel}"
|
|
191
216
|
size='condensed'
|
|
@@ -196,7 +221,8 @@ function renderButton(context) {
|
|
|
196
221
|
function renderBackwardSkipButtons(context) {
|
|
197
222
|
const buttonTag = context.tagFor(Button);
|
|
198
223
|
return html`
|
|
199
|
-
<${buttonTag} class="skip backward"
|
|
224
|
+
<${buttonTag} class="skip backward"
|
|
225
|
+
@click="${(element) => skip(element, SKIP_DIRECTIONS.BACKWARD)}"
|
|
200
226
|
icon="${(x) => x.skipBy == MediaSkipBy.Five ? "5-sec-backward-line" : x.skipBy == MediaSkipBy.Thirty ? "30-sec-backward-line" : "10-sec-backward-line"}"
|
|
201
227
|
size='condensed'
|
|
202
228
|
aria-label="${(x) => x.skipBackwardButtonAriaLabel || x.locale.audioPlayer.skipBackwardButton}"
|
|
@@ -208,7 +234,8 @@ function renderBackwardSkipButtons(context) {
|
|
|
208
234
|
function renderForwardSkipButtons(context) {
|
|
209
235
|
const buttonTag = context.tagFor(Button);
|
|
210
236
|
return html`
|
|
211
|
-
<${buttonTag} class="skip forward"
|
|
237
|
+
<${buttonTag} class="skip forward"
|
|
238
|
+
@click="${(element) => skip(element, SKIP_DIRECTIONS.FORWARD)}"
|
|
212
239
|
icon="${(x) => x.skipBy == MediaSkipBy.Five ? "5-sec-forward-line" : x.skipBy == MediaSkipBy.Thirty ? "30-sec-forward-line" : "10-sec-forward-line"}"
|
|
213
240
|
size='condensed'
|
|
214
241
|
aria-label="${(x) => x.skipForwardButtonAriaLabel || x.locale.audioPlayer.skipForwardButton}"
|
|
@@ -219,29 +246,26 @@ function renderForwardSkipButtons(context) {
|
|
|
219
246
|
}
|
|
220
247
|
function renderSlider(context) {
|
|
221
248
|
const sliderTag = context.tagFor(Slider);
|
|
222
|
-
return html
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
249
|
+
return html`
|
|
250
|
+
<${sliderTag}
|
|
251
|
+
class="slider"
|
|
252
|
+
aria-label="${(x) => x.sliderAriaLabel || x.locale.audioPlayer.sliderLabel}"
|
|
253
|
+
value="${getCurrentTimePercentage}" max="100"
|
|
254
|
+
ariaValuetext="${(x) => formatTime(x.currentTime)}"
|
|
255
|
+
connotation="${(x) => x.connotation}"
|
|
256
|
+
?disabled="${(x) => x.disabled || !x.duration}">
|
|
228
257
|
</${sliderTag}>`;
|
|
229
258
|
}
|
|
230
259
|
function renderTimestamp() {
|
|
231
|
-
return html` <div class="time-stamp"
|
|
232
|
-
<span class="current-time"
|
|
260
|
+
return html` <div class="time-stamp">
|
|
261
|
+
<span class="current-time">${(x) => formatTime(x.currentTime)}</span>
|
|
233
262
|
<span>/</span>
|
|
234
|
-
<span class="total-time"
|
|
263
|
+
<span class="total-time">${(x) => formatTime(x.duration)}</span>
|
|
235
264
|
</div>`;
|
|
236
265
|
}
|
|
237
266
|
const AudioPlayerTemplate = (context) => {
|
|
238
267
|
return html` <div class="wrapper">
|
|
239
|
-
<div
|
|
240
|
-
class="base ${getClasses}"
|
|
241
|
-
@keyup="${(x, c) => x._handleSliderEvent(c.event)}"
|
|
242
|
-
@keydown="${(x, c) => x._handleSliderEvent(c.event)}"
|
|
243
|
-
@mousedown="${(x, c) => x._handleSliderEvent(c.event)}"
|
|
244
|
-
>
|
|
268
|
+
<div class="base ${getClasses}">
|
|
245
269
|
<div class="controls">
|
|
246
270
|
${when(
|
|
247
271
|
(x) => x.skipBy && x.skipBy != MediaSkipBy.Zero,
|
|
@@ -255,12 +279,6 @@ const AudioPlayerTemplate = (context) => {
|
|
|
255
279
|
${when((x) => !x.notime, renderTimestamp())}
|
|
256
280
|
</div>
|
|
257
281
|
${renderSlider(context)}
|
|
258
|
-
<audio
|
|
259
|
-
${ref("_playerEl")}
|
|
260
|
-
src="${(x) => x.src}"
|
|
261
|
-
@timeupdate="${(x) => x._updateProgress()}"
|
|
262
|
-
@loadedmetadata="${(x) => x._updateTotalTime()}"
|
|
263
|
-
></audio>
|
|
264
282
|
</div>
|
|
265
283
|
</div>`;
|
|
266
284
|
};
|