feat(deck-kit): size an icon-only control's glyph, from one constant - #295
Merged
Conversation
The 44x44 targets landed without the mark inside them changing, so a control could be fully operable and still read as unpressable -- an 11px glyph adrift in a 44px box. `touch-target.ts` sizes the box; `ICON_GLYPH` sizes the mark, and the two files now point at each other. 18px, with the line box pinned. `leading-none` rides inside the constant rather than being left to each caller: the tightest caller is a Slider's label row, where three stack on a phone, and pinning is what keeps such a row growing by the glyph's 7px instead of a multiple of them. Icon-only is the whole condition. A control with a visible label already has the word carrying it, so `✕ clear` and `◈ analyze` keep the size they inherit -- growing punctuation beside a word only unbalances the line. Decorative glyphs are not controls and stay put too. Never over the canvas. There the backdrop is the user's artwork (ADR 0013) or the piece itself (ADR 0021), which is why that chrome stays at its drawn size and buys its target as an overlay; a bigger glyph grows the chrome, which is the same charge by another route. A constant rather than a `text-*` at each callsite because the scale guard cannot cover `text-` -- it is `fontSize` union `colors` union `text-center` at once (`theme/audit.ts`), so a mistyped font step renders nothing and no guard objects. One constant means no program names a font step for a glyph, and `icon-glyph.test.ts` pins the one step it does name to the preset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
… the scale it names Three follow-ups from review. `ICON_GLYPH` held a size, not a glyph. `ICON_GLYPH_SIZE` reads honestly beside `TOUCH_TARGET_HEIGHT` / `TOUCH_TARGET_ICON`, which is the pair it is meant to be read with -- and six callsites is as cheap as this rename will ever be. The `fontSize` scale was the one the vocabulary section never listed, which left the only unguarded scale as the only undocumented one. It is now a row in the table, marked unguarded, with the two traps that follow from it: `md` is 18px and sits between `base` and `lg`, not where Tailwind puts it; and since the preset extends rather than replaces, a step it does not name -- `text-3xl` -- resolves to Tailwind's 30px and silently leaves the deck scale. The guard-gap argument now lives there alone; the icon-glyph section points at it instead of restating it. The constant's JSDoc promised to record every exclusion and recorded three of four. A decorative glyph -- a Toast's variant mark, a threat level, the `*` on a modified Preset -- is not a control, and takes the size of the text it decorates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 2, 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.
The 44x44 targets landed without the mark inside them changing, so a control could be fully operable
and still read as unpressable — an 11px glyph adrift in a 44px box.
touch-target.tssizes the box;ICON_GLYPH_SIZEsizes the mark, and the two files point at each other.The rule
Icon-only is the whole condition, and it excludes two things. A control with a visible label
already has the word carrying it, so
✕ clearand◈ analyzekeep the size they inherit — growingpunctuation beside a word only unbalances the line. And a glyph that is no control at all — a
Toast's variant mark, a threat level, the
*on a modified Preset — is decoration beside its owntext, so it takes the size of the text it decorates.
Never over the canvas. There the backdrop is the user's artwork (ADR 0013) or the piece itself
(ADR 0021), which is why that chrome stays at its drawn size and buys its target as an overlay. A
bigger glyph grows the chrome, which is the same charge by another route.
A constant, not a
text-*per callsite. The scale guard cannot covertext-— it isfontSize∪
colors∪text-centerat once (theme/audit.ts), so a mistyped font step renders nothing andno guard objects.
fontSizewas also the one scale the rootCLAUDE.mdvocabulary section neverlisted, leaving the only unguarded scale as the only undocumented one; it is now a row in that
table, marked unguarded, with the two traps that follow —
mdis 18px and sits betweenbaseandlg, not where Tailwind puts it, and since the preset extends rather than replaces,text-3xlresolves to Tailwind's 30px and silently leaves the deck scale.
Callsites
Kit: tooltip trigger
ⓘ, modal close✕, toast dismiss×.GLITCH:
⧉duplicate,✕remove,+add effect, andIconLabelButton's glyph (⚄randomize,⟳re-roll).ASCII//Convert: the AI-config banner dismiss
×.IconLabelButtontakesICON_GLYPH_SIZE sm:text-smon its inner<span>, not on theButton: theButton's font size is an arbitrary property (
[font-size:var(--btn-secondary-size)]) thattailwind-merge does not read as a conflict. Below
smthe glyph stands alone at 18px; fromsmthelabel is beside it and the glyph drops back to the Button's own 13px.
Verified in the browser
Both apps driven at 390px and 900px, sizes read off
getComputedStyle:ⓘtooltip (5 sliders)⧉/✕chain-editor⚄randomize /⟳re-roll× clear/⇋/⇄over canvasexport png/export txtThe tooltip was the one callsite with a layout cost, and it came in as predicted: the Slider label
row went 11px → 18px, exactly +7px, bounded by the pinned line box. The EDIT panel still closes at
bottom: 664in a 664px viewport, so the params stay on screen. Canvas overlays are untouched inboth apps — the regression that mattered most not to cause.
Full suite green (2137 tests across 5 workspaces), typecheck and Biome clean.
Review follow-ups (second commit)
A two-axis review ran over the first commit. Standards found no hard breach; Spec found no scope
creep and nothing behaviourally wrong. Five judgement calls were applied:
touch-target.tsnow points back aticon-glyph.ts— the cross-reference had only run one way,and the box side is the older and better-known of the two.
leading-nonerationale had been written in four places; it now lives in the constant'sJSDoc alone, with local comments carrying only the local fact.
ICON_GLYPH→ICON_GLYPH_SIZE: it holds a size, not a glyph, and reads honestly besideTOUCH_TARGET_HEIGHT/TOUCH_TARGET_ICON.fontSizerow added to the scale vocabulary table (above).are now named.
Known, not addressed here
⚿in ASCII//Convert's header has no glyph in the display font and renders as tofu — pre-existing,and out of the rule's scope since it has a label beside it.
+chip is 29px wide abovesm(Chiphasmin-h-[44px]but nomin-w, and the callsite'ssm:w-autoshrinks it). Pre-existing; this change widened it from ~20px rather than causing it.🤖 Generated with Claude Code