mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
refactor(studio): resolve tween selector ids through the shared reader
The local extractIdFromSelector duplicated the `#id`-only regex that idFromSelector replaced, so both DOM-less paths in resolveSelectorElementIds (no-iframe fallback and querySelectorAll-throw recovery) read no id at all for the bracketed `[id="..."]` form writers emit for CSS-unsafe ids. Deleted the duplicate and imported the shared reader; both forms now resolve.
This commit is contained in:
@@ -90,4 +90,20 @@ describe("resolveSelectorElementIds", () => {
|
||||
expect(resolveSelectorElementIds("#card .label", null)).toEqual(["card"]);
|
||||
expect(resolveSelectorElementIds(".dot", null)).toEqual([]);
|
||||
});
|
||||
|
||||
// The `[id="…"]` form is what writers emit for a CSS-unsafe id (digit-leading,
|
||||
// dotted). The old local `#id`-only regex read no id at all for those, so they
|
||||
// silently dropped out of both DOM-less paths.
|
||||
it("falls back to a bracketed id when there is no DOM", () => {
|
||||
expect(resolveSelectorElementIds('[id="01-hook"] .label', null)).toEqual(["01-hook"]);
|
||||
});
|
||||
|
||||
it("falls back to a bracketed id when querySelectorAll rejects the selector", () => {
|
||||
const doc = {
|
||||
querySelectorAll: () => {
|
||||
throw new SyntaxError("bad selector");
|
||||
},
|
||||
} as unknown as Document;
|
||||
expect(resolveSelectorElementIds('[id="01-hook"]:has(>*)', doc)).toEqual(["01-hook"]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,25 +8,22 @@ import {
|
||||
clearKeyframeCacheForFile,
|
||||
writeGsapAnimationsForElement,
|
||||
} from "./gsapKeyframeCacheHelpers";
|
||||
import { toAbsoluteTime, toClipPercentage, toClipKeyframes } from "./gsapShared";
|
||||
import { idFromSelector, toAbsoluteTime, toClipPercentage, toClipKeyframes } from "./gsapShared";
|
||||
import {
|
||||
deduplicateKeyframes,
|
||||
isStaticPositionHold,
|
||||
synthesizeFlatTweenKeyframes,
|
||||
} from "./gsapTweenSynth";
|
||||
|
||||
function extractIdFromSelector(selector: string): string | null {
|
||||
const match = selector.match(/^#([\w-]+)/);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a tween's target selector to the ids of the element(s) it animates.
|
||||
* A bare `#id` resolves directly; anything else (a class like `.dot`, a group
|
||||
* `.a, .b`, or a descendant selector) is matched against the live preview DOM so
|
||||
* class/selector tweens (e.g. `gsap.from(".dot", {stagger})`) attribute to every
|
||||
* element they animate — not just one parsed from the string. Falls back to a
|
||||
* leading `#id` when there's no DOM (so the cache still populates pre-iframe).
|
||||
* element they animate — not just one parsed from the string. Falls back to the
|
||||
* leading id when there's no DOM (so the cache still populates pre-iframe);
|
||||
* `idFromSelector` reads both `#id` and the `[id="…"]` form writers emit for
|
||||
* CSS-unsafe ids, so those elements resolve pre-iframe too.
|
||||
*/
|
||||
// fallow-ignore-next-line complexity
|
||||
export function resolveSelectorElementIds(
|
||||
@@ -36,7 +33,7 @@ export function resolveSelectorElementIds(
|
||||
const bareId = selector.match(/^#([\w-]+)$/);
|
||||
if (bareId) return [bareId[1]];
|
||||
if (!doc) {
|
||||
const lead = extractIdFromSelector(selector);
|
||||
const lead = idFromSelector(selector);
|
||||
return lead ? [lead] : [];
|
||||
}
|
||||
const ids = new Set<string>();
|
||||
@@ -48,7 +45,7 @@ export function resolveSelectorElementIds(
|
||||
if (el.id) ids.add(el.id);
|
||||
}
|
||||
} catch {
|
||||
const lead = extractIdFromSelector(sel);
|
||||
const lead = idFromSelector(sel);
|
||||
if (lead) ids.add(lead);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user