@hyperframes/studio 0.7.57 → 0.7.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{hyperframes-player--Z69cEkE.js → hyperframes-player-Bm07FLkl.js} +1 -1
- package/dist/assets/{index-KsfE1bUu.js → index-B995FG46.js} +1 -1
- package/dist/assets/index-CrkAdJkb.js +426 -0
- package/dist/assets/index-Dj5p8U_A.css +1 -0
- package/dist/assets/{index-Bf1x1y8H.js → index-FvzmPhfG.js} +1 -1
- package/dist/{chunk-5QSIMBEJ.js → chunk-OBAG3GWK.js} +33 -21
- package/dist/chunk-OBAG3GWK.js.map +1 -0
- package/dist/{domEditingLayers-6LQGKPOI.js → domEditingLayers-2CKWGEHS.js} +2 -2
- package/dist/index.d.ts +27 -7
- package/dist/index.html +2 -2
- package/dist/index.js +18029 -11563
- package/dist/index.js.map +1 -1
- package/dist/styles/tailwind-preset.d.ts +5 -0
- package/dist/styles/tailwind-preset.js +8 -1
- package/dist/styles/tailwind-preset.js.map +1 -1
- package/package.json +7 -7
- package/src/App.tsx +6 -6
- package/src/components/DesignPanelPromoteProvider.tsx +15 -2
- package/src/components/StudioFeedbackBar.tsx +2 -2
- package/src/components/StudioRightPanel.tsx +29 -51
- package/src/components/editor/AnimationCard.test.tsx +134 -0
- package/src/components/editor/AnimationCard.tsx +19 -4
- package/src/components/editor/ArcPathControls.tsx +1 -0
- package/src/components/editor/CanvasContextMenu.test.tsx +27 -14
- package/src/components/editor/CanvasContextMenu.tsx +71 -6
- package/src/components/editor/DomEditOverlay.tsx +5 -2
- package/src/components/editor/GestureRecordControl.tsx +7 -1
- package/src/components/editor/GsapAnimationSection.tsx +109 -14
- package/src/components/editor/InspectorHeaderActions.tsx +42 -4
- package/src/components/editor/LayersPanel.tsx +110 -99
- package/src/components/editor/PropertyPanel.test.tsx +948 -0
- package/src/components/editor/PropertyPanel.tsx +144 -148
- package/src/components/editor/PropertyPanelEmptyState.test.tsx +74 -0
- package/src/components/editor/PropertyPanelEmptyState.tsx +179 -1
- package/src/components/editor/PropertyPanelFlat.tsx +580 -0
- package/src/components/editor/PropertyPanelFlatFooter.test.tsx +83 -0
- package/src/components/editor/PropertyPanelFlatFooter.tsx +73 -0
- package/src/components/editor/PropertyPanelFlatHeader.test.tsx +79 -0
- package/src/components/editor/PropertyPanelFlatHeader.tsx +112 -0
- package/src/components/editor/canvasContextMenuZOrder.test.ts +57 -0
- package/src/components/editor/canvasContextMenuZOrder.ts +40 -1
- package/src/components/editor/domEditingDom.ts +5 -6
- package/src/components/editor/domEditingElement.ts +15 -32
- package/src/components/editor/gsapAnimationCallbacks.ts +27 -0
- package/src/components/editor/gsapLivePreview.ts +34 -0
- package/src/components/editor/layersPanelSort.ts +80 -0
- package/src/components/editor/manualEditingAvailability.test.ts +10 -0
- package/src/components/editor/manualEditingAvailability.ts +9 -0
- package/src/components/editor/propertyPanel3dTransform.tsx +5 -0
- package/src/components/editor/propertyPanelColor.test.tsx +28 -0
- package/src/components/editor/propertyPanelColor.tsx +31 -1
- package/src/components/editor/propertyPanelColorGradingControls.tsx +11 -2
- package/src/components/editor/propertyPanelColorGradingSection.tsx +45 -365
- package/src/components/editor/propertyPanelColorGradingSlider.tsx +19 -5
- package/src/components/editor/propertyPanelFill.tsx +22 -5
- package/src/components/editor/propertyPanelFlatColorGradingSection.test.tsx +622 -0
- package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +570 -0
- package/src/components/editor/propertyPanelFlatLayoutSection.test.tsx +293 -0
- package/src/components/editor/propertyPanelFlatLayoutSection.tsx +383 -0
- package/src/components/editor/propertyPanelFlatMaskInsetRows.tsx +102 -0
- package/src/components/editor/propertyPanelFlatMediaSection.test.tsx +436 -0
- package/src/components/editor/propertyPanelFlatMediaSection.tsx +286 -0
- package/src/components/editor/propertyPanelFlatMotionSection.test.tsx +272 -0
- package/src/components/editor/propertyPanelFlatMotionSection.tsx +315 -0
- package/src/components/editor/propertyPanelFlatPrimitives.test.tsx +1174 -0
- package/src/components/editor/propertyPanelFlatPrimitives.tsx +563 -0
- package/src/components/editor/propertyPanelFlatSelectRow.tsx +101 -0
- package/src/components/editor/propertyPanelFlatStyleHelpers.test.ts +23 -0
- package/src/components/editor/propertyPanelFlatStyleHelpers.ts +27 -0
- package/src/components/editor/propertyPanelFlatStyleSections.test.tsx +598 -0
- package/src/components/editor/propertyPanelFlatStyleSections.tsx +516 -0
- package/src/components/editor/propertyPanelFlatTextSection.test.tsx +465 -0
- package/src/components/editor/propertyPanelFlatTextSection.tsx +407 -0
- package/src/components/editor/propertyPanelFlatTimingDerivation.test.ts +71 -0
- package/src/components/editor/propertyPanelFlatTimingDerivation.ts +59 -0
- package/src/components/editor/propertyPanelFlatToggle.test.tsx +63 -0
- package/src/components/editor/propertyPanelFlatToggle.tsx +53 -0
- package/src/components/editor/propertyPanelFont.test.tsx +30 -0
- package/src/components/editor/propertyPanelFont.tsx +136 -95
- package/src/components/editor/propertyPanelHelpers.ts +73 -0
- package/src/components/editor/propertyPanelInputCoverage.test.tsx +587 -0
- package/src/components/editor/propertyPanelMediaSection.tsx +10 -0
- package/src/components/editor/propertyPanelPrimitives.tsx +60 -29
- package/src/components/editor/propertyPanelSections.test.tsx +161 -0
- package/src/components/editor/propertyPanelSections.tsx +154 -90
- package/src/components/editor/propertyPanelStyleSections.tsx +12 -1
- package/src/components/editor/propertyPanelTimingSection.tsx +1 -1
- package/src/components/editor/propertyPanelTypes.ts +14 -1
- package/src/components/editor/propertyPanelValueTier.test.ts +32 -0
- package/src/components/editor/propertyPanelValueTier.ts +28 -0
- package/src/components/editor/useColorGradingController.test.ts +418 -0
- package/src/components/editor/useColorGradingController.ts +596 -0
- package/src/components/editor/useLayerRevealOverride.test.ts +169 -0
- package/src/components/editor/useLayerRevealOverride.ts +389 -0
- package/src/components/nle/PreviewOverlays.tsx +27 -2
- package/src/components/nle/TimelinePane.test.ts +3 -0
- package/src/components/nle/TimelinePane.tsx +11 -1
- package/src/components/nle/useCanvasZOrderTimelineMirror.test.tsx +440 -0
- package/src/components/nle/useCanvasZOrderTimelineMirror.ts +191 -0
- package/src/components/nle/useTimelineEditCallbacks.ts +1 -0
- package/src/components/nle/zLaneGesture.test.ts +176 -0
- package/src/components/nle/zLaneGesture.ts +77 -0
- package/src/components/panels/VariablesPanel.tsx +4 -0
- package/src/components/sidebar/CompositionsTab.test.ts +28 -2
- package/src/components/sidebar/CompositionsTab.tsx +3 -1
- package/src/components/storyboard/FramePoster.tsx +24 -4
- package/src/components/storyboard/StoryboardFrameFocus.tsx +4 -0
- package/src/components/storyboard/StoryboardFrameTile.tsx +30 -1
- package/src/components/storyboard/StoryboardGrid.tsx +23 -1
- package/src/components/storyboard/StoryboardLoaded.tsx +58 -2
- package/src/components/storyboard/StoryboardView.tsx +9 -2
- package/src/components/storyboard/frameComments.test.ts +95 -0
- package/src/components/storyboard/frameComments.ts +115 -0
- package/src/components/storyboard/useFrameComments.ts +82 -0
- package/src/contexts/DesignPanelInputContext.test.tsx +81 -0
- package/src/contexts/DesignPanelInputContext.tsx +48 -0
- package/src/contexts/DomEditContext.tsx +4 -0
- package/src/contexts/VariablePromoteContext.test.tsx +67 -0
- package/src/contexts/VariablePromoteContext.tsx +10 -5
- package/src/hooks/domEditCommitRunner.ts +11 -0
- package/src/hooks/domEditCommitTypes.ts +17 -1
- package/src/hooks/elementLifecycleOpsTestUtils.ts +25 -0
- package/src/hooks/fetchStubTestUtils.ts +16 -0
- package/src/hooks/gsapScriptCommitTypes.ts +6 -4
- package/src/hooks/timelineEditingHelpers.test.ts +92 -1
- package/src/hooks/timelineEditingHelpers.ts +32 -15
- package/src/hooks/timelineMoveAdapter.ts +2 -1
- package/src/hooks/timelineTimingSync.test.ts +703 -33
- package/src/hooks/timelineTimingSync.ts +282 -97
- package/src/hooks/timelineTrackVisibility.test.ts +55 -1
- package/src/hooks/timelineTrackVisibility.ts +31 -13
- package/src/hooks/useAppHotkeys.ts +9 -0
- package/src/hooks/useClipboard.ts +19 -17
- package/src/hooks/useDomEditAttributeCommits.ts +123 -1
- package/src/hooks/useDomEditCommits.test.tsx +316 -38
- package/src/hooks/useDomEditCommits.ts +81 -162
- package/src/hooks/useDomEditCommitsHelpers.ts +158 -0
- package/src/hooks/useDomEditSession.test.tsx +3 -1
- package/src/hooks/useDomEditSession.ts +18 -6
- package/src/hooks/useDomEditTextCommits.ts +14 -9
- package/src/hooks/useDomEditWiring.ts +10 -9
- package/src/hooks/useElementLifecycleOps.test.tsx +426 -60
- package/src/hooks/useElementLifecycleOps.ts +182 -84
- package/src/hooks/useFileManager.projectOwnership.test.tsx +98 -0
- package/src/hooks/useFileManager.ts +82 -60
- package/src/hooks/useGsapAnimationOps.ts +7 -6
- package/src/hooks/useGsapKeyframeOps.ts +6 -5
- package/src/hooks/useGsapPropertyDebounce.ts +43 -28
- package/src/hooks/useGsapPropertyDebounceFlush.test.ts +35 -0
- package/src/hooks/useGsapScriptCommits.test.tsx +48 -2
- package/src/hooks/useGsapScriptCommits.ts +150 -50
- package/src/hooks/useGsapSelectionHandlers.test.tsx +116 -0
- package/src/hooks/useGsapSelectionHandlers.ts +94 -31
- package/src/hooks/useInspectorSplitResize.ts +51 -0
- package/src/hooks/usePersistentEditHistory.projectOwnership.test.tsx +60 -0
- package/src/hooks/usePersistentEditHistory.test.ts +49 -1
- package/src/hooks/usePersistentEditHistory.ts +71 -31
- package/src/hooks/usePreviewPersistence.ts +2 -2
- package/src/hooks/useProjectCompositionVariables.ts +10 -10
- package/src/hooks/useProjectSignaturePoll.test.tsx +135 -0
- package/src/hooks/useProjectSignaturePoll.ts +68 -0
- package/src/hooks/useSdkSession.lifecycle.test.tsx +137 -0
- package/src/hooks/useSdkSession.ts +155 -14
- package/src/hooks/useSlideshowPersist.ts +7 -1
- package/src/hooks/useStoryboard.ts +23 -4
- package/src/hooks/useTimelineEditing.test.tsx +306 -155
- package/src/hooks/useTimelineEditing.ts +111 -101
- package/src/hooks/useTimelineEditingTypes.ts +4 -1
- package/src/hooks/useTimelineGroupEditing.ts +51 -5
- package/src/hooks/useVariablesPersist.ts +9 -7
- package/src/icons/SystemIcons.tsx +2 -0
- package/src/player/components/Timeline.test.ts +31 -21
- package/src/player/components/Timeline.tsx +62 -91
- package/src/player/components/TimelineCanvas.tsx +36 -5
- package/src/player/components/TimelineLanes.tsx +32 -10
- package/src/player/components/TimelineOverlays.tsx +36 -0
- package/src/player/components/TimelineRuler.tsx +18 -5
- package/src/player/components/TrackGapContextMenu.tsx +116 -0
- package/src/player/components/timelineCallbacks.ts +4 -1
- package/src/player/components/timelineClipDragCommit.test.ts +279 -3
- package/src/player/components/timelineClipDragCommit.ts +173 -71
- package/src/player/components/timelineGapCommit.test.ts +163 -0
- package/src/player/components/timelineGapCommit.ts +103 -0
- package/src/player/components/timelineGaps.test.ts +221 -0
- package/src/player/components/timelineGaps.ts +182 -0
- package/src/player/components/timelineLayout.test.ts +2 -1
- package/src/player/components/timelineLayout.ts +22 -6
- package/src/player/components/timelineMarquee.test.ts +20 -10
- package/src/player/components/timelineMarquee.ts +9 -2
- package/src/player/components/timelineStackingSync.test.ts +42 -1
- package/src/player/components/timelineStackingSync.ts +31 -16
- package/src/player/components/timelineZMirror.test.ts +667 -0
- package/src/player/components/timelineZMirror.ts +393 -0
- package/src/player/components/timelineZoom.test.ts +2 -2
- package/src/player/components/timelineZoom.ts +7 -3
- package/src/player/components/useTimelineClipDrag.ts +1 -1
- package/src/player/components/useTimelineGapHighlights.test.ts +119 -0
- package/src/player/components/useTimelineGapHighlights.ts +110 -0
- package/src/player/components/useTimelinePlayhead.ts +4 -3
- package/src/player/components/useTimelineRangeSelection.ts +6 -4
- package/src/player/components/useTimelineScrollViewport.ts +73 -0
- package/src/player/components/useTimelineStackingSync.test.tsx +0 -1
- package/src/player/components/useTimelineStackingSync.ts +5 -3
- package/src/player/components/useTimelineTrackDerivations.ts +38 -0
- package/src/player/components/useTrackGapMenu.ts +155 -0
- package/src/player/hooks/useExpandedTimelineElements.test.ts +67 -4
- package/src/player/hooks/useExpandedTimelineElements.ts +12 -1
- package/src/player/hooks/useTimelineSyncCallbacks.ts +2 -0
- package/src/player/lib/layerOrdering.test.ts +1 -15
- package/src/player/lib/layerOrdering.ts +5 -28
- package/src/player/lib/timelineDOM.test.ts +72 -0
- package/src/player/lib/timelineDOM.ts +3 -0
- package/src/player/lib/timelineElementHelpers.ts +35 -11
- package/src/player/store/playerStore.ts +12 -1
- package/src/styles/studio.css +22 -0
- package/src/styles/tailwind-preset.shared.js +7 -0
- package/src/telemetry/events.test.ts +10 -0
- package/src/telemetry/events.ts +1 -0
- package/src/utils/designInputTracking.test.ts +97 -0
- package/src/utils/designInputTracking.ts +80 -0
- package/src/utils/domEditSaveQueue.ts +4 -3
- package/src/utils/editHistory.test.ts +82 -0
- package/src/utils/editHistory.ts +14 -2
- package/src/utils/gsapSoftReload.test.ts +54 -115
- package/src/utils/gsapSoftReload.ts +42 -152
- package/src/utils/gsapUndoRestore.test.ts +269 -0
- package/src/utils/gsapUndoRestore.ts +269 -0
- package/src/utils/sdkCutover.gate.test.ts +7 -7
- package/src/utils/sdkCutover.test.ts +490 -57
- package/src/utils/sdkCutover.ts +181 -219
- package/src/utils/sdkEditTransaction.ts +292 -0
- package/src/utils/sdkResolverAttempts.ts +94 -0
- package/src/utils/sdkResolverShadow.test.ts +148 -0
- package/src/utils/sdkResolverShadow.ts +139 -106
- package/src/utils/setSlideshowManifest.test.ts +0 -9
- package/src/utils/setSlideshowManifest.ts +20 -27
- package/src/utils/sourceScopedSelectorIndex.ts +29 -0
- package/src/utils/studioFileHistory.test.ts +41 -0
- package/src/utils/studioFileHistory.ts +30 -27
- package/src/utils/studioFileMutationCoordinator.ts +45 -0
- package/src/utils/studioHelpers.test.ts +45 -0
- package/src/utils/studioHelpers.ts +45 -14
- package/src/utils/studioSaveDiagnostics.ts +17 -0
- package/dist/assets/index-DfmYkU44.js +0 -423
- package/dist/assets/index-_pqzyxB1.css +0 -1
- package/dist/chunk-5QSIMBEJ.js.map +0 -1
- /package/dist/{domEditingLayers-6LQGKPOI.js.map → domEditingLayers-2CKWGEHS.js.map} +0 -0
|
@@ -31,8 +31,10 @@ import {
|
|
|
31
31
|
useTimelineTrackVisibilityEditing,
|
|
32
32
|
} from "./timelineTrackVisibility";
|
|
33
33
|
import { useTimelineGroupEditing } from "./useTimelineGroupEditing";
|
|
34
|
-
import {
|
|
34
|
+
import { serializeZLaneGesture } from "../components/nle/zLaneGesture";
|
|
35
|
+
import { cutoverCommittedOrThrow, sdkTimingPersist } from "../utils/sdkCutover";
|
|
35
36
|
import type { UseTimelineEditingOptions } from "./useTimelineEditingTypes";
|
|
37
|
+
import { getStudioSaveErrorMessage } from "../utils/studioSaveDiagnostics";
|
|
36
38
|
|
|
37
39
|
type TimelineMoveUpdates = Pick<TimelineElement, "start" | "track"> & {
|
|
38
40
|
stackingReorder?: TimelineStackingReorderIntent | null;
|
|
@@ -52,6 +54,7 @@ export function useTimelineEditing({
|
|
|
52
54
|
uploadProjectFiles,
|
|
53
55
|
isRecordingRef,
|
|
54
56
|
sdkSession,
|
|
57
|
+
publishSdkSession,
|
|
55
58
|
forceReloadSdkSession,
|
|
56
59
|
handleDomZIndexReorderCommitRef,
|
|
57
60
|
}: UseTimelineEditingOptions) {
|
|
@@ -120,124 +123,131 @@ export function useTimelineEditing({
|
|
|
120
123
|
recordEdit,
|
|
121
124
|
reloadPreview,
|
|
122
125
|
sdkSession,
|
|
126
|
+
publishSdkSession,
|
|
123
127
|
showToast,
|
|
124
128
|
writeProjectFile,
|
|
125
129
|
});
|
|
126
|
-
|
|
127
130
|
const handleTimelineElementMove = useCallback(
|
|
128
131
|
// fallow-ignore-next-line complexity
|
|
129
132
|
(element: TimelineElement, updates: TimelineMoveUpdates) => {
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
133
|
+
const commitMove = () => {
|
|
134
|
+
const targetPath = element.sourceFile || activeCompPath || "index.html";
|
|
135
|
+
const startChanged = updates.start !== element.start;
|
|
136
|
+
// A vertical-only lane move arrives with start unchanged but track changed
|
|
137
|
+
// (on this single-element path the drag commit has already folded the
|
|
138
|
+
// AUTHORED persist track into updates.track). It must persist like any
|
|
139
|
+
// other move — early-returning on !startChanged alone silently dropped
|
|
140
|
+
// the file write, so the lane snapped back on reload.
|
|
141
|
+
const trackChanged = updates.track !== element.track;
|
|
138
142
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
if (startChanged || trackChanged) {
|
|
144
|
+
const liveAttrs: Array<[string, string]> = [];
|
|
145
|
+
if (startChanged) {
|
|
146
|
+
liveAttrs.push(["data-start", formatTimelineAttributeNumber(updates.start)]);
|
|
147
|
+
}
|
|
148
|
+
if (trackChanged) {
|
|
149
|
+
liveAttrs.push(["data-track-index", formatTimelineAttributeNumber(updates.track)]);
|
|
150
|
+
}
|
|
151
|
+
patchIframeDomTiming(previewIframeRef.current, element, liveAttrs, activeCompPath);
|
|
146
152
|
}
|
|
147
|
-
patchIframeDomTiming(previewIframeRef.current, element, liveAttrs);
|
|
148
|
-
}
|
|
149
153
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
const reorderDone = applyTimelineStackingReorder({
|
|
155
|
+
element,
|
|
156
|
+
stackingReorder: updates.stackingReorder,
|
|
157
|
+
timelineElements,
|
|
158
|
+
iframe: previewIframeRef.current,
|
|
159
|
+
activeCompPath,
|
|
160
|
+
commit: handleDomZIndexReorderCommitRef?.current,
|
|
161
|
+
});
|
|
158
162
|
|
|
159
|
-
|
|
163
|
+
if (!startChanged && !trackChanged) return reorderDone;
|
|
160
164
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
// Snapshot the duration BEFORE the optimistic updates below so a failed
|
|
166
|
+
// persist can roll the readout + live root back (see captureDurationRollback).
|
|
167
|
+
const rollbackDuration = captureDurationRollback(previewIframeRef.current);
|
|
168
|
+
// needsExtension gates the SDK path (setTiming can't grow the root duration), so read the store BEFORE the readout sync below optimistically updates it.
|
|
169
|
+
const needsExtension = extendRootDurationIfNeeded(updates.start + element.duration);
|
|
170
|
+
// Optimistic duration readout: content-driven (grow AND shrink), from the just-patched live DOM. See syncPreviewContentDuration.
|
|
171
|
+
syncPreviewContentDuration(previewIframeRef.current);
|
|
168
172
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
targetPath,
|
|
190
|
-
domId: element.domId,
|
|
191
|
-
label: "Move timeline clip",
|
|
192
|
-
coalesceKey,
|
|
193
|
-
recordEdit,
|
|
194
|
-
edit: { kind: "shift", delta: updates.start - element.start },
|
|
195
|
-
}),
|
|
196
|
-
);
|
|
197
|
-
return reorderDone
|
|
198
|
-
.then(() => {
|
|
199
|
-
// The SDK setTiming path writes start only — a lane change must take
|
|
200
|
-
// the fallback, whose patch builder writes data-track-index too.
|
|
201
|
-
if (sdkSession && element.hfId && !needsExtension && !trackChanged) {
|
|
202
|
-
return sdkTimingPersist(
|
|
203
|
-
element.hfId,
|
|
173
|
+
const buildMovePatches: PersistTimelineEditInput["buildPatches"] = (original, target) => {
|
|
174
|
+
// Persist lane changes too — data-start-only writes let reload snap the lane back.
|
|
175
|
+
const track = trackChanged ? updates.track : undefined;
|
|
176
|
+
return buildTimelineMoveTimingPatch(
|
|
177
|
+
original,
|
|
178
|
+
target,
|
|
179
|
+
updates.start,
|
|
180
|
+
element.duration,
|
|
181
|
+
track,
|
|
182
|
+
);
|
|
183
|
+
};
|
|
184
|
+
const coalesceKey = `timeline-move:${element.hfId ?? element.id}`;
|
|
185
|
+
const moveFallback = () =>
|
|
186
|
+
enqueueEdit(element, "Move timeline clip", buildMovePatches, coalesceKey).then(() =>
|
|
187
|
+
// Soft-reload with the server's rewritten GSAP script — the timing-only move already patched
|
|
188
|
+
// DOM + store, so swapping the script avoids the all-clips flash; falls back to reloadPreview().
|
|
189
|
+
finishClipTimingFallback({
|
|
190
|
+
iframe: previewIframeRef.current,
|
|
191
|
+
reloadPreview,
|
|
192
|
+
projectId: projectIdRef.current,
|
|
204
193
|
targetPath,
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
194
|
+
domId: element.domId,
|
|
195
|
+
label: "Move timeline clip",
|
|
196
|
+
coalesceKey,
|
|
197
|
+
recordEdit,
|
|
198
|
+
edit: { kind: "shift", delta: updates.start - element.start },
|
|
199
|
+
}),
|
|
200
|
+
);
|
|
201
|
+
return reorderDone
|
|
202
|
+
.then(() => {
|
|
203
|
+
// The SDK setTiming path writes start only — a lane change must take
|
|
204
|
+
// the fallback, whose patch builder writes data-track-index too.
|
|
205
|
+
if (sdkSession && element.hfId && !needsExtension && !trackChanged) {
|
|
206
|
+
return sdkTimingPersist(
|
|
207
|
+
element.hfId,
|
|
208
|
+
targetPath,
|
|
209
|
+
{ start: updates.start },
|
|
210
|
+
sdkSession,
|
|
211
|
+
{
|
|
212
|
+
editHistory: { recordEdit },
|
|
213
|
+
writeProjectFile,
|
|
214
|
+
reloadPreview,
|
|
215
|
+
domEditSaveTimestampRef,
|
|
216
|
+
compositionPath: activeCompPath,
|
|
217
|
+
// Capture on-disk bytes as the undo `before` so undoing a timing move
|
|
218
|
+
// restores the file verbatim, not a normalized full-DOM re-emit.
|
|
219
|
+
readProjectFile: (path) => readFileContent(projectIdRef.current ?? "", path),
|
|
220
|
+
publishSession: publishSdkSession,
|
|
221
|
+
},
|
|
222
|
+
{ label: "Move timeline clip", coalesceKey },
|
|
223
|
+
).then((result) => {
|
|
224
|
+
if (!cutoverCommittedOrThrow(result)) return moveFallback();
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return moveFallback();
|
|
228
|
+
})
|
|
229
|
+
.catch((error) => {
|
|
230
|
+
// Failed persist: revert the optimistic duration readout + live root.
|
|
231
|
+
rollbackDuration();
|
|
232
|
+
showToast(getStudioSaveErrorMessage(error), "error");
|
|
233
|
+
throw error;
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
return updates.stackingReorder ? serializeZLaneGesture(commitMove) : commitMove();
|
|
229
237
|
},
|
|
230
238
|
[
|
|
231
239
|
previewIframeRef,
|
|
232
240
|
enqueueEdit,
|
|
233
241
|
activeCompPath,
|
|
234
242
|
sdkSession,
|
|
243
|
+
publishSdkSession,
|
|
235
244
|
recordEdit,
|
|
236
245
|
writeProjectFile,
|
|
237
246
|
reloadPreview,
|
|
238
247
|
domEditSaveTimestampRef,
|
|
239
248
|
timelineElements,
|
|
240
249
|
handleDomZIndexReorderCommitRef,
|
|
250
|
+
showToast,
|
|
241
251
|
],
|
|
242
252
|
);
|
|
243
253
|
|
|
@@ -251,9 +261,6 @@ export function useTimelineEditing({
|
|
|
251
261
|
["data-start", formatTimelineAttributeNumber(updates.start)],
|
|
252
262
|
["data-duration", formatTimelineAttributeNumber(updates.duration)],
|
|
253
263
|
];
|
|
254
|
-
// Patch the live playback-start/media-start attr too, or a resize that
|
|
255
|
-
// trims the playback start leaves the preview showing the old in-point
|
|
256
|
-
// until the next reload (the persisted patch handles it via pbs below).
|
|
257
264
|
if (updates.playbackStart != null) {
|
|
258
265
|
const liveAttr =
|
|
259
266
|
element.playbackStartAttr === "playback-start"
|
|
@@ -261,7 +268,7 @@ export function useTimelineEditing({
|
|
|
261
268
|
: "data-media-start";
|
|
262
269
|
liveAttrs.push([liveAttr, formatTimelineAttributeNumber(updates.playbackStart)]);
|
|
263
270
|
}
|
|
264
|
-
patchIframeDomTiming(previewIframeRef.current, element, liveAttrs);
|
|
271
|
+
patchIframeDomTiming(previewIframeRef.current, element, liveAttrs, activeCompPath);
|
|
265
272
|
// Snapshot the duration BEFORE the optimistic updates below so a failed
|
|
266
273
|
// persist can roll the readout + live root back (see captureDurationRollback).
|
|
267
274
|
const rollbackDuration = captureDurationRollback(previewIframeRef.current);
|
|
@@ -315,15 +322,17 @@ export function useTimelineEditing({
|
|
|
315
322
|
// Capture on-disk bytes as the undo `before` so undoing a timing
|
|
316
323
|
// resize restores the file verbatim, not a normalized full-DOM re-emit.
|
|
317
324
|
readProjectFile: (path) => readFileContent(projectIdRef.current ?? "", path),
|
|
325
|
+
publishSession: publishSdkSession,
|
|
318
326
|
},
|
|
319
327
|
{ label: "Resize timeline clip", coalesceKey },
|
|
320
|
-
).then((
|
|
321
|
-
if (!
|
|
328
|
+
).then((result) => {
|
|
329
|
+
if (!cutoverCommittedOrThrow(result)) return resizeFallback();
|
|
322
330
|
})
|
|
323
331
|
: resizeFallback();
|
|
324
332
|
return persistDone.catch((error) => {
|
|
325
333
|
// Failed persist: revert the optimistic duration readout + live root.
|
|
326
334
|
rollbackDuration();
|
|
335
|
+
showToast(getStudioSaveErrorMessage(error), "error");
|
|
327
336
|
throw error;
|
|
328
337
|
});
|
|
329
338
|
},
|
|
@@ -332,10 +341,12 @@ export function useTimelineEditing({
|
|
|
332
341
|
enqueueEdit,
|
|
333
342
|
activeCompPath,
|
|
334
343
|
sdkSession,
|
|
344
|
+
publishSdkSession,
|
|
335
345
|
recordEdit,
|
|
336
346
|
writeProjectFile,
|
|
337
347
|
reloadPreview,
|
|
338
348
|
domEditSaveTimestampRef,
|
|
349
|
+
showToast,
|
|
339
350
|
],
|
|
340
351
|
);
|
|
341
352
|
|
|
@@ -356,7 +367,6 @@ export function useTimelineEditing({
|
|
|
356
367
|
const handleToggleElementHidden = useTimelineElementVisibilityEditing({
|
|
357
368
|
projectIdRef,
|
|
358
369
|
activeCompPath,
|
|
359
|
-
timelineElements,
|
|
360
370
|
showToast,
|
|
361
371
|
writeProjectFile,
|
|
362
372
|
recordEdit,
|
|
@@ -2,6 +2,7 @@ import type { MutableRefObject, RefObject } from "react";
|
|
|
2
2
|
import type { Composition } from "@hyperframes/sdk";
|
|
3
3
|
import type { TimelineElement } from "../player";
|
|
4
4
|
import type { EditHistoryKind } from "../utils/editHistory";
|
|
5
|
+
import type { PublishSdkSession } from "../utils/sdkCutover";
|
|
5
6
|
|
|
6
7
|
interface RecordEditInput {
|
|
7
8
|
label: string;
|
|
@@ -23,7 +24,7 @@ export type TimelineZIndexReorderCommit = (
|
|
|
23
24
|
key?: string;
|
|
24
25
|
}>,
|
|
25
26
|
coalesceKey?: string,
|
|
26
|
-
) => Promise<void>;
|
|
27
|
+
) => Promise<import("./domEditCommitTypes").DomEditPatchBatchesResult | undefined | void>;
|
|
27
28
|
|
|
28
29
|
export interface UseTimelineEditingOptions {
|
|
29
30
|
projectId: string | null;
|
|
@@ -40,6 +41,8 @@ export interface UseTimelineEditingOptions {
|
|
|
40
41
|
isRecordingRef?: RefObject<boolean>;
|
|
41
42
|
/** Stage 7 §3.2: SDK session for routing timing ops through setTiming. */
|
|
42
43
|
sdkSession?: Composition | null;
|
|
44
|
+
/** Publish a fully persisted candidate SDK session. */
|
|
45
|
+
publishSdkSession?: PublishSdkSession;
|
|
43
46
|
/** Resync the SDK session after a server-authoritative timeline write. */
|
|
44
47
|
forceReloadSdkSession?: () => void;
|
|
45
48
|
handleDomZIndexReorderCommitRef?: MutableRefObject<TimelineZIndexReorderCommit | null>;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { useCallback, type MutableRefObject, type RefObject } from "react";
|
|
2
2
|
import type { Composition } from "@hyperframes/sdk";
|
|
3
3
|
import type { TimelineElement } from "../player";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
cutoverCommittedOrThrow,
|
|
6
|
+
sdkTimingBatchPersist,
|
|
7
|
+
type PublishSdkSession,
|
|
8
|
+
} from "../utils/sdkCutover";
|
|
5
9
|
import {
|
|
6
10
|
buildTimelineMoveTimingPatch,
|
|
7
11
|
buildTimelineResizeTimingPatch,
|
|
@@ -20,6 +24,7 @@ import {
|
|
|
20
24
|
shiftGsapPositions,
|
|
21
25
|
syncPreviewContentDuration,
|
|
22
26
|
} from "./timelineTimingSync";
|
|
27
|
+
import { getStudioSaveErrorMessage } from "../utils/studioSaveDiagnostics";
|
|
23
28
|
|
|
24
29
|
export interface TimelineGroupMoveChange {
|
|
25
30
|
element: TimelineElement;
|
|
@@ -37,6 +42,8 @@ export interface TimelineGroupResizeChange {
|
|
|
37
42
|
export interface TimelineGroupCommitOptions {
|
|
38
43
|
beforeTiming?: Promise<void>;
|
|
39
44
|
coalesceKey?: string;
|
|
45
|
+
/** Per-entry undo coalesce window override (ms) — see EditHistoryEntry.coalesceMs. */
|
|
46
|
+
coalesceMs?: number;
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
interface UseTimelineGroupEditingOptions {
|
|
@@ -51,6 +58,7 @@ interface UseTimelineGroupEditingOptions {
|
|
|
51
58
|
recordEdit: (input: RecordEditInput) => Promise<void>;
|
|
52
59
|
reloadPreview: () => void;
|
|
53
60
|
sdkSession?: Composition | null;
|
|
61
|
+
publishSdkSession?: PublishSdkSession;
|
|
54
62
|
showToast: (message: string, tone?: "error" | "info") => void;
|
|
55
63
|
writeProjectFile: (path: string, content: string) => Promise<void>;
|
|
56
64
|
}
|
|
@@ -106,6 +114,7 @@ export function useTimelineGroupEditing({
|
|
|
106
114
|
recordEdit,
|
|
107
115
|
reloadPreview,
|
|
108
116
|
sdkSession,
|
|
117
|
+
publishSdkSession,
|
|
109
118
|
showToast,
|
|
110
119
|
writeProjectFile,
|
|
111
120
|
}: UseTimelineGroupEditingOptions) {
|
|
@@ -137,6 +146,7 @@ export function useTimelineGroupEditing({
|
|
|
137
146
|
label: string,
|
|
138
147
|
batchChanges: PersistTimelineBatchChange[],
|
|
139
148
|
coalesceKey: string,
|
|
149
|
+
coalesceMs?: number,
|
|
140
150
|
) => {
|
|
141
151
|
await persistTimelineBatchEdit({
|
|
142
152
|
projectId,
|
|
@@ -148,6 +158,7 @@ export function useTimelineGroupEditing({
|
|
|
148
158
|
domEditSaveTimestampRef,
|
|
149
159
|
pendingTimelineEditPathRef,
|
|
150
160
|
coalesceKey,
|
|
161
|
+
coalesceMs,
|
|
151
162
|
});
|
|
152
163
|
forceReloadSdkSession?.();
|
|
153
164
|
},
|
|
@@ -176,6 +187,7 @@ export function useTimelineGroupEditing({
|
|
|
176
187
|
needsExtension: boolean;
|
|
177
188
|
label: string;
|
|
178
189
|
coalesceKey: string;
|
|
190
|
+
coalesceMs?: number;
|
|
179
191
|
}): Promise<boolean> => {
|
|
180
192
|
const sharedPath = allChangesSharePath(input.changes, activeCompPath);
|
|
181
193
|
const canUseSdk =
|
|
@@ -184,7 +196,7 @@ export function useTimelineGroupEditing({
|
|
|
184
196
|
input.eligible &&
|
|
185
197
|
input.sdkChanges.every((change) => change !== null);
|
|
186
198
|
if (!canUseSdk) return false;
|
|
187
|
-
|
|
199
|
+
const result = await sdkTimingBatchPersist(
|
|
188
200
|
input.sdkChanges.filter((change): change is NonNullable<typeof change> => change !== null),
|
|
189
201
|
sharedPath,
|
|
190
202
|
sdkSession,
|
|
@@ -195,14 +207,17 @@ export function useTimelineGroupEditing({
|
|
|
195
207
|
domEditSaveTimestampRef,
|
|
196
208
|
compositionPath: activeCompPath,
|
|
197
209
|
readProjectFile: (path) => readFileContent(projectIdRef.current ?? "", path),
|
|
210
|
+
publishSession: publishSdkSession,
|
|
198
211
|
},
|
|
199
|
-
{ label: input.label, coalesceKey: input.coalesceKey },
|
|
212
|
+
{ label: input.label, coalesceKey: input.coalesceKey, coalesceMs: input.coalesceMs },
|
|
200
213
|
);
|
|
214
|
+
return cutoverCommittedOrThrow(result);
|
|
201
215
|
},
|
|
202
216
|
[
|
|
203
217
|
activeCompPath,
|
|
204
218
|
domEditSaveTimestampRef,
|
|
205
219
|
projectIdRef,
|
|
220
|
+
publishSdkSession,
|
|
206
221
|
recordEdit,
|
|
207
222
|
reloadPreview,
|
|
208
223
|
sdkSession,
|
|
@@ -220,20 +235,38 @@ export function useTimelineGroupEditing({
|
|
|
220
235
|
if (change.track != null) {
|
|
221
236
|
attrs.push(["data-track-index", formatTimelineAttributeNumber(change.track)]);
|
|
222
237
|
}
|
|
223
|
-
patchIframeDomTiming(previewIframeRef.current, change.element, attrs);
|
|
238
|
+
patchIframeDomTiming(previewIframeRef.current, change.element, attrs, activeCompPath);
|
|
224
239
|
}
|
|
225
240
|
|
|
241
|
+
// TRACK-ONLY batch: every change keeps its start (moves never carry a
|
|
242
|
+
// duration change), so nothing timing-related changed — the batch only
|
|
243
|
+
// rewrites data-track-index, which the renderer never reads (documented
|
|
244
|
+
// in core runtime/timeline.ts; track is a studio lane concept). The live
|
|
245
|
+
// DOM patch above + the gesture owner's optimistic store update fully
|
|
246
|
+
// cover the UI, so after the persist there is nothing to GSAP-shift and
|
|
247
|
+
// nothing for the preview to recompute: skip the fallback below entirely.
|
|
248
|
+
// Running it anyway is what made the mirrored z-order lane move blink —
|
|
249
|
+
// a zero-delta batch yields no scriptText, and finishGroupTimingGsapFallback
|
|
250
|
+
// used to full-reload the iframe when there was no script to soft-swap
|
|
251
|
+
// (it now rebinds the runtime timing in place, but a track-only batch
|
|
252
|
+
// needs NO preview sync at all, so the skip stays).
|
|
253
|
+
const trackOnly = changes.every((change) => change.start === change.element.start);
|
|
254
|
+
|
|
226
255
|
const maxEnd = Math.max(...changes.map((change) => change.start + change.element.duration));
|
|
227
256
|
// Snapshot the duration BEFORE the optimistic updates below so a failed
|
|
228
257
|
// persist can roll the readout + live root back (see captureDurationRollback).
|
|
229
258
|
const rollbackDuration = captureDurationRollback(previewIframeRef.current);
|
|
230
259
|
// needsExtension gates the SDK path (setTiming can't grow the root duration),
|
|
231
260
|
// so read the store BEFORE the readout sync below optimistically updates it.
|
|
261
|
+
// Track-only batches leave every clip end unchanged, so both this and the
|
|
262
|
+
// readout sync below are provable no-ops there — kept unconditional so the
|
|
263
|
+
// duration machinery stays on one code path.
|
|
232
264
|
const needsExtension = extendRootDurationIfNeeded(maxEnd);
|
|
233
265
|
// Optimistic duration readout: content-driven (grow AND shrink), read from
|
|
234
266
|
// the just-patched live DOM. See syncPreviewContentDuration.
|
|
235
267
|
syncPreviewContentDuration(previewIframeRef.current);
|
|
236
268
|
const coalesceKey = options?.coalesceKey ?? moveCoalesceKey(changes);
|
|
269
|
+
const coalesceMs = options?.coalesceMs;
|
|
237
270
|
return enqueueGroupOperation("Move timeline clips", async (projectId) => {
|
|
238
271
|
await options?.beforeTiming;
|
|
239
272
|
const handledBySdk = await trySdkBatchPersist({
|
|
@@ -243,6 +276,7 @@ export function useTimelineGroupEditing({
|
|
|
243
276
|
needsExtension,
|
|
244
277
|
label: "Move timeline clips",
|
|
245
278
|
coalesceKey,
|
|
279
|
+
coalesceMs,
|
|
246
280
|
});
|
|
247
281
|
if (handledBySdk) return;
|
|
248
282
|
|
|
@@ -261,7 +295,12 @@ export function useTimelineGroupEditing({
|
|
|
261
295
|
),
|
|
262
296
|
})),
|
|
263
297
|
coalesceKey,
|
|
298
|
+
coalesceMs,
|
|
264
299
|
);
|
|
300
|
+
// Track-only: no timing delta → no GSAP positions to shift and no
|
|
301
|
+
// reload (see the trackOnly doc above). Mixed batches (any start
|
|
302
|
+
// change) keep the full fallback below.
|
|
303
|
+
if (trackOnly) return;
|
|
265
304
|
await finishGroupTimingGsapFallback({
|
|
266
305
|
projectId,
|
|
267
306
|
iframe: previewIframeRef.current,
|
|
@@ -284,6 +323,7 @@ export function useTimelineGroupEditing({
|
|
|
284
323
|
// Failed persist: revert the optimistic duration readout + live root
|
|
285
324
|
// alongside the gesture owner's store rollback.
|
|
286
325
|
rollbackDuration();
|
|
326
|
+
showToast(getStudioSaveErrorMessage(error), "error");
|
|
287
327
|
throw error;
|
|
288
328
|
});
|
|
289
329
|
},
|
|
@@ -295,6 +335,7 @@ export function useTimelineGroupEditing({
|
|
|
295
335
|
recordEdit,
|
|
296
336
|
reloadPreview,
|
|
297
337
|
trySdkBatchPersist,
|
|
338
|
+
showToast,
|
|
298
339
|
],
|
|
299
340
|
);
|
|
300
341
|
|
|
@@ -313,7 +354,7 @@ export function useTimelineGroupEditing({
|
|
|
313
354
|
: "data-media-start";
|
|
314
355
|
liveAttrs.push([liveAttr, formatTimelineAttributeNumber(change.playbackStart)]);
|
|
315
356
|
}
|
|
316
|
-
patchIframeDomTiming(previewIframeRef.current, change.element, liveAttrs);
|
|
357
|
+
patchIframeDomTiming(previewIframeRef.current, change.element, liveAttrs, activeCompPath);
|
|
317
358
|
}
|
|
318
359
|
|
|
319
360
|
const maxEnd = Math.max(...changes.map((change) => change.start + change.duration));
|
|
@@ -327,6 +368,7 @@ export function useTimelineGroupEditing({
|
|
|
327
368
|
// the just-patched live DOM. See syncPreviewContentDuration.
|
|
328
369
|
syncPreviewContentDuration(previewIframeRef.current);
|
|
329
370
|
const coalesceKey = options?.coalesceKey ?? resizeCoalesceKey(changes);
|
|
371
|
+
const coalesceMs = options?.coalesceMs;
|
|
330
372
|
return enqueueGroupOperation("Resize timeline clips", async (projectId) => {
|
|
331
373
|
await options?.beforeTiming;
|
|
332
374
|
const handledBySdk = await trySdkBatchPersist({
|
|
@@ -339,6 +381,7 @@ export function useTimelineGroupEditing({
|
|
|
339
381
|
needsExtension,
|
|
340
382
|
label: "Resize timeline clips",
|
|
341
383
|
coalesceKey,
|
|
384
|
+
coalesceMs,
|
|
342
385
|
});
|
|
343
386
|
if (handledBySdk) return;
|
|
344
387
|
|
|
@@ -355,6 +398,7 @@ export function useTimelineGroupEditing({
|
|
|
355
398
|
}),
|
|
356
399
|
})),
|
|
357
400
|
coalesceKey,
|
|
401
|
+
coalesceMs,
|
|
358
402
|
);
|
|
359
403
|
await finishGroupTimingGsapFallback({
|
|
360
404
|
projectId,
|
|
@@ -387,6 +431,7 @@ export function useTimelineGroupEditing({
|
|
|
387
431
|
// Failed persist: revert the optimistic duration readout + live root
|
|
388
432
|
// alongside the gesture owner's store rollback.
|
|
389
433
|
rollbackDuration();
|
|
434
|
+
showToast(getStudioSaveErrorMessage(error), "error");
|
|
390
435
|
throw error;
|
|
391
436
|
});
|
|
392
437
|
},
|
|
@@ -398,6 +443,7 @@ export function useTimelineGroupEditing({
|
|
|
398
443
|
recordEdit,
|
|
399
444
|
reloadPreview,
|
|
400
445
|
trySdkBatchPersist,
|
|
446
|
+
showToast,
|
|
401
447
|
],
|
|
402
448
|
);
|
|
403
449
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback } from "react";
|
|
2
2
|
import type { Composition } from "@hyperframes/sdk";
|
|
3
|
-
import {
|
|
3
|
+
import { cutoverCommittedOrThrow, persistSdkCandidateMutation } from "../utils/sdkCutover";
|
|
4
4
|
import type { UseSlideshowPersistParams } from "./useSlideshowPersist";
|
|
5
5
|
|
|
6
6
|
/** Same single-writer dependency set the slideshow persist path uses. */
|
|
@@ -21,6 +21,7 @@ export function useVariablesPersist({
|
|
|
21
21
|
recordEdit,
|
|
22
22
|
reloadPreview,
|
|
23
23
|
domEditSaveTimestampRef,
|
|
24
|
+
publishSdkSession,
|
|
24
25
|
}: UseVariablesPersistParams): (
|
|
25
26
|
label: string,
|
|
26
27
|
mutate: (session: Composition) => void,
|
|
@@ -30,11 +31,8 @@ export function useVariablesPersist({
|
|
|
30
31
|
if (!sdkSession) return false;
|
|
31
32
|
const path = activeCompPath ?? "index.html";
|
|
32
33
|
const originalContent = await readProjectFile(path);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (after === originalContent) return false;
|
|
36
|
-
await persistSdkSerialize(
|
|
37
|
-
after,
|
|
34
|
+
const result = await persistSdkCandidateMutation(
|
|
35
|
+
sdkSession,
|
|
38
36
|
path,
|
|
39
37
|
originalContent,
|
|
40
38
|
{
|
|
@@ -43,10 +41,13 @@ export function useVariablesPersist({
|
|
|
43
41
|
reloadPreview,
|
|
44
42
|
domEditSaveTimestampRef,
|
|
45
43
|
compositionPath: activeCompPath,
|
|
44
|
+
readProjectFile,
|
|
45
|
+
publishSession: publishSdkSession,
|
|
46
46
|
},
|
|
47
|
+
mutate,
|
|
47
48
|
{ label },
|
|
48
49
|
);
|
|
49
|
-
return
|
|
50
|
+
return cutoverCommittedOrThrow(result);
|
|
50
51
|
},
|
|
51
52
|
[
|
|
52
53
|
sdkSession,
|
|
@@ -56,6 +57,7 @@ export function useVariablesPersist({
|
|
|
56
57
|
recordEdit,
|
|
57
58
|
reloadPreview,
|
|
58
59
|
domEditSaveTimestampRef,
|
|
60
|
+
publishSdkSession,
|
|
59
61
|
],
|
|
60
62
|
);
|
|
61
63
|
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
ArrowClockwise,
|
|
22
22
|
Gear,
|
|
23
23
|
Scissors as PhScissors,
|
|
24
|
+
Link as PhLink,
|
|
24
25
|
} from "@phosphor-icons/react";
|
|
25
26
|
import type { Icon as PhosphorIcon, IconProps as PhosphorIconProps } from "@phosphor-icons/react";
|
|
26
27
|
|
|
@@ -69,3 +70,4 @@ export const Camera = makeIcon(PhCamera);
|
|
|
69
70
|
export const RotateCw = makeIcon(ArrowClockwise);
|
|
70
71
|
export const Settings = makeIcon(Gear);
|
|
71
72
|
export const Scissors = makeIcon(PhScissors);
|
|
73
|
+
export const Link = makeIcon(PhLink);
|