mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-12 20:47:30 +00:00
fix: wrapper-aware element resolution for caption overlay
- getWordEl skips wrapper spans and finds actual word elements inside them - readWordBoxes handles wrapped words in position calculations - getOrCreateWrapper detects if element IS a wrapper to prevent double-wrapping - Remove debug logging from save Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
41367b8888
commit
3fd7497eda
@@ -53,10 +53,20 @@ function readWordBoxes(
|
||||
if (!groupEl) continue;
|
||||
const computed = win.getComputedStyle(groupEl);
|
||||
if (parseFloat(computed.opacity) <= 0.01 || computed.visibility === "hidden") continue;
|
||||
const wordEls = groupEl.querySelectorAll<HTMLElement>(":scope > span");
|
||||
// Find word spans — may be direct children or inside wrappers
|
||||
const resolvedWordEls: HTMLElement[] = [];
|
||||
for (const child of groupEl.children) {
|
||||
const c = child as HTMLElement;
|
||||
if (c.dataset.captionWrapper === "true") {
|
||||
const inner = c.querySelector<HTMLElement>(":scope > span");
|
||||
if (inner) resolvedWordEls.push(inner);
|
||||
} else if (c.tagName === "SPAN") {
|
||||
resolvedWordEls.push(c);
|
||||
}
|
||||
}
|
||||
for (let wi = 0; wi < group.segmentIds.length; wi++) {
|
||||
const segId = group.segmentIds[wi];
|
||||
const wordEl = wordEls[wi] as HTMLElement | undefined;
|
||||
const wordEl = resolvedWordEls[wi] as HTMLElement | undefined;
|
||||
if (!wordEl) continue;
|
||||
const rect = wordEl.getBoundingClientRect();
|
||||
boxes.push({
|
||||
@@ -77,7 +87,21 @@ function getWordEl(iframe: HTMLIFrameElement, groupIndex: number, wordIndex: num
|
||||
if (!doc) return null;
|
||||
const groupEl = doc.querySelectorAll<HTMLElement>(".caption-group")[groupIndex];
|
||||
if (!groupEl) return null;
|
||||
return groupEl.querySelectorAll<HTMLElement>(":scope > span")[wordIndex] ?? null;
|
||||
// Find word spans — they may be direct children or inside wrapper spans.
|
||||
// Word spans have class "word" or an id starting with "w".
|
||||
// Wrappers have data-caption-wrapper="true".
|
||||
const wordEls: HTMLElement[] = [];
|
||||
for (const child of groupEl.children) {
|
||||
const el = child as HTMLElement;
|
||||
if (el.dataset.captionWrapper === "true") {
|
||||
// Wrapped word — get the inner span
|
||||
const inner = el.querySelector<HTMLElement>(":scope > span");
|
||||
if (inner) wordEls.push(inner);
|
||||
} else if (el.tagName === "SPAN") {
|
||||
wordEls.push(el);
|
||||
}
|
||||
}
|
||||
return wordEls[wordIndex] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,8 +136,12 @@ function readGsapTransform(el: HTMLElement, iframeWin: Window): { x: number; y:
|
||||
* Transforms are applied to the wrapper so the word's GSAP animations are preserved.
|
||||
*/
|
||||
function getOrCreateWrapper(el: HTMLElement): HTMLElement {
|
||||
// If el IS a wrapper, return it
|
||||
if (el.dataset.captionWrapper === "true") return el;
|
||||
// If el's parent is a wrapper, return the parent
|
||||
const parent = el.parentElement;
|
||||
if (parent && parent.dataset.captionWrapper === "true") return parent;
|
||||
// Create new wrapper
|
||||
const doc = el.ownerDocument;
|
||||
const wrapper = doc.createElement("span");
|
||||
wrapper.style.display = "inline-block";
|
||||
|
||||
@@ -66,7 +66,6 @@ export function useCaptionSync(projectId: string | null) {
|
||||
if (!pid) return;
|
||||
|
||||
const overrides = buildOverrides(state.model);
|
||||
// Write to project root — the runtime fetches relative to <base href> which is the project root
|
||||
const overridesPath = "caption-overrides.json";
|
||||
|
||||
await fetch(
|
||||
|
||||
Reference in New Issue
Block a user