woocommerce/plugins/woocommerce-blocks/assets/js/base/hooks/use-style-props.ts

89 lines
2.2 KiB
TypeScript

/**
* External dependencies
*/
import clsx from 'clsx';
import { isString, isObject } from '@woocommerce/types';
import type { Style as StyleEngineProperties } from '@wordpress/style-engine/src/types';
import type { CSSProperties } from 'react';
/**
* Internal dependencies
*/
import { useTypographyProps } from './use-typography-props';
import {
getColorClassesAndStyles,
getBorderClassesAndStyles,
getSpacingClassesAndStyles,
} from '../utils';
export type StyleProps = {
className: string;
style: CSSProperties;
};
type BlockAttributes = Record< string, unknown > & {
style?: StyleEngineProperties | string | undefined;
};
type StyleAttributes = Record< string, unknown > & {
style: StyleEngineProperties;
};
/**
* Parses incoming props.
*
* This may include style properties at the top level, or may include a nested `style` object. This ensures the expected
* values are present and converts any string based values to objects as required.
*/
const parseStyleAttributes = ( rawProps: BlockAttributes ): StyleAttributes => {
const props = isObject( rawProps )
? rawProps
: {
style: {},
};
let style = props.style;
if ( isString( style ) ) {
style = JSON.parse( style ) || {};
}
if ( ! isObject( style ) ) {
style = {};
}
return {
...props,
style,
};
};
/**
* Returns the CSS class names and inline styles for a block when provided with its props/attributes.
*
* This hook (and its utilities) borrow functionality from the Gutenberg Block Editor package--something we don't want
* to import on the frontend.
*/
export const useStyleProps = ( props: BlockAttributes ): StyleProps => {
const styleAttributes = parseStyleAttributes( props );
const colorProps = getColorClassesAndStyles( styleAttributes );
const borderProps = getBorderClassesAndStyles( styleAttributes );
const spacingProps = getSpacingClassesAndStyles( styleAttributes );
const typographyProps = useTypographyProps( styleAttributes );
return {
className: clsx(
typographyProps.className,
colorProps.className,
borderProps.className,
spacingProps.className
),
style: {
...typographyProps.style,
...colorProps.style,
...borderProps.style,
...spacingProps.style,
},
};
};