fix(studio): sub-composition child clips restack via self-contained intent

applyTimelineStackingReorder resolved each z-index change by looking the clip up
in the top-level timelineElements list, but sub-composition children live only
in the expanded list, so the lookup missed them and the reorder silently bailed.
Carry the element's locator (domId/selector/sourceFile) on each z-index change
so the commit resolves the live element directly from the preview DOM. Verified
E2E: dragging a clip inside a sub-composition restacks it and patches the
sub-comp source, while the parent composition is untouched.

Adds timelineEditingHelpers.test.ts (locator-based commit + audio no-op).
This commit is contained in:
Miguel Angel Simon Sierra
2026-07-08 23:46:26 -04:00
parent eef500c890
commit 82fe779bd8
4 changed files with 131 additions and 17 deletions
@@ -27,11 +27,18 @@ function layerContainsElement(layer: StackingTimelineLayer, key: string): boolea
function addElementChange(
changes: TimelineStackingZIndexChange[],
key: string,
currentZIndex: number,
element: TimelineStackingElement,
zIndex: number,
): void {
if (currentZIndex !== zIndex) changes.push({ key, zIndex });
if ((element.zIndex ?? 0) === zIndex) return;
changes.push({
key: getTimelineElementIdentity(element),
zIndex,
domId: element.domId,
selector: element.selector,
selectorIndex: element.selectorIndex,
sourceFile: element.sourceFile,
});
}
function addLayerChanges(
@@ -45,7 +52,7 @@ function addLayerChanges(
const key = getTimelineElementIdentity(element);
if (key === excludedKey) continue;
const before = changes.length;
addElementChange(changes, key, element.zIndex ?? 0, zIndex);
addElementChange(changes, element, zIndex);
if (changes.length > before) count += 1;
}
return count;
@@ -70,12 +77,7 @@ function resolvePlacementZIndexChanges(input: {
targetZIndex: number;
}): TimelineStackingZIndexChange[] {
const changes: TimelineStackingZIndexChange[] = [];
addElementChange(
changes,
getTimelineElementIdentity(input.element),
input.element.zIndex ?? 0,
input.targetZIndex,
);
addElementChange(changes, input.element, input.targetZIndex);
return changes;
}
@@ -9,6 +9,13 @@ export interface TimelineStackingElement {
stackingContextId?: string | null;
parentCompositionId?: string | null;
compositionAncestors?: string[];
// Locator for resolving the live element at commit time (sub-comp children
// aren't in the top-level element list, so the reorder intent must be
// self-contained rather than re-looked-up by identity).
domId?: string;
selector?: string;
selectorIndex?: number;
sourceFile?: string;
}
export interface TimelineStackingOrderItem {
@@ -29,6 +36,10 @@ export type TimelineLayerDropPlacement =
export interface TimelineStackingZIndexChange {
key: string;
zIndex: number;
domId?: string;
selector?: string;
selectorIndex?: number;
sourceFile?: string;
}
export interface TimelineStackingReorderIntent {