feat: Phase 3 — migrate call sites to object-form css() + token.*#2792
Merged
Conversation
…tation Switches TokenPath from an open `[key: string]: TokenPath` index signature to a mapped type over a finite union of framework-known scale keys. This bypasses `noUncheckedIndexedAccess` widening so every dot-chain access (e.g. `token.color.primary[500]`) stays `TokenPath` rather than `TokenPath | undefined`. Adds `VertzThemeRadius` and `VertzThemeShadow` augmentation interfaces alongside the existing `radius`/`shadow` entries on `VertzThemeTokens`. Extends the classname migration mapper to emit `token.radius.*` and `token.shadow.*` references for `rounded:*` and `shadow:*` shorthands. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Converts 38 style modules from array-form shorthand strings to the new object-form css() input backed by `token.*` references. 143 rewritten sites, 224 token references. Tests and typecheck pass against the new TokenPath shape. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Identifiers like `2xl` / `3xl` cannot appear as dot-access property names in JS. The mapper now routes `font:2xl`, `rounded:2xl`, and `shadow:2xl` through `token.<ns>['2xl']`. Also expands the `raw` value path to append a `px` suffix for the `border-r|l|t|b` sides to match the runtime resolver's existing behavior. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Re-runs the classname migration against theme-shadcn/src after the mapper fix. `border-r/l/t/b:N` now emits `'<N>px'` instead of bare `'<N>'`, matching the CSS grammar. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…token.* Converts 17 component / page files from array-form shorthand strings to the new object-form css() input backed by `token.*` references. 69 rewritten sites, 162 token references. Tests and typecheck pass against the new TokenPath shape. Array-form entries that mix with object literals were preserved as-is for follow-up hand-migration. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…selector unwrap
Why: earlier migration script rejected any non-string element in a shorthand
array, blocking call sites that mix 'p:4' shorthands with inline selector
objects, spread expressions, and trailing call-expression wrappers. Also
missed extending mapper/generator coverage needed for theme-shadcn and
examples migration.
Changes:
- rewriter: mixed-array handling converts strings via the shorthand pipeline
while preserving objects, bare identifier/call/property-access spreads,
and explicit SpreadElement nodes (...base).
- rewriter: single-element wrapper arrays unwrap when the parent key is a
selector ('&foo', '@media', computed [DARK]) so [animationDecl('x')]
collapses to animationDecl('x').
- mapper/generator: coverage for additional shorthands (ring variants,
opacity percentages, keyed tokens like token.color['muted-foreground']).
- tests: unit coverage for every new branch — 24 rewriter scenarios,
mapper/generator cases, and regression guard for compound variants.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ran scripts/migrate-classnames across entity-todo, linear, and task-manager to drop legacy array-form shorthand strings in favor of object-form css() with explicit token.* references. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ss() with token.* Follows-up 06c168939 with the sites/ files the improved migrator can now handle (mixed shorthand + selector arrays, spread helpers). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ith token.* Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-form css() with token.* Add migrate-templates.ts helper that rewrites css()/variants() calls inside template literals by unescaping the body, running rewriteSource, and merging the 'token' export into the existing 'vertz/ui' import (multi-line aware). Also manually update CLAUDE.md documentation code blocks (object-form and token references) and three templates whose shorthands (font:6xl, font:md, flex:1) have no mapping — replaced with supported values or raw CSS. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…hand tests for Phase 4 - Rewrite variants.test.ts and css.test.ts to object-form css() with token.* references. Assertions now match var(--spacing-4), var(--font-weight-bold), etc. instead of resolved pixel values. - Rewrite variants.test-d.ts using augmented token keys only (spacing 1/4/8, color.background/foreground/primary[500,700]). Switch ButtonVariants shape from StyleEntry[] to StyleBlock so object-form variants type-check. - Fix one stray shorthand array in native-compiler.test.ts. - Tag 6 shorthand-only test files with REMOVED-IN-PHASE-4 banners so Phase 4 deletion is mechanical: s.test.ts, shorthand-parser.test.ts, shorthand-coverage.test.ts, token-resolver.test.ts, css.test-d.ts, css-integration.test.ts. Closes the Phase 3 exit criterion: zero array-of-shorthand-strings remain in first-party call sites (tests/ files still carry the legacy API but are tagged for deletion). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…-B3, S1-S2)
The mapper's 'raw' valueType previously quoted every value literally, which
produced invalid CSS for transition:colors → 'colors', tracking:tight → 'tight',
grid-cols:2 → '2', etc. Port the per-property expansions that
token-resolver.ts:447-526 performed:
- transition:{none,all,colors,shadow,transform,opacity} → full multi-prop chain
- tracking:{tight,tighter,normal,wide,wider,widest} → em letter-spacing values
- grid-cols:N → repeat(N, minmax(0, 1fr))
- aspect:{square,video,photo} → aspect-ratio values
- top/right/bottom/left/inset:N → spacing scale lookup
Fixture 13-raw-aliases.tsx covers the new paths. A companion one-shot
fix-literal-aliases.ts script rewrites already-migrated object literals that
escaped the AST visitor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ration
- SelectorKey now accepts ancestor-selector patterns (\`\${string} &\` and
\`\${string} &\${string}\`) so \`[data-theme="dark"] &\` descriptors pass
StrictStyleBlock validation.
- Add scrollbar-width, scrollbar-color, scrollbar-gutter to CSSPropertyName —
used by the landing hero's scroll overlay and other standard CSS controls
that were previously rejected by the strict property union.
- Export SelectorKey, StyleBlock, StyleDeclarations from \`@vertz/ui\` so
theme-shadcn can type its style constants without reaching into internals.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…les (B4) Re-run the migration on every file under \`packages/theme-shadcn/src/styles/\` now that the mapper handles mixed arrays, raw-alias expansion, and spread expressions. Hand-migrate \`button\`, \`badge\`, \`sheet\`, \`drawer\`, \`skeleton\`, \`slider\`, and \`_helpers\` where the automated script could not reach identifier-referenced config objects or kebab-case property keys inside strict StyleBlock contexts. Key changes: - \`bgOpacity\` helper now returns camelCase \`backgroundColor\` to satisfy the strict CSS-property typing. - All \`[data-theme="dark"] &\` descriptors use the new SelectorKey pattern. - \`transition:colors/all/shadow\` expansions inlined; \`tracking:tight\` replaced with \`-0.025em\` literal values. - Outline-variant test updated to assert the new object shape. 136/136 theme-shadcn tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…* (B5) Phase 3 Task 3 was marked done but no commit had actually touched \`packages/landing/src\`. Run the migration script across every component and page, then hand-fix the raw-alias regressions exposed by B1. Vendor-prefixed properties (WebkitOverflowScrolling, WebkitBackdropFilter) are now written in the strict camelCase form required by \`StrictStyleBlock\`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…fter raw-alias fix Sweep every first-party consumer again so the invalid \`transition: 'colors'\`, \`letterSpacing: 'tight'\`, and \`gridTemplateColumns: '2'\` literals introduced by the earlier pass get replaced with the real expanded values. Covers the flagship Linear clone, task-manager, entity-todo examples, the dev-orchestrator site, ui-auth's OAuth button, and the create-vertz-app scaffolding templates — all of which were shipping invalid CSS before this fix. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced Apr 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Final phase of the drop-classname-utilities feature. Migrates all first-party consumers from the legacy shorthand-string arrays to object-form
css()/variants()with the typedtoken.*helper, and fixes the five blocker classes the first adversarial review caught.Public API Changes
Additions (non-breaking):
SelectorKeynow accepts ancestor-selector patterns (`${string} &`,`${string} &${string}`) so[data-theme="dark"] &passesStrictStyleBlock.CSSPropertyNamegainsscrollbar-width,scrollbar-color,scrollbar-gutter.@vertz/uire-exportsSelectorKey,StyleBlock,StyleDeclarations.No breaking changes in this PR. The shorthand parser still lives; Phase 4 removes it.
Summary
transition:colorsnow expands to the full 7-prop chain;tracking:tight→-0.025em;grid-cols:N→repeat(N, minmax(0, 1fr));aspect:{square,video,photo}→ ratio values;top:N/inset:Nuse the spacing scale. Covered by new fixture13-raw-aliases.tsx.bgOpacityhelper now emits camelCasebackgroundColor.WebkitOverflowScrolling,WebkitBackdropFilter).create-vertz-apptemplates re-swept after the mapper fix so none of them ship invalid CSS.SelectorKey/CSSPropertyNameextended; types re-exported from@vertz/ui.Review Findings & Resolutions
Re-reviewed by an independent adversarial agent — all six blockers verified resolved.
Phases
css()end-to-end ✅token.*helper + typed augmentation ✅s()(next)Test Plan
vtz test scripts/migrate-classnames— 130/130 passingvtz testinpackages/theme-shadcn— 136/136 passingvtz testinpackages/ui— 2756/2756 passingtsgo --noEmitclean in theme-shadcn, ui-auth, uipresence-room.ts(unchanged on this branch)🤖 Generated with Claude Code