feat(studio): disable move/resize/style editing for locked composition children

Elements inside a data-timeline-locked composition now have all
canvas interactions disabled (move, resize, manual offset/size/rotation,
style editing). Prevents "Unable to patch" errors when trying to move
JS-generated caption elements that can't be patched back to source.
This commit is contained in:
Miguel Ángel
2026-05-20 02:23:57 -04:00
parent ec66d59caa
commit 576598f5ad
2 changed files with 10 additions and 4 deletions
@@ -176,18 +176,21 @@ export function resolveDomEditCapabilities(args: {
inlineStyles: Record<string, string>;
computedStyles: Record<string, string>;
isCompositionHost: boolean;
isInsideLockedComposition: boolean;
isMasterView: boolean;
}): DomEditCapabilities {
if (!args.selector) {
if (!args.selector || args.isInsideLockedComposition) {
return {
canSelect: false,
canSelect: !args.isInsideLockedComposition,
canEditStyles: false,
canMove: false,
canResize: false,
canApplyManualOffset: false,
canApplyManualSize: false,
canApplyManualRotation: false,
reasonIfDisabled: "Studio could not resolve a stable patch target for this element.",
reasonIfDisabled: args.isInsideLockedComposition
? "This element belongs to a locked composition."
: "Studio could not resolve a stable patch target for this element.",
};
}
@@ -299,6 +302,7 @@ export function resolveDomEditSelection(
const inlineStyles = getInlineStyles(current);
const computedStyles = getCuratedComputedStyles(current);
const textFields = collectDomEditTextFields(current);
const isInsideLocked = Boolean(findClosestByAttribute(current, ["data-timeline-locked"]));
const capabilities = resolveDomEditCapabilities({
selector,
tagName: current.tagName.toLowerCase(),
@@ -306,6 +310,7 @@ export function resolveDomEditSelection(
inlineStyles,
computedStyles,
isCompositionHost: Boolean(compositionSrc),
isInsideLockedComposition: isInsideLocked,
isMasterView: options.isMasterView,
});
const rect = current.getBoundingClientRect();
@@ -319,7 +324,7 @@ export function resolveDomEditSelection(
compositionPath,
compositionSrc,
isCompositionHost: Boolean(compositionSrc),
isInsideLockedComposition: Boolean(findClosestByAttribute(current, ["data-timeline-locked"])),
isInsideLockedComposition: isInsideLocked,
label: buildElementLabel(current),
tagName: current.tagName.toLowerCase(),
boundingBox: {