feat(ui): make Mosaic button hover land instantly and fade out - #9298
Conversation
🦋 Changeset detectedLatest commit: ef12fb4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
af13e9d to
2d70852
Compare
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/electron
@clerk/electron-passkeys
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-google-signin
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
API Changes Report
Summary
No API Changes DetectedAll packages have stable APIs with no detected changes. Report generated by Break Check Last ran on |
📝 WalkthroughWalkthroughThe change updates Mosaic motion guidance for hover, press, exit, entrance, and color-only state transitions. Button and Icon styles now use contextual durations, instant hover and active arrivals, base default timing, and persistent link underlines with animated color. Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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.
🧹 Nitpick comments (1)
packages/ui/src/mosaic/components/button/button.styles.ts (1)
89-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winShorten the inline timing rationale.
This block repeats
.claude/skills/mosaic/references/motion.mdand restates selector behavior. Keep one terse comment for the non-obvious:not(:active)constraint. Keep the timing explanation in the reference document.As per coding guidelines, comments must be minimal and must not restate code behavior.
Proposed comment reduction
- // The duration a state carries governs the transition INTO it, so asymmetry falls out - // of the selector rather than being declared twice. The press reads as contact, not a - // fade, so it lands instantly; `:active` stops matching on release and the color heads - // back at the hover/resting rate. Hover is quick to acknowledge and unhurried to let - // go — `fast` while hovered, so entering takes 0.1s, and `base` at rest, so leaving - // takes 0.15s. Instant press, soft settle; quick in, slow out. - // - // `:not(:active)` is load-bearing: inside `@media (hover: hover)` the hover branch - // would otherwise outrank the bare `:active` and steal the press's instant duration. - // The resting value also covers release-from-press on a device with no hover at all. + // Keep :not(:active) so hover styles do not override instant presses.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ui/src/mosaic/components/button/button.styles.ts` around lines 89 - 98, The timing comment block is overly verbose and duplicates external motion guidance. In the styles near the :not(:active) selector, remove the timing and selector-behavior explanation, retaining only one brief comment documenting why :not(:active) is required.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/ui/src/mosaic/components/button/button.styles.ts`:
- Around line 89-98: The timing comment block is overly verbose and duplicates
external motion guidance. In the styles near the :not(:active) selector, remove
the timing and selector-behavior explanation, retaining only one brief comment
documenting why :not(:active) is required.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: eee2dc71-9230-4fd6-8fac-bdb0c294a45a
📒 Files selected for processing (3)
.changeset/button-hover-timing.md.claude/skills/mosaic/references/motion.mdpackages/ui/src/mosaic/components/button/button.styles.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
clerk/clerk_go(manual)clerk/dashboard(manual)clerk/accounts(manual)clerk/backoffice(manual)clerk/clerk(manual)clerk/clerk-docs(manual)clerk/cloudflare-workers(manual)
2d70852 to
d22e1e2
Compare
Hover faded symmetrically at `fast` in both directions. It now arrives instantly and leaves at `base`, matching the press, which already landed instantly. The arrival is instant because a hover or a press is confirmation of something the pointer just did, and confirmation cannot lag. Only the exit is a judgement call: on an isolated control 0.15s costs nothing and takes the edge off, whereas across a traversed collection the same fade strings a wake of dimming rows out behind a fast sweep. Buttons get the exit; `Item` keeps none. Hover and press now carrying the same duration is what removes the machinery. The earlier split needed a `@media (hover: hover)` wrapper and a `:not(:active)` guard purely to stop the hover branch outranking the press; both are gone, and no hover-media guard is needed either, since a `:hover` that sticks after a tap only means the color already landed. `Icon` gets the timing handed to it through `--_cl-icon-duration`, alongside the `--_cl-icon-color` it already reads, since transitions do not inherit and an icon on its own duration would trail the button it sits in. Its standalone default drops from `fast` to `instant`: the arrival never varies, so any non-zero default was wrong for every container at once, and instant also leaves a traversed collection correct in both directions without opting into anything. The link variants' underline follows the same timing. `text-decoration-line` is a keyword and cannot tween, so toggling it snapped the underline away on exit while every other property faded. The line is now always drawn and only `text-decoration-color` moves, which paints nothing at rest, never participates in layout, and keeps the change a color so it inherits the shared timing unaltered. Documents the rules in the mosaic skill's motion.md: `linear` for anything that only recolors, an arrival that never varies, an exit decided by traversal rather than by element type, the three cases that look like this and are not, and the two traps — transitions not inheriting, and keywords not tweening. Corrects the duration-token comment, which still assigned hover to `fast`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Mosaic is pre-release, so its changes take empty changesets — matching `mosaic-item`, `mosaic-button-variants`, and `mosaic-popover`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
d22e1e2 to
ef12fb4
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.claude/skills/mosaic/references/motion.md:
- Around line 10-12: Align the duration tokens in the motion documentation with
the transition example: define the intended press-exit duration, then update the
--cl-duration-fast and --cl-duration-base table entries and the referenced
examples so hover and press exits consistently use the documented token.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: ebc53dee-237a-4639-a70c-9449c1e4b408
📒 Files selected for processing (5)
.changeset/button-hover-timing.md.claude/skills/mosaic/references/motion.mdpackages/ui/src/mosaic/components/button/button.styles.tspackages/ui/src/mosaic/components/icon/icon.styles.tspackages/ui/src/mosaic/tokens.stylex.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
clerk/clerk_go(manual)clerk/dashboard(manual)clerk/accounts(manual)clerk/backoffice(manual)clerk/clerk(manual)clerk/clerk-docs(manual)clerk/cloudflare-workers(manual)
🚧 Files skipped from review as they are similar to previous changes (4)
- .changeset/button-hover-timing.md
- packages/ui/src/mosaic/components/button/button.styles.ts
- packages/ui/src/mosaic/tokens.stylex.ts
- packages/ui/src/mosaic/components/icon/icon.styles.ts
| | `--cl-duration-instant` | `0s` | hover and press arrival | | ||
| | `--cl-duration-fast` | `0.1s` | exits | | ||
| | `--cl-duration-base` | `0.15s` | entrances, hover exit | |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Align the duration-token table with the transition example.
The table describes --cl-duration-fast as the exit duration. The example uses --cl-duration-base for leaving both hover and press states. Define the intended press-exit duration, then update the table and example so implementations cannot diverge.
Also applies to: 96-103, 125-129
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/skills/mosaic/references/motion.md around lines 10 - 12, Align the
duration tokens in the motion documentation with the transition example: define
the intended press-exit duration, then update the --cl-duration-fast and
--cl-duration-base table entries and the referenced examples so hover and press
exits consistently use the documented token.
Description
Mosaic Button hover arrived and left at the same 0.1s. It now lands instantly and leaves over 0.15s, matching the press, which already landed instantly.
The arrival is instant because a hover or a press is confirmation of something the pointer just did, and confirmation cannot lag. The exit is the only contextual half: on an isolated control 0.15s costs nothing and takes the edge off, whereas across a traversed collection the same fade strings a wake of dimming rows out behind a fast sweep — so Item keeps none.
Three things follow:
Checklist
pnpm testruns as expected.pnpm buildruns as expected.Type of change