Skip to content

Comments

fix(components): Fix Lightbox transitions [JOB-152407]#2918

Merged
Aiden-Brine merged 4 commits intomasterfrom
JOB-152407/fix-lightbox
Feb 23, 2026
Merged

fix(components): Fix Lightbox transitions [JOB-152407]#2918
Aiden-Brine merged 4 commits intomasterfrom
JOB-152407/fix-lightbox

Conversation

@Aiden-Brine
Copy link
Contributor

@Aiden-Brine Aiden-Brine commented Feb 19, 2026

Motivations

There is some unexpected behaviour with Lightbox transitions when switching direction:

  • If you click next the current image leaves to the left and the new image comes in from the right
  • If you click previous the current image leave from the right and the new image comes in from the left

However, things get funky when you change directions:

  • If you click next after clicking previous the current image leaves to the right and the new image also comes from the right
  • If you click previous after clicking next the current image leaves to the left and the new image also comes from the left

Changes

This component uses Framer Motion’s AnimatePresence. When the index changes by clicking next, React doesn’t just swap one image for another. It:

  1. Keeps the old image in the tree so it can run its exit animation.
  2. Adds the new image so it can run its enter animation.

So for a short time there are two motion.img elements:

  • One with the old index (exiting).
  • One with the new index (entering).

Both need to know the direction (next or previous) to pick the right animation. That direction was passed in via the custom prop (custom={direction}) where direction was a React state value. When you click “Previous”, the handler runs and updates state:

  • setDirection(-1) and setCurrentImageIndex(newIndex). React then re-renders the component with direction = -1 and the new index.
  • In that render:
    • The new image (entering) is created in this render, so it gets custom={-1}
    • The old image (exiting) is not created in this render. It’s the same element that was already on screen. React and AnimatePresence keep it in the tree to play the exit animation, but they don’t re-render it with new props. So it still has the old custom value from the last time it was rendered (e.g. 1 for “next”).

The entering image gets the new direction from the latest render. The exiting image never gets the new props, so it keeps the old direction. This leads to both slides moving the same way for one transition. The fix for this is that instead of using a state value that the exiting element never sees updated, I switched it to a ref that will always hold the current direction.

Fixed

  • Transitions when switching direction with Lightbox.

Testing

Play around with things in Storybook. Clicking next should always have the current image leave to the left and the new image enter from the right. And then clicking previous should always be the opposite (current image leaves to the right and the new image enters from the left).

Changes can be
tested via Pre-release


In Atlantis we use Github's built in pull request reviews.


await POM.goNextThenPreviousWithRealTimers(250);

await new Promise(resolve => setTimeout(resolve, 50));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I really tried to get this to work with fake timers but due to some of the internals of Framer I couldn't get it to work. That means this test will take ~550ms to run which is not ideal but is also not terrible. Open to suggestions but at this time I'm quite confident we can't have this test coverage with fake timers

@edison-cy-yang
Copy link
Contributor

Great fix — the root cause analysis is spot on and using a ref instead of state is the right approach for this AnimatePresence issue.

One suggestion on the new test: the "applies correct slide direction when changing from next to previous" test is effectively an integration test of Framer Motion's animation pipeline — it clicks buttons, waits with real timers, then inspects translateX transforms on DOM elements. This has a couple of downsides:

  1. Flakiness risk — it relies on real setTimeout delays (250ms + 50ms buffer) that could be sensitive to CI load.
  2. Tests the library, not the component — it's asserting that Framer Motion correctly calls variant functions and applies interpolated styles. If Framer Motion ever changes its transform format (e.g., translate3d instead of translateX), this test breaks even though the component is still correct.

The actual logic that was broken (and fixed) is in the variants object — it now reads from a ref so both entering and exiting elements get the latest direction. That can be tested as a pure function without any animation timing:

// exported from LightBox.tsx (or tested via a test-only export)
it("enter slides from the right when direction is forward", () => {
  expect(variants.enter({ current: 1 })).toEqual({ x: "150%" });
});

it("exit slides to the right when direction is backward", () => {
  expect(variants.exit({ current: -1 })).toEqual({ x: "150%" });
});

This approach:

  • Directly validates the logic that was broken (variant reads ref correctly)
  • Is instant and deterministic (no timers, no DOM inspection)
  • Doesn't depend on Framer Motion internals

The existing navigation tests already cover that clicking next/previous changes the displayed image. Combined with variant unit tests, the full fix is covered: handlers set the ref → variants read the ref correctly → Framer Motion applies the result (library's responsibility).

The POM additions and other test cleanups look good 👍

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 23, 2026

Deploying atlantis with  Cloudflare Pages  Cloudflare Pages

Latest commit: e0e9076
Status: ✅  Deploy successful!
Preview URL: https://0953ab82.atlantis.pages.dev
Branch Preview URL: https://job-152407-fix-lightbox.atlantis.pages.dev

View logs

@Aiden-Brine Aiden-Brine force-pushed the JOB-152407/fix-lightbox branch from 32919bc to e0e9076 Compare February 23, 2026 20:05
Copy link
Contributor

@edison-cy-yang edison-cy-yang left a comment

Choose a reason for hiding this comment

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

Tested this in Storybook, LGTM!

@Aiden-Brine Aiden-Brine merged commit c2beb0c into master Feb 23, 2026
17 checks passed
@Aiden-Brine Aiden-Brine deleted the JOB-152407/fix-lightbox branch February 23, 2026 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants