From beabb54ef313eb652cdd2cbd8263cabdd040a376 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Mon, 12 Oct 2020 17:33:07 -0700 Subject: [PATCH 01/14] Add initial block support for width First pass attempt at creating a block support for adding a width selector with options for 25, 50, 75, 100 percent width. It is based off the work to add a block support for border radius. The intention is to extend this to include custom percentage widths and px support with a slider in the editor for custom sizing (see Search bar for an example). --- lib/block-supports/index.php | 132 +++++++++++++++++ lib/block-supports/width.php | 71 ++++++++++ lib/global-styles.php | 5 + lib/load.php | 1 + packages/block-editor/src/hooks/style.js | 3 + packages/block-editor/src/hooks/width.js | 142 +++++++++++++++++++ packages/block-library/src/button/block.json | 3 +- 7 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 lib/block-supports/index.php create mode 100644 lib/block-supports/width.php create mode 100644 packages/block-editor/src/hooks/width.js diff --git a/lib/block-supports/index.php b/lib/block-supports/index.php new file mode 100644 index 0000000000000..8adf5a10c45ed --- /dev/null +++ b/lib/block-supports/index.php @@ -0,0 +1,132 @@ +get_all_registered(); + // Ideally we need a hook to extend the block registration + // instead of mutating the block type. + foreach ( $registered_block_types as $block_type ) { + gutenberg_register_alignment_support( $block_type ); + gutenberg_register_colors_support( $block_type ); + gutenberg_register_typography_support( $block_type ); + gutenberg_register_custom_classname_support( $block_type ); + gutenberg_register_width_support( $block_type ); + } +} + +add_action( 'init', 'gutenberg_register_block_supports', 21 ); + +/** + * Filters the frontend output of blocks and apply the block support flags transformations. + * + * @param string $block_content rendered block content. + * @param array $block block object. + * @return string filtered block content. + */ +function gutenberg_apply_block_supports( $block_content, $block ) { + if ( ! isset( $block['attrs'] ) ) { + return $block_content; + } + + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); + // If no render_callback, assume styles have been previously handled. + if ( ! $block_type || ! $block_type->render_callback ) { + return $block_content; + } + + $attributes = array(); + $attributes = gutenberg_apply_generated_classname_support( $attributes, $block['attrs'], $block_type ); + $attributes = gutenberg_apply_colors_support( $attributes, $block['attrs'], $block_type ); + $attributes = gutenberg_apply_typography_support( $attributes, $block['attrs'], $block_type ); + $attributes = gutenberg_apply_alignment_support( $attributes, $block['attrs'], $block_type ); + $attributes = gutenberg_apply_custom_classname_support( $attributes, $block['attrs'], $block_type ); + $attributes = gutenberg_apply_width_support( $attributes, $block['attrs'], $block_type ); + + if ( ! count( $attributes ) ) { + return $block_content; + } + + $dom = new DOMDocument( '1.0', 'utf-8' ); + + // Suppress DOMDocument::loadHTML warnings from polluting the front-end. + $previous = libxml_use_internal_errors( true ); + + // We need to wrap the block in order to handle UTF-8 properly. + $wrapped_block_html = + '' + . $block_content + . ''; + + $success = $dom->loadHTML( $wrapped_block_html, LIBXML_HTML_NODEFDTD | LIBXML_COMPACT ); + + // Clear errors and reset the use_errors setting. + libxml_clear_errors(); + libxml_use_internal_errors( $previous ); + + if ( ! $success ) { + return $block_content; + } + + // Structure is like ``, so body is the `lastChild` of our document. + $body_element = $dom->documentElement->lastChild; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + + $xpath = new DOMXPath( $dom ); + $block_root = $xpath->query( './*', $body_element )[0]; + + // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + if ( empty( $block_root ) ) { + return $block_content; + } + + // Merge and dedupe new and existing classes and styles. + $current_classes = explode( ' ', trim( $block_root->getAttribute( 'class' ) ) ); + $classes_to_add = array_key_exists( 'css_classes', $attributes ) ? $attributes['css_classes'] : array(); + $new_classes = array_unique( array_filter( array_merge( $current_classes, $classes_to_add ) ) ); + + $current_styles = preg_split( '/\s*;\s*/', trim( $block_root->getAttribute( 'style' ) ) ); + $styles_to_add = array_key_exists( 'inline_styles', $attributes ) ? $attributes['inline_styles'] : array(); + $new_styles = array_unique( array_map( 'gutenberg_normalize_css_rule', array_filter( array_merge( $current_styles, $styles_to_add ) ) ) ); + + // Apply new styles and classes. + if ( ! empty( $new_classes ) ) { + // `DOMElement::setAttribute` handles attribute value escaping. + $block_root->setAttribute( 'class', implode( ' ', $new_classes ) ); + } + + if ( ! empty( $new_styles ) ) { + // `DOMElement::setAttribute` handles attribute value escaping. + $block_root->setAttribute( 'style', implode( '; ', $new_styles ) . ';' ); + } + + // Avoid using `$dom->saveHtml( $node )` because the node results may not produce consistent + // whitespace for PHP < 7.3. Saving the root HTML `$dom->saveHtml()` prevents this behavior. + $full_html = $dom->saveHtml(); + + // Find the open/close tags. The open tag needs to be adjusted so we get inside the tag + // and not the tag itself. + $start = strpos( $full_html, '', 0 ) + strlen( '' ); + $end = strpos( $full_html, '', $start ); + return trim( substr( $full_html, $start, $end - $start ) ); +} +add_filter( 'render_block', 'gutenberg_apply_block_supports', 10, 2 ); + +/** + * Normalizes spacing in a string representing a CSS rule + * + * @example + * 'color :red;' becomes 'color:red' + * + * @param string $css_rule_string CSS rule. + * @return string Normalized CSS rule. + */ +function gutenberg_normalize_css_rule( $css_rule_string ) { + return trim( implode( ': ', preg_split( '/\s*:\s*/', $css_rule_string, 2 ) ), ';' ); +} diff --git a/lib/block-supports/width.php b/lib/block-supports/width.php new file mode 100644 index 0000000000000..70e0acce4be7e --- /dev/null +++ b/lib/block-supports/width.php @@ -0,0 +1,71 @@ +attributes ) { + $block_type->attributes = array(); + } + + if ( $has_width_support && ! array_key_exists( 'style', $block_type->attributes ) ) { + $block_type->attributes['style'] = array( + 'type' => 'object', + ); + } +} + +/** + * Adds CSS classes and inline styles for width to the incoming + * attributes array. This will be applied to the block markup in the front-end. + * + * @param array $attributes List of attributes to be applied. + * @param array $block_attributes Block attributes. + * @param WP_Block_type $block_type Block type. + * + * @return array Width CSS classes and inline styles. + */ +function gutenberg_apply_width_support( $attributes, $block_attributes, $block_type ) { + $has_width_support = gutenberg_has_width_support( $block_type, '__experimentalWidth' ); + + if ( $has_width_support ) { + $has_width = isset( $block_attributes['style']['width'] ); + if ( $has_width ) { + $width = intval( $block_attributes['style']['width'] ); + $attributes['inline_styles'][] = sprintf( 'width: %d%%;', $width ); + } + } + + return $attributes; +} + +/** + * Checks whether the current block type supports the experimental feature + * requested. + * + * @param WP_Block_Type $block_type Block type to check for support. + * @param string $feature Name of the feature to check support for. + * @param mixed $default Fallback value for feature support, defaults to false. + * + * @return boolean Whether or not the feature is supported. + */ +function gutenberg_has_width_support( $block_type, $feature, $default = false ) { + $supported = false; + if ( property_exists( $block_type, 'supports' ) ) { + $supported = gutenberg_experimental_get( $block_type->supports, array( $feature ), $default ); + } + + return $supported; +} \ No newline at end of file diff --git a/lib/global-styles.php b/lib/global-styles.php index 2b4173f58d9e2..1cb93e33325d1 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -389,6 +389,8 @@ function gutenberg_experimental_global_styles_get_css_property( $style_property return 'font-size'; case 'lineHeight': return 'line-height'; + case 'width': + return 'width'; default: return $style_property; } @@ -407,6 +409,7 @@ function gutenberg_experimental_global_styles_get_style_property() { 'color' => array( 'color', 'text' ), 'fontSize' => array( 'typography', 'fontSize' ), 'lineHeight' => array( 'typography', 'lineHeight' ), + 'width' => array( 'width'), ); } @@ -423,6 +426,7 @@ function gutenberg_experimental_global_styles_get_support_keys() { 'color' => array( 'color' ), 'fontSize' => array( 'fontSize' ), 'lineHeight' => array( 'lineHeight' ), + 'width' => array( '__experimentalWidth' ), ); } @@ -819,6 +823,7 @@ function gutenberg_experimental_global_styles_normalize_schema( $tree ) { 'custom' => array(), 'typography' => array(), 'spacing' => array(), + 'width' => array(), ), ); diff --git a/lib/load.php b/lib/load.php index 42ebfe7bb5733..6b13fd47e2935 100644 --- a/lib/load.php +++ b/lib/load.php @@ -129,3 +129,4 @@ function gutenberg_is_experiment_enabled( $name ) { require dirname( __FILE__ ) . '/block-supports/align.php'; require dirname( __FILE__ ) . '/block-supports/typography.php'; require dirname( __FILE__ ) . '/block-supports/custom-classname.php'; +require dirname( __FILE__ ) . '/block-supports/dimensions.php'; diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index adec7bb0d02df..0f550a6f90a50 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -20,11 +20,13 @@ import { COLOR_SUPPORT_KEY, ColorEdit } from './color'; import { TypographyPanel, TYPOGRAPHY_SUPPORT_KEYS } from './typography'; import { SPACING_SUPPORT_KEY, PaddingEdit } from './padding'; import SpacingPanelControl from '../components/spacing-panel-control'; +import { WIDTH_SUPPORT_KEY, WidthPanel } from './width'; const styleSupportKeys = [ ...TYPOGRAPHY_SUPPORT_KEYS, COLOR_SUPPORT_KEY, SPACING_SUPPORT_KEY, + WIDTH_SUPPORT_KEY, ]; const hasStyleSupport = ( blockType ) => @@ -156,6 +158,7 @@ export const withBlockControls = createHigherOrderComponent( return [ , , + , , hasSpacingSupport && ( diff --git a/packages/block-editor/src/hooks/width.js b/packages/block-editor/src/hooks/width.js new file mode 100644 index 0000000000000..68f8be6d7d58e --- /dev/null +++ b/packages/block-editor/src/hooks/width.js @@ -0,0 +1,142 @@ +/** + * WordPress dependencies + */ +import { getBlockSupport } from '@wordpress/blocks'; +import { Button, ButtonGroup, PanelBody } from '@wordpress/components'; +import { addFilter } from '@wordpress/hooks'; +import { __ } from '@wordpress/i18n'; +import TokenList from '@wordpress/token-list'; + +/** + * Internal dependencies + */ +import { cleanEmptyObject } from './utils'; +import InspectorControls from '../components/inspector-controls'; + +export const WIDTH_SUPPORT_KEY = '__experimentalWidth'; + +/** + * Override props assigned to save component to inject width CSS class + * if applicable. + * + * @param {Object} props Additional props applied to save element. + * @param {Object} blockType Block type. + * @return {Object} Filtered props applied to save element. + */ +function addSaveProps( props, blockType ) { + if ( ! hasWidthSupport( blockType ) ) { + return props; + } + + // Add CSS class indicating that a custom width was applied + // Use TokenList to de-dupe classes. + const classes = new TokenList( props.className ); + classes.add( `custom-width` ); + const newClassName = classes.value; + props.className = newClassName ? newClassName : undefined; + + return props; +} + +/** + * Filters registered block settings to expand the block edit wrapper by + * applying the desired class name. + * + * @param {Object} settings Original block settings. + * @return {Object} Filtered block settings. + */ +function addEditProps( settings ) { + if ( ! hasWidthSupport( settings ) ) { + return settings; + } + + const existingGetEditWrapperProps = settings.getEditWrapperProps; + settings.getEditWrapperProps = ( attributes ) => { + let props = {}; + if ( existingGetEditWrapperProps ) { + props = existingGetEditWrapperProps( attributes ); + } + return addSaveProps( props, settings ); + }; + + return settings; +} + +/** + * Inspector control panel containing the width related configuration. + * + * @param {Object} props Block properties. + * @return {WPElement} Width edit element. + */ +export function WidthEdit( props ) { + const { + attributes: { style }, + setAttributes, + } = props; + + if ( isWidthDisabled( props ) ) { + return null; + } + + const onChange = ( newWidthValue ) => { + const newStyle = { + ...style, + width: newWidthValue, + }; + + setAttributes( { style: cleanEmptyObject( newStyle ) } ); + }; + + return ( + + { [ 25, 50, 75, 100 ].map( ( widthValue ) => { + return ( + + ); + } ) } + + ); +} + +export function WidthPanel( props ) { + if ( isWidthDisabled( props ) ) { + return null; + } + + return ( + + + + + + ); +} + +/** + * Determines if there is width support. + * + * @param {string|Object} blockType Block name or Block Type object. + * @return {boolean} Whether there is support. + */ +export function hasWidthSupport( blockType ) { + return getBlockSupport( blockType, WIDTH_SUPPORT_KEY ); +} + +export function isWidthDisabled( { name: blockName } = {} ) { + return ! hasWidthSupport( blockName ); +} + +addFilter( + 'blocks.getSaveContent.extraProps', + 'core/font/addSaveProps', + addSaveProps +); + +addFilter( 'blocks.registerBlockType', 'core/font/addEditProps', addEditProps ); diff --git a/packages/block-library/src/button/block.json b/packages/block-library/src/button/block.json index b0cff94836069..195e61a9b3de9 100644 --- a/packages/block-library/src/button/block.json +++ b/packages/block-library/src/button/block.json @@ -59,6 +59,7 @@ "align": true, "alignWide": false, "reusable": false, - "__experimentalSelector": ".wp-block-button > a" + "__experimentalSelector": ".wp-block-button > a", + "__experimentalWidth": true } } From 3ec23480949edc090354f06a67103fd8d8db273b Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Tue, 13 Oct 2020 12:40:12 -0700 Subject: [PATCH 02/14] Apply inline styles when width is selected --- lib/global-styles.php | 3 ++- packages/block-editor/src/hooks/width.js | 18 ++++++++++++------ packages/blocks/src/api/constants.js | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/global-styles.php b/lib/global-styles.php index 1cb93e33325d1..2ff51a9800e47 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -409,7 +409,7 @@ function gutenberg_experimental_global_styles_get_style_property() { 'color' => array( 'color', 'text' ), 'fontSize' => array( 'typography', 'fontSize' ), 'lineHeight' => array( 'typography', 'lineHeight' ), - 'width' => array( 'width'), + 'width' => array( 'width', 'width'), ); } @@ -817,6 +817,7 @@ function gutenberg_experimental_global_styles_normalize_schema( $tree ) { 'styles' => array( 'typography' => array(), 'color' => array(), + 'width' => array(), ), 'settings' => array( 'color' => array(), diff --git a/packages/block-editor/src/hooks/width.js b/packages/block-editor/src/hooks/width.js index 68f8be6d7d58e..89f0500e60e3e 100644 --- a/packages/block-editor/src/hooks/width.js +++ b/packages/block-editor/src/hooks/width.js @@ -81,7 +81,9 @@ export function WidthEdit( props ) { const onChange = ( newWidthValue ) => { const newStyle = { ...style, - width: newWidthValue, + width: { + width: newWidthValue, + }, }; setAttributes( { style: cleanEmptyObject( newStyle ) } ); @@ -89,15 +91,15 @@ export function WidthEdit( props ) { return ( - { [ 25, 50, 75, 100 ].map( ( widthValue ) => { + { [ '25%', '50%', '75%', '100%' ].map( ( widthValue ) => { return ( ); } ) } @@ -135,8 +137,12 @@ export function isWidthDisabled( { name: blockName } = {} ) { addFilter( 'blocks.getSaveContent.extraProps', - 'core/font/addSaveProps', + 'core/width/addSaveProps', addSaveProps ); -addFilter( 'blocks.registerBlockType', 'core/font/addEditProps', addEditProps ); +addFilter( + 'blocks.registerBlockType', + 'core/width/addEditProps', + addEditProps +); diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js index 18488d1db55f7..e0792a1b9f47e 100644 --- a/packages/blocks/src/api/constants.js +++ b/packages/blocks/src/api/constants.js @@ -23,4 +23,5 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = { paddingLeft: [ 'spacing', 'padding', 'left' ], paddingRight: [ 'spacing', 'padding', 'right' ], paddingTop: [ 'spacing', 'padding', 'top' ], + width: [ 'width', 'width' ], }; From ae14c83ec10d55ecfc8124f1a4d4864aed79beb6 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Tue, 13 Oct 2020 12:50:21 -0700 Subject: [PATCH 03/14] Add className when custom width is selected When a custom width is selected apply the 'custom-width' className to the block. This is used to key off of for additional block-specific CSS; for example the Button block needs to set its inner component to 100% width for the styling to work correctly. --- packages/block-editor/src/hooks/width.js | 15 +++++++++------ packages/block-library/src/button/style.scss | 4 ++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/width.js b/packages/block-editor/src/hooks/width.js index 89f0500e60e3e..07ef7542374a4 100644 --- a/packages/block-editor/src/hooks/width.js +++ b/packages/block-editor/src/hooks/width.js @@ -21,19 +21,22 @@ export const WIDTH_SUPPORT_KEY = '__experimentalWidth'; * * @param {Object} props Additional props applied to save element. * @param {Object} blockType Block type. + * @param {Object} attributes Block attributes. * @return {Object} Filtered props applied to save element. */ -function addSaveProps( props, blockType ) { +function addSaveProps( props, blockType, attributes ) { if ( ! hasWidthSupport( blockType ) ) { return props; } // Add CSS class indicating that a custom width was applied // Use TokenList to de-dupe classes. - const classes = new TokenList( props.className ); - classes.add( `custom-width` ); - const newClassName = classes.value; - props.className = newClassName ? newClassName : undefined; + if ( attributes.style?.width?.width ) { + const classes = new TokenList( props.className ); + classes.add( `custom-width` ); + const newClassName = classes.value; + props.className = newClassName ? newClassName : undefined; + } return props; } @@ -56,7 +59,7 @@ function addEditProps( settings ) { if ( existingGetEditWrapperProps ) { props = existingGetEditWrapperProps( attributes ); } - return addSaveProps( props, settings ); + return addSaveProps( props, settings, attributes ); }; return settings; diff --git a/packages/block-library/src/button/style.scss b/packages/block-library/src/button/style.scss index f996369d0c94f..58cc6f43561e8 100644 --- a/packages/block-library/src/button/style.scss +++ b/packages/block-library/src/button/style.scss @@ -53,3 +53,7 @@ $blocks-button__height: 3.1em; background-color: transparent; border: 2px solid; } + +.custom-width .wp-block-button__link { + width: 100%; +} From 42f22493ec88f20dce8238dc758639f7cbbd5af0 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Tue, 13 Oct 2020 14:31:13 -0700 Subject: [PATCH 04/14] Adjust CSS for right-aligned buttons in editor --- packages/block-library/src/buttons/editor.scss | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/buttons/editor.scss b/packages/block-library/src/buttons/editor.scss index 121ba5f5af5cf..fdc225489f7b7 100644 --- a/packages/block-library/src/buttons/editor.scss +++ b/packages/block-library/src/buttons/editor.scss @@ -3,10 +3,13 @@ margin-left: 0; } -.wp-block[data-align="center"] > .wp-block-buttons { +.wp-block > .wp-block-buttons { display: flex; - align-items: center; flex-wrap: wrap; +} + +.wp-block[data-align="center"] > .wp-block-buttons { + align-items: center; justify-content: center; } From 873fb26808fc8fade89e89a5d2606a172dd30848 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Tue, 13 Oct 2020 14:39:19 -0700 Subject: [PATCH 05/14] Flatten structure of width settings in the style attribute --- lib/block-supports/width.php | 2 +- lib/global-styles.php | 2 +- packages/block-editor/src/hooks/width.js | 9 +++------ packages/blocks/src/api/constants.js | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/block-supports/width.php b/lib/block-supports/width.php index 70e0acce4be7e..4bc12bc9bab99 100644 --- a/lib/block-supports/width.php +++ b/lib/block-supports/width.php @@ -44,7 +44,7 @@ function gutenberg_apply_width_support( $attributes, $block_attributes, $block_t $has_width = isset( $block_attributes['style']['width'] ); if ( $has_width ) { $width = intval( $block_attributes['style']['width'] ); - $attributes['inline_styles'][] = sprintf( 'width: %d%%;', $width ); + $attributes['inline_styles'][] = sprintf( 'width: %d;', $width ); } } diff --git a/lib/global-styles.php b/lib/global-styles.php index 2ff51a9800e47..caaa80f78a678 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -409,7 +409,7 @@ function gutenberg_experimental_global_styles_get_style_property() { 'color' => array( 'color', 'text' ), 'fontSize' => array( 'typography', 'fontSize' ), 'lineHeight' => array( 'typography', 'lineHeight' ), - 'width' => array( 'width', 'width'), + 'width' => array( 'width'), ); } diff --git a/packages/block-editor/src/hooks/width.js b/packages/block-editor/src/hooks/width.js index 07ef7542374a4..6b86ac8d61f24 100644 --- a/packages/block-editor/src/hooks/width.js +++ b/packages/block-editor/src/hooks/width.js @@ -31,7 +31,7 @@ function addSaveProps( props, blockType, attributes ) { // Add CSS class indicating that a custom width was applied // Use TokenList to de-dupe classes. - if ( attributes.style?.width?.width ) { + if ( attributes.style?.width ) { const classes = new TokenList( props.className ); classes.add( `custom-width` ); const newClassName = classes.value; @@ -84,11 +84,8 @@ export function WidthEdit( props ) { const onChange = ( newWidthValue ) => { const newStyle = { ...style, - width: { - width: newWidthValue, - }, + width: newWidthValue, }; - setAttributes( { style: cleanEmptyObject( newStyle ) } ); }; @@ -99,7 +96,7 @@ export function WidthEdit( props ) { + ); + } ) } + + ); +} diff --git a/packages/block-editor/src/hooks/test/width.js b/packages/block-editor/src/hooks/test/width.js deleted file mode 100644 index 1f99375dae146..0000000000000 --- a/packages/block-editor/src/hooks/test/width.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * External dependencies - */ -import { noop } from 'lodash'; - -/** - * WordPress dependencies - */ -import { applyFilters } from '@wordpress/hooks'; - -/** - * Internal dependencies - */ -import '../width'; - -describe( 'custom width styles', () => { - const blockSettings = { - name: 'lorem/ipsum', - save: noop, - category: 'text', - title: 'block title', - }; - - const settingsWithSupport = { - ...blockSettings, - supports: { - __experimentalWidth: true, - }, - }; - - const settingsWithoutSupport = { - ...blockSettings, - supports: { - __experimentalWidth: false, - }, - }; - - describe( 'addSaveProps', () => { - const addSaveProps = applyFilters.bind( - null, - 'blocks.getSaveContent.extraProps' - ); - - it( 'should do nothing if width support disabled', () => { - const extraProps = addSaveProps( {}, settingsWithoutSupport, { - style: { width: '75%' }, - } ); - expect( extraProps ).not.toHaveProperty( 'className' ); - } ); - - it( 'should not add CSS class if custom width is not set', () => { - const extraProps = addSaveProps( {}, settingsWithSupport, { - style: {}, - } ); - expect( extraProps ).not.toHaveProperty( 'className' ); - } ); - - it( 'should add CSS class if width supported and custom width set', () => { - const extraProps = addSaveProps( {}, settingsWithSupport, { - style: { border: { radius: 0 } }, - } ); - expect( extraProps ).toHaveProperty( 'className' ); - } ); - } ); - - describe( 'addEditProps', () => { - const addEditProps = applyFilters.bind( - null, - 'blocks.registerBlockType' - ); - - it( 'should not modify edit wrapper props when width not supported', () => { - const settings = addEditProps( blockSettings ); - // Test settings don't have getEditWrapperProps so should stay undefined. - expect( settings.getEditWrapperProps ).toBeUndefined(); - } ); - - it( 'should add getEditWrapperProps when width is supported', () => { - const settings = addEditProps( settingsWithSupport ); - expect( settings.getEditWrapperProps ).toBeDefined(); - } ); - - it( 'should add custom-width class to edit props when width is supported and width set', () => { - const settings = addEditProps( settingsWithSupport ); - const props = settings.getEditWrapperProps( { - style: { width: '75%' }, - } ); - expect( props.className ).toMatch( 'custom-width' ); - } ); - } ); -} ); diff --git a/packages/block-editor/src/hooks/width.js b/packages/block-editor/src/hooks/width.js index 6b86ac8d61f24..b570bcbb423b4 100644 --- a/packages/block-editor/src/hooks/width.js +++ b/packages/block-editor/src/hooks/width.js @@ -1,148 +1,95 @@ /** * WordPress dependencies */ -import { getBlockSupport } from '@wordpress/blocks'; -import { Button, ButtonGroup, PanelBody } from '@wordpress/components'; -import { addFilter } from '@wordpress/hooks'; +import { hasBlockSupport } from '@wordpress/blocks'; +import { PanelBody } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import TokenList from '@wordpress/token-list'; /** * Internal dependencies */ import { cleanEmptyObject } from './utils'; import InspectorControls from '../components/inspector-controls'; - -export const WIDTH_SUPPORT_KEY = '__experimentalWidth'; +import useEditorFeature from '../components/use-editor-feature'; +import WidthControl from '../components/width-control'; /** - * Override props assigned to save component to inject width CSS class - * if applicable. - * - * @param {Object} props Additional props applied to save element. - * @param {Object} blockType Block type. - * @param {Object} attributes Block attributes. - * @return {Object} Filtered props applied to save element. + * Key within block settings' supports array indicating support for + * width, e.g. settings found in 'block.json'. */ -function addSaveProps( props, blockType, attributes ) { - if ( ! hasWidthSupport( blockType ) ) { - return props; - } - - // Add CSS class indicating that a custom width was applied - // Use TokenList to de-dupe classes. - if ( attributes.style?.width ) { - const classes = new TokenList( props.className ); - classes.add( `custom-width` ); - const newClassName = classes.value; - props.className = newClassName ? newClassName : undefined; - } - - return props; -} - -/** - * Filters registered block settings to expand the block edit wrapper by - * applying the desired class name. - * - * @param {Object} settings Original block settings. - * @return {Object} Filtered block settings. - */ -function addEditProps( settings ) { - if ( ! hasWidthSupport( settings ) ) { - return settings; - } - - const existingGetEditWrapperProps = settings.getEditWrapperProps; - settings.getEditWrapperProps = ( attributes ) => { - let props = {}; - if ( existingGetEditWrapperProps ) { - props = existingGetEditWrapperProps( attributes ); - } - return addSaveProps( props, settings, attributes ); - }; - - return settings; -} +export const WIDTH_SUPPORT_KEY = '__experimentalWidth'; -/** - * Inspector control panel containing the width related configuration. - * - * @param {Object} props Block properties. - * @return {WPElement} Width edit element. - */ -export function WidthEdit( props ) { +export function WidthPanel( props ) { const { attributes: { style }, setAttributes, } = props; - if ( isWidthDisabled( props ) ) { + const widthOptions = useEditorFeature( 'width' ); + const isDisabled = useIsWidthDisabled( props ); + + if ( isDisabled ) { return null; } - const onChange = ( newWidthValue ) => { - const newStyle = { - ...style, - width: newWidthValue, - }; - setAttributes( { style: cleanEmptyObject( newStyle ) } ); - }; - - return ( - - { [ '25%', '50%', '75%', '100%' ].map( ( widthValue ) => { - return ( - - ); - } ) } - + const selectedWidth = getWidthFromAttributeValue( + widthOptions, + style?.width ); -} -export function WidthPanel( props ) { - if ( isWidthDisabled( props ) ) { - return null; + function onChange( newWidth ) { + setAttributes( { + style: cleanEmptyObject( { + ...style, + width: newWidth, + } ), + } ); } return ( - + ); } /** - * Determines if there is width support. + * Checks if width support has been disabled * * @param {string|Object} blockType Block name or Block Type object. * @return {boolean} Whether there is support. */ -export function hasWidthSupport( blockType ) { - return getBlockSupport( blockType, WIDTH_SUPPORT_KEY ); -} +export function useIsWidthDisabled( { name: blockName } = {} ) { + const notSupported = ! hasBlockSupport( blockName, WIDTH_SUPPORT_KEY ); -export function isWidthDisabled( { name: blockName } = {} ) { - return ! hasWidthSupport( blockName ); + const widthOptions = useEditorFeature( 'width' ); + const hasWidthOptions = !! widthOptions?.length; + + return notSupported || ! hasWidthOptions; } -addFilter( - 'blocks.getSaveContent.extraProps', - 'core/width/addSaveProps', - addSaveProps -); +/** + * Extracts the current width selection, if available, from the CSS variable + * set as the 'styles.width' attribute. + * + * @param {Array} widthOptions Available width options as defined in theme.json + * @param {string} value Attribute value in `styles.width` + * @return {string} Actual width value + */ +const getWidthFromAttributeValue = ( widthOptions, value ) => { + const attributeParsed = /var:preset\|width\|(.+)/.exec( value ); + + if ( attributeParsed && attributeParsed[ 1 ] ) { + return widthOptions.find( + ( { slug } ) => slug === attributeParsed[ 1 ] + )?.slug; + } -addFilter( - 'blocks.registerBlockType', - 'core/width/addEditProps', - addEditProps -); + return value; +}; diff --git a/packages/block-library/src/button/style.scss b/packages/block-library/src/button/style.scss index 58cc6f43561e8..e674899748acf 100644 --- a/packages/block-library/src/button/style.scss +++ b/packages/block-library/src/button/style.scss @@ -54,6 +54,10 @@ $blocks-button__height: 3.1em; border: 2px solid; } -.custom-width .wp-block-button__link { - width: 100%; +// Set the inner button to 100% width when a custom width +// has been set on the parent +div[style*="--wp--preset--width"] { + .wp-block-button__link { + width: 100%; + } } diff --git a/packages/edit-site/src/components/editor/utils.js b/packages/edit-site/src/components/editor/utils.js index 2655b5f86af48..cb34670b46c44 100644 --- a/packages/edit-site/src/components/editor/utils.js +++ b/packages/edit-site/src/components/editor/utils.js @@ -4,6 +4,7 @@ export const PRESET_CATEGORIES = { color: { path: [ 'color', 'palette' ], key: 'color' }, gradient: { path: [ 'color', 'gradients' ], key: 'gradient' }, fontSize: { path: [ 'typography', 'fontSizes' ], key: 'size' }, + width: { path: [ 'width' ], key: 'value' }, }; export const LINK_COLOR = '--wp--style--color--link'; export const LINK_COLOR_DECLARATION = `a { color: var(${ LINK_COLOR }, #00e); }`; diff --git a/phpunit/class-block-supported-styles-test.php b/phpunit/class-block-supported-styles-test.php index 5201cf000d160..262f6c49d0311 100644 --- a/phpunit/class-block-supported-styles-test.php +++ b/phpunit/class-block-supported-styles-test.php @@ -572,62 +572,6 @@ function test_block_alignment_unsupported() { $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } - /** - * Tests width support - */ - function test_width() { - $block_type_settings = array( - 'attributes' => array(), - 'supports' => array( - '__experimentalWidth' => true, - ), - 'render_callback' => true, - ); - $this->register_block_type( 'core/example', $block_type_settings ); - - $block = array( - 'blockName' => 'core/example', - 'attrs' => array( - 'style' => array( 'width' => '75%' ), - ), - 'innerBlock' => array(), - 'innerContent' => array(), - 'innerHTML' => array(), - ); - - $expected_classes = 'foo-bar-class wp-block-example custom-width'; - $expected_styles = 'test: style; width: 75%;'; - - $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); - } - - /** - * Tests width not applied without support flag. - */ - function test_border_radius_unsupported() { - $block_type_settings = array( - 'attributes' => array(), - 'supports' => array(), - 'render_callback' => true, - ); - $this->register_block_type( 'core/example', $block_type_settings ); - - $block = array( - 'blockName' => 'core/example', - 'attrs' => array( - 'style' => array( 'width' => '75%' ), - ), - 'innerBlock' => array(), - 'innerContent' => array(), - 'innerHTML' => array(), - ); - - $expected_classes = 'foo-bar-class wp-block-example'; - $expected_styles = 'test: style;'; - - $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); - } - /** * Tests all support flags together to ensure they work together as expected. */ @@ -635,14 +579,13 @@ function test_all_supported() { $block_type_settings = array( 'attributes' => array(), 'supports' => array( - 'color' => array( + 'color' => array( 'gradients' => true, 'link' => true, ), 'fontSize' => true, 'lineHeight' => true, 'align' => true, - '__experimentalWidth' => true, ), ); $this->register_block_type( 'core/example', $block_type_settings ); @@ -661,7 +604,6 @@ function test_all_supported() { 'lineHeight' => '20', 'fontSize' => '10', ), - 'width' => '75%' ), ), 'innerBlock' => array(), @@ -669,13 +611,8 @@ function test_all_supported() { 'innerHTML' => array(), ); -<<<<<<< HEAD $expected_classes = 'foo-bar-class wp-block-example has-text-color has-background alignwide'; - $expected_styles = 'test: style; color: #000; background-color: #fff; font-size: 10px; line-height: 20;'; -======= - $expected_classes = 'foo-bar-class wp-block-example has-text-color has-background alignwide custom-width'; - $expected_styles = 'test: style; color: #000; background-color: #fff; background: some-gradient; font-size: 10px; line-height: 20; width: 75%;'; ->>>>>>> 6719847199... Add tests for block support + $expected_styles = 'test: style; color: #000; background-color: #fff; background: some-gradient; font-size: 10px; line-height: 20;'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } From abed04ad0fa2dc8c37db6854b4d7e9756c19a71a Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Thu, 15 Oct 2020 15:35:22 -0700 Subject: [PATCH 08/14] Nest width into dimension settings Nesting width into a dimension setting allows for the addition of related settings (height etc) in the future. --- lib/block-supports/dimensions.php | 47 +++++++++++++++++++ lib/block-supports/index.php | 2 +- lib/block-supports/width.php | 31 ------------ lib/experimental-default-theme.json | 46 +++++++++--------- lib/global-styles.php | 11 ++--- .../src/components/width-control/index.js | 2 +- .../src/hooks/{width.js => dimensions.js} | 40 +++++++++++----- packages/block-editor/src/hooks/style.js | 6 +-- packages/block-library/src/button/block.json | 4 +- packages/blocks/src/api/constants.js | 2 +- .../edit-site/src/components/editor/utils.js | 2 +- 11 files changed, 113 insertions(+), 80 deletions(-) create mode 100644 lib/block-supports/dimensions.php delete mode 100644 lib/block-supports/width.php rename packages/block-editor/src/hooks/{width.js => dimensions.js} (63%) diff --git a/lib/block-supports/dimensions.php b/lib/block-supports/dimensions.php new file mode 100644 index 0000000000000..20482368de786 --- /dev/null +++ b/lib/block-supports/dimensions.php @@ -0,0 +1,47 @@ +attributes ) { + $block_type->attributes = array(); + } + + if ( $has_width_support && ! array_key_exists( 'style', $block_type->attributes ) ) { + $block_type->attributes['style'] = array( + 'type' => 'object', + ); + } +} + +/** + * Checks whether the current block type supports the experimental feature + * requested. + * + * @param WP_Block_Type $block_type Block type to check for support. + * @param string $feature Name of the feature to check support for. + * @param mixed $default Fallback value for feature support, defaults to false. + * + * @return boolean Whether or not the feature is supported. + */ +function gutenberg_has_dimensions_support( $block_type, $feature, $default = false ) { + $block_support = false; + if ( property_exists( $block_type, 'supports' ) ) { + $block_support = gutenberg_experimental_get( $block_type->supports, array( '__experimentalDimensions' ), $default ); + } + + return true === $block_support || ( is_array( $block_support ) && gutenberg_experimental_get( $block_support, array( $feature ), false ) ); +} diff --git a/lib/block-supports/index.php b/lib/block-supports/index.php index 3dfacaa5c6f8e..574c7ca920184 100644 --- a/lib/block-supports/index.php +++ b/lib/block-supports/index.php @@ -18,7 +18,7 @@ function gutenberg_register_block_supports() { gutenberg_register_colors_support( $block_type ); gutenberg_register_typography_support( $block_type ); gutenberg_register_custom_classname_support( $block_type ); - gutenberg_register_width_support( $block_type ); + gutenberg_register_dimensions_support( $block_type ); } } diff --git a/lib/block-supports/width.php b/lib/block-supports/width.php deleted file mode 100644 index 97af1745afe8a..0000000000000 --- a/lib/block-supports/width.php +++ /dev/null @@ -1,31 +0,0 @@ -supports, array( '__experimentalWidth' ), false ); - } - - // Setup attributes and styles within that if needed. - if ( ! $block_type->attributes ) { - $block_type->attributes = array(); - } - - if ( $has_width_support && ! array_key_exists( 'style', $block_type->attributes ) ) { - $block_type->attributes['style'] = array( - 'type' => 'object', - ); - } -} diff --git a/lib/experimental-default-theme.json b/lib/experimental-default-theme.json index 4e734b97623d2..069e5a1c436b2 100644 --- a/lib/experimental-default-theme.json +++ b/lib/experimental-default-theme.json @@ -166,28 +166,30 @@ "customPadding": false, "units": [ "px", "em", "rem", "vh", "vw" ] }, - "width": [ - { - "name": "25%", - "slug": "25", - "value": "25%" - }, - { - "name": "50%", - "slug": "50", - "value": "50%" - }, - { - "name": "75%", - "slug": "75", - "value": "75%" - }, - { - "name": "100%", - "slug": "100", - "value": "100%" - } - ] + "dimensions": { + "width": [ + { + "name": "25%", + "slug": "25", + "value": "25%" + }, + { + "name": "50%", + "slug": "50", + "value": "50%" + }, + { + "name": "75%", + "slug": "75", + "value": "75%" + }, + { + "name": "100%", + "slug": "100", + "value": "100%" + } + ] + } } } } diff --git a/lib/global-styles.php b/lib/global-styles.php index d1e89dbf75ead..592adaf8f662d 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -389,8 +389,6 @@ function gutenberg_experimental_global_styles_get_css_property( $style_property return 'font-size'; case 'lineHeight': return 'line-height'; - case 'width': - return 'width'; default: return $style_property; } @@ -409,7 +407,7 @@ function gutenberg_experimental_global_styles_get_style_property() { 'color' => array( 'color', 'text' ), 'fontSize' => array( 'typography', 'fontSize' ), 'lineHeight' => array( 'typography', 'lineHeight' ), - 'width' => array( 'width' ), + 'width' => array( 'dimensions', 'width' ), ); } @@ -426,7 +424,7 @@ function gutenberg_experimental_global_styles_get_support_keys() { 'color' => array( 'color' ), 'fontSize' => array( 'fontSize' ), 'lineHeight' => array( 'lineHeight' ), - 'width' => array( '__experimentalWidth' ), + 'width' => array( '__experimentalDimensions', 'width' ), ); } @@ -450,7 +448,7 @@ function gutenberg_experimental_global_styles_get_presets_structure() { 'key' => 'size', ), 'width' => array( - 'path' => array( 'width' ), + 'path' => array( 'dimensions', 'width' ), 'key' => 'value', ), ); @@ -821,14 +819,13 @@ function gutenberg_experimental_global_styles_normalize_schema( $tree ) { 'styles' => array( 'typography' => array(), 'color' => array(), - 'width' => array(), ), 'settings' => array( 'color' => array(), 'custom' => array(), 'typography' => array(), 'spacing' => array(), - 'width' => array(), + 'dimensions' => array(), ), ); diff --git a/packages/block-editor/src/components/width-control/index.js b/packages/block-editor/src/components/width-control/index.js index d75aac0b613aa..5fbb587899bde 100644 --- a/packages/block-editor/src/components/width-control/index.js +++ b/packages/block-editor/src/components/width-control/index.js @@ -49,7 +49,7 @@ export default function WidthControl( { isPrimary={ selectedWidth === widthOption.slug } onClick={ () => handleChange( widthOption.slug ) } > - { widthOption.slug } + { widthOption.value } ); } ) } diff --git a/packages/block-editor/src/hooks/width.js b/packages/block-editor/src/hooks/dimensions.js similarity index 63% rename from packages/block-editor/src/hooks/width.js rename to packages/block-editor/src/hooks/dimensions.js index b570bcbb423b4..06ca8dbcdfa61 100644 --- a/packages/block-editor/src/hooks/width.js +++ b/packages/block-editor/src/hooks/dimensions.js @@ -17,31 +17,34 @@ import WidthControl from '../components/width-control'; * Key within block settings' supports array indicating support for * width, e.g. settings found in 'block.json'. */ -export const WIDTH_SUPPORT_KEY = '__experimentalWidth'; +export const DIMENSIONS_SUPPORT_KEY = '__experimentalDimensions'; -export function WidthPanel( props ) { +export function DimensionsPanel( props ) { const { attributes: { style }, setAttributes, } = props; - const widthOptions = useEditorFeature( 'width' ); - const isDisabled = useIsWidthDisabled( props ); + const widthOptions = useEditorFeature( 'dimensions.width' ); + const isEnabled = useIsWidthEnabled( props ); - if ( isDisabled ) { + if ( ! isEnabled ) { return null; } const selectedWidth = getWidthFromAttributeValue( widthOptions, - style?.width + style?.dimensions?.width ); function onChange( newWidth ) { setAttributes( { style: cleanEmptyObject( { ...style, - width: newWidth, + dimensions: { + ...style?.dimensions, + width: newWidth, + }, } ), } ); } @@ -60,18 +63,31 @@ export function WidthPanel( props ) { } /** - * Checks if width support has been disabled + * Checks if there is block support for width. * * @param {string|Object} blockType Block name or Block Type object. * @return {boolean} Whether there is support. */ -export function useIsWidthDisabled( { name: blockName } = {} ) { - const notSupported = ! hasBlockSupport( blockName, WIDTH_SUPPORT_KEY ); +export function hasWidthSupport( blockName ) { + const support = hasBlockSupport( blockName, DIMENSIONS_SUPPORT_KEY ); - const widthOptions = useEditorFeature( 'width' ); + // Further dimension properties to be added in future iterations. + // e.g. support && ( support.width || support.height ) + return true === support || ( support && support.width ); +} + +/** + * Checks if width is supported and has not been disabled. + * + * @param {string|Object} blockType Block name or Block Type object. + * @return {boolean} Whether there is support. + */ +export function useIsWidthEnabled( { name: blockName } = {} ) { + const supported = hasWidthSupport( blockName ); + const widthOptions = useEditorFeature( 'dimensions.width' ); const hasWidthOptions = !! widthOptions?.length; - return notSupported || ! hasWidthOptions; + return supported && hasWidthOptions; } /** diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index 0f550a6f90a50..a91be3f94ccf2 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -20,13 +20,13 @@ import { COLOR_SUPPORT_KEY, ColorEdit } from './color'; import { TypographyPanel, TYPOGRAPHY_SUPPORT_KEYS } from './typography'; import { SPACING_SUPPORT_KEY, PaddingEdit } from './padding'; import SpacingPanelControl from '../components/spacing-panel-control'; -import { WIDTH_SUPPORT_KEY, WidthPanel } from './width'; +import { DIMENSIONS_SUPPORT_KEY, DimensionsPanel } from './dimensions'; const styleSupportKeys = [ ...TYPOGRAPHY_SUPPORT_KEYS, COLOR_SUPPORT_KEY, SPACING_SUPPORT_KEY, - WIDTH_SUPPORT_KEY, + DIMENSIONS_SUPPORT_KEY, ]; const hasStyleSupport = ( blockType ) => @@ -158,7 +158,7 @@ export const withBlockControls = createHigherOrderComponent( return [ , , - , + , , hasSpacingSupport && ( diff --git a/packages/block-library/src/button/block.json b/packages/block-library/src/button/block.json index 195e61a9b3de9..38816c479af54 100644 --- a/packages/block-library/src/button/block.json +++ b/packages/block-library/src/button/block.json @@ -60,6 +60,8 @@ "alignWide": false, "reusable": false, "__experimentalSelector": ".wp-block-button > a", - "__experimentalWidth": true + "__experimentalDimensions": { + "width": true + } } } diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js index fe8aea745c486..7bbfc0f451d69 100644 --- a/packages/blocks/src/api/constants.js +++ b/packages/blocks/src/api/constants.js @@ -23,5 +23,5 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = { paddingLeft: [ 'spacing', 'padding', 'left' ], paddingRight: [ 'spacing', 'padding', 'right' ], paddingTop: [ 'spacing', 'padding', 'top' ], - width: [ 'width' ], + width: [ 'dimensions', 'width' ], }; diff --git a/packages/edit-site/src/components/editor/utils.js b/packages/edit-site/src/components/editor/utils.js index cb34670b46c44..0bc1b60bb5af3 100644 --- a/packages/edit-site/src/components/editor/utils.js +++ b/packages/edit-site/src/components/editor/utils.js @@ -4,7 +4,7 @@ export const PRESET_CATEGORIES = { color: { path: [ 'color', 'palette' ], key: 'color' }, gradient: { path: [ 'color', 'gradients' ], key: 'gradient' }, fontSize: { path: [ 'typography', 'fontSizes' ], key: 'size' }, - width: { path: [ 'width' ], key: 'value' }, + width: { path: [ 'dimensions', 'width' ], key: 'value' }, }; export const LINK_COLOR = '--wp--style--color--link'; export const LINK_COLOR_DECLARATION = `a { color: var(${ LINK_COLOR }, #00e); }`; From ab288cfe211641d6a5421ef37a0ec71482b3e71f Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Mon, 19 Oct 2020 11:11:08 -0700 Subject: [PATCH 09/14] Add button block deprecation Adding a block support using CSS variables to the Button block causes the inline style to be added to the button's wrapper div as well as the inner anchor tag. This causes Block Invalidation errors for existing posts, as well as for any patterns that use the Button block. These errors are resolved with a deprecation that omits the block support. Once opened in the block editor they migrate cleanly. --- .../block-library/src/button/deprecated.js | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/packages/block-library/src/button/deprecated.js b/packages/block-library/src/button/deprecated.js index 110807907fc3c..db1e72e303257 100644 --- a/packages/block-library/src/button/deprecated.js +++ b/packages/block-library/src/button/deprecated.js @@ -10,9 +10,15 @@ import classnames from 'classnames'; import { RichText, getColorClassName, + useBlockProps, __experimentalGetGradientClass, } from '@wordpress/block-editor'; +/** + * Internal dependencies + */ +import getColorAndStyleProps from './color-props'; + const migrateCustomColorsAndGradients = ( attributes ) => { if ( ! attributes.customTextColor && @@ -81,6 +87,85 @@ const blockAttributes = { }; const deprecated = [ + { + supports: { + anchor: true, + align: true, + alignWide: false, + reusable: false, + __experimentalSelector: '.wp-block-button > a', + }, + attributes: { + ...blockAttributes, + linkTarget: { + type: 'string', + source: 'attribute', + selector: 'a', + attribute: 'target', + }, + rel: { + type: 'string', + source: 'attribute', + selector: 'a', + attribute: 'rel', + }, + placeholder: { + type: 'string', + }, + borderRadius: { + type: 'number', + }, + backgroundColor: { + type: 'string', + }, + textColor: { + type: 'string', + }, + gradient: { + type: 'string', + }, + style: { + type: 'object', + }, + }, + save( { attributes } ) { + const { + borderRadius, + linkTarget, + rel, + text, + title, + url, + } = attributes; + const colorProps = getColorAndStyleProps( attributes ); + const buttonClasses = classnames( + 'wp-block-button__link', + colorProps.className, + { + 'no-border-radius': borderRadius === 0, + } + ); + const buttonStyle = { + borderRadius: borderRadius ? borderRadius + 'px' : undefined, + ...colorProps.style, + }; + + return ( +
+ +
+ ); + }, + }, { supports: { align: true, From 4cfd6f30de349863153ab57a7f9e7f5dace0e5e5 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Mon, 19 Oct 2020 12:01:34 -0700 Subject: [PATCH 10/14] Remove file not deleted in rebase Fix up an incorrectly applied rebase. --- lib/block-supports/index.php | 131 ------------------ phpunit/class-block-supported-styles-test.php | 6 +- 2 files changed, 3 insertions(+), 134 deletions(-) delete mode 100644 lib/block-supports/index.php diff --git a/lib/block-supports/index.php b/lib/block-supports/index.php deleted file mode 100644 index 574c7ca920184..0000000000000 --- a/lib/block-supports/index.php +++ /dev/null @@ -1,131 +0,0 @@ -get_all_registered(); - // Ideally we need a hook to extend the block registration - // instead of mutating the block type. - foreach ( $registered_block_types as $block_type ) { - gutenberg_register_alignment_support( $block_type ); - gutenberg_register_colors_support( $block_type ); - gutenberg_register_typography_support( $block_type ); - gutenberg_register_custom_classname_support( $block_type ); - gutenberg_register_dimensions_support( $block_type ); - } -} - -add_action( 'init', 'gutenberg_register_block_supports', 21 ); - -/** - * Filters the frontend output of blocks and apply the block support flags transformations. - * - * @param string $block_content rendered block content. - * @param array $block block object. - * @return string filtered block content. - */ -function gutenberg_apply_block_supports( $block_content, $block ) { - if ( ! isset( $block['attrs'] ) ) { - return $block_content; - } - - $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); - // If no render_callback, assume styles have been previously handled. - if ( ! $block_type || ! $block_type->render_callback ) { - return $block_content; - } - - $attributes = array(); - $attributes = gutenberg_apply_generated_classname_support( $attributes, $block['attrs'], $block_type ); - $attributes = gutenberg_apply_colors_support( $attributes, $block['attrs'], $block_type ); - $attributes = gutenberg_apply_typography_support( $attributes, $block['attrs'], $block_type ); - $attributes = gutenberg_apply_alignment_support( $attributes, $block['attrs'], $block_type ); - $attributes = gutenberg_apply_custom_classname_support( $attributes, $block['attrs'], $block_type ); - - if ( ! count( $attributes ) ) { - return $block_content; - } - - $dom = new DOMDocument( '1.0', 'utf-8' ); - - // Suppress DOMDocument::loadHTML warnings from polluting the front-end. - $previous = libxml_use_internal_errors( true ); - - // We need to wrap the block in order to handle UTF-8 properly. - $wrapped_block_html = - '' - . $block_content - . ''; - - $success = $dom->loadHTML( $wrapped_block_html, LIBXML_HTML_NODEFDTD | LIBXML_COMPACT ); - - // Clear errors and reset the use_errors setting. - libxml_clear_errors(); - libxml_use_internal_errors( $previous ); - - if ( ! $success ) { - return $block_content; - } - - // Structure is like ``, so body is the `lastChild` of our document. - $body_element = $dom->documentElement->lastChild; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - - $xpath = new DOMXPath( $dom ); - $block_root = $xpath->query( './*', $body_element )[0]; - - // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - if ( empty( $block_root ) ) { - return $block_content; - } - - // Merge and dedupe new and existing classes and styles. - $current_classes = explode( ' ', trim( $block_root->getAttribute( 'class' ) ) ); - $classes_to_add = array_key_exists( 'css_classes', $attributes ) ? $attributes['css_classes'] : array(); - $new_classes = array_unique( array_filter( array_merge( $current_classes, $classes_to_add ) ) ); - - $current_styles = preg_split( '/\s*;\s*/', trim( $block_root->getAttribute( 'style' ) ) ); - $styles_to_add = array_key_exists( 'inline_styles', $attributes ) ? $attributes['inline_styles'] : array(); - $new_styles = array_unique( array_map( 'gutenberg_normalize_css_rule', array_filter( array_merge( $current_styles, $styles_to_add ) ) ) ); - - // Apply new styles and classes. - if ( ! empty( $new_classes ) ) { - // `DOMElement::setAttribute` handles attribute value escaping. - $block_root->setAttribute( 'class', implode( ' ', $new_classes ) ); - } - - if ( ! empty( $new_styles ) ) { - // `DOMElement::setAttribute` handles attribute value escaping. - $block_root->setAttribute( 'style', implode( '; ', $new_styles ) . ';' ); - } - - // Avoid using `$dom->saveHtml( $node )` because the node results may not produce consistent - // whitespace for PHP < 7.3. Saving the root HTML `$dom->saveHtml()` prevents this behavior. - $full_html = $dom->saveHtml(); - - // Find the open/close tags. The open tag needs to be adjusted so we get inside the tag - // and not the tag itself. - $start = strpos( $full_html, '', 0 ) + strlen( '' ); - $end = strpos( $full_html, '', $start ); - return trim( substr( $full_html, $start, $end - $start ) ); -} -add_filter( 'render_block', 'gutenberg_apply_block_supports', 10, 2 ); - -/** - * Normalizes spacing in a string representing a CSS rule - * - * @example - * 'color :red;' becomes 'color:red' - * - * @param string $css_rule_string CSS rule. - * @return string Normalized CSS rule. - */ -function gutenberg_normalize_css_rule( $css_rule_string ) { - return trim( implode( ': ', preg_split( '/\s*:\s*/', $css_rule_string, 2 ) ), ';' ); -} diff --git a/phpunit/class-block-supported-styles-test.php b/phpunit/class-block-supported-styles-test.php index 262f6c49d0311..19765f6a2b661 100644 --- a/phpunit/class-block-supported-styles-test.php +++ b/phpunit/class-block-supported-styles-test.php @@ -577,8 +577,8 @@ function test_block_alignment_unsupported() { */ function test_all_supported() { $block_type_settings = array( - 'attributes' => array(), - 'supports' => array( + 'attributes' => array(), + 'supports' => array( 'color' => array( 'gradients' => true, 'link' => true, @@ -612,7 +612,7 @@ function test_all_supported() { ); $expected_classes = 'foo-bar-class wp-block-example has-text-color has-background alignwide'; - $expected_styles = 'test: style; color: #000; background-color: #fff; background: some-gradient; font-size: 10px; line-height: 20;'; + $expected_styles = 'test: style; color: #000; background-color: #fff; font-size: 10px; line-height: 20;'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } From bcade7cb50a9874a6383e3dafce771d9a33d6eef Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Tue, 20 Oct 2020 15:25:21 -0700 Subject: [PATCH 11/14] Remove color styling from button wrapper The use of `useBlockProps` in the Button block was causing all of the block's style attributes to be applied to the button's wrapper div, including color props that were previously applied only to the inner anchor tag. When a Button has both a custom background color and a border radius, this causes and issue where the background color (applied to the wrapper) exceeds the lines of the border (applied to the inner anchor tag). This commit removes style attributes related to the color props from the blockProps before they are applied to the wrapper. This also resolves the block invalidation errors that were previously addressed by a block deprecation, so the deprecation is no longer necessary and is also removed in this commit. --- .../block-library/src/button/deprecated.js | 85 ------------------- packages/block-library/src/button/edit.js | 6 ++ packages/block-library/src/button/save.js | 9 +- 3 files changed, 14 insertions(+), 86 deletions(-) diff --git a/packages/block-library/src/button/deprecated.js b/packages/block-library/src/button/deprecated.js index db1e72e303257..110807907fc3c 100644 --- a/packages/block-library/src/button/deprecated.js +++ b/packages/block-library/src/button/deprecated.js @@ -10,15 +10,9 @@ import classnames from 'classnames'; import { RichText, getColorClassName, - useBlockProps, __experimentalGetGradientClass, } from '@wordpress/block-editor'; -/** - * Internal dependencies - */ -import getColorAndStyleProps from './color-props'; - const migrateCustomColorsAndGradients = ( attributes ) => { if ( ! attributes.customTextColor && @@ -87,85 +81,6 @@ const blockAttributes = { }; const deprecated = [ - { - supports: { - anchor: true, - align: true, - alignWide: false, - reusable: false, - __experimentalSelector: '.wp-block-button > a', - }, - attributes: { - ...blockAttributes, - linkTarget: { - type: 'string', - source: 'attribute', - selector: 'a', - attribute: 'target', - }, - rel: { - type: 'string', - source: 'attribute', - selector: 'a', - attribute: 'rel', - }, - placeholder: { - type: 'string', - }, - borderRadius: { - type: 'number', - }, - backgroundColor: { - type: 'string', - }, - textColor: { - type: 'string', - }, - gradient: { - type: 'string', - }, - style: { - type: 'object', - }, - }, - save( { attributes } ) { - const { - borderRadius, - linkTarget, - rel, - text, - title, - url, - } = attributes; - const colorProps = getColorAndStyleProps( attributes ); - const buttonClasses = classnames( - 'wp-block-button__link', - colorProps.className, - { - 'no-border-radius': borderRadius === 0, - } - ); - const buttonStyle = { - borderRadius: borderRadius ? borderRadius + 'px' : undefined, - ...colorProps.style, - }; - - return ( -
- -
- ); - }, - }, { supports: { align: true, diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 690913ea01632..93a88e8e7dbce 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -199,6 +199,12 @@ function ButtonEdit( props ) { const colorProps = getColorAndStyleProps( attributes, colors, true ); const blockProps = useBlockProps(); + // Remove colorProps from style so that they are not applied to the button's + // wrapper + for ( const key of Object.keys( colorProps.style ) ) { + delete blockProps.style[ key ]; + } + return ( <> diff --git a/packages/block-library/src/button/save.js b/packages/block-library/src/button/save.js index 2a49d4e5b87aa..63d7f4f3b098f 100644 --- a/packages/block-library/src/button/save.js +++ b/packages/block-library/src/button/save.js @@ -28,12 +28,19 @@ export default function save( { attributes } ) { ...colorProps.style, }; + const blockProps = useBlockProps.save(); + // Remove colorProps from style so that they are not applied to the button's + // wrapper + for ( const key of Object.keys( colorProps.style ) ) { + delete blockProps.style[ key ]; + } + // The use of a `title` attribute here is soft-deprecated, but still applied // if it had already been assigned, for the sake of backward-compatibility. // A title will no longer be assigned for new or updated button block links. return ( -
+
Date: Wed, 21 Oct 2020 10:44:33 -0700 Subject: [PATCH 12/14] Update docstrings to reflect refactor into dimensions feature Some docstrings still referred to the block support as just width support, and needed to be updated after refactoring into a larger dimensions feature. --- lib/block-supports/dimensions.php | 6 ++-- .../src/components/width-control/index.js | 34 +++++++++++-------- packages/block-editor/src/hooks/dimensions.js | 4 +-- packages/block-editor/src/hooks/style.js | 2 +- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/lib/block-supports/dimensions.php b/lib/block-supports/dimensions.php index 20482368de786..801c8f21f7203 100644 --- a/lib/block-supports/dimensions.php +++ b/lib/block-supports/dimensions.php @@ -1,13 +1,13 @@ - { widthOptions.map( ( widthOption ) => { - return ( - - ); - } ) } - + <> +

{ __( 'Width' ) }

+ + { widthOptions.map( ( widthOption ) => { + return ( + + ); + } ) } + + ); } diff --git a/packages/block-editor/src/hooks/dimensions.js b/packages/block-editor/src/hooks/dimensions.js index 06ca8dbcdfa61..34dc43a68fca3 100644 --- a/packages/block-editor/src/hooks/dimensions.js +++ b/packages/block-editor/src/hooks/dimensions.js @@ -15,7 +15,7 @@ import WidthControl from '../components/width-control'; /** * Key within block settings' supports array indicating support for - * width, e.g. settings found in 'block.json'. + * dimensions including width, e.g. settings found in 'block.json'. */ export const DIMENSIONS_SUPPORT_KEY = '__experimentalDimensions'; @@ -51,7 +51,7 @@ export function DimensionsPanel( props ) { return ( - + , , - , + , , hasSpacingSupport && ( From ef3379ca95f5ee1962985aa53213a5585886236f Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Thu, 22 Oct 2020 15:12:10 -0700 Subject: [PATCH 13/14] Apply inline styles for dynamic blocks Properly register the block support and apply the CSS variable inline styles for dynamic blocks that are rendered in PHP. --- lib/block-supports/dimensions.php | 67 +++++++++++++++++ phpunit/class-block-supported-styles-test.php | 72 +++++++++++++++++-- 2 files changed, 134 insertions(+), 5 deletions(-) diff --git a/lib/block-supports/dimensions.php b/lib/block-supports/dimensions.php index 801c8f21f7203..0a54063445469 100644 --- a/lib/block-supports/dimensions.php +++ b/lib/block-supports/dimensions.php @@ -27,6 +27,64 @@ function gutenberg_register_dimensions_support( $block_type ) { } } +/** + * Add CSS classes and inline styles for dimension features to the incoming attributes array. + * This will be applied to the block markup in the front-end. + * + * @param WP_Block_Type $block_type Block type. + * @param array $block_attributes Block attributes. + * + * @return array Dimensions CSS classes and inline styles. + */ +function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) { + $has_width_support = gutenberg_has_dimensions_support( $block_type, 'width' ); + $styles = array(); + + if ( $has_width_support ) { + $width_style = gutenberg_dimensions_get_css_variable_inline_style( $block_attributes, 'width', 'width' ); + if ( $width_style ) { + $styles[] = $width_style; + } + } + + $attributes = array(); + if ( ! empty( $styles ) ) { + $attributes['style'] = implode( ' ', $styles ); + } + return $attributes; +} + +/** + * Generates an inline style for a dimension feature e.g. width, height. + * + * @param array $attributes Block's attributes. + * @param string $feature Key for the feature within the dimensions styles. + * @param string $css_property Slug for the CSS property the inline style sets. + * + * @return string CSS inline style. + */ +function gutenberg_dimensions_get_css_variable_inline_style( $attributes, $feature, $css_property ) { + // Retrieve current attribute value or skip if not found. + $style_value = gutenberg_experimental_get( $attributes, array( 'style', 'dimensions', $feature ), false ); + if ( ! $style_value ) { + return; + } + + // If we don't have a preset CSS variable, we'll assume it's a regular CSS value. + if ( strpos( $style_value, "var:preset|{$css_property}|" ) === false ) { + return sprintf( '%s: %s;', $css_property, $style_value ); + } + + // We have a preset CSS variable as the style. + // Get the style value from the string and return CSS style. + $index_to_splice = strrpos( $style_value, '|' ) + 1; + $slug = substr( $style_value, $index_to_splice ); + + // Return the actual CSS inline style e.g. `text-decoration:var(--wp--preset--text-decoration--underline);`. + return sprintf( '%s: var(--wp--preset--%s--%s);', $css_property, $css_property, $slug ); +} + + /** * Checks whether the current block type supports the experimental feature * requested. @@ -45,3 +103,12 @@ function gutenberg_has_dimensions_support( $block_type, $feature, $default = fal return true === $block_support || ( is_array( $block_support ) && gutenberg_experimental_get( $block_support, array( $feature ), false ) ); } + +// Register the block support. +WP_Block_Supports::get_instance()->register( + 'dimensions', + array( + 'register_attribute' => 'gutenberg_register_dimensions_support', + 'apply' => 'gutenberg_apply_dimensions_support', + ) +); diff --git a/phpunit/class-block-supported-styles-test.php b/phpunit/class-block-supported-styles-test.php index 19765f6a2b661..4c84296f969b2 100644 --- a/phpunit/class-block-supported-styles-test.php +++ b/phpunit/class-block-supported-styles-test.php @@ -572,6 +572,64 @@ function test_block_alignment_unsupported() { $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } + /** + * Tests width support + */ + function test_width() { + $block_type_settings = array( + 'attributes' => array(), + 'supports' => array( + '__experimentalDimensions' => array( 'width' => true ), + ), + 'render_callback' => true, + ); + $this->register_block_type( 'core/example', $block_type_settings ); + + $block = array( + 'blockName' => 'core/example', + 'attrs' => array( + 'style' => array( + 'dimensions' => array( 'width' => 'var:preset|width|75' ), + ), + ), + 'innerBlock' => array(), + 'innerContent' => array(), + 'innerHTML' => array(), + ); + + $expected_classes = 'foo-bar-class wp-block-example'; + $expected_styles = 'test: style; width: var(--wp--preset--width--75);'; + + $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); + } + + /** + * Tests width not applied without support flag. + */ + function test_width_unsupported() { + $block_type_settings = array( + 'attributes' => array(), + 'supports' => array(), + 'render_callback' => true, + ); + $this->register_block_type( 'core/example', $block_type_settings ); + + $block = array( + 'blockName' => 'core/example', + 'attrs' => array( + 'style' => array( 'dimensions' => array( 'width' => 'var:preset|width|75' ) ), + ), + 'innerBlock' => array(), + 'innerContent' => array(), + 'innerHTML' => array(), + ); + + $expected_classes = 'foo-bar-class wp-block-example'; + $expected_styles = 'test: style;'; + + $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); + } + /** * Tests all support flags together to ensure they work together as expected. */ @@ -579,13 +637,16 @@ function test_all_supported() { $block_type_settings = array( 'attributes' => array(), 'supports' => array( - 'color' => array( + 'color' => array( 'gradients' => true, 'link' => true, ), - 'fontSize' => true, - 'lineHeight' => true, - 'align' => true, + 'fontSize' => true, + 'lineHeight' => true, + 'align' => true, + '__experimentalDimensions' => array( + 'width' => true, + ), ), ); $this->register_block_type( 'core/example', $block_type_settings ); @@ -604,6 +665,7 @@ function test_all_supported() { 'lineHeight' => '20', 'fontSize' => '10', ), + 'dimensions' => array( 'width' => 'var:preset|width|75' ), ), ), 'innerBlock' => array(), @@ -612,7 +674,7 @@ function test_all_supported() { ); $expected_classes = 'foo-bar-class wp-block-example has-text-color has-background alignwide'; - $expected_styles = 'test: style; color: #000; background-color: #fff; font-size: 10px; line-height: 20;'; + $expected_styles = 'test: style; color: #000; background-color: #fff; font-size: 10px; line-height: 20; width: var(--wp--preset--width--75);'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } From 34febe6462fc46675de680db497c3be8248f9886 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Thu, 22 Oct 2020 15:20:05 -0700 Subject: [PATCH 14/14] Update Button to use block supports and apply styling at block level Because block supports implemented with CSS variables add styling to the outermost element of a block, this commit updates the Button block to expect styling to be applied at this level, rather than directly setting it on the inner component. This is accomplished by: 1. Updates the CSS so that the inner button will always inherit color, background-color, and border-radius styling that was applied inline to its wrapper. This only happens when a user has selected an option from a block support, so we can reliably override any other styling applied by defaults or the theme. 2. Adds a deprecation for the Button block since styling is now applied differently. 3. Removes the block-specific implementation of Color settings and instead applies the color block support. 4. Temporarily manually applies the border-radius to the wrapper. There is a PR for a border radius block support, which can be used to replace this. --- packages/block-library/src/button/block.json | 3 + .../block-library/src/button/deprecated.js | 85 +++++++++++++++++++ packages/block-library/src/button/edit.js | 31 ++----- packages/block-library/src/button/save.js | 32 ++----- packages/block-library/src/button/style.scss | 19 +++++ 5 files changed, 123 insertions(+), 47 deletions(-) diff --git a/packages/block-library/src/button/block.json b/packages/block-library/src/button/block.json index 38816c479af54..5d719856f7619 100644 --- a/packages/block-library/src/button/block.json +++ b/packages/block-library/src/button/block.json @@ -62,6 +62,9 @@ "__experimentalSelector": ".wp-block-button > a", "__experimentalDimensions": { "width": true + }, + "color": { + "gradients": true } } } diff --git a/packages/block-library/src/button/deprecated.js b/packages/block-library/src/button/deprecated.js index 110807907fc3c..db1e72e303257 100644 --- a/packages/block-library/src/button/deprecated.js +++ b/packages/block-library/src/button/deprecated.js @@ -10,9 +10,15 @@ import classnames from 'classnames'; import { RichText, getColorClassName, + useBlockProps, __experimentalGetGradientClass, } from '@wordpress/block-editor'; +/** + * Internal dependencies + */ +import getColorAndStyleProps from './color-props'; + const migrateCustomColorsAndGradients = ( attributes ) => { if ( ! attributes.customTextColor && @@ -81,6 +87,85 @@ const blockAttributes = { }; const deprecated = [ + { + supports: { + anchor: true, + align: true, + alignWide: false, + reusable: false, + __experimentalSelector: '.wp-block-button > a', + }, + attributes: { + ...blockAttributes, + linkTarget: { + type: 'string', + source: 'attribute', + selector: 'a', + attribute: 'target', + }, + rel: { + type: 'string', + source: 'attribute', + selector: 'a', + attribute: 'rel', + }, + placeholder: { + type: 'string', + }, + borderRadius: { + type: 'number', + }, + backgroundColor: { + type: 'string', + }, + textColor: { + type: 'string', + }, + gradient: { + type: 'string', + }, + style: { + type: 'object', + }, + }, + save( { attributes } ) { + const { + borderRadius, + linkTarget, + rel, + text, + title, + url, + } = attributes; + const colorProps = getColorAndStyleProps( attributes ); + const buttonClasses = classnames( + 'wp-block-button__link', + colorProps.className, + { + 'no-border-radius': borderRadius === 0, + } + ); + const buttonStyle = { + borderRadius: borderRadius ? borderRadius + 'px' : undefined, + ...colorProps.style, + }; + + return ( +
+ +
+ ); + }, + }, { supports: { align: true, diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 93a88e8e7dbce..95a2bfc2e9e21 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -24,25 +24,16 @@ import { RichText, useBlockProps, __experimentalLinkControl as LinkControl, - __experimentalUseEditorFeature as useEditorFeature, } from '@wordpress/block-editor'; import { rawShortcut, displayShortcut } from '@wordpress/keycodes'; import { link, linkOff } from '@wordpress/icons'; import { createBlock } from '@wordpress/blocks'; -/** - * Internal dependencies - */ -import ColorEdit from './color-edit'; -import getColorAndStyleProps from './color-props'; - const NEW_TAB_REL = 'noreferrer noopener'; const MIN_BORDER_RADIUS_VALUE = 0; const MAX_BORDER_RADIUS_VALUE = 50; const INITIAL_BORDER_RADIUS_POSITION = 5; -const EMPTY_ARRAY = []; - function BorderPanel( { borderRadius = '', setAttributes } ) { const initialBorderRadius = borderRadius; const setBorderRadius = useCallback( @@ -175,7 +166,6 @@ function ButtonEdit( props ) { }, [ setAttributes ] ); - const colors = useEditorFeature( 'color.palette' ) || EMPTY_ARRAY; const onToggleOpenInNewTab = useCallback( ( value ) => { @@ -196,18 +186,18 @@ function ButtonEdit( props ) { [ rel, setAttributes ] ); - const colorProps = getColorAndStyleProps( attributes, colors, true ); const blockProps = useBlockProps(); - // Remove colorProps from style so that they are not applied to the button's - // wrapper - for ( const key of Object.keys( colorProps.style ) ) { - delete blockProps.style[ key ]; - } + // Temporarily, we need to add the border radius to the blockProps so + // that it is applied at the block level. This can be replaced by using + // the border radius block support. + blockProps.style = { + ...blockProps.style, + borderRadius: borderRadius ? borderRadius + 'px' : undefined, + }; return ( <> -
createBlock( 'core/button', { ...attributes, diff --git a/packages/block-library/src/button/save.js b/packages/block-library/src/button/save.js index 63d7f4f3b098f..e169e1a81e693 100644 --- a/packages/block-library/src/button/save.js +++ b/packages/block-library/src/button/save.js @@ -8,33 +8,20 @@ import classnames from 'classnames'; */ import { RichText, useBlockProps } from '@wordpress/block-editor'; -/** - * Internal dependencies - */ -import getColorAndStyleProps from './color-props'; - export default function save( { attributes } ) { const { borderRadius, linkTarget, rel, text, title, url } = attributes; - const colorProps = getColorAndStyleProps( attributes ); - const buttonClasses = classnames( - 'wp-block-button__link', - colorProps.className, - { - 'no-border-radius': borderRadius === 0, - } - ); - const buttonStyle = { + const buttonClasses = classnames( 'wp-block-button__link', { + 'no-border-radius': borderRadius === 0, + } ); + const blockProps = useBlockProps.save(); + // Temporarily, we need to add the border radius to the blockProps so + // that it is applied at the block level. This can be replaced by using + // the border radius block support. + blockProps.style = { + ...blockProps.style, borderRadius: borderRadius ? borderRadius + 'px' : undefined, - ...colorProps.style, }; - const blockProps = useBlockProps.save(); - // Remove colorProps from style so that they are not applied to the button's - // wrapper - for ( const key of Object.keys( colorProps.style ) ) { - delete blockProps.style[ key ]; - } - // The use of a `title` attribute here is soft-deprecated, but still applied // if it had already been assigned, for the sake of backward-compatibility. // A title will no longer be assigned for new or updated button block links. @@ -46,7 +33,6 @@ export default function save( { attributes } ) { className={ buttonClasses } href={ url } title={ title } - style={ buttonStyle } value={ text } target={ linkTarget } rel={ rel } diff --git a/packages/block-library/src/button/style.scss b/packages/block-library/src/button/style.scss index e674899748acf..6747d42bf73db 100644 --- a/packages/block-library/src/button/style.scss +++ b/packages/block-library/src/button/style.scss @@ -1,5 +1,24 @@ $blocks-button__height: 3.1em; +// If a custom style has been applied to the wrapper via block +// support, inherit it in the button +.wp-block-buttons > .wp-block-button { + &.has-text-color .wp-block-button__link { + color: inherit; + } + + &.has-background { + display: inline-block; + .wp-block-button__link { + background-color: inherit; + } + } + + &[style*="border-radius:"] .wp-block-button__link { + border-radius: inherit; + } +} + // Prefer the link selector instead of the regular button classname // to support the previous markup in addition to the new one. .wp-block-button__link {