@scarlett-player/ui 1.8.1 → 1.9.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/dist/index.cjs +214 -35
- package/dist/index.d.cts +51 -12
- package/dist/index.d.ts +51 -12
- package/dist/index.js +218 -35
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -33,7 +33,8 @@ __export(index_exports, {
|
|
|
33
33
|
resolveFitItems: () => resolveFitItems,
|
|
34
34
|
styles: () => styles,
|
|
35
35
|
uiPlugin: () => uiPlugin,
|
|
36
|
-
unregisterControl: () => unregisterControl
|
|
36
|
+
unregisterControl: () => unregisterControl,
|
|
37
|
+
unregisterControlsFor: () => unregisterControlsFor
|
|
37
38
|
});
|
|
38
39
|
module.exports = __toCommonJS(index_exports);
|
|
39
40
|
var import_core2 = require("@scarlett-player/core");
|
|
@@ -123,6 +124,10 @@ var styles = `
|
|
|
123
124
|
============================================ */
|
|
124
125
|
.sp-container {
|
|
125
126
|
position: relative;
|
|
127
|
+
/* Own stacking context: the control bar, menus and overlays all carry
|
|
128
|
+
z-index, and without this they compete with the host page's own layers
|
|
129
|
+
instead of staying inside the player. */
|
|
130
|
+
isolation: isolate;
|
|
126
131
|
width: 100%;
|
|
127
132
|
height: 100%;
|
|
128
133
|
background: #000;
|
|
@@ -244,11 +249,13 @@ var styles = `
|
|
|
244
249
|
cursor: pointer;
|
|
245
250
|
z-index: 10;
|
|
246
251
|
opacity: 0;
|
|
252
|
+
pointer-events: none;
|
|
247
253
|
transition: opacity 0.25s ease;
|
|
248
254
|
}
|
|
249
255
|
|
|
250
256
|
.sp-progress-wrapper--visible {
|
|
251
257
|
opacity: 1;
|
|
258
|
+
pointer-events: auto;
|
|
252
259
|
}
|
|
253
260
|
|
|
254
261
|
/* Touch: a 20px wrapper is not a 20px target. The control bar is a later
|
|
@@ -1371,7 +1378,7 @@ var BigPlayButton = class {
|
|
|
1371
1378
|
* must not sit on top of it, and `error` state alone does not say (a
|
|
1372
1379
|
* dismissed overlay leaves the error behind)
|
|
1373
1380
|
*/
|
|
1374
|
-
constructor(api, isOverlayVisible
|
|
1381
|
+
constructor(api, isOverlayVisible) {
|
|
1375
1382
|
/**
|
|
1376
1383
|
* Latched on the first `playing`.
|
|
1377
1384
|
*
|
|
@@ -1385,7 +1392,8 @@ var BigPlayButton = class {
|
|
|
1385
1392
|
this.start();
|
|
1386
1393
|
};
|
|
1387
1394
|
this.api = api;
|
|
1388
|
-
this.
|
|
1395
|
+
this.hasOverlayProbe = typeof isOverlayVisible === "function";
|
|
1396
|
+
this.isOverlayVisible = isOverlayVisible ?? (() => false);
|
|
1389
1397
|
const btn = document.createElement("button");
|
|
1390
1398
|
btn.className = "sp-big-play";
|
|
1391
1399
|
btn.setAttribute("type", "button");
|
|
@@ -1414,7 +1422,7 @@ var BigPlayButton = class {
|
|
|
1414
1422
|
this.hasStarted = true;
|
|
1415
1423
|
}
|
|
1416
1424
|
let visible;
|
|
1417
|
-
if (
|
|
1425
|
+
if (this.hasOverlayProbe ? this.isOverlayVisible() : Boolean(error)) {
|
|
1418
1426
|
visible = false;
|
|
1419
1427
|
} else if (playbackState === "loading") {
|
|
1420
1428
|
visible = false;
|
|
@@ -1840,15 +1848,17 @@ var ProgressBar = class {
|
|
|
1840
1848
|
const seekableRange = this.api.getState("seekableRange");
|
|
1841
1849
|
if (live && seekableRange) {
|
|
1842
1850
|
const rangeLength = seekableRange.end - seekableRange.start;
|
|
1843
|
-
|
|
1851
|
+
const time2 = seekableRange.start + percent * rangeLength;
|
|
1852
|
+
return Number.isFinite(time2) ? time2 : null;
|
|
1844
1853
|
}
|
|
1845
1854
|
const duration = this.api.getState("duration") || 0;
|
|
1846
|
-
|
|
1855
|
+
const time = percent * duration;
|
|
1856
|
+
return Number.isFinite(time) ? time : null;
|
|
1847
1857
|
}
|
|
1848
1858
|
updateTooltip(clientX) {
|
|
1849
1859
|
const rect = this.el.getBoundingClientRect();
|
|
1850
1860
|
const percent = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
1851
|
-
const time = this.getTimeFromPosition(clientX);
|
|
1861
|
+
const time = this.getTimeFromPosition(clientX) ?? 0;
|
|
1852
1862
|
const live = this.api.getState("live");
|
|
1853
1863
|
const seekableRange = this.api.getState("seekableRange");
|
|
1854
1864
|
if (live && seekableRange) {
|
|
@@ -1883,7 +1893,9 @@ var ProgressBar = class {
|
|
|
1883
1893
|
}
|
|
1884
1894
|
this.lastSeekTime = now;
|
|
1885
1895
|
const time = this.getTimeFromPosition(clientX);
|
|
1886
|
-
|
|
1896
|
+
if (time !== null && Number.isFinite(time)) {
|
|
1897
|
+
video.currentTime = time;
|
|
1898
|
+
}
|
|
1887
1899
|
}
|
|
1888
1900
|
destroy() {
|
|
1889
1901
|
this.wrapper.removeEventListener("mousedown", this.onMouseDown);
|
|
@@ -2114,11 +2126,9 @@ var LiveIndicator = class {
|
|
|
2114
2126
|
}
|
|
2115
2127
|
}
|
|
2116
2128
|
seekToLive() {
|
|
2117
|
-
const video = getVideo(this.api.container);
|
|
2118
|
-
if (!video) return;
|
|
2119
2129
|
const seekableRange = this.api.getState("seekableRange");
|
|
2120
2130
|
if (seekableRange) {
|
|
2121
|
-
|
|
2131
|
+
this.api.emit("playback:seeking", { time: seekableRange.end });
|
|
2122
2132
|
}
|
|
2123
2133
|
}
|
|
2124
2134
|
destroy() {
|
|
@@ -2164,6 +2174,9 @@ var QualityMenu = class {
|
|
|
2164
2174
|
const qualities = this.api.getState("qualities") || [];
|
|
2165
2175
|
const currentQuality = this.api.getState("currentQuality");
|
|
2166
2176
|
this.el.style.display = qualities.length > 0 ? "" : "none";
|
|
2177
|
+
if (qualities.length === 0 && this.isOpen) {
|
|
2178
|
+
this.close();
|
|
2179
|
+
}
|
|
2167
2180
|
this.btnLabel.textContent = currentQuality?.label || "Auto";
|
|
2168
2181
|
const qualitiesJson = JSON.stringify(qualities.map((q) => q.id));
|
|
2169
2182
|
const currentId = currentQuality?.id || "auto";
|
|
@@ -2228,6 +2241,16 @@ var QualityMenu = class {
|
|
|
2228
2241
|
this.menu.classList.remove("sp-quality-menu--open");
|
|
2229
2242
|
this.btn.setAttribute("aria-expanded", "false");
|
|
2230
2243
|
}
|
|
2244
|
+
/**
|
|
2245
|
+
* Whether the dropdown is open.
|
|
2246
|
+
*
|
|
2247
|
+
* Read by the UI plugin so the control bar's auto-hide waits for it.
|
|
2248
|
+
*
|
|
2249
|
+
* @returns True while the menu is showing
|
|
2250
|
+
*/
|
|
2251
|
+
isMenuOpen() {
|
|
2252
|
+
return this.isOpen;
|
|
2253
|
+
}
|
|
2231
2254
|
destroy() {
|
|
2232
2255
|
document.removeEventListener("click", this.closeHandler);
|
|
2233
2256
|
this.el.remove();
|
|
@@ -2652,7 +2675,7 @@ var SettingsMenu = class {
|
|
|
2652
2675
|
this.el.appendChild(this.panel);
|
|
2653
2676
|
this.closeHandler = (e) => {
|
|
2654
2677
|
if (!this.el.contains(e.target)) {
|
|
2655
|
-
this.close();
|
|
2678
|
+
this.close(false);
|
|
2656
2679
|
}
|
|
2657
2680
|
};
|
|
2658
2681
|
document.addEventListener("click", this.closeHandler);
|
|
@@ -2665,7 +2688,6 @@ var SettingsMenu = class {
|
|
|
2665
2688
|
this.showPanel("main");
|
|
2666
2689
|
} else {
|
|
2667
2690
|
this.close();
|
|
2668
|
-
this.btn.focus();
|
|
2669
2691
|
}
|
|
2670
2692
|
return;
|
|
2671
2693
|
}
|
|
@@ -2702,6 +2724,8 @@ var SettingsMenu = class {
|
|
|
2702
2724
|
this.updateSpeedActiveStates();
|
|
2703
2725
|
} else if (this.currentPanel === "captions") {
|
|
2704
2726
|
this.updateCaptionsActiveStates();
|
|
2727
|
+
} else if (this.currentPanel === "audio") {
|
|
2728
|
+
this.updateAudioActiveStates();
|
|
2705
2729
|
}
|
|
2706
2730
|
}
|
|
2707
2731
|
}
|
|
@@ -2716,11 +2740,25 @@ var SettingsMenu = class {
|
|
|
2716
2740
|
this.btn.setAttribute("aria-expanded", "true");
|
|
2717
2741
|
this.focusFirstItem();
|
|
2718
2742
|
}
|
|
2719
|
-
|
|
2743
|
+
/**
|
|
2744
|
+
* Close the panel.
|
|
2745
|
+
*
|
|
2746
|
+
* Choosing an item tears down the row that had focus, which drops focus to
|
|
2747
|
+
* `<body>` and strands keyboard viewers outside the player entirely. Hand it
|
|
2748
|
+
* back to the button that opened the menu instead.
|
|
2749
|
+
*
|
|
2750
|
+
* @param restoreFocus - Return focus to the gear button. The outside-click
|
|
2751
|
+
* handler passes false, so a click elsewhere is not pulled back into the bar.
|
|
2752
|
+
*/
|
|
2753
|
+
close(restoreFocus = true) {
|
|
2754
|
+
const wasOpen = this.isOpen;
|
|
2720
2755
|
this.isOpen = false;
|
|
2721
2756
|
this.currentPanel = "main";
|
|
2722
2757
|
this.panel.classList.remove("sp-settings-panel--open");
|
|
2723
2758
|
this.btn.setAttribute("aria-expanded", "false");
|
|
2759
|
+
if (wasOpen && restoreFocus) {
|
|
2760
|
+
this.btn.focus();
|
|
2761
|
+
}
|
|
2724
2762
|
}
|
|
2725
2763
|
showPanel(panel) {
|
|
2726
2764
|
this.currentPanel = panel;
|
|
@@ -2737,6 +2775,9 @@ var SettingsMenu = class {
|
|
|
2737
2775
|
case "captions":
|
|
2738
2776
|
this.renderCaptionsPanel();
|
|
2739
2777
|
break;
|
|
2778
|
+
case "audio":
|
|
2779
|
+
this.renderAudioPanel();
|
|
2780
|
+
break;
|
|
2740
2781
|
}
|
|
2741
2782
|
this.focusFirstItem();
|
|
2742
2783
|
}
|
|
@@ -2765,6 +2806,16 @@ var SettingsMenu = class {
|
|
|
2765
2806
|
);
|
|
2766
2807
|
this.panel.appendChild(captionsRow);
|
|
2767
2808
|
}
|
|
2809
|
+
const audioTracks = this.api.getState("audioTracks") || [];
|
|
2810
|
+
if (audioTracks.length > 1) {
|
|
2811
|
+
const currentAudioTrack = this.api.getState("currentAudioTrack");
|
|
2812
|
+
const audioRow = this.createMainRow(
|
|
2813
|
+
"Audio",
|
|
2814
|
+
currentAudioTrack?.label || "Default",
|
|
2815
|
+
() => this.showPanel("audio")
|
|
2816
|
+
);
|
|
2817
|
+
this.panel.appendChild(audioRow);
|
|
2818
|
+
}
|
|
2768
2819
|
const speedLabel = playbackRate === 1 ? "Normal" : `${playbackRate}x`;
|
|
2769
2820
|
const speedRow = this.createMainRow(
|
|
2770
2821
|
"Speed",
|
|
@@ -2865,6 +2916,36 @@ var SettingsMenu = class {
|
|
|
2865
2916
|
this.panel.appendChild(item);
|
|
2866
2917
|
}
|
|
2867
2918
|
}
|
|
2919
|
+
renderAudioPanel() {
|
|
2920
|
+
this.panel.innerHTML = "";
|
|
2921
|
+
this.panel.className = "sp-settings-panel sp-settings-panel--open sp-settings-panel--sub";
|
|
2922
|
+
const header = this.createSubHeader("Audio");
|
|
2923
|
+
this.panel.appendChild(header);
|
|
2924
|
+
const audioTracks = this.api.getState("audioTracks") || [];
|
|
2925
|
+
const currentAudioTrack = this.api.getState("currentAudioTrack");
|
|
2926
|
+
const activeId = currentAudioTrack?.id ?? null;
|
|
2927
|
+
for (const track of audioTracks) {
|
|
2928
|
+
const item = this.createMenuItem(track.label, track.id, track.id === activeId);
|
|
2929
|
+
item.addEventListener("click", (e) => {
|
|
2930
|
+
e.preventDefault();
|
|
2931
|
+
this.selectAudioTrack(track.id);
|
|
2932
|
+
});
|
|
2933
|
+
this.panel.appendChild(item);
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
selectAudioTrack(trackId) {
|
|
2937
|
+
this.api.emit("track:audio", { trackId });
|
|
2938
|
+
this.close();
|
|
2939
|
+
}
|
|
2940
|
+
updateAudioActiveStates() {
|
|
2941
|
+
const currentAudioTrack = this.api.getState("currentAudioTrack");
|
|
2942
|
+
const activeId = currentAudioTrack?.id ?? null;
|
|
2943
|
+
const items = this.panel.querySelectorAll(".sp-settings-panel__item");
|
|
2944
|
+
items.forEach((item) => {
|
|
2945
|
+
const id = item.getAttribute("data-id");
|
|
2946
|
+
item.classList.toggle("sp-settings-panel__item--active", id === activeId);
|
|
2947
|
+
});
|
|
2948
|
+
}
|
|
2868
2949
|
selectCaption(trackId) {
|
|
2869
2950
|
this.api.emit("track:text", { trackId });
|
|
2870
2951
|
this.close();
|
|
@@ -3254,6 +3335,17 @@ var OverflowTray = class {
|
|
|
3254
3335
|
this.panel.classList.remove("sp-overflow-tray--open");
|
|
3255
3336
|
this.btn.setAttribute("aria-expanded", "false");
|
|
3256
3337
|
}
|
|
3338
|
+
/**
|
|
3339
|
+
* Whether the strip is open.
|
|
3340
|
+
*
|
|
3341
|
+
* Read by the UI plugin so the control bar's auto-hide waits for it: hiding
|
|
3342
|
+
* the bar would take the open tray with it, mid-use.
|
|
3343
|
+
*
|
|
3344
|
+
* @returns True while the strip is showing
|
|
3345
|
+
*/
|
|
3346
|
+
isMenuOpen() {
|
|
3347
|
+
return this.isOpen;
|
|
3348
|
+
}
|
|
3257
3349
|
/**
|
|
3258
3350
|
* Show the button only while the tray holds something the viewer can see.
|
|
3259
3351
|
*
|
|
@@ -3293,19 +3385,53 @@ var OverflowTray = class {
|
|
|
3293
3385
|
};
|
|
3294
3386
|
|
|
3295
3387
|
// src/control-registry.ts
|
|
3296
|
-
var
|
|
3388
|
+
var globalRegistry = /* @__PURE__ */ new Map();
|
|
3389
|
+
var scopedRegistries = /* @__PURE__ */ new Map();
|
|
3297
3390
|
var listeners = /* @__PURE__ */ new Set();
|
|
3298
|
-
function registerControl(id, factory) {
|
|
3299
|
-
|
|
3391
|
+
function registerControl(id, factory, options = {}) {
|
|
3392
|
+
const { owner } = options;
|
|
3393
|
+
if (owner) {
|
|
3394
|
+
let scoped = scopedRegistries.get(owner);
|
|
3395
|
+
if (!scoped) {
|
|
3396
|
+
scoped = /* @__PURE__ */ new Map();
|
|
3397
|
+
scopedRegistries.set(owner, scoped);
|
|
3398
|
+
}
|
|
3399
|
+
scoped.set(id, factory);
|
|
3400
|
+
} else {
|
|
3401
|
+
globalRegistry.set(id, factory);
|
|
3402
|
+
}
|
|
3300
3403
|
for (const listener of listeners) {
|
|
3301
|
-
listener(id);
|
|
3404
|
+
listener(id, owner);
|
|
3302
3405
|
}
|
|
3303
3406
|
}
|
|
3304
|
-
function unregisterControl(id) {
|
|
3305
|
-
|
|
3407
|
+
function unregisterControl(id, options = {}) {
|
|
3408
|
+
const { owner } = options;
|
|
3409
|
+
if (!owner) {
|
|
3410
|
+
return globalRegistry.delete(id);
|
|
3411
|
+
}
|
|
3412
|
+
const scoped = scopedRegistries.get(owner);
|
|
3413
|
+
if (!scoped) {
|
|
3414
|
+
return false;
|
|
3415
|
+
}
|
|
3416
|
+
const removed = scoped.delete(id);
|
|
3417
|
+
if (scoped.size === 0) {
|
|
3418
|
+
scopedRegistries.delete(owner);
|
|
3419
|
+
}
|
|
3420
|
+
return removed;
|
|
3421
|
+
}
|
|
3422
|
+
function unregisterControlsFor(owner) {
|
|
3423
|
+
const removed = scopedRegistries.get(owner)?.size ?? 0;
|
|
3424
|
+
scopedRegistries.delete(owner);
|
|
3425
|
+
return removed;
|
|
3306
3426
|
}
|
|
3307
|
-
function getControlFactory(id) {
|
|
3308
|
-
|
|
3427
|
+
function getControlFactory(id, owner) {
|
|
3428
|
+
if (owner) {
|
|
3429
|
+
const scoped = scopedRegistries.get(owner)?.get(id);
|
|
3430
|
+
if (scoped) {
|
|
3431
|
+
return scoped;
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
return globalRegistry.get(id) ?? null;
|
|
3309
3435
|
}
|
|
3310
3436
|
function onControlRegistered(listener) {
|
|
3311
3437
|
listeners.add(listener);
|
|
@@ -3314,12 +3440,13 @@ function onControlRegistered(listener) {
|
|
|
3314
3440
|
};
|
|
3315
3441
|
}
|
|
3316
3442
|
function resetControlRegistry() {
|
|
3317
|
-
|
|
3443
|
+
globalRegistry.clear();
|
|
3444
|
+
scopedRegistries.clear();
|
|
3318
3445
|
listeners.clear();
|
|
3319
3446
|
}
|
|
3320
3447
|
|
|
3321
3448
|
// src/version.ts
|
|
3322
|
-
var PKG_VERSION = true ? "1.
|
|
3449
|
+
var PKG_VERSION = true ? "1.9.0" : "0.0.0-dev";
|
|
3323
3450
|
|
|
3324
3451
|
// src/index.ts
|
|
3325
3452
|
var DEFAULT_LAYOUT = [
|
|
@@ -3338,7 +3465,19 @@ var DEFAULT_LAYOUT = [
|
|
|
3338
3465
|
"pip",
|
|
3339
3466
|
"fullscreen"
|
|
3340
3467
|
];
|
|
3468
|
+
var STYLE_ID = "sp-ui-styles";
|
|
3341
3469
|
var DEFAULT_HIDE_DELAY = 3e3;
|
|
3470
|
+
var ACTIVATION_KEYS = /* @__PURE__ */ new Set([" ", "Enter"]);
|
|
3471
|
+
var SLIDER_KEYS = /* @__PURE__ */ new Set([
|
|
3472
|
+
"ArrowLeft",
|
|
3473
|
+
"ArrowRight",
|
|
3474
|
+
"ArrowUp",
|
|
3475
|
+
"ArrowDown",
|
|
3476
|
+
"Home",
|
|
3477
|
+
"End",
|
|
3478
|
+
"PageUp",
|
|
3479
|
+
"PageDown"
|
|
3480
|
+
]);
|
|
3342
3481
|
var UNMEASURED_CONTROL_WIDTH = 48;
|
|
3343
3482
|
var FALLBACK_VOLUME_SLIDER_WIDTH = 64;
|
|
3344
3483
|
var OVERFLOW_BUTTON_WIDTH = 44;
|
|
@@ -3355,7 +3494,7 @@ function uiPlugin(config = {}) {
|
|
|
3355
3494
|
let bufferingIndicator = null;
|
|
3356
3495
|
let errorOverlay = null;
|
|
3357
3496
|
let bigPlayButton = null;
|
|
3358
|
-
let
|
|
3497
|
+
let releaseStyles = null;
|
|
3359
3498
|
let controls = [];
|
|
3360
3499
|
let hideTimeout = null;
|
|
3361
3500
|
let stateUnsubscribe = null;
|
|
@@ -3363,6 +3502,7 @@ function uiPlugin(config = {}) {
|
|
|
3363
3502
|
let errorUnsubscribe = null;
|
|
3364
3503
|
let reconnectingUnsubscribe = null;
|
|
3365
3504
|
let recoveredUnsubscribe = null;
|
|
3505
|
+
let loadedUnsubscribe = null;
|
|
3366
3506
|
let controlsVisible = true;
|
|
3367
3507
|
let rafHandle = null;
|
|
3368
3508
|
let tray = null;
|
|
@@ -3374,6 +3514,7 @@ function uiPlugin(config = {}) {
|
|
|
3374
3514
|
let volumeSliderWidth = FALLBACK_VOLUME_SLIDER_WIDTH;
|
|
3375
3515
|
let lastFitSignature = null;
|
|
3376
3516
|
let fitPending = true;
|
|
3517
|
+
let addedContainerClass = false;
|
|
3377
3518
|
const layout = config.controls || DEFAULT_LAYOUT;
|
|
3378
3519
|
const hideDelay = config.hideDelay ?? DEFAULT_HIDE_DELAY;
|
|
3379
3520
|
const showBigPlayButton = config.bigPlayButton !== false;
|
|
@@ -3416,7 +3557,7 @@ function uiPlugin(config = {}) {
|
|
|
3416
3557
|
case "spacer":
|
|
3417
3558
|
return new Spacer();
|
|
3418
3559
|
default: {
|
|
3419
|
-
const factory = getControlFactory(slot);
|
|
3560
|
+
const factory = getControlFactory(slot, api.container);
|
|
3420
3561
|
if (factory) {
|
|
3421
3562
|
try {
|
|
3422
3563
|
return factory(api);
|
|
@@ -3643,6 +3784,10 @@ function uiPlugin(config = {}) {
|
|
|
3643
3784
|
updateControls();
|
|
3644
3785
|
});
|
|
3645
3786
|
};
|
|
3787
|
+
const hasOpenMenu = () => controls.some((control) => {
|
|
3788
|
+
const menu = control;
|
|
3789
|
+
return typeof menu.isMenuOpen === "function" && menu.isMenuOpen();
|
|
3790
|
+
});
|
|
3646
3791
|
const showControls = () => {
|
|
3647
3792
|
if (controlsVisible) {
|
|
3648
3793
|
resetHideTimer();
|
|
@@ -3659,6 +3804,10 @@ function uiPlugin(config = {}) {
|
|
|
3659
3804
|
const hideControls = () => {
|
|
3660
3805
|
const paused = api?.getState("paused");
|
|
3661
3806
|
if (paused) return;
|
|
3807
|
+
if (hasOpenMenu()) {
|
|
3808
|
+
resetHideTimer();
|
|
3809
|
+
return;
|
|
3810
|
+
}
|
|
3662
3811
|
controlsVisible = false;
|
|
3663
3812
|
controlBar?.classList.remove("sp-controls--visible");
|
|
3664
3813
|
controlBar?.classList.add("sp-controls--hidden");
|
|
@@ -3676,22 +3825,33 @@ function uiPlugin(config = {}) {
|
|
|
3676
3825
|
const handlePointerActivity = (event) => {
|
|
3677
3826
|
last_pointer_type = event.pointerType;
|
|
3678
3827
|
};
|
|
3679
|
-
const handleInteraction = () => {
|
|
3680
|
-
if (last_pointer_type === "touch") {
|
|
3828
|
+
const handleInteraction = (event) => {
|
|
3829
|
+
if (last_pointer_type === "touch" && !isOnControls(event)) {
|
|
3681
3830
|
const gestures = api?.getPlugin("gestures");
|
|
3682
3831
|
if (gestures?.ownsTapInteraction()) return;
|
|
3683
3832
|
}
|
|
3684
3833
|
showControls();
|
|
3685
3834
|
};
|
|
3835
|
+
const isOnControls = (event) => {
|
|
3836
|
+
const target = event?.target;
|
|
3837
|
+
if (!(target instanceof Node)) return false;
|
|
3838
|
+
return Boolean(controlBar?.contains(target)) || Boolean(progressBar?.render().contains(target));
|
|
3839
|
+
};
|
|
3686
3840
|
const handleMouseLeave = () => {
|
|
3687
3841
|
hideControls();
|
|
3688
3842
|
};
|
|
3689
3843
|
const handleKeyDown = (e) => {
|
|
3690
3844
|
if (!api.container.contains(document.activeElement)) return;
|
|
3845
|
+
if (e.defaultPrevented) return;
|
|
3846
|
+
if (e.metaKey || e.ctrlKey || e.altKey) return;
|
|
3691
3847
|
const activeEl = document.activeElement;
|
|
3692
3848
|
if (activeEl instanceof HTMLInputElement || activeEl instanceof HTMLTextAreaElement || activeEl instanceof HTMLSelectElement || activeEl?.isContentEditable) {
|
|
3693
3849
|
return;
|
|
3694
3850
|
}
|
|
3851
|
+
const role = activeEl?.getAttribute("role");
|
|
3852
|
+
const isActivatable = activeEl instanceof HTMLButtonElement || role === "button" || role === "menuitem";
|
|
3853
|
+
if (isActivatable && ACTIVATION_KEYS.has(e.key)) return;
|
|
3854
|
+
if (role === "slider" && SLIDER_KEYS.has(e.key)) return;
|
|
3695
3855
|
const video = api.container.querySelector("video");
|
|
3696
3856
|
if (!video) return;
|
|
3697
3857
|
const live = api.getState("live");
|
|
@@ -3758,9 +3918,7 @@ function uiPlugin(config = {}) {
|
|
|
3758
3918
|
version: PKG_VERSION,
|
|
3759
3919
|
async init(pluginApi) {
|
|
3760
3920
|
api = pluginApi;
|
|
3761
|
-
|
|
3762
|
-
styleEl.textContent = styles;
|
|
3763
|
-
document.head.appendChild(styleEl);
|
|
3921
|
+
releaseStyles = (0, import_core2.injectSharedStyles)(STYLE_ID, styles);
|
|
3764
3922
|
if (config.theme) {
|
|
3765
3923
|
this.setTheme(config.theme);
|
|
3766
3924
|
}
|
|
@@ -3773,6 +3931,10 @@ function uiPlugin(config = {}) {
|
|
|
3773
3931
|
if (containerStyle.position === "static") {
|
|
3774
3932
|
container.style.position = "relative";
|
|
3775
3933
|
}
|
|
3934
|
+
if (!container.classList.contains("sp-container")) {
|
|
3935
|
+
container.classList.add("sp-container");
|
|
3936
|
+
addedContainerClass = true;
|
|
3937
|
+
}
|
|
3776
3938
|
const isPlaying = api.getState("playing");
|
|
3777
3939
|
gradient = document.createElement("div");
|
|
3778
3940
|
gradient.className = isPlaying ? "sp-gradient" : "sp-gradient sp-gradient--visible";
|
|
@@ -3788,13 +3950,20 @@ function uiPlugin(config = {}) {
|
|
|
3788
3950
|
if (payload?.fatal) {
|
|
3789
3951
|
const error = api.getState("error") || payload;
|
|
3790
3952
|
errorOverlay?.show(error);
|
|
3953
|
+
scheduleUpdate();
|
|
3791
3954
|
}
|
|
3792
3955
|
});
|
|
3793
3956
|
reconnectingUnsubscribe = api.on("error:reconnecting", () => {
|
|
3794
3957
|
errorOverlay?.showReconnecting();
|
|
3958
|
+
scheduleUpdate();
|
|
3795
3959
|
});
|
|
3796
3960
|
recoveredUnsubscribe = api.on("error:recovered", () => {
|
|
3797
3961
|
errorOverlay?.hide();
|
|
3962
|
+
scheduleUpdate();
|
|
3963
|
+
});
|
|
3964
|
+
loadedUnsubscribe = api.on("media:loaded", () => {
|
|
3965
|
+
errorOverlay?.hide();
|
|
3966
|
+
scheduleUpdate();
|
|
3798
3967
|
});
|
|
3799
3968
|
if (showBigPlayButton) {
|
|
3800
3969
|
bigPlayButton = new BigPlayButton(api, () => errorOverlay?.isVisible() ?? false);
|
|
@@ -3819,10 +3988,13 @@ function uiPlugin(config = {}) {
|
|
|
3819
3988
|
});
|
|
3820
3989
|
resizeObserver.observe(container);
|
|
3821
3990
|
}
|
|
3822
|
-
controlRegistryUnsubscribe = onControlRegistered((id) => {
|
|
3991
|
+
controlRegistryUnsubscribe = onControlRegistered((id, owner) => {
|
|
3823
3992
|
if (!layout.includes(id)) {
|
|
3824
3993
|
return;
|
|
3825
3994
|
}
|
|
3995
|
+
if (owner && owner !== api.container) {
|
|
3996
|
+
return;
|
|
3997
|
+
}
|
|
3826
3998
|
api.logger.debug(`Control "${id}" registered after init, rebuilding control bar`);
|
|
3827
3999
|
rebuildControlBar();
|
|
3828
4000
|
});
|
|
@@ -3866,6 +4038,8 @@ function uiPlugin(config = {}) {
|
|
|
3866
4038
|
reconnectingUnsubscribe = null;
|
|
3867
4039
|
recoveredUnsubscribe?.();
|
|
3868
4040
|
recoveredUnsubscribe = null;
|
|
4041
|
+
loadedUnsubscribe?.();
|
|
4042
|
+
loadedUnsubscribe = null;
|
|
3869
4043
|
if (api?.container) {
|
|
3870
4044
|
api.container.removeEventListener("pointerdown", handlePointerActivity);
|
|
3871
4045
|
api.container.removeEventListener("pointermove", handlePointerActivity);
|
|
@@ -3895,8 +4069,12 @@ function uiPlugin(config = {}) {
|
|
|
3895
4069
|
gradient = null;
|
|
3896
4070
|
bufferingIndicator?.remove();
|
|
3897
4071
|
bufferingIndicator = null;
|
|
3898
|
-
|
|
3899
|
-
|
|
4072
|
+
releaseStyles?.();
|
|
4073
|
+
releaseStyles = null;
|
|
4074
|
+
if (addedContainerClass) {
|
|
4075
|
+
api?.container?.classList.remove("sp-container");
|
|
4076
|
+
addedContainerClass = false;
|
|
4077
|
+
}
|
|
3900
4078
|
api?.logger.debug("UI controls plugin destroyed");
|
|
3901
4079
|
},
|
|
3902
4080
|
// Public API
|
|
@@ -3949,5 +4127,6 @@ var index_default = uiPlugin;
|
|
|
3949
4127
|
resolveFitItems,
|
|
3950
4128
|
styles,
|
|
3951
4129
|
uiPlugin,
|
|
3952
|
-
unregisterControl
|
|
4130
|
+
unregisterControl,
|
|
4131
|
+
unregisterControlsFor
|
|
3953
4132
|
});
|