Skip to content

Commit 7fd4b45

Browse files
sampottscursoragent
andcommitted
feat(core): add scheduleTransitionSettle for menu viewport sync
Introduce the helper alongside menu viewport sizing so the transition lifecycle PR stays focused on createTransition while viewport code can wait for layout and animation settle. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 21f35a9 commit 7fd4b45

1 file changed

Lines changed: 52 additions & 1 deletion

File tree

packages/core/src/dom/ui/transition.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createState, type State } from '@videojs/store';
2-
import { getMaxCSSTransitionTime } from '@videojs/utils/dom';
2+
import { afterDoubleAnimationFrame, getMaxCSSTransitionTime } from '@videojs/utils/dom';
33
import { noop } from '@videojs/utils/function';
44
import type { TransitionState } from '../../core/ui/transition';
55

@@ -16,6 +16,57 @@ export interface WaitForAnimationsOptions {
1616
includeCSSTransitions?: boolean;
1717
}
1818

19+
export interface ScheduleTransitionSettleOptions {
20+
includeCSSTransitions?: boolean;
21+
isVisuallyComplete?: (element: HTMLElement) => boolean;
22+
}
23+
24+
/** After double-RAF, optionally poll visual completion, then wait for animations to settle. */
25+
export function scheduleTransitionSettle(
26+
element: HTMLElement,
27+
isCurrent: () => boolean,
28+
onSettled: () => void,
29+
options: ScheduleTransitionSettleOptions = {}
30+
): () => void {
31+
let pollRaf = 0;
32+
let settled = false;
33+
34+
function settle(): void {
35+
if (settled || !isCurrent()) return;
36+
settled = true;
37+
cancelAnimationFrame(pollRaf);
38+
pollRaf = 0;
39+
onSettled();
40+
}
41+
42+
function pollVisualComplete(): void {
43+
pollRaf = 0;
44+
if (settled || !isCurrent()) return;
45+
46+
if (options.isVisuallyComplete?.(element)) {
47+
settle();
48+
return;
49+
}
50+
51+
pollRaf = requestAnimationFrame(pollVisualComplete);
52+
}
53+
54+
afterDoubleAnimationFrame(isCurrent, () => {
55+
pollVisualComplete();
56+
57+
waitForAnimations(element, {
58+
includeCSSTransitions: options.includeCSSTransitions ?? false,
59+
}).then(() => {
60+
settle();
61+
});
62+
});
63+
64+
return () => {
65+
settled = true;
66+
cancelAnimationFrame(pollRaf);
67+
};
68+
}
69+
1970
/**
2071
* Manages open/close transition lifecycle via `createState`.
2172
*

0 commit comments

Comments
 (0)