Skip to content

feat(Gallery): add built-in image rotation support#378

Open
what3verCODE wants to merge 4 commits into
gravity-ui:mainfrom
what3verCODE:feat/gallery-image-rotation
Open

feat(Gallery): add built-in image rotation support#378
what3verCODE wants to merge 4 commits into
gravity-ui:mainfrom
what3verCODE:feat/gallery-image-rotation

Conversation

@what3verCODE
Copy link
Copy Markdown

Summary

Implements image rotation for Gallery via context and action utilities.

  • Add GalleryImageRotationContext to share rotation state between header actions and image view
  • Add useImageRotation hook — owns rotation styles, container dimension tracking, and maxWidth/maxHeight
    swap at 90°/270° to prevent cropping
  • Use unbounded rotation values so CSS transitions always animate the correct ±90° direction
  • Merge zoom and rotation transforms in ImageView; reset zoom on rotation change
  • Add getGalleryItemRotateLeftAction / getGalleryItemRotateRightAction — context-aware via __renderT
  • Add rotate-left / rotate-right i18n keys (en + ru)
  • Export new hook, context, and action utilities from package index

Closes #377

Test plan

  • Rotate left/right — image rotates 90° in the correct direction with smooth transition
  • Rotate left from 0° animates counterclockwise (not 270° clockwise)
  • At 90°/270°, image fits container without cropping
  • Rotation resets when switching gallery items
  • Zoom resets when rotation changes
  • Zoom and rotation compose correctly together
  • Check RotationGallery story in Storybook

Add rotate-left/rotate-right actions for Gallery images with 90° increments via CSS transform.

- Add GalleryImageRotationContext to share rotation state between header actions and image view
- Add useImageRotation hook with useMemo-based styles, container dimension tracking,
  and max-width/max-height swap for 90/270 rotations to prevent cropping
- Use unbounded rotation values (no modulo) so CSS transitions animate the correct direction
- Merge zoom and rotation transforms in ImageView; reset zoom when rotation changes
- Add getGalleryItemRotateLeftAction and getGalleryItemRotateRightAction utilities
  using __renderT for context-aware rendering
- Add rotate-left/rotate-right i18n keys (en + ru)
- Export new hook, context, and action utilities from package index
@what3verCODE what3verCODE requested a review from kseniya57 as a code owner April 20, 2026 14:24
Copy link
Copy Markdown
Member

@d3m1d0v d3m1d0v May 15, 2026

Choose a reason for hiding this comment

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

GalleryContext already exists. Why not add GalleryImageRotationContext.tsx functionality to GalleryContext? There are reasons to create a separate context for image rotation?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yeah, moved GalleryContext before modal comp. Now should be fine

Comment on lines +31 to +35
...(rotation ? {transform: `rotate(${rotation}deg)`} : {}),
...(isHorizontalRotation && containerDims.width > 0
? {maxWidth: containerDims.height, maxHeight: containerDims.width}
: {}),
}),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should rotation occur if the image dimensions haven't been set yet? I don't think so. The useImageZoom* hooks also check for the dimensions before zooming the image.

Comment thread src/components/Gallery/Gallery.tsx Outdated
Comment on lines +75 to +77
const [rotation, setRotation] = React.useState(0);
const rotateLeft = React.useCallback(() => setRotation((r) => r - ROTATION_STEP), []);
const rotateRight = React.useCallback(() => setRotation((r) => r + ROTATION_STEP), []);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be moved to a separate hook – useRotationState(), to which you can pass the initial value and custom rotation step as arguments.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, but i think for now it enough to keep this hook in Gallery/Image scope without args

…yles

Merge image rotation state into GalleryContext so a single provider
serves both gallery actions and views. Extract rotation state ownership
into a dedicated useImageRotationState hook. Gate the rotation style
output on measured container dimensions to avoid emitting a rotate
transform before max-width/max-height swaps can apply.
Add unit tests for the new state hook and the consumer hook, including
the dimension guard, the 90°/270° max-width/max-height swap, negative
and >360° angle normalization, and rotation action passthrough.
@what3verCODE what3verCODE requested a review from d3m1d0v May 15, 2026 12:20
Copy link
Copy Markdown
Member

@d3m1d0v d3m1d0v left a comment

Choose a reason for hiding this comment

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

Plz update README for Gallery component and add new one for added hooks

* @returns Rotation state, actions, computed styles, and a setter for container dimensions.
*/
export function useImageRotation(): UseImageRotationReturn {
const {rotation, rotateLeft, rotateRight} = useGalleryContext();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

<ImageView> already uses useGalleryContext and passes the onTap handler to useImageZoom. I suggest doing something similar in useImageRotation.

rotateLeft and rotateRight seem redundant here.

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.

feat(Gallery): Support image rotation action internally

2 participants