mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
fix(core,cli,lint): close the figma brand-token loop — runtime CSS variables, --name, snippet lint
Brand-loop live test (SDS duplicate, plans/figma/brand-loop-test-plan.md) proved the recolor chain end-to-end and surfaced three gaps: - runtime now defines every declared composition variable as a CSS custom property (document root at init + scoped sub-comp hosts in the loader), so imported var(--slug, literal) fills resolve live — without this the frozen literal always won and variable-driven rebranding could not propagate. Slug kept byte-compatible with the figma importer (parity test). render --variables overrides win. - figma component --name: variant frames are often all named 'Platform=Desktop' and slug-collided across imports. - imported fragments carry data-hf-snippet and the project linter skips composition-root rules for them. - /figma skill documents the field-tested non-Enterprise tokens path (MCP get_variable_defs joined with REST boundVariables ids). Shared-helper extractions (injectScopedStyles, flattenedRoot module, parseHostVariableValues, rasterizeFallback, shapeCss) satisfy the dedup/complexity audit the runtime changes tripped. Validated live: brand-loop renders purple from the attribute alone (no manual :root); 118 figma + 662 runtime/compiler + 331 lint tests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
80271863d3
commit
def276524b
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* THE slug for composition-variable ids → CSS custom-property names. Shared
|
||||
* by the figma importer (emits `var(--<slug>, literal)`) and the runtime
|
||||
* (defines `--<slug>` from declared variables) — one function so the two
|
||||
* sides can never drift. The slug is lossy (case-folded, symbol runs
|
||||
* collapse to "-"), so distinct ids CAN collide; callers surface
|
||||
* detectSlugCollisions() as a warning rather than silently merging.
|
||||
*/
|
||||
|
||||
export function slugify(name: string): string {
|
||||
const slug = name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
return slug.length > 0 ? slug : "node";
|
||||
}
|
||||
|
||||
export function cssVariableName(id: string): string {
|
||||
return `--${slugify(id)}`;
|
||||
}
|
||||
|
||||
/** Groups of distinct ids that collapse to the same CSS variable name. */
|
||||
export function detectSlugCollisions(ids: Iterable<string>): string[][] {
|
||||
const bySlug = new Map<string, string[]>();
|
||||
for (const id of ids) {
|
||||
const slug = cssVariableName(id);
|
||||
const group = bySlug.get(slug);
|
||||
if (group) {
|
||||
if (!group.includes(id)) group.push(id);
|
||||
} else {
|
||||
bySlug.set(slug, [id]);
|
||||
}
|
||||
}
|
||||
return [...bySlug.values()].filter((g) => g.length > 1);
|
||||
}
|
||||
Reference in New Issue
Block a user