Uh oh!
There was an error while loading. Please reload this page.
fix(design-system): make the radius contract describe the app it governs - #1535
Merged
Conversation
An audit of the radius system found the same failure repeated: the rules were not derived from the design language, they were retrofitted to whatever the CSS already said. The suite was 18/18 green — but green because the non-conforming parts were either absent from the tables or had the rule rewritten around them. Two contracts had gone further and were actively holding defects in place. Contracts that were protecting defects -------------------------------------- .providerLogo — PR-UI-13 had pinned a single ~27-28% radius ratio across plate sizes after an audit found the 44px and 32px plates reading as different shapes. The tier convergence rewrote both to --radius-surface, which is 18.2% at 44px and 25% at 32px: the exact drift that PR removed. Both inline comments still claimed 27.3% / 28.1%, now arithmetically false, and SELECTOR_TIER pinned the regression, so restoring the ratio failed CI. Square icon plates are governed by RATIO, not by tier — a fixed px cannot read the same at 32px and 48px. Added --radius-plate: 27%, which is scale-invariant, restores the PR-UI-13 anchor (12px at 44px), and is correct at sizes not yet added. Applied to all six plates, which had drifted to four different ratios (18.2 / 25 / 16.7 / 22.2%). The compact override and the catalog-row override no longer restate a radius at all — with a ratio the size change alone is enough. .maka-search-modal-input-row — pinned by radius-nesting-contract to calc(var(--radius-modal) - 8px) = 4px, described as concentric nesting inside the 12px shell, with a warning that a tier "would read as too round". Measured live: that row is the middle of a 3-row grid, 57px below the shell's top edge, 12px in from its sides, adjacent to no shell corner. The 8px was the vertical margin to the header band — an axis with nothing to do with the corner. Its twin .maka-palette-input-wrap (same primitive, same position, same shell) used the control tier all along, so the two searches differed by 50% in roundness. Now control, and pinned in SELECTOR_TIER so they stay together. The rule itself was the root cause: it said only "with padding between them" and never mentioned adjacency, so the search modal satisfied it literally. Rewritten in maka-tokens.css and the nesting contract to state the precondition — the inner corner must sit in the outer corner, with an equal inset on both edges meeting there. Its worked example was this very bug; it now cites the one genuinely concentric site instead. Rules rewritten to fit the code ------------------------------- TabsList / TabsTrigger were dropped from COMPONENT_RADIUS when #499 moved them to primitives/tabs.tsx, on the stated grounds that they were "governed by primitives-design-contract escape hatches". That file contains no radius assertion at all, leaving the vocabulary's own "tab trigger" and "tab list" as the only named roles governed nowhere. The components had merely changed file; re-pointed. The vocabulary said `checkbox` belongs to pill/999px while every checkbox renders rounded-[var(--radius-control)]. The code is right (a fully round checkbox is a radio); the vocabulary was wrong, and because Checkbox is absent from COMPONENT_RADIUS nothing ever caught it. .enabledEmptyChip was pinned to control by reading its class name — it renders as a full-width two-line card with 16px padding. Surface now, matching its twin .settingsWechatQrState. Dead by construction -------------------- input-group's `**:[textarea_button]:rounded-[calc(var(--radius-sm)-1px)]` compiles to `:is(... *):is(textarea button)` — a <button> inside a <textarea>, which the HTML content model forbids. Not merely unused; unmatchable. Removed. Also refreshed the segmented.css comment, which justified using the tier over the calc form on the grounds that the calc was unspellable — true until #1514 fixed the value splitter. The tier is still right, for the better reason that it survives a token revalue. Not changed, deliberately ------------------------- Toggle / ToggleGroup look dead from the app's side (no JSX call sites) but are design-system primitives with a dedicated story, pinned by storybook-baseline-contract. Their entries stay. The tier VALUES themselves (6/8/12/999) are untouched. The audit raised real questions there — one control token spans 16px Kbd to 36px Input, a 2.25x swing in roundness, and 6-vs-8 is below the perceptual threshold as a global semantic distinction — but changing them moves the whole app's surface and is a design decision, not a defect fix. Verified: lint, format:check, build, typecheck, knip (both workspaces), check-console, check-dead-css, and 2879 main-process tests. Plate geometry was compared visually at all four sizes before and after.
Uh oh!
There was an error while loading. Please reload this page.
jackwener added a commit
that referenced
this pull request
Jul 27, 2026
…name (#1537) The CSS scanner matched the property name as a bare substring, so `--os-track-border-radius: …` in base.css was scanned as though it were a plain `border-radius` declaration. Both such properties currently hold whitelisted tokens, so nothing failed — but the moment one held a raw px the offender would have read renderer CSS: border-radius: 4px; naming a declaration that does not exist anywhere in the stylesheet, and sending whoever has to fix it looking for the wrong thing. Keeping these in scope is deliberate, not merely tolerated. `.os-theme-maka` is OverlayScrollbars' theming API: the library's own CSS consumes those properties and renders a real scrollbar corner. A radius that reaches the screen is governed no matter which declaration spells it. So the fix is to capture the whole property name rather than to anchor the match and drop the coverage. The lookbehind is load-bearing: without it a prefixed property also matches at its inner `border-radius` and is reported twice. `\b` cannot do this job — `-` is a non-word character, so a word boundary already exists between `-` and `border`. Found while reviewing #1520; deliberately left out of that PR and #1535 as pre-existing and orthogonal. Verified: lint, format:check, typecheck, check-dead-css, and 2891 main-process tests. The new assertion fails against the old regex.
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.
Follow-up to #1520. Audited the radius system from first principles — the four tier values, every
calc()shrink site, theCOMPONENT_RADIUStable, and theSELECTOR_TIERtable.The suite was 18/18 green. It was green because the non-conforming parts were either absent from the tables or had the rule rewritten around them. Two contracts had gone further and were holding defects in place — the fix was the thing failing CI.
Contracts that were protecting defects
.providerLogo— a repaired invariant, silently reverted, then lockedPR-UI-13 pinned a single ~27-28% radius ratio across plate sizes, after an audit found the 44px and 32px plates reading as different shapes. The tier convergence rewrote both to
--radius-surface:/* 27.3% — anchor ratio *//* 28.1% — matches md ratio */Both comments arithmetically false, the drift restored, and
SELECTOR_TIERpinned it — restoring the ratio failed CI.Square icon plates are governed by ratio, not tier: a fixed px cannot read the same at 32px and 48px. Added
--radius-plate: 27%— scale-invariant, restores the PR-UI-13 anchor (12px at 44px), correct at sizes not yet added. Applied to all six plates, which had drifted to four different ratios (18.2 / 25 / 16.7 / 22.2%). The compact and catalog-row overrides no longer restate a radius at all; with a ratio the size change alone suffices.Compared visually at all four sizes before merging — the old column visibly drifts (48px reads squarer than 32px), the new one is one shape scaled.
.maka-search-modal-input-row— concentric nesting that was never adjacentPinned to
calc(var(--radius-modal) - 8px)= 4px as "an input inside a 12px modal shell with an 8px inset", warning that a tier "would read as too round against the shell corners".Measured live: that row is the middle of a 3-row grid — 57px below the shell's top edge, 12px in from its sides, adjacent to no shell corner. The
8pxwas the vertical margin to the header band, an axis with nothing to do with the corner. Its twin.maka-palette-input-wrap— same primitive, same position, same 12px shell — used the control tier all along, so the two searches differed by 50% in roundness.The rule itself was the root cause. It said only "with padding between them" and never mentioned adjacency, so the search modal satisfied it literally — and its one worked example was this bug. Rewritten to state the precondition: the inner corner must sit in the outer corner, with an equal inset on both edges meeting there. It now cites the one genuinely concentric site in the codebase (segmented: 8px track, uniform 2px pad, buttons hugging its corners, 8−2=6 landing exactly on control).
Rules that had been rewritten to fit the code
TabsList/TabsTriggerwere dropped fromCOMPONENT_RADIUSwhen refactor(ui): hover/selected state + tab component governance (post #496 color migrate) #499 moved them toprimitives/tabs.tsx, on the stated grounds they were "governed by primitives-design-contract escape hatches". That file contains no radius assertion at all — leaving the vocabulary's own "tab trigger" and "tab list" as the only named roles governed nowhere. They had merely changed file; re-pointed.checkbox → pill 999px, while every checkbox rendersrounded-[var(--radius-control)]. The code is right (a fully round checkbox is a radio); the vocabulary was wrong, and becauseCheckboxis absent from the table nothing ever caught it..enabledEmptyChipwas pinned to control by reading its class name. It renders as a full-width two-line card with 16px padding — surface now, matching its twin.settingsWechatQrState.Dead by construction
input-group's**:[textarea_button]:rounded-[calc(var(--radius-sm)-1px)]compiles to:is(… *):is(textarea button)— a<button>inside a<textarea>, which the HTML content model forbids. Not merely unused, unmatchable. Removed.Deliberately not changed
Toggle/ToggleGrouplook dead from the app's side (no JSX call sites) but are design-system primitives with a dedicated story, pinned bystorybook-baseline-contract. Entries stay.controltoken spans a 16pxKbdto a 36pxInput, a 2.25× swing in roundness, and 6-vs-8 is below the perceptual threshold as a global semantic distinction (it only does work in concentric nesting). But changing them moves the whole app's surface: a design decision, not a defect fix. Left for a separate call.Gate
lint · format:check · build · typecheck · knip (both workspaces) · check-console · check-dead-css — all clean, plus 2879 main-process tests passing.