Skip to content

feat(checkbox): MoonSize tiers, the reviewed checkbox design and bundled Inter - #66

Merged
kirillDevPro merged 3 commits into
Moonbot-Tech:masterfrom
ThusMad:feat/checkbox-redesign
Sep 13, 2026
Merged

feat(checkbox): MoonSize tiers, the reviewed checkbox design and bundled Inter#66
kirillDevPro merged 3 commits into
Moonbot-Tech:masterfrom
ThusMad:feat/checkbox-redesign

Conversation

@ThusMad

@ThusMad ThusMad commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

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 bundled Inter-SemiBold.ttf was also a byte-for-byte copy of Inter-Regular.ttf. moon_ui_components::init now registers the fonts, embedded as 'static bytes, 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.

  • Shared size scale. 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.
  • Checkbox API. Checkboxes support Sm and Md. size(impl Into<MoonCheckboxSize>) accepts a tier directly, and Compact and Normal remain as deprecated aliases.
sm md
Box / radius 16 / 4px 20 / 6px
Mark / stroke 12 / 1.67px 14 / 2px
Text (label Medium, description Regular) 14/20 16/24
Box→text / label→description gap 8 / 0px 12 / 2px
  • Checked state. The box is one solid tone, border and fill alike, and the mark uses the palette ink with the best contrast on that tone.
  • Marks. The check and indeterminate minus come from SVG assets. Their stroke-width is 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.
  • Scaling. The tiers follow only UI zoom; custom sizes keep following text scaling.
  • Interaction. Pointer cursor, no hover or press fill. A 2px focus ring whose outer edge sits 4px outside the box is drawn as an overlay, so it never changes layout. Pressing a checkbox now focuses it.
  • Audit contract. checkbox.checked_glyph.asset moves from a golden-PNG presence check to the stroke-rewrite and mark-geometry tests.
  • Baselines. The API baseline records the additions and declares the two widened signatures (MoonCheckbox::size, and the foundation re-export gaining MoonSize). The mirror and audit baselines record the reviewed base-checkbox drift, which is still one file and within budget. .vscode is ignored.

How to verify

  • tools\run-component-guardrails.ps1 passes on every commit: 454, 455 and 464 component tests, and 7 gallery tests each time.
  • cargo test -p moon-gpui passes (186 tests).
  • New tests:
    • tests/bundled_fonts.rs runs 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 on windows-latest; GPUI enumerates the software adapter there, but this has not run in CI yet.
    • root::clicking_empty_space_moves_focus_off_control fails when track_focus is removed.
    • The checkbox layout tests use debug-selector probes: mark size and centring, description stacking and gaps, focus ring geometry without layout movement, and click-to-focus followed by Tab. They also cover the stroke rewrite for both icons, tier snapping, deprecated aliases, and serde reading the old MoonSize names.

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

ThusMad and others added 3 commits September 13, 2026 20:53
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants