import deepmerge from 'deepmerge'; import { useSelect } from '@wordpress/data'; import { useCallback } from '@wordpress/element'; import { storeName, TypographyProperties } from '../store'; import { useEmailTheme } from './use-email-theme'; interface ElementProperties { typography: TypographyProperties; } export interface StyleProperties { spacing?: { padding: { top: string; right: string; bottom: string; left: string; }; blockGap: string; }; typography?: TypographyProperties; color?: { background: string; text: string; }; elements?: Record; } interface EmailStylesData { styles: StyleProperties; defaultStyles: StyleProperties; updateStyleProp: (path, newValue) => void; updateStyles: (newStyles: StyleProperties) => void; } /** * Immutably sets a value inside an object. Like `lodash#set`, but returning a * new object. Treats nullish initial values as empty objects. Clones any * nested objects. Supports arrays, too. * * @param {Object} object Object to set a value in. * @param {number|string|Array} setPath Path in the object to modify. * @param {*} value New value to set. * @return {Object} Cloned object with the new value set. */ export function setImmutably(setObject, setPath, value): typeof setObject { // Normalize path const path = Array.isArray(setPath) ? [...setPath] : [setPath]; // Shallowly clone the base of the object const object = Array.isArray(setObject) ? [...setObject] : { ...setObject }; const leaf = path.pop(); // Traverse object from root to leaf, shallowly cloning at each level let prev = object; path.forEach((key) => { const lvl = prev[key]; prev[key] = Array.isArray(lvl) ? [...lvl] : { ...lvl }; prev = prev[key]; }); prev[leaf] = value; return object; } export const useEmailStyles = (): EmailStylesData => { const { templateTheme, updateTemplateTheme } = useEmailTheme(); // This is email level styling stored in post meta. const styles = templateTheme?.styles; // Default styles from theme.json. const { styles: defaultStyles } = useSelect((select) => ({ styles: select(storeName).getStyles(), })); // Update email styles. const updateStyles = useCallback( (newStyles) => { const newTheme = { ...templateTheme, styles: newStyles, }; updateTemplateTheme(newTheme); }, [updateTemplateTheme, templateTheme], ); // Update an email style prop. const updateStyleProp = useCallback( (path, newValue) => { const newTheme = setImmutably( templateTheme, ['styles', ...path], newValue, ); updateTemplateTheme(newTheme); }, [updateTemplateTheme, templateTheme], ); return { styles: deepmerge.all([defaultStyles || {}, styles || {}]), defaultStyles, updateStyleProp, updateStyles, }; };