mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
feat(studio): expose resolved z-index and stacking context on timeline clips
This commit is contained in:
@@ -192,9 +192,12 @@ function domSiblingClips(
|
||||
start: host.start,
|
||||
duration: host.duration,
|
||||
track: host.track,
|
||||
zIndex: 0,
|
||||
stackingContextId: host.stackingContextId ?? host.domId ?? host.id ?? null,
|
||||
kind: "element",
|
||||
tagName: null,
|
||||
compositionId: null,
|
||||
compositionAncestors: host.compositionAncestors ?? [],
|
||||
parentCompositionId: host.id ?? null,
|
||||
compositionSrc: host.compositionSrc ?? null,
|
||||
assetUrl: null,
|
||||
|
||||
@@ -38,9 +38,12 @@ export interface ClipManifestClip {
|
||||
start: number;
|
||||
duration: number;
|
||||
track: number;
|
||||
zIndex?: number;
|
||||
stackingContextId?: string | null;
|
||||
kind: "video" | "audio" | "image" | "element" | "composition";
|
||||
tagName: string | null;
|
||||
compositionId: string | null;
|
||||
compositionAncestors?: string[];
|
||||
parentCompositionId: string | null;
|
||||
compositionSrc: string | null;
|
||||
assetUrl: string | null;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
import type { TimelineElement } from "../store/playerStore";
|
||||
import type { ClipManifestClip } from "./playbackTypes";
|
||||
import { getElementZIndex } from "./layerOrdering";
|
||||
import {
|
||||
resolveMediaElement,
|
||||
applyMediaMetadataFromElement,
|
||||
@@ -65,6 +66,40 @@ function resolveClipTag(clip: ClipManifestClip): string {
|
||||
return clip.tagName || clip.kind || "div";
|
||||
}
|
||||
|
||||
function resolveDomCompositionContext(
|
||||
element: Element,
|
||||
root: Element | null,
|
||||
): {
|
||||
parentCompositionId: string | null;
|
||||
compositionAncestors: string[];
|
||||
stackingContextId: string | null;
|
||||
} {
|
||||
const ancestors: string[] = [];
|
||||
let parentCompositionId: string | null = null;
|
||||
let cursor = element.parentElement;
|
||||
while (cursor) {
|
||||
const compositionId = cursor.getAttribute("data-composition-id");
|
||||
if (compositionId) {
|
||||
ancestors.push(compositionId);
|
||||
if (!parentCompositionId && cursor !== root) {
|
||||
parentCompositionId = compositionId;
|
||||
}
|
||||
}
|
||||
cursor = cursor.parentElement;
|
||||
}
|
||||
const compositionAncestors = ancestors.reverse();
|
||||
return {
|
||||
parentCompositionId,
|
||||
compositionAncestors,
|
||||
stackingContextId: parentCompositionId ?? compositionAncestors[0] ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
function getTimelineElementZIndex(element: Element | null): number | undefined {
|
||||
if (!element || !("style" in element)) return undefined;
|
||||
return getElementZIndex(element as HTMLElement);
|
||||
}
|
||||
|
||||
// fallow-ignore-next-line complexity
|
||||
export function createTimelineElementFromManifestClip(params: {
|
||||
clip: ClipManifestClip;
|
||||
@@ -86,6 +121,14 @@ export function createTimelineElementFromManifestClip(params: {
|
||||
let sourceFile: string | undefined;
|
||||
|
||||
let hfId: string | undefined;
|
||||
const domContext = hostEl
|
||||
? resolveDomCompositionContext(hostEl, doc?.querySelector("[data-composition-id]") ?? null)
|
||||
: null;
|
||||
const compositionAncestors = clip.compositionAncestors ?? domContext?.compositionAncestors;
|
||||
const parentCompositionId = clip.parentCompositionId ?? domContext?.parentCompositionId;
|
||||
const stackingContextId =
|
||||
clip.stackingContextId ?? parentCompositionId ?? compositionAncestors?.[0] ?? null;
|
||||
|
||||
if (hostEl) {
|
||||
domId = hostEl.id || undefined;
|
||||
hfId = hostEl.getAttribute("data-hf-id") || undefined;
|
||||
@@ -112,6 +155,10 @@ export function createTimelineElementFromManifestClip(params: {
|
||||
start: clip.start,
|
||||
duration: clip.duration,
|
||||
track: clip.track,
|
||||
zIndex: clip.zIndex ?? getTimelineElementZIndex(hostEl),
|
||||
stackingContextId,
|
||||
parentCompositionId,
|
||||
compositionAncestors,
|
||||
domId,
|
||||
hfId,
|
||||
selector,
|
||||
@@ -206,6 +253,7 @@ export function createImplicitTimelineLayersFromDOM(
|
||||
});
|
||||
if (existingKeys.has(identity.key) || existingKeys.has(identity.id)) continue;
|
||||
|
||||
const compositionContext = resolveDomCompositionContext(child, rootComp);
|
||||
layers.push({
|
||||
domId: child.id || undefined,
|
||||
hfId: child.getAttribute("data-hf-id") || undefined,
|
||||
@@ -217,6 +265,10 @@ export function createImplicitTimelineLayersFromDOM(
|
||||
selectorIndex,
|
||||
sourceFile,
|
||||
start: 0,
|
||||
zIndex: getTimelineElementZIndex(child),
|
||||
stackingContextId: compositionContext.stackingContextId,
|
||||
parentCompositionId: compositionContext.parentCompositionId,
|
||||
compositionAncestors: compositionContext.compositionAncestors,
|
||||
tag: child.tagName.toLowerCase(),
|
||||
timingSource: "implicit",
|
||||
track: maxTrack + 1 + layers.length,
|
||||
@@ -278,6 +330,7 @@ export function parseTimelineFromDOM(doc: Document, rootDuration: number): Timel
|
||||
selectorIndex,
|
||||
sourceFile,
|
||||
});
|
||||
const compositionContext = resolveDomCompositionContext(el, rootComp);
|
||||
const entry: TimelineElement = {
|
||||
id: identity.id,
|
||||
label,
|
||||
@@ -286,6 +339,10 @@ export function parseTimelineFromDOM(doc: Document, rootDuration: number): Timel
|
||||
start,
|
||||
duration: dur,
|
||||
track: isNaN(track) ? 0 : track,
|
||||
zIndex: getTimelineElementZIndex(el),
|
||||
stackingContextId: compositionContext.stackingContextId,
|
||||
parentCompositionId: compositionContext.parentCompositionId,
|
||||
compositionAncestors: compositionContext.compositionAncestors,
|
||||
domId: el.id || undefined,
|
||||
hfId: el.getAttribute("data-hf-id") || undefined,
|
||||
selector,
|
||||
@@ -406,6 +463,10 @@ export function buildStandaloneRootTimelineElement(params: {
|
||||
start: 0,
|
||||
duration: params.rootDuration,
|
||||
track: 0,
|
||||
zIndex: 0,
|
||||
stackingContextId: params.compositionId,
|
||||
parentCompositionId: null,
|
||||
compositionAncestors: [params.compositionId],
|
||||
compositionSrc,
|
||||
selector: params.selector,
|
||||
selectorIndex: params.selectorIndex,
|
||||
|
||||
@@ -28,6 +28,14 @@ export interface TimelineElement {
|
||||
start: number;
|
||||
duration: number;
|
||||
track: number;
|
||||
/** Resolved z-index for stacking-aware timeline ordering. */
|
||||
zIndex?: number;
|
||||
/** Stacking context this element belongs to; root clips use the root composition id. */
|
||||
stackingContextId?: string | null;
|
||||
/** Nearest parent composition context, matching RuntimeTimelineClip. */
|
||||
parentCompositionId?: string | null;
|
||||
/** Composition ancestry from root to nearest parent, matching RuntimeTimelineClip. */
|
||||
compositionAncestors?: string[];
|
||||
domId?: string;
|
||||
/** Stable `data-hf-id` attribute value — used as primary patch target when present */
|
||||
hfId?: string;
|
||||
|
||||
Reference in New Issue
Block a user