/** * External dependencies */ import { ComponentType, Dispatch, SetStateAction } from 'react'; import { __ } from '@wordpress/i18n'; import { AlignmentToolbar, BlockControls as BlockControlsWrapper, MediaReplaceFlow, } from '@wordpress/block-editor'; import type { BlockAlignment } from '@wordpress/blocks'; import { ToolbarButton, ToolbarGroup } from '@wordpress/components'; import { crop } from '@wordpress/icons'; import { WP_REST_API_Category } from 'wp-types'; import { ProductResponseItem } from '@woocommerce/types'; import TextToolbarButton from '@woocommerce/editor-components/text-toolbar-button'; /** * Internal dependencies */ import { useBackgroundImage } from './use-background-image'; import { EditorBlock, GenericBlockUIConfig } from './types'; type Media = { id: number; url: string }; interface WithBlockControlsRequiredProps< T > { attributes: BlockControlRequiredAttributes & EditorBlock< T >[ 'attributes' ]; setAttributes: ( attrs: Partial< BlockControlRequiredAttributes > ) => void; useEditingImage: [ boolean, Dispatch< SetStateAction< boolean > > ]; } interface WithBlockControlsCategoryProps< T > extends WithBlockControlsRequiredProps< T > { category: WP_REST_API_Category; product: never; } interface WithBlockControlsProductProps< T > extends WithBlockControlsRequiredProps< T > { category: never; product: ProductResponseItem; } type WithBlockControlsProps< T extends EditorBlock< T > > = | ( T & WithBlockControlsCategoryProps< T > ) | ( T & WithBlockControlsProductProps< T > ); type BlockControlRequiredAttributes = { contentAlign: BlockAlignment; editMode: boolean; mediaId: number; mediaSrc: string; }; interface BlockControlsProps { backgroundImageId: number; backgroundImageSrc: string; contentAlign: BlockAlignment; cropLabel: string; editLabel: string; editMode: boolean; isEditingImage: boolean; mediaSrc: string; setAttributes: ( attrs: Partial< BlockControlRequiredAttributes > ) => void; setIsEditingImage: ( value: boolean ) => void; } interface BlockControlsConfiguration extends GenericBlockUIConfig { cropLabel: string; editLabel: string; } export const BlockControls = ( { backgroundImageId, backgroundImageSrc, contentAlign, cropLabel, editLabel, editMode, isEditingImage, mediaSrc, setAttributes, setIsEditingImage, }: BlockControlsProps ) => { return ( { setAttributes( { contentAlign: nextAlign } ); } } /> { backgroundImageSrc && ! isEditingImage && ( setIsEditingImage( true ) } icon={ crop } label={ cropLabel } /> ) } { setAttributes( { mediaId: media.id, mediaSrc: media.url, } ); } } allowedTypes={ [ 'image' ] } /> { backgroundImageId && mediaSrc ? ( setAttributes( { mediaId: 0, mediaSrc: '' } ) } > { __( 'Reset', 'woo-gutenberg-products-block' ) } ) : null } setAttributes( { editMode: ! editMode } ), isActive: editMode, }, ] } /> ); }; export const withBlockControls = ( { cropLabel, editLabel, }: BlockControlsConfiguration ) => < T extends EditorBlock< T > >( Component: ComponentType< T > ) => ( props: WithBlockControlsProps< T > ) => { const [ isEditingImage, setIsEditingImage ] = props.useEditingImage; const { attributes, category, name, product, setAttributes } = props; const { contentAlign, editMode, mediaId, mediaSrc } = attributes; const item = category || product; const { backgroundImageId, backgroundImageSrc } = useBackgroundImage( { item, mediaId, mediaSrc, blockName: name, } ); return ( <> ); };