mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
feat(studio): consolidate timeline editor callbacks
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import React from "react";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { DomEditSelection } from "../components/editor/domEditing";
|
||||
import type { RightInspectorPanes } from "../utils/studioHelpers";
|
||||
import { makeSelection } from "./domSelectionTestHarness";
|
||||
import { useInspectorState, type InspectorState } from "./useStudioContextValue";
|
||||
|
||||
interface HarnessProps {
|
||||
rightPanelTab: string;
|
||||
rightInspectorPanes: RightInspectorPanes;
|
||||
rightCollapsed: boolean;
|
||||
isPlaying: boolean;
|
||||
isGestureRecording: boolean;
|
||||
domEditSelection: DomEditSelection | null;
|
||||
}
|
||||
|
||||
function renderInspectorState(props: HarnessProps): InspectorState {
|
||||
let state: InspectorState | null = null;
|
||||
|
||||
function Harness() {
|
||||
state = useInspectorState(
|
||||
props.rightPanelTab,
|
||||
props.rightInspectorPanes,
|
||||
props.rightCollapsed,
|
||||
props.isPlaying,
|
||||
props.domEditSelection,
|
||||
props.isGestureRecording,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
renderToStaticMarkup(React.createElement(Harness));
|
||||
if (!state) throw new Error("Expected inspector state");
|
||||
return state;
|
||||
}
|
||||
|
||||
function selectedProps(
|
||||
overrides: Partial<HarnessProps> = {},
|
||||
): HarnessProps & { domEditSelection: DomEditSelection } {
|
||||
const element = document.createElement("div");
|
||||
return {
|
||||
rightPanelTab: "renders",
|
||||
rightInspectorPanes: { layers: false, design: false },
|
||||
rightCollapsed: true,
|
||||
isPlaying: false,
|
||||
isGestureRecording: false,
|
||||
domEditSelection: makeSelection("Selected", element),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("useInspectorState", () => {
|
||||
it("shows the motion path for pure selection with the inspector collapsed", () => {
|
||||
expect(renderInspectorState(selectedProps()).shouldShowMotionPath).toBe(true);
|
||||
});
|
||||
|
||||
it("hides the motion path without a selection", () => {
|
||||
expect(
|
||||
renderInspectorState({ ...selectedProps(), domEditSelection: null }).shouldShowMotionPath,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("hides the motion path during playback", () => {
|
||||
expect(renderInspectorState(selectedProps({ isPlaying: true })).shouldShowMotionPath).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it("hides the motion path during gesture recording", () => {
|
||||
expect(
|
||||
renderInspectorState(selectedProps({ isGestureRecording: true })).shouldShowMotionPath,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps selected DOM bounds coupled to the inspector or variables panel", () => {
|
||||
expect(renderInspectorState(selectedProps()).shouldShowSelectedDomBounds).toBe(false);
|
||||
expect(
|
||||
renderInspectorState(
|
||||
selectedProps({
|
||||
rightPanelTab: "design",
|
||||
rightInspectorPanes: { layers: false, design: true },
|
||||
}),
|
||||
).shouldShowSelectedDomBounds,
|
||||
).toBe(true);
|
||||
expect(
|
||||
renderInspectorState(selectedProps({ rightPanelTab: "variables" }))
|
||||
.shouldShowSelectedDomBounds,
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useMemo, useRef, useState, type DragEvent } from "react";
|
||||
import { STUDIO_INSPECTOR_PANELS_ENABLED } from "../components/editor/manualEditingAvailability";
|
||||
import type { DomEditSelection } from "../components/editor/domEditing";
|
||||
import type { StudioContextValue } from "../contexts/StudioContext";
|
||||
import type { RightInspectorPanes } from "../utils/studioHelpers";
|
||||
import type { TimelineFileDropHandler } from "./useTimelineEditingTypes";
|
||||
@@ -69,6 +70,7 @@ export interface InspectorState {
|
||||
designPanelActive: boolean;
|
||||
inspectorPanelActive: boolean;
|
||||
inspectorButtonActive: boolean;
|
||||
shouldShowMotionPath: boolean;
|
||||
shouldShowSelectedDomBounds: boolean;
|
||||
}
|
||||
|
||||
@@ -77,6 +79,7 @@ export function useInspectorState(
|
||||
rightInspectorPanes: RightInspectorPanes,
|
||||
rightCollapsed: boolean,
|
||||
isPlaying: boolean,
|
||||
domEditSelection: DomEditSelection | null,
|
||||
isGestureRecording?: boolean,
|
||||
): InspectorState {
|
||||
// fallow-ignore-next-line complexity
|
||||
@@ -93,8 +96,9 @@ export function useInspectorState(
|
||||
inspectorPanelActive,
|
||||
inspectorButtonActive:
|
||||
STUDIO_INSPECTOR_PANELS_ENABLED && !rightCollapsed && inspectorPanelActive,
|
||||
// Keep the selection box + motion path drawn even when the Inspector is
|
||||
// collapsed — closing the panel shouldn't visually deselect the element.
|
||||
shouldShowMotionPath: !!domEditSelection && !isPlaying && !isGestureRecording,
|
||||
// Keep the selection box drawn even when the Inspector is collapsed —
|
||||
// closing the panel shouldn't visually deselect the element.
|
||||
// The Variables tab also works against the canvas selection (bind card),
|
||||
// so the selection outline stays visible there too.
|
||||
shouldShowSelectedDomBounds:
|
||||
@@ -102,7 +106,14 @@ export function useInspectorState(
|
||||
!isPlaying &&
|
||||
!isGestureRecording,
|
||||
};
|
||||
}, [rightPanelTab, rightInspectorPanes, rightCollapsed, isPlaying, isGestureRecording]);
|
||||
}, [
|
||||
rightPanelTab,
|
||||
rightInspectorPanes,
|
||||
rightCollapsed,
|
||||
isPlaying,
|
||||
isGestureRecording,
|
||||
domEditSelection,
|
||||
]);
|
||||
}
|
||||
|
||||
// fallow-ignore-next-line complexity
|
||||
|
||||
Reference in New Issue
Block a user