mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
fix(studio): persist canvas z-order actions correctly for static elements
An adversarial review of the canvas context-menu z-order pipeline (Bring to Front / Forward / Backward / Send to Back) found the resolver math sound but the glue between the menu and the commit hook broken: - The menu optimistically wrote style.zIndex AND position: relative to the live elements BEFORE the commit hook ran. The hook decides whether to persist position by checking getComputedStyle(el).position === 'static' — always false after the pre-apply — so the position patch was never persisted on the menu path and the reorder silently reverted at the post-commit reload for any nested/static element (root clips survive only because the runtime forces position:absolute). The same pre-apply made the failure rollback capture the already-mutated values, restoring the broken state on persist errors. The menu no longer pre-applies; the hook owns the live writes (it already applied both synchronously) and now sees true priors. Siblings without a persistable identity still get their z applied live-only so a renumber stays visually coherent. - The commit hook's entry.key store-sync plumbing had zero production callers; the store zIndex went stale until full reload. All three callers (canvas menu via PreviewOverlays, timeline lane z-sync, LayersPanel) now derive and pass the timeline store key (new deriveTimelineStoreKey helper). - patchElementBatch discarded the server's per-patch matched[]; unresolvable siblings persisted partially and silently. Unmatched targets now warn and report save-failure telemetry (z-reorder-unmatched) without rolling back the matched subset. - template/noscript elements counted as painting siblings, so renumber fallbacks wrote z-index/position into <template> tags in the source file. Excluded from the sibling family. - The default undo coalesce key merged DISTINCT z actions within 300ms into one undo entry; the action kind is now part of the key (LayersPanel drags keep coalescing within a drag; explicit lane-move gesture keys untouched). - rectsIntersect comment claimed touching rects intersect; the strict inequalities say otherwise — comment fixed.
This commit is contained in:
@@ -81,8 +81,18 @@ function isElementNode(node: Node): node is HTMLElement {
|
||||
* z-index onto the qa-clean audio element, and counting it as a sibling skews the
|
||||
* renumber for the visible elements. `<script>/<style>/<link>/<meta>` are also
|
||||
* non-painting and could otherwise pad the family / eat a z slot.
|
||||
* `<template>/<noscript>` never paint either — letting them in meant renumber
|
||||
* fallbacks wrote z-index/position into template source markup.
|
||||
*/
|
||||
const NON_PAINTING_TAGS = new Set(["AUDIO", "SCRIPT", "STYLE", "LINK", "META"]);
|
||||
const NON_PAINTING_TAGS = new Set([
|
||||
"AUDIO",
|
||||
"SCRIPT",
|
||||
"STYLE",
|
||||
"LINK",
|
||||
"META",
|
||||
"TEMPLATE",
|
||||
"NOSCRIPT",
|
||||
]);
|
||||
|
||||
/** A painting element: an element node whose tag actually renders pixels. */
|
||||
function isPaintingElement(node: Node): node is HTMLElement {
|
||||
@@ -112,7 +122,7 @@ function getFamily(target: HTMLElement): { entries: RenderEntry[]; targetIndex:
|
||||
return { entries, targetIndex };
|
||||
}
|
||||
|
||||
/** True if two DOM bounding rects intersect (even if touching). */
|
||||
/** True if two DOM bounding rects strictly overlap (rects that merely touch do NOT intersect). */
|
||||
function rectsIntersect(
|
||||
a: { left: number; top: number; right: number; bottom: number },
|
||||
b: { left: number; top: number; right: number; bottom: number },
|
||||
|
||||
Reference in New Issue
Block a user