Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Design Tools: Add block instance elements color support for buttons and headings #53667

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ Gather blocks in a layout container. ([Source](https://github.com/WordPress/gute

- **Name:** core/group
- **Category:** design
- **Supports:** align (full, wide), anchor, ariaLabel, color (background, gradients, heading, link, text), dimensions (minHeight), layout (allowSizingOnChildren), position (sticky), spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Supports:** align (full, wide), anchor, ariaLabel, color (background, button, gradients, heading, link, text), dimensions (minHeight), layout (allowSizingOnChildren), position (sticky), spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Attributes:** allowedBlocks, tagName, templateLock

## Heading
Expand Down
6 changes: 5 additions & 1 deletion lib/block-supports/colors.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ function gutenberg_register_colors_support( $block_type ) {
$has_background_colors_support = true === $color_support || ( is_array( $color_support ) && _wp_array_get( $color_support, array( 'background' ), true ) );
$has_gradients_support = _wp_array_get( $color_support, array( 'gradients' ), false );
$has_link_colors_support = _wp_array_get( $color_support, array( 'link' ), false );
$has_button_colors_support = _wp_array_get( $color_support, array( 'button' ), false );
$has_heading_colors_support = _wp_array_get( $color_support, array( 'heading' ), false );
$has_color_support = $has_text_colors_support ||
$has_background_colors_support ||
$has_gradients_support ||
$has_link_colors_support;
$has_link_colors_support ||
$has_button_colors_support ||
$has_heading_colors_support;

if ( ! $block_type->attributes ) {
$block_type->attributes = array();
Expand Down
162 changes: 129 additions & 33 deletions lib/block-supports/elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,84 @@ function gutenberg_get_elements_class_name( $block ) {
* @return string Filtered block content.
*/
function gutenberg_render_elements_support( $block_content, $block ) {
if ( ! $block_content ) {
if ( ! $block_content || empty( $block['attrs'] ) ) {
return $block_content;
}

$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
$skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' );
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
$skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' );
$skip_heading_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'heading' );
$skip_button_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'button' );
$skips_all_element_color_serialization = $skip_link_color_serialization &&
$skip_heading_color_serialization &&
$skip_button_color_serialization;

if ( $skip_link_color_serialization ) {
if ( $skips_all_element_color_serialization ) {
return $block_content;
}

$link_color = null;
if ( ! empty( $block['attrs'] ) ) {
$link_color = _wp_array_get( $block['attrs'], array( 'style', 'elements', 'link', 'color', 'text' ), null );
$element_colors_set = 0;

$link_color_paths = array(
'style.elements.link.color.text',
'style.elements.link.:hover.color.text',
);

foreach ( $link_color_paths as $element_color_path ) {
$element_color = _wp_array_get( $block['attrs'], explode( '.', $element_color_path, ), null );

if ( null !== $element_color && ! $skip_link_color_serialization ) {
$element_colors_set++;
}
}

$heading_color_paths = array(
'style.elements.heading.color.text',
'style.elements.heading.color.background',
'style.elements.heading.color.gradient',
'style.elements.h1.color.text',
'style.elements.h1.color.background',
'style.elements.h1.color.gradient',
'style.elements.h2.color.text',
'style.elements.h2.color.background',
'style.elements.h2.color.gradient',
'style.elements.h3.color.text',
'style.elements.h3.color.background',
'style.elements.h3.color.gradient',
'style.elements.h4.color.text',
'style.elements.h4.color.background',
'style.elements.h4.color.gradient',
'style.elements.h5.color.text',
'style.elements.h5.color.background',
'style.elements.h5.color.gradient',
'style.elements.h6.color.text',
'style.elements.h6.color.background',
'style.elements.h6.color.gradient',
);

foreach ( $heading_color_paths as $element_color_path ) {
$element_color = _wp_array_get( $block['attrs'], explode( '.', $element_color_path, ), null );

if ( null !== $element_color && ! $skip_heading_color_serialization ) {
$element_colors_set++;
}
}

$hover_link_color = null;
if ( ! empty( $block['attrs'] ) ) {
$hover_link_color = _wp_array_get( $block['attrs'], array( 'style', 'elements', 'link', ':hover', 'color', 'text' ), null );
$button_color_paths = array(
'style.elements.button.color.text',
'style.elements.button.color.background',
'style.elements.button.color.gradient',
);

foreach ( $button_color_paths as $element_color_path ) {
$element_color = _wp_array_get( $block['attrs'], explode( '.', $element_color_path, ), null );

if ( null !== $element_color && ! $skip_button_color_serialization ) {
$element_colors_set++;
}
}

/*
* For now we only care about link colors.
* This code in the future when we have a public API
* should take advantage of WP_Theme_JSON_Gutenberg::compute_style_properties
* and work for any element and style.
*/
if ( null === $link_color && null === $hover_link_color ) {
if ( ! $element_colors_set ) {
return $block_content;
}

Expand Down Expand Up @@ -80,30 +130,76 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
$element_block_styles = isset( $block['attrs']['style']['elements'] ) ? $block['attrs']['style']['elements'] : null;

/*
* For now we only care about link color.
*/
$skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' );
if ( ! $element_block_styles ) {
return null;
}

$skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' );
$skip_heading_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'heading' );
$skip_button_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'button' );
$skips_all_element_color_serialization = $skip_link_color_serialization &&
$skip_heading_color_serialization &&
$skip_button_color_serialization;

if ( $skip_link_color_serialization ) {
if ( $skips_all_element_color_serialization ) {
return null;
}
$class_name = gutenberg_get_elements_class_name( $block );

$class_name = gutenberg_get_elements_class_name( $block );

// Link colors
$link_block_styles = isset( $element_block_styles['link'] ) ? $element_block_styles['link'] : null;

gutenberg_style_engine_get_styles(
$link_block_styles,
array(
'selector' => ".$class_name a",
'context' => 'block-supports',
)
);
if ( ! $skip_link_color_serialization && $link_block_styles ) {
gutenberg_style_engine_get_styles(
$link_block_styles,
array(
'selector' => ".$class_name a",
'context' => 'block-supports',
)
);

if ( isset( $link_block_styles[':hover'] ) ) {
gutenberg_style_engine_get_styles(
$link_block_styles[':hover'],
array(
'selector' => ".$class_name a:hover",
'context' => 'block-supports',
)
);
}
}

// Heading colors
if ( ! $skip_heading_color_serialization ) {
$heading_levels = array( 'heading', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' );

foreach ( $heading_levels as $heading_level ) {
$heading_block_styles = isset( $element_block_styles[ $heading_level ] ) ? $element_block_styles[ $heading_level ] : null;
$heading_selector = 'heading' !== $heading_level
? ".$class_name $heading_level"
: ".$class_name h1, .$class_name h2, .$class_name h3, .$class_name h4, .$class_name h5, .$class_name h6";

if ( $heading_block_styles ) {
gutenberg_style_engine_get_styles(
$heading_block_styles,
array(
'selector' => $heading_selector,
'context' => 'block-supports',
)
);
}
}
}

// Button colors
$button_block_styles = isset( $element_block_styles['button'] ) ? $element_block_styles['button'] : null;

if ( isset( $link_block_styles[':hover'] ) ) {
if ( ! $skip_button_color_serialization && $button_block_styles ) {
gutenberg_style_engine_get_styles(
$link_block_styles[':hover'],
$button_block_styles,
array(
'selector' => ".$class_name a:hover",
'selector' => ".$class_name .wp-element-button, .$class_name .wp-block-button__link",
'context' => 'block-supports',
)
);
Expand Down
75 changes: 72 additions & 3 deletions packages/block-editor/src/hooks/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
} from './dimensions';
import useDisplayBlockControls from '../components/use-display-block-controls';
import { shouldSkipSerialization } from './utils';
import { scopeSelector } from '../components/global-styles/utils';
import { useBlockEditingMode } from '../components/block-editing-mode';

const styleSupportKeys = [
Expand Down Expand Up @@ -382,13 +383,26 @@ const withElementsStyles = createHigherOrderComponent(
const blockElementsContainerIdentifier = `wp-elements-${ useInstanceId(
BlockListBlock
) }`;
const baseElementSelector = `.editor-styles-wrapper .${ blockElementsContainerIdentifier }`;

const skipLinkColorSerialization = shouldSkipSerialization(
props.name,
COLOR_SUPPORT_KEY,
'link'
);

const skipHeadingColorSerialization = shouldSkipSerialization(
props.name,
COLOR_SUPPORT_KEY,
'heading'
);

const skipButtonColorSerialization = shouldSkipSerialization(
props.name,
COLOR_SUPPORT_KEY,
'button'
);

const styles = useMemo( () => {
// The .editor-styles-wrapper selector is required on elements styles. As it is
// added to all other editor styles, not providing it causes reset and global
Expand All @@ -398,13 +412,68 @@ const withElementsStyles = createHigherOrderComponent(
styles: ! skipLinkColorSerialization
? props.attributes.style?.elements?.link
: undefined,
selector: `.editor-styles-wrapper .${ blockElementsContainerIdentifier } ${ ELEMENTS.link }`,
selector: `${ baseElementSelector } ${ ELEMENTS.link }`,
},
{
styles: ! skipLinkColorSerialization
? props.attributes.style?.elements?.link?.[ ':hover' ]
: undefined,
selector: `.editor-styles-wrapper .${ blockElementsContainerIdentifier } ${ ELEMENTS.link }:hover`,
selector: `${ baseElementSelector } ${ ELEMENTS.link }:hover`,
},
{
styles: ! skipHeadingColorSerialization
? props.attributes.style?.elements?.heading
: undefined,
selector: scopeSelector(
baseElementSelector,
ELEMENTS.heading
),
},
{
styles: ! skipHeadingColorSerialization
? props.attributes.style?.elements?.h1
: undefined,
selector: scopeSelector( baseElementSelector, ELEMENTS.h1 ),
},
{
styles: ! skipHeadingColorSerialization
? props.attributes.style?.elements?.h2
: undefined,
selector: scopeSelector( baseElementSelector, ELEMENTS.h2 ),
},
{
styles: ! skipHeadingColorSerialization
? props.attributes.style?.elements?.h3
: undefined,
selector: scopeSelector( baseElementSelector, ELEMENTS.h3 ),
},
{
styles: ! skipHeadingColorSerialization
? props.attributes.style?.elements?.h4
: undefined,
selector: scopeSelector( baseElementSelector, ELEMENTS.h4 ),
},
{
styles: ! skipHeadingColorSerialization
? props.attributes.style?.elements?.h5
: undefined,
selector: scopeSelector( baseElementSelector, ELEMENTS.h5 ),
},
{
styles: ! skipHeadingColorSerialization
? props.attributes.style?.elements?.h6
: undefined,
selector: scopeSelector( baseElementSelector, ELEMENTS.h6 ),
},
//TODO: Refactor this to a helper that can more concisely flesh out the rest of the heading elements.
{
styles: ! skipButtonColorSerialization
? props.attributes.style?.elements?.button
: undefined,
selector: scopeSelector(
baseElementSelector,
ELEMENTS.button
),
},
];
const elementCssRules = [];
Expand All @@ -421,7 +490,7 @@ const withElementsStyles = createHigherOrderComponent(
: undefined;
}, [
props.attributes.style?.elements,
blockElementsContainerIdentifier,
baseElementSelector,
skipLinkColorSerialization,
] );

Expand Down
4 changes: 4 additions & 0 deletions packages/block-editor/src/hooks/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ export function useBlockSettings( name, parentLayout ) {
const isBackgroundEnabled = useSetting( 'color.background' );
const isLinkEnabled = useSetting( 'color.link' );
const isTextEnabled = useSetting( 'color.text' );
const isHeadingEnabled = useSetting( 'color.heading' );
const isButtonEnabled = useSetting( 'color.button' );

const rawSettings = useMemo( () => {
return {
Expand Down Expand Up @@ -193,6 +195,8 @@ export function useBlockSettings( name, parentLayout ) {
customDuotone,
background: isBackgroundEnabled,
link: isLinkEnabled,
heading: isHeadingEnabled,
button: isButtonEnabled,
text: isTextEnabled,
},
typography: {
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/group/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"color": {
"gradients": true,
"heading": true,
"button": true,
"link": true,
"__experimentalDefaultControls": {
"background": true,
Expand Down
6 changes: 6 additions & 0 deletions packages/style-engine/class-wp-style-engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ final class WP_Style_Engine {
'default' => 'background-color',
),
'path' => array( 'color', 'background' ),
'css_vars' => array(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just double-checked and refreshed my memory: the addition here and in gradient looks safe to me and doesn't affect calls from colors.php since in that file, we're calling gutenberg_style_engine_get_styles with the convert_vars_to_classnames option flag, which means that it skips adding the css_vars in cases where we intend to grab classnames instead. For example, if we add a Post Title block to a post or page and set background / gradient colors, then with this PR applied, it'll still receive classnames and not any inline styles, which is as we'd expect 👍

E.g. this is as on trunk:

image

While elsewhere on the same page, the container-based element styles are applied correctly via the background-color property, etc:

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The style engine™️ delivers

'color' => '--wp--preset--color--$slug',
),
'classnames' => array(
'has-background' => true,
'has-$slug-background-color' => 'color',
Expand All @@ -67,6 +70,9 @@ final class WP_Style_Engine {
'property_keys' => array(
'default' => 'background',
),
'css_vars' => array(
'gradient' => '--wp--preset--gradient--$slug',
),
'path' => array( 'color', 'gradient' ),
'classnames' => array(
'has-background' => true,
Expand Down