diff --git a/lib/class-wp-rest-block-editor-settings-controller.php b/lib/class-wp-rest-block-editor-settings-controller.php index 1d66d1f903b0e5..6de3788fe28c24 100644 --- a/lib/class-wp-rest-block-editor-settings-controller.php +++ b/lib/class-wp-rest-block-editor-settings-controller.php @@ -149,7 +149,7 @@ public function get_item_schema() { '__experimentalStyles' => array( 'description' => __( 'Styles consolidated from core, theme, and user origins.', 'gutenberg' ), 'type' => 'object', - 'context' => array( 'mobile' ), + 'context' => array( 'post-editor', 'site-editor', 'widgets-editor', 'mobile' ), ), 'alignWide' => array( diff --git a/lib/global-styles.php b/lib/global-styles.php index a749a66c40cf0d..0cf5e4bb92415d 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -111,7 +111,7 @@ function_exists( 'gutenberg_is_edit_site_page' ) && } $consolidated = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( $settings, $origin ); - if ( 'mobile' === $context ) { + if ( 'site-editor' !== $context ) { $settings['__experimentalStyles'] = $consolidated->get_raw_data()['styles']; } diff --git a/packages/block-editor/src/components/border-radius-control/all-input-control.js b/packages/block-editor/src/components/border-radius-control/all-input-control.js index 00073ba297c666..041610711ffb67 100644 --- a/packages/block-editor/src/components/border-radius-control/all-input-control.js +++ b/packages/block-editor/src/components/border-radius-control/all-input-control.js @@ -1,7 +1,10 @@ /** * WordPress dependencies */ -import { __experimentalUnitControl as UnitControl } from '@wordpress/components'; +import { + __experimentalParseUnit as parseUnit, + __experimentalUnitControl as UnitControl, +} from '@wordpress/components'; import { __ } from '@wordpress/i18n'; /** @@ -9,11 +12,22 @@ import { __ } from '@wordpress/i18n'; */ import { getAllValue, hasMixedValues, hasDefinedValues } from './utils'; -export default function AllInputControl( { onChange, values, ...props } ) { +export default function AllInputControl( { + onChange, + values, + defaults, + ...props +} ) { const allValue = getAllValue( values ); const hasValues = hasDefinedValues( values ); - const isMixed = hasValues && hasMixedValues( values ); - const allPlaceholder = isMixed ? __( 'Mixed' ) : null; + const isMixedValues = hasValues && hasMixedValues( values ); + + const [ allDefault ] = parseUnit( getAllValue( defaults ) ); + const isMixedDefaults = + hasDefinedValues( defaults ) && hasMixedValues( defaults ); + + const isMixed = isMixedValues || ( ! hasValues && isMixedDefaults ); + const allPlaceholder = isMixed ? __( 'Mixed' ) : allDefault; return ( setIsLinked( ! isLinked ); @@ -74,6 +83,7 @@ export default function BorderRadiusControl( { onChange, values } ) { ) } diff --git a/packages/block-editor/src/components/border-radius-control/input-controls.js b/packages/block-editor/src/components/border-radius-control/input-controls.js index db294c7f8bd1b6..cc96d42a311e74 100644 --- a/packages/block-editor/src/components/border-radius-control/input-controls.js +++ b/packages/block-editor/src/components/border-radius-control/input-controls.js @@ -1,9 +1,17 @@ /** * WordPress dependencies */ -import { __experimentalUnitControl as UnitControl } from '@wordpress/components'; +import { + __experimentalParseUnit as parseUnit, + __experimentalUnitControl as UnitControl, +} from '@wordpress/components'; import { __ } from '@wordpress/i18n'; +/** + * Internal dependencies + */ +import { getValuesObject } from './utils'; + const CORNERS = { topLeft: __( 'Top left' ), topRight: __( 'Top right' ), @@ -14,6 +22,7 @@ const CORNERS = { export default function BoxInputControls( { onChange, values: valuesProp, + defaults: defaultsProp, ...props } ) { const createHandleOnChange = ( corner ) => ( next ) => { @@ -27,16 +36,9 @@ export default function BoxInputControls( { } ); }; - // For shorthand style & backwards compatibility, handle flat string value. - const values = - typeof valuesProp !== 'string' - ? valuesProp - : { - topLeft: valuesProp, - topRight: valuesProp, - bottomLeft: valuesProp, - bottomRight: valuesProp, - }; + // For shorthand style & backwards compatibility, handle flat string values. + const values = getValuesObject( valuesProp ); + const defaults = getValuesObject( defaultsProp ); // Controls are wrapped in tooltips as visible labels aren't desired here. return ( @@ -47,6 +49,7 @@ export default function BoxInputControls( { key={ key } aria-label={ label } value={ values[ key ] } + placeholder={ parseUnit( defaults[ key ] )[ 0 ] } onChange={ createHandleOnChange( key ) } /> ) ) } diff --git a/packages/block-editor/src/components/border-radius-control/utils.js b/packages/block-editor/src/components/border-radius-control/utils.js index a5bf6e176c92db..ab1af5c1e85304 100644 --- a/packages/block-editor/src/components/border-radius-control/utils.js +++ b/packages/block-editor/src/components/border-radius-control/utils.js @@ -73,6 +73,24 @@ export function getAllValue( values = {} ) { return allValue; } +/** + * For shorthand style & backwards compatibility, takes the radius values + * and handles flat string value. + * + * @param {string} values Radius values. + * @return {Object} Radius values in longhand object form. + */ +export function getValuesObject( values = {} ) { + return typeof values !== 'string' + ? values + : { + topLeft: values, + topRight: values, + bottomLeft: values, + bottomRight: values, + }; +} + /** * Checks to determine if values are mixed. * diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 99c1042b991730..b81a1e897a49a0 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -147,3 +147,4 @@ export { default as __experimentalUseNoRecursiveRenders } from './use-no-recursi export { default as BlockEditorProvider } from './provider'; export { default as useSetting } from './use-setting'; +export { default as __experimentalUseStyle } from './use-style'; diff --git a/packages/block-editor/src/components/line-height-control/index.js b/packages/block-editor/src/components/line-height-control/index.js index f4b5261b40acee..c3c0f74908c338 100644 --- a/packages/block-editor/src/components/line-height-control/index.js +++ b/packages/block-editor/src/components/line-height-control/index.js @@ -15,7 +15,11 @@ import { isLineHeightDefined, } from './utils'; -export default function LineHeightControl( { value: lineHeight, onChange } ) { +export default function LineHeightControl( { + value: lineHeight, + onChange, + placeholder = BASE_DEFAULT_VALUE, +} ) { const isDefined = isLineHeightDefined( lineHeight ); const handleOnKeyDown = ( event ) => { @@ -70,7 +74,7 @@ export default function LineHeightControl( { value: lineHeight, onChange } ) { onKeyDown={ handleOnKeyDown } onChange={ handleOnChange } label={ __( 'Line height' ) } - placeholder={ BASE_DEFAULT_VALUE } + placeholder={ placeholder } step={ STEP } type="number" value={ value } diff --git a/packages/block-editor/src/components/use-style/index.js b/packages/block-editor/src/components/use-style/index.js new file mode 100644 index 00000000000000..e62c802d1de9b7 --- /dev/null +++ b/packages/block-editor/src/components/use-style/index.js @@ -0,0 +1,51 @@ +/** + * External dependencies + */ +import { get } from 'lodash'; + +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { useBlockEditContext } from '../block-edit'; +import { store as blockEditorStore } from '../../store'; +import { getValueFromVariable } from '../../utils/style-variable-resolution'; + +/** + * Hook that retrieves the global styles of a block. + * It works with nested objects using by finding the value at path. + * + * @param {string|Array} path The path to the setting. + * + * @return {any} Returns the style value defined for the path. + * + * @example + * ```js + * const backgroundColor = useStyle( 'color.background' ); + * ``` + */ +export default function useStyle( path ) { + const { name: blockName } = useBlockEditContext(); + + const settings = useSelect( ( select ) => { + return select( blockEditorStore ).getSettings(); + }, [] ); + const settingsForBlock = get( settings, [ + '__experimentalStyles', + 'blocks', + blockName, + ] ); + const value = get( settingsForBlock, path ); + return useMemo( () => { + return getValueFromVariable( + settings.__experimentalFeatures, + blockName, + value + ); + }, [ settings.__experimentalFeatures, blockName, value ] ); +} diff --git a/packages/block-editor/src/hooks/border-color.js b/packages/block-editor/src/hooks/border-color.js index 036ff345a8ccdd..6833fb3afd2562 100644 --- a/packages/block-editor/src/hooks/border-color.js +++ b/packages/block-editor/src/hooks/border-color.js @@ -9,6 +9,7 @@ import classnames from 'classnames'; import { addFilter } from '@wordpress/hooks'; import { __ } from '@wordpress/i18n'; import { createHigherOrderComponent } from '@wordpress/compose'; +import { useState } from '@wordpress/element'; /** * Internal dependencies @@ -22,6 +23,7 @@ import { import useSetting from '../components/use-setting'; import { hasBorderSupport, shouldSkipSerialization } from './border'; import { cleanEmptyObject } from './utils'; +import useStyle from '../components/use-style'; // Defining empty array here instead of inline avoids unnecessary re-renders of // color control. @@ -49,7 +51,21 @@ export function BorderColorEdit( props ) { const disableCustomColors = ! useSetting( 'color.custom' ); const disableCustomGradients = ! useSetting( 'color.customGradient' ); + const { style: borderStyle } = style?.border || {}; + const defaultBorderStyle = useStyle( [ 'border', 'style' ] ); + const defaultBorderColor = useStyle( [ 'border', 'color' ] ); + + const [ colorValue, setColorValue ] = useState( + getColorObjectByAttributeValues( + colors, + borderColor, + style?.border?.color + )?.color + ); + const onChangeColor = ( value ) => { + setColorValue( value ); + const colorObject = getColorObjectByColorValue( colors, value ); const newStyle = { ...style, @@ -62,6 +78,15 @@ export function BorderColorEdit( props ) { // If empty slug, ensure undefined to remove attribute. const newNamedColor = colorObject?.slug ? colorObject.slug : undefined; + if ( value && borderStyle === undefined ) { + // If a border color is selected, make sure the style property is selected + // so that the user can get immediate visual feedback. Set style to the default + // style if it exists, or set it to solid. + newStyle.border.style = defaultBorderStyle + ? defaultBorderStyle + : 'solid'; + } + setAttributes( { style: cleanEmptyObject( newStyle ), borderColor: newNamedColor, @@ -71,7 +96,7 @@ export function BorderColorEdit( props ) { return ( { let newStyle = { ...style, @@ -36,6 +39,7 @@ export function BorderRadiusEdit( props ) { return ( ); diff --git a/packages/block-editor/src/hooks/border-style.js b/packages/block-editor/src/hooks/border-style.js index feaac4c694389a..dba904ce936a68 100644 --- a/packages/block-editor/src/hooks/border-style.js +++ b/packages/block-editor/src/hooks/border-style.js @@ -3,6 +3,7 @@ */ import BorderStyleControl from '../components/border-style-control'; import { cleanEmptyObject } from './utils'; +import useStyle from '../components/use-style'; /** * Inspector control for configuring border style property. @@ -17,6 +18,8 @@ export const BorderStyleEdit = ( props ) => { setAttributes, } = props; + const defaultBorderStyle = useStyle( [ 'border', 'style' ] ); + const onChange = ( newBorderStyle ) => { const newStyleAttributes = { ...style, @@ -31,7 +34,7 @@ export const BorderStyleEdit = ( props ) => { return ( ); diff --git a/packages/block-editor/src/hooks/border-width.js b/packages/block-editor/src/hooks/border-width.js index 4a08e240cef607..7f3f7cdc24f9bb 100644 --- a/packages/block-editor/src/hooks/border-width.js +++ b/packages/block-editor/src/hooks/border-width.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { + __experimentalParseUnit as parseUnit, __experimentalUnitControl as UnitControl, __experimentalUseCustomUnits as useCustomUnits, } from '@wordpress/components'; @@ -13,6 +14,7 @@ import { __ } from '@wordpress/i18n'; */ import { cleanEmptyObject } from './utils'; import useSetting from '../components/use-setting'; +import useStyle from '../components/use-style'; const MIN_BORDER_WIDTH = 0; @@ -34,6 +36,11 @@ export const BorderWidthEdit = ( props ) => { const [ styleSelection, setStyleSelection ] = useState(); const [ colorSelection, setColorSelection ] = useState(); + const defaultBorderStyle = useStyle( [ 'border', 'style' ] ); + const [ defaultBorderWidth ] = parseUnit( + useStyle( [ 'border', 'width' ] ) + ); + // Temporarily track previous border color & style selections to be able to // restore them when border width changes from zero value. useEffect( () => { @@ -81,6 +88,12 @@ export const BorderWidthEdit = ( props ) => { newStyle.border.style = styleSelection; } + if ( ! hasZeroWidth && borderStyle === undefined ) { + newStyle.border.style = defaultBorderStyle + ? defaultBorderStyle + : 'solid'; + } + // Restore previous border color selection if width is no longer zero // and current border color is undefined. if ( ! hasZeroWidth && borderColor === undefined ) { @@ -106,6 +119,7 @@ export const BorderWidthEdit = ( props ) => { return ( ); } diff --git a/packages/block-editor/src/utils/index.js b/packages/block-editor/src/utils/index.js index f498a6bf4740bb..498376b2d90fcb 100644 --- a/packages/block-editor/src/utils/index.js +++ b/packages/block-editor/src/utils/index.js @@ -1,3 +1,7 @@ export { default as transformStyles } from './transform-styles'; export * from './theme'; export * from './block-variation-transforms'; +export { + getValueFromVariable as __experimentalGetValueFromVariable, + getPresetVariableFromValue as __experimentalGetPresetVariableFromValue, +} from './style-variable-resolution'; diff --git a/packages/block-editor/src/utils/style-variable-resolution.js b/packages/block-editor/src/utils/style-variable-resolution.js new file mode 100644 index 00000000000000..c369b4becf182f --- /dev/null +++ b/packages/block-editor/src/utils/style-variable-resolution.js @@ -0,0 +1,188 @@ +/** + * External dependencies + */ +import { get, find, isString, kebabCase } from 'lodash'; + +/** + * WordPress dependencies + */ +import { __EXPERIMENTAL_PRESET_METADATA as PRESET_METADATA } from '@wordpress/blocks'; + +const STYLE_PROPERTIES_TO_CSS_VAR_INFIX = { + linkColor: 'color', + backgroundColor: 'color', + background: 'gradient', +}; + +function findInPresetsBy( + features, + blockName, + presetPath, + presetProperty, + presetValueValue +) { + // Block presets take priority above root level presets. + const orderedPresetsByOrigin = [ + get( features, [ 'blocks', blockName, ...presetPath ] ), + get( features, presetPath ), + ]; + for ( const presetByOrigin of orderedPresetsByOrigin ) { + if ( presetByOrigin ) { + // Preset origins ordered by priority. + const origins = [ 'user', 'theme', 'core' ]; + for ( const origin of origins ) { + const presets = presetByOrigin[ origin ]; + if ( presets ) { + const presetObject = find( + presets, + ( preset ) => + preset[ presetProperty ] === presetValueValue + ); + if ( presetObject ) { + if ( presetProperty === 'slug' ) { + return presetObject; + } + // if there is a highest priority preset with the same slug but different value the preset we found was overwritten and should be ignored. + const highestPresetObjectWithSameSlug = findInPresetsBy( + features, + blockName, + presetPath, + 'slug', + presetObject.slug + ); + if ( + highestPresetObjectWithSameSlug[ + presetProperty + ] === presetObject[ presetProperty ] + ) { + return presetObject; + } + return undefined; + } + } + } + } + } +} + +function getValueFromPresetVariable( + features, + blockName, + variable, + [ presetType, slug ] +) { + const metadata = find( PRESET_METADATA, [ 'cssVarInfix', presetType ] ); + if ( ! metadata ) { + return variable; + } + + const presetObject = findInPresetsBy( + features, + blockName, + metadata.path, + 'slug', + slug + ); + + if ( presetObject ) { + const { valueKey } = metadata; + const result = presetObject[ valueKey ]; + return getValueFromVariable( features, blockName, result ); + } + + return variable; +} + +function getValueFromCustomVariable( features, blockName, variable, path ) { + const result = + get( features, [ 'blocks', blockName, 'custom', ...path ] ) ?? + get( features, [ 'custom', ...path ] ); + if ( ! result ) { + return variable; + } + // A variable may reference another variable so we need recursion until we find the value. + return getValueFromVariable( features, blockName, result ); +} + +export function getValueFromVariable( features, blockName, variable ) { + if ( ! variable || ! isString( variable ) ) { + return variable; + } + const USER_VALUE_PREFIX = 'var:'; + const THEME_VALUE_PREFIX = 'var(--wp--'; + const THEME_VALUE_SUFFIX = ')'; + + let parsedVar; + + if ( variable.startsWith( USER_VALUE_PREFIX ) ) { + parsedVar = variable.slice( USER_VALUE_PREFIX.length ).split( '|' ); + } else if ( + variable.startsWith( THEME_VALUE_PREFIX ) && + variable.endsWith( THEME_VALUE_SUFFIX ) + ) { + parsedVar = variable + .slice( THEME_VALUE_PREFIX.length, -THEME_VALUE_SUFFIX.length ) + .split( '--' ); + } else { + // We don't know how to parse the value: either is raw of uses complex CSS such as `calc(1px * var(--wp--variable) )` + return variable; + } + + const [ type, ...path ] = parsedVar; + if ( type === 'preset' ) { + return getValueFromPresetVariable( + features, + blockName, + variable, + path + ); + } + if ( type === 'custom' ) { + return getValueFromCustomVariable( + features, + blockName, + variable, + path + ); + } + return variable; +} + +export function getPresetVariableFromValue( + features, + blockName, + presetPropertyName, + presetPropertyValue +) { + if ( ! presetPropertyValue ) { + return presetPropertyValue; + } + + const cssVarInfix = + STYLE_PROPERTIES_TO_CSS_VAR_INFIX[ presetPropertyName ] || + kebabCase( presetPropertyName ); + + const metadata = find( PRESET_METADATA, [ 'cssVarInfix', cssVarInfix ] ); + if ( ! metadata ) { + // The property doesn't have preset data + // so the value should be returned as it is. + return presetPropertyValue; + } + const { valueKey, path } = metadata; + + const presetObject = findInPresetsBy( + features, + blockName, + path, + valueKey, + presetPropertyValue + ); + + if ( ! presetObject ) { + // Value wasn't found in the presets, + // so it must be a custom value. + return presetPropertyValue; + } + + return `var:preset|${ cssVarInfix }|${ presetObject.slug }`; +} diff --git a/packages/block-library/src/group/block.json b/packages/block-library/src/group/block.json index 5e182cd0e9cba9..62f20f53e3b3e8 100644 --- a/packages/block-library/src/group/block.json +++ b/packages/block-library/src/group/block.json @@ -33,7 +33,12 @@ "color": true, "radius": true, "style": true, - "width": true + "width": true, + "__experimentalDefaultControls": { + "color": true, + "radius": true, + "width": true + } }, "__experimentalLayout": true }, diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js index 5564b339ec4a41..4a3c892fe7af3b 100644 --- a/packages/blocks/src/api/constants.js +++ b/packages/blocks/src/api/constants.js @@ -126,3 +126,45 @@ export const __EXPERIMENTAL_ELEMENTS = { h5: 'h5', h6: 'h6', }; + +export const __EXPERIMENTAL_PRESET_METADATA = [ + { + path: [ 'color', 'palette' ], + valueKey: 'color', + cssVarInfix: 'color', + classes: [ + { classSuffix: 'color', propertyName: 'color' }, + { + classSuffix: 'background-color', + propertyName: 'background-color', + }, + { + classSuffix: 'border-color', + propertyName: 'border-color', + }, + ], + }, + { + path: [ 'color', 'gradients' ], + valueKey: 'gradient', + cssVarInfix: 'gradient', + classes: [ + { + classSuffix: 'gradient-background', + propertyName: 'background', + }, + ], + }, + { + path: [ 'typography', 'fontSizes' ], + valueKey: 'size', + cssVarInfix: 'font-size', + classes: [ { classSuffix: 'font-size', propertyName: 'font-size' } ], + }, + { + path: [ 'typography', 'fontFamilies' ], + valueKey: 'fontFamily', + cssVarInfix: 'font-family', + classes: [], + }, +]; diff --git a/packages/blocks/src/api/index.js b/packages/blocks/src/api/index.js index 394fddaa5de6e3..fc22e6cebfa2ef 100644 --- a/packages/blocks/src/api/index.js +++ b/packages/blocks/src/api/index.js @@ -159,4 +159,5 @@ export { default as node } from './node'; export { __EXPERIMENTAL_STYLE_PROPERTY, __EXPERIMENTAL_ELEMENTS, + __EXPERIMENTAL_PRESET_METADATA, } from './constants'; diff --git a/packages/edit-site/src/components/editor/global-styles-provider.js b/packages/edit-site/src/components/editor/global-styles-provider.js index d85aecdf251bcc..181c4d9a2be452 100644 --- a/packages/edit-site/src/components/editor/global-styles-provider.js +++ b/packages/edit-site/src/components/editor/global-styles-provider.js @@ -16,10 +16,15 @@ import { import { __EXPERIMENTAL_STYLE_PROPERTY as STYLE_PROPERTY, __EXPERIMENTAL_ELEMENTS as ELEMENTS, + __EXPERIMENTAL_PRESET_METADATA as PRESET_METADATA, store as blocksStore, } from '@wordpress/blocks'; import { useEntityProp } from '@wordpress/core-data'; import { useSelect, useDispatch } from '@wordpress/data'; +import { + __experimentalGetValueFromVariable as getValueFromVariable, + __experimentalGetPresetVariableFromValue as getPresetVariableFromValue, +} from '@wordpress/block-editor'; /** * Internal dependencies @@ -28,9 +33,6 @@ import { ROOT_BLOCK_NAME, ROOT_BLOCK_SELECTOR, ROOT_BLOCK_SUPPORTS, - getValueFromVariable, - getPresetVariable, - PRESET_METADATA, } from './utils'; import { toCustomProperties, toStyles } from './global-styles-renderer'; import { store as editSiteStore } from '../../store'; @@ -256,7 +258,11 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { if ( origin === 'theme' ) { const value = get( themeStyles?.styles, path ); - return getValueFromVariable( themeStyles, context, value ); + return getValueFromVariable( + themeStyles.settings, + context, + value + ); } if ( origin === 'user' ) { @@ -265,11 +271,19 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { // We still need to use merged styles here because the // presets used to resolve user variable may be defined a // layer down ( core, theme, or user ). - return getValueFromVariable( mergedStyles, context, value ); + return getValueFromVariable( + mergedStyles.settings, + context, + value + ); } const value = get( mergedStyles?.styles, path ); - return getValueFromVariable( mergedStyles, context, value ); + return getValueFromVariable( + mergedStyles.settings, + context, + value + ); }, setStyle: ( context, propertyName, newValue ) => { const newContent = { ...userStyles }; @@ -288,8 +302,8 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { set( newStyles, propertyPath, - getPresetVariable( - mergedStyles, + getPresetVariableFromValue( + mergedStyles.settings, context, propertyName, newValue @@ -323,6 +337,7 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { }, ], __experimentalFeatures: mergedStyles.settings, + __experimentalStyles: mergedStyles.styles, } ); }, [ blocks, mergedStyles ] ); diff --git a/packages/edit-site/src/components/editor/global-styles-renderer.js b/packages/edit-site/src/components/editor/global-styles-renderer.js index fdec33c3fc0230..caa6b6fd744ee8 100644 --- a/packages/edit-site/src/components/editor/global-styles-renderer.js +++ b/packages/edit-site/src/components/editor/global-styles-renderer.js @@ -20,12 +20,13 @@ import { import { __EXPERIMENTAL_STYLE_PROPERTY as STYLE_PROPERTY, __EXPERIMENTAL_ELEMENTS as ELEMENTS, + __EXPERIMENTAL_PRESET_METADATA as PRESET_METADATA, } from '@wordpress/blocks'; /** * Internal dependencies */ -import { PRESET_METADATA, ROOT_BLOCK_SELECTOR } from './utils'; +import { ROOT_BLOCK_SELECTOR } from './utils'; function compileStyleValue( uncompiledValue ) { const VARIABLE_REFERENCE_PREFIX = 'var:'; diff --git a/packages/edit-site/src/components/editor/utils.js b/packages/edit-site/src/components/editor/utils.js index ba883f330ea264..49148154997824 100644 --- a/packages/edit-site/src/components/editor/utils.js +++ b/packages/edit-site/src/components/editor/utils.js @@ -1,11 +1,12 @@ /** * External dependencies */ -import { get, find, forEach, camelCase, isString } from 'lodash'; +import { get } from 'lodash'; /** * WordPress dependencies */ import { useSelect } from '@wordpress/data'; + /** * Internal dependencies */ @@ -28,69 +29,6 @@ export const ROOT_BLOCK_SUPPORTS = [ 'textTransform', ]; -export const PRESET_METADATA = [ - { - path: [ 'color', 'palette' ], - valueKey: 'color', - cssVarInfix: 'color', - classes: [ - { classSuffix: 'color', propertyName: 'color' }, - { - classSuffix: 'background-color', - propertyName: 'background-color', - }, - { - classSuffix: 'border-color', - propertyName: 'border-color', - }, - ], - }, - { - path: [ 'color', 'gradients' ], - valueKey: 'gradient', - cssVarInfix: 'gradient', - classes: [ - { - classSuffix: 'gradient-background', - propertyName: 'background', - }, - ], - }, - { - path: [ 'typography', 'fontSizes' ], - valueKey: 'size', - cssVarInfix: 'font-size', - classes: [ { classSuffix: 'font-size', propertyName: 'font-size' } ], - }, - { - path: [ 'typography', 'fontFamilies' ], - valueKey: 'fontFamily', - cssVarInfix: 'font-family', - classes: [], - }, -]; - -const STYLE_PROPERTIES_TO_CSS_VAR_INFIX = { - linkColor: 'color', - backgroundColor: 'color', - background: 'gradient', -}; - -function getPresetMetadataFromStyleProperty( styleProperty ) { - if ( ! getPresetMetadataFromStyleProperty.MAP ) { - getPresetMetadataFromStyleProperty.MAP = {}; - PRESET_METADATA.forEach( ( { cssVarInfix }, index ) => { - getPresetMetadataFromStyleProperty.MAP[ camelCase( cssVarInfix ) ] = - PRESET_METADATA[ index ]; - } ); - forEach( STYLE_PROPERTIES_TO_CSS_VAR_INFIX, ( value, key ) => { - getPresetMetadataFromStyleProperty.MAP[ key ] = - getPresetMetadataFromStyleProperty.MAP[ value ]; - } ); - } - return getPresetMetadataFromStyleProperty.MAP[ styleProperty ]; -} - const PATHS_WITH_MERGE = { 'color.gradients': true, 'color.palette': true, @@ -110,159 +48,3 @@ export function useSetting( path, blockName = '' ) { } return result; } - -function findInPresetsBy( - styles, - context, - presetPath, - presetProperty, - presetValueValue -) { - // Block presets take priority above root level presets. - const orderedPresetsByOrigin = [ - get( styles, [ 'settings', 'blocks', context, ...presetPath ] ), - get( styles, [ 'settings', ...presetPath ] ), - ]; - for ( const presetByOrigin of orderedPresetsByOrigin ) { - if ( presetByOrigin ) { - // Preset origins ordered by priority. - const origins = [ 'user', 'theme', 'core' ]; - for ( const origin of origins ) { - const presets = presetByOrigin[ origin ]; - if ( presets ) { - const presetObject = find( - presets, - ( preset ) => - preset[ presetProperty ] === presetValueValue - ); - if ( presetObject ) { - if ( presetProperty === 'slug' ) { - return presetObject; - } - // if there is a highest priority preset with the same slug but different value the preset we found was overwritten and should be ignored. - const highestPresetObjectWithSameSlug = findInPresetsBy( - styles, - context, - presetPath, - 'slug', - presetObject.slug - ); - if ( - highestPresetObjectWithSameSlug[ - presetProperty - ] === presetObject[ presetProperty ] - ) { - return presetObject; - } - return undefined; - } - } - } - } - } -} - -export function getPresetVariable( styles, context, propertyName, value ) { - if ( ! value ) { - return value; - } - - const metadata = getPresetMetadataFromStyleProperty( propertyName ); - if ( ! metadata ) { - // The property doesn't have preset data - // so the value should be returned as it is. - return value; - } - const { valueKey, path, cssVarInfix } = metadata; - - const presetObject = findInPresetsBy( - styles, - context, - path, - valueKey, - value - ); - - if ( ! presetObject ) { - // Value wasn't found in the presets, - // so it must be a custom value. - return value; - } - - return `var:preset|${ cssVarInfix }|${ presetObject.slug }`; -} - -function getValueFromPresetVariable( - styles, - blockName, - variable, - [ presetType, slug ] -) { - presetType = camelCase( presetType ); - const metadata = getPresetMetadataFromStyleProperty( presetType ); - if ( ! metadata ) { - return variable; - } - - const presetObject = findInPresetsBy( - styles, - blockName, - metadata.path, - 'slug', - slug - ); - - if ( presetObject ) { - const { valueKey } = metadata; - const result = presetObject[ valueKey ]; - return getValueFromVariable( styles, blockName, result ); - } - - return variable; -} - -function getValueFromCustomVariable( styles, blockName, variable, path ) { - const result = - get( styles, [ 'settings', 'blocks', blockName, 'custom', ...path ] ) ?? - get( styles, [ 'settings', 'custom', ...path ] ); - if ( ! result ) { - return variable; - } - // A variable may reference another variable so we need recursion until we find the value. - return getValueFromVariable( styles, blockName, result ); -} - -export function getValueFromVariable( styles, blockName, variable ) { - if ( ! variable || ! isString( variable ) ) { - return variable; - } - - let parsedVar; - const INTERNAL_REFERENCE_PREFIX = 'var:'; - const CSS_REFERENCE_PREFIX = 'var(--wp--'; - const CSS_REFERENCE_SUFFIX = ')'; - if ( variable.startsWith( INTERNAL_REFERENCE_PREFIX ) ) { - parsedVar = variable - .slice( INTERNAL_REFERENCE_PREFIX.length ) - .split( '|' ); - } else if ( - variable.startsWith( CSS_REFERENCE_PREFIX ) && - variable.endsWith( CSS_REFERENCE_SUFFIX ) - ) { - parsedVar = variable - .slice( CSS_REFERENCE_PREFIX.length, -CSS_REFERENCE_SUFFIX.length ) - .split( '--' ); - } else { - // Value is raw. - return variable; - } - - const [ type, ...path ] = parsedVar; - if ( type === 'preset' ) { - return getValueFromPresetVariable( styles, blockName, variable, path ); - } - if ( type === 'custom' ) { - return getValueFromCustomVariable( styles, blockName, variable, path ); - } - return variable; -} diff --git a/packages/edit-site/src/components/sidebar/border-panel.js b/packages/edit-site/src/components/sidebar/border-panel.js index e7d5c801ff9355..a9af374e9b1f32 100644 --- a/packages/edit-site/src/components/sidebar/border-panel.js +++ b/packages/edit-site/src/components/sidebar/border-panel.js @@ -123,7 +123,7 @@ export default function BorderPanel( { { hasBorderColor && (