diff --git a/packages/block-editor/src/components/use-editor-feature/index.js b/packages/block-editor/src/components/use-editor-feature/index.js index 81ab094ec7f6c..1065859edc910 100644 --- a/packages/block-editor/src/components/use-editor-feature/index.js +++ b/packages/block-editor/src/components/use-editor-feature/index.js @@ -1,12 +1,11 @@ /** * External dependencies */ -import { get, isObject } from 'lodash'; +import { get } from 'lodash'; /** * WordPress dependencies */ -import { store as blocksStore } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; /** @@ -50,15 +49,6 @@ const deprecatedFlags = { 'spacing.customPadding': ( settings ) => settings.enableCustomSpacing, }; -function blockAttributesMatch( blockAttributes, attributes ) { - for ( const attribute in attributes ) { - if ( attributes[ attribute ] !== blockAttributes[ attribute ] ) { - return false; - } - } - return true; -} - /** * Hook that retrieves the setting for the given editor feature. * It works with nested objects using by finding the value at path. @@ -73,36 +63,16 @@ function blockAttributesMatch( blockAttributes, attributes ) { * ``` */ export default function useEditorFeature( featurePath ) { - const { name: blockName, clientId } = useBlockEditContext(); + const { name: blockName } = useBlockEditContext(); const setting = useSelect( ( select ) => { - const { getBlockAttributes, getSettings } = select( - blockEditorStore - ); - const settings = getSettings(); - const blockType = select( blocksStore ).getBlockType( blockName ); - - let context = blockName; - const selectors = get( blockType, [ - 'supports', - '__experimentalSelector', - ] ); - if ( clientId && isObject( selectors ) ) { - const blockAttributes = getBlockAttributes( clientId ) || {}; - for ( const contextSelector in selectors ) { - const { attributes } = selectors[ contextSelector ]; - if ( blockAttributesMatch( blockAttributes, attributes ) ) { - context = contextSelector; - break; - } - } - } + const settings = select( blockEditorStore ).getSettings(); // 1 - Use __experimental features, if available. // We cascade to the all value if the block one is not available. - const defaultsPath = `__experimentalFeatures.defaults.${ featurePath }`; - const blockPath = `__experimentalFeatures.${ context }.${ featurePath }`; + const defaultsPath = `__experimentalFeatures.${ featurePath }`; + const blockPath = `__experimentalFeatures.blocks.${ blockName }.${ featurePath }`; const experimentalFeaturesResult = get( settings, blockPath ) ?? get( settings, defaultsPath ); if ( experimentalFeaturesResult !== undefined ) { @@ -123,7 +93,7 @@ export default function useEditorFeature( featurePath ) { // To remove when __experimentalFeatures are ported to core. return featurePath === 'typography.dropCap' ? true : undefined; }, - [ blockName, clientId, featurePath ] + [ blockName, featurePath ] ); return setting; 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 bba4af1ea54b8..f1d40b83821c5 100644 --- a/packages/edit-site/src/components/editor/global-styles-provider.js +++ b/packages/edit-site/src/components/editor/global-styles-provider.js @@ -24,8 +24,6 @@ import { useSelect, useDispatch } from '@wordpress/data'; * Internal dependencies */ import { - ALL_BLOCKS_NAME, - ALL_BLOCKS_SELECTOR, ROOT_BLOCK_NAME, ROOT_BLOCK_SELECTOR, ROOT_BLOCK_SUPPORTS, @@ -35,7 +33,7 @@ import { import getGlobalStyles from './global-styles-renderer'; import { store as editSiteStore } from '../../store'; -const EMPTY_CONTENT = { isGlobalStylesUserThemeJSON: true }; +const EMPTY_CONTENT = { isGlobalStylesUserThemeJSON: true, version: 1 }; const EMPTY_CONTENT_STRING = JSON.stringify( EMPTY_CONTENT ); const GlobalStylesContext = createContext( { @@ -83,16 +81,7 @@ const extractSupportKeys = ( supports ) => { }; const getContexts = ( blockTypes ) => { - const result = { - [ ROOT_BLOCK_NAME ]: { - selector: ROOT_BLOCK_SELECTOR, - supports: ROOT_BLOCK_SUPPORTS, - }, - [ ALL_BLOCKS_NAME ]: { - selector: ALL_BLOCKS_SELECTOR, - supports: [], // by being an empty array, the styles subtree will be ignored - }, - }; + const result = {}; // Add contexts from block metadata. blockTypes.forEach( ( blockType ) => { @@ -107,16 +96,6 @@ const getContexts = ( blockTypes ) => { supports, blockName, }; - } else if ( hasSupport && typeof blockSelector === 'object' ) { - Object.keys( blockSelector ).forEach( ( key ) => { - result[ key ] = { - selector: blockSelector[ key ].selector, - supports, - blockName, - title: blockSelector[ key ].title, - attributes: blockSelector[ key ].attributes, - }; - } ); } else if ( hasSupport ) { const suffix = blockName.replace( 'core/', '' ).replace( '/', '-' ); result[ blockName ] = { @@ -145,6 +124,8 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { const { userStyles, mergedStyles } = useMemo( () => { let newUserStyles; try { + // TODO: IF USER STYLES AREN'T IN THE LAST VERSION + // WE SHOULD MIGRATE THEM. newUserStyles = content ? JSON.parse( content ) : EMPTY_CONTENT; } catch ( e ) { /* eslint-disable no-console */ @@ -177,42 +158,65 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { const nextValue = useMemo( () => ( { + root: { + selector: ROOT_BLOCK_SELECTOR, + supports: ROOT_BLOCK_SUPPORTS, + name: ROOT_BLOCK_NAME, + }, contexts, - getSetting: ( context, path ) => - get( userStyles?.settings?.[ context ], path ), - setSetting: ( context, path, newValue ) => { + getSetting: ( blockName, propertyPath ) => { + const path = + blockName === ROOT_BLOCK_NAME + ? propertyPath + : [ 'blocks', blockName, ...propertyPath ]; + get( userStyles?.settings, path ); + }, + setSetting: ( blockName, propertyPath, newValue ) => { const newContent = { ...userStyles }; - let contextSettings = newContent?.settings?.[ context ]; - if ( ! contextSettings ) { - contextSettings = {}; - set( newContent, [ 'settings', context ], contextSettings ); + const path = + blockName === ROOT_BLOCK_NAME + ? [ 'settings' ] + : [ 'settings', 'blocks', blockName ]; + + let newSettings = get( newContent, path ); + if ( ! newSettings ) { + newSettings = {}; + set( newContent, path, newSettings ); } - set( contextSettings, path, newValue ); + set( newSettings, propertyPath, newValue ); + setContent( JSON.stringify( newContent ) ); }, - getStyle: ( context, propertyName, origin = 'merged' ) => { + getStyle: ( blockName, propertyName, origin = 'merged' ) => { const styleOrigin = 'user' === origin ? userStyles : mergedStyles; - const value = get( - styleOrigin?.styles?.[ context ], - STYLE_PROPERTY[ propertyName ].value - ); - return getValueFromVariable( mergedStyles, context, value ); + const propertyPath = STYLE_PROPERTY[ propertyName ].value; + const path = + blockName === ROOT_BLOCK_NAME + ? propertyPath + : [ 'blocks', blockName, ...propertyPath ]; + + const value = get( styleOrigin?.styles, path ); + return getValueFromVariable( mergedStyles, blockName, value ); }, - setStyle: ( context, propertyName, newValue ) => { + setStyle: ( blockName, propertyName, newValue ) => { const newContent = { ...userStyles }; - let contextStyles = newContent?.styles?.[ context ]; - if ( ! contextStyles ) { - contextStyles = {}; - set( newContent, [ 'styles', context ], contextStyles ); + const path = + ROOT_BLOCK_NAME === blockName + ? [ 'styles' ] + : [ 'styles', 'blocks', blockName ]; + let newStyles = get( newContent, path ); + if ( ! newStyles ) { + newStyles = {}; + set( newContent, path, newStyles ); } set( - contextStyles, + newStyles, STYLE_PROPERTY[ propertyName ].value, getPresetVariable( mergedStyles, - context, + path, propertyName, newValue ) 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 b8bbc57cfe1ed..59a001bd5c8f8 100644 --- a/packages/edit-site/src/components/editor/global-styles-renderer.js +++ b/packages/edit-site/src/components/editor/global-styles-renderer.js @@ -11,7 +11,11 @@ import { __EXPERIMENTAL_STYLE_PROPERTY as STYLE_PROPERTY } from '@wordpress/bloc /** * Internal dependencies */ -import { LINK_COLOR_DECLARATION, PRESET_METADATA } from './utils'; +import { + LINK_COLOR_DECLARATION, + PRESET_METADATA, + ROOT_BLOCK_SELECTOR, +} from './utils'; function compileStyleValue( uncompiledValue ) { const VARIABLE_REFERENCE_PREFIX = 'var:'; @@ -141,56 +145,86 @@ function getBlockStylesDeclarations( blockStyles = {} ) { } export default ( blockData, tree, type = 'all' ) => { + // Can this be converted to a context, as the global context? + // See comment in the server. + const styles = + type === 'all' || type === 'blockStyles' + ? [ LINK_COLOR_DECLARATION ] + : []; + + // Process top-level. + if ( type === 'all' || type === 'cssVariables' ) { + const declarations = [ + ...getBlockPresetsDeclarations( tree?.settings ), + ...flattenTree( tree?.settings?.custom, '--wp--custom--', '--' ), + ]; + if ( declarations.length > 0 ) { + styles.push( + `${ ROOT_BLOCK_SELECTOR } { ${ declarations.join( ';' ) } }` + ); + } + } + + if ( type === 'all' || type === 'blockStyles' ) { + const declarations = getBlockStylesDeclarations( tree?.styles ); + if ( declarations.length > 0 ) { + styles.push( + `${ ROOT_BLOCK_SELECTOR } { ${ declarations.join( ';' ) } }` + ); + } + + const presetClasses = getBlockPresetClasses( + ROOT_BLOCK_SELECTOR, + tree?.settings + ); + if ( presetClasses ) { + styles.push( presetClasses ); + } + } + + // Process blocks. return reduce( blockData, - ( styles, { selector }, context ) => { + ( accumulator, { blockName, selector } ) => { if ( type === 'all' || type === 'cssVariables' ) { - const variableDeclarations = [ + const declarations = [ ...getBlockPresetsDeclarations( - tree?.settings?.[ context ] + tree?.settings?.blocks?.[ blockName ] ), ...flattenTree( - tree?.settings?.[ context ]?.custom, + tree?.settings?.blocks?.[ blockName ]?.custom, '--wp--custom--', '--' ), ]; - if ( variableDeclarations.length > 0 ) { - styles.push( - `${ selector } { ${ variableDeclarations.join( - ';' - ) } }` + if ( declarations.length > 0 ) { + accumulator.push( + `${ selector } { ${ declarations.join( ';' ) } }` ); } } if ( type === 'all' || type === 'blockStyles' ) { - const blockStyleDeclarations = getBlockStylesDeclarations( - tree?.styles?.[ context ] + const declarations = getBlockStylesDeclarations( + tree?.styles?.blocks?.[ blockName ] ); - if ( blockStyleDeclarations.length > 0 ) { - styles.push( - `${ selector } { ${ blockStyleDeclarations.join( - ';' - ) } }` + if ( declarations.length > 0 ) { + accumulator.push( + `${ selector } { ${ declarations.join( ';' ) } }` ); } const presetClasses = getBlockPresetClasses( selector, - tree?.settings?.[ context ] + tree?.settings?.blocks?.[ blockName ] ); if ( presetClasses ) { - styles.push( presetClasses ); + accumulator.push( presetClasses ); } } - return styles; + return accumulator; }, - // Can this be converted to a context, as the global context? - // See comment in the server. - type === 'all' || type === 'blockStyles' - ? [ LINK_COLOR_DECLARATION ] - : [] + styles ).join( '' ); }; diff --git a/packages/edit-site/src/components/editor/utils.js b/packages/edit-site/src/components/editor/utils.js index 4c08feac99b32..5503c183105e3 100644 --- a/packages/edit-site/src/components/editor/utils.js +++ b/packages/edit-site/src/components/editor/utils.js @@ -92,23 +92,16 @@ function getPresetMetadataFromStyleProperty( styleProperty ) { export const LINK_COLOR = '--wp--style--color--link'; export const LINK_COLOR_DECLARATION = `a { color: var(${ LINK_COLOR }, #00e); }`; -export function useEditorFeature( featurePath, blockName = ALL_BLOCKS_NAME ) { +export function useEditorFeature( featurePath, blockName = '' ) { const settings = useSelect( ( select ) => { return select( editSiteStore ).getSettings(); } ); - return ( - get( - settings, - `__experimentalFeatures.${ blockName }.${ featurePath }` - ) ?? - get( - settings, - `__experimentalFeatures.${ ALL_BLOCKS_NAME }.${ featurePath }` - ) - ); + const topLevelPath = `__experimentalFeatures.${ featurePath }`; + const blockPath = `__experimentalFeatures.blocks.${ blockName }.${ featurePath }`; + return get( settings, blockPath ) ?? get( settings, topLevelPath ); } -export function getPresetVariable( styles, blockName, propertyName, value ) { +export function getPresetVariable( styles, stylePath, propertyName, value ) { if ( ! value ) { return value; } @@ -117,9 +110,7 @@ export function getPresetVariable( styles, blockName, propertyName, value ) { return value; } const { valueKey, path, cssVarInfix } = presetData; - const presets = - get( styles, [ blockName, ...path ] ) ?? - get( styles, [ ALL_BLOCKS_NAME, ...path ] ); + const presets = get( styles, [ ...stylePath, ...path ] ); const presetObject = find( presets, ( preset ) => { return preset[ valueKey ] === value; } ); diff --git a/packages/edit-site/src/components/sidebar/global-styles-sidebar.js b/packages/edit-site/src/components/sidebar/global-styles-sidebar.js index f0017eb703d05..15293c420a692 100644 --- a/packages/edit-site/src/components/sidebar/global-styles-sidebar.js +++ b/packages/edit-site/src/components/sidebar/global-styles-sidebar.js @@ -169,6 +169,7 @@ export default function GlobalStylesSidebar( { closeLabel, } ) { const { + root, contexts, getStyle, setStyle, @@ -177,7 +178,7 @@ export default function GlobalStylesSidebar( { } = useGlobalStylesContext(); const [ canRestart, onReset ] = useGlobalStylesReset(); - if ( typeof contexts !== 'object' || ! contexts?.[ ROOT_BLOCK_NAME ] ) { + if ( typeof contexts !== 'object' || ! root ) { // No sidebar is shown. return null; } @@ -226,10 +227,7 @@ export default function GlobalStylesSidebar( { return (