feat(studio): nest the existing 3D transform sub-view in a flat wrapper

This commit is contained in:
Vance Ingalls
2026-07-14 15:50:41 -07:00
parent 3b958aeb77
commit 5edaf6db7a
2 changed files with 95 additions and 0 deletions
@@ -6,6 +6,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
import {
LayoutFlexBlock,
LayoutGeometryRows,
LayoutTransform3DBlock,
LayoutZIndexRow,
} from "./propertyPanelFlatLayoutSection";
@@ -163,3 +164,28 @@ describe("LayoutFlexBlock", () => {
act(() => root.unmount());
});
});
describe("LayoutTransform3DBlock", () => {
it("renders the nested 3D transform sub-view", () => {
const { host, root } = renderInto(
<LayoutTransform3DBlock
gsapRuntimeValues={{}}
gsapAnimId={null}
gsapKeyframes={null}
currentPct={0}
elStart={0}
elDuration={0}
element={{} as never}
onCommitAnimatedProperty={vi.fn()}
onCommitAnimatedProperties={vi.fn()}
onSeekToTime={vi.fn()}
onRemoveKeyframe={vi.fn()}
onConvertToKeyframes={vi.fn()}
/>,
);
// PropertyPanel3dTransform's own internals aren't this task's concern (it's
// reused unmodified) — just confirm the wrapper mounted something.
expect(host.children.length).toBeGreaterThan(0);
act(() => root.unmount());
});
});
@@ -3,6 +3,8 @@ import { KeyframeNavigation } from "./KeyframeNavigation";
import { formatPxMetricValue } from "./propertyPanelHelpers";
import { STUDIO_KEYFRAMES_ENABLED } from "./manualEditingAvailability";
import { resolveValueTier } from "./propertyPanelValueTier";
import { PropertyPanel3dTransform } from "./propertyPanel3dTransform";
import type { DomEditSelection } from "./domEditingTypes";
type KeyframeEntry = Array<{
percentage: number;
@@ -235,3 +237,70 @@ export function LayoutFlexBlock({
</div>
);
}
export function LayoutTransform3DBlock({
gsapRuntimeValues,
gsapAnimId,
resolveAnimIdForProp,
gsapKeyframes,
currentPct,
elStart,
elDuration,
element,
onCommitAnimatedProperty,
onCommitAnimatedProperties,
onSeekToTime,
onRemoveKeyframe,
onConvertToKeyframes,
onLivePreviewProps,
}: {
gsapRuntimeValues: Record<string, number>;
gsapAnimId: string | null;
resolveAnimIdForProp?: (prop: string) => string | null;
gsapKeyframes: Array<{
percentage: number;
properties: Record<string, number | string>;
ease?: string;
}> | null;
currentPct: number;
elStart: number;
elDuration: number;
element: DomEditSelection;
onCommitAnimatedProperty?: (
element: DomEditSelection,
property: string,
value: number,
) => Promise<void>;
onCommitAnimatedProperties?: (
element: DomEditSelection,
props: Record<string, number | string>,
) => Promise<void>;
onSeekToTime?: (time: number) => void;
onRemoveKeyframe?: (animId: string, pct: number) => void;
onConvertToKeyframes?: (animId: string, duration?: number) => void;
onLivePreviewProps?: (element: DomEditSelection, props: Record<string, number>) => void;
}) {
return (
<div className="border-t border-panel-hairline pt-2.5">
<div className="mb-[3px] text-[9px] font-semibold uppercase tracking-[0.12em] text-panel-text-5">
3D Transform
</div>
<PropertyPanel3dTransform
gsapRuntimeValues={gsapRuntimeValues}
gsapAnimId={gsapAnimId}
resolveAnimIdForProp={resolveAnimIdForProp}
gsapKeyframes={gsapKeyframes}
currentPct={currentPct}
elStart={elStart}
elDuration={elDuration}
element={element}
onCommitAnimatedProperty={onCommitAnimatedProperty}
onCommitAnimatedProperties={onCommitAnimatedProperties}
onSeekToTime={onSeekToTime}
onRemoveKeyframe={onRemoveKeyframe}
onConvertToKeyframes={onConvertToKeyframes}
onLivePreviewProps={onLivePreviewProps}
/>
</div>
);
}