Skip to content

feat(configurator): metadata-driven token→domain classification (UX redesign, phase 2) - #692

Merged
jackgranatowski merged 5 commits into
mainfrom
ux/configurator-metadata-classification
Aug 20, 2026
Merged

jackgranatowski merged 5 commits into
mainfrom
ux/configurator-metadata-classification

Conversation

@jackgranatowski

Copy link
Copy Markdown
Contributor

Phase 2 of the configurator UX redesign — one deterministic classifier

Stacked on #691 (phase 1). Review/merge #691 first; this branch includes its commit.

The problem

Token→panel classification was substring matching over a hand-kept pattern list. Fragments overlapped — color is a substring of --sf-focus-ring-color, shadow of --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-match domainOf(), 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.jsonnamespace → domain plus a tiny exceptions map for the handful of genuinely mixed namespaces (content, scroll, field).
  • domains.tsclassifyKnown() / domainOf() / inferNamespace() / DOMAINS, built from the manifest's own namespace with graceful name-inference fallback for legacy/imported keys.
  • check-curation.mjs consumes the same domain-map.json, so the build guard and the runtime can never drift.
  • AllTokensTab and GenericTokenPanel now filter by domainOf() instead of raw patterns — the list, the badge and the Reset scope are now always identical.
  • Deleted the obsolete 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:

From → To Examples
Shadows → Effects --sf-drop-shadow-{xs,s,m,l,xl} (matches the Effects panel)
Misc → Motion all --sf-animation-*, --sf-transition-*
Misc → Layout --sf-box-*, --sf-cover-padding, --sf-equal-gap, --sf-imposter-margin, --sf-stack-gap, --sf-sticky-offset*, --sf-breakout-width, --sf-center-max
Misc → Borders --sf-border{,-strong,-subtle}, --sf-field-*
Typography → Components --sf-btn-*font*
Colors → Typography --sf-body-color, --sf-heading-color
Colors → Shadows --sf-shadow-color, --sf-shadow-glow-color
Colors → Misc --sf-focus-ring-color

Verification

  • npm run check: 0 errors · npm run lint: clean · node scripts/check-curation.mjs: OK
  • npm run test: 252/252 pass. domains.test.ts rewritten (21 tests) with a real-catalogue guard: no token falls through, and name inference matches the framework namespace for all 734 tokens.
  • Screenshot-verified in Chromium: Effects now lists all drop-shadow-*/blur/opacity-*, and the category-Reset scope equals the badge scope.

…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.
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jackgranatowski, you've reached your PR review limit, so we couldn't start this review.

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 @coderabbitai review or push new commits to the PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 54886776-3e0c-4dbf-866d-1f9ff7110a5a

📥 Commits

Reviewing files that changed from the base of the PR and between 83753b2 and 5d6707b.

📒 Files selected for processing (11)
  • configurator/scripts/check-curation.mjs
  • configurator/src/components/DomainPanel.svelte
  • configurator/src/components/inputs/TokenRow.svelte
  • configurator/src/components/panels/AllTokensTab.svelte
  • configurator/src/components/panels/GenericTokenPanel.svelte
  • configurator/src/data/domain-map.json
  • configurator/src/data/domain-patterns.json
  • configurator/src/lib/domains.ts
  • configurator/src/lib/tokenModel.ts
  • configurator/tests/domains.test.ts
  • configurator/tests/tokenModel.test.ts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown

Greptile Summary

This PR replaces overlapping token-name pattern matching with deterministic namespace-based domain classification and introduces token-role, dependency, validation, and detached-state guidance.

  • Adds a shared namespace-to-domain map used by runtime classification and the curation check.
  • Aligns panel lists, badges, and reset scope around domainOf().
  • Adds token relationship metadata, override-state warnings, and catalogue-backed tests.

Confidence Score: 4/5

The 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 <number> grammar to integer-only z-index, and dependency guidance does not update when overrides change token relationships.

Files Needing Attention: configurator/src/lib/tokenModel.ts, configurator/src/components/inputs/TokenRow.svelte, configurator/src/components/panels/AllTokensTab.svelte

Important Files Changed

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]
Loading

Reviews (1): Last reviewed commit: "feat(configurator): metadata-driven toke..." | Re-trigger Greptile

Comment thread configurator/src/lib/tokenModel.ts Outdated
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";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Number validation uses integer grammar

When a user overrides a <number> token such as --sf-text-ratio-min with a valid fractional value like 1.25, validation probes it through integer-only z-index, causing the configurator to label the valid override “Invalid” and offer to reset it.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

@jackgranatowski
jackgranatowski merged commit 10e1e8a into main Aug 20, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants