feat(ui): add the @lody/ui Toggle, ToggleGroup and Toolbar - #727
Merged
Merged
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
A control that stays pressed, a set of them answering to one value, and the bar that holds them, sharing one `toggle` token group. On is the well rather than ink. The rules give a stored state ink, and ink is what a control that already sits in a well becomes when it is on — a Switch's off state occupies the well, so on has to leave it. A toggle rests on nothing, so the well is free, and sinking into it is the plainest thing this system can say about a button that went down and stayed. It also keeps a bar of eight from reading as eight primary buttons. A set is not a Tabs strip with its track removed: a strip picks what you see, so it is one control with one pill sliding across it, while a set stores what is on and two of its members can be pressed at once. A bar draws nothing at all — not even the line a table draws — and exists to make a row of controls one tab stop the arrow keys walk. Migrates the task body's format bar and the tasks view's "Show" chips, and deletes the dead Radix `toggle.tsx` and its dependency. Model: claude-opus-5[1m]
Model: claude-opus-5[1m]
wibus-wee
force-pushed
the
feat/ui-toggle-toolbar
branch
from
September 15, 2026 10:53
196109a to
147220f
Compare
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.
Related issue
Same-repository branch; no intake Issue.
Problem / pressure
@lody/uihas a control for every value a form stores and none for the state an interface holds without storing it — bold, wrapped lines, this filter. So twenty-two files inpackages/componentseach draw their ownaria-pressedbutton, and the fills they chose to mean "on" run to thirteen unrelated washes:bg-muted,bg-muted/30,/40,/60,/80,bg-muted-foreground/20,bg-secondary,bg-secondary/50,bg-primary/10,/15,/[0.05],bg-white/10,bg-white/14— and several that change nothing but the text colour.packages/components/src/ui/toggle.tsx(the Radix wrapper) had reached zero in-repo callers and was never deleted, so@radix-ui/react-togglewas still a production dependency of a package that never imported it.Summary
packages/ui/src/toggle/: one family, one token group.toggle.tokens.stylex.ts(+ palette theme),surface.ts(shared appearance),set.ts(the size/shape context, in its own file so the two parts do not close an import cycle),toggle.tsx,toggle-group.tsx,toolbar.tsx.Button; the state is a fill and a label colour (secondaryLabel→label).Toggle:mini/small/medium/large(24/28/32/36, taken fromcontrol, not frombutton),shape="pill",icon, and Base UI'spressed/onPressedChange/value. A real<button>witharia-pressed; it does not bob, it goes down and stays.ToggleGroup: generic over the caller's own union,multiple,wrap,orientation; states the size and shape once for its members. Not aTabsstrip — two members can be pressed at once, which no sliding pill can say, so there is no track.Toolbar:Root/Button/Group/Separator. Draws nothing at all, not even the line a table draws; it exists to make a row of controls one tab stop the arrow keys walk, skipping the disabled ones.Toolbar.Buttonis Base UI's, unstyled, like every trigger here.separator.tsxnow exports its styles so the bar's line is the same oneSeparatordraws.tasks/task-body-selection-toolbar.tsx(the whole bar: nine tab stops → one) andtasks/tasks-workspace.tsx(the "Show" chips → a wrapping multiple set).src/ui/toggle.tsxdeleted,@radix-ui/react-toggleremoved.test/toggle.test.tsx(13 tests),test/gallery.test.tsxtoken coverage,RULES.md"Pressed", README rows and prose, anAGENTS.mdbullet (existing bullets trimmed in wording only to stay under the 8 KiB gate — it was 8190 of 8192 bytes, now 7956; no rule changed),specs/ui-primitives.md(draft), and an implemented Agent Note.Visual explanation
Before / after
<button>witharia-pressedand a bespokecn(...)Toggle, with the size ladder, the pill shape, the ring and the disabled opacityflex-wrapdiv of hand-styled buttonsToggleGroup multiple wrap, reporting every pressed membertoggle.tsxand an unused@radix-ui/react-toggledependencyTest plan
pnpm --filter @lody/ui test: 21 files, 258 tests pass — 13 new intest/toggle.test.tsx(the button and itsaria-pressed; controlled press; the rest/pressed class pair; the glyph box, including throughToolbar.Button render={…}; nativedisabled; size stated once on a set and overridden on a member; one-of and several-of; the set as one tab stop with arrow-key walking; the bar's role, its empty appearance, a toggle staying a toggle inside it, a disabled control stepped over, and the bar's line beingSeparator's turned ninety degrees) plus the board's token coverage.pnpm --filter @lody/ui typecheck, rootpnpm typecheck: clean.NODE_ENV=development pnpm --filter @lody/components test: 445 files, 3306 tests pass.pnpm lint: 0 errors (0 warnings on the new files).pnpm lint:i18n: clean after addingtasks.body.format.marks/.blocksto both locales.pnpm check:public-boundary,check:platform-boundaries,check:code-collab-imports: pass.pnpm run docs check: no errors.rgb(232, 234, 237)/rgb(28, 28, 28)undershadow.inset; the bar paintsrgba(0,0,0,0)withbox-shadow: none, 8px between clusters and 4px inside one; its line is a 1px hairline stretched to the 28px row.pnpm install --frozen-lockfilepasses on the hand-edited lockfile.Context handoff
Instructions for reviewing agents
surface.ts(the ring composed onto the pressed edge, not replacing it),toggle-group.tsx(generic, so the ref is a prop),toolbar.tsx(Toolbar.Buttonunstyled; the separator reusesseparatorStyles).multipleis off; aToolbarthat draws nothing; omittingToolbar.Input/Link; theAGENTS.mdtrims must not have changed a rule..darktheme--popoverishsl(220 54% 11.5%)and the well ishsl(0 0% 11%), so the "Show" chips lean on the label colour until that menu becomesMenu.Authoring context
@lody/uiatoms on Base UI, strictly to the new design; per component: settle the tokens, write the primitive, add the board entry, then migrate the old callers. This round was a gap survey of what atoms are still missing.@lody/uidepends only on React, Base UI and StyleX;packages/ui/AGENTS.mdmust stay strictly under 8192 bytes; one family per PR.packages/components; hand-editingpnpm-lock.yamlrather than re-resolving (a full--lockfile-onlyrun also re-resolvesesbuild,better-authand@stylexjs/unpluginfor unrelated reasons — 137 lines for a 3-line removal).packages/components/src/ui/toggle.tsx(zero in-repo callers before this PR).aria-pressedfiles (most are selected rows or radios wearing a disguise, not toggles); the file viewer's action strip — its two toggles are the clearest case this family has, but moving two of eight 24px buttons puts two glyph sizes in one row, and the row cannot move together until its Save button'sstatus-warningtone is decided (these rules givewarningto an outcome, not to a control a person presses); the format bar's own popover surface; regeneratingopen-source-attributions.generated.ts(a 12,484-line diff of unrelated drift since 2026-09-04).🤖 Generated with Claude Code