diff --git a/assets/js/atomic/blocks/product-elements/title/block.tsx b/assets/js/atomic/blocks/product-elements/title/block.tsx index 86801e51fbd..99369553568 100644 --- a/assets/js/atomic/blocks/product-elements/title/block.tsx +++ b/assets/js/atomic/blocks/product-elements/title/block.tsx @@ -7,7 +7,6 @@ import { useInnerBlockLayoutContext, useProductDataContext, } from '@woocommerce/shared-context'; -import { getColorClassName, getFontSizeClass } from '@wordpress/block-editor'; import { isFeaturePluginBuild } from '@woocommerce/block-settings'; import { withProductDataContext } from '@woocommerce/shared-hocs'; import ProductName from '@woocommerce/base-components/product-name'; @@ -18,6 +17,11 @@ import { useStoreEvents } from '@woocommerce/base-context/hooks'; */ import './style.scss'; import { Attributes } from './types'; +import { + useSpacingProps, + useTypographyProps, + useColorProps, +} from '../../../../utils/style-attributes-utils'; type Props = Attributes & HTMLAttributes< HTMLDivElement >; @@ -49,33 +53,26 @@ const TagName = ( { * will be used if this is not provided. * @return {*} The component. */ -export const Block = ( { - className, - headingLevel = 2, - showProductLink = true, - align, - textColor, - fontSize, - style, -}: Props ): JSX.Element => { +export const Block = ( props: Props ): JSX.Element => { + const { + className, + headingLevel = 2, + showProductLink = true, + align, + } = props; + const { parentClassName } = useInnerBlockLayoutContext(); const { product } = useProductDataContext(); const { dispatchStoreEvent } = useStoreEvents(); - const colorClass = getColorClassName( 'color', textColor ); - const fontSizeClass = getFontSizeClass( fontSize ); - const titleClasses = classnames( 'wp-block-woocommerce-product-title', { - 'has-text-color': textColor || style?.color?.text || style?.color, - [ `has-font-size` ]: - fontSize || style?.typography?.fontSize || style?.fontSize, - [ colorClass ]: colorClass, - [ fontSizeClass ]: fontSizeClass, - } ); + const colorProps = useColorProps( props ); + const spacingProps = useSpacingProps( props ); + const typographyProps = useTypographyProps( props ); - const titleStyle = { - fontSize: style?.fontSize || style?.typography?.fontSize, - color: style?.color?.text || style?.color, - }; + const titleClasses = classnames( + 'wp-block-woocommerce-product-title', + colorProps.className + ); if ( ! product.id ) { return ( @@ -88,7 +85,6 @@ export const Block = ( { [ `${ parentClassName }__product-title` ]: parentClassName, [ `wc-block-components-product-title--align-${ align }` ]: align && isFeaturePluginBuild(), - [ titleClasses ]: isFeaturePluginBuild(), } ) } /> @@ -109,9 +105,7 @@ export const Block = ( { ) } > ); diff --git a/assets/js/atomic/blocks/product-elements/title/index.ts b/assets/js/atomic/blocks/product-elements/title/index.ts index bf70fbfd62c..03935b1a702 100644 --- a/assets/js/atomic/blocks/product-elements/title/index.ts +++ b/assets/js/atomic/blocks/product-elements/title/index.ts @@ -24,17 +24,25 @@ const blockConfig: BlockConfiguration = { icon: { src: icon }, attributes, edit, - supports: isFeaturePluginBuild() - ? { - html: false, - color: { - background: false, - }, - typography: { - fontSize: true, - }, - } - : sharedConfig.supports, + supports: { + typography: { + fontSize: true, + lineHeight: true, + ...( isFeaturePluginBuild() && { + __experimentalFontWeight: true, + __experimentalTextTransform: true, + __experimentalFontFamily: true, + } ), + }, + color: { + text: false, + background: true, + gradients: true, + }, + spacing: { + margin: true, + }, + }, }; registerBlockType( 'woocommerce/product-title', blockConfig ); diff --git a/assets/js/utils/style-attributes-utils.ts b/assets/js/utils/style-attributes-utils.ts new file mode 100644 index 00000000000..ab4145af1f4 --- /dev/null +++ b/assets/js/utils/style-attributes-utils.ts @@ -0,0 +1,103 @@ +/* eslint-disable @wordpress/no-unsafe-wp-apis */ +/** + * External dependencies + */ +import { __experimentalUseColorProps } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { isFeaturePluginBuild } from '../settings/blocks/feature-flags'; +import { isString, isObject } from '../types/type-guards'; + +type WithClass = { + className: string; +}; + +type WithStyle = { + style: Record< string, unknown >; +}; + +const parseStyle = ( style: unknown ): Record< string, unknown > => { + if ( isString( style ) ) { + return JSON.parse( style ) || {}; + } + + if ( isObject( style ) ) { + return style; + } + + return {}; +}; + +const parseSpacingStyle = ( + spacing: Record< string, unknown > +): Record< string, unknown > => { + const keys = [ 'margin' ]; + + const getValueOrDefault = ( value: unknown ) => { + return isString( value ) && value.length > 0 ? value : '0'; + }; + + return Object.keys( spacing ).reduce( ( acc, key ) => { + const spacingProperty = isObject( spacing[ key ] ) + ? ( spacing[ key ] as Record< string, unknown > ) + : {}; + + if ( keys.includes( key ) ) { + return { + ...acc, + [ key ]: `${ getValueOrDefault( + spacingProperty.top + ) } ${ getValueOrDefault( + spacingProperty.right + ) } ${ getValueOrDefault( + spacingProperty.bottom + ) } ${ getValueOrDefault( spacingProperty.left ) }`, + }; + } + + return acc; + }, {} ); +}; + +export const useSpacingProps = ( attributes: unknown ): WithStyle => { + const style = isObject( attributes ) ? parseStyle( attributes.style ) : {}; + const spacingStyles = isObject( style.spacing ) ? style.spacing : {}; + + return { + style: parseSpacingStyle( spacingStyles ), + }; +}; + +export const useTypographyProps = ( attributes: unknown ): WithStyle => { + const attributesObject = isObject( attributes ) ? attributes : {}; + const style = parseStyle( attributesObject.style ); + const typography = isObject( style.typography ) + ? ( style.typography as Record< string, unknown > ) + : {}; + + return { + style: { + fontSize: attributesObject.fontSize || typography.fontSize, + lineHeight: typography.lineHeight, + fontWeight: typography.fontWeight, + textTransform: typography.textTransform, + fontFamily: attributesObject.fontFamily, + }, + }; +}; + +export const useColorProps = ( attributes: unknown ): WithStyle & WithClass => { + if ( ! isFeaturePluginBuild() ) { + return { + className: '', + style: {}, + }; + } + + const attributesObject = isObject( attributes ) ? attributes : {}; + const style = parseStyle( attributesObject.style ); + + return __experimentalUseColorProps( { ...attributesObject, style } ); +};