diff --git a/packages/edit-site/src/components/global-styles/variations/variation.js b/packages/edit-site/src/components/global-styles/variations/variation.js index dc531b40635259..d2fa64ca64a27a 100644 --- a/packages/edit-site/src/components/global-styles/variations/variation.js +++ b/packages/edit-site/src/components/global-styles/variations/variation.js @@ -15,12 +15,19 @@ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; * Internal dependencies */ import { mergeBaseAndUserConfigs } from '../global-styles-provider'; +import getValueFromObjectPath from '../../../utils/get-value-from-object-path'; +import setNestedValue from '../../../utils/set-nested-value'; import { unlock } from '../../../lock-unlock'; const { GlobalStylesContext, areGlobalStyleConfigsEqual } = unlock( blockEditorPrivateApis ); +const PATHS_TO_AVOID_OVERWRITING = [ + [ 'settings', 'typography', 'fontFamilies', 'custom' ], + [ 'settings', 'color', 'palette', 'custom' ], +]; + export default function Variation( { variation, children } ) { const [ isFocused, setIsFocused ] = useState( false ); const { base, user, setUserConfig } = useContext( GlobalStylesContext ); @@ -38,10 +45,20 @@ export default function Variation( { variation, children } ) { ); const selectVariation = () => { - setUserConfig( () => ( { - settings: variation.settings, - styles: variation.styles, - } ) ); + setUserConfig( ( currentConfig ) => { + // Avoids overwriting certain paths when applying a theme variation. + for ( const path of PATHS_TO_AVOID_OVERWRITING ) { + // Gets the value from the current config. + const value = getValueFromObjectPath( currentConfig, path ); + // Sets the value in the applied variation. + setNestedValue( variation, path, value ); + } + + return { + settings: variation.settings, + styles: variation.styles, + }; + } ); }; const selectOnEnter = ( event ) => { diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 21f19201b75108..d6b0b5661546ae 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -27,6 +27,8 @@ import { store as coreStore } from '@wordpress/core-data'; import { useSupportedStyles } from '../../components/global-styles/hooks'; import { unlock } from '../../lock-unlock'; import cloneDeep from '../../utils/clone-deep'; +import getValueFromObjectPath from '../../utils/get-value-from-object-path'; +import setNestedValue from '../../utils/set-nested-value'; const { cleanEmptyObject, GlobalStylesContext } = unlock( blockEditorPrivateApis @@ -105,14 +107,6 @@ const STYLE_PATH_TO_PRESET_BLOCK_ATTRIBUTE = { const SUPPORTED_STYLES = [ 'border', 'color', 'spacing', 'typography' ]; -const getValueFromObjectPath = ( object, path ) => { - let value = object; - path.forEach( ( fieldName ) => { - value = value?.[ fieldName ]; - } ); - return value; -}; - const flatBorderProperties = [ 'borderColor', 'borderWidth', 'borderStyle' ]; const sides = [ 'top', 'right', 'bottom', 'left' ]; @@ -236,46 +230,6 @@ function useChangesToPush( name, attributes, userConfig ) { }, [ supports, attributes, blockUserConfig ] ); } -/** - * Sets the value at path of object. - * If a portion of path doesn’t exist, it’s created. - * Arrays are created for missing index properties while objects are created - * for all other missing properties. - * - * This function intentionally mutates the input object. - * - * Inspired by _.set(). - * - * @see https://lodash.com/docs/4.17.15#set - * - * @todo Needs to be deduplicated with its copy in `@wordpress/core-data`. - * - * @param {Object} object Object to modify - * @param {Array} path Path of the property to set. - * @param {*} value Value to set. - */ -function setNestedValue( object, path, value ) { - if ( ! object || typeof object !== 'object' ) { - return object; - } - - path.reduce( ( acc, key, idx ) => { - if ( acc[ key ] === undefined ) { - if ( Number.isInteger( path[ idx + 1 ] ) ) { - acc[ key ] = []; - } else { - acc[ key ] = {}; - } - } - if ( idx === path.length - 1 ) { - acc[ key ] = value; - } - return acc[ key ]; - }, object ); - - return object; -} - function PushChangesToGlobalStylesControl( { name, attributes, diff --git a/packages/edit-site/src/utils/get-value-from-object-path.js b/packages/edit-site/src/utils/get-value-from-object-path.js new file mode 100644 index 00000000000000..f1109904f24021 --- /dev/null +++ b/packages/edit-site/src/utils/get-value-from-object-path.js @@ -0,0 +1,7 @@ +export default function getValueFromObjectPath( object, path ) { + let value = object; + path.forEach( ( fieldName ) => { + value = value?.[ fieldName ]; + } ); + return value; +} diff --git a/packages/edit-site/src/utils/set-nested-value.js b/packages/edit-site/src/utils/set-nested-value.js new file mode 100644 index 00000000000000..ec684e751cd041 --- /dev/null +++ b/packages/edit-site/src/utils/set-nested-value.js @@ -0,0 +1,39 @@ +/** + * Sets the value at path of object. + * If a portion of path doesn’t exist, it’s created. + * Arrays are created for missing index properties while objects are created + * for all other missing properties. + * + * This function intentionally mutates the input object. + * + * Inspired by _.set(). + * + * @see https://lodash.com/docs/4.17.15#set + * + * @todo Needs to be deduplicated with its copy in `@wordpress/core-data`. + * + * @param {Object} object Object to modify + * @param {Array} path Path of the property to set. + * @param {*} value Value to set. + */ +export default function setNestedValue( object, path, value ) { + if ( ! object || typeof object !== 'object' ) { + return object; + } + + path.reduce( ( acc, key, idx ) => { + if ( acc[ key ] === undefined ) { + if ( Number.isInteger( path[ idx + 1 ] ) ) { + acc[ key ] = []; + } else { + acc[ key ] = {}; + } + } + if ( idx === path.length - 1 ) { + acc[ key ] = value; + } + return acc[ key ]; + }, object ); + + return object; +}