feat(configurator): metadata-driven token→domain classification (UX redesign, phase 2) - #692
Conversation
…ate in All tokens
Introduce src/lib/tokenModel.ts, the configurator's first-class understanding
of how tokens relate — derived from the framework manifest (role, aliasOf,
namespace, value) instead of re-guessing from names:
- roleOf: source | alias | output
- aliasTargetOf / referencesIn / pureVarTarget
- buildDependencyGraph: whole-catalogue dependsOn / usedBy
- SCALE_FAMILIES + scaleShadows: generalise scale-step shadow detection to
radius, border-width and motion (previously only text/space)
- validateTokenValue: reject empty / CSS-breaking values (closes the "--x: ;"
export hole) with optional CSS.supports probing in the browser
- tokenState: default | custom | relinked | detached | invalid
Wire it into the All tokens screen (TokenRow/AllTokensTab): each row now shows
a role badge, its alias source ("inherits X"), a "used by N" dependents count,
and an explicit Detached/Invalid warning with a one-click restore — directly
addressing the audit findings that outputs were editable like knobs with no
dependency context and detachment was invisible.
Adds tests/tokenModel.test.ts (34 tests incl. a guard over the real baked
catalogue). check, lint and all 244 unit tests pass.
…le source of truth) Replace the substring pattern matching in domains.ts with a deterministic classifier keyed on the framework-authored `namespace`. Overlapping fragments (e.g. "color" in --sf-focus-ring-color, "shadow" in --sf-drop-shadow-*) used to let a token match several domains at once; object key order silently picked the winner, and the All-tokens tab filtered by raw patterns while the sidebar badge and category Reset used first-match domainOf() — so they routinely disagreed about what belongs to a panel. - New src/data/domain-map.json: namespace→domain (one-to-one) + a tiny set of per-token exceptions for genuinely mixed namespaces (content/scroll/field). - domains.ts: classifyKnown()/domainOf()/inferNamespace()/DOMAINS, built from the manifest's own namespace with graceful name-inference fallback. - check-curation.mjs consumes the SAME domain-map.json, so the build guard and runtime can never drift. - AllTokensTab and GenericTokenPanel now filter by domainOf() (not patterns), so the list, the badge and the Reset scope are always identical. - Delete the obsolete domain-patterns.json. 78 tokens move to a more coherent home (all bug-fixes), e.g. drop-shadow-* Shadows→Effects (matches the Effects panel), animation/transition Misc→Motion, layout primitives (box/cover/equal/imposter/stack/sticky) Misc→Layout, btn/card →Components, border/field →Borders, focus-ring →Misc. Tests: rewrote domains.test.ts (21 tests incl. a real-catalogue guard that no token falls through and name-inference matches the framework namespace for all 734 tokens). check, lint, curation CLI and all 252 unit tests pass.
|
Warning Review limit reached
Next review available in: 57 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (11)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR replaces overlapping token-name pattern matching with deterministic namespace-based domain classification and introduces token-role, dependency, validation, and detached-state guidance.
Confidence Score: 4/5The valid-number validation defect should be fixed before merging because normal fractional scale overrides are incorrectly presented as unsafe and removable. Namespace classification is consistently centralized, but browser validation maps the broad Files Needing Attention: configurator/src/lib/tokenModel.ts, configurator/src/components/inputs/TokenRow.svelte, configurator/src/components/panels/AllTokensTab.svelte
|
| Filename | Overview |
|---|---|
| configurator/src/lib/domains.ts | Centralizes deterministic domain classification around manifest namespaces, explicit exceptions, and a Misc fallback. |
| configurator/src/data/domain-map.json | Defines the shared namespace-to-domain mapping and exceptions consumed by runtime and curation checks. |
| configurator/src/lib/tokenModel.ts | Adds role, graph, scale, and override-state modeling, but browser validation incorrectly rejects fractional <number> values through a z-index probe. |
| configurator/src/components/inputs/TokenRow.svelte | Displays role and relationship context plus detached/invalid warnings; it exposes the false invalid classification to users. |
| configurator/src/components/panels/AllTokensTab.svelte | Uses unified domain classification and adds dependency counts, although those counts remain based on defaults after overrides alter relationships. |
| configurator/scripts/check-curation.mjs | Migrates the curation guard to the shared namespace map while preserving orphan detection for public knobs. |
| configurator/tests/tokenModel.test.ts | Covers the new model extensively under Node, but does not exercise the browser-only CSS.supports validation branch. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Framework token metadata] --> B[domain-map.json]
A --> C[api-index.generated.json]
B --> D[classifyKnown / domainOf]
C --> D
D --> E[Sidebar counts and Reset scope]
D --> F[All Tokens and generic panels]
C --> G[Token role and dependency model]
H[Active overrides] --> I[tokenState validation]
G --> I
G --> J[Role and dependency guidance]
I --> K[Custom, relinked, detached, or invalid warning]
Reviews (1): Last reviewed commit: "feat(configurator): metadata-driven toke..." | Re-trigger Greptile
| if (s.includes("<color>")) return "color"; | ||
| if (s.includes("<length>") || s.includes("<length-percentage>")) return "width"; | ||
| if (s.includes("<percentage>")) return "width"; | ||
| if (s.includes("<number>") || s.includes("<integer>")) return "z-index"; |
There was a problem hiding this comment.
| const TIER_ORDER: Record<string, number> = { PUBLIC: 0, "PUBLIC-ADVANCED": 1, INTERNAL: 2 }; | ||
|
|
||
| // Whole-catalogue dependency graph (built once from the full token set, not | ||
| // just this domain's slice) so every row can show how many tokens read it. |
There was a problem hiding this comment.
Dependency counts ignore overrides
The dependency graph is built exclusively from catalogue defaults, so relinking a token or replacing a reference with a concrete override leaves the “used by N” guidance stale. Build the graph from effective values or label these counts as default-catalogue relationships.
Phase 2 of the configurator UX redesign — one deterministic classifier
The problem
Token→panel classification was substring matching over a hand-kept pattern list. Fragments overlapped —
coloris a substring of--sf-focus-ring-color,shadowof--sf-drop-shadow-*,-bg-of--sf-color-bg--active— so a token matched several domains at once and the order of the pattern object silently decided the winner. Worse, the All-tokens tab filtered by the raw patterns while the sidebar badge and the category Reset used first-matchdomainOf(), so the two routinely disagreed about which tokens belong to a panel (a specific audit finding).The fix
Classify on the framework-authored
namespace(the segment after--sf-), which is precise and one-to-one with a domain.src/data/domain-map.json—namespace → domainplus a tinyexceptionsmap for the handful of genuinely mixed namespaces (content,scroll,field).domains.ts—classifyKnown()/domainOf()/inferNamespace()/DOMAINS, built from the manifest's own namespace with graceful name-inference fallback for legacy/imported keys.check-curation.mjsconsumes the samedomain-map.json, so the build guard and the runtime can never drift.domainOf()instead of raw patterns — the list, the badge and the Reset scope are now always identical.domain-patterns.json.Move-diff (all bug-fixes, 78 tokens)
Every reclassification moves a token to where its control actually lives or to a more coherent home. Highlights:
--sf-drop-shadow-{xs,s,m,l,xl}(matches the Effects panel)--sf-animation-*,--sf-transition-*--sf-box-*,--sf-cover-padding,--sf-equal-gap,--sf-imposter-margin,--sf-stack-gap,--sf-sticky-offset*,--sf-breakout-width,--sf-center-max--sf-border{,-strong,-subtle},--sf-field-*--sf-btn-*font*--sf-body-color,--sf-heading-color--sf-shadow-color,--sf-shadow-glow-color--sf-focus-ring-colorVerification
npm run check: 0 errors ·npm run lint: clean ·node scripts/check-curation.mjs: OKnpm run test: 252/252 pass.domains.test.tsrewritten (21 tests) with a real-catalogue guard: no token falls through, and name inference matches the frameworknamespacefor all 734 tokens.drop-shadow-*/blur/opacity-*, and the category-Reset scope equals the badge scope.