From 3b35e88cb43a50125290e84f4a45d6b94def44d9 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Tue, 27 Sep 2022 18:40:03 +0900 Subject: [PATCH 01/22] ServerSideRender: add new `skipBlockSupportAttributes` prop --- .../src/server-side-render.js | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/server-side-render/src/server-side-render.js b/packages/server-side-render/src/server-side-render.js index deb7d025b647e8..b9e557c631703f 100644 --- a/packages/server-side-render/src/server-side-render.js +++ b/packages/server-side-render/src/server-side-render.js @@ -14,6 +14,8 @@ import { addQueryArgs } from '@wordpress/url'; import { Placeholder, Spinner } from '@wordpress/components'; import { __experimentalSanitizeBlockAttributes } from '@wordpress/blocks'; +const EMPTY_OBJECT = {}; + export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { return addQueryArgs( `/wp/v2/block-renderer/${ block }`, { context: 'edit', @@ -62,6 +64,26 @@ function DefaultLoadingResponsePlaceholder( { children, showLoader } ) { ); } +function removeBlockSupportAttributes( attributes ) { + const { + backgroundColor, + borderColor, + fontFamily, + fontSize, + gradient, + textColor, + ...restAttributes + } = attributes; + + const { border, color, elements, spacing, typography, ...restStyles } = + attributes?.style || EMPTY_OBJECT; + + return { + ...restAttributes, + style: restStyles, + }; +} + export default function ServerSideRender( props ) { const { attributes, @@ -69,6 +91,7 @@ export default function ServerSideRender( props ) { className, httpMethod = 'GET', urlQueryArgs, + skipBlockSupportAttributes = false, EmptyResponsePlaceholder = DefaultEmptyResponsePlaceholder, ErrorResponsePlaceholder = DefaultErrorResponsePlaceholder, LoadingResponsePlaceholder = DefaultLoadingResponsePlaceholder, @@ -88,10 +111,15 @@ export default function ServerSideRender( props ) { setIsLoading( true ); - const sanitizedAttributes = + let sanitizedAttributes = attributes && __experimentalSanitizeBlockAttributes( block, attributes ); + if ( skipBlockSupportAttributes ) { + sanitizedAttributes = + removeBlockSupportAttributes( sanitizedAttributes ); + } + // If httpMethod is 'POST', send the attributes in the request body instead of the URL. // This allows sending a larger attributes object than in a GET request, where the attributes are in the URL. const isPostRequest = 'POST' === httpMethod; From 2b6ec9a2b30a737666fb90bb83f10c7d51ebc365 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Tue, 27 Sep 2022 18:49:11 +0900 Subject: [PATCH 02/22] Update readme --- packages/server-side-render/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/server-side-render/README.md b/packages/server-side-render/README.md index 55dc97ec091340..238faa92559bf5 100644 --- a/packages/server-side-render/README.md +++ b/packages/server-side-render/README.md @@ -76,6 +76,13 @@ function add_rest_method( $endpoints ) { add_filter( 'rest_endpoints', 'add_rest_method'); ``` +### skipBlockSupportAttributes + +Remove attributes and style properties applied by global styles. This prevents duplication of styles in the block wrapper and the `ServerSideRender` components. + +- Type: `Boolean` +- Required: No + ### urlQueryArgs Query arguments to apply to the request URL. From 43fde2501be643db7b41f5f824f5d2a1d2ab55e2 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Tue, 27 Sep 2022 18:52:52 +0900 Subject: [PATCH 03/22] update changelog --- packages/server-side-render/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/server-side-render/CHANGELOG.md b/packages/server-side-render/CHANGELOG.md index 394b8cc4c12477..b2eafd797a07f4 100644 --- a/packages/server-side-render/CHANGELOG.md +++ b/packages/server-side-render/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Feature + +- Add `skipBlockSupportAttributes` props to prevent duplication of styles in the block wrapper and the `ServerSideRender` components. [#44491](https://github.com/WordPress/gutenberg/pull/44491) + ## 3.16.0 (2022-09-21) ## 3.15.0 (2022-09-13) From 59a6178868bd6ac2cb6628cc4ffc811f81e341bf Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Tue, 27 Sep 2022 19:09:46 +0900 Subject: [PATCH 04/22] add unit test --- .../src/server-side-render.js | 40 +++++------ packages/server-side-render/src/test/index.js | 66 ++++++++++++++++++- 2 files changed, 85 insertions(+), 21 deletions(-) diff --git a/packages/server-side-render/src/server-side-render.js b/packages/server-side-render/src/server-side-render.js index b9e557c631703f..badb59ebd78cd5 100644 --- a/packages/server-side-render/src/server-side-render.js +++ b/packages/server-side-render/src/server-side-render.js @@ -24,6 +24,26 @@ export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { } ); } +export function removeBlockSupportAttributes( attributes ) { + const { + backgroundColor, + borderColor, + fontFamily, + fontSize, + gradient, + textColor, + ...restAttributes + } = attributes; + + const { border, color, elements, spacing, typography, ...restStyles } = + attributes?.style || EMPTY_OBJECT; + + return { + ...restAttributes, + style: restStyles, + }; +} + function DefaultEmptyResponsePlaceholder( { className } ) { return ( @@ -64,26 +84,6 @@ function DefaultLoadingResponsePlaceholder( { children, showLoader } ) { ); } -function removeBlockSupportAttributes( attributes ) { - const { - backgroundColor, - borderColor, - fontFamily, - fontSize, - gradient, - textColor, - ...restAttributes - } = attributes; - - const { border, color, elements, spacing, typography, ...restStyles } = - attributes?.style || EMPTY_OBJECT; - - return { - ...restAttributes, - style: restStyles, - }; -} - export default function ServerSideRender( props ) { const { attributes, diff --git a/packages/server-side-render/src/test/index.js b/packages/server-side-render/src/test/index.js index 60b2f89007adec..c1a382ad17be07 100644 --- a/packages/server-side-render/src/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -1,7 +1,10 @@ /** * Internal dependencies */ -import { rendererPath } from '../server-side-render'; +import { + rendererPath, + removeBlockSupportAttributes, +} from '../server-side-render'; describe( 'rendererPath', () => { test( 'should return an base path for empty input', () => { @@ -75,4 +78,65 @@ describe( 'rendererPath', () => { '/wp/v2/block-renderer/core/test-block?context=edit&attributes%5BstringArg%5D=test&id=1234' ); } ); + + test( 'Should remove attributes and style properties applied by global styles', () => { + expect( + removeBlockSupportAttributes( { + backgroundColor: 'foreground', + borderColor: 'foreground', + fontFamily: 'system-font', + fontSize: 'small', + gradient: 'vivid-cyan-blue-to-vivid-purple', + textColor: 'foreground', + customAttribute: 'customAttribute', + style: { + border: { + radius: '10px', + style: 'solid', + width: '10px', + }, + color: { + background: '#000000', + text: '#000000', + }, + elements: { + link: { + color: { + text: '#000000', + }, + }, + }, + spacing: { + margin: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + padding: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + }, + typography: { + fontSize: '10px', + fontStyle: 'normal', + fontWeight: '500', + letterSpacing: '10px', + lineHeight: '1', + textDecoration: 'line-through', + textTransform: 'uppercase', + }, + customStyle: 'customStyle', + }, + } ) + ).toEqual( { + customAttribute: 'customAttribute', + style: { + customStyle: 'customStyle', + }, + } ); + } ); } ); From b70814f34696dc94cf8572b688d7cfdc7eedeb5a Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Tue, 27 Sep 2022 19:39:24 +0900 Subject: [PATCH 05/22] Fix typo --- packages/server-side-render/README.md | 2 +- packages/server-side-render/src/test/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server-side-render/README.md b/packages/server-side-render/README.md index 238faa92559bf5..479627fd6c5269 100644 --- a/packages/server-side-render/README.md +++ b/packages/server-side-render/README.md @@ -78,7 +78,7 @@ add_filter( 'rest_endpoints', 'add_rest_method'); ### skipBlockSupportAttributes -Remove attributes and style properties applied by global styles. This prevents duplication of styles in the block wrapper and the `ServerSideRender` components. +Remove attributes and style properties applied by the block supports. This prevents duplication of styles in the block wrapper and the `ServerSideRender` components. - Type: `Boolean` - Required: No diff --git a/packages/server-side-render/src/test/index.js b/packages/server-side-render/src/test/index.js index c1a382ad17be07..c50befa3ba8a28 100644 --- a/packages/server-side-render/src/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -79,7 +79,7 @@ describe( 'rendererPath', () => { ); } ); - test( 'Should remove attributes and style properties applied by global styles', () => { + test( 'Should remove attributes and style properties applied by the block supports', () => { expect( removeBlockSupportAttributes( { backgroundColor: 'foreground', From 8791cc3d9441cdefdd1486966b688b1baeee23a4 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sun, 2 Oct 2022 16:30:46 +0900 Subject: [PATCH 06/22] Don't remove attributes and styles which serialization is omitted --- packages/server-side-render/src/constants.js | 76 +++++++++ .../src/server-side-render.js | 40 +---- packages/server-side-render/src/utils.js | 160 ++++++++++++++++++ 3 files changed, 244 insertions(+), 32 deletions(-) create mode 100644 packages/server-side-render/src/constants.js create mode 100644 packages/server-side-render/src/utils.js diff --git a/packages/server-side-render/src/constants.js b/packages/server-side-render/src/constants.js new file mode 100644 index 00000000000000..30a8e9f4a5641f --- /dev/null +++ b/packages/server-side-render/src/constants.js @@ -0,0 +1,76 @@ +export const ATTRIBUTE_PROPERTY = { + textColor: [ 'color', 'text' ], + backgroundColor: [ 'color', 'background' ], + gradient: [ 'color', 'gradient' ], + fontSize: [ 'typography', 'fontSize' ], + fontFamily: [ 'typography', '__experimentalFontFamily' ], + borderColor: [ '__experimentalBorder', 'color' ], +}; + +export const STYLE_PROPERTY = { + color: { + text: { + support: [ 'color', 'text' ], + }, + background: { + support: [ 'color', 'background' ], + }, + gradient: { + support: [ 'color', 'gradient' ], + }, + }, + typography: { + fontSize: { + support: [ 'typography', 'fontSize' ], + }, + fontWeight: { + support: [ 'typography', '__experimentalFontWeight' ], + }, + fontStyle: { + support: [ 'typography', '__experimentalFontStyle' ], + }, + textTransform: { + support: [ 'typography', '__experimentalTextTransform' ], + }, + leterSpacing: { + support: [ 'typography', '__experimentalLetterSpacing' ], + }, + textDecoration: { + support: [ 'typography', '__experimentalTextDecoration' ], + }, + }, + spacing: { + margin: { + support: [ 'spacing', 'margin' ], + }, + padding: { + support: [ 'spacing', 'padding' ], + }, + blockGap: { + support: [ 'spacing', 'blockGap' ], + }, + }, + border: { + radius: { + support: [ '__experimentalBorder', 'radius' ], + subProperties: [ + 'topLeft', + 'topRight', + 'bottomRight', + 'bottomLeft', + ], + }, + color: { + support: [ '__experimentalBorder', 'color' ], + additionalProperties: [ 'top', 'right', 'bottom', 'left' ], + }, + style: { + support: [ '__experimentalBorder', 'style' ], + additionalProperties: [ 'top', 'right', 'bottom', 'left' ], + }, + width: { + support: [ '__experimentalBorder', 'width' ], + additionalProperties: [ 'top', 'right', 'bottom', 'left' ], + }, + }, +}; diff --git a/packages/server-side-render/src/server-side-render.js b/packages/server-side-render/src/server-side-render.js index badb59ebd78cd5..ccd6471e69b9f2 100644 --- a/packages/server-side-render/src/server-side-render.js +++ b/packages/server-side-render/src/server-side-render.js @@ -10,39 +10,13 @@ import { useDebounce, usePrevious } from '@wordpress/compose'; import { RawHTML, useEffect, useRef, useState } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import apiFetch from '@wordpress/api-fetch'; -import { addQueryArgs } from '@wordpress/url'; import { Placeholder, Spinner } from '@wordpress/components'; import { __experimentalSanitizeBlockAttributes } from '@wordpress/blocks'; -const EMPTY_OBJECT = {}; - -export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { - return addQueryArgs( `/wp/v2/block-renderer/${ block }`, { - context: 'edit', - ...( null !== attributes ? { attributes } : {} ), - ...urlQueryArgs, - } ); -} - -export function removeBlockSupportAttributes( attributes ) { - const { - backgroundColor, - borderColor, - fontFamily, - fontSize, - gradient, - textColor, - ...restAttributes - } = attributes; - - const { border, color, elements, spacing, typography, ...restStyles } = - attributes?.style || EMPTY_OBJECT; - - return { - ...restAttributes, - style: restStyles, - }; -} +/** + * Internal dependencies + */ +import { rendererPath, removeBlockSupportAttributes } from './utils'; function DefaultEmptyResponsePlaceholder( { className } ) { return ( @@ -116,8 +90,10 @@ export default function ServerSideRender( props ) { __experimentalSanitizeBlockAttributes( block, attributes ); if ( skipBlockSupportAttributes ) { - sanitizedAttributes = - removeBlockSupportAttributes( sanitizedAttributes ); + sanitizedAttributes = removeBlockSupportAttributes( + block, + sanitizedAttributes + ); } // If httpMethod is 'POST', send the attributes in the request body instead of the URL. diff --git a/packages/server-side-render/src/utils.js b/packages/server-side-render/src/utils.js new file mode 100644 index 00000000000000..7dbaacfb6b0e02 --- /dev/null +++ b/packages/server-side-render/src/utils.js @@ -0,0 +1,160 @@ +/** + * External dependencies + */ +import { pickBy, isEmpty, mapValues } from 'lodash'; + +/** + * WordPress dependencies + */ +import { addQueryArgs } from '@wordpress/url'; +import { getBlockSupport } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { ATTRIBUTE_PROPERTY, STYLE_PROPERTY } from './constants'; + +const identity = ( x ) => x; + +function shouldSkipSerialization( blockType, featureSet, feature ) { + const support = getBlockSupport( blockType, featureSet ); + const skipSerialization = support?.__experimentalSkipSerialization; + + if ( Array.isArray( skipSerialization ) ) { + return skipSerialization.includes( feature ); + } + + return skipSerialization; +} + +export function removeBlockSupportAttributes( block, attributes ) { + // Omit className and style from attributes. + const { className, style, ...restAttributes } = attributes; + + // Create new attributes object. + const newAttributes = Object.keys( ATTRIBUTE_PROPERTY ).reduce( + ( acc, attributeName ) => { + const support = ATTRIBUTE_PROPERTY[ attributeName ]; + + const skipSerialization = shouldSkipSerialization( + block, + support[ 0 ], + support[ 1 ] + ); + + // Reset attributes which serialization is NOT omitted. + if ( ! skipSerialization ) { + acc[ attributeName ] = undefined; + return acc; + } + + // Add attributes which serialization is omitted. + acc[ attributeName ] = restAttributes[ attributeName ]; + return acc; + }, + {} + ); + + // Create new style object. + const newStyle = Object.keys( STYLE_PROPERTY ).reduce( + ( acc, styleName ) => { + // Initialize style name properties. + acc[ styleName ] = {}; + if ( styleName === 'border' ) { + acc[ styleName ] = { + top: {}, + right: {}, + bottom: {}, + left: {}, + }; + } + + // Only add styles for which serialization is omitted. + Object.keys( STYLE_PROPERTY[ styleName ] ).forEach( ( key ) => { + const { support, subProperties, additionalProperties } = + STYLE_PROPERTY[ styleName ][ key ]; + + const skipSerialization = shouldSkipSerialization( + block, + support[ 0 ], + support[ 1 ] + ); + + // Skip styles which serialization is NOT omitted. + if ( ! skipSerialization ) { + return; + } + + // Add border-radius styles. + if ( subProperties ) { + if ( typeof style?.[ styleName ]?.[ key ] === 'string' ) { + acc[ styleName ][ key ] = style?.[ styleName ]?.[ key ]; + } else if ( + typeof style?.[ styleName ]?.[ key ] === 'object' + ) { + acc[ styleName ][ key ] = {}; + subProperties.forEach( ( prop ) => { + acc[ styleName ][ key ][ prop ] = + style?.[ styleName ]?.[ key ]?.[ prop ]; + } ); + } + return; + } + + // Add border-{color|width|style} styles. + if ( additionalProperties ) { + if ( typeof style?.[ styleName ]?.[ key ] === 'string' ) { + acc[ styleName ][ key ] = style?.[ styleName ]?.[ key ]; + } else { + additionalProperties.forEach( ( prop ) => { + acc[ styleName ][ prop ][ key ] = + style?.[ styleName ]?.[ prop ]?.[ key ]; + } ); + } + return; + } + + // Add other styles. + acc[ styleName ][ key ] = style?.[ styleName ]?.[ key ]; + } ); + + return acc; + }, + {} + ); + + return cleanEmptyObject( { + ...restAttributes, + ...newAttributes, + style: newStyle, + } ); +} + +export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { + return addQueryArgs( `/wp/v2/block-renderer/${ block }`, { + context: 'edit', + ...( null !== attributes ? { attributes } : {} ), + ...urlQueryArgs, + } ); +} + +/** + * Removed falsy values from nested object. + * + * @param {*} object + * @return {*} Object cleaned from falsy values + */ +export const cleanEmptyObject = ( object ) => { + if ( + object === null || + typeof object !== 'object' || + Array.isArray( object ) + ) { + return object; + } + const cleanedNestedObjects = pickBy( + mapValues( object, cleanEmptyObject ), + identity + ); + return isEmpty( cleanedNestedObjects ) ? undefined : cleanedNestedObjects; +}; From a42b10ee5a2e4fc8729ea1e75a387a2df45fcfda Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sun, 2 Oct 2022 18:35:50 +0900 Subject: [PATCH 07/22] Update unit tests --- packages/server-side-render/src/constants.js | 4 +- packages/server-side-render/src/test/index.js | 256 ++++++++++++++---- 2 files changed, 204 insertions(+), 56 deletions(-) diff --git a/packages/server-side-render/src/constants.js b/packages/server-side-render/src/constants.js index 30a8e9f4a5641f..0e549cc06f84aa 100644 --- a/packages/server-side-render/src/constants.js +++ b/packages/server-side-render/src/constants.js @@ -1,7 +1,7 @@ export const ATTRIBUTE_PROPERTY = { textColor: [ 'color', 'text' ], backgroundColor: [ 'color', 'background' ], - gradient: [ 'color', 'gradient' ], + gradient: [ 'color', 'gradients' ], fontSize: [ 'typography', 'fontSize' ], fontFamily: [ 'typography', '__experimentalFontFamily' ], borderColor: [ '__experimentalBorder', 'color' ], @@ -16,7 +16,7 @@ export const STYLE_PROPERTY = { support: [ 'color', 'background' ], }, gradient: { - support: [ 'color', 'gradient' ], + support: [ 'color', 'gradients' ], }, }, typography: { diff --git a/packages/server-side-render/src/test/index.js b/packages/server-side-render/src/test/index.js index c50befa3ba8a28..453c533398fea1 100644 --- a/packages/server-side-render/src/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -1,10 +1,16 @@ /** - * Internal dependencies + * WordPress dependencies */ import { - rendererPath, - removeBlockSupportAttributes, -} from '../server-side-render'; + registerBlockType, + unregisterBlockType, + getBlockTypes, +} from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { rendererPath, removeBlockSupportAttributes } from '../utils'; describe( 'rendererPath', () => { test( 'should return an base path for empty input', () => { @@ -78,64 +84,206 @@ describe( 'rendererPath', () => { '/wp/v2/block-renderer/core/test-block?context=edit&attributes%5BstringArg%5D=test&id=1234' ); } ); +} ); + +describe( 'skipBlockSupportAttributes', () => { + afterEach( () => { + getBlockTypes().forEach( ( block ) => { + unregisterBlockType( block.name ); + } ); + } ); + + const attributes = { + className: 'class-name', + customAttribute: 'custom-attribute', + textColor: 'foreground', + backgroundColor: 'foreground', + gradient: 'vivid-cyan-blue-to-vivid-purple', + fontSize: 'small', + fontFamily: 'system-font', + borderColor: 'foreground', + style: { + color: { + text: '#000000', + background: '#000000', + gradients: '#000000', + }, + typography: { + fontSize: '10px', + lineHeight: '1', + fontWeight: '500', + fontStyle: 'normal', + textTransform: 'uppercase', + textDecoration: 'line-through', + letterSpacing: '10px', + }, + spacing: { + margin: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + padding: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + blockGap: '10px', + }, + border: { + radius: '10px', + style: 'solid', + top: { + width: '10px', + color: '#000000', + }, + right: { + width: '10px', + color: '#000000', + }, + bottom: { + width: '10px', + color: '#000000', + }, + left: { + width: '10px', + color: '#000000', + }, + }, + }, + }; + + test( 'Should remove attributes and style properties', () => { + registerBlockType( 'core/test-block', { + category: 'text', + title: 'test block', + supports: { + color: { + text: true, + background: true, + gradients: true, + link: true, + }, + typography: { + fontSize: true, + lineHeight: true, + __experimentalFontFamily: true, + __experimentalFontWeight: true, + __experimentalFontStyle: true, + __experimentalTextTransform: true, + __experimentalTextDecoration: true, + __experimentalLetterSpacing: true, + }, + spacing: { + margin: true, + padding: true, + blockGap: true, + }, + __experimentalBorder: { + radius: true, + width: true, + color: true, + style: true, + }, + }, + } ); - test( 'Should remove attributes and style properties applied by the block supports', () => { expect( - removeBlockSupportAttributes( { - backgroundColor: 'foreground', - borderColor: 'foreground', - fontFamily: 'system-font', - fontSize: 'small', - gradient: 'vivid-cyan-blue-to-vivid-purple', - textColor: 'foreground', - customAttribute: 'customAttribute', - style: { - border: { - radius: '10px', - style: 'solid', - width: '10px', + removeBlockSupportAttributes( 'core/test-block', attributes ) + ).toEqual( { + customAttribute: 'custom-attribute', + } ); + } ); + + test( 'Should skip attributes and style properties which serialization is omitted', () => { + registerBlockType( 'core/test-block', { + category: 'text', + title: 'test block', + supports: { + color: { + text: true, + background: true, + gradients: true, + link: true, + __experimentalSkipSerialization: [ 'text', 'gradients' ], + }, + typography: { + fontSize: true, + lineHeight: true, + __experimentalFontFamily: true, + __experimentalFontWeight: true, + __experimentalFontStyle: true, + __experimentalTextTransform: true, + __experimentalTextDecoration: true, + __experimentalLetterSpacing: true, + __experimentalSkipSerialization: [ + 'fontSize', + '__experimentalFontWeight', + ], + }, + spacing: { + margin: true, + padding: true, + blockGap: true, + __experimentalSkipSerialization: true, + }, + __experimentalBorder: { + radius: true, + width: true, + color: true, + style: true, + __experimentalSkipSerialization: [ 'width', 'style' ], + }, + }, + } ); + + expect( + removeBlockSupportAttributes( 'core/test-block', attributes ) + ).toEqual( { + customAttribute: 'custom-attribute', + textColor: 'foreground', + gradient: 'vivid-cyan-blue-to-vivid-purple', + fontSize: 'small', + style: { + color: { + text: '#000000', + }, + typography: { + fontSize: '10px', + fontWeight: '500', + }, + spacing: { + margin: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', }, - color: { - background: '#000000', - text: '#000000', + padding: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', }, - elements: { - link: { - color: { - text: '#000000', - }, - }, + blockGap: '10px', + }, + border: { + style: 'solid', + top: { + width: '10px', }, - spacing: { - margin: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, - padding: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, + right: { + width: '10px', }, - typography: { - fontSize: '10px', - fontStyle: 'normal', - fontWeight: '500', - letterSpacing: '10px', - lineHeight: '1', - textDecoration: 'line-through', - textTransform: 'uppercase', + bottom: { + width: '10px', + }, + left: { + width: '10px', }, - customStyle: 'customStyle', }, - } ) - ).toEqual( { - customAttribute: 'customAttribute', - style: { - customStyle: 'customStyle', }, } ); } ); From f1b0670a7b304a194489860dd96e72cd40aa10fd Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sun, 2 Oct 2022 18:42:24 +0900 Subject: [PATCH 08/22] Update readme --- packages/server-side-render/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server-side-render/README.md b/packages/server-side-render/README.md index 479627fd6c5269..faec9024bd49b0 100644 --- a/packages/server-side-render/README.md +++ b/packages/server-side-render/README.md @@ -78,7 +78,7 @@ add_filter( 'rest_endpoints', 'add_rest_method'); ### skipBlockSupportAttributes -Remove attributes and style properties applied by the block supports. This prevents duplication of styles in the block wrapper and the `ServerSideRender` components. +Remove attributes and style properties applied by the block supports. This prevents duplication of styles in the block wrapper and the `ServerSideRender` components. Attributes and styles provided by the block supports for which `__experimentalSkipSerialization` is specified will not be removed. - Type: `Boolean` - Required: No From 04f3af08234f71775dd1067961c649d2922253bb Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sun, 2 Oct 2022 18:49:08 +0900 Subject: [PATCH 09/22] Don't remove custom style --- packages/server-side-render/src/test/index.js | 5 +++++ packages/server-side-render/src/utils.js | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/server-side-render/src/test/index.js b/packages/server-side-render/src/test/index.js index 453c533398fea1..3eec69c9a7e8ad 100644 --- a/packages/server-side-render/src/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -103,6 +103,7 @@ describe( 'skipBlockSupportAttributes', () => { fontFamily: 'system-font', borderColor: 'foreground', style: { + customStyle: 'custom-style', color: { text: '#000000', background: '#000000', @@ -194,6 +195,9 @@ describe( 'skipBlockSupportAttributes', () => { removeBlockSupportAttributes( 'core/test-block', attributes ) ).toEqual( { customAttribute: 'custom-attribute', + style: { + customStyle: 'custom-style', + }, } ); } ); @@ -247,6 +251,7 @@ describe( 'skipBlockSupportAttributes', () => { gradient: 'vivid-cyan-blue-to-vivid-purple', fontSize: 'small', style: { + customStyle: 'custom-style', color: { text: '#000000', }, diff --git a/packages/server-side-render/src/utils.js b/packages/server-side-render/src/utils.js index 7dbaacfb6b0e02..10f1d581285912 100644 --- a/packages/server-side-render/src/utils.js +++ b/packages/server-side-render/src/utils.js @@ -126,7 +126,10 @@ export function removeBlockSupportAttributes( block, attributes ) { return cleanEmptyObject( { ...restAttributes, ...newAttributes, - style: newStyle, + style: { + ...style, + ...newStyle, + }, } ); } From abf2d7e61ddaf69f412a04ec0f46f24eac1d0ecc Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sun, 2 Oct 2022 20:35:07 +0900 Subject: [PATCH 10/22] Support color.link and update tests --- packages/server-side-render/src/constants.js | 5 + packages/server-side-render/src/test/index.js | 190 +++++++++++------- packages/server-side-render/src/utils.js | 19 +- 3 files changed, 131 insertions(+), 83 deletions(-) diff --git a/packages/server-side-render/src/constants.js b/packages/server-side-render/src/constants.js index 0e549cc06f84aa..b88ee3395349dd 100644 --- a/packages/server-side-render/src/constants.js +++ b/packages/server-side-render/src/constants.js @@ -19,6 +19,11 @@ export const STYLE_PROPERTY = { support: [ 'color', 'gradients' ], }, }, + elements: { + link: { + support: [ 'color', 'link' ], + }, + }, typography: { fontSize: { support: [ 'typography', 'fontSize' ], diff --git a/packages/server-side-render/src/test/index.js b/packages/server-side-render/src/test/index.js index 3eec69c9a7e8ad..2e05d0f70d4456 100644 --- a/packages/server-side-render/src/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -86,6 +86,73 @@ describe( 'rendererPath', () => { } ); } ); +const allAttributes = { + textColor: 'foreground', + backgroundColor: 'foreground', + gradient: 'vivid-cyan-blue-to-vivid-purple', + fontSize: 'small', + fontFamily: 'system-font', + borderColor: 'foreground', + style: { + color: { + text: '#000000', + background: '#000000', + gradients: '#000000', + }, + elements: { + link: { + color: { + text: '#000000', + }, + }, + }, + typography: { + fontSize: '10px', + lineHeight: '1', + fontWeight: '500', + fontStyle: 'normal', + textTransform: 'uppercase', + textDecoration: 'line-through', + letterSpacing: '10px', + }, + spacing: { + margin: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + padding: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + blockGap: '10px', + }, + border: { + radius: '10px', + style: 'solid', + top: { + width: '10px', + color: '#000000', + }, + right: { + width: '10px', + color: '#000000', + }, + bottom: { + width: '10px', + color: '#000000', + }, + left: { + width: '10px', + color: '#000000', + }, + }, + }, +}; + describe( 'skipBlockSupportAttributes', () => { afterEach( () => { getBlockTypes().forEach( ( block ) => { @@ -93,72 +160,42 @@ describe( 'skipBlockSupportAttributes', () => { } ); } ); - const attributes = { - className: 'class-name', - customAttribute: 'custom-attribute', - textColor: 'foreground', - backgroundColor: 'foreground', - gradient: 'vivid-cyan-blue-to-vivid-purple', - fontSize: 'small', - fontFamily: 'system-font', - borderColor: 'foreground', - style: { - customStyle: 'custom-style', - color: { - text: '#000000', - background: '#000000', - gradients: '#000000', - }, - typography: { - fontSize: '10px', - lineHeight: '1', - fontWeight: '500', - fontStyle: 'normal', - textTransform: 'uppercase', - textDecoration: 'line-through', - letterSpacing: '10px', - }, - spacing: { - margin: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, - padding: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, - blockGap: '10px', + test( 'should remove custom CSS class', () => { + const attributes = { + className: 'class-name', + }; + + registerBlockType( 'core/test-block', { + title: 'test block', + } ); + + expect( + removeBlockSupportAttributes( 'core/test-block', attributes ) + ).toEqual( {} ); + } ); + + test( 'should not remove custom style', () => { + const attributes = { + style: { + customStyle: 'custom-style', }, - border: { - radius: '10px', - style: 'solid', - top: { - width: '10px', - color: '#000000', - }, - right: { - width: '10px', - color: '#000000', - }, - bottom: { - width: '10px', - color: '#000000', - }, - left: { - width: '10px', - color: '#000000', - }, + }; + + registerBlockType( 'core/test-block', { + title: 'test block', + } ); + + expect( + removeBlockSupportAttributes( 'core/test-block', attributes ) + ).toEqual( { + style: { + customStyle: 'custom-style', }, - }, - }; + } ); + } ); - test( 'Should remove attributes and style properties', () => { + test( 'Should remove all attributes and style properties', () => { registerBlockType( 'core/test-block', { - category: 'text', title: 'test block', supports: { color: { @@ -192,18 +229,12 @@ describe( 'skipBlockSupportAttributes', () => { } ); expect( - removeBlockSupportAttributes( 'core/test-block', attributes ) - ).toEqual( { - customAttribute: 'custom-attribute', - style: { - customStyle: 'custom-style', - }, - } ); + removeBlockSupportAttributes( 'core/test-block', allAttributes ) + ).toEqual( {} ); } ); - test( 'Should skip attributes and style properties which serialization is omitted', () => { + test( 'Should pass attributes and style properties which serialization is omitted', () => { registerBlockType( 'core/test-block', { - category: 'text', title: 'test block', supports: { color: { @@ -211,7 +242,11 @@ describe( 'skipBlockSupportAttributes', () => { background: true, gradients: true, link: true, - __experimentalSkipSerialization: [ 'text', 'gradients' ], + __experimentalSkipSerialization: [ + 'text', + 'gradients', + 'link', + ], }, typography: { fontSize: true, @@ -244,17 +279,22 @@ describe( 'skipBlockSupportAttributes', () => { } ); expect( - removeBlockSupportAttributes( 'core/test-block', attributes ) + removeBlockSupportAttributes( 'core/test-block', allAttributes ) ).toEqual( { - customAttribute: 'custom-attribute', textColor: 'foreground', gradient: 'vivid-cyan-blue-to-vivid-purple', fontSize: 'small', style: { - customStyle: 'custom-style', color: { text: '#000000', }, + elements: { + link: { + color: { + text: '#000000', + }, + }, + }, typography: { fontSize: '10px', fontWeight: '500', diff --git a/packages/server-side-render/src/utils.js b/packages/server-side-render/src/utils.js index 10f1d581285912..e7cd8d011af260 100644 --- a/packages/server-side-render/src/utils.js +++ b/packages/server-side-render/src/utils.js @@ -123,14 +123,17 @@ export function removeBlockSupportAttributes( block, attributes ) { {} ); - return cleanEmptyObject( { - ...restAttributes, - ...newAttributes, - style: { - ...style, - ...newStyle, - }, - } ); + // Override with new block support attributes and styles. + return ( + cleanEmptyObject( { + ...restAttributes, + ...newAttributes, + style: { + ...style, + ...newStyle, + }, + } ) || {} + ); } export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { From e027d442ca5335cf91d159302258d0f11993d8e1 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sun, 2 Oct 2022 21:24:02 +0900 Subject: [PATCH 11/22] Update function docs --- packages/server-side-render/src/utils.js | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/server-side-render/src/utils.js b/packages/server-side-render/src/utils.js index e7cd8d011af260..350128dc219372 100644 --- a/packages/server-side-render/src/utils.js +++ b/packages/server-side-render/src/utils.js @@ -16,6 +16,16 @@ import { ATTRIBUTE_PROPERTY, STYLE_PROPERTY } from './constants'; const identity = ( x ) => x; +/** + * Check whether serialization of specific block support feature or set should + * be skipped. + * + * @param {string} blockType Block name. + * @param {string} featureSet Name of block support feature set. + * @param {string} feature Name of the individual feature to check. + * + * @return {boolean} Whether serialization should occur. + */ function shouldSkipSerialization( blockType, featureSet, feature ) { const support = getBlockSupport( blockType, featureSet ); const skipSerialization = support?.__experimentalSkipSerialization; @@ -27,6 +37,13 @@ function shouldSkipSerialization( blockType, featureSet, feature ) { return skipSerialization; } +/** + * Remove attributes and styles, taking into account serialization of block supports. + * + * @param {string} block Block name. + * @param {*} attributes Block attributes. + * @return {*} Cleaned up block attributes. + */ export function removeBlockSupportAttributes( block, attributes ) { // Omit className and style from attributes. const { className, style, ...restAttributes } = attributes; @@ -136,6 +153,14 @@ export function removeBlockSupportAttributes( block, attributes ) { ); } +/** + * Create the path to fetch api. + * + * @param {string} block Block name. + * @param {*} attributes Block attributes. + * @param {*} urlQueryArgs Query arguments to apply to the request URL. + * @return {string} Path to fetch api. + */ export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { return addQueryArgs( `/wp/v2/block-renderer/${ block }`, { context: 'edit', From d9600d69aa864ea6e6775f5ddb919119755c31cd Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Wed, 5 Oct 2022 15:01:25 +0900 Subject: [PATCH 12/22] Revert "Update function docs" This reverts commit e027d442ca5335cf91d159302258d0f11993d8e1. --- packages/server-side-render/src/utils.js | 25 ------------------------ 1 file changed, 25 deletions(-) diff --git a/packages/server-side-render/src/utils.js b/packages/server-side-render/src/utils.js index 350128dc219372..e7cd8d011af260 100644 --- a/packages/server-side-render/src/utils.js +++ b/packages/server-side-render/src/utils.js @@ -16,16 +16,6 @@ import { ATTRIBUTE_PROPERTY, STYLE_PROPERTY } from './constants'; const identity = ( x ) => x; -/** - * Check whether serialization of specific block support feature or set should - * be skipped. - * - * @param {string} blockType Block name. - * @param {string} featureSet Name of block support feature set. - * @param {string} feature Name of the individual feature to check. - * - * @return {boolean} Whether serialization should occur. - */ function shouldSkipSerialization( blockType, featureSet, feature ) { const support = getBlockSupport( blockType, featureSet ); const skipSerialization = support?.__experimentalSkipSerialization; @@ -37,13 +27,6 @@ function shouldSkipSerialization( blockType, featureSet, feature ) { return skipSerialization; } -/** - * Remove attributes and styles, taking into account serialization of block supports. - * - * @param {string} block Block name. - * @param {*} attributes Block attributes. - * @return {*} Cleaned up block attributes. - */ export function removeBlockSupportAttributes( block, attributes ) { // Omit className and style from attributes. const { className, style, ...restAttributes } = attributes; @@ -153,14 +136,6 @@ export function removeBlockSupportAttributes( block, attributes ) { ); } -/** - * Create the path to fetch api. - * - * @param {string} block Block name. - * @param {*} attributes Block attributes. - * @param {*} urlQueryArgs Query arguments to apply to the request URL. - * @return {string} Path to fetch api. - */ export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { return addQueryArgs( `/wp/v2/block-renderer/${ block }`, { context: 'edit', From 1a7fd7c22104c88abb26c968753508fec072d2c0 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Wed, 5 Oct 2022 15:01:32 +0900 Subject: [PATCH 13/22] Revert "Support color.link and update tests" This reverts commit abf2d7e61ddaf69f412a04ec0f46f24eac1d0ecc. --- packages/server-side-render/src/constants.js | 5 - packages/server-side-render/src/test/index.js | 190 +++++++----------- packages/server-side-render/src/utils.js | 19 +- 3 files changed, 83 insertions(+), 131 deletions(-) diff --git a/packages/server-side-render/src/constants.js b/packages/server-side-render/src/constants.js index b88ee3395349dd..0e549cc06f84aa 100644 --- a/packages/server-side-render/src/constants.js +++ b/packages/server-side-render/src/constants.js @@ -19,11 +19,6 @@ export const STYLE_PROPERTY = { support: [ 'color', 'gradients' ], }, }, - elements: { - link: { - support: [ 'color', 'link' ], - }, - }, typography: { fontSize: { support: [ 'typography', 'fontSize' ], diff --git a/packages/server-side-render/src/test/index.js b/packages/server-side-render/src/test/index.js index 2e05d0f70d4456..3eec69c9a7e8ad 100644 --- a/packages/server-side-render/src/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -86,73 +86,6 @@ describe( 'rendererPath', () => { } ); } ); -const allAttributes = { - textColor: 'foreground', - backgroundColor: 'foreground', - gradient: 'vivid-cyan-blue-to-vivid-purple', - fontSize: 'small', - fontFamily: 'system-font', - borderColor: 'foreground', - style: { - color: { - text: '#000000', - background: '#000000', - gradients: '#000000', - }, - elements: { - link: { - color: { - text: '#000000', - }, - }, - }, - typography: { - fontSize: '10px', - lineHeight: '1', - fontWeight: '500', - fontStyle: 'normal', - textTransform: 'uppercase', - textDecoration: 'line-through', - letterSpacing: '10px', - }, - spacing: { - margin: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, - padding: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, - blockGap: '10px', - }, - border: { - radius: '10px', - style: 'solid', - top: { - width: '10px', - color: '#000000', - }, - right: { - width: '10px', - color: '#000000', - }, - bottom: { - width: '10px', - color: '#000000', - }, - left: { - width: '10px', - color: '#000000', - }, - }, - }, -}; - describe( 'skipBlockSupportAttributes', () => { afterEach( () => { getBlockTypes().forEach( ( block ) => { @@ -160,42 +93,72 @@ describe( 'skipBlockSupportAttributes', () => { } ); } ); - test( 'should remove custom CSS class', () => { - const attributes = { - className: 'class-name', - }; - - registerBlockType( 'core/test-block', { - title: 'test block', - } ); - - expect( - removeBlockSupportAttributes( 'core/test-block', attributes ) - ).toEqual( {} ); - } ); - - test( 'should not remove custom style', () => { - const attributes = { - style: { - customStyle: 'custom-style', + const attributes = { + className: 'class-name', + customAttribute: 'custom-attribute', + textColor: 'foreground', + backgroundColor: 'foreground', + gradient: 'vivid-cyan-blue-to-vivid-purple', + fontSize: 'small', + fontFamily: 'system-font', + borderColor: 'foreground', + style: { + customStyle: 'custom-style', + color: { + text: '#000000', + background: '#000000', + gradients: '#000000', }, - }; - - registerBlockType( 'core/test-block', { - title: 'test block', - } ); - - expect( - removeBlockSupportAttributes( 'core/test-block', attributes ) - ).toEqual( { - style: { - customStyle: 'custom-style', + typography: { + fontSize: '10px', + lineHeight: '1', + fontWeight: '500', + fontStyle: 'normal', + textTransform: 'uppercase', + textDecoration: 'line-through', + letterSpacing: '10px', }, - } ); - } ); + spacing: { + margin: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + padding: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + blockGap: '10px', + }, + border: { + radius: '10px', + style: 'solid', + top: { + width: '10px', + color: '#000000', + }, + right: { + width: '10px', + color: '#000000', + }, + bottom: { + width: '10px', + color: '#000000', + }, + left: { + width: '10px', + color: '#000000', + }, + }, + }, + }; - test( 'Should remove all attributes and style properties', () => { + test( 'Should remove attributes and style properties', () => { registerBlockType( 'core/test-block', { + category: 'text', title: 'test block', supports: { color: { @@ -229,12 +192,18 @@ describe( 'skipBlockSupportAttributes', () => { } ); expect( - removeBlockSupportAttributes( 'core/test-block', allAttributes ) - ).toEqual( {} ); + removeBlockSupportAttributes( 'core/test-block', attributes ) + ).toEqual( { + customAttribute: 'custom-attribute', + style: { + customStyle: 'custom-style', + }, + } ); } ); - test( 'Should pass attributes and style properties which serialization is omitted', () => { + test( 'Should skip attributes and style properties which serialization is omitted', () => { registerBlockType( 'core/test-block', { + category: 'text', title: 'test block', supports: { color: { @@ -242,11 +211,7 @@ describe( 'skipBlockSupportAttributes', () => { background: true, gradients: true, link: true, - __experimentalSkipSerialization: [ - 'text', - 'gradients', - 'link', - ], + __experimentalSkipSerialization: [ 'text', 'gradients' ], }, typography: { fontSize: true, @@ -279,22 +244,17 @@ describe( 'skipBlockSupportAttributes', () => { } ); expect( - removeBlockSupportAttributes( 'core/test-block', allAttributes ) + removeBlockSupportAttributes( 'core/test-block', attributes ) ).toEqual( { + customAttribute: 'custom-attribute', textColor: 'foreground', gradient: 'vivid-cyan-blue-to-vivid-purple', fontSize: 'small', style: { + customStyle: 'custom-style', color: { text: '#000000', }, - elements: { - link: { - color: { - text: '#000000', - }, - }, - }, typography: { fontSize: '10px', fontWeight: '500', diff --git a/packages/server-side-render/src/utils.js b/packages/server-side-render/src/utils.js index e7cd8d011af260..10f1d581285912 100644 --- a/packages/server-side-render/src/utils.js +++ b/packages/server-side-render/src/utils.js @@ -123,17 +123,14 @@ export function removeBlockSupportAttributes( block, attributes ) { {} ); - // Override with new block support attributes and styles. - return ( - cleanEmptyObject( { - ...restAttributes, - ...newAttributes, - style: { - ...style, - ...newStyle, - }, - } ) || {} - ); + return cleanEmptyObject( { + ...restAttributes, + ...newAttributes, + style: { + ...style, + ...newStyle, + }, + } ); } export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { From 43910b23d86ed2638b4bd070747536e73275fd2d Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Wed, 5 Oct 2022 15:01:38 +0900 Subject: [PATCH 14/22] Revert "Don't remove custom style" This reverts commit 04f3af08234f71775dd1067961c649d2922253bb. --- packages/server-side-render/src/test/index.js | 5 ----- packages/server-side-render/src/utils.js | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/server-side-render/src/test/index.js b/packages/server-side-render/src/test/index.js index 3eec69c9a7e8ad..453c533398fea1 100644 --- a/packages/server-side-render/src/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -103,7 +103,6 @@ describe( 'skipBlockSupportAttributes', () => { fontFamily: 'system-font', borderColor: 'foreground', style: { - customStyle: 'custom-style', color: { text: '#000000', background: '#000000', @@ -195,9 +194,6 @@ describe( 'skipBlockSupportAttributes', () => { removeBlockSupportAttributes( 'core/test-block', attributes ) ).toEqual( { customAttribute: 'custom-attribute', - style: { - customStyle: 'custom-style', - }, } ); } ); @@ -251,7 +247,6 @@ describe( 'skipBlockSupportAttributes', () => { gradient: 'vivid-cyan-blue-to-vivid-purple', fontSize: 'small', style: { - customStyle: 'custom-style', color: { text: '#000000', }, diff --git a/packages/server-side-render/src/utils.js b/packages/server-side-render/src/utils.js index 10f1d581285912..7dbaacfb6b0e02 100644 --- a/packages/server-side-render/src/utils.js +++ b/packages/server-side-render/src/utils.js @@ -126,10 +126,7 @@ export function removeBlockSupportAttributes( block, attributes ) { return cleanEmptyObject( { ...restAttributes, ...newAttributes, - style: { - ...style, - ...newStyle, - }, + style: newStyle, } ); } From 5d811c8cd46bc3c4c5c230696eea8560292a3823 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Wed, 5 Oct 2022 15:01:46 +0900 Subject: [PATCH 15/22] Revert "Update readme" This reverts commit f1b0670a7b304a194489860dd96e72cd40aa10fd. --- packages/server-side-render/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server-side-render/README.md b/packages/server-side-render/README.md index faec9024bd49b0..479627fd6c5269 100644 --- a/packages/server-side-render/README.md +++ b/packages/server-side-render/README.md @@ -78,7 +78,7 @@ add_filter( 'rest_endpoints', 'add_rest_method'); ### skipBlockSupportAttributes -Remove attributes and style properties applied by the block supports. This prevents duplication of styles in the block wrapper and the `ServerSideRender` components. Attributes and styles provided by the block supports for which `__experimentalSkipSerialization` is specified will not be removed. +Remove attributes and style properties applied by the block supports. This prevents duplication of styles in the block wrapper and the `ServerSideRender` components. - Type: `Boolean` - Required: No From bd1ff1ed05a10a96a9d7b0092dc7bc89d274aaf5 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Wed, 5 Oct 2022 15:01:58 +0900 Subject: [PATCH 16/22] Revert "Update unit tests" This reverts commit a42b10ee5a2e4fc8729ea1e75a387a2df45fcfda. --- packages/server-side-render/src/constants.js | 4 +- packages/server-side-render/src/test/index.js | 256 ++++-------------- 2 files changed, 56 insertions(+), 204 deletions(-) diff --git a/packages/server-side-render/src/constants.js b/packages/server-side-render/src/constants.js index 0e549cc06f84aa..30a8e9f4a5641f 100644 --- a/packages/server-side-render/src/constants.js +++ b/packages/server-side-render/src/constants.js @@ -1,7 +1,7 @@ export const ATTRIBUTE_PROPERTY = { textColor: [ 'color', 'text' ], backgroundColor: [ 'color', 'background' ], - gradient: [ 'color', 'gradients' ], + gradient: [ 'color', 'gradient' ], fontSize: [ 'typography', 'fontSize' ], fontFamily: [ 'typography', '__experimentalFontFamily' ], borderColor: [ '__experimentalBorder', 'color' ], @@ -16,7 +16,7 @@ export const STYLE_PROPERTY = { support: [ 'color', 'background' ], }, gradient: { - support: [ 'color', 'gradients' ], + support: [ 'color', 'gradient' ], }, }, typography: { diff --git a/packages/server-side-render/src/test/index.js b/packages/server-side-render/src/test/index.js index 453c533398fea1..c50befa3ba8a28 100644 --- a/packages/server-side-render/src/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -1,16 +1,10 @@ -/** - * WordPress dependencies - */ -import { - registerBlockType, - unregisterBlockType, - getBlockTypes, -} from '@wordpress/blocks'; - /** * Internal dependencies */ -import { rendererPath, removeBlockSupportAttributes } from '../utils'; +import { + rendererPath, + removeBlockSupportAttributes, +} from '../server-side-render'; describe( 'rendererPath', () => { test( 'should return an base path for empty input', () => { @@ -84,206 +78,64 @@ describe( 'rendererPath', () => { '/wp/v2/block-renderer/core/test-block?context=edit&attributes%5BstringArg%5D=test&id=1234' ); } ); -} ); - -describe( 'skipBlockSupportAttributes', () => { - afterEach( () => { - getBlockTypes().forEach( ( block ) => { - unregisterBlockType( block.name ); - } ); - } ); - - const attributes = { - className: 'class-name', - customAttribute: 'custom-attribute', - textColor: 'foreground', - backgroundColor: 'foreground', - gradient: 'vivid-cyan-blue-to-vivid-purple', - fontSize: 'small', - fontFamily: 'system-font', - borderColor: 'foreground', - style: { - color: { - text: '#000000', - background: '#000000', - gradients: '#000000', - }, - typography: { - fontSize: '10px', - lineHeight: '1', - fontWeight: '500', - fontStyle: 'normal', - textTransform: 'uppercase', - textDecoration: 'line-through', - letterSpacing: '10px', - }, - spacing: { - margin: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, - padding: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, - blockGap: '10px', - }, - border: { - radius: '10px', - style: 'solid', - top: { - width: '10px', - color: '#000000', - }, - right: { - width: '10px', - color: '#000000', - }, - bottom: { - width: '10px', - color: '#000000', - }, - left: { - width: '10px', - color: '#000000', - }, - }, - }, - }; - - test( 'Should remove attributes and style properties', () => { - registerBlockType( 'core/test-block', { - category: 'text', - title: 'test block', - supports: { - color: { - text: true, - background: true, - gradients: true, - link: true, - }, - typography: { - fontSize: true, - lineHeight: true, - __experimentalFontFamily: true, - __experimentalFontWeight: true, - __experimentalFontStyle: true, - __experimentalTextTransform: true, - __experimentalTextDecoration: true, - __experimentalLetterSpacing: true, - }, - spacing: { - margin: true, - padding: true, - blockGap: true, - }, - __experimentalBorder: { - radius: true, - width: true, - color: true, - style: true, - }, - }, - } ); + test( 'Should remove attributes and style properties applied by the block supports', () => { expect( - removeBlockSupportAttributes( 'core/test-block', attributes ) - ).toEqual( { - customAttribute: 'custom-attribute', - } ); - } ); - - test( 'Should skip attributes and style properties which serialization is omitted', () => { - registerBlockType( 'core/test-block', { - category: 'text', - title: 'test block', - supports: { - color: { - text: true, - background: true, - gradients: true, - link: true, - __experimentalSkipSerialization: [ 'text', 'gradients' ], - }, - typography: { - fontSize: true, - lineHeight: true, - __experimentalFontFamily: true, - __experimentalFontWeight: true, - __experimentalFontStyle: true, - __experimentalTextTransform: true, - __experimentalTextDecoration: true, - __experimentalLetterSpacing: true, - __experimentalSkipSerialization: [ - 'fontSize', - '__experimentalFontWeight', - ], - }, - spacing: { - margin: true, - padding: true, - blockGap: true, - __experimentalSkipSerialization: true, - }, - __experimentalBorder: { - radius: true, - width: true, - color: true, - style: true, - __experimentalSkipSerialization: [ 'width', 'style' ], - }, - }, - } ); - - expect( - removeBlockSupportAttributes( 'core/test-block', attributes ) - ).toEqual( { - customAttribute: 'custom-attribute', - textColor: 'foreground', - gradient: 'vivid-cyan-blue-to-vivid-purple', - fontSize: 'small', - style: { - color: { - text: '#000000', - }, - typography: { - fontSize: '10px', - fontWeight: '500', - }, - spacing: { - margin: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, - padding: { - top: '10px', - right: '10px', - bottom: '10px', - left: '10px', - }, - blockGap: '10px', - }, - border: { - style: 'solid', - top: { + removeBlockSupportAttributes( { + backgroundColor: 'foreground', + borderColor: 'foreground', + fontFamily: 'system-font', + fontSize: 'small', + gradient: 'vivid-cyan-blue-to-vivid-purple', + textColor: 'foreground', + customAttribute: 'customAttribute', + style: { + border: { + radius: '10px', + style: 'solid', width: '10px', }, - right: { - width: '10px', + color: { + background: '#000000', + text: '#000000', }, - bottom: { - width: '10px', + elements: { + link: { + color: { + text: '#000000', + }, + }, }, - left: { - width: '10px', + spacing: { + margin: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + padding: { + top: '10px', + right: '10px', + bottom: '10px', + left: '10px', + }, + }, + typography: { + fontSize: '10px', + fontStyle: 'normal', + fontWeight: '500', + letterSpacing: '10px', + lineHeight: '1', + textDecoration: 'line-through', + textTransform: 'uppercase', }, + customStyle: 'customStyle', }, + } ) + ).toEqual( { + customAttribute: 'customAttribute', + style: { + customStyle: 'customStyle', }, } ); } ); From aa507a18913949ec5211cbff8ed9cfb04c9b4196 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Wed, 5 Oct 2022 15:02:07 +0900 Subject: [PATCH 17/22] Revert "Don't remove attributes and styles which serialization is omitted" This reverts commit 8791cc3d9441cdefdd1486966b688b1baeee23a4. --- packages/server-side-render/src/constants.js | 76 --------- .../src/server-side-render.js | 40 ++++- packages/server-side-render/src/utils.js | 160 ------------------ 3 files changed, 32 insertions(+), 244 deletions(-) delete mode 100644 packages/server-side-render/src/constants.js delete mode 100644 packages/server-side-render/src/utils.js diff --git a/packages/server-side-render/src/constants.js b/packages/server-side-render/src/constants.js deleted file mode 100644 index 30a8e9f4a5641f..00000000000000 --- a/packages/server-side-render/src/constants.js +++ /dev/null @@ -1,76 +0,0 @@ -export const ATTRIBUTE_PROPERTY = { - textColor: [ 'color', 'text' ], - backgroundColor: [ 'color', 'background' ], - gradient: [ 'color', 'gradient' ], - fontSize: [ 'typography', 'fontSize' ], - fontFamily: [ 'typography', '__experimentalFontFamily' ], - borderColor: [ '__experimentalBorder', 'color' ], -}; - -export const STYLE_PROPERTY = { - color: { - text: { - support: [ 'color', 'text' ], - }, - background: { - support: [ 'color', 'background' ], - }, - gradient: { - support: [ 'color', 'gradient' ], - }, - }, - typography: { - fontSize: { - support: [ 'typography', 'fontSize' ], - }, - fontWeight: { - support: [ 'typography', '__experimentalFontWeight' ], - }, - fontStyle: { - support: [ 'typography', '__experimentalFontStyle' ], - }, - textTransform: { - support: [ 'typography', '__experimentalTextTransform' ], - }, - leterSpacing: { - support: [ 'typography', '__experimentalLetterSpacing' ], - }, - textDecoration: { - support: [ 'typography', '__experimentalTextDecoration' ], - }, - }, - spacing: { - margin: { - support: [ 'spacing', 'margin' ], - }, - padding: { - support: [ 'spacing', 'padding' ], - }, - blockGap: { - support: [ 'spacing', 'blockGap' ], - }, - }, - border: { - radius: { - support: [ '__experimentalBorder', 'radius' ], - subProperties: [ - 'topLeft', - 'topRight', - 'bottomRight', - 'bottomLeft', - ], - }, - color: { - support: [ '__experimentalBorder', 'color' ], - additionalProperties: [ 'top', 'right', 'bottom', 'left' ], - }, - style: { - support: [ '__experimentalBorder', 'style' ], - additionalProperties: [ 'top', 'right', 'bottom', 'left' ], - }, - width: { - support: [ '__experimentalBorder', 'width' ], - additionalProperties: [ 'top', 'right', 'bottom', 'left' ], - }, - }, -}; diff --git a/packages/server-side-render/src/server-side-render.js b/packages/server-side-render/src/server-side-render.js index ccd6471e69b9f2..badb59ebd78cd5 100644 --- a/packages/server-side-render/src/server-side-render.js +++ b/packages/server-side-render/src/server-side-render.js @@ -10,13 +10,39 @@ import { useDebounce, usePrevious } from '@wordpress/compose'; import { RawHTML, useEffect, useRef, useState } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import apiFetch from '@wordpress/api-fetch'; +import { addQueryArgs } from '@wordpress/url'; import { Placeholder, Spinner } from '@wordpress/components'; import { __experimentalSanitizeBlockAttributes } from '@wordpress/blocks'; -/** - * Internal dependencies - */ -import { rendererPath, removeBlockSupportAttributes } from './utils'; +const EMPTY_OBJECT = {}; + +export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { + return addQueryArgs( `/wp/v2/block-renderer/${ block }`, { + context: 'edit', + ...( null !== attributes ? { attributes } : {} ), + ...urlQueryArgs, + } ); +} + +export function removeBlockSupportAttributes( attributes ) { + const { + backgroundColor, + borderColor, + fontFamily, + fontSize, + gradient, + textColor, + ...restAttributes + } = attributes; + + const { border, color, elements, spacing, typography, ...restStyles } = + attributes?.style || EMPTY_OBJECT; + + return { + ...restAttributes, + style: restStyles, + }; +} function DefaultEmptyResponsePlaceholder( { className } ) { return ( @@ -90,10 +116,8 @@ export default function ServerSideRender( props ) { __experimentalSanitizeBlockAttributes( block, attributes ); if ( skipBlockSupportAttributes ) { - sanitizedAttributes = removeBlockSupportAttributes( - block, - sanitizedAttributes - ); + sanitizedAttributes = + removeBlockSupportAttributes( sanitizedAttributes ); } // If httpMethod is 'POST', send the attributes in the request body instead of the URL. diff --git a/packages/server-side-render/src/utils.js b/packages/server-side-render/src/utils.js deleted file mode 100644 index 7dbaacfb6b0e02..00000000000000 --- a/packages/server-side-render/src/utils.js +++ /dev/null @@ -1,160 +0,0 @@ -/** - * External dependencies - */ -import { pickBy, isEmpty, mapValues } from 'lodash'; - -/** - * WordPress dependencies - */ -import { addQueryArgs } from '@wordpress/url'; -import { getBlockSupport } from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import { ATTRIBUTE_PROPERTY, STYLE_PROPERTY } from './constants'; - -const identity = ( x ) => x; - -function shouldSkipSerialization( blockType, featureSet, feature ) { - const support = getBlockSupport( blockType, featureSet ); - const skipSerialization = support?.__experimentalSkipSerialization; - - if ( Array.isArray( skipSerialization ) ) { - return skipSerialization.includes( feature ); - } - - return skipSerialization; -} - -export function removeBlockSupportAttributes( block, attributes ) { - // Omit className and style from attributes. - const { className, style, ...restAttributes } = attributes; - - // Create new attributes object. - const newAttributes = Object.keys( ATTRIBUTE_PROPERTY ).reduce( - ( acc, attributeName ) => { - const support = ATTRIBUTE_PROPERTY[ attributeName ]; - - const skipSerialization = shouldSkipSerialization( - block, - support[ 0 ], - support[ 1 ] - ); - - // Reset attributes which serialization is NOT omitted. - if ( ! skipSerialization ) { - acc[ attributeName ] = undefined; - return acc; - } - - // Add attributes which serialization is omitted. - acc[ attributeName ] = restAttributes[ attributeName ]; - return acc; - }, - {} - ); - - // Create new style object. - const newStyle = Object.keys( STYLE_PROPERTY ).reduce( - ( acc, styleName ) => { - // Initialize style name properties. - acc[ styleName ] = {}; - if ( styleName === 'border' ) { - acc[ styleName ] = { - top: {}, - right: {}, - bottom: {}, - left: {}, - }; - } - - // Only add styles for which serialization is omitted. - Object.keys( STYLE_PROPERTY[ styleName ] ).forEach( ( key ) => { - const { support, subProperties, additionalProperties } = - STYLE_PROPERTY[ styleName ][ key ]; - - const skipSerialization = shouldSkipSerialization( - block, - support[ 0 ], - support[ 1 ] - ); - - // Skip styles which serialization is NOT omitted. - if ( ! skipSerialization ) { - return; - } - - // Add border-radius styles. - if ( subProperties ) { - if ( typeof style?.[ styleName ]?.[ key ] === 'string' ) { - acc[ styleName ][ key ] = style?.[ styleName ]?.[ key ]; - } else if ( - typeof style?.[ styleName ]?.[ key ] === 'object' - ) { - acc[ styleName ][ key ] = {}; - subProperties.forEach( ( prop ) => { - acc[ styleName ][ key ][ prop ] = - style?.[ styleName ]?.[ key ]?.[ prop ]; - } ); - } - return; - } - - // Add border-{color|width|style} styles. - if ( additionalProperties ) { - if ( typeof style?.[ styleName ]?.[ key ] === 'string' ) { - acc[ styleName ][ key ] = style?.[ styleName ]?.[ key ]; - } else { - additionalProperties.forEach( ( prop ) => { - acc[ styleName ][ prop ][ key ] = - style?.[ styleName ]?.[ prop ]?.[ key ]; - } ); - } - return; - } - - // Add other styles. - acc[ styleName ][ key ] = style?.[ styleName ]?.[ key ]; - } ); - - return acc; - }, - {} - ); - - return cleanEmptyObject( { - ...restAttributes, - ...newAttributes, - style: newStyle, - } ); -} - -export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { - return addQueryArgs( `/wp/v2/block-renderer/${ block }`, { - context: 'edit', - ...( null !== attributes ? { attributes } : {} ), - ...urlQueryArgs, - } ); -} - -/** - * Removed falsy values from nested object. - * - * @param {*} object - * @return {*} Object cleaned from falsy values - */ -export const cleanEmptyObject = ( object ) => { - if ( - object === null || - typeof object !== 'object' || - Array.isArray( object ) - ) { - return object; - } - const cleanedNestedObjects = pickBy( - mapValues( object, cleanEmptyObject ), - identity - ); - return isEmpty( cleanedNestedObjects ) ? undefined : cleanedNestedObjects; -}; From 7b02d8d7d808c27b0a86de6cc345de2b1ad63074 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Wed, 5 Oct 2022 16:21:46 +0900 Subject: [PATCH 18/22] Don't pass className --- packages/server-side-render/src/server-side-render.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server-side-render/src/server-side-render.js b/packages/server-side-render/src/server-side-render.js index badb59ebd78cd5..07d120e11440d4 100644 --- a/packages/server-side-render/src/server-side-render.js +++ b/packages/server-side-render/src/server-side-render.js @@ -32,6 +32,7 @@ export function removeBlockSupportAttributes( attributes ) { fontSize, gradient, textColor, + className, ...restAttributes } = attributes; From 4be4688000d2571fceed73285a1077941d6aa30c Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Wed, 5 Oct 2022 16:22:54 +0900 Subject: [PATCH 19/22] Update unit test --- packages/server-side-render/src/test/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server-side-render/src/test/index.js b/packages/server-side-render/src/test/index.js index c50befa3ba8a28..13819fedd3c2b1 100644 --- a/packages/server-side-render/src/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -89,6 +89,7 @@ describe( 'rendererPath', () => { gradient: 'vivid-cyan-blue-to-vivid-purple', textColor: 'foreground', customAttribute: 'customAttribute', + className: 'custom-class', style: { border: { radius: '10px', From ce8937a7803994f31b12a17a0f976c3283ca14fb Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Fri, 7 Oct 2022 16:10:18 +0900 Subject: [PATCH 20/22] Update readme Co-authored-by: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> --- packages/server-side-render/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server-side-render/README.md b/packages/server-side-render/README.md index 479627fd6c5269..b80ce5098f016e 100644 --- a/packages/server-side-render/README.md +++ b/packages/server-side-render/README.md @@ -82,6 +82,7 @@ Remove attributes and style properties applied by the block supports. This preve - Type: `Boolean` - Required: No +- Default: false ### urlQueryArgs From d58e60c6e539633483608f0fc6b22636003f9877 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Fri, 7 Oct 2022 16:19:52 +0900 Subject: [PATCH 21/22] Update readme --- packages/server-side-render/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/server-side-render/README.md b/packages/server-side-render/README.md index b80ce5098f016e..9c780868931475 100644 --- a/packages/server-side-render/README.md +++ b/packages/server-side-render/README.md @@ -56,6 +56,7 @@ The HTTP request method to use, either 'GET' or 'POST'. It's 'GET' by default. T - Type: `String` - Required: No +- Default: 'GET' #### Example: @@ -78,7 +79,7 @@ add_filter( 'rest_endpoints', 'add_rest_method'); ### skipBlockSupportAttributes -Remove attributes and style properties applied by the block supports. This prevents duplication of styles in the block wrapper and the `ServerSideRender` components. +Remove attributes and style properties applied by the block supports. This prevents duplication of styles in the block wrapper and the `ServerSideRender` components. Even if certain features skip serialization to HTML markup by `__experimentalSkipSerialization`, all attributes and style properties are removed. - Type: `Boolean` - Required: No From 0de5c1f05d815ec802309f40daba5d4039fec6dc Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Fri, 7 Oct 2022 16:52:45 +0900 Subject: [PATCH 22/22] Revert unexpected changes --- .github/dependabot.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index cd5fa3082d7d78..59542a88ffa3dd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,9 +2,9 @@ version: 2 updates: - # Check for updates to GitHub Actions. - - package-ecosystem: 'github-actions' - directory: '/' - schedule: - interval: 'daily' - open-pull-requests-limit: 10 + # Check for updates to GitHub Actions. + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 10