From 2bef26afb3d198e85badcbb020aa9f17fe008f6b Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Sun, 18 Jun 2023 18:41:34 +1000 Subject: [PATCH 1/7] Global Styles: Add default border style when applying block styles globally --- .../push-changes-to-global-styles/index.js | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index e481606524f60..6483c6451a2b6 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -105,27 +105,33 @@ const getValueFromObjectPath = ( object, path ) => { function useChangesToPush( name, attributes ) { const supports = useSupportedStyles( name ); - return useMemo( - () => - supports.flatMap( ( key ) => { - if ( ! STYLE_PROPERTY[ key ] ) { - return []; - } - const { value: path } = STYLE_PROPERTY[ key ]; - const presetAttributeKey = path.join( '.' ); - const presetAttributeValue = - attributes[ - STYLE_PATH_TO_PRESET_BLOCK_ATTRIBUTE[ - presetAttributeKey - ] - ]; - const value = presetAttributeValue - ? `var:preset|${ STYLE_PATH_TO_CSS_VAR_INFIX[ presetAttributeKey ] }|${ presetAttributeValue }` - : getValueFromObjectPath( attributes.style, path ); - return value ? [ { path, value } ] : []; - } ), - [ supports, attributes ] - ); + return useMemo( () => { + const changes = supports.flatMap( ( key ) => { + if ( ! STYLE_PROPERTY[ key ] ) { + return []; + } + const { value: path } = STYLE_PROPERTY[ key ]; + const presetAttributeKey = path.join( '.' ); + const presetAttributeValue = + attributes[ + STYLE_PATH_TO_PRESET_BLOCK_ATTRIBUTE[ presetAttributeKey ] + ]; + const value = presetAttributeValue + ? `var:preset|${ STYLE_PATH_TO_CSS_VAR_INFIX[ presetAttributeKey ] }|${ presetAttributeValue }` + : getValueFromObjectPath( attributes.style, path ); + return value ? [ { path, value } ] : []; + } ); + + // To ensure display of a visible border, global styles require a + // default border style if a border color or width is present. + const { color, style, width } = attributes.style?.border || {}; + + if ( ( color || width ) && ! style ) { + changes.push( { path: [ 'border', 'style' ], value: 'solid' } ); + } + + return changes; + }, [ supports, attributes ] ); } /** @@ -269,7 +275,19 @@ function PushChangesToGlobalStylesControl( { } ); } - }, [ changes, attributes, userConfig, name ] ); + }, [ + __unstableMarkNextChangeAsNotPersistent, + attributes, + changes, + createSuccessNotice, + inheritedBehaviors, + name, + setAttributes, + setBehavior, + setUserConfig, + userConfig, + userHasEditedBehaviors, + ] ); return ( Date: Sun, 18 Jun 2023 19:36:46 +1000 Subject: [PATCH 2/7] Fix application and clearing of presets --- .../hooks/push-changes-to-global-styles/index.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 6483c6451a2b6..c78a010b1d46b 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -36,6 +36,7 @@ const { // removed by moving PushChangesToGlobalStylesControl to // @wordpress/block-editor. const STYLE_PATH_TO_CSS_VAR_INFIX = { + 'border.color': 'color', 'color.background': 'color', 'color.text': 'color', 'elements.link.color.text': 'color', @@ -85,6 +86,7 @@ const STYLE_PATH_TO_CSS_VAR_INFIX = { // removed by moving PushChangesToGlobalStylesControl to // @wordpress/block-editor. const STYLE_PATH_TO_PRESET_BLOCK_ATTRIBUTE = { + 'border.color': 'borderColor', 'color.background': 'backgroundColor', 'color.text': 'textColor', 'color.gradient': 'gradient', @@ -219,12 +221,22 @@ function PushChangesToGlobalStylesControl( { ); } + const newBlockAttributes = { + borderColor: undefined, + backgroundColor: undefined, + textColor: undefined, + gradient: undefined, + fontSize: undefined, + fontFamily: undefined, + style: newBlockStyles, + }; + // @wordpress/core-data doesn't support editing multiple entity types in // a single undo level. So for now, we disable @wordpress/core-data undo // tracking and implement our own Undo button in the snackbar // notification. __unstableMarkNextChangeAsNotPersistent(); - setAttributes( { style: newBlockStyles } ); + setAttributes( newBlockAttributes ); setUserConfig( () => newUserConfig, { undoIgnore: true } ); createSuccessNotice( sprintf( @@ -239,7 +251,7 @@ function PushChangesToGlobalStylesControl( { label: __( 'Undo' ), onClick() { __unstableMarkNextChangeAsNotPersistent(); - setAttributes( { style: blockStyles } ); + setAttributes( attributes ); setUserConfig( () => userConfig, { undoIgnore: true, } ); From 26d8df22b527e6b268aa21236f9aeca980b33eeb Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 19 Jun 2023 15:21:05 +1000 Subject: [PATCH 3/7] Apply default border style for preset border color --- .../edit-site/src/hooks/push-changes-to-global-styles/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index c78a010b1d46b..3060a3ff812ba 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -78,6 +78,7 @@ const STYLE_PATH_TO_CSS_VAR_INFIX = { 'elements.h6.typography.fontFamily': 'font-family', 'elements.h6.color.gradient': 'gradient', 'color.gradient': 'gradient', + 'spacing.blockGap': 'spacing', 'typography.fontSize': 'font-size', 'typography.fontFamily': 'font-family', }; @@ -128,7 +129,7 @@ function useChangesToPush( name, attributes ) { // default border style if a border color or width is present. const { color, style, width } = attributes.style?.border || {}; - if ( ( color || width ) && ! style ) { + if ( ( attributes.borderColor || color || width ) && ! style ) { changes.push( { path: [ 'border', 'style' ], value: 'solid' } ); } From c3066c4fe9880d27b8e9ab282935907277bde1c0 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 19 Jun 2023 16:14:55 +1000 Subject: [PATCH 4/7] Fix pushing of split border styles --- .../push-changes-to-global-styles/index.js | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 3060a3ff812ba..0a8401bac6caf 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -105,6 +105,44 @@ const getValueFromObjectPath = ( object, path ) => { return value; }; +function getBorderStyleChanges( border, presetColor ) { + if ( ! border && ! presetColor ) { + return []; + } + + const changes = [ + ...getFallbackBorderStyleChange( border?.top, 'top' ), + ...getFallbackBorderStyleChange( border?.right, 'right' ), + ...getFallbackBorderStyleChange( border?.bottom, 'bottom' ), + ...getFallbackBorderStyleChange( border?.left, 'left' ), + ]; + + // Handle a flat border i.e. all sides the same, CSS shorthand. + const { color: customColor, style, width } = border || {}; + const hasColorOrWidth = presetColor || customColor || width; + + if ( hasColorOrWidth && ! style ) { + changes.push( { path: [ 'border', 'style' ], value: 'solid' } ); + } + + return changes; +} + +function getFallbackBorderStyleChange( border, side ) { + if ( ! border ) { + return []; + } + + const { color, style, width } = border; + const hasColorOrWidth = color || width; + + if ( ! hasColorOrWidth || style ) { + return []; + } + + return [ { path: [ 'border', side, 'style' ], value: 'solid' } ]; +} + function useChangesToPush( name, attributes ) { const supports = useSupportedStyles( name ); @@ -127,11 +165,10 @@ function useChangesToPush( name, attributes ) { // To ensure display of a visible border, global styles require a // default border style if a border color or width is present. - const { color, style, width } = attributes.style?.border || {}; - - if ( ( attributes.borderColor || color || width ) && ! style ) { - changes.push( { path: [ 'border', 'style' ], value: 'solid' } ); - } + getBorderStyleChanges( + attributes.style?.border, + attributes.borderColor + ).forEach( ( change ) => changes.push( change ) ); return changes; }, [ supports, attributes ] ); From 9376d7658b1658c974676dcc6391c56bc572d0e4 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 19 Jun 2023 18:24:06 +1000 Subject: [PATCH 5/7] Fix application of block border styles over existing global styles --- .../push-changes-to-global-styles/index.js | 62 ++++++++++++++----- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 0a8401bac6caf..ea82da9be99a1 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -27,6 +27,7 @@ import { useSupportedStyles } from '../../components/global-styles/hooks'; import { unlock } from '../../lock-unlock'; const { + cleanEmptyObject, GlobalStylesContext, __experimentalUseGlobalBehaviors: useGlobalBehaviors, __experimentalUseHasBehaviorsPanel: useHasBehaviorsPanel, @@ -105,16 +106,19 @@ const getValueFromObjectPath = ( object, path ) => { return value; }; -function getBorderStyleChanges( border, presetColor ) { +const flatBorderProperties = [ 'borderColor', 'borderWidth', 'borderStyle' ]; +const sides = [ 'top', 'right', 'bottom', 'left' ]; + +function getBorderStyleChanges( border, presetColor, userStyle ) { if ( ! border && ! presetColor ) { return []; } const changes = [ - ...getFallbackBorderStyleChange( border?.top, 'top' ), - ...getFallbackBorderStyleChange( border?.right, 'right' ), - ...getFallbackBorderStyleChange( border?.bottom, 'bottom' ), - ...getFallbackBorderStyleChange( border?.left, 'left' ), + ...getFallbackBorderStyleChange( 'top', border, userStyle ), + ...getFallbackBorderStyleChange( 'right', border, userStyle ), + ...getFallbackBorderStyleChange( 'bottom', border, userStyle ), + ...getFallbackBorderStyleChange( 'left', border, userStyle ), ]; // Handle a flat border i.e. all sides the same, CSS shorthand. @@ -122,18 +126,29 @@ function getBorderStyleChanges( border, presetColor ) { const hasColorOrWidth = presetColor || customColor || width; if ( hasColorOrWidth && ! style ) { - changes.push( { path: [ 'border', 'style' ], value: 'solid' } ); + // Global Styles need individual side configurations to overcome + // theme.json configurations which are per side as well. + sides.forEach( ( side ) => { + // Only add fallback border-style if global styles don't already + // have something set. + if ( ! userStyle?.[ side ]?.style ) { + changes.push( { + path: [ 'border', side, 'style' ], + value: 'solid', + } ); + } + } ); } return changes; } -function getFallbackBorderStyleChange( border, side ) { - if ( ! border ) { +function getFallbackBorderStyleChange( side, border, globalBorderStyle ) { + if ( ! border?.[ side ] || globalBorderStyle?.[ side ]?.style ) { return []; } - const { color, style, width } = border; + const { color, style, width } = border[ side ]; const hasColorOrWidth = color || width; if ( ! hasColorOrWidth || style ) { @@ -143,8 +158,9 @@ function getFallbackBorderStyleChange( border, side ) { return [ { path: [ 'border', side, 'style' ], value: 'solid' } ]; } -function useChangesToPush( name, attributes ) { +function useChangesToPush( name, attributes, userConfig ) { const supports = useSupportedStyles( name ); + const blockUserConfig = userConfig?.styles?.blocks?.[ name ]; return useMemo( () => { const changes = supports.flatMap( ( key ) => { @@ -160,6 +176,20 @@ function useChangesToPush( name, attributes ) { const value = presetAttributeValue ? `var:preset|${ STYLE_PATH_TO_CSS_VAR_INFIX[ presetAttributeKey ] }|${ presetAttributeValue }` : getValueFromObjectPath( attributes.style, path ); + + // The shorthand border styles can't be mapped directly as global + // styles requires longhand config. + if ( flatBorderProperties.includes( key ) && value ) { + // The shorthand config path is included to clear the block attribute. + const borderChanges = [ { path, value } ]; + sides.forEach( ( side ) => { + const currentPath = [ ...path ]; + currentPath.splice( -1, 0, side ); + borderChanges.push( { path: currentPath, value } ); + } ); + return borderChanges; + } + return value ? [ { path, value } ] : []; } ); @@ -167,11 +197,12 @@ function useChangesToPush( name, attributes ) { // default border style if a border color or width is present. getBorderStyleChanges( attributes.style?.border, - attributes.borderColor + attributes.borderColor, + blockUserConfig?.border ).forEach( ( change ) => changes.push( change ) ); return changes; - }, [ supports, attributes ] ); + }, [ supports, attributes, blockUserConfig ] ); } /** @@ -223,14 +254,15 @@ function PushChangesToGlobalStylesControl( { attributes, setAttributes, } ) { - const changes = useChangesToPush( name, attributes ); - const hasBehaviorsPanel = useHasBehaviorsPanel( attributes, name, { blockSupportOnly: true, } ); + const { user: userConfig, setUserConfig } = useContext( GlobalStylesContext ); + const changes = useChangesToPush( name, attributes, userConfig ); + const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( blockEditorStore ); const { createSuccessNotice } = useDispatch( noticesStore ); @@ -266,7 +298,7 @@ function PushChangesToGlobalStylesControl( { gradient: undefined, fontSize: undefined, fontFamily: undefined, - style: newBlockStyles, + style: cleanEmptyObject( newBlockStyles ), }; // @wordpress/core-data doesn't support editing multiple entity types in From aebc2857266aa96143dcb68c233d356c63550cbd Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:59:27 +1000 Subject: [PATCH 6/7] Fix pushing of blockGap styles --- .../src/hooks/push-changes-to-global-styles/index.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index ea82da9be99a1..4bf567c257702 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -12,7 +12,7 @@ import { import { BaseControl, Button } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { - __EXPERIMENTAL_STYLE_PROPERTY as STYLE_PROPERTY, + __EXPERIMENTAL_STYLE_PROPERTY, getBlockType, hasBlockSupport, } from '@wordpress/blocks'; @@ -33,6 +33,14 @@ const { __experimentalUseHasBehaviorsPanel: useHasBehaviorsPanel, } = unlock( blockEditorPrivateApis ); +// Block Gap is a special case and isn't defined within the blocks +// style properties config. We'll add it here to allow it to be pushed +// to global styles as well. +const STYLE_PROPERTY = { + ...__EXPERIMENTAL_STYLE_PROPERTY, + blockGap: { value: [ 'spacing', 'blockGap' ] }, +}; + // TODO: Temporary duplication of constant in @wordpress/block-editor. Can be // removed by moving PushChangesToGlobalStylesControl to // @wordpress/block-editor. @@ -79,7 +87,7 @@ const STYLE_PATH_TO_CSS_VAR_INFIX = { 'elements.h6.typography.fontFamily': 'font-family', 'elements.h6.color.gradient': 'gradient', 'color.gradient': 'gradient', - 'spacing.blockGap': 'spacing', + blockGap: 'spacing', 'typography.fontSize': 'font-size', 'typography.fontFamily': 'font-family', }; From 1fcce005c53792fc121e84aa039d34cba2dcdc1c Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:25:13 +1000 Subject: [PATCH 7/7] Fix pushing link colors and behaviors --- .../push-changes-to-global-styles/index.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 4bf567c257702..bd751ef4b312b 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -185,6 +185,30 @@ function useChangesToPush( name, attributes, userConfig ) { ? `var:preset|${ STYLE_PATH_TO_CSS_VAR_INFIX[ presetAttributeKey ] }|${ presetAttributeValue }` : getValueFromObjectPath( attributes.style, path ); + // Links only have a single support entry but have two element + // style properties, color and hover color. The following check + // will add the hover color to the changes if required. + if ( key === 'linkColor' ) { + const linkChanges = value ? [ { path, value } ] : []; + const hoverPath = [ + 'elements', + 'link', + ':hover', + 'color', + 'text', + ]; + const hoverValue = getValueFromObjectPath( + attributes.style, + hoverPath + ); + + if ( hoverValue ) { + linkChanges.push( { path: hoverPath, value: hoverValue } ); + } + + return linkChanges; + } + // The shorthand border styles can't be mapped directly as global // styles requires longhand config. if ( flatBorderProperties.includes( key ) && value ) { @@ -284,6 +308,7 @@ function PushChangesToGlobalStylesControl( { if ( changes.length === 0 && ! userHasEditedBehaviors ) { return; } + if ( changes.length > 0 ) { const { style: blockStyles } = attributes; @@ -339,8 +364,10 @@ function PushChangesToGlobalStylesControl( { } ); } + if ( userHasEditedBehaviors ) { __unstableMarkNextChangeAsNotPersistent(); + setAttributes( { behaviors: undefined } ); setBehavior( attributes.behaviors ); createSuccessNotice( sprintf(