@scarlett-player/ui 1.2.0 → 1.4.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.
- package/dist/index.cjs +81 -10
- package/dist/index.d.cts +76 -4
- package/dist/index.d.ts +76 -4
- package/dist/index.js +76 -9
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -23,9 +23,13 @@ __export(index_exports, {
|
|
|
23
23
|
default: () => index_default,
|
|
24
24
|
formatLiveTime: () => formatLiveTime,
|
|
25
25
|
formatTime: () => formatTime,
|
|
26
|
+
getControlFactory: () => getControlFactory,
|
|
26
27
|
icons: () => icons,
|
|
28
|
+
registerControl: () => registerControl,
|
|
29
|
+
resetControlRegistry: () => resetControlRegistry,
|
|
27
30
|
styles: () => styles,
|
|
28
|
-
uiPlugin: () => uiPlugin
|
|
31
|
+
uiPlugin: () => uiPlugin,
|
|
32
|
+
unregisterControl: () => unregisterControl
|
|
29
33
|
});
|
|
30
34
|
module.exports = __toCommonJS(index_exports);
|
|
31
35
|
|
|
@@ -2615,6 +2619,32 @@ var BandwidthIndicator = class {
|
|
|
2615
2619
|
}
|
|
2616
2620
|
};
|
|
2617
2621
|
|
|
2622
|
+
// src/control-registry.ts
|
|
2623
|
+
var registry = /* @__PURE__ */ new Map();
|
|
2624
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
2625
|
+
function registerControl(id, factory) {
|
|
2626
|
+
registry.set(id, factory);
|
|
2627
|
+
for (const listener of listeners) {
|
|
2628
|
+
listener(id);
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
function unregisterControl(id) {
|
|
2632
|
+
return registry.delete(id);
|
|
2633
|
+
}
|
|
2634
|
+
function getControlFactory(id) {
|
|
2635
|
+
return registry.get(id) ?? null;
|
|
2636
|
+
}
|
|
2637
|
+
function onControlRegistered(listener) {
|
|
2638
|
+
listeners.add(listener);
|
|
2639
|
+
return () => {
|
|
2640
|
+
listeners.delete(listener);
|
|
2641
|
+
};
|
|
2642
|
+
}
|
|
2643
|
+
function resetControlRegistry() {
|
|
2644
|
+
registry.clear();
|
|
2645
|
+
listeners.clear();
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2618
2648
|
// src/index.ts
|
|
2619
2649
|
var DEFAULT_LAYOUT = [
|
|
2620
2650
|
"play",
|
|
@@ -2644,6 +2674,7 @@ function uiPlugin(config = {}) {
|
|
|
2644
2674
|
let controls = [];
|
|
2645
2675
|
let hideTimeout = null;
|
|
2646
2676
|
let stateUnsubscribe = null;
|
|
2677
|
+
let controlRegistryUnsubscribe = null;
|
|
2647
2678
|
let errorUnsubscribe = null;
|
|
2648
2679
|
let reconnectingUnsubscribe = null;
|
|
2649
2680
|
let recoveredUnsubscribe = null;
|
|
@@ -2685,10 +2716,43 @@ function uiPlugin(config = {}) {
|
|
|
2685
2716
|
return new FullscreenButton(api);
|
|
2686
2717
|
case "spacer":
|
|
2687
2718
|
return new Spacer();
|
|
2688
|
-
default:
|
|
2719
|
+
default: {
|
|
2720
|
+
const factory = getControlFactory(slot);
|
|
2721
|
+
if (factory) {
|
|
2722
|
+
try {
|
|
2723
|
+
return factory(api);
|
|
2724
|
+
} catch (error) {
|
|
2725
|
+
api.logger.error(`Control factory for "${slot}" threw`, { error });
|
|
2726
|
+
return null;
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
api.logger.warn(`Unknown control slot: ${slot}`);
|
|
2689
2730
|
return null;
|
|
2731
|
+
}
|
|
2690
2732
|
}
|
|
2691
2733
|
};
|
|
2734
|
+
const populateControlBar = () => {
|
|
2735
|
+
if (!controlBar) {
|
|
2736
|
+
return;
|
|
2737
|
+
}
|
|
2738
|
+
for (const slot of layout) {
|
|
2739
|
+
const control = createControl(slot);
|
|
2740
|
+
if (control) {
|
|
2741
|
+
controls.push(control);
|
|
2742
|
+
controlBar.appendChild(control.render());
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
};
|
|
2746
|
+
const rebuildControlBar = () => {
|
|
2747
|
+
if (!controlBar) {
|
|
2748
|
+
return;
|
|
2749
|
+
}
|
|
2750
|
+
controls.forEach((c) => c.destroy());
|
|
2751
|
+
controls = [];
|
|
2752
|
+
controlBar.replaceChildren();
|
|
2753
|
+
populateControlBar();
|
|
2754
|
+
updateControls();
|
|
2755
|
+
};
|
|
2692
2756
|
const updateControls = () => {
|
|
2693
2757
|
controls.forEach((c) => c.update());
|
|
2694
2758
|
progressBar?.update();
|
|
@@ -2861,14 +2925,15 @@ function uiPlugin(config = {}) {
|
|
|
2861
2925
|
controlBar.className = isPlaying ? "sp-controls sp-controls--hidden" : "sp-controls sp-controls--visible";
|
|
2862
2926
|
controlBar.setAttribute("role", "toolbar");
|
|
2863
2927
|
controlBar.setAttribute("aria-label", "Video controls");
|
|
2864
|
-
|
|
2865
|
-
const control = createControl(slot);
|
|
2866
|
-
if (control) {
|
|
2867
|
-
controls.push(control);
|
|
2868
|
-
controlBar.appendChild(control.render());
|
|
2869
|
-
}
|
|
2870
|
-
}
|
|
2928
|
+
populateControlBar();
|
|
2871
2929
|
container.appendChild(controlBar);
|
|
2930
|
+
controlRegistryUnsubscribe = onControlRegistered((id) => {
|
|
2931
|
+
if (!layout.includes(id)) {
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
api.logger.debug(`Control "${id}" registered after init, rebuilding control bar`);
|
|
2935
|
+
rebuildControlBar();
|
|
2936
|
+
});
|
|
2872
2937
|
container.addEventListener("mousemove", handleInteraction);
|
|
2873
2938
|
container.addEventListener("mouseenter", handleInteraction);
|
|
2874
2939
|
container.addEventListener("mouseleave", handleMouseLeave);
|
|
@@ -2914,6 +2979,8 @@ function uiPlugin(config = {}) {
|
|
|
2914
2979
|
}
|
|
2915
2980
|
document.removeEventListener("keydown", handleKeyDown);
|
|
2916
2981
|
document.removeEventListener("fullscreenchange", scheduleUpdate);
|
|
2982
|
+
controlRegistryUnsubscribe?.();
|
|
2983
|
+
controlRegistryUnsubscribe = null;
|
|
2917
2984
|
controls.forEach((c) => c.destroy());
|
|
2918
2985
|
controls = [];
|
|
2919
2986
|
progressBar?.destroy();
|
|
@@ -2970,7 +3037,11 @@ var index_default = uiPlugin;
|
|
|
2970
3037
|
0 && (module.exports = {
|
|
2971
3038
|
formatLiveTime,
|
|
2972
3039
|
formatTime,
|
|
3040
|
+
getControlFactory,
|
|
2973
3041
|
icons,
|
|
3042
|
+
registerControl,
|
|
3043
|
+
resetControlRegistry,
|
|
2974
3044
|
styles,
|
|
2975
|
-
uiPlugin
|
|
3045
|
+
uiPlugin,
|
|
3046
|
+
unregisterControl
|
|
2976
3047
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
import { Plugin } from '@scarlett-player/core';
|
|
1
|
+
import { Plugin, IPluginAPI } from '@scarlett-player/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* UI Controls Plugin Types
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Control slots this package implements itself.
|
|
9
9
|
*/
|
|
10
|
-
type
|
|
10
|
+
type BuiltinControlSlot = 'play' | 'skip-backward' | 'skip-forward' | 'volume' | 'progress' | 'time' | 'live-indicator' | 'quality' | 'settings' | 'captions' | 'airplay' | 'chromecast' | 'pip' | 'fullscreen' | 'spacer' | 'bandwidth-indicator';
|
|
11
|
+
/**
|
|
12
|
+
* A control slot: a built-in, or any id a plugin registered through
|
|
13
|
+
* {@link registerControl}.
|
|
14
|
+
*
|
|
15
|
+
* `string & {}` keeps editor autocomplete listing the built-ins while still
|
|
16
|
+
* accepting custom ids — a plain `| string` would collapse the union and lose
|
|
17
|
+
* the suggestions.
|
|
18
|
+
*/
|
|
19
|
+
type ControlSlot = BuiltinControlSlot | (string & {});
|
|
20
|
+
/**
|
|
21
|
+
* Builds a control instance. Receives the same plugin API the built-ins get.
|
|
22
|
+
*/
|
|
23
|
+
type ControlFactory = (api: IPluginAPI) => Control;
|
|
11
24
|
/**
|
|
12
25
|
* Layout configuration for the control bar.
|
|
13
26
|
*/
|
|
@@ -65,6 +78,65 @@ interface IUIPlugin extends Plugin {
|
|
|
65
78
|
getControlBar(): HTMLElement | null;
|
|
66
79
|
}
|
|
67
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Custom control registry.
|
|
83
|
+
*
|
|
84
|
+
* The built-in controls are created by a switch in the UI plugin. Anything a
|
|
85
|
+
* plugin package contributes is registered here instead, so a control-bar
|
|
86
|
+
* button no longer requires editing this package.
|
|
87
|
+
*
|
|
88
|
+
* The registry is module-level and therefore shared by every player instance on
|
|
89
|
+
* the page. That matches how plugin packages register — once, at import time or
|
|
90
|
+
* in `init()` — and the factory receives the per-instance `IPluginAPI`, so the
|
|
91
|
+
* controls themselves stay properly scoped to their player.
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Register a control factory under a slot id.
|
|
96
|
+
*
|
|
97
|
+
* The id only takes effect for players whose layout lists it — registering
|
|
98
|
+
* alone never adds a button anywhere. Hosts opt controls in through
|
|
99
|
+
* `uiPlugin({ controls: [...] })`.
|
|
100
|
+
*
|
|
101
|
+
* Registering an id that already exists replaces the factory and re-notifies,
|
|
102
|
+
* which keeps hot-reload workable.
|
|
103
|
+
*
|
|
104
|
+
* @param id - Slot id, conventionally the plugin's own name
|
|
105
|
+
* @param factory - Builds the control for a given player
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* registerControl('share', (api) => new ShareButton(api));
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
declare function registerControl(id: string, factory: ControlFactory): void;
|
|
113
|
+
/**
|
|
114
|
+
* Remove a registered control factory.
|
|
115
|
+
*
|
|
116
|
+
* Players already showing the control keep their existing instance until they
|
|
117
|
+
* rebuild; this only stops future ones being created.
|
|
118
|
+
*
|
|
119
|
+
* @param id - Slot id to remove
|
|
120
|
+
* @returns Whether a factory was registered under that id
|
|
121
|
+
*/
|
|
122
|
+
declare function unregisterControl(id: string): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Look up a registered factory.
|
|
125
|
+
*
|
|
126
|
+
* @param id - Slot id
|
|
127
|
+
* @returns The factory, or null when nothing is registered for that id
|
|
128
|
+
*/
|
|
129
|
+
declare function getControlFactory(id: string): ControlFactory | null;
|
|
130
|
+
/**
|
|
131
|
+
* Clear all registrations and listeners.
|
|
132
|
+
*
|
|
133
|
+
* Test-support only — the registry is module-level, so without this a
|
|
134
|
+
* registration in one test leaks into the next.
|
|
135
|
+
*
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
declare function resetControlRegistry(): void;
|
|
139
|
+
|
|
68
140
|
/**
|
|
69
141
|
* SVG Icons for UI Controls
|
|
70
142
|
*
|
|
@@ -148,4 +220,4 @@ declare function formatLiveTime(behindLive: number): string;
|
|
|
148
220
|
*/
|
|
149
221
|
declare function uiPlugin(config?: UIPluginConfig): IUIPlugin;
|
|
150
222
|
|
|
151
|
-
export { type Control, type ControlSlot, type IUIPlugin, type LayoutConfig, type ThemeConfig, type UIPluginConfig, uiPlugin as default, formatLiveTime, formatTime, icons, styles, uiPlugin };
|
|
223
|
+
export { type BuiltinControlSlot, type Control, type ControlFactory, type ControlSlot, type IUIPlugin, type LayoutConfig, type ThemeConfig, type UIPluginConfig, uiPlugin as default, formatLiveTime, formatTime, getControlFactory, icons, registerControl, resetControlRegistry, styles, uiPlugin, unregisterControl };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
import { Plugin } from '@scarlett-player/core';
|
|
1
|
+
import { Plugin, IPluginAPI } from '@scarlett-player/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* UI Controls Plugin Types
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Control slots this package implements itself.
|
|
9
9
|
*/
|
|
10
|
-
type
|
|
10
|
+
type BuiltinControlSlot = 'play' | 'skip-backward' | 'skip-forward' | 'volume' | 'progress' | 'time' | 'live-indicator' | 'quality' | 'settings' | 'captions' | 'airplay' | 'chromecast' | 'pip' | 'fullscreen' | 'spacer' | 'bandwidth-indicator';
|
|
11
|
+
/**
|
|
12
|
+
* A control slot: a built-in, or any id a plugin registered through
|
|
13
|
+
* {@link registerControl}.
|
|
14
|
+
*
|
|
15
|
+
* `string & {}` keeps editor autocomplete listing the built-ins while still
|
|
16
|
+
* accepting custom ids — a plain `| string` would collapse the union and lose
|
|
17
|
+
* the suggestions.
|
|
18
|
+
*/
|
|
19
|
+
type ControlSlot = BuiltinControlSlot | (string & {});
|
|
20
|
+
/**
|
|
21
|
+
* Builds a control instance. Receives the same plugin API the built-ins get.
|
|
22
|
+
*/
|
|
23
|
+
type ControlFactory = (api: IPluginAPI) => Control;
|
|
11
24
|
/**
|
|
12
25
|
* Layout configuration for the control bar.
|
|
13
26
|
*/
|
|
@@ -65,6 +78,65 @@ interface IUIPlugin extends Plugin {
|
|
|
65
78
|
getControlBar(): HTMLElement | null;
|
|
66
79
|
}
|
|
67
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Custom control registry.
|
|
83
|
+
*
|
|
84
|
+
* The built-in controls are created by a switch in the UI plugin. Anything a
|
|
85
|
+
* plugin package contributes is registered here instead, so a control-bar
|
|
86
|
+
* button no longer requires editing this package.
|
|
87
|
+
*
|
|
88
|
+
* The registry is module-level and therefore shared by every player instance on
|
|
89
|
+
* the page. That matches how plugin packages register — once, at import time or
|
|
90
|
+
* in `init()` — and the factory receives the per-instance `IPluginAPI`, so the
|
|
91
|
+
* controls themselves stay properly scoped to their player.
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Register a control factory under a slot id.
|
|
96
|
+
*
|
|
97
|
+
* The id only takes effect for players whose layout lists it — registering
|
|
98
|
+
* alone never adds a button anywhere. Hosts opt controls in through
|
|
99
|
+
* `uiPlugin({ controls: [...] })`.
|
|
100
|
+
*
|
|
101
|
+
* Registering an id that already exists replaces the factory and re-notifies,
|
|
102
|
+
* which keeps hot-reload workable.
|
|
103
|
+
*
|
|
104
|
+
* @param id - Slot id, conventionally the plugin's own name
|
|
105
|
+
* @param factory - Builds the control for a given player
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* registerControl('share', (api) => new ShareButton(api));
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
declare function registerControl(id: string, factory: ControlFactory): void;
|
|
113
|
+
/**
|
|
114
|
+
* Remove a registered control factory.
|
|
115
|
+
*
|
|
116
|
+
* Players already showing the control keep their existing instance until they
|
|
117
|
+
* rebuild; this only stops future ones being created.
|
|
118
|
+
*
|
|
119
|
+
* @param id - Slot id to remove
|
|
120
|
+
* @returns Whether a factory was registered under that id
|
|
121
|
+
*/
|
|
122
|
+
declare function unregisterControl(id: string): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Look up a registered factory.
|
|
125
|
+
*
|
|
126
|
+
* @param id - Slot id
|
|
127
|
+
* @returns The factory, or null when nothing is registered for that id
|
|
128
|
+
*/
|
|
129
|
+
declare function getControlFactory(id: string): ControlFactory | null;
|
|
130
|
+
/**
|
|
131
|
+
* Clear all registrations and listeners.
|
|
132
|
+
*
|
|
133
|
+
* Test-support only — the registry is module-level, so without this a
|
|
134
|
+
* registration in one test leaks into the next.
|
|
135
|
+
*
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
declare function resetControlRegistry(): void;
|
|
139
|
+
|
|
68
140
|
/**
|
|
69
141
|
* SVG Icons for UI Controls
|
|
70
142
|
*
|
|
@@ -148,4 +220,4 @@ declare function formatLiveTime(behindLive: number): string;
|
|
|
148
220
|
*/
|
|
149
221
|
declare function uiPlugin(config?: UIPluginConfig): IUIPlugin;
|
|
150
222
|
|
|
151
|
-
export { type Control, type ControlSlot, type IUIPlugin, type LayoutConfig, type ThemeConfig, type UIPluginConfig, uiPlugin as default, formatLiveTime, formatTime, icons, styles, uiPlugin };
|
|
223
|
+
export { type BuiltinControlSlot, type Control, type ControlFactory, type ControlSlot, type IUIPlugin, type LayoutConfig, type ThemeConfig, type UIPluginConfig, uiPlugin as default, formatLiveTime, formatTime, getControlFactory, icons, registerControl, resetControlRegistry, styles, uiPlugin, unregisterControl };
|
package/dist/index.js
CHANGED
|
@@ -2584,6 +2584,32 @@ var BandwidthIndicator = class {
|
|
|
2584
2584
|
}
|
|
2585
2585
|
};
|
|
2586
2586
|
|
|
2587
|
+
// src/control-registry.ts
|
|
2588
|
+
var registry = /* @__PURE__ */ new Map();
|
|
2589
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
2590
|
+
function registerControl(id, factory) {
|
|
2591
|
+
registry.set(id, factory);
|
|
2592
|
+
for (const listener of listeners) {
|
|
2593
|
+
listener(id);
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
function unregisterControl(id) {
|
|
2597
|
+
return registry.delete(id);
|
|
2598
|
+
}
|
|
2599
|
+
function getControlFactory(id) {
|
|
2600
|
+
return registry.get(id) ?? null;
|
|
2601
|
+
}
|
|
2602
|
+
function onControlRegistered(listener) {
|
|
2603
|
+
listeners.add(listener);
|
|
2604
|
+
return () => {
|
|
2605
|
+
listeners.delete(listener);
|
|
2606
|
+
};
|
|
2607
|
+
}
|
|
2608
|
+
function resetControlRegistry() {
|
|
2609
|
+
registry.clear();
|
|
2610
|
+
listeners.clear();
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2587
2613
|
// src/index.ts
|
|
2588
2614
|
var DEFAULT_LAYOUT = [
|
|
2589
2615
|
"play",
|
|
@@ -2613,6 +2639,7 @@ function uiPlugin(config = {}) {
|
|
|
2613
2639
|
let controls = [];
|
|
2614
2640
|
let hideTimeout = null;
|
|
2615
2641
|
let stateUnsubscribe = null;
|
|
2642
|
+
let controlRegistryUnsubscribe = null;
|
|
2616
2643
|
let errorUnsubscribe = null;
|
|
2617
2644
|
let reconnectingUnsubscribe = null;
|
|
2618
2645
|
let recoveredUnsubscribe = null;
|
|
@@ -2654,10 +2681,43 @@ function uiPlugin(config = {}) {
|
|
|
2654
2681
|
return new FullscreenButton(api);
|
|
2655
2682
|
case "spacer":
|
|
2656
2683
|
return new Spacer();
|
|
2657
|
-
default:
|
|
2684
|
+
default: {
|
|
2685
|
+
const factory = getControlFactory(slot);
|
|
2686
|
+
if (factory) {
|
|
2687
|
+
try {
|
|
2688
|
+
return factory(api);
|
|
2689
|
+
} catch (error) {
|
|
2690
|
+
api.logger.error(`Control factory for "${slot}" threw`, { error });
|
|
2691
|
+
return null;
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
api.logger.warn(`Unknown control slot: ${slot}`);
|
|
2658
2695
|
return null;
|
|
2696
|
+
}
|
|
2659
2697
|
}
|
|
2660
2698
|
};
|
|
2699
|
+
const populateControlBar = () => {
|
|
2700
|
+
if (!controlBar) {
|
|
2701
|
+
return;
|
|
2702
|
+
}
|
|
2703
|
+
for (const slot of layout) {
|
|
2704
|
+
const control = createControl(slot);
|
|
2705
|
+
if (control) {
|
|
2706
|
+
controls.push(control);
|
|
2707
|
+
controlBar.appendChild(control.render());
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
};
|
|
2711
|
+
const rebuildControlBar = () => {
|
|
2712
|
+
if (!controlBar) {
|
|
2713
|
+
return;
|
|
2714
|
+
}
|
|
2715
|
+
controls.forEach((c) => c.destroy());
|
|
2716
|
+
controls = [];
|
|
2717
|
+
controlBar.replaceChildren();
|
|
2718
|
+
populateControlBar();
|
|
2719
|
+
updateControls();
|
|
2720
|
+
};
|
|
2661
2721
|
const updateControls = () => {
|
|
2662
2722
|
controls.forEach((c) => c.update());
|
|
2663
2723
|
progressBar?.update();
|
|
@@ -2830,14 +2890,15 @@ function uiPlugin(config = {}) {
|
|
|
2830
2890
|
controlBar.className = isPlaying ? "sp-controls sp-controls--hidden" : "sp-controls sp-controls--visible";
|
|
2831
2891
|
controlBar.setAttribute("role", "toolbar");
|
|
2832
2892
|
controlBar.setAttribute("aria-label", "Video controls");
|
|
2833
|
-
|
|
2834
|
-
const control = createControl(slot);
|
|
2835
|
-
if (control) {
|
|
2836
|
-
controls.push(control);
|
|
2837
|
-
controlBar.appendChild(control.render());
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2893
|
+
populateControlBar();
|
|
2840
2894
|
container.appendChild(controlBar);
|
|
2895
|
+
controlRegistryUnsubscribe = onControlRegistered((id) => {
|
|
2896
|
+
if (!layout.includes(id)) {
|
|
2897
|
+
return;
|
|
2898
|
+
}
|
|
2899
|
+
api.logger.debug(`Control "${id}" registered after init, rebuilding control bar`);
|
|
2900
|
+
rebuildControlBar();
|
|
2901
|
+
});
|
|
2841
2902
|
container.addEventListener("mousemove", handleInteraction);
|
|
2842
2903
|
container.addEventListener("mouseenter", handleInteraction);
|
|
2843
2904
|
container.addEventListener("mouseleave", handleMouseLeave);
|
|
@@ -2883,6 +2944,8 @@ function uiPlugin(config = {}) {
|
|
|
2883
2944
|
}
|
|
2884
2945
|
document.removeEventListener("keydown", handleKeyDown);
|
|
2885
2946
|
document.removeEventListener("fullscreenchange", scheduleUpdate);
|
|
2947
|
+
controlRegistryUnsubscribe?.();
|
|
2948
|
+
controlRegistryUnsubscribe = null;
|
|
2886
2949
|
controls.forEach((c) => c.destroy());
|
|
2887
2950
|
controls = [];
|
|
2888
2951
|
progressBar?.destroy();
|
|
@@ -2939,7 +3002,11 @@ export {
|
|
|
2939
3002
|
index_default as default,
|
|
2940
3003
|
formatLiveTime,
|
|
2941
3004
|
formatTime,
|
|
3005
|
+
getControlFactory,
|
|
2942
3006
|
icons,
|
|
3007
|
+
registerControl,
|
|
3008
|
+
resetControlRegistry,
|
|
2943
3009
|
styles,
|
|
2944
|
-
uiPlugin
|
|
3010
|
+
uiPlugin,
|
|
3011
|
+
unregisterControl
|
|
2945
3012
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scarlett-player/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "UI Controls Plugin for Scarlett Player",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"typescript": "^5.3.0",
|
|
30
30
|
"vitest": "^1.6.0",
|
|
31
31
|
"jsdom": "^24.0.0",
|
|
32
|
-
"@scarlett-player/core": "1.
|
|
32
|
+
"@scarlett-player/core": "1.4.1"
|
|
33
33
|
},
|
|
34
34
|
"keywords": [
|
|
35
35
|
"video",
|