From 30e1f1ff96d430462b1c86775b34ba4cc9bd19c6 Mon Sep 17 00:00:00 2001 From: Jorge Date: Wed, 5 May 2021 22:48:48 +0100 Subject: [PATCH] Add link color as an element mechanism. --- lib/block-supports/elements.php | 60 ++++++++++++ lib/load.php | 1 + packages/block-editor/src/hooks/color.js | 28 +++--- packages/block-editor/src/hooks/style.js | 92 ++++++++++++++++++- packages/blocks/src/api/constants.js | 4 + .../edit-site/src/components/editor/utils.js | 2 +- .../src/components/sidebar/color-panel.js | 24 ++--- 7 files changed, 180 insertions(+), 31 deletions(-) create mode 100644 lib/block-supports/elements.php diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php new file mode 100644 index 00000000000000..1023153f05059d --- /dev/null +++ b/lib/block-supports/elements.php @@ -0,0 +1,60 @@ +get_registered( $block['blockName'] ); + $link_color = _wp_array_get( $block['attrs'], array( 'style', 'elements', 'link', 'color', 'text' ), null ); + + /* + * For now we only care about link color. + * This code in the future when we have a public API + * should take advantage of WP_Theme_JSON::compute_style_properties + * and work for any element and style. + */ + if ( null === $link_color ) { + return $block_content; + } + $class_name = 'wp-block-elements-container-' . uniqid(); + + if ( strpos( $link_color, 'var:preset|color|' ) !== false ) { + // Get the name from the string and add proper styles. + $index_to_splice = strrpos( $link_color, '|' ) + 1; + $link_color_name = substr( $link_color, $index_to_splice ); + $link_color = "var(--wp--preset--color--$link_color_name)"; + } + + $style = implode( + "\n", + array( + '\n", + ) + ); + + // Like the layout hook this assumes the hook only applies to blocks with a single wrapper. + $content = preg_replace( + '/' . preg_quote( 'class="', '/' ) . '/', + 'class="' . $class_name . ' ', + $block_content, + 1 + ); + return $content . $style; + +} + + +add_filter( 'render_block', 'gutenberg_render_elements_support', 10, 2 ); diff --git a/lib/load.php b/lib/load.php index 623fee5963794d..18a86eb37525ae 100644 --- a/lib/load.php +++ b/lib/load.php @@ -123,6 +123,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/query-utils.php'; require __DIR__ . '/block-supports/generated-classname.php'; +require __DIR__ . '/block-supports/elements.php'; require __DIR__ . '/block-supports/colors.php'; require __DIR__ . '/block-supports/align.php'; require __DIR__ . '/block-supports/typography.php'; diff --git a/packages/block-editor/src/hooks/color.js b/packages/block-editor/src/hooks/color.js index 431e1956989ac4..1ed6e4f812421d 100644 --- a/packages/block-editor/src/hooks/color.js +++ b/packages/block-editor/src/hooks/color.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { isObject } from 'lodash'; +import { isObject, setWith, clone } from 'lodash'; /** * WordPress dependencies @@ -303,17 +303,15 @@ export function ColorEdit( props ) { const onChangeLinkColor = ( value ) => { const colorObject = getColorObjectByColorValue( colors, value ); - props.setAttributes( { - style: { - ...props.attributes.style, - color: { - ...props.attributes.style?.color, - link: colorObject?.slug - ? `var:preset|color|${ colorObject.slug }` - : value, - }, - }, - } ); + const newStyle = setWith( + style ? clone( style ) : {}, + [ 'elements', 'link', 'color', 'text' ], + colorObject?.slug + ? `var:preset|color|${ colorObject.slug }` + : value, + clone + ); + props.setAttributes( { style: newStyle } ); }; return ( @@ -363,10 +361,10 @@ export function ColorEdit( props ) { onColorChange: onChangeLinkColor, colorValue: getLinkColorFromAttributeValue( colors, - style?.color?.link + style?.elements?.link?.color?.text ), - clearable: !! props.attributes.style?.color - ?.link, + clearable: !! style?.elements?.link?.color + ?.text, }, ] : [] ), diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index e856f8e91bd828..f15e92dcf5c217 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -1,7 +1,19 @@ /** * External dependencies */ -import { capitalize, get, has, omit, omitBy, startsWith } from 'lodash'; +import { + capitalize, + kebabCase, + get, + has, + map, + omit, + omitBy, + startsWith, + isEmpty, + first, +} from 'lodash'; +import classnames from 'classnames'; /** * WordPress dependencies @@ -12,7 +24,7 @@ import { hasBlockSupport, __EXPERIMENTAL_STYLE_PROPERTY as STYLE_PROPERTY, } from '@wordpress/blocks'; -import { createHigherOrderComponent } from '@wordpress/compose'; +import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; /** * Internal dependencies @@ -31,6 +43,16 @@ const styleSupportKeys = [ SPACING_SUPPORT_KEY, ]; +export const ELEMENTS = { + link: 'a', + h1: 'h1', + h2: 'h2', + h3: 'h3', + h4: 'h4', + h5: 'h5', + h6: 'h6', +}; + const hasStyleSupport = ( blockType ) => styleSupportKeys.some( ( key ) => hasBlockSupport( blockType, key ) ); @@ -59,7 +81,8 @@ export function getInlineStyles( styles = {} ) { Object.keys( STYLE_PROPERTY ).forEach( ( propKey ) => { const path = STYLE_PROPERTY[ propKey ].value; const subPaths = STYLE_PROPERTY[ propKey ].properties; - if ( has( styles, path ) ) { + // Ignore styles on elements because they are handled on the server. + if ( has( styles, path ) && 'elements' !== first( path ) ) { if ( !! subPaths ) { subPaths.forEach( ( suffix ) => { output[ @@ -75,6 +98,24 @@ export function getInlineStyles( styles = {} ) { return output; } +function compileElementsStyles( selector, elements = {} ) { + return map( elements, ( styles, element ) => { + const linearStyles = getInlineStyles( styles ); + if ( ! isEmpty( linearStyles ) ) { + return [ + `.${ selector } ${ ELEMENTS[ element ] }{`, + ...map( + linearStyles, + ( value, property ) => + `\t${ kebabCase( property ) }: ${ value }` + ), + '}', + ].join( '\n' ); + } + return ''; + } ).join( '\n' ); +} + /** * Filters registered block settings, extending attributes to include `style` attribute. * @@ -202,6 +243,45 @@ export const withBlockControls = createHigherOrderComponent( 'withToolbarControls' ); +/** + * Override the default block element to include duotone styles. + * + * @param {Function} BlockListBlock Original component + * @return {Function} Wrapped component + */ +const withElementsStyles = createHigherOrderComponent( + ( BlockListBlock ) => ( props ) => { + const elements = props.attributes.style?.elements; + if ( ! elements ) { + return ; + } + const blockElementsContainerIdentifier = `wp-block-elements-container-${ useInstanceId( + BlockListBlock + ) }`; + const styles = compileElementsStyles( + blockElementsContainerIdentifier, + props.attributes.style?.elements + ); + + return ( + <> +