mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
Merge pull request #2499 from heygen-com/task1-base-variable-defaults
feat(sdk): getVariableValue({ base: true }) reads pre-override declared defaults
This commit is contained in:
@@ -117,7 +117,7 @@ comp.setVariableValue("heroImage", { url: "/assets/hero.jpg", fit: "cover" });
|
||||
### `getVariableValue`
|
||||
|
||||
```typescript
|
||||
getVariableValue(id: string): string | number | boolean | FontValue | ImageValue | undefined
|
||||
getVariableValue(id: string, opts?: { base?: boolean }): string | number | boolean | FontValue | ImageValue | undefined
|
||||
```
|
||||
|
||||
Return a declared variable's current `default` value, or `undefined` if the id is undeclared or has no value set.
|
||||
@@ -126,6 +126,12 @@ Return a declared variable's current `default` value, or `undefined` if the id i
|
||||
const color = comp.getVariableValue("brandColor"); // "#6C5CE7"
|
||||
```
|
||||
|
||||
Pass `{ base: true }` to read the default **as authored at open** — before the
|
||||
T3 override-set or any `setVariableValue` folded into the declaration. This is
|
||||
the value to restore when a host replays an undo that removes a `var.<id>`
|
||||
override. For a variable declared mid-session, `{ base: true }` returns its
|
||||
live default (its declaration is its base).
|
||||
|
||||
### `listVariables`
|
||||
|
||||
```typescript
|
||||
@@ -753,4 +759,3 @@ comp.dispose();
|
||||
Template-driven products with host-owned history.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
|
||||
+36
-10
@@ -88,6 +88,13 @@ class CompositionImpl implements Composition {
|
||||
/** Accumulated override-set — T3 embedded mode fold contract. */
|
||||
private overrides: OverrideSet;
|
||||
|
||||
/**
|
||||
* Declared variable defaults as authored at open — captured BEFORE the
|
||||
* T3 override-set (and any later setVariableValue) folded into the
|
||||
* declarations. Serves getVariableValue({ base: true }).
|
||||
*/
|
||||
private readonly baseVariableDefaults: Record<string, unknown>;
|
||||
|
||||
/** Lazily-built element snapshot, invalidated on every mutation. */
|
||||
private elementsCache: ElementSnapshot[] | null = null;
|
||||
/** Lazily-built root snapshot (getRootElements), invalidated alongside elementsCache. */
|
||||
@@ -114,11 +121,16 @@ class CompositionImpl implements Composition {
|
||||
/** Override-set state at outermost batch entry — restored if the batch throws. */
|
||||
private batchOverridesSnapshot: OverrideSet = {};
|
||||
|
||||
constructor(parsed: ParsedDocument, opts: OpenCompositionOptions) {
|
||||
constructor(
|
||||
parsed: ParsedDocument,
|
||||
opts: OpenCompositionOptions,
|
||||
baseVariableDefaults: Record<string, unknown> = {},
|
||||
) {
|
||||
this.parsed = parsed;
|
||||
this.persist = opts.persist;
|
||||
this.preview = opts.preview;
|
||||
this.overrides = { ...(opts.overrides ?? {}) };
|
||||
this.baseVariableDefaults = baseVariableDefaults;
|
||||
this.previewSelectionUnsubscribe =
|
||||
this.preview?.on("selection", (ids) => this.updateSelection(ids)) ?? null;
|
||||
}
|
||||
@@ -169,14 +181,20 @@ class CompositionImpl implements Composition {
|
||||
// ── #2098 CRUD conveniences — thin aliases over the canonical surface below.
|
||||
// They delegate so the per-file declaration-element scope (template/fragment
|
||||
// sub-comps included) is resolved in exactly one place.
|
||||
getVariableValue(id: string): string | number | boolean | FontValue | ImageValue | undefined {
|
||||
return this.getVariableValues()[id] as
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| FontValue
|
||||
| ImageValue
|
||||
| undefined;
|
||||
getVariableValue(
|
||||
id: string,
|
||||
opts?: { base?: boolean },
|
||||
): string | number | boolean | FontValue | ImageValue | undefined {
|
||||
// { base: true } reads the declaration default as authored at open —
|
||||
// BEFORE the override-set / any setVariableValue folded into it. This
|
||||
// is the value an undo-to-base must restore; the live default IS the
|
||||
// override after a fold. Ids unseen at open (declared mid-session) fall
|
||||
// through to the live default — their declaration is their base.
|
||||
const source =
|
||||
opts?.base && id in this.baseVariableDefaults
|
||||
? this.baseVariableDefaults
|
||||
: this.getVariableValues();
|
||||
return source[id] as string | number | boolean | FontValue | ImageValue | undefined;
|
||||
}
|
||||
|
||||
listVariables(): CompositionVariable[] {
|
||||
@@ -877,11 +895,19 @@ export async function openComposition(
|
||||
// the query API derives element snapshots from it lazily.
|
||||
const parsed = parseMutable(html);
|
||||
|
||||
// Pre-override declared defaults — applyOverrideSet below folds `var.<id>`
|
||||
// overrides destructively into the declarations, so this is the last moment
|
||||
// the authored base values are readable. getVariableValue({ base: true })
|
||||
// serves them for the rest of the session (undo-to-base restores).
|
||||
const baseVariableDefaults = readDeclaredDefaults(
|
||||
declarationElement(parsed.document, parsed.wrapped),
|
||||
);
|
||||
|
||||
// T3 embedded: replay the stored override-set onto the base in one pass,
|
||||
// so the session exposes the user's exact edited state — not the template.
|
||||
if (opts?.overrides) applyOverrideSet(parsed, opts.overrides);
|
||||
|
||||
const session = new CompositionImpl(parsed, opts ?? {});
|
||||
const session = new CompositionImpl(parsed, opts ?? {}, baseVariableDefaults);
|
||||
|
||||
const isEmbedded = opts?.overrides !== undefined;
|
||||
|
||||
|
||||
@@ -138,3 +138,36 @@ describe("validateVariableValues", () => {
|
||||
expect(comp.validateVariableValues({ title: "still-a-string" })).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getVariableValue base defaults", () => {
|
||||
it("returns the pre-override declared default with { base: true }", async () => {
|
||||
// openComposition({overrides}) folds var.<id> into the declaration —
|
||||
// the live default becomes the override. base:true must still see
|
||||
// the authored value.
|
||||
const comp = await openComposition(BASE_HTML, {
|
||||
overrides: { "var.accent": "#FF0000" },
|
||||
});
|
||||
expect(comp.getVariableValue("accent")).toBe("#FF0000");
|
||||
expect(comp.getVariableValue("accent", { base: true })).toBe("#00C3FF");
|
||||
});
|
||||
|
||||
it("keeps the base default stable across live setVariableValue dispatches", async () => {
|
||||
const comp = await openComposition(BASE_HTML);
|
||||
comp.setVariableValue("accent", "#123456");
|
||||
expect(comp.getVariableValue("accent")).toBe("#123456");
|
||||
expect(comp.getVariableValue("accent", { base: true })).toBe("#00C3FF");
|
||||
});
|
||||
|
||||
it("returns undefined for an undeclared id with { base: true }", async () => {
|
||||
const comp = await openComposition(BASE_HTML);
|
||||
expect(comp.getVariableValue("never-declared", { base: true })).toBeUndefined();
|
||||
});
|
||||
|
||||
it("falls back to the live default for a variable declared mid-session", async () => {
|
||||
// A variable that did not exist at open has no pre-override snapshot —
|
||||
// its current declaration IS its base.
|
||||
const comp = await openComposition(BASE_HTML);
|
||||
comp.declareVariable({ id: "brand-title", type: "string", label: "Title", default: "Hi" });
|
||||
expect(comp.getVariableValue("brand-title", { base: true })).toBe("Hi");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -434,8 +434,16 @@ export interface Composition {
|
||||
/**
|
||||
* Current `default` value for a declared variable, or undefined if
|
||||
* undeclared/unset. Convenience over getVariableValues() (kept from #2098).
|
||||
*
|
||||
* `{ base: true }` returns the default as authored at open — BEFORE the
|
||||
* T3 override-set or any setVariableValue folded into the declaration.
|
||||
* Hosts replaying an undo that removes a `var.<id>` override should restore
|
||||
* this value. Ids declared mid-session fall through to the live default.
|
||||
*/
|
||||
getVariableValue(id: string): string | number | boolean | FontValue | ImageValue | undefined;
|
||||
getVariableValue(
|
||||
id: string,
|
||||
opts?: { base?: boolean },
|
||||
): string | number | boolean | FontValue | ImageValue | undefined;
|
||||
/**
|
||||
* Every declared variable's full schema (id/type/label/default/…), or [] when
|
||||
* none. Alias of getVariableDeclarations() (kept from #2098's surface).
|
||||
|
||||
Reference in New Issue
Block a user