From 38d4ee5d5da509f07392d79a6dd71a33293aa325 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Thu, 1 Aug 2024 00:09:26 +0800 Subject: [PATCH] Fix resizing container --- .../src/image-cropper/component.tsx | 59 ++++++++++--------- packages/components/src/image-cropper/hook.ts | 17 +----- .../components/src/image-cropper/reducer.ts | 21 +++---- 3 files changed, 44 insertions(+), 53 deletions(-) diff --git a/packages/components/src/image-cropper/component.tsx b/packages/components/src/image-cropper/component.tsx index 4f663f210a739..ab1087f08d7a0 100644 --- a/packages/components/src/image-cropper/component.tsx +++ b/packages/components/src/image-cropper/component.tsx @@ -6,7 +6,13 @@ import { animate } from 'framer-motion'; /** * WordPress dependencies */ -import { forwardRef, useContext, useRef, useEffect } from '@wordpress/element'; +import { + forwardRef, + useContext, + useRef, + useEffect, + useMemo, +} from '@wordpress/element'; import { useMergeRefs } from '@wordpress/compose'; /** * Internal dependencies @@ -153,11 +159,14 @@ const Cropper = forwardRef< HTMLDivElement >( ( {}, ref ) => { originalWidth, originalHeight, refs: { imageRef }, - getState, dispatch, } = useContext( ImageCropperContext ); const isAxisSwapped = rotations % 2 !== 0; const degree = angle + rotations * 90; + const aspectRatio = useMemo( + () => originalWidth / originalHeight, + [ originalWidth, originalHeight ] + ); const squareImageHorizontalOffset = ( image.width - image.height ) / 2; const paddingY = Math.max( @@ -178,29 +187,20 @@ const Cropper = forwardRef< HTMLDivElement >( ( {}, ref ) => { const containerRef = useRef< HTMLDivElement >( null! ); useEffect( () => { const container = containerRef.current; - const aspectRatio = originalWidth / originalHeight; const resizeObserver = new ResizeObserver( ( [ entry ] ) => { - const [ { inlineSize: width } ] = entry.contentBoxSize; - const _isAxisSwapped = getState().transforms.rotations % 2 !== 0; - const { width: imageWidth, height: imageHeight } = getState().image; - const imageDimensions = _isAxisSwapped - ? { - width: imageHeight, - height: imageWidth, - } - : { - width: imageWidth, - height: imageHeight, - }; + const [ { inlineSize } ] = entry.contentBoxSize; + const originalInlineSize = isAxisSwapped + ? originalHeight + : originalWidth; - if ( width < imageDimensions.width ) { - dispatch( { - type: 'RESIZE_CONTAINER', - width: _isAxisSwapped ? width * aspectRatio : width, - height: _isAxisSwapped ? width : width / aspectRatio, - } ); - } + dispatch( { + type: 'RESIZE_CONTAINER', + width: + inlineSize < originalInlineSize + ? inlineSize + : originalInlineSize, + } ); } ); resizeObserver.observe( container ); @@ -208,7 +208,13 @@ const Cropper = forwardRef< HTMLDivElement >( ( {}, ref ) => { return () => { resizeObserver.disconnect(); }; - }, [ getState, dispatch, originalWidth, originalHeight ] ); + }, [ + dispatch, + originalWidth, + originalHeight, + aspectRatio, + isAxisSwapped, + ] ); return ( ( ( {}, ref ) => { style={ { width: `${ paddingInline * 2 + - ( isAxisSwapped ? image.height : image.width ) - }px`, - height: `${ - paddingBlock * 2 + - ( isAxisSwapped ? image.width : image.height ) + ( isAxisSwapped ? originalHeight : originalWidth ) }px`, + aspectRatio: '1 / 1', '--wp-cropper-image-x': `${ image.x }px`, '--wp-cropper-image-y': `${ image.y }px`, '--wp-cropper-scale-x': scale.x, diff --git a/packages/components/src/image-cropper/hook.ts b/packages/components/src/image-cropper/hook.ts index cf1977cdd64c0..7a4e0b6aeaba6 100644 --- a/packages/components/src/image-cropper/hook.ts +++ b/packages/components/src/image-cropper/hook.ts @@ -10,13 +10,7 @@ import { /** * WordPress dependencies */ -import { - useRef, - useMemo, - useReducer, - useCallback, - useEffect, -} from '@wordpress/element'; +import { useRef, useMemo, useReducer, useCallback } from '@wordpress/element'; /** * Internal dependencies @@ -146,12 +140,6 @@ export const useImageCropper = ( { return blob; }, [] ); - const stateRef = useRef< State >( state ); - useEffect( () => { - stateRef.current = state; - }, [ state ] ); - const getState = useCallback( () => stateRef.current, [] ); - return useMemo( () => ( { state, @@ -162,10 +150,9 @@ export const useImageCropper = ( { imageRef, cropperWindowRef, }, - getState, dispatch, getImageBlob, } ), - [ state, src, width, height, getImageBlob, getState ] + [ state, src, width, height, getImageBlob ] ); }; diff --git a/packages/components/src/image-cropper/reducer.ts b/packages/components/src/image-cropper/reducer.ts index e7b480b95c881..40448fc1ec087 100644 --- a/packages/components/src/image-cropper/reducer.ts +++ b/packages/components/src/image-cropper/reducer.ts @@ -74,10 +74,10 @@ type Action = direction: ResizeDirection; delta: { width: number; height: number }; } + // Resize the container and image to a new width. + | { type: 'RESIZE_CONTAINER'; width: number } // Reset the state to the initial state. - | { type: 'RESET' } - // Resize the container and image to a new width and height. - | { type: 'RESIZE_CONTAINER'; width: number; height: number }; + | { type: 'RESET' }; function createInitialState( { width, @@ -382,19 +382,20 @@ function imageCropperReducer( state: State, action: Action ) { }; } case 'RESIZE_CONTAINER': { - if ( - action.width === image.width && - action.height === image.height - ) { + const isAxisSwapped = rotations % 2 !== 0; + const imageInlineSize = isAxisSwapped ? image.height : image.width; + const ratio = action.width / imageInlineSize; + + if ( ratio === 1 ) { return state; } - const ratio = action.width / image.width; + return { ...state, image: { ...state.image, - width: action.width, - height: action.height, + width: image.width * ratio, + height: image.height * ratio, x: image.x * ratio, y: image.y * ratio, },