@f8team/reel-core 1.0.5 → 1.1.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/CHANGELOG.md +35 -0
- package/dist/index.cjs +41 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +40 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @f8team/reel-core
|
|
2
2
|
|
|
3
|
+
## 1.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e6d5243: Stop a replaced source from loading anyway.
|
|
8
|
+
|
|
9
|
+
The YouTube and HLS loaders cleared their `aborted` flag in `detach()`, so a source switch
|
|
10
|
+
(abort, then detach) let an attach that was still waiting for the YouTube or hls.js runtime carry
|
|
11
|
+
on: YouTube mounted a second iframe that stayed in the page, and HLS bound a stale hls.js instance
|
|
12
|
+
to the `<video>`. Each attach now remembers which abort/detach generation it started in and stops
|
|
13
|
+
when a newer one has happened.
|
|
14
|
+
|
|
15
|
+
`<Root>` (React) and `<reel-player>` (Lit) no longer call `setSource` again for the source the
|
|
16
|
+
player was created with in `options.source`. That second call aborted the first load on mount
|
|
17
|
+
(an extra media request) and was how the duplicate YouTube iframe was reached.
|
|
18
|
+
|
|
19
|
+
## 1.1.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- fe0431b: Fix controls that never auto-hide in fullscreen.
|
|
24
|
+
|
|
25
|
+
Entering fullscreen is only possible by hitting the fullscreen control, and the
|
|
26
|
+
pointer focus it leaves behind kept `:focus-within` matching forever, so the
|
|
27
|
+
themes held the controls bar and the mobile transport at full opacity for the
|
|
28
|
+
rest of the session. Reported on Android Chrome and Safari.
|
|
29
|
+
|
|
30
|
+
The idle timer now releases that pointer focus instead of only dropping
|
|
31
|
+
`data-reel-controls-visible`. Keyboard focus and open control menus still keep
|
|
32
|
+
the chrome on screen - the timer re-arms rather than hiding.
|
|
33
|
+
|
|
34
|
+
`@f8team/reel-core` gains `blurFocusInside` and `shouldKeepControlsVisible` so
|
|
35
|
+
the Lit element, the React adapter and app-level players share one auto-hide
|
|
36
|
+
focus contract; `@f8team/reel-react` re-exports both.
|
|
37
|
+
|
|
3
38
|
## 1.0.5
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -400,6 +400,12 @@ var HlsLoader = class {
|
|
|
400
400
|
this.rejectAttach = null;
|
|
401
401
|
this.manifestTimeout = null;
|
|
402
402
|
this.aborted = false;
|
|
403
|
+
/**
|
|
404
|
+
* Bumped by every abort/detach. `detach()` clears `aborted` so the loader can be reused, so a
|
|
405
|
+
* source switch (abort, then detach) used to let an attach that was still awaiting the runtime
|
|
406
|
+
* carry on and bind a stale hls.js instance to the <video>. Each attach keeps its own value.
|
|
407
|
+
*/
|
|
408
|
+
this.generation = 0;
|
|
403
409
|
this.lastLoadingFragmentKey = null;
|
|
404
410
|
this.repeatedFragmentLoadCount = 0;
|
|
405
411
|
this.repeatedFragmentErrorFired = false;
|
|
@@ -418,11 +424,12 @@ var HlsLoader = class {
|
|
|
418
424
|
async attach(video, source) {
|
|
419
425
|
this.detach();
|
|
420
426
|
this.aborted = false;
|
|
427
|
+
const generation = this.generation;
|
|
421
428
|
this.video = video;
|
|
422
429
|
this.currentSource = source;
|
|
423
430
|
this.unauthorizedFired = false;
|
|
424
431
|
const Hls = await (this.options.loadRuntime ?? defaultLoad)();
|
|
425
|
-
if (this.aborted) {
|
|
432
|
+
if (this.aborted || generation !== this.generation) {
|
|
426
433
|
throw makeAbortError();
|
|
427
434
|
}
|
|
428
435
|
if (!Hls.isSupported()) {
|
|
@@ -733,6 +740,7 @@ var HlsLoader = class {
|
|
|
733
740
|
this.abortLiveXhrs();
|
|
734
741
|
}
|
|
735
742
|
abort() {
|
|
743
|
+
this.generation += 1;
|
|
736
744
|
if (this.aborted) return;
|
|
737
745
|
this.aborted = true;
|
|
738
746
|
this.clearManifestTimeout();
|
|
@@ -1066,17 +1074,24 @@ var YouTubeLoader = class {
|
|
|
1066
1074
|
this.duration = 0;
|
|
1067
1075
|
this.rejectAttach = null;
|
|
1068
1076
|
this.aborted = false;
|
|
1077
|
+
/**
|
|
1078
|
+
* Bumped by every abort/detach. `detach()` clears `aborted` so the loader can be reused, so a
|
|
1079
|
+
* source switch (abort, then detach) used to let an attach that was still awaiting the runtime
|
|
1080
|
+
* carry on and mount a second iframe. Each attach keeps the value it started with instead.
|
|
1081
|
+
*/
|
|
1082
|
+
this.generation = 0;
|
|
1069
1083
|
}
|
|
1070
1084
|
async attach(video, source) {
|
|
1071
1085
|
this.detach();
|
|
1072
1086
|
this.aborted = false;
|
|
1087
|
+
const generation = this.generation;
|
|
1073
1088
|
const id = extractYouTubeId(source.src);
|
|
1074
1089
|
if (!id) {
|
|
1075
1090
|
throw new Error(`Cannot extract YouTube videoId from "${source.src}"`);
|
|
1076
1091
|
}
|
|
1077
1092
|
this.video = video;
|
|
1078
1093
|
const YT = await (this.options.loadRuntime ?? defaultLoad2)();
|
|
1079
|
-
if (this.aborted) {
|
|
1094
|
+
if (this.aborted || generation !== this.generation) {
|
|
1080
1095
|
throw makeYtAbortError();
|
|
1081
1096
|
}
|
|
1082
1097
|
const parent = video.parentElement;
|
|
@@ -1172,6 +1187,7 @@ var YouTubeLoader = class {
|
|
|
1172
1187
|
});
|
|
1173
1188
|
}
|
|
1174
1189
|
abort() {
|
|
1190
|
+
this.generation += 1;
|
|
1175
1191
|
if (this.aborted) return;
|
|
1176
1192
|
this.aborted = true;
|
|
1177
1193
|
const reject = this.rejectAttach;
|
|
@@ -2394,6 +2410,27 @@ function createFocusTrap(container) {
|
|
|
2394
2410
|
return { activate, deactivate };
|
|
2395
2411
|
}
|
|
2396
2412
|
|
|
2413
|
+
// src/a11y/controlsFocus.ts
|
|
2414
|
+
var OPEN_MENU_SELECTOR = "[data-reel-menu-open]";
|
|
2415
|
+
function activeElementInside(container) {
|
|
2416
|
+
const active = (container.ownerDocument ?? document).activeElement;
|
|
2417
|
+
if (!(active instanceof HTMLElement)) return null;
|
|
2418
|
+
return container.contains(active) ? active : null;
|
|
2419
|
+
}
|
|
2420
|
+
function blurFocusInside(container) {
|
|
2421
|
+
activeElementInside(container)?.blur();
|
|
2422
|
+
}
|
|
2423
|
+
function shouldKeepControlsVisible(container) {
|
|
2424
|
+
if (container.querySelector(OPEN_MENU_SELECTOR) !== null) return true;
|
|
2425
|
+
const active = activeElementInside(container);
|
|
2426
|
+
if (!active) return false;
|
|
2427
|
+
try {
|
|
2428
|
+
return active.matches(":focus-visible");
|
|
2429
|
+
} catch {
|
|
2430
|
+
return false;
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2397
2434
|
// src/util/time.ts
|
|
2398
2435
|
var TIME_RE = /^(?:(\d+):)?(\d{1,2}):(\d{1,2})(?:\.(\d+))?$/;
|
|
2399
2436
|
function parseTime(input) {
|
|
@@ -2433,6 +2470,7 @@ exports.TOKEN_TO_CSS_VAR = TOKEN_TO_CSS_VAR;
|
|
|
2433
2470
|
exports.announce = announce;
|
|
2434
2471
|
exports.applyTheme = applyTheme;
|
|
2435
2472
|
exports.areSourceDescriptorsEquivalent = areSourceDescriptorsEquivalent;
|
|
2473
|
+
exports.blurFocusInside = blurFocusInside;
|
|
2436
2474
|
exports.createFocusTrap = createFocusTrap;
|
|
2437
2475
|
exports.createPlayer = createPlayer;
|
|
2438
2476
|
exports.definePlugin = definePlugin;
|
|
@@ -2444,6 +2482,7 @@ exports.looksLikeProgressive = looksLikeProgressive;
|
|
|
2444
2482
|
exports.looksLikeYouTube = looksLikeYouTube;
|
|
2445
2483
|
exports.parseTime = parseTime;
|
|
2446
2484
|
exports.resolveTokens = resolveTokens;
|
|
2485
|
+
exports.shouldKeepControlsVisible = shouldKeepControlsVisible;
|
|
2447
2486
|
exports.toSeconds = toSeconds;
|
|
2448
2487
|
//# sourceMappingURL=index.cjs.map
|
|
2449
2488
|
//# sourceMappingURL=index.cjs.map
|