mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
fix(studio): a host that swaps its multi-clip trim handler gets the new one (#4630)
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { act } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { TimelineEditCallbacks } from "../player/components/timelineCallbacks";
|
||||
import { TimelineEditProvider, useTimelineEditContext } from "./TimelineEditContext";
|
||||
|
||||
(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
function mountProvider() {
|
||||
const seen: TimelineEditCallbacks[] = [];
|
||||
function Consumer() {
|
||||
seen.push(useTimelineEditContext());
|
||||
return null;
|
||||
}
|
||||
const root = createRoot(document.createElement("div"));
|
||||
const render = (value: TimelineEditCallbacks) =>
|
||||
act(() =>
|
||||
root.render(
|
||||
<TimelineEditProvider value={value}>
|
||||
<Consumer />
|
||||
</TimelineEditProvider>,
|
||||
),
|
||||
);
|
||||
return { seen, render, unmount: () => act(() => root.unmount()) };
|
||||
}
|
||||
|
||||
describe("TimelineEditProvider", () => {
|
||||
it("hands consumers the latest multi-clip resize callback", () => {
|
||||
const { seen, render, unmount } = mountProvider();
|
||||
const onMoveElement = vi.fn();
|
||||
const staleResize = vi.fn();
|
||||
const currentResize = vi.fn();
|
||||
render({ onMoveElement, onResizeElements: staleResize });
|
||||
render({ onMoveElement, onResizeElements: currentResize });
|
||||
expect(seen.at(-1)!.onResizeElements).toBe(currentResize);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it("keeps the same bag when the parent passes the same callbacks in a new object", () => {
|
||||
const { seen, render, unmount } = mountProvider();
|
||||
const onMoveElement = vi.fn();
|
||||
const onResizeElements = vi.fn();
|
||||
render({ onMoveElement, onResizeElements });
|
||||
render({ onMoveElement, onResizeElements });
|
||||
expect(seen.at(-1)).toBe(seen[0]);
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
@@ -25,6 +25,32 @@ export function useTimelineEditContextValue(): TimelineEditCallbacks | null {
|
||||
return useContext(TimelineEditContext);
|
||||
}
|
||||
|
||||
const EDIT_CALLBACK_KEY_SET: Record<keyof TimelineEditCallbacks, true> = {
|
||||
onMoveElement: true,
|
||||
onMoveElements: true,
|
||||
onResizeElement: true,
|
||||
onResizeElements: true,
|
||||
onToggleTrackHidden: true,
|
||||
onSetAudioGroupAttributeLive: true,
|
||||
onSetAudioGroupAttributeQuiet: true,
|
||||
onRevertAudioGroupAttributeLive: true,
|
||||
onGroupClips: true,
|
||||
onSetElementAttributeLive: true,
|
||||
onSetElementAttributeQuiet: true,
|
||||
onRevertElementAttributeLive: true,
|
||||
onBlockedEditAttempt: true,
|
||||
onSplitElement: true,
|
||||
onRazorSplit: true,
|
||||
onRazorSplitAll: true,
|
||||
onDeleteKeyframe: true,
|
||||
onDeleteAllKeyframes: true,
|
||||
onMoveKeyframeToPlayhead: true,
|
||||
onMoveKeyframe: true,
|
||||
onToggleKeyframeAtPlayhead: true,
|
||||
onTogglePropertyGroupKeyframe: true,
|
||||
};
|
||||
const EDIT_CALLBACK_KEYS = Object.keys(EDIT_CALLBACK_KEY_SET) as (keyof TimelineEditCallbacks)[];
|
||||
|
||||
export function TimelineEditProvider({
|
||||
value,
|
||||
children,
|
||||
@@ -37,29 +63,7 @@ export function TimelineEditProvider({
|
||||
// Each callback is a stable reference from the parent — memoize the bag
|
||||
// so consumers don't re-render when unrelated parent state changes.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[
|
||||
value.onMoveElement,
|
||||
value.onMoveElements,
|
||||
value.onResizeElement,
|
||||
value.onToggleTrackHidden,
|
||||
value.onSetAudioGroupAttributeLive,
|
||||
value.onSetAudioGroupAttributeQuiet,
|
||||
value.onRevertAudioGroupAttributeLive,
|
||||
value.onGroupClips,
|
||||
value.onSetElementAttributeLive,
|
||||
value.onSetElementAttributeQuiet,
|
||||
value.onRevertElementAttributeLive,
|
||||
value.onBlockedEditAttempt,
|
||||
value.onSplitElement,
|
||||
value.onRazorSplit,
|
||||
value.onRazorSplitAll,
|
||||
value.onDeleteKeyframe,
|
||||
value.onDeleteAllKeyframes,
|
||||
value.onMoveKeyframeToPlayhead,
|
||||
value.onMoveKeyframe,
|
||||
value.onToggleKeyframeAtPlayhead,
|
||||
value.onTogglePropertyGroupKeyframe,
|
||||
],
|
||||
EDIT_CALLBACK_KEYS.map((key) => value[key]),
|
||||
);
|
||||
return <TimelineEditContext.Provider value={memoized}>{children}</TimelineEditContext.Provider>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user