Uh oh!
There was an error while loading. Please reload this page.
feat(theme): add semantic/layouts — the container system - #884
Merged
Conversation
Ten tokens and nine `@utility` classes: how far content sits from the app chrome (BOUNDARY), how far things sit from each other (RHYTHM), and how wide a reading column may get (MEASURE). A DERIVED group: every token is a var() reference to --spacing-* / --container-*, never a literal length. That is why none carries a breakpoint map — the spacing scale is already fluid and var() is substituted at use time on the element, so a layout token follows the override for free. Duplicating the scale into layout would only let the two drift. Emitting them as `@utility` rather than `@layer components` is what gives them variants (`md:layout-column`), the same reason the typography utilities are emitted that way. Generalizes the utility emitter into emitUtilities(map) with a thin emitLayoutUtilities caller, so the shape is reusable. Regenerating dist also picks up one line main was stale on: an emitted comment that still read `bg-[var(--x)]` where the source has said `bg-(--x)` since ENG-47001.
The catalog's token allowlists are scraped from the built theme, so adding semantic/layouts adds ten --layout-* entries. Regenerated rather than hand-edited, which is what catalog:check verifies.
herbert-julio-azion
approved these changes
Aug 12, 2026
isaque-bock-azion
previously approved these changes
Aug 14, 2026
guilherme-santana-azion
previously approved these changes
Aug 14, 2026
…lighter type scale `Avatar › VariantGrid` failed the visual shard on `dark-desktop` only, at 1.0301% / 1354px against a 1% threshold — deterministically, byte-identical across two runs. The cause is not this branch. That baseline was last regenerated on 2026-07-22 by #768 and has missed two theme changes since: #889 (opaque neutral border tokens) and #876 (headings and body steps to font-weight 300, body leading 1.5 → 1.375). #876 regenerated 548 baselines across three rounds and updated this story's `--dark-tablet` file, but never the dark-desktop one — which alone keeps the bare story id instead of a `--mode` suffix (see .storybook/visual-modes.js), so it is the easy file to miss in a partial regeneration. Aligning baseline to render needs a zero shift (dx=0, dy=0); what differs is ink — text -9%, icons -7% — the lighter weight. This branch only adds tokens, and is simply the first PR to run the suite with #876 merged in. Regenerated via the app-storybook-generate-baseline workflow on linux. The `-u` path could not rewrite it on its own: stale-baseline vs clean render is 0.9875%, under the threshold, so the snapshot passed and was left alone. The file had to be deleted so it was written as a missing snapshot. Against the render CI actually produced, the new baseline is 0.0426% (56px). Still stale and left alone, since both currently pass: this story's `--dark-mobile` baseline (also 2026-07-22). Worth noting separately that the Avatar stories source their photo from a live Unsplash URL, which contributed the residual noise here and is what kept this story on the 1% boundary. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
isaque-bock-azion
dismissed stale reviews from guilherme-santana-azion and themself
via
August 14, 2026 21:26
3c9dc47robsongajunior
approved these changes
Aug 14, 2026
robson-junior-azion
approved these changes
Aug 14, 2026
rafael-garbinatto-azion
approved these changes
Aug 14, 2026
Uh oh!
There was an error while loading. Please reload this page.
gabriel-lisboa-azion added a commit
that referenced
this pull request
Aug 17, 2026
Brings the three commits demo lacked, so the deployed sample exercises them alongside the four fixes carved out of this branch (#899–#902), whose content was already here: - feat(webkit): chip's three kinds (#883) - feat(theme): the semantic/layouts container system (#884) - feat(theme): lightened heading and body type (#876) Conflict resolutions worth knowing: `build-tokens.mjs` — main has no illustration tokens, so main's side of all six hunks was empty. Taking it would have silently deleted this branch's illustration wiring; ours was kept. The merge then produced a DUPLICATE `emitUtilities` and `emitLayoutUtilities` with no conflict at all (both sides had added an identical helper in different places), which is a syntax error the merge itself reported as clean — the second copy is removed and `emitIllustrationUtilities` reuses the first. `texts.data.js` — the five conflicts were all `text-body-*` weight, resolved to main's `light` since that is the change being previewed. Resolved in place rather than with `--theirs`, which would have discarded the file's auto-merged hunks. Entry count held at 144. `.size-limit.json` — union, not a side: main's `chip` plus this branch's `footer-root` and `resizable-panel-root`. `dist/v4/globals.*` are generated, so they were rebuilt from the merged sources rather than hand-merged. The 466 conflicting visual baselines took main's copies; neither side is valid for a merged tree, and this branch opens no PR the visual gate guards. Verified after: no `undefined` in the built CSS, illustration tokens still emitted, main's layout utilities present, body weights now 300, no token data file lost entries, and 154 tests pass across toast, table, sidebar, resizable-panel and chip.
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 freeto 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.
What
The layout system every console page is built on, as a theme token group: ten tokens and nine
@utilityclasses, covering three decisions expressed once — how far content sits from the app chrome (boundary), how far things sit from each other (rhythm), and how wide a reading column may get (measure).Four container types, picked by what the page is:
.layout-column.layout-column-focused.layout-column-form.layout-form-create--layout-measure-control)Plus
.layout-boundary/.layout-boundary-inline, the two rhythm steps (--layout-section-gap,--layout-group-gap) with their.layout-section-start/.layout-group-startmargin forms, and.layout-field-controlfor the control side of a settings row.A derived group
Every token is a
var()reference to--spacing-*/--container-*, never a literal length, and that is why none of them carries a breakpoint map. The spacing scale is already fluid (--spacing-lgis1rem, then1.5remfromsm), andvar()is substituted at use time on the element — so a layout token follows the breakpoint override for free. Giving it its own map would duplicate the spacing scale into layout and let the two drift.Why
@utilityand not@layer componentsSame reason the typography utilities are emitted that way:
@layer componentsclasses are opaque to v4's variant resolver, and their modifiers silently drop. A layout class is exactly the kind you want behind a variant —md:layout-column.Two things worth a reviewer's eye
.layout-field-controlcarries a:not(#\#)specificity pin. It is applied toItem.Actions, whose own root already declaresshrink-0, and Vue merges both class lists onto one element. Custom@utilityblocks sort before the core utilities, so without the pinshrink-0wins and the control side can no longer yield to a long field name. Measured, not assumed —.layout-field-controlat byte 19079 vs.shrink-0at 31336 in a built bundle.#\#is an id no element can carry, so the selector always matches while reading (1,1,0); it is Tailwind's own important-strategy idiom and stays variant-safe. Only this one of the nine has it, because only this one has a live conflict.The boundary widening nests on the column, not the boundary. Specificity is (0,2,0) either way, so correctness does not decide it. Nesting on the column keeps both declarations that can set
max-widthin one block, keeps.layout-boundaryto the three padding declarations its name promises, and keeps "a fifth column class costs one line" true — they are generated from aCOLUMN_MEASUREmap and the nested rule comes along.Also in the diff
emitIllustrationUtilities-style emission generalized intoemitUtilities(map)with a thinemitLayoutUtilitiescaller.distpicks up one line main was stale on: an emitted comment still readingbg-[var(--x)]where the source has saidbg-(--x)since ENG-47001.DESIGN.md, a Layout row in Get Started, and the derived-group note in the theme's token README.DESIGN.mdships here rather than separately because that section is the catalog for these tokens — documenting them before they exist would be the drift the rule guards against.Verification
build:tokensclean,assertNoZeroWithUnitpassing, theme suite 12/12.git diff dist/v4/globals.cssis additions only apart from the stale comment: 10--layout-*lines in:root, no new@medialines (every token is a barevar()), 9 new@utilityblocks.validate-story-source --allreports 91/91 compliant.