/* eslint-disable @wordpress/no-unsafe-wp-apis */
/**
* External dependencies
*/
import type { BlockAlignment } from '@wordpress/blocks';
import { ProductResponseItem } from '@woocommerce/types';
import { __experimentalGetSpacingClassesAndStyles as getSpacingClassesAndStyles } from '@wordpress/block-editor';
import { Icon, Placeholder, Spinner } from '@wordpress/components';
import classnames from 'classnames';
import { isEmpty } from 'lodash';
import { useCallback, useState } from '@wordpress/element';
import { WP_REST_API_Category } from 'wp-types';
import { useBorderProps } from '@woocommerce/base-hooks';
import type { ComponentType, Dispatch, SetStateAction } from 'react';
/**
* Internal dependencies
*/
import { CallToAction } from './call-to-action';
import { ConstrainedResizable } from './constrained-resizable';
import { EditorBlock, GenericBlockUIConfig } from './types';
import { useBackgroundImage } from './use-background-image';
import {
dimRatioToClass,
getBackgroundImageStyles,
getClassPrefixFromName,
} from './utils';
interface WithFeaturedItemConfig extends GenericBlockUIConfig {
emptyMessage: string;
}
export interface FeaturedItemRequiredAttributes {
contentAlign: BlockAlignment;
dimRatio: number;
focalPoint: { x: number; y: number };
hasParallax: boolean;
imageFit: 'cover' | 'none';
isRepeated: boolean;
linkText: string;
mediaId: number;
mediaSrc: string;
minHeight: number;
overlayColor: string;
overlayGradient: string;
showDesc: boolean;
showPrice: boolean;
}
interface FeaturedCategoryRequiredAttributes
extends FeaturedItemRequiredAttributes {
categoryId: number | 'preview';
productId: never;
}
interface FeaturedProductRequiredAttributes
extends FeaturedItemRequiredAttributes {
categoryId: never;
productId: number | 'preview';
}
interface FeaturedItemRequiredProps< T > {
attributes: (
| FeaturedCategoryRequiredAttributes
| FeaturedProductRequiredAttributes
) &
EditorBlock< T >[ 'attributes' ] & {
// This is hardcoded because border and color are not yet included
// in Gutenberg's official types.
style: {
border?: { radius?: number };
color?: { text?: string };
};
textColor?: string;
};
isLoading: boolean;
setAttributes: ( attrs: Partial< FeaturedItemRequiredAttributes > ) => void;
useEditingImage: [ boolean, Dispatch< SetStateAction< boolean > > ];
}
interface FeaturedCategoryProps< T > extends FeaturedItemRequiredProps< T > {
category: WP_REST_API_Category;
product: never;
}
interface FeaturedProductProps< T > extends FeaturedItemRequiredProps< T > {
category: never;
product: ProductResponseItem;
}
type FeaturedItemProps< T extends EditorBlock< T > > =
| ( T & FeaturedCategoryProps< T > )
| ( T & FeaturedProductProps< T > );
export const withFeaturedItem =
( { emptyMessage, icon, label }: WithFeaturedItemConfig ) =>
< T extends EditorBlock< T > >( Component: ComponentType< T > ) =>
( props: FeaturedItemProps< T > ) => {
const [ isEditingImage ] = props.useEditingImage;
const {
attributes,
category,
isLoading,
isSelected,
name,
product,
setAttributes,
} = props;
const { mediaId, mediaSrc } = attributes;
const item = category || product;
const [ backgroundImageSize, setBackgroundImageSize ] = useState( {} );
const { backgroundImageSrc } = useBackgroundImage( {
item,
mediaId,
mediaSrc,
blockName: name,
} );
const className = getClassPrefixFromName( name );
const onResize = useCallback(
( _event, _direction, elt ) => {
setAttributes( {
minHeight: parseInt( elt.style.height, 10 ),
} );
},
[ setAttributes ]
);
const renderButton = () => {
const { categoryId, linkText, productId } = attributes;
return (