mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
111 lines
2.9 KiB
JavaScript
111 lines
2.9 KiB
JavaScript
import { createState } from "@videojs/store";
|
|
import { noop } from "@videojs/utils/function";
|
|
//#region src/dom/ui/transition.ts
|
|
/**
|
|
* Manages open/close transition lifecycle via `createState`.
|
|
*
|
|
* **Open:** patches `{ active: true, status: 'starting' }`, then after a
|
|
* double-RAF patches `{ status: 'idle' }` so the browser paints the
|
|
* initial ("from") state before transitioning. Reopening an active transition
|
|
* flushes styles first so CSS transitions can restart.
|
|
*
|
|
* **Close:** patches `{ status: 'ending' }` (keeping `active: true` so the
|
|
* element stays mounted), then after a double-RAF waits for
|
|
* `getAnimations()` to settle before patching `{ active: false, status: 'idle' }`.
|
|
*/
|
|
function createTransition() {
|
|
const state = createState({
|
|
active: false,
|
|
status: "idle"
|
|
});
|
|
let destroyed = false;
|
|
let rafId1 = 0;
|
|
let rafId2 = 0;
|
|
function open(el = null) {
|
|
cancelAnimationFrame(rafId1);
|
|
cancelAnimationFrame(rafId2);
|
|
rafId1 = 0;
|
|
rafId2 = 0;
|
|
const restarting = state.current.active;
|
|
if (restarting) state.patch({ status: "idle" });
|
|
state.patch({
|
|
active: true,
|
|
status: "starting"
|
|
});
|
|
return new Promise((resolve) => {
|
|
rafId1 = requestAnimationFrame(() => {
|
|
rafId1 = 0;
|
|
if (restarting) {
|
|
cancelAnimations(el);
|
|
flushStyles(el);
|
|
}
|
|
rafId2 = requestAnimationFrame(() => {
|
|
rafId2 = 0;
|
|
if (destroyed || !state.current.active) return resolve();
|
|
state.patch({ status: "idle" });
|
|
resolve();
|
|
});
|
|
});
|
|
});
|
|
}
|
|
function close(el) {
|
|
cancelAnimationFrame(rafId1);
|
|
cancelAnimationFrame(rafId2);
|
|
rafId1 = 0;
|
|
rafId2 = 0;
|
|
state.patch({ status: "ending" });
|
|
return new Promise((resolve) => {
|
|
rafId1 = requestAnimationFrame(() => {
|
|
rafId1 = 0;
|
|
rafId2 = requestAnimationFrame(() => {
|
|
rafId2 = 0;
|
|
if (destroyed) return resolve();
|
|
waitForAnimations(el).finally(() => {
|
|
if (destroyed || state.current.status !== "ending") return resolve();
|
|
state.patch({
|
|
active: false,
|
|
status: "idle"
|
|
});
|
|
resolve();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
function cancel() {
|
|
cancelAnimationFrame(rafId1);
|
|
cancelAnimationFrame(rafId2);
|
|
rafId1 = 0;
|
|
rafId2 = 0;
|
|
if (state.current.status !== "idle") state.patch({ status: "idle" });
|
|
}
|
|
return {
|
|
state,
|
|
open,
|
|
close,
|
|
cancel,
|
|
destroy() {
|
|
if (destroyed) return;
|
|
destroyed = true;
|
|
cancel();
|
|
}
|
|
};
|
|
}
|
|
function flushStyles(el) {
|
|
if (!el) return;
|
|
el.offsetHeight;
|
|
}
|
|
function cancelAnimations(el) {
|
|
const animations = el?.getAnimations?.({ subtree: true }) ?? [];
|
|
for (const animation of animations) animation.cancel();
|
|
}
|
|
function waitForAnimations(el) {
|
|
if (!el) return Promise.resolve();
|
|
const animations = el.getAnimations?.() ?? [];
|
|
if (animations.length === 0) return Promise.resolve();
|
|
return Promise.all(animations.map((a) => a.finished)).then(noop, noop);
|
|
}
|
|
//#endregion
|
|
export { createTransition };
|
|
|
|
//# sourceMappingURL=transition.js.map
|