Skip to content

feat: add Rotate plugin - #469

Merged
igordanchenko merged 9 commits into
mainfrom
feat/rotate-plugin
Oct 30, 2026
Merged

igordanchenko merged 9 commits into
mainfrom
feat/rotate-plugin

Conversation

@igordanchenko

@igordanchenko igordanchenko commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Description

Adds a Rotate plugin that lets users fix images with incorrect orientation. This feature has been requested a number of times over the years (see #100 and #348).

Supersedes #467. Thanks, @callumjohnspiller, for the initial implementation that got this moving!

Rotate plugin

  • Clockwise and counterclockwise toolbar buttons (rotate.buttons: "both" by default, "clockwise" or "counterclockwise")
  • rotate.ref for programmatic control (rotation, disabled, rotateClockwise, rotateCounterClockwise)
  • on.rotate callback, which apps can use to persist user rotations, together with the initial slide.rotation
  • Custom icons and controls via render.iconRotateClockwise, render.iconRotateCounterClockwise and render.buttonRotate, and the Rotate clockwise / Rotate counterclockwise labels
  • Rotation is tracked per image src, so it persists across navigation and slides changes while the lightbox is open (with the Inline plugin, until the lightbox unmounts)
  • Only image slides can be rotated; the buttons are disabled for other slide types

Core

  • useSlideRotation hook and SlideRotationContext, which return 0 unless the Rotate plugin is installed
  • rotation prop on ImageSlide, which fits quarter-turn rotations into the slide
  • normalizeRotation utility

Without the Rotate plugin, the lightbox behaves exactly as before.

Compatibility

  • Zoom: maximum zoom level and panning limits account for rotation, and rotating an image resets its zoom level
  • Thumbnails: thumbnails rotate along with their slides, regardless of plugin order
  • Both imageFit modes (contain and cover) in landscape and portrait viewports
  • Custom render.slide / render.thumbnail functions opt in via the useSlideRotation hook (documented, including a next/image example)
  • The plugin relies on the CSS rotate property (Chrome/Edge 104+, Safari 14.1+, Firefox 72+)

Docs

  • New Rotate plugin page (docs/plugins/rotate.md), including persisting rotation between sessions, custom slides, and a live demo and sandbox
  • New "With Rotate Plugin" section in the Next.js example (docs/examples/nextjs.md)
  • Rotate plugin added to the plugin lists in README.md and docs/plugins.md

Testing

  • Unit tests for the Rotate plugin, the useSlideRotation hook and normalizeRotation, including Zoom integration (maximum zoom for rotated images, zoom reset on rotation, responsive image sizing and source selection) and rotated image sizing in both imageFit modes
  • Rotate plugin added to the type tests
  • Layout, Zoom and Thumbnails integration verified manually in the browser (contain and cover image fit, landscape and portrait viewports)

Related issue

Closes #468

Add a Rotate plugin that lets users fix images with incorrect orientation via clockwise and
counterclockwise toolbar buttons (configurable via `rotate.buttons`). Each image keeps its
rotation while the lightbox is open, including when navigating away and back or when slides are
added or removed. Rotated images fit the slide area and work with the Zoom and Thumbnails plugins
regardless of plugin order.

The plugin also supports an initial `slide.rotation`, an `on.rotate` callback, a `rotate.ref`
for programmatic control, and custom icons and controls via `render`. Custom slide renderers
can read the rotation with the `useSlideRotation` hook and pass it to `ImageSlide`.

Co-authored-by: Callum John Spiller <callumjohnspiller@gmail.com>
@igordanchenko igordanchenko mentioned this pull request Oct 20, 2026
@pkg-pr-new

pkg-pr-new Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
npm i https://pkg.pr.new/yet-another-react-lightbox@469

commit: a40e084

@igordanchenko igordanchenko mentioned this pull request Oct 20, 2026

@callumjohnspiller callumjohnspiller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is really cool - definitely a vast improvement on my original PR!

With the Inline plugin, the lightbox never closes, so user rotations last until the lightbox
unmounts.
…-back

Calling `rotateClockwise()` or `rotateCounterClockwise()` more than once before the lightbox
re-rendered (e.g., twice in the same event handler to rotate by 180 degrees) applied only the
last call, and `on.rotate` reported the same stale angle for each call. Each call now builds on
the rotation set by the previous one.
The assertion hard-coded `0px` because jsdom reports a zero slide height. Compute the expected
`maxWidth` from the slide rect passed to `render.slide` instead, so the test keeps passing when
the test setup mocks a non-zero container height.
Add tests for rotated cover images sized to the transposed slide rect, max zoom computed from
transposed image dimensions, zoom reset on rotation, and `ResponsiveImage` sizing and source
selection for rotated and zoomed images.

Mock `clientHeight` for `.yarl__container` in the test setup, so that the slide rect has a non-zero
height in jsdom.
The `normalizeRotation` tests in `utils.spec.ts` already cover the edge cases. The hook test
now only checks that the provided rotation is normalized.
…oads

On the first rotation, images with `srcSet` briefly shrank and then expanded once the browser
loaded the larger source picked for the rotated layout, which showed as a flicker on fast
networks and a visible jump on slow ones. Rotated images now fit the slide right away.
@igordanchenko

Copy link
Copy Markdown
Owner Author

@callumjohnspiller, I'm finalizing the implementation and would appreciate it if you could take another look. You can install the latest preview build with npm i https://pkg.pr.new/yet-another-react-lightbox@469. Please let me know if you have any feedback!

@igordanchenko
igordanchenko merged commit 1b70b01 into main Oct 30, 2026
12 checks passed
@igordanchenko
igordanchenko deleted the feat/rotate-plugin branch October 30, 2026 18:53
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 3.33.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@github-actions github-actions Bot added the released Implemented and released label Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released Implemented and released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rotate Plugin

2 participants