2022-05-19 16:16:46 +00:00
|
|
|
/* eslint-disable @wordpress/no-unsafe-wp-apis */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
2022-05-30 14:38:52 +00:00
|
|
|
import { WP_REST_API_Category } from 'wp-types';
|
|
|
|
import { ProductResponseItem } from '@woocommerce/types';
|
2022-05-19 16:16:46 +00:00
|
|
|
import {
|
|
|
|
__experimentalImageEditingProvider as ImageEditingProvider,
|
|
|
|
__experimentalImageEditor as GutenbergImageEditor,
|
|
|
|
} from '@wordpress/block-editor';
|
2023-03-02 14:26:00 +00:00
|
|
|
import type { ComponentType, Dispatch, SetStateAction } from 'react';
|
2022-05-19 16:16:46 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import { BLOCK_NAMES, DEFAULT_EDITOR_SIZE } from './constants';
|
2022-05-30 14:38:52 +00:00
|
|
|
import { EditorBlock } from './types';
|
2022-05-19 16:16:46 +00:00
|
|
|
import { useBackgroundImage } from './use-background-image';
|
|
|
|
|
2022-05-30 14:38:52 +00:00
|
|
|
type MediaAttributes = { mediaId: number; mediaSrc: string };
|
|
|
|
type MediaSize = { height: number; width: number };
|
|
|
|
|
|
|
|
interface WithImageEditorRequiredProps< T > {
|
|
|
|
attributes: MediaAttributes & EditorBlock< T >[ 'attributes' ];
|
|
|
|
backgroundImageSize: MediaSize;
|
|
|
|
setAttributes: ( attrs: Partial< MediaAttributes > ) => void;
|
|
|
|
useEditingImage: [ boolean, Dispatch< SetStateAction< boolean > > ];
|
|
|
|
}
|
|
|
|
|
|
|
|
interface WithImageEditorCategoryProps< T >
|
|
|
|
extends WithImageEditorRequiredProps< T > {
|
|
|
|
category: WP_REST_API_Category;
|
|
|
|
product: never;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface WithImageEditorProductProps< T >
|
|
|
|
extends WithImageEditorRequiredProps< T > {
|
|
|
|
category: never;
|
|
|
|
product: ProductResponseItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
type WithImageEditorProps< T extends EditorBlock< T > > =
|
|
|
|
| ( T & WithImageEditorCategoryProps< T > )
|
|
|
|
| ( T & WithImageEditorProductProps< T > );
|
|
|
|
|
|
|
|
interface ImageEditorProps {
|
|
|
|
backgroundImageId: number;
|
|
|
|
backgroundImageSize: MediaSize;
|
|
|
|
backgroundImageSrc: string;
|
|
|
|
isEditingImage: boolean;
|
|
|
|
setAttributes: ( attrs: MediaAttributes ) => void;
|
|
|
|
setIsEditingImage: ( value: boolean ) => void;
|
|
|
|
}
|
|
|
|
|
2022-05-19 16:16:46 +00:00
|
|
|
export const ImageEditor = ( {
|
|
|
|
backgroundImageId,
|
|
|
|
backgroundImageSize,
|
|
|
|
backgroundImageSrc,
|
|
|
|
isEditingImage,
|
|
|
|
setAttributes,
|
|
|
|
setIsEditingImage,
|
2022-05-30 14:38:52 +00:00
|
|
|
}: ImageEditorProps ) => {
|
2022-05-19 16:16:46 +00:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<ImageEditingProvider
|
|
|
|
id={ backgroundImageId }
|
|
|
|
url={ backgroundImageSrc }
|
|
|
|
naturalHeight={
|
|
|
|
backgroundImageSize.height || DEFAULT_EDITOR_SIZE.height
|
|
|
|
}
|
|
|
|
naturalWidth={
|
|
|
|
backgroundImageSize.width || DEFAULT_EDITOR_SIZE.width
|
|
|
|
}
|
2022-05-30 14:38:52 +00:00
|
|
|
onSaveImage={ ( { id, url }: { id: number; url: string } ) => {
|
2022-05-19 16:16:46 +00:00
|
|
|
setAttributes( { mediaId: id, mediaSrc: url } );
|
|
|
|
} }
|
|
|
|
isEditing={ isEditingImage }
|
|
|
|
onFinishEditing={ () => setIsEditingImage( false ) }
|
|
|
|
>
|
|
|
|
<GutenbergImageEditor
|
|
|
|
url={ backgroundImageSrc }
|
|
|
|
height={
|
|
|
|
backgroundImageSize.height || DEFAULT_EDITOR_SIZE.height
|
|
|
|
}
|
|
|
|
width={
|
|
|
|
backgroundImageSize.width || DEFAULT_EDITOR_SIZE.width
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</ImageEditingProvider>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2022-06-15 09:56:52 +00:00
|
|
|
export const withImageEditor =
|
|
|
|
< T extends EditorBlock< T > >( Component: ComponentType< T > ) =>
|
|
|
|
( props: WithImageEditorProps< T > ) => {
|
|
|
|
const [ isEditingImage, setIsEditingImage ] = props.useEditingImage;
|
2022-05-19 16:16:46 +00:00
|
|
|
|
2022-06-15 09:56:52 +00:00
|
|
|
const { attributes, backgroundImageSize, name, setAttributes } = props;
|
|
|
|
const { mediaId, mediaSrc } = attributes;
|
|
|
|
const item =
|
|
|
|
name === BLOCK_NAMES.featuredProduct
|
|
|
|
? props.product
|
|
|
|
: props.category;
|
2022-05-19 16:16:46 +00:00
|
|
|
|
2022-06-15 09:56:52 +00:00
|
|
|
const { backgroundImageId, backgroundImageSrc } = useBackgroundImage( {
|
|
|
|
item,
|
|
|
|
mediaId,
|
|
|
|
mediaSrc,
|
|
|
|
blockName: name,
|
|
|
|
} );
|
2022-05-19 16:16:46 +00:00
|
|
|
|
2022-06-15 09:56:52 +00:00
|
|
|
if ( isEditingImage ) {
|
|
|
|
return (
|
|
|
|
<ImageEditor
|
|
|
|
backgroundImageId={ backgroundImageId }
|
|
|
|
backgroundImageSize={ backgroundImageSize }
|
|
|
|
backgroundImageSrc={ backgroundImageSrc }
|
|
|
|
isEditingImage={ isEditingImage }
|
|
|
|
setAttributes={ setAttributes }
|
|
|
|
setIsEditingImage={ setIsEditingImage }
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
2022-05-19 16:16:46 +00:00
|
|
|
|
2022-06-15 09:56:52 +00:00
|
|
|
return <Component { ...props } />;
|
|
|
|
};
|