refactor(web): composer controls own their look instead of restyling ui components - #13209
Conversation
| */ | ||
| function composerControlClassName(size: ComposerControlSize, className?: string) { | ||
| return cn( | ||
| "relative inline-flex shrink-0 cursor-pointer items-center justify-center whitespace-nowrap rounded-[var(--control-radius)] border border-transparent text-base outline-none hover:bg-accent data-pressed:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-disabled:pointer-events-none data-disabled:opacity-64 pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 [&:active:not([aria-haspopup])]:scale-[0.97] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:-mx-0.5 [&_svg[data-composer-control-icon]]:mx-0 [&_svg:not([class*='text-'])]:text-[var(--control-icon-color)]", |
There was a problem hiding this comment.
Shared primitives over custom controls: this recreates ui/Button and ui/SelectTrigger styling instead of composing those primitives. Add the composer sizes/variants to the UI primitives and have ComposerControl delegate to them.
Suggested fix: No diff; the fix requires coordinated primitive variants and component changes.
Posted via Macroscope — UI Consistency
| // The composer's labeled primary actions (Submit, Refine, Implement) share the send button's | ||
| // message-action pill, so they are composer-owned buttons rather than restyled Buttons. | ||
| const messageActionPillClassName = | ||
| "inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-full bg-message-action font-medium text-base text-message-action-foreground shadow-xs shadow-message-action/24 outline-none hover:bg-message-action-hover focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 disabled:shadow-none sm:text-sm"; |
There was a problem hiding this comment.
Shared primitives over custom controls: this class turns several raw <button> elements into product controls. Add a message-action variant/size to ui/Button and render these actions with Button instead.
Suggested fix: No diff; the fix requires adding a shared Button variant and updating multiple call sites.
Posted via Macroscope — UI Consistency
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This multi-surface web refactor changes the runtime appearance and implementation of composer, model-picker, attachment, and settings controls, including replacing shared UI wrappers with custom styling and raw buttons. The unresolved architecture concerns about bypassing shared primitives merit human evaluation before merging. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: pingdotgg/t3code/.coderabbit.yaml Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (15)
💤 Files with no reviewable changes (6)
Included review availability: Your plan provides up to 10 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthroughComposer controls now use Base UI primitives or native buttons with updated styling. Provider and traits picker trigger variants were removed, and model-picker list styles changed. The restyle lint threshold is now zero. ChangesComposer and picker controls
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Refactor Possibly related PRs
Suggested reviewers: Merge Risk: ⚪ Minimal · up to No actionable issue remains from these control changes; the PR is mergeable after normal checks. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
…ui components The chat composer restyled Button, SelectTrigger and ComboboxItem with className in 101 places. components/ui stays generic, so nothing here adds a ui variant; each cluster either becomes a composer-owned element or moves onto an existing primitive. - ComposerControl / ComposerSelectControl: the composer toolbar control is a real named concept but composer-specific, so it is now an app control that renders its own element (useRender button, Select.Trigger) with one class recipe for the sm toolbar and the dimmer xs resting strip. Plan mode is marked with aria-pressed instead of call-site color classes. Settings pickers that pass triggerVariant still get a plain Button in that variant. - Provider-unavailable action becomes a ComposerControl (was a ghost Button restyled to look like one). - ComposerPrimaryActions: Submit/Refine/Implement pills share the send button's message-action look, which only the composer uses, so they are plain composer-owned buttons with one local class recipe, like send and stop already were. Previous buttons drop rounded-full (plain outline). - Attachment chips: retry uses Button's overlay variant and remove uses media-close (drift from bg-background/85). The snap-shot hover reveal moves to a plain wrapper span. - Model picker: ModelListRow and the legacy row drop their padding, radius and highlight overrides and use ComboboxItem's own states; the favorite star uses ghost-muted; provider setup link becomes InlineButton; the list and empty state use their defaults. ComboboxItem's hover no longer paints disabled rows (generic fix, replaces data-disabled:hover:bg-transparent). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
bb80f82 to
2212de6
Compare
…ui components (pingdotgg#13209) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ui components (pingdotgg#13209) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
## What's Changed * hatch/variant functions by @juliusmarminge in pingdotgg/t3code#13191 * refactor(web): context chips render through one ContextChip component by @juliusmarminge in pingdotgg/t3code#13192 * refactor(web): ui components drop their secondary className props by @juliusmarminge in pingdotgg/t3code#13193 * refactor(web): menu triggers and items stop restyling ui/menu by @juliusmarminge in pingdotgg/t3code#13205 * refactor(web): field controls stop restyling Input, Select, Combobox and Command by @juliusmarminge in pingdotgg/t3code#13206 * refactor(web): app code stops restyling sidebar, popover, table and misc ui exports by @juliusmarminge in pingdotgg/t3code#13207 * refactor(web): Button consumers outside the composer stop restyling it by @juliusmarminge in pingdotgg/t3code#13208 * refactor(web): composer controls own their look instead of restyling ui components by @juliusmarminge in pingdotgg/t3code#13209 * chore(web): no-restyle fails lint, and the ceiling gate goes by @juliusmarminge in pingdotgg/t3code#13210 * fix(mobile): recover from screen render errors by @juliusmarminge in pingdotgg/t3code#13197 * feat(web): navigate back and forward with mod+[ and mod+] by @juliusmarminge in pingdotgg/t3code#13212 * fix(web): sort title matches by recent activity by @Yash-Singh1 in pingdotgg/t3code#13219 * test(desktop): remove redundant keyring module-load test by @t3-code[bot] in pingdotgg/t3code#13220 **Full Changelog**: pingdotgg/t3code@v0.0.43-nightly.20260923.2135...v0.0.43-nightly.20260923.2150 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.43-nightly.20260923.2150
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
## What Changed `AgentPicker.fork.tsx` drops the `triggerVariant` prop and stops passing `variant` to `ComposerControl`. No caller sets `triggerVariant`, so the trigger renders as before. ## Why Upstream `0e512db` (`pingdotgg#13209`) removed `variant` from `ComposerControl`. Syncing `v0.0.43-nightly.20260923.2150` replays cleanly but fails web typecheck at `AgentPicker.fork.tsx`, blocking the sync. Landing this on the trunk first lets the sync pass its check battery. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why - [ ] I included before/after screenshots for any UI changes - [ ] I included a video for animation/interaction changes ## Fork trailers Refs #1277 Fork-Domain: custom-agents Fork-Tier: bugfix Fork-Upstreamable: no Co-authored-by: donjor <38745786+donjor@users.noreply.github.com>
The composer's controls own their look instead of restyling ui components. No composer look goes into
components/ui.ComposerControl/ComposerSelectControlrender their own element with one class recipe for the toolbar size and the resting-strip size, instead of restyling Button and SelectTrigger. Plan mode isaria-pressed. The "open provider settings" button is a ComposerControl too.triggerVariant="outline"plus a size and colour class string, which restyled a real Button where the lint rule couldn't see it. In Settings they are now the composer control, 28px on every breakpoint, with no outline.overlay(a dark circle), remove usesmedia-close, and the snapshot hover-reveal moves to a wrapper.ComboboxItem's defaults, so they are tighter with the standard highlight.ghost-muted, and "open provider setup" is anInlineButton.ComboboxItem(generic): disabled items don't highlight on hover.No screenshots yet: these changes are verified by lint, typecheck and tests only.
no-restylefindings: 101 → 0.Claude Opus 5.5 via Claude Code.
🤖 Generated with Claude Code
Summary by CodeRabbit