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';
|
2022-05-19 16:16:46 +00:00
|
|
|
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';
|
2022-05-30 14:38:52 +00:00
|
|
|
import { LooselyMustHave, ProductResponseItem } from '@woocommerce/types';
|
2023-03-02 14:26:00 +00:00
|
|
|
import type { ComponentType } from 'react';
|
2022-05-19 16:16:46 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import { useBackgroundImage } from './use-background-image';
|
|
|
|
import { BLOCK_NAMES } from './constants';
|
2022-05-30 14:38:52 +00:00
|
|
|
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 > );
|
2022-05-19 16:16:46 +00:00
|
|
|
|
|
|
|
export const InspectorControls = ( {
|
|
|
|
alt,
|
|
|
|
backgroundImageSrc,
|
|
|
|
contentPanel,
|
|
|
|
dimRatio,
|
2022-05-31 11:26:36 +00:00
|
|
|
focalPoint,
|
2022-05-19 16:16:46 +00:00
|
|
|
hasParallax,
|
|
|
|
imageFit,
|
2022-05-30 14:38:52 +00:00
|
|
|
isRepeated,
|
2022-05-19 16:16:46 +00:00
|
|
|
overlayColor,
|
|
|
|
overlayGradient,
|
|
|
|
setAttributes,
|
|
|
|
setGradient,
|
|
|
|
showDesc,
|
2022-05-30 14:38:52 +00:00
|
|
|
}: InspectorControlsProps ) => {
|
2022-05-19 16:16:46 +00:00
|
|
|
// 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 (
|
|
|
|
<GutenbergInspectorControls key="inspector">
|
2023-12-12 23:05:20 +00:00
|
|
|
<PanelBody title={ __( 'Content', 'woocommerce' ) }>
|
2022-05-19 16:16:46 +00:00
|
|
|
<ToggleControl
|
2023-12-12 23:05:20 +00:00
|
|
|
label={ __( 'Show description', 'woocommerce' ) }
|
2022-05-19 16:16:46 +00:00
|
|
|
checked={ showDesc }
|
|
|
|
onChange={ () => setAttributes( { showDesc: ! showDesc } ) }
|
|
|
|
/>
|
|
|
|
{ contentPanel }
|
|
|
|
</PanelBody>
|
|
|
|
{ !! backgroundImageSrc && (
|
|
|
|
<>
|
|
|
|
{ focalPointPickerExists && (
|
|
|
|
<PanelBody
|
2023-12-12 23:05:20 +00:00
|
|
|
title={ __( 'Media settings', 'woocommerce' ) }
|
2022-05-19 16:16:46 +00:00
|
|
|
>
|
|
|
|
<ToggleControl
|
|
|
|
label={ __(
|
|
|
|
'Fixed background',
|
2023-12-12 22:12:36 +00:00
|
|
|
'woocommerce'
|
2022-05-19 16:16:46 +00:00
|
|
|
) }
|
|
|
|
checked={ hasParallax }
|
|
|
|
onChange={ () => {
|
|
|
|
setAttributes( {
|
|
|
|
hasParallax: ! hasParallax,
|
|
|
|
} );
|
|
|
|
} }
|
|
|
|
/>
|
|
|
|
<ToggleControl
|
|
|
|
label={ __(
|
|
|
|
'Repeated background',
|
2023-12-12 22:12:36 +00:00
|
|
|
'woocommerce'
|
2022-05-19 16:16:46 +00:00
|
|
|
) }
|
|
|
|
checked={ isRepeated }
|
|
|
|
onChange={ () => {
|
|
|
|
setAttributes( {
|
|
|
|
isRepeated: ! isRepeated,
|
|
|
|
} );
|
|
|
|
} }
|
|
|
|
/>
|
|
|
|
{ ! isRepeated && (
|
|
|
|
<ToggleGroupControl
|
|
|
|
help={
|
|
|
|
<>
|
2022-06-01 08:02:24 +00:00
|
|
|
<span
|
|
|
|
style={ {
|
|
|
|
display: 'block',
|
|
|
|
marginBottom: '1em',
|
|
|
|
} }
|
|
|
|
>
|
2022-05-19 16:16:46 +00:00
|
|
|
{ __(
|
2022-09-12 08:39:26 +00:00
|
|
|
'Select “Cover” to have the image automatically fit its container.',
|
2023-12-12 22:12:36 +00:00
|
|
|
'woocommerce'
|
2022-05-19 16:16:46 +00:00
|
|
|
) }
|
2022-06-01 08:02:24 +00:00
|
|
|
</span>
|
|
|
|
<span>
|
2022-05-19 16:16:46 +00:00
|
|
|
{ __(
|
2022-09-12 08:39:26 +00:00
|
|
|
'This may affect your ability to freely move the focal point of the image.',
|
2023-12-12 22:12:36 +00:00
|
|
|
'woocommerce'
|
2022-05-19 16:16:46 +00:00
|
|
|
) }
|
2022-06-01 08:02:24 +00:00
|
|
|
</span>
|
2022-05-19 16:16:46 +00:00
|
|
|
</>
|
|
|
|
}
|
2023-12-12 23:05:20 +00:00
|
|
|
label={ __( 'Image fit', 'woocommerce' ) }
|
2022-05-19 16:16:46 +00:00
|
|
|
value={ imageFit }
|
2022-05-30 14:38:52 +00:00
|
|
|
onChange={ ( value: ImageFit ) =>
|
2022-05-19 16:16:46 +00:00
|
|
|
setAttributes( {
|
|
|
|
imageFit: value,
|
|
|
|
} )
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<ToggleGroupControlOption
|
2023-12-12 23:05:20 +00:00
|
|
|
label={ __( 'None', 'woocommerce' ) }
|
2022-05-19 16:16:46 +00:00
|
|
|
value="none"
|
|
|
|
/>
|
|
|
|
<ToggleGroupControlOption
|
|
|
|
/* translators: "Cover" is a verb that indicates an image covering the entire container. */
|
2023-12-12 23:05:20 +00:00
|
|
|
label={ __( 'Cover', 'woocommerce' ) }
|
2022-05-19 16:16:46 +00:00
|
|
|
value="cover"
|
|
|
|
/>
|
|
|
|
</ToggleGroupControl>
|
|
|
|
) }
|
|
|
|
<FocalPointPicker
|
|
|
|
label={ __(
|
|
|
|
'Focal Point Picker',
|
2023-12-12 22:12:36 +00:00
|
|
|
'woocommerce'
|
2022-05-19 16:16:46 +00:00
|
|
|
) }
|
|
|
|
url={ backgroundImageSrc }
|
|
|
|
value={ focalPoint }
|
|
|
|
onChange={ ( value ) =>
|
|
|
|
setAttributes( {
|
|
|
|
focalPoint: value,
|
|
|
|
} )
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
{ isImgElement && (
|
|
|
|
<TextareaControl
|
|
|
|
label={ __(
|
|
|
|
'Alt text (alternative text)',
|
2023-12-12 22:12:36 +00:00
|
|
|
'woocommerce'
|
2022-05-19 16:16:46 +00:00
|
|
|
) }
|
|
|
|
value={ alt }
|
2022-05-30 14:38:52 +00:00
|
|
|
onChange={ ( value: string ) => {
|
2022-05-19 16:16:46 +00:00
|
|
|
setAttributes( { alt: value } );
|
|
|
|
} }
|
|
|
|
help={
|
|
|
|
<>
|
|
|
|
<ExternalLink href="https://www.w3.org/WAI/tutorials/images/decision-tree">
|
|
|
|
{ __(
|
|
|
|
'Describe the purpose of the image',
|
2023-12-12 22:12:36 +00:00
|
|
|
'woocommerce'
|
2022-05-19 16:16:46 +00:00
|
|
|
) }
|
|
|
|
</ExternalLink>
|
|
|
|
</>
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
) }
|
|
|
|
</PanelBody>
|
|
|
|
) }
|
|
|
|
<PanelColorGradientSettings
|
|
|
|
__experimentalHasMultipleOrigins
|
|
|
|
__experimentalIsRenderedInSidebar
|
2023-12-12 23:05:20 +00:00
|
|
|
title={ __( 'Overlay', 'woocommerce' ) }
|
2022-05-19 16:16:46 +00:00
|
|
|
initialOpen={ true }
|
|
|
|
settings={ [
|
|
|
|
{
|
|
|
|
colorValue: overlayColor,
|
|
|
|
gradientValue: overlayGradient,
|
2022-05-30 14:38:52 +00:00
|
|
|
onColorChange: ( value: string ) =>
|
2022-05-19 16:16:46 +00:00
|
|
|
setAttributes( { overlayColor: value } ),
|
2022-05-30 14:38:52 +00:00
|
|
|
onGradientChange: ( value: string ) => {
|
2022-05-19 16:16:46 +00:00
|
|
|
setGradient( value );
|
|
|
|
setAttributes( {
|
|
|
|
overlayGradient: value,
|
|
|
|
} );
|
|
|
|
},
|
2023-12-12 23:05:20 +00:00
|
|
|
label: __( 'Color', 'woocommerce' ),
|
2022-05-19 16:16:46 +00:00
|
|
|
},
|
|
|
|
] }
|
|
|
|
>
|
|
|
|
<RangeControl
|
2023-12-12 23:05:20 +00:00
|
|
|
label={ __( 'Opacity', 'woocommerce' ) }
|
2022-05-19 16:16:46 +00:00
|
|
|
value={ dimRatio }
|
|
|
|
onChange={ ( value ) =>
|
2022-05-30 14:38:52 +00:00
|
|
|
setAttributes( { dimRatio: value as number } )
|
2022-05-19 16:16:46 +00:00
|
|
|
}
|
|
|
|
min={ 0 }
|
|
|
|
max={ 100 }
|
|
|
|
step={ 10 }
|
|
|
|
required
|
|
|
|
/>
|
|
|
|
</PanelColorGradientSettings>
|
|
|
|
</>
|
|
|
|
) }
|
|
|
|
</GutenbergInspectorControls>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2022-06-15 09:56:52 +00:00
|
|
|
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;
|
2022-05-19 16:16:46 +00:00
|
|
|
|
2022-06-15 09:56:52 +00:00
|
|
|
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 { setGradient } = useGradient( {
|
|
|
|
gradientAttribute: 'overlayGradient',
|
|
|
|
customGradientAttribute: 'overlayGradient',
|
|
|
|
} );
|
|
|
|
const { backgroundImageSrc } = useBackgroundImage( {
|
|
|
|
item,
|
|
|
|
mediaId,
|
|
|
|
mediaSrc,
|
|
|
|
blockName: name,
|
|
|
|
} );
|
2022-05-19 16:16:46 +00:00
|
|
|
|
2022-06-15 09:56:52 +00:00
|
|
|
const contentPanel =
|
|
|
|
name === BLOCK_NAMES.featuredProduct ? (
|
|
|
|
<ToggleControl
|
2023-12-12 22:12:36 +00:00
|
|
|
label={ __( 'Show price', 'woocommerce' ) }
|
2022-06-15 09:56:52 +00:00
|
|
|
checked={ showPrice }
|
|
|
|
onChange={ () =>
|
|
|
|
setAttributes( {
|
|
|
|
showPrice: ! showPrice,
|
|
|
|
} )
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
) : undefined;
|
2022-05-19 16:16:46 +00:00
|
|
|
|
2022-06-15 09:56:52 +00:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<InspectorControls
|
|
|
|
alt={ alt }
|
|
|
|
backgroundImageSrc={ backgroundImageSrc }
|
|
|
|
contentPanel={ contentPanel }
|
|
|
|
dimRatio={ dimRatio }
|
|
|
|
focalPoint={ focalPoint }
|
|
|
|
hasParallax={ hasParallax }
|
|
|
|
isRepeated={ isRepeated }
|
|
|
|
imageFit={ imageFit }
|
|
|
|
overlayColor={ overlayColor }
|
|
|
|
overlayGradient={ overlayGradient }
|
|
|
|
setAttributes={ setAttributes }
|
|
|
|
setGradient={ setGradient }
|
|
|
|
showDesc={ showDesc }
|
|
|
|
/>
|
|
|
|
<Component { ...props } />
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|