@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
|
@@ -2,6 +2,7 @@ import type { ParsedGsap } from "@hyperframes/core/gsap-parser";
|
|
|
2
2
|
import type { Composition } from "@hyperframes/sdk";
|
|
3
3
|
import type { DomEditSelection } from "../components/editor/domEditingTypes";
|
|
4
4
|
import type { EditHistoryKind } from "../utils/editHistory";
|
|
5
|
+
import type { PublishSdkSession } from "../utils/sdkCutover";
|
|
5
6
|
import type { RuntimeTweenChange } from "./gsapRuntimePatch";
|
|
6
7
|
|
|
7
8
|
export interface MutationResult {
|
|
@@ -22,10 +23,9 @@ export interface CommitMutationOptions {
|
|
|
22
23
|
beforeReload?: () => void;
|
|
23
24
|
/**
|
|
24
25
|
* Serialize this commit against others sharing the same key. Used to chain
|
|
25
|
-
* per-animationId GSAP meta updates
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* (and under distinct keys) run concurrently as before.
|
|
26
|
+
* per-animationId GSAP meta updates. Every commit independently takes the
|
|
27
|
+
* project/file mutation lock, so this key only adds ordering and can never
|
|
28
|
+
* bypass whole-file serialization.
|
|
29
29
|
*/
|
|
30
30
|
serializeKey?: string;
|
|
31
31
|
/**
|
|
@@ -87,6 +87,8 @@ export interface GsapScriptCommitsParams {
|
|
|
87
87
|
showToast: (message: string, tone?: "error" | "info") => void;
|
|
88
88
|
/** Stage 7 §3.5: SDK session for routing GSAP tween ops through addGsapTween/setGsapTween/removeGsapTween. */
|
|
89
89
|
sdkSession?: Composition | null;
|
|
90
|
+
/** Publish a fully persisted candidate SDK session. */
|
|
91
|
+
publishSdkSession?: PublishSdkSession;
|
|
90
92
|
writeProjectFile?: (path: string, content: string) => Promise<void>;
|
|
91
93
|
/** Resync the in-memory SDK session after a server-authoritative write. */
|
|
92
94
|
forceReloadSdkSession?: () => void;
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
buildTimelineMoveTimingPatch,
|
|
6
6
|
deleteSelectedKeyframes,
|
|
7
7
|
extendRootDurationIfNeeded,
|
|
8
|
+
patchIframeDomTiming,
|
|
8
9
|
persistTimelineBatchEdit,
|
|
9
10
|
type PersistTimelineBatchChange,
|
|
10
11
|
} from "./timelineEditingHelpers";
|
|
@@ -42,7 +43,11 @@ describe("applyTimelineStackingReorder", () => {
|
|
|
42
43
|
it("commits via the change's own locator even when the element is not in timelineElements", () => {
|
|
43
44
|
// Sub-comp children live in the preview iframe but NOT in the top-level
|
|
44
45
|
// timelineElements list — the intent must be self-contained.
|
|
45
|
-
const iframe = makeIframeWith(
|
|
46
|
+
const iframe = makeIframeWith(`
|
|
47
|
+
<div data-composition-id="scene" data-composition-file="scenes/scene.html">
|
|
48
|
+
<div id="chip" style="z-index: 1"></div>
|
|
49
|
+
</div>
|
|
50
|
+
`);
|
|
46
51
|
const commit = vi.fn<(entries: unknown[]) => void>();
|
|
47
52
|
|
|
48
53
|
applyTimelineStackingReorder({
|
|
@@ -96,6 +101,92 @@ describe("applyTimelineStackingReorder", () => {
|
|
|
96
101
|
|
|
97
102
|
expect(commit).not.toHaveBeenCalled();
|
|
98
103
|
});
|
|
104
|
+
|
|
105
|
+
it("resolves selectorIndex within the change's source file", () => {
|
|
106
|
+
const iframe = makeIframeWith(`
|
|
107
|
+
<div data-composition-id="root">
|
|
108
|
+
<div class="chip">root</div>
|
|
109
|
+
<div data-composition-id="scene" data-composition-file="scenes/scene.html">
|
|
110
|
+
<div class="chip">scene zero</div>
|
|
111
|
+
<div class="chip" style="z-index: 1">scene one</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
`);
|
|
115
|
+
const sceneOne = iframe.contentDocument?.querySelectorAll(".chip")[2];
|
|
116
|
+
const commit = vi.fn<(entries: unknown[]) => void>();
|
|
117
|
+
|
|
118
|
+
applyTimelineStackingReorder({
|
|
119
|
+
element: el({ id: "scene-one", tag: "div" }),
|
|
120
|
+
stackingReorder: {
|
|
121
|
+
contextKey: "scene",
|
|
122
|
+
placement: { type: "above", layerId: "layer:scene:x" },
|
|
123
|
+
zIndexChanges: [
|
|
124
|
+
{
|
|
125
|
+
key: "scenes/scene.html#.chip:1",
|
|
126
|
+
zIndex: 5,
|
|
127
|
+
selector: ".chip",
|
|
128
|
+
selectorIndex: 1,
|
|
129
|
+
sourceFile: "scenes/scene.html",
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
timelineElements: [],
|
|
134
|
+
iframe,
|
|
135
|
+
activeCompPath: "index.html",
|
|
136
|
+
commit,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const entries = commit.mock.calls[0]![0] as Array<{ element: Element }>;
|
|
140
|
+
expect(entries[0]!.element).toBe(sceneOne);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("patchIframeDomTiming", () => {
|
|
145
|
+
it("resolves selectorIndex within the element's source file", () => {
|
|
146
|
+
const iframe = makeIframeWith(`
|
|
147
|
+
<div data-composition-id="root">
|
|
148
|
+
<div class="clip" data-start="1">root</div>
|
|
149
|
+
<div data-composition-id="scene" data-composition-file="scenes/scene.html">
|
|
150
|
+
<div class="clip" data-start="2">scene zero</div>
|
|
151
|
+
<div class="clip" data-start="3">scene one</div>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
`);
|
|
155
|
+
const clips = iframe.contentDocument?.querySelectorAll<HTMLElement>(".clip");
|
|
156
|
+
const target = el({
|
|
157
|
+
id: "scene-one",
|
|
158
|
+
tag: "div",
|
|
159
|
+
selector: ".clip",
|
|
160
|
+
selectorIndex: 1,
|
|
161
|
+
sourceFile: "scenes/scene.html",
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
patchIframeDomTiming(iframe, target, [["data-start", "9"]], "index.html");
|
|
165
|
+
|
|
166
|
+
expect([...clips!].map((clip) => clip.dataset.start)).toEqual(["1", "2", "9"]);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("resolves duplicate domId within the element's source file", () => {
|
|
170
|
+
const iframe = makeIframeWith(`
|
|
171
|
+
<div data-composition-id="root">
|
|
172
|
+
<div id="card" data-start="1">root</div>
|
|
173
|
+
<div data-composition-id="scene" data-composition-file="scenes/scene.html">
|
|
174
|
+
<div id="card" data-start="2">scene</div>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
`);
|
|
178
|
+
const cards = iframe.contentDocument?.querySelectorAll<HTMLElement>("#card");
|
|
179
|
+
const target = el({
|
|
180
|
+
id: "scene-card",
|
|
181
|
+
tag: "div",
|
|
182
|
+
domId: "card",
|
|
183
|
+
sourceFile: "scenes/scene.html",
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
patchIframeDomTiming(iframe, target, [["data-start", "9"]], "index.html");
|
|
187
|
+
|
|
188
|
+
expect([...cards!].map((card) => card.dataset.start)).toEqual(["1", "9"]);
|
|
189
|
+
});
|
|
99
190
|
});
|
|
100
191
|
|
|
101
192
|
describe("extendRootDurationIfNeeded", () => {
|
|
@@ -13,6 +13,7 @@ import { saveProjectFilesWithHistory, type RecordEditInput } from "../utils/stud
|
|
|
13
13
|
import type { TimelineZIndexReorderCommit } from "./useTimelineEditingTypes";
|
|
14
14
|
import { setCompositionDurationToContent } from "../utils/timelineAssetDrop";
|
|
15
15
|
import { readFileContent } from "./timelineTimingSync";
|
|
16
|
+
import { findElementForSelection } from "../components/editor/domEditingElement";
|
|
16
17
|
export { deleteSelectedKeyframes } from "./deleteSelectedKeyframes";
|
|
17
18
|
export { readFileContent };
|
|
18
19
|
function isHTMLElement(element: Element | null): element is HTMLElement {
|
|
@@ -53,12 +54,6 @@ export function applyTimelineStackingReorder(input: {
|
|
|
53
54
|
input.timelineElements.map((el) => [getTimelineElementIdentity(el), el]),
|
|
54
55
|
);
|
|
55
56
|
const doc = input.iframe?.contentDocument ?? null;
|
|
56
|
-
const findLive = (domId?: string, selector?: string, selectorIndex?: number): Element | null => {
|
|
57
|
-
if (!doc) return null;
|
|
58
|
-
if (domId) return doc.getElementById(domId);
|
|
59
|
-
if (selector) return doc.querySelectorAll(selector)[selectorIndex ?? 0] ?? null;
|
|
60
|
-
return null;
|
|
61
|
-
};
|
|
62
57
|
const commitEntries: Array<{
|
|
63
58
|
element: HTMLElement;
|
|
64
59
|
zIndex: number;
|
|
@@ -73,7 +68,15 @@ export function applyTimelineStackingReorder(input: {
|
|
|
73
68
|
const domId = change.domId ?? sibling?.domId;
|
|
74
69
|
const selector = change.selector ?? sibling?.selector;
|
|
75
70
|
const selectorIndex = change.selectorIndex ?? sibling?.selectorIndex;
|
|
76
|
-
const
|
|
71
|
+
const sourceFile =
|
|
72
|
+
change.sourceFile ?? sibling?.sourceFile ?? input.activeCompPath ?? "index.html";
|
|
73
|
+
const element = doc
|
|
74
|
+
? findElementForSelection(
|
|
75
|
+
doc,
|
|
76
|
+
{ id: domId, selector, selectorIndex, sourceFile },
|
|
77
|
+
input.activeCompPath,
|
|
78
|
+
)
|
|
79
|
+
: null;
|
|
77
80
|
if (!isHTMLElement(element)) return Promise.resolve();
|
|
78
81
|
if (getElementZIndex(element) === change.zIndex) continue;
|
|
79
82
|
commitEntries.push({
|
|
@@ -82,12 +85,15 @@ export function applyTimelineStackingReorder(input: {
|
|
|
82
85
|
id: domId ?? sibling?.id ?? change.key,
|
|
83
86
|
selector,
|
|
84
87
|
selectorIndex,
|
|
85
|
-
sourceFile
|
|
88
|
+
sourceFile,
|
|
86
89
|
key: change.key,
|
|
87
90
|
});
|
|
88
91
|
}
|
|
89
92
|
if (commitEntries.length === 0) return Promise.resolve();
|
|
90
|
-
|
|
93
|
+
// The durability report is for gesture-level callers (z→lane mirror); this
|
|
94
|
+
// lane-drag z-sync path has no dependent follow-up write — swallow it.
|
|
95
|
+
// Promise.resolve-wrapped: a commit implementation may return void.
|
|
96
|
+
return Promise.resolve(input.commit?.(commitEntries, input.coalesceKey)).then(() => undefined);
|
|
91
97
|
}
|
|
92
98
|
export function extendRootDurationIfNeeded(newEnd: number): boolean {
|
|
93
99
|
const store = usePlayerStore.getState();
|
|
@@ -126,15 +132,22 @@ export type PatchTarget = NonNullable<ReturnType<typeof buildPatchTarget>>;
|
|
|
126
132
|
export function findTimelineElementInIframe(
|
|
127
133
|
iframe: HTMLIFrameElement | null,
|
|
128
134
|
element: TimelineElement,
|
|
135
|
+
activeCompositionPath: string | null = null,
|
|
129
136
|
): Element | null {
|
|
130
137
|
try {
|
|
131
138
|
const doc = iframe?.contentDocument;
|
|
132
139
|
if (!doc) return null;
|
|
133
|
-
return
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
:
|
|
140
|
+
return findElementForSelection(
|
|
141
|
+
doc,
|
|
142
|
+
{
|
|
143
|
+
hfId: element.hfId,
|
|
144
|
+
id: element.domId,
|
|
145
|
+
selector: element.selector,
|
|
146
|
+
selectorIndex: element.selectorIndex,
|
|
147
|
+
sourceFile: element.sourceFile || activeCompositionPath || "index.html",
|
|
148
|
+
},
|
|
149
|
+
activeCompositionPath,
|
|
150
|
+
);
|
|
138
151
|
} catch {
|
|
139
152
|
return null;
|
|
140
153
|
}
|
|
@@ -143,9 +156,10 @@ export function patchIframeDomTiming(
|
|
|
143
156
|
iframe: HTMLIFrameElement | null,
|
|
144
157
|
element: TimelineElement,
|
|
145
158
|
attrs: Array<[string, string]>,
|
|
159
|
+
activeCompositionPath: string | null = null,
|
|
146
160
|
): void {
|
|
147
161
|
try {
|
|
148
|
-
const el = findTimelineElementInIframe(iframe, element);
|
|
162
|
+
const el = findTimelineElementInIframe(iframe, element, activeCompositionPath);
|
|
149
163
|
if (!el) return;
|
|
150
164
|
for (const [name, value] of attrs) el.setAttribute(name, value);
|
|
151
165
|
} catch {
|
|
@@ -299,6 +313,8 @@ export interface PersistTimelineBatchEditInput {
|
|
|
299
313
|
domEditSaveTimestampRef: React.MutableRefObject<number>;
|
|
300
314
|
pendingTimelineEditPathRef: React.MutableRefObject<Set<string>>;
|
|
301
315
|
coalesceKey?: string;
|
|
316
|
+
/** Per-entry undo coalesce window override (ms) — see EditHistoryEntry.coalesceMs. */
|
|
317
|
+
coalesceMs?: number;
|
|
302
318
|
}
|
|
303
319
|
|
|
304
320
|
export async function persistTimelineBatchEdit(
|
|
@@ -347,6 +363,7 @@ export async function persistTimelineBatchEdit(
|
|
|
347
363
|
label: input.label,
|
|
348
364
|
kind: "timeline",
|
|
349
365
|
coalesceKey: input.coalesceKey,
|
|
366
|
+
coalesceMs: input.coalesceMs,
|
|
350
367
|
files,
|
|
351
368
|
readFile: async (path) => originals.get(path) ?? readFileContent(input.projectId, path),
|
|
352
369
|
writeFile: input.writeProjectFile,
|
|
@@ -23,6 +23,7 @@ export function persistTimelineMoveEditsAtomically(
|
|
|
23
23
|
coalesceKey: string | undefined,
|
|
24
24
|
operation: TimelineMoveOperation,
|
|
25
25
|
deps: AtomicMoveDeps,
|
|
26
|
+
coalesceMs?: number,
|
|
26
27
|
): Promise<void> {
|
|
27
28
|
return deps.handleTimelineGroupMove(
|
|
28
29
|
edits.map(({ element, updates }) => ({
|
|
@@ -34,6 +35,6 @@ export function persistTimelineMoveEditsAtomically(
|
|
|
34
35
|
// ("timing") omit it so they stay eligible for the SDK fast path.
|
|
35
36
|
track: operation === "timing" ? undefined : updates.track,
|
|
36
37
|
})),
|
|
37
|
-
{ coalesceKey },
|
|
38
|
+
{ coalesceKey, coalesceMs },
|
|
38
39
|
);
|
|
39
40
|
}
|