Files
piratepoet/packages/js/email-editor/src/hooks/use-email-styles.ts
Oluwaseun Olorunsola 1c3ea9cd0a Move email editor components out of the engine folder
MAILPOET-6215
2024-11-11 11:53:49 +02:00

113 lines
2.8 KiB
TypeScript

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< string, ElementProperties >;
}
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 setObject
* @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,
};
};