Skip to content

refactor(flip-card): composable Front/Back API with motion-safe code#511

Merged
hari merged 13 commits into
mainfrom
refactor/flip-card-composable-api
Jun 15, 2026
Merged

refactor(flip-card): composable Front/Back API with motion-safe code#511
hari merged 13 commits into
mainfrom
refactor/flip-card-composable-api

Conversation

@sudhashrestha

@sudhashrestha sudhashrestha commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Replace fixed image/title props with FlipCard.Front and FlipCard.Back. Consumers own face markup. Flip uses transform-only transitions with reduced-motion guards.

Summary by CodeRabbit

  • New Features
    • FlipCard and FlippingCards now use composable Front/Back faces for X/Y flip customization.
    • SplitReveal now supports composable Images, Task, Overlay, Shutter, and Progress, including opt-in image preloading and externally-controlled ready/progress.
    • Added usePrefersReducedMotion for motion-aware behavior.
  • Improvements
    • Scroll locking now better preserves/restores page state during preloader activity.
    • Updated docs and examples to match the new composition-based APIs.

…forms

Replace fixed image/title props with FlipCard.Front and FlipCard.Back.
Consumers own face markup. Flip uses transform-only transitions with
reduced-motion guards.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sudhashrestha sudhashrestha requested a review from hari June 13, 2026 08:17
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Three composable API refactors land together: FlipCard is rebuilt from prop-driven to context-based with FlipCard.Front/FlipCard.Back subcomponents; FlippingCards is rebuilt as a grid wrapper around FlipCard; and SplitReveal is extracted from a monolithic file into co-located submodules (root, overlay, shutter, progress, task, images, context, types). Shared hooks usePrefersReducedMotion and useLockBody are extracted. Registry build tooling gains relative import resolution and export-statement parsing.

Changes

Card Composition Refactor

Layer / File(s) Summary
FlipCard composition-based architecture
animata/card/flip-card.tsx
Replaces prop-driven FlipCard with context-based FlipCardRoot providing the rotation axis, FlipCardFront/FlipCardBack face subcomponents consuming it, and Object.assign attaching Front/Back to produce the public FlipCard.
FlipCard consumer migration
animata/card/swap-card.tsx, animata/card/flip-card.stories.tsx
Updates SwapCard to compose two FlipCard instances using FlipCard.Front/FlipCard.Back JSX instead of props; rewrites Storybook Primary/Secondary stories to use custom render functions embedding the same JSX.
FlippingCards grid component
animata/list/flipping-cards.tsx
Replaces the list-prop-driven FlippingCard with FlippingCardsRoot (grid div), FlippingCardsItem (FlipCard wrapper with rotate="y"), and FlippingCards via Object.assign; adds getFlippingCardsAccent helper.
FlippingCards story and docs
animata/list/flipping-cards.stories.tsx, content/docs/list/flipping-cards.mdx, content/docs/list/index.mdx
Rewrites the story to map demoItems into FlippingCards.Item.Front/Back with accent colors; adds usage and changelog docs.
Card documentation and changelog
content/docs/card/flip-card.mdx, content/docs/card/index.mdx, content/docs/changelog/2026-06.mdx
Adds FlipCard and FlippingCards usage examples, Recent changes table entries, and 2026-06 changelog entries describing the composable API.

SplitReveal Modularization

Layer / File(s) Summary
SplitReveal types and context
animata/preloader/split-reveal/types.ts, animata/preloader/split-reveal/context.tsx
Defines all phase/progress/task types, context value interfaces, root props, and exports useSplitReveal/useSplitRevealInternal hooks with provider-boundary validation.
Shared utility hooks
hooks/use-prefers-reduced-motion.ts, hooks/use-lock-body.ts, animata/card/card-stack.tsx
Adds usePrefersReducedMotion via useSyncExternalStore; rewrites useLockBody with an active parameter and full style save/restore including scroll position; removes the inline duplicate from card-stack.tsx.
SplitRevealRoot state and lifecycle
animata/preloader/split-reveal/root.tsx
Implements 349-line SplitRevealRoot orchestrating the loading→fade-ui→reveal→done lifecycle with reducer state, task registry, AbortController-guarded bootstrap, phase timers, reduced-motion shortcut, and pageshow/resume cache-restore handlers.
Overlay and shutter UI components
animata/preloader/split-reveal/overlay.tsx, animata/preloader/split-reveal/shutter.tsx
Adds SplitRevealOverlay (fixed full-screen div with phase-driven pointer-events, CSS timing vars, and ARIA attributes) and SplitRevealShutter (top/bottom half-height div consuming backgroundColor from context).
Progress UI components
animata/preloader/split-reveal/progress-track.tsx, animata/preloader/split-reveal/progress-count.tsx, animata/preloader/split-reveal/progress-slot.tsx, animata/preloader/split-reveal/progress.tsx
Adds SplitRevealProgressTrack, SplitRevealProgressCount, SplitRevealProgressSlot, and SplitRevealProgress supporting a render-function or default UI from context state.
Task system for async preload work
animata/preloader/split-reveal/execute-task.ts, animata/preloader/split-reveal/task.tsx
Adds executeTask running task run promises or consuming async generators with abort-aware progress reporting; adds SplitRevealTask component registering task definitions via refs and registerTask from internal context.
Image preloading utility and component
animata/preloader/split-reveal/preload-images.ts, animata/preloader/split-reveal/images.tsx
Adds preloadImages preloading URLs in parallel with img.decode() fallback and single-settle guard; adds SplitRevealImages wrapping it as a task with deduplication and abort awareness.
Public compound API and barrel exports
animata/preloader/split-reveal/index.tsx, animata/preloader/split-reveal.tsx
Builds SplitReveal via Object.assign(SplitRevealRoot, { Overlay, Shutter, Progress, ... }); re-exports all hooks, utilities, components, and types; converts the top-level split-reveal.tsx to a two-line barrel.
Story and demo updates
animata/preloader/split-reveal.stories.tsx, app/demo/library/hero/photographer-portfolio.tsx, app/demo/library/hero/photographer-portfolio-notes.tsx
Updates Storybook story and photographer portfolio demo to compose SplitReveal.Images/Overlay/Shutter/Progress; removes renderProgress prop; updates demo notes to match new pattern.
SplitReveal documentation and changelog
content/docs/preloader/split-reveal.mdx, content/docs/preloader/index.mdx, content/docs/card/card-stack.mdx, content/docs/changelog/2026-06.mdx
Rewrites SplitReveal docs covering composable overlay, Task with run/generator forms, external ready/progress control, progress customization, and co-located import guidance; updates install instructions, changelog, and index pages.

Build and CI Infrastructure

Layer / File(s) Summary
Registry build and CI improvements
scripts/build-registry.js, .github/workflows/react-doctor.yml, scripts/validate-registry-install.js
Adds resolveRelativeImport with .tsx/.ts/index fallback; extends parseImports to capture export...from statements; switches react-doctor to millionco/react-doctor@v2 action with scope: changed and blocking: error; updates install fixtures for new hook files.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant SplitRevealRoot
  participant SplitRevealTask
  participant SplitRevealImages
  participant executeTask
  participant SplitRevealOverlay

  App->>SplitRevealRoot: render with lockScroll, onComplete
  SplitRevealRoot->>SplitRevealRoot: provide SplitRevealContext + SplitRevealInternalContext
  SplitRevealImages->>SplitRevealTask: register run callback via SplitRevealTask
  SplitRevealTask->>SplitRevealRoot: registerTask(id, definition)
  SplitRevealRoot->>executeTask: bootstrap — run all tasks in parallel
  executeTask->>SplitRevealRoot: report({ loaded, total }) per image
  SplitRevealRoot->>SplitRevealRoot: phase loading → fade-ui → reveal → done
  SplitRevealOverlay->>SplitRevealRoot: reads phase, zIndex, timing via useSplitReveal()
  SplitRevealRoot->>App: onComplete()
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • codse/animata#471: Introduces the original SplitReveal component that this PR fully modularizes into co-located submodules.
  • codse/animata#425: Modifies animata/card/swap-card.tsx and the FlipCard prop wiring that this PR refactors into the composable FlipCard.Front/Back API.

Poem

🐰 Hop hop, the cards now flip with flair,
Front and Back compose beyond compare!
The Reveal splits wide, modules in a row,
Context flows where only rabbits know.
Each task reports its progress with grace—
The warren's built, every piece in place! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: converting FlipCard from a props-based component to a composable API with Front/Back sub-components, and adding motion-safety support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/flip-card-composable-api

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 13, 2026

Copy link
Copy Markdown

Deploying animata with  Cloudflare Pages  Cloudflare Pages

Latest commit: 32f5c13
Status: ✅  Deploy successful!
Preview URL: https://ebaf3458.animata.pages.dev
Branch Preview URL: https://refactor-flip-card-composabl.animata.pages.dev

View logs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@animata/card/flip-card.tsx`:
- Around line 13-21: The hover rotation entries in ROTATION_CLASS (the hover
strings for keys x and y) cancel the flip under prefers-reduced-motion causing
FlipCardBack to remain pre-rotated and inaccessible; remove the motion-reduce
override tokens ("motion-reduce:group-hover/card:rotate-x-0" and
"motion-reduce:group-hover/card:rotate-y-0") from the hover values so the hover
still applies instantly for reduced-motion users (the existing
motion-reduce:transition-none handling at the transition site can remain as-is);
keep the back rotations ("rotate-x-180" / "rotate-y-180") unchanged.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: ae1301a5-1e28-4a41-8f14-241aa590eb0a

📥 Commits

Reviewing files that changed from the base of the PR and between ca96973 and 09d4bc8.

📒 Files selected for processing (6)
  • animata/card/flip-card.stories.tsx
  • animata/card/flip-card.tsx
  • animata/card/swap-card.tsx
  • content/docs/card/flip-card.mdx
  • content/docs/card/index.mdx
  • content/docs/changelog/2026-06.mdx

Comment thread animata/card/flip-card.tsx
Replace list prop and inline 3D flip with FlippingCards.Item.Front/Back.
Storybook demo and docs updated; accent helper exported for back faces.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 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 `@animata/list/flipping-cards.stories.tsx`:
- Around line 63-67: The story hardcodes light-only colors in
FlippingCards.Item.Front and its children; make these classes theme-responsive
by replacing static color classes with light/dark-aware classes. Update
FlippingCards.Item.Front’s className from "flex bg-white" to include a dark
variant (e.g. "flex bg-white dark:bg-slate-900" or your design token like "flex
bg-surface dark:bg-surface-dark"), change the inner div’s border/text classes
from "border border-black/15 ... text-sm" to use dual-mode classes (e.g. "border
border-black/15 dark:border-white/15 text-black dark:text-white px-3 py-4
text-sm"), and update the span classes that use "text-black" and "border-black"
to corresponding "text-black dark:text-white" and "border-black/15
dark:border-white/15" (or your token equivalents) so the face adapts in dark
mode. Ensure all color uses within FlippingCards.Item.Front, the inner
container, and both spans are converted to light/dark variants or theme tokens.

In `@animata/list/flipping-cards.tsx`:
- Around line 31-33: Replace the arbitrary HSL hue math in
getFlippingCardsAccent with the theme accent token so the component uses the
shared accent styling; specifically, change the function
getFlippingCardsAccent(index: number) to return the theme value like
"hsl(var(--accent))" (or "hsl(var(--accent) / <alpha>)" if you need opacity)
instead of computing `(index * 47) % 360`.

In `@content/docs/list/flipping-cards.mdx`:
- Line 21: The docs note incorrectly lists Marquee as a required install for the
flipping-cards example; update content/docs/list/flipping-cards.mdx to remove
the sentence that instructs installing Marquee and instead mention only the
required Flip Card, and confirm the example file animata/list/flipping-cards.tsx
(which does not import or use Marquee) needs no code changes—just update the
text to say "This uses [Flip Card](/docs/card/flip-card) for the hover flip" and
remove the Marquee install reference.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9acbc95c-a295-48ea-8d5a-2f34ea4e7f5f

📥 Commits

Reviewing files that changed from the base of the PR and between 09d4bc8 and a273f76.

📒 Files selected for processing (5)
  • animata/list/flipping-cards.stories.tsx
  • animata/list/flipping-cards.tsx
  • content/docs/changelog/2026-06.mdx
  • content/docs/list/flipping-cards.mdx
  • content/docs/list/index.mdx

Comment thread animata/list/flipping-cards.stories.tsx Outdated
Comment thread animata/list/flipping-cards.tsx Outdated
Comment thread content/docs/list/flipping-cards.mdx Outdated
Opt-in Images and Task primitives, external ready/progress control, and
tree-shakeable modules. Registry bundler follows co-located imports; photographer
demo uses the default Progress UI.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (1)
animata/preloader/split-reveal/index.tsx (1)

3-3: ⚡ Quick win

Use a co-located stylesheet for this TSX entrypoint.

index.tsx imports ../split-reveal.css; this breaks the co-location rule for animata/**/*.{tsx,css}. Please move/rename to a co-located file (for example ./index.css) and import it locally.

As per coding guidelines, animata/**/*.{tsx,css}: “Create co-located <name>.css files for keyframes, pseudo-elements, and selectors that Tailwind cannot express, and import them from the corresponding TSX file.”

🤖 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 `@animata/preloader/split-reveal/index.tsx` at line 3, The index.tsx file
imports a non-co-located stylesheet at ../split-reveal.css, which violates the
co-location rule for animata components. Move the split-reveal.css file to the
same directory as index.tsx and rename it to index.css, then update the import
statement in index.tsx to reference the co-located file with a relative path
like ./index.css instead of ../split-reveal.css.

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.

Inline comments:
In `@animata/preloader/split-reveal/execute-task.ts`:
- Around line 15-27: The abort handling in the generator execution loop has two
issues: first, iterator.next() is called at the start of each loop iteration
before checking signal.aborted, allowing one extra generator step to execute
even when aborted; second, when returning due to abort (when signal.aborted is
true), the code returns without calling iterator.return(), which skips generator
cleanup such as finally blocks. To fix this, move the abort check
(signal.aborted) to occur before calling iterator.next() in the while loop
condition or at the loop start, and when returning due to abort, call
iterator.return() first to ensure all cleanup code in the generator executes
properly.

In `@animata/preloader/split-reveal/overlay.tsx`:
- Around line 23-35: The overlay component spreads the consumer-provided props
after defining the required style, which allows a consumer-provided style prop
to override the critical overlay styles (zIndex, --split-reveal-duration,
--split-reveal-progress-fade). Move the style prop definition to come after the
{...props} spread so that the required internal styles take precedence and
cannot be overridden by consumer props, ensuring the overlay behavior is not
broken.

In `@animata/preloader/split-reveal/progress-count.tsx`:
- Around line 20-24: The inline styles in the progress-count component use
hex-suffix opacity notation (${foregroundColor}73 and ${foregroundColor}33)
which only works with hex color strings and breaks with hsl(), rgb(), or CSS
variable values. Replace these color assignments with a format that works
universally across all color types, such as using the rgba() function with a
calculated alpha value or applying opacity through a separate CSS property that
works regardless of the foregroundColor format.

In `@animata/preloader/split-reveal/root.tsx`:
- Around line 21-22: The backgroundColor and foregroundColor default parameters
in the SplitReveal component are hard-coded to light theme values (`#fff` and
`#000`), which breaks the component's appearance in dark mode. Replace these
hard-coded color defaults with theme-responsive tokens that automatically adapt
to the current theme context, ensuring the component works correctly for both
light and dark themes as required by the coding guidelines.
- Around line 121-124: The useEffect hook that manages task bootstrap is
including `controlledReady` and `controlledProgress` in its dependency list,
which causes it to re-run and abort in-flight executeTask calls whenever these
props change. Remove `controlledReady` and `controlledProgress` from the
dependency array of the useEffect that contains the task bootstrap logic. The
effect should initialize the task once at mount, and changing the `ready` flag
should only unblock the reveal without restarting the actual task work defined
in the SplitRevealTask.
- Around line 237-248: The Promise.all() chain for executing tasks only calls
the completion logic in the .then() handler, which means if any task rejects,
tasksDone never gets set to true, phase remains "loading", and the page stays
frozen in a deadlock state. Add error handling to the Promise chain by attaching
a .catch() or .finally() block that ensures the same completion logic (setting
tasksDone = true and calling maybeReveal(currentRun)) executes regardless of
whether the tasks succeed or fail. Make sure the abort signal check (currentRun
!== runId || abortController?.signal.aborted) is applied in both the success and
failure paths to prevent race conditions.

In `@animata/preloader/split-reveal/task.tsx`:
- Around line 25-36: The useEffect dependency array in the task registration is
incomplete. The effect creates a task definition using runRef.current and
generatorRef.current, but the dependency array only includes id and
registerTask. When the run or generator props change, their ref values update
but the effect does not re-run, causing the registered task to have stale
generator and run values. Add runRef and generatorRef (or their current values
if they are stable) to the dependency array so the task gets re-registered
whenever these values change.

In `@animata/preloader/split-reveal/use-prefers-reduced-motion.ts`:
- Around line 5-13: The subscribeReducedMotion function uses addEventListener
and removeEventListener on the MediaQueryList object, but these methods are not
supported in older browsers. Add a feature check to detect whether
addEventListener exists on the MediaQueryList object returned by
window.matchMedia. If it does not exist, fall back to using the deprecated
addListener method for adding the listener, and removeListener for removing it
in the cleanup function. This will ensure compatibility with older browser
versions while maintaining modern browser behavior.

In `@scripts/build-registry.js`:
- Around line 216-218: Relative paths with `../../` sequences can normalize
outside the project root and still be read and bundled into the registry JSON,
leaking unintended local files. After normalizing the path using
path.posix.normalize in the path resolution logic around line 216, add a
validation check to ensure the fully resolved absolute path (when joined with
ROOT) stays within the project root directory before returning it as a valid
base. The same constraint should be enforced at the bundling site around lines
256-259 to prevent any escaped paths from being included in the generated
registry output.
- Around line 267-268: The regex pattern in the `re` variable at lines 267-268
does not match TypeScript type re-exports (`export type { ... } from`). Update
the regex to include `type\s+` as an optional pattern in the export alternatives
so that both `export { ... } from` and `export type { ... } from` syntax are
matched and properly captured during bundling/classification.

---

Nitpick comments:
In `@animata/preloader/split-reveal/index.tsx`:
- Line 3: The index.tsx file imports a non-co-located stylesheet at
../split-reveal.css, which violates the co-location rule for animata components.
Move the split-reveal.css file to the same directory as index.tsx and rename it
to index.css, then update the import statement in index.tsx to reference the
co-located file with a relative path like ./index.css instead of
../split-reveal.css.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: fbfaae16-71a4-4d95-88ef-4390cc4fb72d

📥 Commits

Reviewing files that changed from the base of the PR and between a273f76 and e2c3ac8.

⛔ Files ignored due to path filters (1)
  • app/demo/generated/demo-sources.ts is excluded by !**/generated/**
📒 Files selected for processing (24)
  • animata/preloader/split-reveal.stories.tsx
  • animata/preloader/split-reveal.tsx
  • animata/preloader/split-reveal/context.tsx
  • animata/preloader/split-reveal/execute-task.ts
  • animata/preloader/split-reveal/images.tsx
  • animata/preloader/split-reveal/index.tsx
  • animata/preloader/split-reveal/overlay.tsx
  • animata/preloader/split-reveal/preload-images.ts
  • animata/preloader/split-reveal/progress-count.tsx
  • animata/preloader/split-reveal/progress-slot.tsx
  • animata/preloader/split-reveal/progress-track.tsx
  • animata/preloader/split-reveal/progress.tsx
  • animata/preloader/split-reveal/root.tsx
  • animata/preloader/split-reveal/shutter.tsx
  • animata/preloader/split-reveal/task.tsx
  • animata/preloader/split-reveal/types.ts
  • animata/preloader/split-reveal/use-prefers-reduced-motion.ts
  • animata/preloader/split-reveal/use-scroll-lock.ts
  • app/demo/library/hero/photographer-portfolio-notes.tsx
  • app/demo/library/hero/photographer-portfolio.tsx
  • content/docs/changelog/2026-06.mdx
  • content/docs/preloader/index.mdx
  • content/docs/preloader/split-reveal.mdx
  • scripts/build-registry.js
✅ Files skipped from review due to trivial changes (5)
  • animata/preloader/split-reveal/progress-slot.tsx
  • animata/preloader/split-reveal/progress-track.tsx
  • animata/preloader/split-reveal/types.ts
  • app/demo/library/hero/photographer-portfolio-notes.tsx
  • content/docs/changelog/2026-06.mdx

Comment thread animata/preloader/split-reveal/execute-task.ts
Comment thread animata/preloader/split-reveal/overlay.tsx
Comment thread animata/preloader/split-reveal/progress-count.tsx Outdated
Comment thread animata/preloader/split-reveal/root.tsx Outdated
Comment thread animata/preloader/split-reveal/root.tsx
Comment thread animata/preloader/split-reveal/root.tsx Outdated
Comment thread animata/preloader/split-reveal/task.tsx Outdated
Comment thread hooks/use-prefers-reduced-motion.ts
Comment thread scripts/build-registry.js Outdated
Comment thread scripts/build-registry.js Outdated
sudhashrestha and others added 7 commits June 15, 2026 10:03
Move scroll lock and reduced-motion hooks to hooks/, consolidate on
useLockBody, and skip re-bootstrap until the first run completes so
Images task registration does not abort preload.

Co-authored-by: Cursor <cursoragent@cursor.com>
Required for createContext and hooks when imported from server components.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace per-index HSL accents with hsl(var(--accent)) and theme tokens on
the story front face for light and dark mode.

Co-authored-by: Cursor <cursoragent@cursor.com>
Note shared hooks in split-reveal and card-stack install steps and drop the
incorrect Marquee requirement from flipping-cards manual install.

Co-authored-by: Cursor <cursoragent@cursor.com>
Expect use-lock-body and use-prefers-reduced-motion in split-reveal and
card-stack shadcn dry-run output.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use --scope changed --base main so react-doctor 0.5.x runs without crashing.

Co-authored-by: Cursor <cursoragent@cursor.com>
pnpm dlx @latest resolves to incompatible versions and conflicts with
minimumReleaseAge; millionco/react-doctor@v2 uses npm exec instead.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 @.github/workflows/react-doctor.yml:
- Line 39: The GitHub Action reference `millionco/react-doctor@v2` on line 39
uses a floating tag which is vulnerable to upstream tag retargeting. Replace the
floating tag with a full commit SHA to pin the action to an immutable release,
and add an inline comment preserving the original tag version for readability.
This ensures the workflow cannot be compromised by tag reassignment or deletion
by the upstream maintainers.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: efc4ec3c-aefb-40c6-9358-81ee1f91fd0f

📥 Commits

Reviewing files that changed from the base of the PR and between cc81e3e and 998bb76.

📒 Files selected for processing (1)
  • .github/workflows/react-doctor.yml

Comment thread .github/workflows/react-doctor.yml Outdated
sudhashrestha and others added 2 commits June 15, 2026 12:04
Restore reduced-motion flip access, harden split-reveal lifecycle and
task execution, use theme tokens and color-mix for progress text, and
pin react-doctor action plus registry import parsing safeguards.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use the documented minimal checkout + action setup with PR feedback
permissions, concurrency cancellation, and default v2 action inputs.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

React Doctor found 3 new issues in 1 file · 3 warnings · score 92 / 100 (Great) · 0 fixed · vs main

3 warnings

animata/preloader/split-reveal/root.tsx

  • ⚠️ L18 Large component is hard to read and change no-giant-component
  • ⚠️ L34 Ref initializer runs on every render rerender-lazy-ref-init
  • ⚠️ L41 State only used in handlers rerender-state-only-in-handlers

Reviewed by React Doctor for commit 32f5c13. See inline comments for fixes.

Remove push-to-main trigger so the scan runs as a PR gate only.

Co-authored-by: Cursor <cursoragent@cursor.com>
SplitRevealTaskDefinition,
} from "./types";

export function SplitRevealRoot({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/no-giant-component (warning)

Component "SplitRevealRoot" is 342 lines long, which is hard to read & change. Split it into a few smaller components.

Fix → Pull each section into its own component so the parent is easier to read, test, and change.

Docs

controlledProgressRef.current = controlledProgress;
controlledReadyRef.current = controlledReady;
const maybeRevealRef = useRef<(() => void) | null>(null);
const [bootstrapEpoch, setBootstrapEpoch] = useState(0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/rerender-state-only-in-handlers (warning)

Each update to "bootstrapEpoch" redraws your component for nothing because this useState is set but never shown on screen.

Fix → Use useRef instead of useState when the value is only set and never shown on screen. ref.current = ... updates it without redrawing the component.

Docs

const reduceMotion = usePrefersReducedMotion();
const onCompleteRef = useRef(onComplete);
const phaseRef = useRef<PreloaderPhase>("loading");
const tasksRef = useRef<Map<string, SplitRevealTaskDefinition>>(new Map());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/rerender-lazy-ref-init (warning)

useRef(new Map()) rebuilds this value on every render & throws it away.

Fix → Initialize the ref lazily so expensive values are not rebuilt and discarded on every render.

Docs

@hari hari merged commit de9aabb into main Jun 15, 2026
8 checks passed
@hari hari deleted the refactor/flip-card-composable-api branch June 15, 2026 07:06
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.

2 participants