/* eslint-disable @wordpress/no-unsafe-wp-apis */ /** * External dependencies */ import { WP_REST_API_Category } from 'wp-types'; import { __ } from '@wordpress/i18n'; import { InspectorControls as GutenbergInspectorControls, __experimentalPanelColorGradientSettings as PanelColorGradientSettings, __experimentalUseGradient as useGradient, } from '@wordpress/block-editor'; import { FocalPointPicker, PanelBody, RangeControl, ToggleControl, __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOption as ToggleGroupControlOption, TextareaControl, ExternalLink, } from '@wordpress/components'; import { LooselyMustHave, ProductResponseItem } from '@woocommerce/types'; import type { ComponentType } from 'react'; /** * Internal dependencies */ import { useBackgroundImage } from './use-background-image'; import { BLOCK_NAMES } from './constants'; import { FeaturedItemRequiredAttributes } from './with-featured-item'; import { EditorBlock, ImageFit } from './types'; type InspectorControlRequiredKeys = | 'dimRatio' | 'focalPoint' | 'hasParallax' | 'imageFit' | 'isRepeated' | 'overlayColor' | 'overlayGradient' | 'showDesc'; interface InspectorControlsRequiredAttributes extends LooselyMustHave< FeaturedItemRequiredAttributes, InspectorControlRequiredKeys > { alt: string; backgroundImageSrc: string; contentPanel: JSX.Element | undefined; } interface InspectorControlsProps extends InspectorControlsRequiredAttributes { setAttributes: ( attrs: Partial< InspectorControlsRequiredAttributes > ) => void; // Gutenberg doesn't provide some types, so we have to hard-code them here setGradient: ( newGradientValue: string ) => void; } interface WithInspectorControlsRequiredProps< T > { attributes: InspectorControlsRequiredAttributes & EditorBlock< T >[ 'attributes' ]; setAttributes: InspectorControlsProps[ 'setAttributes' ]; } interface WithInspectorControlsCategoryProps< T > extends WithInspectorControlsRequiredProps< T > { category: WP_REST_API_Category; product: never; } interface WithInspectorControlsProductProps< T > extends WithInspectorControlsRequiredProps< T > { category: never; product: ProductResponseItem; showPrice: boolean; } type WithInspectorControlsProps< T extends EditorBlock< T > > = | ( T & WithInspectorControlsCategoryProps< T > ) | ( T & WithInspectorControlsProductProps< T > ); export const InspectorControls = ( { alt, backgroundImageSrc, contentPanel, dimRatio, focalPoint, hasParallax, imageFit, isRepeated, overlayColor, overlayGradient, setAttributes, setGradient, showDesc, }: InspectorControlsProps ) => { // FocalPointPicker was introduced in Gutenberg 5.0 (WordPress 5.2), // so we need to check if it exists before using it. const focalPointPickerExists = typeof FocalPointPicker === 'function'; const isImgElement = ! isRepeated && ! hasParallax; return ( setAttributes( { showDesc: ! showDesc } ) } /> { contentPanel } { !! backgroundImageSrc && ( <> { focalPointPickerExists && ( { setAttributes( { hasParallax: ! hasParallax, } ); } } /> { setAttributes( { isRepeated: ! isRepeated, } ); } } /> { ! isRepeated && ( { __( 'Select “Cover” to have the image automatically fit its container.', 'woocommerce' ) } { __( 'This may affect your ability to freely move the focal point of the image.', 'woocommerce' ) } } label={ __( 'Image fit', 'woocommerce' ) } value={ imageFit } onChange={ ( value: ImageFit ) => setAttributes( { imageFit: value, } ) } > ) } setAttributes( { focalPoint: value, } ) } /> { isImgElement && ( { setAttributes( { alt: value } ); } } help={ <> { __( 'Describe the purpose of the image', 'woocommerce' ) } } /> ) } ) } setAttributes( { overlayColor: value } ), onGradientChange: ( value: string ) => { setGradient( value ); setAttributes( { overlayGradient: value, } ); }, label: __( 'Color', 'woocommerce' ), }, ] } > setAttributes( { dimRatio: value as number } ) } min={ 0 } max={ 100 } step={ 10 } required /> ) } ); }; export const withInspectorControls = < T extends EditorBlock< T > >( Component: ComponentType< T > ) => ( props: WithInspectorControlsProps< T > ) => { const { attributes, name, setAttributes } = props; const { alt, dimRatio, focalPoint, hasParallax, isRepeated, imageFit, mediaId, mediaSrc, overlayColor, overlayGradient, showDesc, showPrice, } = attributes; const item = name === BLOCK_NAMES.featuredProduct ? props.product : props.category; const { setGradient } = useGradient( { gradientAttribute: 'overlayGradient', customGradientAttribute: 'overlayGradient', } ); const { backgroundImageSrc } = useBackgroundImage( { item, mediaId, mediaSrc, blockName: name, } ); const contentPanel = name === BLOCK_NAMES.featuredProduct ? ( setAttributes( { showPrice: ! showPrice, } ) } /> ) : undefined; return ( <> ); };