Skip to content

Commit

Permalink
Client: adapt to new shape
Browse files Browse the repository at this point in the history
  • Loading branch information
oandregal committed May 4, 2021
1 parent f93fa2e commit 1b03c7a
Show file tree
Hide file tree
Showing 9 changed files with 718 additions and 260 deletions.
42 changes: 6 additions & 36 deletions packages/block-editor/src/components/use-editor-feature/index.js
Original file line number Diff line number Diff line change
@@ -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';

/**
Expand Down Expand Up @@ -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.
Expand All @@ -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 ) {
Expand All @@ -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;
Expand Down
3 changes: 0 additions & 3 deletions packages/block-library/src/common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
// Gradients
@include gradient-colors();

.has-link-color a:not(.wp-block-button__link) {
color: var(--wp--style--color--link, #00e);
}
}

// Font sizes.
Expand Down
1 change: 1 addition & 0 deletions packages/blocks/src/api/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const DEPRECATED_ENTRY_KEYS = [

export const __EXPERIMENTAL_STYLE_PROPERTY = {
'--wp--style--color--link': {
valueGlobal: [ 'elements', 'link', 'color', 'text' ],
value: [ 'color', 'link' ],
support: [ 'color', 'link' ],
},
Expand Down
182 changes: 99 additions & 83 deletions packages/edit-site/src/components/editor/global-styles-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,17 @@ import { useSelect, useDispatch } from '@wordpress/data';
* Internal dependencies
*/
import {
ALL_BLOCKS_NAME,
ALL_BLOCKS_SELECTOR,
ELEMENTS,
ROOT_BLOCK_NAME,
ROOT_BLOCK_SELECTOR,
ROOT_BLOCK_SUPPORTS,
getValueFromVariable,
getPresetVariable,
} from './utils';
import getGlobalStyles from './global-styles-renderer';
import { toCustomProperties, toStyles } 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( {
Expand Down Expand Up @@ -82,47 +81,36 @@ const extractSupportKeys = ( supports ) => {
return supportKeys;
};

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
},
};

// Add contexts from block metadata.
const getBlockMetadata = ( blockTypes ) => {
const result = {};

blockTypes.forEach( ( blockType ) => {
const blockName = blockType.name;
const blockSelector = blockType?.supports?.__experimentalSelector;
const name = blockType.name;
const supports = extractSupportKeys( blockType?.supports );
const hasSupport = supports.length > 0;

if ( hasSupport && typeof blockSelector === 'string' ) {
result[ blockName ] = {
selector: blockSelector,
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,
};
if ( hasSupport ) {
const selector =
blockType?.supports?.__experimentalSelector ??
'.wp-block-' + name.replace( 'core/', '' ).replace( '/', '-' );

const blockSelectors = selector.split( ',' );
const elements = [];
Object.keys( ELEMENTS ).forEach( ( key ) => {
const elementSelector = [];
blockSelectors.forEach( ( blockSelector ) => {
elementSelector.push(
blockSelector + ' ' + ELEMENTS[ key ]
);
} );
elements[ key ] = elementSelector.join( ',' );
} );
} else if ( hasSupport ) {
const suffix = blockName.replace( 'core/', '' ).replace( '/', '-' );
result[ blockName ] = {
selector: '.wp-block-' + suffix,

result[ name ] = {
name,
selector,
supports,
blockName,
elements,
};
}
} );
Expand All @@ -140,13 +128,21 @@ export default function GlobalStylesProvider( { children, baseStyles } ) {
} );
const { updateSettings } = useDispatch( editSiteStore );

const contexts = useMemo( () => getContexts( blockTypes ), [ blockTypes ] );
const blocks = useMemo( () => getBlockMetadata( blockTypes ), [
blockTypes,
] );

const { __experimentalGlobalStylesBaseStyles: themeStyles } = settings;
const { userStyles, mergedStyles } = useMemo( () => {
let newUserStyles;
try {
newUserStyles = content ? JSON.parse( content ) : EMPTY_CONTENT;

// At the moment, we ignore previous user config that
// is in a different version than the theme config.
if ( newUserStyles?.version !== baseStyles?.version ) {
newUserStyles = EMPTY_CONTENT;
}
} catch ( e ) {
/* eslint-disable no-console */
console.error( 'User data is not JSON' );
Expand All @@ -160,9 +156,9 @@ export default function GlobalStylesProvider( { children, baseStyles } ) {
if ( ! newUserStyles.isGlobalStylesUserThemeJSON ) {
newUserStyles = EMPTY_CONTENT;
}
// TODO: we probably want to check here that the shape is what we want
// This is, settings & styles are top-level keys, or perhaps a version.
// As to avoid merging trees that are different.

// At this point, the version schema of the theme & user
// is the same, so we can merge them.
const newMergedStyles = mergeWith(
{},
baseStyles,
Expand All @@ -178,98 +174,118 @@ export default function GlobalStylesProvider( { children, baseStyles } ) {

const nextValue = useMemo(
() => ( {
contexts,
getSetting: ( context, path ) =>
get( userStyles?.settings?.[ context ], path ),
setSetting: ( context, path, newValue ) => {
root: {
name: ROOT_BLOCK_NAME,
selector: ROOT_BLOCK_SELECTOR,
supports: ROOT_BLOCK_SUPPORTS,
elements: ELEMENTS,
},
blocks,
getSetting: ( context, propertyPath ) => {
const path =
context === ROOT_BLOCK_NAME
? propertyPath
: [ 'blocks', context, ...propertyPath ];
get( userStyles?.settings, path );
},
setSetting: ( context, propertyPath, newValue ) => {
const newContent = { ...userStyles };
let contextSettings = newContent?.settings?.[ context ];
if ( ! contextSettings ) {
contextSettings = {};
set( newContent, [ 'settings', context ], contextSettings );
const path =
context === ROOT_BLOCK_NAME
? [ 'settings' ]
: [ 'settings', 'blocks', context ];

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' ) => {
const propertyPath =
STYLE_PROPERTY[ propertyName ].valueGlobal ??
STYLE_PROPERTY[ propertyName ].value;
const path =
context === ROOT_BLOCK_NAME
? propertyPath
: [ 'blocks', context, ...propertyPath ];

if ( origin === 'theme' ) {
const value = get(
themeStyles?.styles?.[ context ],
STYLE_PROPERTY[ propertyName ].value
);
const value = get( themeStyles?.styles, path );
return getValueFromVariable( themeStyles, context, value );
}

if ( origin === 'user' ) {
const value = get(
userStyles?.styles?.[ context ],
STYLE_PROPERTY[ propertyName ].value
);
const value = get( userStyles?.styles, path );

// 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 );
}

const value = get(
mergedStyles?.styles?.[ context ],
STYLE_PROPERTY[ propertyName ].value
);
const value = get( mergedStyles?.styles, path );
return getValueFromVariable( mergedStyles, context, value );
},
setStyle: ( context, propertyName, newValue ) => {
const newContent = { ...userStyles };
let contextStyles = newContent?.styles?.[ context ];
if ( ! contextStyles ) {
contextStyles = {};
set( newContent, [ 'styles', context ], contextStyles );

const path =
ROOT_BLOCK_NAME === context
? [ 'styles' ]
: [ 'styles', 'blocks', context ];
const propertyPath =
STYLE_PROPERTY[ propertyName ].valueGlobal ??
STYLE_PROPERTY[ propertyName ].value;

let newStyles = get( newContent, path );
if ( ! newStyles ) {
newStyles = {};
set( newContent, path, newStyles );
}
set(
contextStyles,
STYLE_PROPERTY[ propertyName ].value,
newStyles,
propertyPath,
getPresetVariable(
mergedStyles,
context,
propertyName,
newValue
)
);

setContent( JSON.stringify( newContent ) );
},
} ),
[ content, mergedStyles, themeStyles ]
);

useEffect( () => {
const newStyles = settings.styles.filter(
const nonGlobalStyles = settings.styles.filter(
( style ) => ! style.isGlobalStyles
);
const customProperties = toCustomProperties( mergedStyles, blocks );
const globalStyles = toStyles( mergedStyles, blocks );
updateSettings( {
...settings,
styles: [
...newStyles,
...nonGlobalStyles,
{
css: getGlobalStyles(
contexts,
mergedStyles,
'cssVariables'
),
css: customProperties,
isGlobalStyles: true,
__experimentalNoWrapper: true,
},
{
css: getGlobalStyles(
contexts,
mergedStyles,
'blockStyles'
),
css: globalStyles,
isGlobalStyles: true,
},
],
__experimentalFeatures: mergedStyles.settings,
} );
}, [ contexts, mergedStyles ] );
}, [ blocks, mergedStyles ] );

return (
<GlobalStylesContext.Provider value={ nextValue }>
Expand Down
Loading

0 comments on commit 1b03c7a

Please sign in to comment.