33/**
44 * External dependencies
55 */
6+ import { useCallback , useEffect , useRef , useState } from '@wordpress/element' ;
67import { WP_REST_API_Category } from 'wp-types' ;
78import { ProductResponseItem } from '@woocommerce/types' ;
89import {
@@ -18,7 +19,7 @@ import { BLOCK_NAMES, DEFAULT_EDITOR_SIZE } from './constants';
1819import { EditorBlock } from './types' ;
1920import { useBackgroundImage } from './use-background-image' ;
2021
21- type MediaAttributes = { mediaId : number ; mediaSrc : string } ;
22+ type MediaAttributes = { align : string ; mediaId : number ; mediaSrc : string } ;
2223type MediaSize = { height : number ; width : number } ;
2324
2425interface WithImageEditorRequiredProps < T > {
@@ -45,24 +46,70 @@ type WithImageEditorProps< T extends EditorBlock< T > > =
4546 | ( T & WithImageEditorProductProps < T > ) ;
4647
4748interface ImageEditorProps {
49+ align : string ;
4850 backgroundImageId : number ;
4951 backgroundImageSize : MediaSize ;
5052 backgroundImageSrc : string ;
53+ containerRef : React . RefObject < HTMLDivElement > ;
5154 isEditingImage : boolean ;
5255 setAttributes : ( attrs : MediaAttributes ) => void ;
5356 setIsEditingImage : ( value : boolean ) => void ;
5457}
5558
59+ // Adapted from:
60+ // https://github.com/WordPress/gutenberg/blob/v15.6.1/packages/block-library/src/image/use-client-width.js
61+ function useClientWidth (
62+ ref : React . RefObject < HTMLDivElement > ,
63+ dependencies : string [ ]
64+ ) {
65+ const [ clientWidth , setClientWidth ] : [
66+ number | undefined ,
67+ Dispatch < SetStateAction < number | undefined > >
68+ ] = useState ( ) ;
69+
70+ const calculateClientWidth = useCallback ( ( ) => {
71+ setClientWidth ( ref . current ?. clientWidth ) ;
72+ } , [ ref ] ) ;
73+
74+ useEffect ( calculateClientWidth , [
75+ calculateClientWidth ,
76+ ...dependencies ,
77+ ] ) ;
78+ useEffect ( ( ) => {
79+ if ( ! ref . current ) {
80+ return ;
81+ }
82+ const { defaultView } = ref . current . ownerDocument ;
83+
84+ if ( ! defaultView ) {
85+ return ;
86+ }
87+ defaultView . addEventListener ( 'resize' , calculateClientWidth ) ;
88+
89+ return ( ) => {
90+ defaultView . removeEventListener ( 'resize' , calculateClientWidth ) ;
91+ } ;
92+ } , [ ref , calculateClientWidth ] ) ;
93+
94+ return clientWidth ;
95+ }
96+
5697export const ImageEditor = ( {
98+ align,
5799 backgroundImageId,
58100 backgroundImageSize,
59101 backgroundImageSrc,
102+ containerRef,
60103 isEditingImage,
61104 setAttributes,
62105 setIsEditingImage,
63106} : ImageEditorProps ) => {
64- return (
65- < >
107+ const clientWidth = useClientWidth ( containerRef , [ align ] ) ;
108+
109+ // Fallback for WP 6.1 or lower. In WP 6.2. ImageEditingProvider was merged
110+ // with ImageEditor, see: https://github.com/WordPress/gutenberg/pull/47171
111+ if ( typeof ImageEditingProvider === 'function' ) {
112+ return (
66113 < ImageEditingProvider
67114 id = { backgroundImageId }
68115 url = { backgroundImageSrc }
@@ -88,7 +135,23 @@ export const ImageEditor = ( {
88135 }
89136 />
90137 </ ImageEditingProvider >
91- </ >
138+ ) ;
139+ }
140+
141+ return (
142+ < GutenbergImageEditor
143+ id = { backgroundImageId }
144+ url = { backgroundImageSrc }
145+ height = { backgroundImageSize . height || DEFAULT_EDITOR_SIZE . height }
146+ width = { backgroundImageSize . width || DEFAULT_EDITOR_SIZE . width }
147+ naturalHeight = { backgroundImageSize . height }
148+ naturalWidth = { backgroundImageSize . width }
149+ onSaveImage = { ( { id, url } : { id : number ; url : string } ) => {
150+ setAttributes ( { mediaId : id , mediaSrc : url } ) ;
151+ } }
152+ onFinishEditing = { ( ) => setIsEditingImage ( false ) }
153+ clientWidth = { clientWidth }
154+ />
92155 ) ;
93156} ;
94157
@@ -97,6 +160,8 @@ export const withImageEditor =
97160 ( props : WithImageEditorProps < T > ) => {
98161 const [ isEditingImage , setIsEditingImage ] = props . useEditingImage ;
99162
163+ const ref = useRef < HTMLDivElement > ( null ) ;
164+
100165 const { attributes, backgroundImageSize, name, setAttributes } = props ;
101166 const { mediaId, mediaSrc } = attributes ;
102167 const item =
@@ -113,14 +178,18 @@ export const withImageEditor =
113178
114179 if ( isEditingImage ) {
115180 return (
116- < ImageEditor
117- backgroundImageId = { backgroundImageId }
118- backgroundImageSize = { backgroundImageSize }
119- backgroundImageSrc = { backgroundImageSrc }
120- isEditingImage = { isEditingImage }
121- setAttributes = { setAttributes }
122- setIsEditingImage = { setIsEditingImage }
123- />
181+ < div ref = { ref } >
182+ < ImageEditor
183+ align = { attributes . align }
184+ backgroundImageId = { backgroundImageId }
185+ backgroundImageSize = { backgroundImageSize }
186+ backgroundImageSrc = { backgroundImageSrc }
187+ containerRef = { ref }
188+ isEditingImage = { isEditingImage }
189+ setAttributes = { setAttributes }
190+ setIsEditingImage = { setIsEditingImage }
191+ />
192+ </ div >
124193 ) ;
125194 }
126195
0 commit comments