Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/studio/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export function StudioApp() {
uploadProjectFiles: fileManager.uploadProjectFiles,
isRecordingRef: isGestureRecordingRef,
sdkSession: editFlowSdkSession,
publishSdkSession: sdkHandle.publish,
forceReloadSdkSession: sdkHandle.forceReload,
handleDomZIndexReorderCommitRef,
});
Expand Down Expand Up @@ -317,6 +318,7 @@ export function StudioApp() {
selectSidebarTab: sidebarTabRef.current.select,
getSidebarTab: sidebarTabRef.current.get,
sdkSession: editFlowSdkSession,
publishSdkSession: sdkHandle.publish,
forceReloadSdkSession: sdkHandle.forceReload,
});
domEditSelectionBridgeRef.current = domEditSession.domEditSelection;
Expand Down Expand Up @@ -533,6 +535,7 @@ export function StudioApp() {
recordingDuration={gestureRecording.recordingDuration}
onToggleRecording={recordingToggle}
sdkSession={sdkHandle.session}
publishSdkSession={sdkHandle.publish}
reloadPreview={reloadPreview}
domEditSaveTimestampRef={domEditSaveTimestampRef}
recordEdit={editHistory.recordEdit}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function DesignPanelPromoteProvider({
const persist = useVariablesPersist({
...persistDeps,
sdkSession: handle.session,
publishSdkSession: handle.publish,
activeCompPath: targetPath,
});
return (
Expand Down
5 changes: 5 additions & 0 deletions packages/studio/src/components/StudioRightPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface StudioRightPanelProps {
onToggleRecording?: () => void;
/** Dependencies for the Slideshow persist callback, threaded from App.tsx. */
sdkSession: Composition | null;
publishSdkSession: (session: Composition) => void;
reloadPreview: () => void;
domEditSaveTimestampRef: MutableRefObject<number>;
recordEdit: (entry: {
Expand All @@ -75,6 +76,7 @@ export function StudioRightPanel({
recordingDuration,
onToggleRecording,
sdkSession,
publishSdkSession,
reloadPreview,
domEditSaveTimestampRef,
recordEdit,
Expand Down Expand Up @@ -167,6 +169,7 @@ export function StudioRightPanel({
recordEdit,
reloadPreview,
domEditSaveTimestampRef,
publishSdkSession,
});

// Notes path: persists are debounced in SlideshowPanel; coalesceKey ensures
Expand All @@ -179,6 +182,7 @@ export function StudioRightPanel({
recordEdit,
reloadPreview,
domEditSaveTimestampRef,
publishSdkSession,
coalesceKey: activeCompPath ? `slideshow-notes:${activeCompPath}` : "slideshow-notes",
});

Expand Down Expand Up @@ -534,6 +538,7 @@ export function StudioRightPanel({
) : rightPanelTab === "variables" ? (
<VariablesPanel
sdkSession={sdkSession}
publishSdkSession={publishSdkSession}
reloadPreview={reloadPreview}
domEditSaveTimestampRef={domEditSaveTimestampRef}
recordEdit={recordEdit}
Expand Down
3 changes: 3 additions & 0 deletions packages/studio/src/components/panels/VariablesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ function shellSingleQuote(value: string): string {

interface VariablesPanelProps {
sdkSession: Composition | null;
publishSdkSession: (session: Composition) => void;
reloadPreview: () => void;
domEditSaveTimestampRef: MutableRefObject<number>;
recordEdit: (entry: {
Expand Down Expand Up @@ -247,6 +248,7 @@ const EMPTY_STATE = (
// fallow-ignore-next-line complexity
export const VariablesPanel = memo(function VariablesPanel({
sdkSession,
publishSdkSession,
reloadPreview,
domEditSaveTimestampRef,
recordEdit,
Expand Down Expand Up @@ -285,6 +287,7 @@ export const VariablesPanel = memo(function VariablesPanel({
recordEdit,
reloadPreview,
domEditSaveTimestampRef,
publishSdkSession,
});

const declarations = useMemo(
Expand Down
2 changes: 2 additions & 0 deletions packages/studio/src/hooks/gsapScriptCommitTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export interface GsapScriptCommitsParams {
showToast: (message: string, tone?: "error" | "info") => void;
/** Stage 7 §3.5: SDK session for routing GSAP tween ops through addGsapTween/setGsapTween/removeGsapTween. */
sdkSession?: Composition | null;
/** Publish a fully persisted candidate SDK session. */
publishSdkSession?: (session: Composition) => void;
writeProjectFile?: (path: string, content: string) => Promise<void>;
/** Resync the in-memory SDK session after a server-authoritative write. */
forceReloadSdkSession?: () => void;
Expand Down
30 changes: 17 additions & 13 deletions packages/studio/src/hooks/useDomEditCommits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { useDomGeometryCommits } from "./useDomGeometryCommits";
import { useElementLifecycleOps } from "./useElementLifecycleOps";
import { formatFieldsSuffix } from "./gsapScriptCommitHelpers";
import { readProjectFileContent } from "../utils/studioFileHistory";
import { cutoverCommittedOrThrow, type CutoverResult } from "../utils/sdkCutover";

// ── Helpers ──

Expand Down Expand Up @@ -117,16 +118,20 @@ export interface UseDomEditCommitsParams {
* path, whose session is already current) so a later SDK edit doesn't
* serialize the pre-write doc and revert the server's change. */
forceReloadSdkSession?: () => void;
/** Stage 7 Step 3c: called before the server-side patch path; returns true if SDK handled it. */
/** Stage 7 Step 3c: called before the server-side patch path. */
onTrySdkPersist?: (
selection: DomEditSelection,
operations: PatchOperation[],
originalContent: string,
targetPath: string,
options?: { label?: string; coalesceKey?: string; skipRefresh?: boolean },
) => Promise<boolean>;
/** Stage 7 §3.1: called before the server-side delete path; returns true if SDK handled it. */
onTrySdkDelete?: (hfId: string, originalContent: string, targetPath: string) => Promise<boolean>;
) => Promise<CutoverResult>;
/** Stage 7 §3.1: called before the server-side delete path. */
onTrySdkDelete?: (
hfId: string,
originalContent: string,
targetPath: string,
) => Promise<CutoverResult>;
/** Resolver-shadow tripwire for z-index reorder targets (telemetry-only, decoupled from cutover). */
onReorderShadow?: (targets: string[]) => void;
}
Expand Down Expand Up @@ -221,18 +226,17 @@ export function useDomEditCommits({
// Skip the SDK path when prepareContent is set (e.g. @font-face injection
// for a custom font): sdkCutoverPersist serializes only the patched DOM
// and would drop the injected content. Let the server path run prepareContent.
if (
onTrySdkPersist &&
!options?.prepareContent &&
(await onTrySdkPersist(selection, operations, originalContent, targetPath, {
if (onTrySdkPersist && !options?.prepareContent) {
const cutover = await onTrySdkPersist(selection, operations, originalContent, targetPath, {
label: options?.label,
coalesceKey: options?.coalesceKey,
skipRefresh: options?.skipRefresh,
}))
) {
// SDK handled it — its in-memory doc is already current, so do NOT
// forceReload (that would echo-reload the session we just wrote).
return;
});
if (cutoverCommittedOrThrow(cutover)) {
// SDK handled it — its in-memory doc is already current, so do NOT
// forceReload (that would echo-reload the session we just wrote).
return;
}
}

// Mark the save timestamp before the file write so the SSE file-change
Expand Down
7 changes: 7 additions & 0 deletions packages/studio/src/hooks/useDomEditSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export interface UseDomEditSessionParams {
selectSidebarTab?: (tab: SidebarTab) => void;
getSidebarTab?: () => SidebarTab;
sdkSession?: Composition | null;
publishSdkSession?: (session: Composition) => void;
forceReloadSdkSession?: () => void;
}

Expand Down Expand Up @@ -108,6 +109,7 @@ export function useDomEditSession({
selectSidebarTab,
getSidebarTab,
sdkSession,
publishSdkSession,
forceReloadSdkSession,
}: UseDomEditSessionParams) {
void _setRefreshKey;
Expand Down Expand Up @@ -217,6 +219,7 @@ export function useDomEditSession({
onFileContentChanged: updateEditingFileContent,
showToast,
sdkSession,
publishSdkSession,
writeProjectFile,
forceReloadSdkSession,
});
Expand Down Expand Up @@ -274,6 +277,8 @@ export function useDomEditSession({
reloadPreview,
domEditSaveTimestampRef,
compositionPath: activeCompPath,
readProjectFile,
publishSession: publishSdkSession,
},
options,
);
Expand All @@ -287,6 +292,8 @@ export function useDomEditSession({
reloadPreview,
domEditSaveTimestampRef,
compositionPath: activeCompPath,
readProjectFile,
publishSession: publishSdkSession,
})
: undefined,
// Resolver shadow for the z-index reorder edit: it takes the server path (no
Expand Down
11 changes: 8 additions & 3 deletions packages/studio/src/hooks/useElementLifecycleOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ import {
type DomEditSelection,
} from "../components/editor/domEditing";
import type { CommitDomEditPatchBatches, DomEditPatchBatch } from "./domEditCommitTypes";
import { cutoverCommittedOrThrow, type CutoverResult } from "../utils/sdkCutover";

interface UseElementLifecycleOpsParams extends DomEditCommitBaseParams {
/** Route delete through SDK when session resolves the hf-id; returns true if handled. */
onTrySdkDelete?: (hfId: string, originalContent: string, targetPath: string) => Promise<boolean>;
/** Route delete through SDK when session resolves the hf-id. */
onTrySdkDelete?: (
hfId: string,
originalContent: string,
targetPath: string,
) => Promise<CutoverResult>;
/** Resolver-shadow tripwire for the reordered targets (telemetry-only, decoupled from cutover). */
onReorderShadow?: (targets: string[]) => void;
/** Resync the SDK session after a server-fallback delete. */
Expand Down Expand Up @@ -59,7 +64,7 @@ export function useElementLifecycleOps({

if (onTrySdkDelete && selection.hfId) {
const handled = await onTrySdkDelete(selection.hfId, originalContent, targetPath);
if (handled) {
if (cutoverCommittedOrThrow(handled)) {
clearDomSelection();
usePlayerStore.getState().setSelectedElementId(null);
showToast(`Deleted ${label}. Use Undo to restore it.`, "info");
Expand Down
13 changes: 7 additions & 6 deletions packages/studio/src/hooks/useGsapAnimationOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
sdkGsapDeleteAllForSelectorPersist,
sdkAddWithKeyframesPersist,
sdkReplaceWithKeyframesPersist,
cutoverCommittedOrThrow,
type CutoverDeps,
} from "../utils/sdkCutover";
import {
Expand Down Expand Up @@ -52,7 +53,7 @@ export function useGsapAnimationOps({
sdkDeps,
{ label: "Edit GSAP animation", coalesceKey: `gsap:${animationId}:meta` },
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
commitMutationSafely(
selection,
Expand All @@ -74,7 +75,7 @@ export function useGsapAnimationOps({
sdkDeps,
{ label: "Delete GSAP animation" },
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
commitMutationSafely(
selection,
Expand All @@ -96,7 +97,7 @@ export function useGsapAnimationOps({
sdkDeps,
{ label: "Delete all animations for element" },
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
void commitMutation(
selection,
Expand Down Expand Up @@ -162,7 +163,7 @@ export function useGsapAnimationOps({
sdkDeps,
{ label: `Add GSAP ${method} animation` },
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}

await commitMutation(
Expand Down Expand Up @@ -213,7 +214,7 @@ export function useGsapAnimationOps({
sdkDeps,
{ label },
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
void commitMutation(
selection,
Expand Down Expand Up @@ -256,7 +257,7 @@ export function useGsapAnimationOps({
sdkDeps,
{ label },
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
void commitMutation(
selection,
Expand Down
11 changes: 6 additions & 5 deletions packages/studio/src/hooks/useGsapKeyframeOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
sdkGsapRemoveKeyframePersist,
sdkGsapRemoveAllKeyframesPersist,
sdkGsapConvertToKeyframesPersist,
cutoverCommittedOrThrow,
type CutoverDeps,
} from "../utils/sdkCutover";
import type { KeyframeCacheEntry } from "../player/store/playerStore";
Expand Down Expand Up @@ -136,7 +137,7 @@ export function useGsapKeyframeOps({
coalesceKey: `gsap:${animationId}:kf:${percentage}`,
},
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
await commitMutation(selection, mutation, {
label: `Add keyframe at ${percentage}%`,
Expand Down Expand Up @@ -169,7 +170,7 @@ export function useGsapKeyframeOps({
sdkDeps,
toSdkPersistOptions(`Add keyframe at ${percentage}%`, commitOverrides),
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
return commitMutation(
selection,
Expand Down Expand Up @@ -218,7 +219,7 @@ export function useGsapKeyframeOps({
sdkDeps,
toSdkPersistOptions(label, commitOverrides),
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
const commitOptions = commitOverrides?.skipReload
? { label, ...commitOverrides }
Expand Down Expand Up @@ -300,7 +301,7 @@ export function useGsapKeyframeOps({
sdkDeps,
toSdkPersistOptions("Convert to keyframes", commitOverrides),
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
return commitMutation(
selection,
Expand Down Expand Up @@ -329,7 +330,7 @@ export function useGsapKeyframeOps({
sdkDeps,
{ label: "Remove all keyframes" },
);
if (handled) return;
if (cutoverCommittedOrThrow(handled)) return;
}
commitMutationSafely(
selection,
Expand Down
Loading
Loading