@mattebox/player-cast 0.1.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 (50) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +24 -0
  3. package/README.md +54 -0
  4. package/dist/cast-button.d.ts +13 -0
  5. package/dist/cast-button.d.ts.map +1 -0
  6. package/dist/cast-button.js +65 -0
  7. package/dist/cast-button.js.map +1 -0
  8. package/dist/cast-screen.d.ts +24 -0
  9. package/dist/cast-screen.d.ts.map +1 -0
  10. package/dist/cast-screen.js +148 -0
  11. package/dist/cast-screen.js.map +1 -0
  12. package/dist/cast.d.ts +77 -0
  13. package/dist/cast.d.ts.map +1 -0
  14. package/dist/cast.js +343 -0
  15. package/dist/cast.js.map +1 -0
  16. package/dist/cdn/mattebox-player-cast.min.js +91 -0
  17. package/dist/component.d.ts +48 -0
  18. package/dist/component.d.ts.map +1 -0
  19. package/dist/component.js +89 -0
  20. package/dist/component.js.map +1 -0
  21. package/dist/es2015/cast-button.js +59 -0
  22. package/dist/es2015/cast-screen.js +151 -0
  23. package/dist/es2015/cast.js +299 -0
  24. package/dist/es2015/component.js +84 -0
  25. package/dist/es2015/host.js +19 -0
  26. package/dist/es2015/icons.js +23 -0
  27. package/dist/es2015/index.js +17 -0
  28. package/dist/es2015/shared.js +125 -0
  29. package/dist/es2015/slider.js +154 -0
  30. package/dist/host.d.ts +14 -0
  31. package/dist/host.d.ts.map +1 -0
  32. package/dist/host.js +19 -0
  33. package/dist/host.js.map +1 -0
  34. package/dist/icons.d.ts +33 -0
  35. package/dist/icons.d.ts.map +1 -0
  36. package/dist/icons.js +52 -0
  37. package/dist/icons.js.map +1 -0
  38. package/dist/index.d.ts +22 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +21 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/shared.d.ts +29 -0
  43. package/dist/shared.d.ts.map +1 -0
  44. package/dist/shared.js +125 -0
  45. package/dist/shared.js.map +1 -0
  46. package/dist/slider.d.ts +28 -0
  47. package/dist/slider.d.ts.map +1 -0
  48. package/dist/slider.js +165 -0
  49. package/dist/slider.js.map +1 -0
  50. package/package.json +59 -0
@@ -0,0 +1,125 @@
1
+ //#region src/shared.ts
2
+ /**
3
+ * The styles and helpers the two elements share, copied from the player:
4
+ * the button and slider styles, the glyph slots, the part helper, the label
5
+ * template, and the time format. The player exports none of them, on
6
+ * purpose: a control of the page's own carries its own, and so does this
7
+ * package. The tokens come through the `--mbx-*` custom properties the
8
+ * player sets, which inherit into every control.
9
+ */
10
+ const BUTTON_STYLE = `
11
+ :host { display: inline-flex; }
12
+ :host([hidden]) { display: none; }
13
+ [part~="button"] {
14
+ display: inline-flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+ flex: none;
18
+ width: 40px;
19
+ height: 40px;
20
+ padding: 0;
21
+ font: inherit;
22
+ color: inherit;
23
+ background: transparent;
24
+ border: 0;
25
+ border-radius: var(--mbx-radius);
26
+ cursor: pointer;
27
+ opacity: 0.9;
28
+ }
29
+ [part~="button"]:hover { opacity: 1; }
30
+ [part~="button"]:focus-visible { outline: 2px solid var(--mbx-accent); outline-offset: -2px; }
31
+ [part~="icon"], ::slotted(*) { width: 1.75em; height: 1.75em; fill: currentColor; }
32
+ slot[hidden] { display: none; }
33
+ `;
34
+ /** The style of a slider: the rail, the track with its fill, and the thumb. */
35
+ /** The style of a slider: the rail, the track with its fill, and the thumb. */
36
+ const SLIDER_STYLE = `
37
+ :host { display: block; }
38
+ :host([hidden]) { display: none; }
39
+ [part~="slider"] {
40
+ position: relative;
41
+ height: 40px;
42
+ border-radius: var(--mbx-radius);
43
+ cursor: pointer;
44
+ touch-action: none;
45
+ }
46
+ [part~="slider"]:focus-visible { outline: 2px solid var(--mbx-accent); outline-offset: -2px; }
47
+ [part~="rail"] { position: absolute; top: 0; bottom: 0; left: 8px; right: 8px; }
48
+ [part~="track"] {
49
+ position: absolute;
50
+ top: 50%;
51
+ left: 0;
52
+ right: 0;
53
+ height: 4px;
54
+ transform: translateY(-50%);
55
+ background: rgba(255, 255, 255, 0.35);
56
+ border-radius: 2px;
57
+ overflow: hidden;
58
+ }
59
+ [part~="fill"] { position: absolute; top: 0; bottom: 0; left: 0; background: var(--mbx-accent); }
60
+ [part~="thumb"] {
61
+ position: absolute;
62
+ top: 50%;
63
+ width: 12px;
64
+ height: 12px;
65
+ margin: -6px 0 0 -6px;
66
+ border-radius: 50%;
67
+ background: var(--mbx-text);
68
+ pointer-events: none;
69
+ }
70
+ `;
71
+ /** A `<style>` with `text`, for a shadow root. */
72
+ function style(text) {
73
+ const node = document.createElement("style");
74
+ node.textContent = text;
75
+ return node;
76
+ }
77
+ /**
78
+ * A named slot per state with the default glyph as its fallback, so a page
79
+ * drops its own SVG into `slot="icon-<state>"` and the button keeps the
80
+ * name. Returns the slots by state; `show` hides all but one.
81
+ */
82
+ function iconSlots(states, fallback) {
83
+ const out = {};
84
+ for (const state of states) {
85
+ const slot = document.createElement("slot");
86
+ slot.name = `icon-${state}`;
87
+ slot.append(fallback(state));
88
+ slot.hidden = true;
89
+ out[state] = slot;
90
+ }
91
+ return out;
92
+ }
93
+ function show(slots, state) {
94
+ for (const key of Object.keys(slots)) slots[key].hidden = key !== state;
95
+ }
96
+ /** An element with its part names, and its text when it has any. */
97
+ function el(tag, part, text) {
98
+ const node = document.createElement(tag);
99
+ node.setAttribute("part", part);
100
+ if (text !== void 0) node.textContent = text;
101
+ return node;
102
+ }
103
+ function fill(template, values) {
104
+ return template.replace(/\{(\w+)\}/g, (match, name) => {
105
+ const value = values[name];
106
+ return value === void 0 ? match : String(value);
107
+ });
108
+ }
109
+ function pad(n) {
110
+ return n < 10 ? `0${n}` : `${n}`;
111
+ }
112
+ /** `m:ss`, or `h:mm:ss` from an hour up. Anything not a finite positive number reads as zero. */
113
+ function format(seconds) {
114
+ const total = Number.isFinite(seconds) && seconds > 0 ? Math.floor(seconds) : 0;
115
+ const hours = Math.floor(total / 3600);
116
+ const minutes = Math.floor(total % 3600 / 60);
117
+ const rest = total % 60;
118
+ return hours > 0 ? `${hours}:${pad(minutes)}:${pad(rest)}` : `${minutes}:${pad(rest)}`;
119
+ }
120
+ /** What a screen reader hears for a position: "1:23 of 4:56", or the position alone when the duration is unknown or infinite. */
121
+ function describe(current, duration) {
122
+ return Number.isFinite(duration) ? `${format(current)} of ${format(duration)}` : format(current);
123
+ }
124
+ //#endregion
125
+ export { BUTTON_STYLE, SLIDER_STYLE, describe, el, fill, format, iconSlots, show, style };
@@ -0,0 +1,154 @@
1
+ import { el } from "./shared.js";
2
+ //#region src/slider.ts
3
+ /**
4
+ * The slider primitive, copied from the player's, which exports none: a
5
+ * `div` with
6
+ * `role="slider"`, pointer capture for the drag, and the arrow keys. It
7
+ * owns geometry only. What the value means and what happens on change is
8
+ * the caller's, through `onInput`.
9
+ *
10
+ * Not `<input type="range">`: a range input cannot carry layers such as
11
+ * buffered ranges, its geometry is not readable for a preview anchor, and
12
+ * it renders differently per browser. The track is exposed so a caller can
13
+ * lay its own layers on it.
14
+ *
15
+ * The track and the thumb sit on a rail inset from the root's edges by half
16
+ * a thumb, so the thumb at either end is whole and not clipped, and every
17
+ * fraction is measured against the rail.
18
+ *
19
+ * The steps are read on every key, so an element can take them from its
20
+ * attributes as they change.
21
+ *
22
+ * A drag ends on `pointerup`, and also on a move that reports no button
23
+ * held: the button went up where no `pointerup` reached the slider, such
24
+ * as outside the window, and the thumb must not stay on the pointer. A
25
+ * lost capture ends it too.
26
+ */
27
+ function clamp(value, min, max) {
28
+ return Math.min(max, Math.max(min, value));
29
+ }
30
+ function slider(options) {
31
+ const { onInput } = options;
32
+ const root = el("div", "slider");
33
+ root.setAttribute("role", "slider");
34
+ root.tabIndex = 0;
35
+ const rail = el("div", "rail");
36
+ const track = el("div", "track");
37
+ const fill = el("div", "fill");
38
+ const thumb = el("div", "thumb");
39
+ track.append(fill);
40
+ rail.append(track, thumb);
41
+ root.append(rail);
42
+ let min = 0;
43
+ let max = 1;
44
+ let value = 0;
45
+ let held = false;
46
+ function paint() {
47
+ const percent = `${(max > min ? (value - min) / (max - min) : 0) * 100}%`;
48
+ fill.style.width = percent;
49
+ thumb.style.left = percent;
50
+ }
51
+ /** The value under a horizontal pointer position. */
52
+ function at(clientX) {
53
+ const rect = rail.getBoundingClientRect();
54
+ if (rect.width === 0) return min;
55
+ return min + clamp((clientX - rect.left) / rect.width, 0, 1) * (max - min);
56
+ }
57
+ function hold(on) {
58
+ held = on;
59
+ options.onDrag(on);
60
+ }
61
+ function down(event) {
62
+ if (event.button !== 0) return;
63
+ event.preventDefault();
64
+ hold(true);
65
+ try {
66
+ root.setPointerCapture(event.pointerId);
67
+ } catch (_unused) {}
68
+ onInput(at(event.clientX));
69
+ }
70
+ function move(event) {
71
+ if (!held) return;
72
+ if (event.buttons === 0) {
73
+ up(event);
74
+ return;
75
+ }
76
+ onInput(at(event.clientX));
77
+ }
78
+ function up(event) {
79
+ if (!held) return;
80
+ hold(false);
81
+ onInput(at(event.clientX));
82
+ }
83
+ function cancel() {
84
+ if (held) hold(false);
85
+ }
86
+ function key(event) {
87
+ let next;
88
+ switch (event.key) {
89
+ case "ArrowRight":
90
+ case "ArrowUp":
91
+ next = value + options.step();
92
+ break;
93
+ case "ArrowLeft":
94
+ case "ArrowDown":
95
+ next = value - options.step();
96
+ break;
97
+ case "PageUp":
98
+ next = value + options.page();
99
+ break;
100
+ case "PageDown":
101
+ next = value - options.page();
102
+ break;
103
+ case "Home":
104
+ next = min;
105
+ break;
106
+ case "End":
107
+ next = max;
108
+ break;
109
+ default: return;
110
+ }
111
+ event.preventDefault();
112
+ onInput(clamp(next, min, max));
113
+ }
114
+ root.addEventListener("pointerdown", down);
115
+ root.addEventListener("pointermove", move);
116
+ root.addEventListener("pointerup", up);
117
+ root.addEventListener("pointercancel", cancel);
118
+ root.addEventListener("lostpointercapture", cancel);
119
+ root.addEventListener("keydown", key);
120
+ return {
121
+ root,
122
+ track,
123
+ rail,
124
+ label(text) {
125
+ root.setAttribute("aria-label", text);
126
+ },
127
+ dragging() {
128
+ return held;
129
+ },
130
+ range(low, high) {
131
+ min = low;
132
+ max = high;
133
+ root.setAttribute("aria-valuemin", String(low));
134
+ root.setAttribute("aria-valuemax", String(high));
135
+ paint();
136
+ },
137
+ set(next, text) {
138
+ value = clamp(next, min, max);
139
+ root.setAttribute("aria-valuenow", String(value));
140
+ root.setAttribute("aria-valuetext", text);
141
+ paint();
142
+ },
143
+ dispose() {
144
+ root.removeEventListener("pointerdown", down);
145
+ root.removeEventListener("pointermove", move);
146
+ root.removeEventListener("pointerup", up);
147
+ root.removeEventListener("pointercancel", cancel);
148
+ root.removeEventListener("lostpointercapture", cancel);
149
+ root.removeEventListener("keydown", key);
150
+ }
151
+ };
152
+ }
153
+ //#endregion
154
+ export { slider };
package/dist/host.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The contract of a control of the page's own, as guide chapter 03 of the
3
+ * player states it: the nearest <mattebox-player> above, through shadow
4
+ * hosts, then read for `video`, `engine`, `player` and `error`, with
5
+ * `sourcechange` heard on it. This package implements the contract from
6
+ * outside, on purpose: the player exports no base class, and a control that
7
+ * needs more than this surface has found a gap in the player's API.
8
+ */
9
+ import type { PlayerHost } from '@mattebox/player';
10
+ export type { PlayerHost };
11
+ export declare const PLAYER = "mattebox-player";
12
+ /** The nearest player above `node`, or null outside one. It may not be upgraded yet. */
13
+ export declare function findPlayer(node: Node): HTMLElement | null;
14
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,eAAO,MAAM,MAAM,oBAAoB,CAAC;AASxC,wFAAwF;AACxF,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,IAAI,CAOzD"}
package/dist/host.js ADDED
@@ -0,0 +1,19 @@
1
+ export const PLAYER = 'mattebox-player';
2
+ /** The parent, or the host of the shadow root `node` sits in, or null at the document. */
3
+ function above(node) {
4
+ const parent = node.parentNode;
5
+ if (parent !== null)
6
+ return parent;
7
+ return node instanceof ShadowRoot ? node.host : null;
8
+ }
9
+ /** The nearest player above `node`, or null outside one. It may not be upgraded yet. */
10
+ export function findPlayer(node) {
11
+ let current = node;
12
+ while (current !== null) {
13
+ if (current instanceof HTMLElement && current.localName === PLAYER)
14
+ return current;
15
+ current = above(current);
16
+ }
17
+ return null;
18
+ }
19
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,MAAM,GAAG,iBAAiB,CAAC;AAExC,0FAA0F;AAC1F,SAAS,KAAK,CAAC,IAAU;IACvB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;IAC/B,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACnC,OAAO,IAAI,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACvD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,UAAU,CAAC,IAAU;IACnC,IAAI,OAAO,GAAgB,IAAI,CAAC;IAChC,OAAO,OAAO,KAAK,IAAI,EAAE,CAAC;QACxB,IAAI,OAAO,YAAY,WAAW,IAAI,OAAO,CAAC,SAAS,KAAK,MAAM;YAAE,OAAO,OAAO,CAAC;QACnF,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The play and pause glyphs, copied from Vidstack's media-icons 0.10.0
3
+ * (https://github.com/vidstack/media-icons): filled paths on a 32-unit
4
+ * viewBox, drawn for a control bar, one visual weight across the set.
5
+ * Copied, not depended on. The notice below is the license's one condition,
6
+ * and packages/player/NOTICE repeats it for the published tarball.
7
+ *
8
+ * MIT License
9
+ *
10
+ * Copyright (c) 2023 Rahim Alwer
11
+ *
12
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ * of this software and associated documentation files (the "Software"), to deal
14
+ * in the Software without restriction, including without limitation the rights
15
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ * copies of the Software, and to permit persons to whom the Software is
17
+ * furnished to do so, subject to the following conditions:
18
+ *
19
+ * The above copyright notice and this permission notice shall be included in all
20
+ * copies or substantial portions of the Software.
21
+ *
22
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ * SOFTWARE.
29
+ */
30
+ export type IconName = 'play' | 'pause' | 'cast' | 'cast-active';
31
+ /** A glyph, hidden from the accessibility tree: the button it sits in carries the name. */
32
+ export declare function icon(name: IconName): SVGSVGElement;
33
+ //# sourceMappingURL=icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC;AAgBjE,2FAA2F;AAC3F,wBAAgB,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,aAAa,CAUlD"}
package/dist/icons.js ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The play and pause glyphs, copied from Vidstack's media-icons 0.10.0
3
+ * (https://github.com/vidstack/media-icons): filled paths on a 32-unit
4
+ * viewBox, drawn for a control bar, one visual weight across the set.
5
+ * Copied, not depended on. The notice below is the license's one condition,
6
+ * and packages/player/NOTICE repeats it for the published tarball.
7
+ *
8
+ * MIT License
9
+ *
10
+ * Copyright (c) 2023 Rahim Alwer
11
+ *
12
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ * of this software and associated documentation files (the "Software"), to deal
14
+ * in the Software without restriction, including without limitation the rights
15
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ * copies of the Software, and to permit persons to whom the Software is
17
+ * furnished to do so, subject to the following conditions:
18
+ *
19
+ * The above copyright notice and this permission notice shall be included in all
20
+ * copies or substantial portions of the Software.
21
+ *
22
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ * SOFTWARE.
29
+ */
30
+ /** Each glyph's subpaths joined into one `d`, drawn even-odd like the player's. */
31
+ const PATHS = {
32
+ play: 'M10.6667 6.6548C10.6667 6.10764 11.2894 5.79346 11.7295 6.11862L24.377 15.4634C24.7377 15.7298 24.7377 16.2692 24.3771 16.5357L11.7295 25.8813C11.2895 26.2065 10.6667 25.8923 10.6667 25.3451L10.6667 6.6548Z',
33
+ pause: 'M8.66667 6.66667C8.29848 6.66667 8 6.96514 8 7.33333V24.6667C8 25.0349 8.29848 25.3333 8.66667 25.3333H12.6667C13.0349 25.3333 13.3333 25.0349 13.3333 24.6667V7.33333C13.3333 6.96514 13.0349 6.66667 12.6667 6.66667H8.66667Z M19.3333 6.66667C18.9651 6.66667 18.6667 6.96514 18.6667 7.33333V24.6667C18.6667 25.0349 18.9651 25.3333 19.3333 25.3333H23.3333C23.7015 25.3333 24 25.0349 24 24.6667V7.33333C24 6.96514 23.7015 6.66667 23.3333 6.66667H19.3333Z',
34
+ // The cast glyphs are this package's own drawing, not media-icons: a
35
+ // screen with the corner open for three arcs, filled while casting.
36
+ cast: 'M4 6h24v18H20v-2h6V8H6v1H4V6zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z',
37
+ 'cast-active': 'M4 6h24v18H20A16 16 0 0 0 4 8zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z',
38
+ };
39
+ const SVG = 'http://www.w3.org/2000/svg';
40
+ /** A glyph, hidden from the accessibility tree: the button it sits in carries the name. */
41
+ export function icon(name) {
42
+ const svg = document.createElementNS(SVG, 'svg');
43
+ svg.setAttribute('viewBox', '0 0 32 32');
44
+ svg.setAttribute('aria-hidden', 'true');
45
+ svg.setAttribute('part', 'icon');
46
+ const path = document.createElementNS(SVG, 'path');
47
+ path.setAttribute('fill-rule', 'evenodd');
48
+ path.setAttribute('d', PATHS[name]);
49
+ svg.append(path);
50
+ return svg;
51
+ }
52
+ //# sourceMappingURL=icons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.js","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,mFAAmF;AACnF,MAAM,KAAK,GAAuC;IAChD,IAAI,EAAE,gNAAgN;IACtN,KAAK,EACH,ocAAoc;IACtc,qEAAqE;IACrE,oEAAoE;IACpE,IAAI,EAAE,sIAAsI;IAC5I,aAAa,EACX,uIAAuI;CAC1I,CAAC;AAEF,MAAM,GAAG,GAAG,4BAA4B,CAAC;AAEzC,2FAA2F;AAC3F,MAAM,UAAU,IAAI,CAAC,IAAc;IACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACjD,GAAG,CAAC,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACzC,GAAG,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACxC,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC1C,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACpC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjB,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @mattebox/player-cast: <mbx-cast-button> and <mbx-cast-screen>, Chromecast
3
+ * from the player over Google's sender SDK. Importing this module registers
4
+ * both elements; that is the package's one side effect. It is a package of
5
+ * its own because the button loads Google's script onto the page, which the
6
+ * player never does on an integrator's behalf: the AirPlay button, over
7
+ * Safari's own API, ships with the player.
8
+ */
9
+ import { MbxCastButton } from './cast-button.js';
10
+ import { MbxCastScreen } from './cast-screen.js';
11
+ export type { CastState, LoadRequest as CastLoadRequest, MediaInfo, Track } from './cast.js';
12
+ export { MbxCastButton } from './cast-button.js';
13
+ export { MbxCastScreen } from './cast-screen.js';
14
+ export declare const CAST_BUTTON = "mbx-cast-button";
15
+ export declare const CAST_SCREEN = "mbx-cast-screen";
16
+ declare global {
17
+ interface HTMLElementTagNameMap {
18
+ 'mbx-cast-button': MbxCastButton;
19
+ 'mbx-cast-screen': MbxCastScreen;
20
+ }
21
+ }
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,YAAY,EAAE,SAAS,EAAE,WAAW,IAAI,eAAe,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAC7C,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAS7C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,aAAa,CAAC;QACjC,iBAAiB,EAAE,aAAa,CAAC;KAClC;CACF"}
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @mattebox/player-cast: <mbx-cast-button> and <mbx-cast-screen>, Chromecast
3
+ * from the player over Google's sender SDK. Importing this module registers
4
+ * both elements; that is the package's one side effect. It is a package of
5
+ * its own because the button loads Google's script onto the page, which the
6
+ * player never does on an integrator's behalf: the AirPlay button, over
7
+ * Safari's own API, ships with the player.
8
+ */
9
+ import { MbxCastButton } from './cast-button.js';
10
+ import { MbxCastScreen } from './cast-screen.js';
11
+ export { MbxCastButton } from './cast-button.js';
12
+ export { MbxCastScreen } from './cast-screen.js';
13
+ export const CAST_BUTTON = 'mbx-cast-button';
14
+ export const CAST_SCREEN = 'mbx-cast-screen';
15
+ if (customElements.get(CAST_BUTTON) === undefined) {
16
+ customElements.define(CAST_BUTTON, MbxCastButton);
17
+ }
18
+ if (customElements.get(CAST_SCREEN) === undefined) {
19
+ customElements.define(CAST_SCREEN, MbxCastScreen);
20
+ }
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAC7C,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAE7C,IAAI,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,SAAS,EAAE,CAAC;IAClD,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;AACpD,CAAC;AACD,IAAI,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,SAAS,EAAE,CAAC;IAClD,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The styles and helpers the two elements share, copied from the player:
3
+ * the button and slider styles, the glyph slots, the part helper, the label
4
+ * template, and the time format. The player exports none of them, on
5
+ * purpose: a control of the page's own carries its own, and so does this
6
+ * package. The tokens come through the `--mbx-*` custom properties the
7
+ * player sets, which inherit into every control.
8
+ */
9
+ export declare const BUTTON_STYLE = "\n:host { display: inline-flex; }\n:host([hidden]) { display: none; }\n[part~=\"button\"] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 40px;\n height: 40px;\n padding: 0;\n font: inherit;\n color: inherit;\n background: transparent;\n border: 0;\n border-radius: var(--mbx-radius);\n cursor: pointer;\n opacity: 0.9;\n}\n[part~=\"button\"]:hover { opacity: 1; }\n[part~=\"button\"]:focus-visible { outline: 2px solid var(--mbx-accent); outline-offset: -2px; }\n[part~=\"icon\"], ::slotted(*) { width: 1.75em; height: 1.75em; fill: currentColor; }\nslot[hidden] { display: none; }\n";
10
+ /** The style of a slider: the rail, the track with its fill, and the thumb. */
11
+ /** The style of a slider: the rail, the track with its fill, and the thumb. */
12
+ export declare const SLIDER_STYLE = "\n:host { display: block; }\n:host([hidden]) { display: none; }\n[part~=\"slider\"] {\n position: relative;\n height: 40px;\n border-radius: var(--mbx-radius);\n cursor: pointer;\n touch-action: none;\n}\n[part~=\"slider\"]:focus-visible { outline: 2px solid var(--mbx-accent); outline-offset: -2px; }\n[part~=\"rail\"] { position: absolute; top: 0; bottom: 0; left: 8px; right: 8px; }\n[part~=\"track\"] {\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 4px;\n transform: translateY(-50%);\n background: rgba(255, 255, 255, 0.35);\n border-radius: 2px;\n overflow: hidden;\n}\n[part~=\"fill\"] { position: absolute; top: 0; bottom: 0; left: 0; background: var(--mbx-accent); }\n[part~=\"thumb\"] {\n position: absolute;\n top: 50%;\n width: 12px;\n height: 12px;\n margin: -6px 0 0 -6px;\n border-radius: 50%;\n background: var(--mbx-text);\n pointer-events: none;\n}\n";
13
+ /** A `<style>` with `text`, for a shadow root. */
14
+ export declare function style(text: string): HTMLStyleElement;
15
+ /**
16
+ * A named slot per state with the default glyph as its fallback, so a page
17
+ * drops its own SVG into `slot="icon-<state>"` and the button keeps the
18
+ * name. Returns the slots by state; `show` hides all but one.
19
+ */
20
+ export declare function iconSlots<S extends string>(states: readonly S[], fallback: (state: S) => SVGSVGElement): Record<S, HTMLSlotElement>;
21
+ export declare function show<S extends string>(slots: Record<S, HTMLSlotElement>, state: S): void;
22
+ /** An element with its part names, and its text when it has any. */
23
+ export declare function el<K extends keyof HTMLElementTagNameMap>(tag: K, part: string, text?: string): HTMLElementTagNameMap[K];
24
+ export declare function fill(template: string, values: Readonly<Record<string, string | number>>): string;
25
+ /** `m:ss`, or `h:mm:ss` from an hour up. Anything not a finite positive number reads as zero. */
26
+ export declare function format(seconds: number): string;
27
+ /** What a screen reader hears for a position: "1:23 of 4:56", or the position alone when the duration is unknown or infinite. */
28
+ export declare function describe(current: number, duration: number): string;
29
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,YAAY,8oBAuBxB,CAAC;AAEF,+EAA+E;AAE/E,+EAA+E;AAC/E,eAAO,MAAM,YAAY,o5BAkCxB,CAAC;AAEF,kDAAkD;AAClD,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAIpD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EACxC,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,aAAa,GACpC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAU5B;AAED,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAExF;AAED,oEAAoE;AACpE,wBAAgB,EAAE,CAAC,CAAC,SAAS,MAAM,qBAAqB,EACtD,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,GACZ,qBAAqB,CAAC,CAAC,CAAC,CAK1B;AAED,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAKhG;AAMD,iGAAiG;AACjG,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,iIAAiI;AACjI,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAElE"}
package/dist/shared.js ADDED
@@ -0,0 +1,125 @@
1
+ /**
2
+ * The styles and helpers the two elements share, copied from the player:
3
+ * the button and slider styles, the glyph slots, the part helper, the label
4
+ * template, and the time format. The player exports none of them, on
5
+ * purpose: a control of the page's own carries its own, and so does this
6
+ * package. The tokens come through the `--mbx-*` custom properties the
7
+ * player sets, which inherit into every control.
8
+ */
9
+ export const BUTTON_STYLE = `
10
+ :host { display: inline-flex; }
11
+ :host([hidden]) { display: none; }
12
+ [part~="button"] {
13
+ display: inline-flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ flex: none;
17
+ width: 40px;
18
+ height: 40px;
19
+ padding: 0;
20
+ font: inherit;
21
+ color: inherit;
22
+ background: transparent;
23
+ border: 0;
24
+ border-radius: var(--mbx-radius);
25
+ cursor: pointer;
26
+ opacity: 0.9;
27
+ }
28
+ [part~="button"]:hover { opacity: 1; }
29
+ [part~="button"]:focus-visible { outline: 2px solid var(--mbx-accent); outline-offset: -2px; }
30
+ [part~="icon"], ::slotted(*) { width: 1.75em; height: 1.75em; fill: currentColor; }
31
+ slot[hidden] { display: none; }
32
+ `;
33
+ /** The style of a slider: the rail, the track with its fill, and the thumb. */
34
+ /** The style of a slider: the rail, the track with its fill, and the thumb. */
35
+ export const SLIDER_STYLE = `
36
+ :host { display: block; }
37
+ :host([hidden]) { display: none; }
38
+ [part~="slider"] {
39
+ position: relative;
40
+ height: 40px;
41
+ border-radius: var(--mbx-radius);
42
+ cursor: pointer;
43
+ touch-action: none;
44
+ }
45
+ [part~="slider"]:focus-visible { outline: 2px solid var(--mbx-accent); outline-offset: -2px; }
46
+ [part~="rail"] { position: absolute; top: 0; bottom: 0; left: 8px; right: 8px; }
47
+ [part~="track"] {
48
+ position: absolute;
49
+ top: 50%;
50
+ left: 0;
51
+ right: 0;
52
+ height: 4px;
53
+ transform: translateY(-50%);
54
+ background: rgba(255, 255, 255, 0.35);
55
+ border-radius: 2px;
56
+ overflow: hidden;
57
+ }
58
+ [part~="fill"] { position: absolute; top: 0; bottom: 0; left: 0; background: var(--mbx-accent); }
59
+ [part~="thumb"] {
60
+ position: absolute;
61
+ top: 50%;
62
+ width: 12px;
63
+ height: 12px;
64
+ margin: -6px 0 0 -6px;
65
+ border-radius: 50%;
66
+ background: var(--mbx-text);
67
+ pointer-events: none;
68
+ }
69
+ `;
70
+ /** A `<style>` with `text`, for a shadow root. */
71
+ export function style(text) {
72
+ const node = document.createElement('style');
73
+ node.textContent = text;
74
+ return node;
75
+ }
76
+ /**
77
+ * A named slot per state with the default glyph as its fallback, so a page
78
+ * drops its own SVG into `slot="icon-<state>"` and the button keeps the
79
+ * name. Returns the slots by state; `show` hides all but one.
80
+ */
81
+ export function iconSlots(states, fallback) {
82
+ const out = {};
83
+ for (const state of states) {
84
+ const slot = document.createElement('slot');
85
+ slot.name = `icon-${state}`;
86
+ slot.append(fallback(state));
87
+ slot.hidden = true;
88
+ out[state] = slot;
89
+ }
90
+ return out;
91
+ }
92
+ export function show(slots, state) {
93
+ for (const key of Object.keys(slots))
94
+ slots[key].hidden = key !== state;
95
+ }
96
+ /** An element with its part names, and its text when it has any. */
97
+ export function el(tag, part, text) {
98
+ const node = document.createElement(tag);
99
+ node.setAttribute('part', part);
100
+ if (text !== undefined)
101
+ node.textContent = text;
102
+ return node;
103
+ }
104
+ export function fill(template, values) {
105
+ return template.replace(/\{(\w+)\}/g, (match, name) => {
106
+ const value = values[name];
107
+ return value === undefined ? match : String(value);
108
+ });
109
+ }
110
+ function pad(n) {
111
+ return n < 10 ? `0${n}` : `${n}`;
112
+ }
113
+ /** `m:ss`, or `h:mm:ss` from an hour up. Anything not a finite positive number reads as zero. */
114
+ export function format(seconds) {
115
+ const total = Number.isFinite(seconds) && seconds > 0 ? Math.floor(seconds) : 0;
116
+ const hours = Math.floor(total / 3600);
117
+ const minutes = Math.floor((total % 3600) / 60);
118
+ const rest = total % 60;
119
+ return hours > 0 ? `${hours}:${pad(minutes)}:${pad(rest)}` : `${minutes}:${pad(rest)}`;
120
+ }
121
+ /** What a screen reader hears for a position: "1:23 of 4:56", or the position alone when the duration is unknown or infinite. */
122
+ export function describe(current, duration) {
123
+ return Number.isFinite(duration) ? `${format(current)} of ${format(duration)}` : format(current);
124
+ }
125
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"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"}