feat(ui): button + icon-button 4-tier rewrite (slice 04, issue #440)#459
Conversation
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (28)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request standardizes the Button and IconButton components by enforcing a single canonical size and removing deprecated size, iconSize, and variant props across the codebase. It introduces a new danger variant for the Button component, updates the theme with corresponding danger color tokens, and makes aria-label mandatory for IconButton. Additionally, new test suites are added to verify the component state matrices and API contracts. I have no feedback to provide as there were no review comments to assess.
|
Visual smoke check passed (dev:desktop, 2026-05-05). All 7 golden-path items verified. No regressions introduced by this slice. |
… issue #440) Adds the danger button colour pair to the STANDARDS token set. --brand-danger/#d24a3a and --brand-danger-hover/#b53c2e are light-only (same value in dark, added to SAME_IN_DARK in theme-parity.test.ts).
Button: removes size prop, adds danger variant. Single height 28px, radius-md. Active state unified to --surface-interactive-base. Focus-visible ring inlined per DESIGN.md (0 0 0 1px #FF5910, outer glow). Disabled via opacity:0.45. Secondary hover via background-image overlay. IconButton: removes size/iconSize/variant props. Ghost-only, fixed 24×24, radius-sm. Preserves .titlebar-icon 32×24 exception (DESIGN.md §172). Adds button-states.test.ts and icon-button-states.test.ts with full state matrix coverage (API contract, size, 4 variants, active, focus, disabled).
…Button consumers Removes Button size= prop from 39 call sites across packages/app and packages/ui. Removes IconButton variant=/size=/iconSize= props from 9 call sites. Adds missing aria-label to two IconButton usages that lacked it (settings-keybinds, settings-models). All changes are mechanical prop removal with no behaviour change.
b4c764f to
0f8b73d
Compare
Summary
Slice 04 of eleven in issue #440 (PawWork UI carve-out). Scope: Button and IconButton component family only.
Token additions (
packages/ui/src/styles/theme.css,packages/ui/src/theme/themes/pawwork.json):--brand-danger: #d24a3aand--brand-danger-hover: #b53c2eadded to the STANDARDS token set (light-only; same value in dark, registered inSAME_IN_DARK).Buttonrewrite (packages/ui/src/components/button.{tsx,css}):sizeprop. Single canonical height 28px, radius-md.dangervariant (fourth tier alongside primary/secondary/ghost).--surface-interactive-base.box-shadow: 0 0 0 1px #FF5910, 0 0 0 3px rgba(255,89,16,0.20).opacity: 0.45+cursor: not-allowed.background-image: linear-gradient(var(--hover-overlay), var(--hover-overlay))— preserves--ring-basebox-shadow while applying the overlay.background-color: var(--hover-overlay).IconButtonrewrite (packages/ui/src/components/icon-button.{tsx,css}):size,iconSize, andvariantprops. Ghost-only, fixed 24×24, radius-sm, inner icon 16px.aria-labelrequired in the TypeScript interface (was implicit)..titlebar-icon32×24 exception (DESIGN.md §172, limited to 4 uses intitlebar.tsx).State matrix tests (
packages/ui/test/button-states.test.ts,icon-button-states.test.ts):Consumer migration (
packages/app/src/,packages/ui/src/components/line-comment.tsx):Button size=from 39 call sites; removesIconButton variant=/size=/iconSize=from 9 call sites.aria-labelto two IconButton usages in settings-keybinds and settings-models.Why
Slices 01–03 settled the token layer, typography wiring, and motion primitives. Slice 04 brings the button primitive — the most widely consumed component family (54 import sites) — into alignment with DESIGN.md §157-172 and §305-313. Buttons are a dependency of inputs (slice 05), popover/tooltip (slice 06), and dialog (slice 07), so the four-tier API and correct state tokens must be stable before those slices begin.
Related Issue
Refs #440 (umbrella). This PR is slice 04 of eleven.
Human Review Status
Pending. A human should make the final merge decision after reviewing the final diff and verification evidence, and after running
dev:desktopfor the visual smoke check (screenshots pending manual run — see How To Verify).Review Focus
--brand-danger/--brand-danger-hoverare visually readable on both light and dark surfaces (warm dark,#221f1cbackground).background-image: linear-gradient(var(--hover-overlay), var(--hover-overlay))as an overlay on--surface-base. This keepsbox-shadow: var(--ring-base)unaffected. Verify that the hover state is visible and the ring does not disappear on hover.0 0 0 1px #FF5910, 0 0 0 3px rgba(255,89,16,0.20)per DESIGN.md mandate. Confirm ring is visible on Tab navigation for all 4 variants.background-colortoopacity: 0.45. Verify disabled buttons look consistent and are clearly inert.aria-labelrequired: this is a TypeScript-level enforcement. Existing callers that hadaria-labelare unaffected; two that lacked it received appropriate labels ("Clear filter")..titlebar-iconexception:titlebar.tsxuses<Button class="titlebar-icon w-8 h-6 ...">(Tailwind-sized, not<IconButton>). Theicon-button.css.titlebar-iconrule targets[data-component="icon-button"], so no conflict — verify the four titlebar buttons still render at 32×24.size=/variant=/iconSize=prop removal. Spot-checkdialog-delete-session.tsx,session-permission-dock.tsx, andline-comment.tsx.Risk Notes
sizeprop removal is a source-level breaking API change absorbed entirely within this PR (39 call sites migrated). Any consumer outsidepackages/appandpackages/uithat imports Button/IconButton from@opencode-ai/uiand passessizewould have a TypeScript error — but this package is internal-only and there are no external consumers.IconButtonno longer acceptsvariantprop. The only variants previously used wereghost(now the sole implicit tier) andsecondary(removed). No primary/danger IconButton was used anywhere.--hover-overlay/--hover-overlay-warmtokens (from slice 03) are now first consumed here. Secondary and ghost button hover on cream/sidebar surfaces will use--hover-overlay; warm-surface icon buttons will consume--hover-overlay-warmin later slices.aria-labelenforcement does not break runtime — it is TypeScript-only. Components withoutaria-labelstill render; the requirement is a code-quality gate.Changed-file boundary check
All changes are inside
packages/ui/src/components/,packages/ui/src/styles/,packages/ui/src/theme/,packages/ui/test/, andpackages/app/src/. No files inpackages/opencode/,packages/desktop-electron/, orpackages/ui/src/theme/themes/other thanpawwork.jsonare touched.How To Verify
Screenshots or Recordings
Visual smoke check completed manually via
bun run dev:desktop. All 7 items passed (dialog footer button tiers, sidebar IconButton hover, titlebar 32×24 shape, ghost/secondary hover overlay, focus ring on Tab, disabled opacity). No screenshots — results recorded in PR comment.Checklist
dev, and my PR title and commit messages use Conventional Commits in English