refactor(ui): converge spacing to --space-* scale, ban bare px (#430 PR3) - #448
Merged
Conversation
…430 PR3) The --spacing token was 0.25rem, which under the 15px root font-size equals 3.75px, not the 4px the comment claimed. This silently broke alignment between Tailwind's spacing scale (p-2 = 7.5px) and hand-written px (padding: 8px) — two unrelated scales. Fix the ruler to absolute 4px in both :root and @theme inline so Tailwind utilities (p-N, gap-N, m-N) and hand-written var(--space-N) share one source. Define a 14-value scale covering the codebase's real spacing distribution: 0/2/4/6/8/10/12 below 16 (even numbers, dense UI needs the 6 and 10 half-steps), 16/20/24/32/40/48/64 at and above (pure 4px multiples). 1px stays a literal (hairline). Deliberately absent: 14/18/ 22/26/28/30/34/36/52/56 — snapped to the nearest scale value in the follow-up commits to kill magic numbers. Per the #430 adversarial review, spacing has no single-property anchor like border-radius, so the upcoming contract scopes to padding/margin/ gap only (not width/height/inset/grid).
…430 PR3) Replace every bare px value in padding/gap/margin across renderer CSS (689 sites) and TSX arbitrary spacing utilities (125 sites) with var(--space-*) tokens or Tailwind scale utilities. Snap non-scale values to the nearest scale tier: 3->2, 5->4, 7->6, 9->8, 11->12, 14->12, 18->16, 22->24, 26->24, 28->24, 30->32, 34->32, 36->40, 52->48, 56->64, 72->64. Negative margins use calc(var(--space-N) * -1). 1px stays a literal (hairline). Responsive clamp()/max() bounds stay literal (they are viewport parameters, not spacing beats). Update 6 contract tests that pinned the old bare-px literals to expect the new var(--space-*) or scale-utility forms. The chat-header inset contract's pxDeclaration helper now resolves var(--space-*) tokens to their px equivalents so the geometric invariant (buttons x width + gaps + clearance = inset) still holds.
…/margin (#430 PR3) Lock the spacing vocabulary so future PRs can't drift back to ad-hoc px values. The contract enforces: 1. CSS padding/margin/gap must use var(--space-*), calc(var(--spacing) or var(--space-N)), or literals (0/auto/inherit/1px hairline). Bare Npx is banned. Responsive clamp()/max()/min() bounds are exempt (viewport parameters, not spacing beats). 2. --spacing is 4px (absolute, not 0.25rem) and --space-* tokens are pinned to calc(var(--spacing) * N) with the correct multipliers. 3. The @theme inline bridge exports --spacing: 4px so Tailwind p-N/ gap-N/m-N share the ruler with hand-written var(--space-N). 4. TSX has no arbitrary p-[Npx]/gap-[Npx]/m-[Npx] (except 1px hairline). Spacing has no single-property anchor like border-radius (adversarial review in #430), so the contract scopes to padding/margin/gap only. Also fixes 3 single-line declarations the batch replacement missed (margin: 2px 0, padding: 16px 20px, margin-top: 2px in single-line multi-declaration rules).
…PR3) Old story showed 6 arbitrary calc(var(--spacing) * N) steps with a stale 0.25rem comment and a step*4px label that was silently wrong (--spacing was 3.75px, not 4px). Redesign to show the full 14-value --space-* scale with token name, pixel value, visual bar, and usage. Add a 1px hairline section and keep the layout-geometry section.
The ratchet (#459) froze 442 legacy off-grid px values per file as a transitional mechanism. This PR replaces bare px spacing wholesale with the --space-* scale and bans new bare px outright (spacing-converge-contract), which strictly supersedes the ratchet: after the conversion the ratchet baselines are all stale-high and its anti-rust slack check would fail. One mechanism, the stronger one.
jackwener
force-pushed
the
opencode/spacing-converge-pr3
branch
from
July 3, 2026 08:04
4c81bd1 to
bdd4ecb
Compare
Member
|
Merged,感谢!🎉 这是 #430 系列里含金量最高的一条 —— Maintainer 落地时做了三件事:
全量 1696/1696 pass。 |
jackwener
added a commit
that referenced
this pull request
Jul 3, 2026
This was referenced Jul 4, 2026
Closed
Astro-Han
pushed a commit
that referenced
this pull request
Jul 5, 2026
…#532) The spacing-converge pass (#448) moved footer-action / lineage-badge marker shells off bare-px arbitraries (gap-[6px], px-[8px], py-[4px], gap-[3px], px-[5px]) onto the 4px-ruler scale (gap-1.5, px-2, py-1, gap-0.5, px-1) but left the contract test's expected literals behind, so 'npm --workspace @maka/ui test' has been red on main since then. Update the pinned literals; the merge semantics under test (UiButton base utilities like gap-2 must merge out) are unchanged and still pass.
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.
Summary
Converge every padding/gap/margin magic number onto a single
--spacing: 4pxruler with a 14-value--space-*scale, then lock it with a contract test that bans bareNpx. Mirrors the proven radius/typography converge pattern.Why
--spacingwas0.25rem, which under the 15px root font-size equals 3.75px, not the 4px the comment claimed. This silently broke alignment between Tailwind's spacing scale (p-2= 7.5px) and hand-written px (padding: 8px) — two unrelated scales. On top of that bug, 687 CSS sites and 125 TSX sites used bare px values across 28 distinct values, with no governance against drift.Closes #430
Scope
Changed:
--spacingbug fix:0.25rem→ absolute4pxin both:rootand@theme inline, so Tailwind'sp-N/gap-N/m-Nand hand-writtenvar(--space-N)share one ruler (the Tailwind scale shifts +6.7%:p-2from 7.5px → 8px).--space-*scale (14 values):0/2/4/6/8/10/12below 16 (even numbers, dense UI needs the 6 and 10 half-steps),16/20/24/32/40/48/64at and above (pure 4px multiples). 1px stays a hairline literal.var(--space-*): padding/gap/margin across all renderer CSS. Non-scale values snapped to nearest tier: 3→2, 5→4, 7→6, 9→8, 11→12, 14→12, 18→16, 22→24, 26→24, 28→24, 30→32, 34→32, 36→40, 52→48, 56→64, 72→64. Negative margins usecalc(var(--space-N) * -1). Responsiveclamp()/max()bounds stay literal (viewport params, not spacing beats).p-[8px]→p-2,gap-[6px]→gap-1.5, etc.spacing-converge-contract.test.ts: bans bareNpxin padding/margin/gap (CSS + TSX), pins token values, verifies@theme inlinebridge. Allows0/auto/inherit/1pxhairline andclamp()/max()/min()responsive params (only when they contain a responsive dimension likevh/vw/%; pure-pxmax(8px, 12px)is rejected). Traces semantic custom properties to catch indirect bare-px references (e.g.--local-gap: 8px; gap: var(--local-gap)).var(--space-*)/ scale-utility forms.docs/design-system.md§1.5 refreshed.spacing.stories.tsxredesigned for the 14-value--space-*scale (was 6 arbitrary steps with stale0.25remcomment and wrongstep*4pxlabels). Story layout gaps also usevar(--space-*)tokens.visible-copy-hygiene-contract.test.tshad 2 failing assertions on a clean main (leftover from refactor(ui): split --accent into semantic aliases, lock call-site governance #441's--accent→--linksemantic split). Fixed in a separate commit so the PR starts green.Not included:
icon-system-contract.test.tsalready treats dense/hero as deliberate call-site values (refactor(ui): converge design-token magic numbers (motion, typography, spacing) #430 decided: no change).Verification
Commands run:
npm run rebuild— full build passes (all 6@maka/*workspaces).npm run -w @maka/desktop test— 1699/1699 pass (was 1681; +18 new spacing contract tests across 3 review rounds).tsc -p tsconfig.main.jsonandtsc -p tsconfig.json— TS compilation clean.npm run -w @maka/desktop build-storybook— Storybook build succeeds.var(--space-*)references and@theme inline --spacingbridge.Screenshot smoke (2026-07-03):
dev.mjshas a pre-existing node v26 esbuild binary incompatibility, not introduced by this PR).--spacing4px ruler (+6.7% Tailwind shift), 18→16, 14→12.Known issue (not introduced by this PR):
#roothasdisplay:flex; justify-content:centerfor preload skeleton; React mount leaves.appFrameshrink-wrapped and centered, causing visible left-right shift. This is a#root/.appFrameflex layout issue, unrelated to spacing tokens.User-facing impact
p-*,gap-*,m-*) grows ~6.7% because the ruler corrects from 3.75px to 4px. Dense UI elements (buttons, chips, cards) get marginally more breathing room — this is the intended "align Tailwind with hand-written px" effect from refactor(ui): converge design-token magic numbers (motion, typography, spacing) #430.Reviewer notes
--spacingbug + scale definition, (3) full bare-px replacement, (4) contract test, (5) docs, (6) storybook story redesign, (7) review round 2 fixes (margin-block-end, calc tightening, sidebar 8px), (8) review round 3 fixes (clamp/max/min responsive-only, semantic var tracing, story inline tokens).--spacing: 4pxin@theme inlineis the single most impactful line — it makes Tailwind's entire spacing scale switch from 3.75px to 4px base. This is the core fix, not a side effect.isInsideResponsiveFunctionnow requires a responsive dimension (vh/vw/%/etc) inside clamp/max/min — pure-pxmax(8px, 12px)is rejected. Semantic var tracing catches--local: 8px; gap: var(--local).