Conversation
…dback Adds three transitions-dev recipes scoped to the react-grab shadow root (:host), prefixed with rg-t- to avoid host-page collisions: - Notification badge slide-in (recipe 03) on the unread comment count - Number pop-in with trailing-digit stagger (recipe 02) replays as the count changes - Icon-swap cross-fade (recipe 09) on the comments dropdown Copy/Confirmed swap Introduces two small Solid components: - IconSwap (stacked-grid two-icon cross-fade) - UnreadCountBadge (combines the badge and digit pop-in, replays the digit animation on value change via remove-class -> reflow -> re-add) All transitions honor prefers-reduced-motion: reduce. Existing animation systems (anchored dropdown, toolbar collapse) are untouched because they already implement equivalent or richer behavior. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
commit: |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 127a70c. Configure here.
Contributor
There was a problem hiding this comment.
1 issue found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/react-grab/src/components/unread-count-badge.tsx">
<violation number="1" location="packages/react-grab/src/components/unread-count-badge.tsx:19">
P2: For single-digit badge values (1–9), the only character hits `characterIndex === lastIndex` and receives `staggerIndex: 2`, adding a 140ms `animation-delay`. Because the `rg-t-digit-pop-in` animation starts at `opacity: 0` with `fill-mode: both`, the digit is invisible for that entire delay — the badge dot slides in but shows no number. The same empty-flash problem affects two-digit values where both characters get stagger delays. Add an early return for the first character so at least one digit always appears immediately.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Per feedback: revert the IconSwap cross-fade on the comments dropdown Copy/Confirmed button. Restores the prior <Show> swap and removes the IconSwap component, plus the rg-t-icon-swap CSS and tokens. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
The previous structure put rg-t-badge-dot, rg-t-digit-group, and Tailwind's flex centering on the same span. .rg-t-badge-dot's display: block in styles.css clobbered display: flex from Tailwind, and .rg-t-digit-group's display: inline-flex; align-items: baseline raced against the centering classes. Result was a chunky, mis-centered black pill overlapping the comment icon. Split into three nodes: outer .rg-t-badge (absolute wrapper, slide animation), middle .rg-t-badge-dot (the visible pill, owns flex centering and Tailwind layout classes), inner .rg-t-digit-group (inline-flex baseline row of per-digit spans, owns the .is-animating replay). Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
The completion view dismissed at FEEDBACK_DURATION_MS - FADE_DURATION_MS + FADE_DURATION_MS, while the outer label container animated opacity and filter on a hard-coded 150ms transition. The pink overlay-canvas selection box converged in ~80-90ms and the label was unmounted at 100ms after fade start, ripping away the last 50ms of the label's transition. Visible result: the pink box disappears noticeably before the label finishes fading. Bind the label container's opacity/filter transition to FADE_DURATION_MS so the HTML fade and the canvas fade complete on the same timeline. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
1 issue found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/react-grab/src/components/comments-dropdown.tsx">
<violation number="1">
P3: Keep the copy feedback in a fixed swap envelope; this `Show` replacement drops the intended cross-fade and causes a width/layout jump when the state changes.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
…ailwind utilities Recipe 02 (number pop-in) doesn't suit a 10x10 status pill: each digit re-enters from translate(0, 8px) with opacity 0, so on a pill that small the digit was completely outside the visible area for the first ~150ms of every replay. Result: subsequent updates flashed an empty black circle before the new number arrived. Switch to recipe-04 (text states swap) in spirit, using two persistent text slots stacked in the same grid cell: - The active slot is at translate-y-0 / opacity 100 / blur 0 - The inactive slot is at translate-y +/- 2 / opacity 0 / blur 2px - On value change, write the new value into whichever slot is currently inactive and flip data-state. The new digit slides in while the old one slides out; the pill is never empty. Drop all hand-written rg-t-* CSS classes and rewrite the badge in pure Tailwind v4 utilities. The only raw CSS remaining is the rg-badge-slide keyframe registered as --animate-rg-badge-slide in @theme so it becomes animate-rg-badge-slide. The data-driven open/close transitions and the slot text-swap are expressed entirely with group-data-[...]/badge variants. New @theme tokens: --ease-badge-pop, --ease-badge-close, --ease-text-swap. prefers-reduced-motion guard now keys on [data-react-grab-unread-indicator] so we don't have to enumerate inner classes. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
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.

Summary
Inspired by two of the nine recipes in Jakubantalik/transitions-dev — Notification badge (03) for slide-in, and Text states swap (04) in spirit for the digit transition — applied to the toolbar's unread comment count, plus a related fix that aligns the selection-label fade with the existing canvas pink-overlay fade so they finish together.
The implementation is all Tailwind v4 utilities in JSX. The only raw CSS is a single keyframe (
rg-badge-slide) registered as--animate-rg-badge-slidein@themeso it becomes theanimate-rg-badge-slideutility.What changed
Notification badge slide-in — appears via
data-[open=true]:animate-rg-badge-slidefrom a small offset.Pill open/close pop — driven by
group-data-[open=false]/badge:variants on the visible pill (scale 1 → 0, opacity 1 → 0, blur 0 → 2px). Open usesease-badge-popover 500ms; close usesease-badge-closeover 180ms.Digit text-swap (in place) — the obvious naive port of recipe-02 (per-digit pop-in from
translate(0, 8px)) doesn't suit a 10×10px status pill: the digit starts entirely below the visible pill, so subsequent updates flashed an empty black circle before the new number arrived. Replaced with the recipe-04 pattern using two persistent text slots stacked in the same grid cell:[grid-area:1/1]so they paint over each other, both centered.translate-y-0 opacity-100 blur-0.±translate-y-2 opacity-0 blur-[2px].data-stateflips. The new digit slides in while the old one slides out — the pill is never empty.All toggling is
group-data-[state=a]/badge:/group-data-[state=b]/badge:variants — no per-slot signals, no class rip-and-reapply replay.Bonus fix: label fade timing
The
<SelectionLabel>outer container animatedopacity, filteron a hard-codedduration-150Tailwind transition, butCompletionViewcallsonDismissatFADE_DURATION_MS(100ms) after the fade trigger and theOverlayCanvasopacity-lerps the label-tagged pink box to converge in roughly the same window. The 50ms tail of the 150ms transition was being ripped away when Solid unmounted the label, so the pink box visibly disappeared before the label finished. Bound the label container's transition toFADE_DURATION_MSso both fades run on the same timeline.Implementation notes
@themetokens:--ease-badge-pop,--ease-badge-close,--ease-text-swap,--animate-rg-badge-slide. The single keyframe@keyframes rg-badge-slidelives instyles.css.prefers-reduced-motion: reducekeys on[data-react-grab-unread-indicator](and descendants) so the entire badge tree freezes without enumerating internal classes.UnreadCountBadge(components/unread-count-badge.tsx).Iteration history (in this PR)
translate-y-8made the digit invisible for ~150ms of every replay..rg-t-*CSS classes with state-paired selectors — replaced with Tailwindgroup-data-*variants and@themetokens.Deliberately out of scope
createAnchoredDropdowninutils/already implements a richer variant with viewport flip, anchor-edge selection, and safe-polygon hover bridges. Replacing it would be a regression.grid-template-columns: 0fr ↔ 1frplus opacity, which is more capable than recipe 01's plain width/height tween.completion-view.tsx— the status-text site renders structurally different parents in each branch (with vs without check icon and dismiss button); a clean two-span stacked swap would need restructuring that view. Skipped.Validation
pnpm build✅pnpm typecheck✅pnpm lint✅Files
Summary by cubic
Adds
transitions-dev-style animations to the toolbar unread badge and syncs the selection-label fade with the canvas. Uses Tailwind utilities inside thereact-grabshadow root and honors reduced motion.New Features
Bug Fixes
FADE_DURATION_MSto finish with the canvas.Written for commit 9cab5bc. Summary will update on new commits. Review in cubic