Skip to content

Commit

Permalink
Add: API to allow blocks to access global styles.
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta committed Aug 19, 2021
1 parent ab1380c commit 5cba6cb
Show file tree
Hide file tree
Showing 14 changed files with 318 additions and 235 deletions.
2 changes: 1 addition & 1 deletion lib/class-wp-rest-block-editor-settings-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
4 changes: 1 addition & 3 deletions lib/global-styles.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ function_exists( 'gutenberg_is_edit_site_page' ) &&
}
$consolidated = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( $settings, $origin );

if ( 'mobile' === $context ) {
$settings['__experimentalStyles'] = $consolidated->get_raw_data()['styles'];
}
$settings['__experimentalStyles'] = $consolidated->get_raw_data()['styles'];

if ( 'site-editor' === $context ) {
$theme = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( $settings, 'theme' );
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,4 @@ export { default as __experimentalUseNoRecursiveRenders } from './use-no-recursi
export { default as BlockEditorProvider } from './provider';
export { default as __experimentalUseSimulatedMediaQuery } from './use-simulated-media-query';
export { default as useSetting } from './use-setting';
export { default as __experimentalUseStyle } from './use-style';
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) => {
Expand Down Expand Up @@ -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 }
Expand Down
52 changes: 52 additions & 0 deletions packages/block-editor/src/components/use-style/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* External dependencies
*/
import { get } from 'lodash';

/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { useBlockEditContext } from '../block-edit';
import { store as blockEditorStore } from '../../store';
import { getResolvedStyleVariable } 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 setting = useSelect(
( select ) => {
const settings = select( blockEditorStore ).getSettings();
const settingsForBlock = get( settings, [
'__experimentalStyles',
'blocks',
blockName,
] );
return getResolvedStyleVariable(
settings.__experimentalFeatures,
blockName,
get( settingsForBlock, path )
);
},
[ blockName, path ]
);

return setting;
}
3 changes: 3 additions & 0 deletions packages/block-editor/src/hooks/line-height.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { hasBlockSupport } from '@wordpress/blocks';
import LineHeightControl from '../components/line-height-control';
import { cleanEmptyObject } from './utils';
import useSetting from '../components/use-setting';
import useStyle from '../components/use-style';

export const LINE_HEIGHT_SUPPORT_KEY = 'typography.lineHeight';

Expand All @@ -24,6 +25,7 @@ export function LineHeightEdit( props ) {
attributes: { style },
} = props;
const isDisabled = useIsLineHeightDisabled( props );
const defaultLineHeight = useStyle( [ 'typography', 'lineHeight' ] );

if ( isDisabled ) {
return null;
Expand All @@ -45,6 +47,7 @@ export function LineHeightEdit( props ) {
<LineHeightControl
value={ style?.typography?.lineHeight }
onChange={ onChange }
placeholder={ defaultLineHeight }
/>
);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/block-editor/src/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export { default as transformStyles } from './transform-styles';
export * from './theme';
export * from './block-variation-transforms';
export {
getResolvedStyleVariable as __experimentalGetResolvedStyleVariable,
getPresetVariableRepresentingAValue as __experimentalGetPresetVariableRepresentingAValue,
} from './style-variable-resolution';
180 changes: 180 additions & 0 deletions packages/block-editor/src/utils/style-variable-resolution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/**
* 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,
context,
presetPath,
presetProperty,
presetValueValue
) {
// Block presets take priority above root level presets.
const orderedPresetsByOrigin = [
get( features, [ 'blocks', context, ...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,
context,
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 getResolvedStyleVariable( 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 getResolvedStyleVariable( features, blockName, result );
}

export function getResolvedStyleVariable( features, context, variable ) {
if ( ! variable || ! isString( variable ) ) {
return variable;
}
const INTERNAL_REFERENCE_PREFIX = 'var:';
const CSS_REFERENCE_PREFIX = 'var(--wp--';
const CSS_REFERENCE_SUFFIX = ')';

let parsedVar;

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( features, context, variable, path );
}
if ( type === 'custom' ) {
return getValueFromCustomVariable( features, context, variable, path );
}
return variable;
}

export function getPresetVariableRepresentingAValue(
features,
context,
propertyName,
value
) {
if ( ! value ) {
return value;
}

const cssVarInfix =
STYLE_PROPERTIES_TO_CSS_VAR_INFIX[ propertyName ] ||
kebabCase( propertyName );

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 value;
}
const { valueKey, path } = metadata;

const presetObject = findInPresetsBy(
features,
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 }`;
}
42 changes: 42 additions & 0 deletions packages/blocks/src/api/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,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: [],
},
];
1 change: 1 addition & 0 deletions packages/blocks/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,5 @@ export { default as node } from './node';
export {
__EXPERIMENTAL_STYLE_PROPERTY,
__EXPERIMENTAL_ELEMENTS,
__EXPERIMENTAL_PRESET_METADATA,
} from './constants';
Loading

0 comments on commit 5cba6cb

Please sign in to comment.