Skip to content

fix(ui): buttons no longer shift or resize on click (colour-only press)#103

Merged
eliotlim merged 4 commits into
mainfrom
fix/ob-376-press-state-stability
Jul 5, 2026
Merged

fix(ui): buttons no longer shift or resize on click (colour-only press)#103
eliotlim merged 4 commits into
mainfrom
fix/ob-376-press-state-stability

Conversation

@eliotlim

@eliotlim eliotlim commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Problem

Interactive controls physically shrank or nudged when pressed: Button scaled to 0.97, IconButton to 0.94, and the kit action button moved down 1px. This reads as jitter and is the press-instability the epic targets. Board: OB-376 (Epic OB-374 — colour & interaction consistency).

Solution

Replace the three transform-based presses with a colour-only press, formalising a two-rule model already latent in the design system (imported in OB-271):

  • Opaque/filled controls (Button default/destructive/secondary, .obe-kit-action) darken their fill by mixing --press-ink (8%, the DS press standard).
  • Transparent controls (Button ghost/outline/link, IconButton) deepen to --hover-strong (the DS pressed/selected token, already used for selected tree rows).

Key files: button.tsx, icon-button.tsx, index.css (.obe-kit-action), sidebarStyles.ts (dropped the now-redundant active:scale-100 guard). New deps: none. Design review (Devon) caught that the first pass restored press feedback only for filled variants and dropped it for ghost/outline/link (~35 + ~28 call sites, incl. the profile-menu trigger); fixed here so every variant has a colour press.

Before / After

Behavior Before After
Filled primary button, press-and-hold Before: button scales to 0.97 while held
scales to 0.97 while held — visibly shrinks and springs back (131px pressed vs 135px resting)
After: colour-only press, no size change
fill darkens via --press-ink only — 135px pressed = 135px resting, byte-identical edges
Button ghost / outline / link scale(0.97) only bg deepens to --hover-strong (link: text-primary/70); no geometry change
IconButton scale(0.94) active:bg-hover-strong; no geometry change
.obe-kit-action translateY(1px) fill darkens via --press-ink; no geometry change

Test procedure

  • pnpm verify (repo root) — typecheck + lint (6 pkgs), unit (sdk 152 / ui 847 / server 586), server+mcp e2e. All green.
  • Press-state guard: packages/web/e2e/press-state.spec.ts — holds a real mousedown over a Button, an IconButton, and a plain ghost Button, asserting getBoundingClientRect is identical resting-vs-pressed in light and dark, and that the background changed vs the hover-only state (proves :active engaged → the geometry check is non-vacuous). Verified to fail if a scale is reintroduced.
    • Run: build ui, rm -rf packages/web/.next, then the web e2e harness (4 workers × own data server, port 4400+workerIndex).

Operational notes

  • Pure CSS/class change; no runtime/data/behaviour change beyond press visuals. Strictly better under prefers-reduced-motion (no transform left to suppress). No migration, no env vars, nothing irreversible.
  • Capture GIFs live on the chore/artifacts branch (pr-assets/ob-376/), kept off this branch so no binaries merge to main.

Footer: verify green (typecheck 6 · lint 6 · unit 1585 · server e2e 251 · mcp 39 · press-state 1); design gate cleared by Devon (CLEAR-WITH-NITS, all nits addressed in-PR, pre-endorsed → no re-review).

🤖 Generated with Claude Code

https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG

eliotlim and others added 4 commits July 5, 2026 20:19
…ze on click

Replace the three transform-based press treatments with the existing
colour-only press language (OB-376):

- Button: drop active:scale-[0.97] + disabled:active:scale-100, remove
  transform from the transition list (colour-mix press-darken stays).
- IconButton: drop active:scale-[0.94] + disabled:active:scale-100; add a
  colour-only press (bg deepens to bg-hover-strong on :active) so it keeps
  visible feedback.
- .obe-kit-action: delete the translateY(1px) press, swap transform out of
  the transition, add a --press-ink colour-mix darken to match Button.
- SIDEBAR_PRESS: drop the now-redundant active:scale-100 override.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG
Playwright e2e holds a real mousedown over a representative shared Button
(sidebar Settings) and IconButton (page-actions copy-link) and asserts
getBoundingClientRect is identical resting vs pressed, in light and dark.
Waits for the :active transition to settle before measuring (background-color
— and the removed transform — animate on the shared tempo) and asserts the
background-color changes on press, proving the mousedown engaged :active so
the geometry check is not vacuous.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG
The base active:scale-[0.97] covered every variant; removing it left the
transparent variants (ghost/outline) and link with hover but no press state,
since the colour-mix press only exists on the opaque fills. Complete the
two-rule model: transparent controls deepen to --hover-strong (the DS
pressed/selected token) on :active, link darkens its text.

- ghost:   add active:bg-hover-strong active:text-accent-foreground
- outline: add active:bg-hover-strong
- link:    add active:text-primary/70 (no bg press is conventional)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG
- Add a plain ghost Button probe (sidebar Home launcher) asserting zero
  getBoundingClientRect delta on a held mousedown, so the base scale press
  can't silently regress for the transparent variants again. It is a
  geometry-only leg: HomeButton's SIDEBAR_HOVER dark override ties hover to
  active in dark, so the colour proof stays on targets with cleanly distinct
  hover/active in both themes.
- Tighten the non-vacuity proof: compare hover-only bg vs pressed bg (both
  after the transition settles) so it proves :active specifically, not :hover.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG
@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app.book.pub Ready Ready Preview, Comment Jul 5, 2026 12:53pm

Request Review

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.

1 participant