mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-07 18:26:17 +00:00
fix(studio): never re-author a target the DOM proved is not unique
writeTargetSelector returned the selection's bare selector whenever the structural walk failed, including when a live DOM was there to check against. An element detached between selecting and committing takes that path, so the add re-authored the exact `.group` string the function exists to replace. Return null instead: a failed walk against a live DOM is evidence, not absence of it. Callers that cannot drop a user edit opt back in with `?? selectorFromSelection` where the trade is visible. The replace-with-keyframes paths had the mirror defect. The server deletes and re-adds the tween, so their target string is a full rewrite, and they derived it from the selection: promoting a set on a tween already narrowed to `#scene > div:nth-child(3)` widened it back onto every class sibling, undoing the narrowing an earlier add had made. They now keep the tween's own authored target, matching what eight sibling commit modules already do.
This commit is contained in:
@@ -13,7 +13,7 @@ import type { DomEditSelection } from "../components/editor/domEditingTypes";
|
||||
import { usePlayerStore } from "../player/store/playerStore";
|
||||
import { fetchParsedAnimations, getAnimationsForElement } from "./useGsapTweenCache";
|
||||
import {
|
||||
selectorFromSelection,
|
||||
existingTweenTargetSelector,
|
||||
computeElementPercentage,
|
||||
KEYFRAME_PCT_MATCH,
|
||||
isInstantHold,
|
||||
@@ -251,7 +251,10 @@ async function extendKeyframedTweenToPlayhead(
|
||||
iframe: HTMLIFrameElement | null,
|
||||
commitOverrides?: Partial<CommitMutationOptions>,
|
||||
): Promise<void> {
|
||||
const selector = selectorFromSelection(sel);
|
||||
// Re-authoring an EXISTING tween: keep the target it already writes rather
|
||||
// than re-deriving one from the selection, which would widen a tween already
|
||||
// narrowed to one element back onto its class siblings (existingTweenTargetSelector).
|
||||
const selector = existingTweenTargetSelector(anim, sel);
|
||||
const position = readElementPosition(iframe, sel, anim);
|
||||
if (!selector || Object.keys(position).length === 0 || !session.commitMutation) return;
|
||||
const extended = buildExtendedKeyframes(anim, currentTime, position, duration);
|
||||
@@ -336,7 +339,10 @@ export async function promoteSetToKeyframes(
|
||||
t: number,
|
||||
iframe: HTMLIFrameElement | null,
|
||||
): Promise<void> {
|
||||
const selector = selectorFromSelection(sel);
|
||||
// Re-authoring an EXISTING tween: keep the target it already writes rather
|
||||
// than re-deriving one from the selection, which would widen a tween already
|
||||
// narrowed to one element back onto its class siblings (existingTweenTargetSelector).
|
||||
const selector = existingTweenTargetSelector(setAnim, sel);
|
||||
const setStart = resolveTweenStart(setAnim) ?? 0;
|
||||
if (!selector || !session.commitMutation) return;
|
||||
// Playhead at or before the set → there's no forward range to promote into.
|
||||
@@ -390,7 +396,10 @@ export async function applyArcKeyframeAtPlayhead(
|
||||
iframe: HTMLIFrameElement | null,
|
||||
): Promise<void> {
|
||||
if (!session.commitMutation) return;
|
||||
const targetSelector = selectorFromSelection(sel);
|
||||
// Re-authoring an EXISTING tween: keep the target it already writes rather
|
||||
// than re-deriving one from the selection, which would widen a tween already
|
||||
// narrowed to one element back onto its class siblings (existingTweenTargetSelector).
|
||||
const targetSelector = existingTweenTargetSelector(arcAnim, sel);
|
||||
if (!targetSelector) return;
|
||||
const start = resolveTweenStart(arcAnim) ?? 0;
|
||||
const duration = resolveEditableTweenDuration(arcAnim, sel);
|
||||
|
||||
Reference in New Issue
Block a user