feat(checkbox): MoonSize tiers, the reviewed checkbox design and bundled Inter - #66
Merged
kirillDevPro merged 3 commits intoSep 13, 2026
Merged
Conversation
…installing The theme asks for "Inter" and "Geist Mono", but no desktop platform registered the bundled files: only the web text system loaded them. On a machine without Inter installed every MoonUI app fell back to the system face (Segoe UI on Windows), which has no Medium weight and is not monospaced. The bundled Inter-SemiBold.ttf was also a byte-for-byte copy of Inter-Regular. `moon_ui_components::init` now registers the fonts, embedded as 'static bytes, with the app's text system on desktop; the web platform keeps loading its own copy and gains the new weights. Inter ships at Regular, Medium, SemiBold and Bold: the 18pt optical-size static cut (OFL 1.1, no Reserved Font Name) with its family renamed from "Inter 18pt" to "Inter" and STAT removed, so the theme's family resolves on DirectWrite, CoreText and cosmic-text without an alias. NOTICE records the licence and the modification. `tests/bundled_fonts.rs` runs the real platform (headless Windows uses a no-op text system) without the libtest harness, since quitting that platform ends the process, and checks that the four Inter weights and Geist Mono resolve to distinct faces. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A press only moves focus when it lands on a focusable element, so clicking empty space left the last control focused indefinitely, and a window with no focus never delivered Tab to Root's handler at all. Root now tracks its own focus handle (not a tab stop). GPUI focuses the nearest focusable element under a press, so a click that no control claims focuses Root: the previous control blurs, and keys still reach Root's Tab handling because focus lands on Root rather than on nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Introduces `MoonSize { Xs, Sm, Md, Lg, Xl, Xxl }` as the shared size scale
(reusing the unused foundation enum; the old variant names stay as deprecated
consts and serde aliases). A component renders the tiers it supports and snaps
the rest to the nearest one; checkboxes are the first: `Sm` and `Md`, with
`MoonCheckboxSize::Compact`/`Normal` kept as deprecated aliases and
`size(impl Into<MoonCheckboxSize>)` accepting a tier directly.
Checkbox design, per tier (sm / md):
- box 16 / 20px, radius 4 / 6px, checked state is one solid tone (border and
fill), mark in the palette ink with the best contrast on that tone;
- check and indeterminate minus marks from SVG assets, 12 / 14px, their stroke
rewritten at paint time to 1.67 / 2px and tinted, so the shape stays a file
while stroke and colour are metrics; the mark is centred inside the 1px
border (it sat 1px low-right before);
- text 14/20 and 16/24, label Medium, new `description()` support text Regular,
box-to-text gap 8 / 12px, label-to-description gap 0 / 2px; with a
description the box centres on the label's line;
- tiers follow only UI zoom; custom sizes keep following text scaling;
- pointer cursor, no hover or press fill;
- a 2px focus ring whose outer edge sits 4px outside the box, drawn as an
overlay so it never changes layout; pressing a checkbox now focuses it.
The `checkbox.checked_glyph.asset` audit contract moves from a golden-PNG
presence check to the stroke-rewrite and mark-geometry tests. The API baseline
records the additions and declares the two widened signatures; the mirror and
audit baselines record the reviewed base-checkbox drift. `.vscode` is ignored.
Gallery screenshots are not refreshed in this change: the new geometry and the
bundled Inter alter most pages, and the opt-in snapshot comparison needs a
reviewed capture.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
What & why
Three commits, each passing the guardrails on its own:
1.
feat(fonts): bundle Inter and Geist Mono so apps render them without installing. The theme asks for "Inter" and "Geist Mono", but only the web platform registered the bundled files. On a desktop without Inter installed, every MoonUI app fell back to the system face (Segoe UI on Windows), which has no Medium weight and isn't monospaced. The bundledInter-SemiBold.ttfwas also a byte-for-byte copy ofInter-Regular.ttf.moon_ui_components::initnow registers the fonts, embedded as'staticbytes, with the app's text system. Inter ships at Regular, Medium, SemiBold and Bold: the 18pt optical-size static cut, with the family renamed from "Inter 18pt" to "Inter" and STAT removed, so the theme's family resolves on DirectWrite, CoreText and cosmic-text without an alias. NOTICE records the OFL licence and the modification. Binary size grows by about 1.7 MB.2.
fix(root): clicking empty space moves focus off the focused control. A press only moved focus when it landed on a focusable element, so clicking empty space left the last control focused indefinitely. A window with nothing focused also never delivered Tab to Root's handler. Root now tracks its own focus handle (not a tab stop). A click that no control claims focuses Root: the previous control blurs, and Tab still works.3.
feat(checkbox): MoonSize tiers and the reviewed checkbox design.MoonSize { Xs, Sm, Md, Lg, Xl, Xxl }reuses the previously unused foundation enum; the old variant names stay as deprecated consts and serde aliases. A component renders the tiers it supports and snaps the rest to the nearest one.SmandMd.size(impl Into<MoonCheckboxSize>)accepts a tier directly, andCompactandNormalremain as deprecated aliases.stroke-widthis rewritten at paint time and the colour is applied as a tint, so the shape stays a file while stroke and colour are metrics. The mark is now centred inside the 1px border; it previously sat 1px low and right.description()support text. Appears under the label. With a description, the box centres on the label's line.checkbox.checked_glyph.assetmoves from a golden-PNG presence check to the stroke-rewrite and mark-geometry tests.MoonCheckbox::size, and thefoundationre-export gainingMoonSize). The mirror and audit baselines record the reviewed base-checkbox drift, which is still one file and within budget..vscodeis ignored.How to verify
tools\run-component-guardrails.ps1passes on every commit: 454, 455 and 464 component tests, and 7 gallery tests each time.cargo test -p moon-gpuipasses (186 tests).tests/bundled_fonts.rsruns the real platform (headless Windows uses a no-op text system) without the libtest harness, because quitting that platform ends the process. It checks that Inter 400/500/600/700 and Geist Mono resolve to distinct faces. It fails when registration is removed. CI note: it creates DirectX devices onwindows-latest; GPUI enumerates the software adapter there, but this has not run in CI yet.root::clicking_empty_space_moves_focus_off_controlfails whentrack_focusis removed.MoonSizenames.Not in this PR: refreshed gallery golden snapshots. The new checkbox geometry and the bundled Inter change most pages, and the opt-in snapshot comparison needs a reviewed capture.
🤖 Generated with Claude Code