From 6fe71ec4d5cd4b0eb83a2c0062865cc806599649 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 4 Jul 2024 14:05:15 +0200 Subject: [PATCH 01/41] Block Variations: Add block-support for variation-specific classnames --- .../src/components/block-edit/edit.js | 23 ++- .../src/components/block-edit/test/edit.js | 43 ++++++ .../src/components/block-list/block.js | 26 +++- .../hooks/generated-variation-class-name.js | 64 +++++++++ packages/block-editor/src/hooks/index.js | 1 + .../block-editor/src/hooks/index.native.js | 1 + .../test/generated-variation-class-name.js | 132 ++++++++++++++++++ packages/blocks/src/api/index.js | 1 + .../parser/apply-built-in-validation-fixes.js | 1 + packages/blocks/src/api/registration.js | 20 +++ packages/blocks/src/api/serializer.js | 2 +- packages/blocks/src/api/test/serializer.js | 27 ++++ schemas/json/block.json | 17 ++- 13 files changed, 347 insertions(+), 11 deletions(-) create mode 100644 packages/block-editor/src/hooks/generated-variation-class-name.js create mode 100644 packages/block-editor/src/hooks/test/generated-variation-class-name.js diff --git a/packages/block-editor/src/components/block-edit/edit.js b/packages/block-editor/src/components/block-edit/edit.js index 83d0e3f406f829..6addedc96491ad 100644 --- a/packages/block-editor/src/components/block-edit/edit.js +++ b/packages/block-editor/src/components/block-edit/edit.js @@ -11,6 +11,7 @@ import { getBlockDefaultClassName, hasBlockSupport, getBlockType, + getActiveBlockVariation, } from '@wordpress/blocks'; import { useContext, useMemo } from '@wordpress/element'; @@ -71,12 +72,24 @@ const EditWithGeneratedProps = ( props ) => { return ; } - // Generate a class name for the block's editable form. - const generatedClassName = hasBlockSupport( blockType, 'className', true ) - ? getBlockDefaultClassName( name ) - : null; + const generatedClassNames = []; + + if ( hasBlockSupport( blockType, 'className', true ) ) { + generatedClassNames.push( getBlockDefaultClassName( name ) ); + } + if ( hasBlockSupport( blockType, 'className.variation', false ) ) { + const activeVariation = getActiveBlockVariation( name, attributes ); + if ( activeVariation && activeVariation?.name ) { + generatedClassNames.push( + getBlockDefaultClassName( + `${ name }/${ activeVariation.name }` + ) + ); + } + } + const className = clsx( - generatedClassName, + generatedClassNames, attributes.className, props.className ); diff --git a/packages/block-editor/src/components/block-edit/test/edit.js b/packages/block-editor/src/components/block-edit/test/edit.js index 76afbcb852ac19..3a058ae4f44468 100644 --- a/packages/block-editor/src/components/block-edit/test/edit.js +++ b/packages/block-editor/src/components/block-edit/test/edit.js @@ -9,6 +9,8 @@ import { render, screen } from '@testing-library/react'; import { registerBlockType, unregisterBlockType, + registerBlockVariation, + unregisterBlockVariation, getBlockTypes, } from '@wordpress/blocks'; @@ -84,6 +86,47 @@ describe( 'Edit', () => { expect( editElement ).toHaveClass( 'my-class' ); } ); + it( 'should combine the default class name with a variation one', () => { + const edit = ( { className } ) => ( +
+ ); + + registerBlockType( 'core/test-block', { + edit, + save: noop, + category: 'text', + title: 'block title', + attributes: { + fruit: { + type: 'string', + default: 'Apples', + }, + }, + } ); + + registerBlockVariation( 'core/test-block', { + name: 'variation', + title: 'block variation title', + attributes: { + fruit: { + type: 'string', + default: 'Bananas', + }, + }, + isActive: ( { fruit } ) => fruit === 'Bananas', + } ); + + render( + + ); + + const editElement = screen.getByTestId( 'foo-bar' ); + expect( editElement ).toHaveClass( 'wp-block-test-block' ); + expect( editElement ).toHaveClass( 'wp-block-test-block-variation' ); + + unregisterBlockVariation( 'core/test-block', 'variation' ); + } ); + it( 'should assign context', () => { const edit = ( { context } ) => context.value; registerBlockType( 'core/test-block', { diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index deda4e3b9d0897..c24f1d3c0105fd 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -592,12 +592,30 @@ function BlockListBlockProvider( props ) { hasBlockSupport: _hasBlockSupport, getActiveBlockVariation, } = select( blocksStore ); + const attributes = getBlockAttributes( clientId ); const { name: blockName, isValid } = blockWithoutAttributes; + const match = getActiveBlockVariation( blockName, attributes ); const blockType = getBlockType( blockName ); const { supportsLayout, __unstableIsPreviewMode: isPreviewMode } = getSettings(); const hasLightBlockWrapper = blockType?.apiVersion > 1; + const defaultClassNames = []; + if ( hasLightBlockWrapper && blockName ) { + defaultClassNames.push( getBlockDefaultClassName( blockName ) ); + + if ( + hasBlockSupport( blockType, 'className.variation', false ) + ) { + if ( match && match?.name ) { + defaultClassNames.push( + getBlockDefaultClassName( + `${ blockName }/${ match.name }` + ) + ); + } + } + } const previewContext = { isPreviewMode, blockWithoutAttributes, @@ -610,9 +628,10 @@ function BlockListBlockProvider( props ) { className: hasLightBlockWrapper ? attributes.className : undefined, - defaultClassName: hasLightBlockWrapper - ? getBlockDefaultClassName( blockName ) - : undefined, + defaultClassName: + defaultClassNames.length > 0 + ? clsx( defaultClassNames ) + : undefined, blockTitle: blockType?.title, }; @@ -625,7 +644,6 @@ function BlockListBlockProvider( props ) { const _isSelected = isBlockSelected( clientId ); const canRemove = canRemoveBlock( clientId ); const canMove = canMoveBlock( clientId ); - const match = getActiveBlockVariation( blockName, attributes ); const isMultiSelected = isBlockMultiSelected( clientId ); const checkDeep = true; const isAncestorOfSelectedBlock = hasSelectedInnerBlock( diff --git a/packages/block-editor/src/hooks/generated-variation-class-name.js b/packages/block-editor/src/hooks/generated-variation-class-name.js new file mode 100644 index 00000000000000..fe332d747823f5 --- /dev/null +++ b/packages/block-editor/src/hooks/generated-variation-class-name.js @@ -0,0 +1,64 @@ +/** + * WordPress dependencies + */ +import { addFilter } from '@wordpress/hooks'; +import { + hasBlockSupport, + getBlockDefaultClassName, + getActiveBlockVariation, +} from '@wordpress/blocks'; + +/** + * Override props assigned to save component to inject generated className if + * block supports it. This is only applied if the block's save result is an + * element and not a markup string. + * + * @param {Object} extraProps Additional props applied to save element. + * @param {Object} blockType Block type. + * @param {Object} attributes Block attributes. + * + * @return {Object} Filtered props applied to save element. + */ +export function addGeneratedVariationClassName( + extraProps, + blockType, + attributes +) { + // Adding the generated className. + if ( hasBlockSupport( blockType, 'className.variation', false ) ) { + const activeVariation = getActiveBlockVariation( + blockType.name, + attributes + ); + + if ( ! activeVariation ) { + return extraProps; + } + + const variationName = `${ blockType.name }/${ activeVariation.name }`; + + if ( typeof extraProps.className === 'string' ) { + // We have some extra classes and want to add the default classname + extraProps.className = [ + ...new Set( [ + getBlockDefaultClassName( variationName ), + ...extraProps.className.split( ' ' ), + ] ), + ] + .join( ' ' ) + .trim(); + } else { + // There is no string in the className variable, + // so we just dump the default name in there. + extraProps.className = getBlockDefaultClassName( variationName ); + } + } + + return extraProps; +} + +addFilter( + 'blocks.getSaveContent.extraProps', + 'core/generated-variation-class-name/save-props', + addGeneratedVariationClassName +); diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js index 66ff60b691b66f..ac935847459c89 100644 --- a/packages/block-editor/src/hooks/index.js +++ b/packages/block-editor/src/hooks/index.js @@ -14,6 +14,7 @@ import anchor from './anchor'; import ariaLabel from './aria-label'; import customClassName from './custom-class-name'; import './generated-class-name'; +import './generated-variation-class-name'; import style from './style'; import './settings'; import color from './color'; diff --git a/packages/block-editor/src/hooks/index.native.js b/packages/block-editor/src/hooks/index.native.js index c7f9df868f2bd7..f2449c5500e7d7 100644 --- a/packages/block-editor/src/hooks/index.native.js +++ b/packages/block-editor/src/hooks/index.native.js @@ -11,6 +11,7 @@ import align from './align'; import anchor from './anchor'; import customClassName from './custom-class-name'; import './generated-class-name'; +import './generated-variation-class-name'; import style from './style'; import color from './color'; import fontSize from './font-size'; diff --git a/packages/block-editor/src/hooks/test/generated-variation-class-name.js b/packages/block-editor/src/hooks/test/generated-variation-class-name.js new file mode 100644 index 00000000000000..fab89b7f6b66f4 --- /dev/null +++ b/packages/block-editor/src/hooks/test/generated-variation-class-name.js @@ -0,0 +1,132 @@ +/** + * WordPress dependencies + */ +import { applyFilters } from '@wordpress/hooks'; +import { + registerBlockType, + unregisterBlockType, + registerBlockVariation, + unregisterBlockVariation, + getBlockType, +} from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import '../generated-variation-class-name'; + +describe( 'generated variation className', () => { + const defaultBlockSettings = { + attributes: { + fruit: { + type: 'string', + default: 'Bananas', + source: 'text', + selector: 'div', + }, + }, + save: ( { attributes } ) => ( + // eslint-disable-next-line react/no-unknown-property +
{ attributes.fruit }
+ ), + category: 'text', + title: 'block title', + }; + + const variationBlockSettings = { + attributes: { + fruit: { + type: 'string', + default: 'Bananas', + source: 'text', + selector: 'div', + }, + }, + isActive: ( { fruit } ) => fruit === 'Apples', + }; + + beforeAll( () => { + registerBlockType( 'core/test-block', { + ...defaultBlockSettings, + } ); + + registerBlockVariation( 'core/test-block', { + name: 'variation', + title: 'Variation', + ...variationBlockSettings, + } ); + } ); + + afterAll( () => { + unregisterBlockType( 'core/test-block' ); + unregisterBlockVariation( 'core/test-block', 'variation' ); + } ); + + describe( 'addSaveProps', () => { + const addSaveProps = applyFilters.bind( + null, + 'blocks.getSaveContent.extraProps' + ); + + it( 'should do nothing if the block settings do not define generated className support', () => { + const attributes = { className: 'foo' }; + const extraProps = addSaveProps( + {}, + { + ...defaultBlockSettings, + supports: { + className: false, + }, + }, + attributes + ); + + expect( extraProps ).not.toHaveProperty( 'className' ); + } ); + + it( 'should inject the generated className', () => { + const attributes = { fruit: 'Apples' }; + const blockType = getBlockType( 'core/test-block' ); + const variationBlockType = { + ...blockType, + ...variationBlockSettings, + }; + const extraProps = addSaveProps( + { className: 'foo' }, + variationBlockType, + attributes + ); + + expect( extraProps.className ).toContain( + 'wp-block-test-block-variation' + ); + } ); + + it( 'should not inject duplicates into className', () => { + const attributes = { fruit: 'Apples' }; + const blockType = getBlockType( 'core/test-block' ); + const variationBlockType = { + ...blockType, + attributes: { + ...blockType.attributes, + fruit: { + type: 'string', + default: 'Apples', + source: 'text', + selector: 'div', + }, + }, + isActive: ( { fruit } ) => fruit === 'Apples', + }; + const extraProps = addSaveProps( + { className: 'foo wp-block-test-block-variation' }, + variationBlockType, + attributes + ); + + expect( extraProps.className ).toBe( + 'wp-block-test-block-variation foo' + ); + } ); + } ); +} ); diff --git a/packages/blocks/src/api/index.js b/packages/blocks/src/api/index.js index 803467cb2187e2..445d69ee32c972 100644 --- a/packages/blocks/src/api/index.js +++ b/packages/blocks/src/api/index.js @@ -136,6 +136,7 @@ export { getBlockSupport, hasBlockSupport, getBlockVariations, + getActiveBlockVariation, isReusableBlock, isTemplatePart, getChildBlockNames, diff --git a/packages/blocks/src/api/parser/apply-built-in-validation-fixes.js b/packages/blocks/src/api/parser/apply-built-in-validation-fixes.js index 13dbb1e6825c96..3d4fde9e216e89 100644 --- a/packages/blocks/src/api/parser/apply-built-in-validation-fixes.js +++ b/packages/blocks/src/api/parser/apply-built-in-validation-fixes.js @@ -20,6 +20,7 @@ export function applyBuiltInValidationFixes( block, blockType ) { blockType, block.originalContent ); + return { ...block, attributes: updatedBlockAttributes, diff --git a/packages/blocks/src/api/registration.js b/packages/blocks/src/api/registration.js index b0f5ae350759f0..973a342d8c0789 100644 --- a/packages/blocks/src/api/registration.js +++ b/packages/blocks/src/api/registration.js @@ -693,6 +693,26 @@ export const getBlockVariations = ( blockName, scope ) => { return select( blocksStore ).getBlockVariations( blockName, scope ); }; +/** + * Returns the active block variation for a given block based on its attributes. + * Ignored from documentation as the recommended usage is via useSelect from @wordpress/data. + * + * @ignore + * + * @param {string} blockName Name of block (example: “core/columns”). + * @param {Object} attributes Block attributes used to determine active variation. + * @param {WPBlockVariationScope} [scope] Block variation scope name. + * + * @return {(WPBlockVariation|undefined)} Active block variation. + */ +export const getActiveBlockVariation = ( blockName, attributes, scope ) => { + return select( blocksStore ).getActiveBlockVariation( + blockName, + attributes, + scope + ); +}; + /** * Registers a new block variation for the given block type. * diff --git a/packages/blocks/src/api/serializer.js b/packages/blocks/src/api/serializer.js index 2e7246ce9584a9..839f9485dcb51e 100644 --- a/packages/blocks/src/api/serializer.js +++ b/packages/blocks/src/api/serializer.js @@ -41,7 +41,7 @@ export function getBlockDefaultClassName( blockName ) { // Generated HTML classes for blocks follow the `wp-block-{name}` nomenclature. // Blocks provided by WordPress drop the prefixes 'core/' or 'core-' (historically used in 'core-embed/'). const className = - 'wp-block-' + blockName.replace( /\//, '-' ).replace( /^core-/, '' ); + 'wp-block-' + blockName.replace( /\//g, '-' ).replace( /^core-/, '' ); return applyFilters( 'blocks.getBlockDefaultClassName', diff --git a/packages/blocks/src/api/test/serializer.js b/packages/blocks/src/api/test/serializer.js index 7fed23041daaa6..daa90d9a840068 100644 --- a/packages/blocks/src/api/test/serializer.js +++ b/packages/blocks/src/api/test/serializer.js @@ -13,6 +13,7 @@ import serialize, { getCommentDelimitedContent, serializeBlock, getBlockInnerHTML, + getBlockDefaultClassName, } from '../serializer'; import { getBlockTypes, @@ -472,4 +473,30 @@ describe( 'block serializer', () => { expect( getBlockInnerHTML( block ) ).toBe( 'chicken' ); } ); } ); + + describe( 'getBlockDefaultClassName', () => { + it( 'should return the default class name for a block without the core namespace', () => { + expect( getBlockDefaultClassName( 'core/test-block' ) ).toBe( + 'wp-block-test-block' + ); + } ); + + it( 'should return the default class name for a block', () => { + expect( getBlockDefaultClassName( 'core/test-block' ) ).toBe( + 'wp-block-test-block' + ); + expect( getBlockDefaultClassName( 'plugin/test-block' ) ).toBe( + 'wp-block-plugin-test-block' + ); + } ); + + it( 'should return the default class name for a variant block nomenclature', () => { + expect( + getBlockDefaultClassName( 'core/test-block/variant' ) + ).toBe( 'wp-block-test-block-variant' ); + expect( + getBlockDefaultClassName( 'plugin/test-block/variant' ) + ).toBe( 'wp-block-plugin-test-block-variant' ); + } ); + } ); } ); diff --git a/schemas/json/block.json b/schemas/json/block.json index 8e314a45ae1cff..d09c19635e8857 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -256,7 +256,22 @@ }, "className": { "description": "By default, the class .wp-block-your-block-name is added to the root element of your saved markup. This helps having a consistent mechanism for styling blocks that themes and plugins can rely on. If, for whatever reason, a class is not desired on the markup, this functionality can be disabled.", - "type": "boolean", + "oneOf": [ + { "type": "boolean" }, + { + "type": "object", + "properties": { + "block": { + "type": "boolean", + "description": "Add a block specific class name" + }, + "variation": { + "type": "boolean", + "description": "Add a variation specific class name" + } + } + } + ], "default": true }, "color": { From d42c4d14f5b06086161af30d99195d18512302ec Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 4 Jul 2024 16:21:35 +0200 Subject: [PATCH 02/41] Add new helpers --- packages/block-editor/src/hooks/supports.js | 19 ++++ .../block-editor/src/hooks/test/supports.js | 97 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 packages/block-editor/src/hooks/test/supports.js diff --git a/packages/block-editor/src/hooks/supports.js b/packages/block-editor/src/hooks/supports.js index 75f2bdf2dc219e..b1f83d0427b3e9 100644 --- a/packages/block-editor/src/hooks/supports.js +++ b/packages/block-editor/src/hooks/supports.js @@ -339,3 +339,22 @@ export const getLayoutSupport = ( nameOrType ) => */ export const hasStyleSupport = ( nameOrType ) => styleSupportKeys.some( ( key ) => hasBlockSupport( nameOrType, key ) ); + +/** + * Returns true if the block defines support for block class name. + * + * @param {string|Object} nameOrType Block name or type object. + * @return {boolean} Whether the block supports the feature. + */ +export const hasBlockClassNameSupport = ( nameOrType ) => + getBlockSupport( nameOrType, 'className', true ) === true || + hasBlockSupport( nameOrType, 'className.block', false ); + +/** + * Returns true if the block defines support for variation class name. + * + * @param {string|Object} nameOrType Block name or type object. + * @return {boolean} Whether the block supports the feature. + */ +export const hasVariationClassNameSupport = ( nameOrType ) => + hasBlockSupport( nameOrType, 'className.variation', false ); diff --git a/packages/block-editor/src/hooks/test/supports.js b/packages/block-editor/src/hooks/test/supports.js new file mode 100644 index 00000000000000..102dcbc957535b --- /dev/null +++ b/packages/block-editor/src/hooks/test/supports.js @@ -0,0 +1,97 @@ +/** + * Internal dependencies + */ +import { + hasBlockClassNameSupport, + hasVariationClassNameSupport, +} from '../supports'; + +describe( 'hasBlockClassNameSupport', () => { + const blockName = 'block/name'; + + it( 'should default to true', () => { + const block = { + name: blockName, + }; + expect( hasBlockClassNameSupport( block ) ).toEqual( true ); + } ); + + it( 'should return false if the block does not support className', () => { + const block = { + name: blockName, + supports: { + className: false, + }, + }; + expect( hasBlockClassNameSupport( block ) ).toEqual( false ); + } ); + + it( 'should reflect the nested supports property if true', () => { + const block = { + name: blockName, + supports: { + className: { + block: true, + }, + }, + }; + expect( hasBlockClassNameSupport( block ) ).toEqual( true ); + } ); + + it( 'should reflect the nested supports property if false', () => { + const block = { + name: blockName, + supports: { + className: { + block: false, + }, + }, + }; + expect( hasBlockClassNameSupport( block ) ).toEqual( false ); + } ); +} ); + +describe( 'hasVariationClassNameSupport', () => { + const blockName = 'block/name'; + + it( 'should default to false', () => { + const block = { + name: blockName, + }; + expect( hasVariationClassNameSupport( block ) ).toEqual( false ); + } ); + + it( 'should return false if the block does not explicitly support variation class names', () => { + const block = { + name: blockName, + supports: { + className: true, + }, + }; + expect( hasVariationClassNameSupport( block ) ).toEqual( false ); + } ); + + it( 'should reflect the nested supports property if true', () => { + const block = { + name: blockName, + supports: { + className: { + variation: true, + }, + }, + }; + expect( hasVariationClassNameSupport( block ) ).toEqual( true ); + } ); + + it( 'should reflect the nested supports property if false', () => { + const block = { + name: blockName, + supports: { + className: { + variation: false, + }, + }, + }; + expect( hasVariationClassNameSupport( block ) ).toEqual( false ); + } ); +} ); From 1081fe43dd98de73d3e5784898e96b95519b40e6 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 11:19:32 +0200 Subject: [PATCH 03/41] Use new helpers --- packages/block-editor/src/components/block-edit/edit.js | 9 ++++++--- packages/block-editor/src/components/block-list/block.js | 5 ++--- packages/block-editor/src/hooks/generated-class-name.js | 9 +++++++-- .../src/hooks/generated-variation-class-name.js | 8 ++++++-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/edit.js b/packages/block-editor/src/components/block-edit/edit.js index 6addedc96491ad..6c70af7599a725 100644 --- a/packages/block-editor/src/components/block-edit/edit.js +++ b/packages/block-editor/src/components/block-edit/edit.js @@ -9,7 +9,6 @@ import clsx from 'clsx'; import { withFilters } from '@wordpress/components'; import { getBlockDefaultClassName, - hasBlockSupport, getBlockType, getActiveBlockVariation, } from '@wordpress/blocks'; @@ -19,6 +18,10 @@ import { useContext, useMemo } from '@wordpress/element'; * Internal dependencies */ import BlockContext from '../block-context'; +import { + hasBlockClassNameSupport, + hasVariationClassNameSupport, +} from '../../hooks/supports'; /** * Default value used for blocks which do not define their own context needs, @@ -74,10 +77,10 @@ const EditWithGeneratedProps = ( props ) => { const generatedClassNames = []; - if ( hasBlockSupport( blockType, 'className', true ) ) { + if ( hasBlockClassNameSupport( blockType ) ) { generatedClassNames.push( getBlockDefaultClassName( name ) ); } - if ( hasBlockSupport( blockType, 'className.variation', false ) ) { + if ( hasVariationClassNameSupport( blockType ) ) { const activeVariation = getActiveBlockVariation( name, attributes ); if ( activeVariation && activeVariation?.name ) { generatedClassNames.push( diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index c24f1d3c0105fd..e97bed3032c5dc 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -43,6 +43,7 @@ import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; import { PrivateBlockContext } from './private-block-context'; +import { hasVariationClassNameSupport } from '../../hooks/supports'; import { unlock } from '../../lock-unlock'; @@ -604,9 +605,7 @@ function BlockListBlockProvider( props ) { if ( hasLightBlockWrapper && blockName ) { defaultClassNames.push( getBlockDefaultClassName( blockName ) ); - if ( - hasBlockSupport( blockType, 'className.variation', false ) - ) { + if ( hasVariationClassNameSupport( blockType ) ) { if ( match && match?.name ) { defaultClassNames.push( getBlockDefaultClassName( diff --git a/packages/block-editor/src/hooks/generated-class-name.js b/packages/block-editor/src/hooks/generated-class-name.js index 0f4e5f43576fa9..759f4ee036b925 100644 --- a/packages/block-editor/src/hooks/generated-class-name.js +++ b/packages/block-editor/src/hooks/generated-class-name.js @@ -2,7 +2,12 @@ * WordPress dependencies */ import { addFilter } from '@wordpress/hooks'; -import { hasBlockSupport, getBlockDefaultClassName } from '@wordpress/blocks'; +import { getBlockDefaultClassName } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { hasBlockClassNameSupport } from '../hooks/supports'; /** * Override props assigned to save component to inject generated className if @@ -16,7 +21,7 @@ import { hasBlockSupport, getBlockDefaultClassName } from '@wordpress/blocks'; */ export function addGeneratedClassName( extraProps, blockType ) { // Adding the generated className. - if ( hasBlockSupport( blockType, 'className', true ) ) { + if ( hasBlockClassNameSupport( blockType ) ) { if ( typeof extraProps.className === 'string' ) { // We have some extra classes and want to add the default classname // We use uniq to prevent duplicate classnames. diff --git a/packages/block-editor/src/hooks/generated-variation-class-name.js b/packages/block-editor/src/hooks/generated-variation-class-name.js index fe332d747823f5..120969173336c6 100644 --- a/packages/block-editor/src/hooks/generated-variation-class-name.js +++ b/packages/block-editor/src/hooks/generated-variation-class-name.js @@ -3,11 +3,15 @@ */ import { addFilter } from '@wordpress/hooks'; import { - hasBlockSupport, getBlockDefaultClassName, getActiveBlockVariation, } from '@wordpress/blocks'; +/** + * Internal dependencies + */ +import { hasVariationClassNameSupport } from '../hooks/supports'; + /** * Override props assigned to save component to inject generated className if * block supports it. This is only applied if the block's save result is an @@ -25,7 +29,7 @@ export function addGeneratedVariationClassName( attributes ) { // Adding the generated className. - if ( hasBlockSupport( blockType, 'className.variation', false ) ) { + if ( hasVariationClassNameSupport( blockType ) ) { const activeVariation = getActiveBlockVariation( blockType.name, attributes From 6cd7199783b6a0694da35f5b9e2bd9b9b9b9c6b4 Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:22:26 +0200 Subject: [PATCH 04/41] Change attribute from class to className and remove eslint ignore --- .../src/hooks/test/generated-variation-class-name.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/block-editor/src/hooks/test/generated-variation-class-name.js b/packages/block-editor/src/hooks/test/generated-variation-class-name.js index fab89b7f6b66f4..f87e65266dbe2b 100644 --- a/packages/block-editor/src/hooks/test/generated-variation-class-name.js +++ b/packages/block-editor/src/hooks/test/generated-variation-class-name.js @@ -26,8 +26,7 @@ describe( 'generated variation className', () => { }, }, save: ( { attributes } ) => ( - // eslint-disable-next-line react/no-unknown-property -
{ attributes.fruit }
+
{ attributes.fruit }
), category: 'text', title: 'block title', From 608bfd661c52c675abb06b5c8fd5b5a62c490380 Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:23:08 +0200 Subject: [PATCH 05/41] Fix variation attributes in test --- .../src/hooks/test/generated-variation-class-name.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/test/generated-variation-class-name.js b/packages/block-editor/src/hooks/test/generated-variation-class-name.js index f87e65266dbe2b..307f916d651f1b 100644 --- a/packages/block-editor/src/hooks/test/generated-variation-class-name.js +++ b/packages/block-editor/src/hooks/test/generated-variation-class-name.js @@ -34,12 +34,7 @@ describe( 'generated variation className', () => { const variationBlockSettings = { attributes: { - fruit: { - type: 'string', - default: 'Bananas', - source: 'text', - selector: 'div', - }, + fruit: 'Apples', }, isActive: ( { fruit } ) => fruit === 'Apples', }; From d9036b615e67dea59554e4963e04953a62d5d5bf Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:24:08 +0200 Subject: [PATCH 06/41] Fix variation attributes in test --- .../src/hooks/test/generated-variation-class-name.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/block-editor/src/hooks/test/generated-variation-class-name.js b/packages/block-editor/src/hooks/test/generated-variation-class-name.js index 307f916d651f1b..b1787ef2dbb456 100644 --- a/packages/block-editor/src/hooks/test/generated-variation-class-name.js +++ b/packages/block-editor/src/hooks/test/generated-variation-class-name.js @@ -81,13 +81,9 @@ describe( 'generated variation className', () => { it( 'should inject the generated className', () => { const attributes = { fruit: 'Apples' }; const blockType = getBlockType( 'core/test-block' ); - const variationBlockType = { - ...blockType, - ...variationBlockSettings, - }; const extraProps = addSaveProps( { className: 'foo' }, - variationBlockType, + blockType, attributes ); From 4de031b606d1f21a275f8ff5fc5a49a68fffd914 Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:24:36 +0200 Subject: [PATCH 07/41] Fix variation attributes in test --- .../hooks/test/generated-variation-class-name.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/packages/block-editor/src/hooks/test/generated-variation-class-name.js b/packages/block-editor/src/hooks/test/generated-variation-class-name.js index b1787ef2dbb456..f8a914e558c852 100644 --- a/packages/block-editor/src/hooks/test/generated-variation-class-name.js +++ b/packages/block-editor/src/hooks/test/generated-variation-class-name.js @@ -95,22 +95,9 @@ describe( 'generated variation className', () => { it( 'should not inject duplicates into className', () => { const attributes = { fruit: 'Apples' }; const blockType = getBlockType( 'core/test-block' ); - const variationBlockType = { - ...blockType, - attributes: { - ...blockType.attributes, - fruit: { - type: 'string', - default: 'Apples', - source: 'text', - selector: 'div', - }, - }, - isActive: ( { fruit } ) => fruit === 'Apples', - }; const extraProps = addSaveProps( { className: 'foo wp-block-test-block-variation' }, - variationBlockType, + blockType, attributes ); From b1bd36c9fd870b2e94a95d962975bfe6c0018b5c Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:25:29 +0200 Subject: [PATCH 08/41] Remove redundant assertion --- packages/blocks/src/api/test/serializer.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/blocks/src/api/test/serializer.js b/packages/blocks/src/api/test/serializer.js index daa90d9a840068..f7161798059420 100644 --- a/packages/blocks/src/api/test/serializer.js +++ b/packages/blocks/src/api/test/serializer.js @@ -482,9 +482,6 @@ describe( 'block serializer', () => { } ); it( 'should return the default class name for a block', () => { - expect( getBlockDefaultClassName( 'core/test-block' ) ).toBe( - 'wp-block-test-block' - ); expect( getBlockDefaultClassName( 'plugin/test-block' ) ).toBe( 'wp-block-plugin-test-block' ); From 3cb6023dd1d36a2da6be23de73fef59637eb24ae Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 11:26:24 +0200 Subject: [PATCH 09/41] Undo whitespace change --- .../blocks/src/api/parser/apply-built-in-validation-fixes.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/blocks/src/api/parser/apply-built-in-validation-fixes.js b/packages/blocks/src/api/parser/apply-built-in-validation-fixes.js index 3d4fde9e216e89..13dbb1e6825c96 100644 --- a/packages/blocks/src/api/parser/apply-built-in-validation-fixes.js +++ b/packages/blocks/src/api/parser/apply-built-in-validation-fixes.js @@ -20,7 +20,6 @@ export function applyBuiltInValidationFixes( block, blockType ) { blockType, block.originalContent ); - return { ...block, attributes: updatedBlockAttributes, From e384ec71a6421286cb8decac8c69eb23a023eb61 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 12:16:15 +0200 Subject: [PATCH 10/41] Fix test --- .../src/hooks/test/generated-variation-class-name.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/block-editor/src/hooks/test/generated-variation-class-name.js b/packages/block-editor/src/hooks/test/generated-variation-class-name.js index f8a914e558c852..6a6487de4a488f 100644 --- a/packages/block-editor/src/hooks/test/generated-variation-class-name.js +++ b/packages/block-editor/src/hooks/test/generated-variation-class-name.js @@ -28,6 +28,12 @@ describe( 'generated variation className', () => { save: ( { attributes } ) => (
{ attributes.fruit }
), + supports: { + className: { + block: true, + variation: true, + }, + }, category: 'text', title: 'block title', }; From 5dce388f9428b6a8ef3bdb12a7b708a958afba1c Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 14:29:04 +0200 Subject: [PATCH 11/41] Fix other test --- .../block-editor/src/components/block-edit/test/edit.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/block-editor/src/components/block-edit/test/edit.js b/packages/block-editor/src/components/block-edit/test/edit.js index 3a058ae4f44468..06944d278ad496 100644 --- a/packages/block-editor/src/components/block-edit/test/edit.js +++ b/packages/block-editor/src/components/block-edit/test/edit.js @@ -102,6 +102,12 @@ describe( 'Edit', () => { default: 'Apples', }, }, + supports: { + className: { + block: true, + variation: true, + }, + }, } ); registerBlockVariation( 'core/test-block', { From e99838e671c69a509c02d8d72dd2683d77cdd8ba Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:02:35 +0200 Subject: [PATCH 12/41] Fix more variation attributes in test --- packages/block-editor/src/components/block-edit/test/edit.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/test/edit.js b/packages/block-editor/src/components/block-edit/test/edit.js index 06944d278ad496..2e392cddda8e4b 100644 --- a/packages/block-editor/src/components/block-edit/test/edit.js +++ b/packages/block-editor/src/components/block-edit/test/edit.js @@ -114,10 +114,7 @@ describe( 'Edit', () => { name: 'variation', title: 'block variation title', attributes: { - fruit: { - type: 'string', - default: 'Bananas', - }, + fruit: 'Bananas', }, isActive: ( { fruit } ) => fruit === 'Bananas', } ); From cb9430ad99708b38d40fc8f17969ac1361ceeeaf Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 15:14:28 +0200 Subject: [PATCH 13/41] Remove greedy flag from Regex --- packages/blocks/src/api/serializer.js | 2 +- packages/blocks/src/api/test/serializer.js | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/blocks/src/api/serializer.js b/packages/blocks/src/api/serializer.js index 839f9485dcb51e..2e7246ce9584a9 100644 --- a/packages/blocks/src/api/serializer.js +++ b/packages/blocks/src/api/serializer.js @@ -41,7 +41,7 @@ export function getBlockDefaultClassName( blockName ) { // Generated HTML classes for blocks follow the `wp-block-{name}` nomenclature. // Blocks provided by WordPress drop the prefixes 'core/' or 'core-' (historically used in 'core-embed/'). const className = - 'wp-block-' + blockName.replace( /\//g, '-' ).replace( /^core-/, '' ); + 'wp-block-' + blockName.replace( /\//, '-' ).replace( /^core-/, '' ); return applyFilters( 'blocks.getBlockDefaultClassName', diff --git a/packages/blocks/src/api/test/serializer.js b/packages/blocks/src/api/test/serializer.js index f7161798059420..84d97b5a03ae9f 100644 --- a/packages/blocks/src/api/test/serializer.js +++ b/packages/blocks/src/api/test/serializer.js @@ -486,14 +486,5 @@ describe( 'block serializer', () => { 'wp-block-plugin-test-block' ); } ); - - it( 'should return the default class name for a variant block nomenclature', () => { - expect( - getBlockDefaultClassName( 'core/test-block/variant' ) - ).toBe( 'wp-block-test-block-variant' ); - expect( - getBlockDefaultClassName( 'plugin/test-block/variant' ) - ).toBe( 'wp-block-plugin-test-block-variant' ); - } ); } ); } ); From b47cc1fa3ab9b141e84b1171efe2f1bef494a8f2 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 15:20:20 +0200 Subject: [PATCH 14/41] Update comment --- packages/block-editor/src/hooks/generated-class-name.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/generated-class-name.js b/packages/block-editor/src/hooks/generated-class-name.js index 759f4ee036b925..250d31de70c64a 100644 --- a/packages/block-editor/src/hooks/generated-class-name.js +++ b/packages/block-editor/src/hooks/generated-class-name.js @@ -24,7 +24,7 @@ export function addGeneratedClassName( extraProps, blockType ) { if ( hasBlockClassNameSupport( blockType ) ) { if ( typeof extraProps.className === 'string' ) { // We have some extra classes and want to add the default classname - // We use uniq to prevent duplicate classnames. + // We use a Set to prevent duplicate classnames. extraProps.className = [ ...new Set( [ From 2bde39265b41b08984fe6fd6432baadca6ae0375 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 17:16:46 +0200 Subject: [PATCH 15/41] Change test to make it more easily extensible --- .../block-editor/src/hooks/test/generated-class-name.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/hooks/test/generated-class-name.js b/packages/block-editor/src/hooks/test/generated-class-name.js index a37ceb74c87bdc..f6dd799df86a5b 100644 --- a/packages/block-editor/src/hooks/test/generated-class-name.js +++ b/packages/block-editor/src/hooks/test/generated-class-name.js @@ -12,7 +12,7 @@ const noop = () => {}; describe( 'generated className', () => { const blockSettings = { - name: 'chicken/ribs', + name: 'produce/fruit', save: noop, category: 'text', title: 'block title', @@ -48,18 +48,18 @@ describe( 'generated className', () => { attributes ); - expect( extraProps.className ).toBe( 'wp-block-chicken-ribs foo' ); + expect( extraProps.className ).toBe( 'wp-block-produce-fruit foo' ); } ); it( 'should not inject duplicates into className', () => { const attributes = { className: 'bar' }; const extraProps = addSaveProps( - { className: 'foo wp-block-chicken-ribs' }, + { className: 'foo wp-block-produce-fruit' }, blockSettings, attributes ); - expect( extraProps.className ).toBe( 'wp-block-chicken-ribs foo' ); + expect( extraProps.className ).toBe( 'wp-block-produce-fruit foo' ); } ); } ); } ); From 1568b021df9cf70fb7c3bf00cf17374e6978b9f2 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 15:31:48 +0200 Subject: [PATCH 16/41] Absorb variation logic into addGeneratedClassName --- .../src/hooks/generated-class-name.js | 61 +++++++--- .../hooks/generated-variation-class-name.js | 68 ----------- packages/block-editor/src/hooks/index.js | 1 - .../block-editor/src/hooks/index.native.js | 1 - .../src/hooks/test/generated-class-name.js | 96 +++++++++++++++ .../test/generated-variation-class-name.js | 115 ------------------ 6 files changed, 137 insertions(+), 205 deletions(-) delete mode 100644 packages/block-editor/src/hooks/generated-variation-class-name.js delete mode 100644 packages/block-editor/src/hooks/test/generated-variation-class-name.js diff --git a/packages/block-editor/src/hooks/generated-class-name.js b/packages/block-editor/src/hooks/generated-class-name.js index 250d31de70c64a..51bcfc6837a477 100644 --- a/packages/block-editor/src/hooks/generated-class-name.js +++ b/packages/block-editor/src/hooks/generated-class-name.js @@ -2,12 +2,18 @@ * WordPress dependencies */ import { addFilter } from '@wordpress/hooks'; -import { getBlockDefaultClassName } from '@wordpress/blocks'; +import { + getBlockDefaultClassName, + getActiveBlockVariation, +} from '@wordpress/blocks'; /** * Internal dependencies */ -import { hasBlockClassNameSupport } from '../hooks/supports'; +import { + hasBlockClassNameSupport, + hasVariationClassNameSupport, +} from '../hooks/supports'; /** * Override props assigned to save component to inject generated className if @@ -16,30 +22,45 @@ import { hasBlockClassNameSupport } from '../hooks/supports'; * * @param {Object} extraProps Additional props applied to save element. * @param {Object} blockType Block type. + * @param {Object} attributes Block attributes. * * @return {Object} Filtered props applied to save element. */ -export function addGeneratedClassName( extraProps, blockType ) { - // Adding the generated className. +export function addGeneratedClassName( extraProps, blockType, attributes ) { + const generatedClassNames = []; if ( hasBlockClassNameSupport( blockType ) ) { - if ( typeof extraProps.className === 'string' ) { - // We have some extra classes and want to add the default classname - // We use a Set to prevent duplicate classnames. - - extraProps.className = [ - ...new Set( [ - getBlockDefaultClassName( blockType.name ), - ...extraProps.className.split( ' ' ), - ] ), - ] - .join( ' ' ) - .trim(); - } else { - // There is no string in the className variable, - // so we just dump the default name in there. - extraProps.className = getBlockDefaultClassName( blockType.name ); + generatedClassNames.push( getBlockDefaultClassName( blockType.name ) ); + } + if ( hasVariationClassNameSupport( blockType ) ) { + const activeVariation = getActiveBlockVariation( + blockType.name, + attributes + ); + if ( activeVariation ) { + generatedClassNames.push( + getBlockDefaultClassName( blockType.name ) + + '-' + + activeVariation.name + ); } } + if ( typeof extraProps.className === 'string' ) { + // We have some extra classes and want to add the default classname + // We use a Set to prevent duplicate classnames. + extraProps.className = [ + ...new Set( [ + ...generatedClassNames, + ...extraProps.className.split( ' ' ), + ] ), + ] + .join( ' ' ) + .trim(); + } else if ( generatedClassNames.length ) { + // There is no string in the className variable, + // so we just dump the default name(s) in there. + extraProps.className = generatedClassNames.join( ' ' ); + } + return extraProps; } diff --git a/packages/block-editor/src/hooks/generated-variation-class-name.js b/packages/block-editor/src/hooks/generated-variation-class-name.js deleted file mode 100644 index 120969173336c6..00000000000000 --- a/packages/block-editor/src/hooks/generated-variation-class-name.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * WordPress dependencies - */ -import { addFilter } from '@wordpress/hooks'; -import { - getBlockDefaultClassName, - getActiveBlockVariation, -} from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import { hasVariationClassNameSupport } from '../hooks/supports'; - -/** - * Override props assigned to save component to inject generated className if - * block supports it. This is only applied if the block's save result is an - * element and not a markup string. - * - * @param {Object} extraProps Additional props applied to save element. - * @param {Object} blockType Block type. - * @param {Object} attributes Block attributes. - * - * @return {Object} Filtered props applied to save element. - */ -export function addGeneratedVariationClassName( - extraProps, - blockType, - attributes -) { - // Adding the generated className. - if ( hasVariationClassNameSupport( blockType ) ) { - const activeVariation = getActiveBlockVariation( - blockType.name, - attributes - ); - - if ( ! activeVariation ) { - return extraProps; - } - - const variationName = `${ blockType.name }/${ activeVariation.name }`; - - if ( typeof extraProps.className === 'string' ) { - // We have some extra classes and want to add the default classname - extraProps.className = [ - ...new Set( [ - getBlockDefaultClassName( variationName ), - ...extraProps.className.split( ' ' ), - ] ), - ] - .join( ' ' ) - .trim(); - } else { - // There is no string in the className variable, - // so we just dump the default name in there. - extraProps.className = getBlockDefaultClassName( variationName ); - } - } - - return extraProps; -} - -addFilter( - 'blocks.getSaveContent.extraProps', - 'core/generated-variation-class-name/save-props', - addGeneratedVariationClassName -); diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js index ac935847459c89..66ff60b691b66f 100644 --- a/packages/block-editor/src/hooks/index.js +++ b/packages/block-editor/src/hooks/index.js @@ -14,7 +14,6 @@ import anchor from './anchor'; import ariaLabel from './aria-label'; import customClassName from './custom-class-name'; import './generated-class-name'; -import './generated-variation-class-name'; import style from './style'; import './settings'; import color from './color'; diff --git a/packages/block-editor/src/hooks/index.native.js b/packages/block-editor/src/hooks/index.native.js index f2449c5500e7d7..c7f9df868f2bd7 100644 --- a/packages/block-editor/src/hooks/index.native.js +++ b/packages/block-editor/src/hooks/index.native.js @@ -11,7 +11,6 @@ import align from './align'; import anchor from './anchor'; import customClassName from './custom-class-name'; import './generated-class-name'; -import './generated-variation-class-name'; import style from './style'; import color from './color'; import fontSize from './font-size'; diff --git a/packages/block-editor/src/hooks/test/generated-class-name.js b/packages/block-editor/src/hooks/test/generated-class-name.js index f6dd799df86a5b..da7b855fd4f5cd 100644 --- a/packages/block-editor/src/hooks/test/generated-class-name.js +++ b/packages/block-editor/src/hooks/test/generated-class-name.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { applyFilters } from '@wordpress/hooks'; +import { registerBlockType, unregisterBlockType } from '@wordpress/blocks'; /** * Internal dependencies @@ -16,8 +17,43 @@ describe( 'generated className', () => { save: noop, category: 'text', title: 'block title', + attributes: { + fruit: { + type: 'string', + default: 'apple', + }, + }, }; + const variations = [ + { + name: 'apple', + attributes: { + fruit: 'apple', + }, + isActive: [ 'fruit' ], + isDefault: true, + }, + { + name: 'banana', + attributes: { + fruit: 'banana', + }, + isActive: [ 'fruit' ], + }, + ]; + + beforeAll( () => { + registerBlockType( 'produce/fruit', { + ...blockSettings, + variations, + } ); + } ); + + afterAll( () => { + unregisterBlockType( 'produce/fruit' ); + } ); + describe( 'addSaveProps', () => { const addSaveProps = applyFilters.bind( null, @@ -61,5 +97,65 @@ describe( 'generated className', () => { expect( extraProps.className ).toBe( 'wp-block-produce-fruit foo' ); } ); + + it( "should not inject the generated variation className if support isn't enabled", () => { + const attributes = { className: 'foo', fruit: 'banana' }; + const extraProps = addSaveProps( + {}, + { + ...blockSettings, + variations, + supports: { + className: false, + }, + }, + attributes + ); + + expect( extraProps ).not.toHaveProperty( 'className' ); + } ); + + it( 'should inject the generated variation className', () => { + const attributes = { className: 'bar', fruit: 'banana' }; + const extraProps = addSaveProps( + { className: 'foo' }, + { + ...blockSettings, + variations, + supports: { + className: { + variation: true, + }, + }, + }, + attributes + ); + + expect( extraProps.className ).toBe( + 'wp-block-produce-fruit-banana foo' + ); + } ); + + it( 'should inject generated classNames for both block and variation', () => { + const attributes = { className: 'bar', fruit: 'banana' }; + const extraProps = addSaveProps( + { className: 'foo' }, + { + ...blockSettings, + variations, + supports: { + className: { + block: true, + variation: true, + }, + }, + }, + attributes + ); + + expect( extraProps.className ).toBe( + 'wp-block-produce-fruit wp-block-produce-fruit-banana foo' + ); + } ); } ); } ); diff --git a/packages/block-editor/src/hooks/test/generated-variation-class-name.js b/packages/block-editor/src/hooks/test/generated-variation-class-name.js deleted file mode 100644 index 6a6487de4a488f..00000000000000 --- a/packages/block-editor/src/hooks/test/generated-variation-class-name.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * WordPress dependencies - */ -import { applyFilters } from '@wordpress/hooks'; -import { - registerBlockType, - unregisterBlockType, - registerBlockVariation, - unregisterBlockVariation, - getBlockType, -} from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import '../generated-variation-class-name'; - -describe( 'generated variation className', () => { - const defaultBlockSettings = { - attributes: { - fruit: { - type: 'string', - default: 'Bananas', - source: 'text', - selector: 'div', - }, - }, - save: ( { attributes } ) => ( -
{ attributes.fruit }
- ), - supports: { - className: { - block: true, - variation: true, - }, - }, - category: 'text', - title: 'block title', - }; - - const variationBlockSettings = { - attributes: { - fruit: 'Apples', - }, - isActive: ( { fruit } ) => fruit === 'Apples', - }; - - beforeAll( () => { - registerBlockType( 'core/test-block', { - ...defaultBlockSettings, - } ); - - registerBlockVariation( 'core/test-block', { - name: 'variation', - title: 'Variation', - ...variationBlockSettings, - } ); - } ); - - afterAll( () => { - unregisterBlockType( 'core/test-block' ); - unregisterBlockVariation( 'core/test-block', 'variation' ); - } ); - - describe( 'addSaveProps', () => { - const addSaveProps = applyFilters.bind( - null, - 'blocks.getSaveContent.extraProps' - ); - - it( 'should do nothing if the block settings do not define generated className support', () => { - const attributes = { className: 'foo' }; - const extraProps = addSaveProps( - {}, - { - ...defaultBlockSettings, - supports: { - className: false, - }, - }, - attributes - ); - - expect( extraProps ).not.toHaveProperty( 'className' ); - } ); - - it( 'should inject the generated className', () => { - const attributes = { fruit: 'Apples' }; - const blockType = getBlockType( 'core/test-block' ); - const extraProps = addSaveProps( - { className: 'foo' }, - blockType, - attributes - ); - - expect( extraProps.className ).toContain( - 'wp-block-test-block-variation' - ); - } ); - - it( 'should not inject duplicates into className', () => { - const attributes = { fruit: 'Apples' }; - const blockType = getBlockType( 'core/test-block' ); - const extraProps = addSaveProps( - { className: 'foo wp-block-test-block-variation' }, - blockType, - attributes - ); - - expect( extraProps.className ).toBe( - 'wp-block-test-block-variation foo' - ); - } ); - } ); -} ); From 818af29c6f866a1205265cfd72e3e1252fc19931 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 17:44:39 +0200 Subject: [PATCH 17/41] Reuse addGeneratedClassName --- .../src/components/block-edit/edit.js | 33 +++++-------------- .../src/components/block-list/block.js | 28 ++++------------ 2 files changed, 14 insertions(+), 47 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/edit.js b/packages/block-editor/src/components/block-edit/edit.js index 6c70af7599a725..1008e6c0900e08 100644 --- a/packages/block-editor/src/components/block-edit/edit.js +++ b/packages/block-editor/src/components/block-edit/edit.js @@ -7,21 +7,14 @@ import clsx from 'clsx'; * WordPress dependencies */ import { withFilters } from '@wordpress/components'; -import { - getBlockDefaultClassName, - getBlockType, - getActiveBlockVariation, -} from '@wordpress/blocks'; +import { getBlockType } from '@wordpress/blocks'; import { useContext, useMemo } from '@wordpress/element'; /** * Internal dependencies */ import BlockContext from '../block-context'; -import { - hasBlockClassNameSupport, - hasVariationClassNameSupport, -} from '../../hooks/supports'; +import { addGeneratedClassName } from '../../hooks/generated-class-name'; /** * Default value used for blocks which do not define their own context needs, @@ -75,24 +68,14 @@ const EditWithGeneratedProps = ( props ) => { return ; } - const generatedClassNames = []; - - if ( hasBlockClassNameSupport( blockType ) ) { - generatedClassNames.push( getBlockDefaultClassName( name ) ); - } - if ( hasVariationClassNameSupport( blockType ) ) { - const activeVariation = getActiveBlockVariation( name, attributes ); - if ( activeVariation && activeVariation?.name ) { - generatedClassNames.push( - getBlockDefaultClassName( - `${ name }/${ activeVariation.name }` - ) - ); - } - } + const generatedClassName = addGeneratedClassName( + {}, + blockType, + attributes + )?.className; const className = clsx( - generatedClassNames, + generatedClassName, attributes.className, props.className ); diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index e97bed3032c5dc..d98669cbe63974 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -22,7 +22,6 @@ import { getDefaultBlockName, isUnmodifiedBlock, isReusableBlock, - getBlockDefaultClassName, hasBlockSupport, store as blocksStore, } from '@wordpress/blocks'; @@ -43,7 +42,7 @@ import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; import { PrivateBlockContext } from './private-block-context'; -import { hasVariationClassNameSupport } from '../../hooks/supports'; +import { addGeneratedClassName } from '../../hooks/generated-class-name'; import { unlock } from '../../lock-unlock'; @@ -593,28 +592,12 @@ function BlockListBlockProvider( props ) { hasBlockSupport: _hasBlockSupport, getActiveBlockVariation, } = select( blocksStore ); - const attributes = getBlockAttributes( clientId ); const { name: blockName, isValid } = blockWithoutAttributes; - const match = getActiveBlockVariation( blockName, attributes ); const blockType = getBlockType( blockName ); const { supportsLayout, __unstableIsPreviewMode: isPreviewMode } = getSettings(); const hasLightBlockWrapper = blockType?.apiVersion > 1; - const defaultClassNames = []; - if ( hasLightBlockWrapper && blockName ) { - defaultClassNames.push( getBlockDefaultClassName( blockName ) ); - - if ( hasVariationClassNameSupport( blockType ) ) { - if ( match && match?.name ) { - defaultClassNames.push( - getBlockDefaultClassName( - `${ blockName }/${ match.name }` - ) - ); - } - } - } const previewContext = { isPreviewMode, blockWithoutAttributes, @@ -627,10 +610,10 @@ function BlockListBlockProvider( props ) { className: hasLightBlockWrapper ? attributes.className : undefined, - defaultClassName: - defaultClassNames.length > 0 - ? clsx( defaultClassNames ) - : undefined, + defaultClassName: hasLightBlockWrapper + ? addGeneratedClassName( {}, blockType, attributes ) + ?.className + : undefined, blockTitle: blockType?.title, }; @@ -643,6 +626,7 @@ function BlockListBlockProvider( props ) { const _isSelected = isBlockSelected( clientId ); const canRemove = canRemoveBlock( clientId ); const canMove = canMoveBlock( clientId ); + const match = getActiveBlockVariation( blockName, attributes ); const isMultiSelected = isBlockMultiSelected( clientId ); const checkDeep = true; const isAncestorOfSelectedBlock = hasSelectedInnerBlock( From b34a14e63964e0077a2c76bb5f836abd51111b24 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 18:21:50 +0200 Subject: [PATCH 18/41] Use shorthand --- packages/block-editor/src/components/block-edit/test/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-edit/test/edit.js b/packages/block-editor/src/components/block-edit/test/edit.js index 2e392cddda8e4b..79f564e95dfd9c 100644 --- a/packages/block-editor/src/components/block-edit/test/edit.js +++ b/packages/block-editor/src/components/block-edit/test/edit.js @@ -116,7 +116,7 @@ describe( 'Edit', () => { attributes: { fruit: 'Bananas', }, - isActive: ( { fruit } ) => fruit === 'Bananas', + isActive: [ 'fruit' ], } ); render( From 8515de7a5f633f2e86fbdcf9dd164dd69236d4f5 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 17:58:58 +0200 Subject: [PATCH 19/41] Simplify test --- .../src/components/block-edit/test/edit.js | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/test/edit.js b/packages/block-editor/src/components/block-edit/test/edit.js index 79f564e95dfd9c..45b819ca57965b 100644 --- a/packages/block-editor/src/components/block-edit/test/edit.js +++ b/packages/block-editor/src/components/block-edit/test/edit.js @@ -9,8 +9,6 @@ import { render, screen } from '@testing-library/react'; import { registerBlockType, unregisterBlockType, - registerBlockVariation, - unregisterBlockVariation, getBlockTypes, } from '@wordpress/blocks'; @@ -108,15 +106,16 @@ describe( 'Edit', () => { variation: true, }, }, - } ); - - registerBlockVariation( 'core/test-block', { - name: 'variation', - title: 'block variation title', - attributes: { - fruit: 'Bananas', - }, - isActive: [ 'fruit' ], + variations: [ + { + name: 'variation', + title: 'block variation title', + attributes: { + fruit: 'Bananas', + }, + isActive: [ 'fruit' ], + }, + ], } ); render( @@ -126,8 +125,6 @@ describe( 'Edit', () => { const editElement = screen.getByTestId( 'foo-bar' ); expect( editElement ).toHaveClass( 'wp-block-test-block' ); expect( editElement ).toHaveClass( 'wp-block-test-block-variation' ); - - unregisterBlockVariation( 'core/test-block', 'variation' ); } ); it( 'should assign context', () => { From 2df5db716e3da183922e7f19168e9a147f1d240d Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 18:04:03 +0200 Subject: [PATCH 20/41] More verbose schema descriptions --- schemas/json/block.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/schemas/json/block.json b/schemas/json/block.json index d09c19635e8857..21f4030d336b13 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -263,11 +263,11 @@ "properties": { "block": { "type": "boolean", - "description": "Add a block specific class name" + "description": "Add the .wp-block-your-block-name class to the block's wrapper element" }, "variation": { "type": "boolean", - "description": "Add a variation specific class name" + "description": "Add the .wp-block-your-block-name-your-block-variation class to the block's wrapper element" } } } From d625240c698d1cf40a21294af33dd353126ea3ce Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 18:39:24 +0200 Subject: [PATCH 21/41] Revert "Reuse addGeneratedClassName" This reverts commit 7011264a1d796aed0b873a95949489b261fe9676. --- .../src/components/block-edit/edit.js | 33 ++++++++++++++----- .../src/components/block-list/block.js | 28 ++++++++++++---- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/edit.js b/packages/block-editor/src/components/block-edit/edit.js index 1008e6c0900e08..6c70af7599a725 100644 --- a/packages/block-editor/src/components/block-edit/edit.js +++ b/packages/block-editor/src/components/block-edit/edit.js @@ -7,14 +7,21 @@ import clsx from 'clsx'; * WordPress dependencies */ import { withFilters } from '@wordpress/components'; -import { getBlockType } from '@wordpress/blocks'; +import { + getBlockDefaultClassName, + getBlockType, + getActiveBlockVariation, +} from '@wordpress/blocks'; import { useContext, useMemo } from '@wordpress/element'; /** * Internal dependencies */ import BlockContext from '../block-context'; -import { addGeneratedClassName } from '../../hooks/generated-class-name'; +import { + hasBlockClassNameSupport, + hasVariationClassNameSupport, +} from '../../hooks/supports'; /** * Default value used for blocks which do not define their own context needs, @@ -68,14 +75,24 @@ const EditWithGeneratedProps = ( props ) => { return ; } - const generatedClassName = addGeneratedClassName( - {}, - blockType, - attributes - )?.className; + const generatedClassNames = []; + + if ( hasBlockClassNameSupport( blockType ) ) { + generatedClassNames.push( getBlockDefaultClassName( name ) ); + } + if ( hasVariationClassNameSupport( blockType ) ) { + const activeVariation = getActiveBlockVariation( name, attributes ); + if ( activeVariation && activeVariation?.name ) { + generatedClassNames.push( + getBlockDefaultClassName( + `${ name }/${ activeVariation.name }` + ) + ); + } + } const className = clsx( - generatedClassName, + generatedClassNames, attributes.className, props.className ); diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index d98669cbe63974..e97bed3032c5dc 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -22,6 +22,7 @@ import { getDefaultBlockName, isUnmodifiedBlock, isReusableBlock, + getBlockDefaultClassName, hasBlockSupport, store as blocksStore, } from '@wordpress/blocks'; @@ -42,7 +43,7 @@ import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; import { PrivateBlockContext } from './private-block-context'; -import { addGeneratedClassName } from '../../hooks/generated-class-name'; +import { hasVariationClassNameSupport } from '../../hooks/supports'; import { unlock } from '../../lock-unlock'; @@ -592,12 +593,28 @@ function BlockListBlockProvider( props ) { hasBlockSupport: _hasBlockSupport, getActiveBlockVariation, } = select( blocksStore ); + const attributes = getBlockAttributes( clientId ); const { name: blockName, isValid } = blockWithoutAttributes; + const match = getActiveBlockVariation( blockName, attributes ); const blockType = getBlockType( blockName ); const { supportsLayout, __unstableIsPreviewMode: isPreviewMode } = getSettings(); const hasLightBlockWrapper = blockType?.apiVersion > 1; + const defaultClassNames = []; + if ( hasLightBlockWrapper && blockName ) { + defaultClassNames.push( getBlockDefaultClassName( blockName ) ); + + if ( hasVariationClassNameSupport( blockType ) ) { + if ( match && match?.name ) { + defaultClassNames.push( + getBlockDefaultClassName( + `${ blockName }/${ match.name }` + ) + ); + } + } + } const previewContext = { isPreviewMode, blockWithoutAttributes, @@ -610,10 +627,10 @@ function BlockListBlockProvider( props ) { className: hasLightBlockWrapper ? attributes.className : undefined, - defaultClassName: hasLightBlockWrapper - ? addGeneratedClassName( {}, blockType, attributes ) - ?.className - : undefined, + defaultClassName: + defaultClassNames.length > 0 + ? clsx( defaultClassNames ) + : undefined, blockTitle: blockType?.title, }; @@ -626,7 +643,6 @@ function BlockListBlockProvider( props ) { const _isSelected = isBlockSelected( clientId ); const canRemove = canRemoveBlock( clientId ); const canMove = canMoveBlock( clientId ); - const match = getActiveBlockVariation( blockName, attributes ); const isMultiSelected = isBlockMultiSelected( clientId ); const checkDeep = true; const isAncestorOfSelectedBlock = hasSelectedInnerBlock( From faac58c7f42f62ea8d0f7d74042b1bf850071501 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 8 Jul 2024 20:47:17 +0200 Subject: [PATCH 22/41] Replace slash with hyphen --- packages/block-editor/src/components/block-edit/edit.js | 4 +--- packages/block-editor/src/components/block-list/block.js | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/edit.js b/packages/block-editor/src/components/block-edit/edit.js index 6c70af7599a725..69a9f3e85e34b8 100644 --- a/packages/block-editor/src/components/block-edit/edit.js +++ b/packages/block-editor/src/components/block-edit/edit.js @@ -84,9 +84,7 @@ const EditWithGeneratedProps = ( props ) => { const activeVariation = getActiveBlockVariation( name, attributes ); if ( activeVariation && activeVariation?.name ) { generatedClassNames.push( - getBlockDefaultClassName( - `${ name }/${ activeVariation.name }` - ) + getBlockDefaultClassName( name ) + '-' + activeVariation.name ); } } diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index e97bed3032c5dc..7cef11486125f6 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -608,9 +608,9 @@ function BlockListBlockProvider( props ) { if ( hasVariationClassNameSupport( blockType ) ) { if ( match && match?.name ) { defaultClassNames.push( - getBlockDefaultClassName( - `${ blockName }/${ match.name }` - ) + getBlockDefaultClassName( blockName ) + + '-' + + match.name ); } } From c8b9a6a305ada852e8c682de7a44417c693abc2d Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 10 Jul 2024 11:57:36 +0200 Subject: [PATCH 23/41] Add getBlockVariationClassName selector --- packages/blocks/src/api/index.js | 1 + packages/blocks/src/api/serializer.js | 21 ++++++++ packages/blocks/src/api/test/serializer.js | 57 ++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/packages/blocks/src/api/index.js b/packages/blocks/src/api/index.js index 445d69ee32c972..beb31d038e466c 100644 --- a/packages/blocks/src/api/index.js +++ b/packages/blocks/src/api/index.js @@ -70,6 +70,7 @@ export { default as serialize, getBlockInnerHTML as getBlockContent, getBlockDefaultClassName, + getBlockVariationClassName, getBlockMenuDefaultClassName, getSaveElement, getSaveContent, diff --git a/packages/blocks/src/api/serializer.js b/packages/blocks/src/api/serializer.js index 2e7246ce9584a9..2bf203baad143d 100644 --- a/packages/blocks/src/api/serializer.js +++ b/packages/blocks/src/api/serializer.js @@ -15,6 +15,7 @@ import { removep } from '@wordpress/autop'; * Internal dependencies */ import { + getActiveBlockVariation, getBlockType, getFreeformContentHandlerName, getUnregisteredTypeHandlerName, @@ -50,6 +51,26 @@ export function getBlockDefaultClassName( blockName ) { ); } +/** + * Returns a block variation specific classname. + * + * If the given block matches a variation, the classname will be the block's default classname + * with the variation name appended (separated by a hyphen). + * + * @param {string} blockName The block name. + * @param {Object} attributes Block attributes. + * + * @return {string|null} The block variation classname, or null if the block doesn't match any variation. + */ +export function getBlockVariationClassName( blockName, attributes ) { + const activeVariation = getActiveBlockVariation( blockName, attributes ); + if ( ! activeVariation ) { + return null; + } + + return getBlockDefaultClassName( blockName ) + '-' + activeVariation.name; +} + /** * Returns the block's default menu item classname from its name. * diff --git a/packages/blocks/src/api/test/serializer.js b/packages/blocks/src/api/test/serializer.js index 84d97b5a03ae9f..dedd255141c3fe 100644 --- a/packages/blocks/src/api/test/serializer.js +++ b/packages/blocks/src/api/test/serializer.js @@ -14,6 +14,7 @@ import serialize, { serializeBlock, getBlockInnerHTML, getBlockDefaultClassName, + getBlockVariationClassName, } from '../serializer'; import { getBlockTypes, @@ -487,4 +488,60 @@ describe( 'block serializer', () => { ); } ); } ); + + describe( 'getBlockVariationClassName', () => { + const blockSettings = { + title: 'Fruit', + attributes: { + fruit: { + type: 'string', + default: 'apple', + }, + } + }; + const variations = [ + { + name: 'apple', + attributes: { + fruit: 'apple', + }, + isActive: [ 'fruit' ], + isDefault: true, + }, + { + name: 'banana', + attributes: { + fruit: 'banana', + }, + isActive: [ 'fruit' ], + }, + ]; + + it( 'should return null if the block does not have any variations', () => { + registerBlockType( 'core/fruit', blockSettings ); + expect( + getBlockVariationClassName( 'core/fruit', { + fruit: 'orange', + } ) + ).toBeNull(); + } ); + + it( 'should return null if the given attributes do not match any variation', () => { + registerBlockType( 'core/fruit', { ...blockSettings, variations } ); + expect( + getBlockVariationClassName( 'core/fruit', { + fruit: 'orange', + } ) + ).toBeNull(); + } ); + + it( 'should return the correct variation class name for a block', () => { + registerBlockType( 'core/fruit', { ...blockSettings, variations } ); + expect( + getBlockVariationClassName( 'core/fruit', { + fruit: 'banana', + } ) + ).toBe( 'wp-block-fruit-banana' ); + } ); + } ); } ); From 2b215d7fbb1edb7c0fa485a9c471ffe3bbf91e77 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 10 Jul 2024 11:58:34 +0200 Subject: [PATCH 24/41] Use new selector --- .../src/components/block-edit/edit.js | 13 +++++++------ .../src/components/block-list/block.js | 16 +++++++++------- .../src/hooks/generated-class-name.js | 12 ++++-------- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/edit.js b/packages/block-editor/src/components/block-edit/edit.js index 69a9f3e85e34b8..c04ee34b8aee37 100644 --- a/packages/block-editor/src/components/block-edit/edit.js +++ b/packages/block-editor/src/components/block-edit/edit.js @@ -9,8 +9,8 @@ import clsx from 'clsx'; import { withFilters } from '@wordpress/components'; import { getBlockDefaultClassName, + getBlockVariationClassName, getBlockType, - getActiveBlockVariation, } from '@wordpress/blocks'; import { useContext, useMemo } from '@wordpress/element'; @@ -81,11 +81,12 @@ const EditWithGeneratedProps = ( props ) => { generatedClassNames.push( getBlockDefaultClassName( name ) ); } if ( hasVariationClassNameSupport( blockType ) ) { - const activeVariation = getActiveBlockVariation( name, attributes ); - if ( activeVariation && activeVariation?.name ) { - generatedClassNames.push( - getBlockDefaultClassName( name ) + '-' + activeVariation.name - ); + const variationClassName = getBlockVariationClassName( + blockType.name, + attributes + ); + if ( variationClassName ) { + generatedClassNames.push( variationClassName ); } } diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 7cef11486125f6..5053342e585ec8 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -23,6 +23,7 @@ import { isUnmodifiedBlock, isReusableBlock, getBlockDefaultClassName, + getBlockVariationClassName, hasBlockSupport, store as blocksStore, } from '@wordpress/blocks'; @@ -596,7 +597,6 @@ function BlockListBlockProvider( props ) { const attributes = getBlockAttributes( clientId ); const { name: blockName, isValid } = blockWithoutAttributes; - const match = getActiveBlockVariation( blockName, attributes ); const blockType = getBlockType( blockName ); const { supportsLayout, __unstableIsPreviewMode: isPreviewMode } = getSettings(); @@ -606,12 +606,12 @@ function BlockListBlockProvider( props ) { defaultClassNames.push( getBlockDefaultClassName( blockName ) ); if ( hasVariationClassNameSupport( blockType ) ) { - if ( match && match?.name ) { - defaultClassNames.push( - getBlockDefaultClassName( blockName ) + - '-' + - match.name - ); + const variationClassName = getBlockVariationClassName( + blockType.name, + attributes + ); + if ( variationClassName ) { + defaultClassNames.push( variationClassName ); } } } @@ -652,6 +652,8 @@ function BlockListBlockProvider( props ) { const movingClientId = hasBlockMovingClientId(); const blockEditingMode = getBlockEditingMode( clientId ); + const match = getActiveBlockVariation( blockName, attributes ); + const multiple = hasBlockSupport( blockName, 'multiple', true ); // For block types with `multiple` support, there is no "original diff --git a/packages/block-editor/src/hooks/generated-class-name.js b/packages/block-editor/src/hooks/generated-class-name.js index 51bcfc6837a477..3f88775ea08e69 100644 --- a/packages/block-editor/src/hooks/generated-class-name.js +++ b/packages/block-editor/src/hooks/generated-class-name.js @@ -4,7 +4,7 @@ import { addFilter } from '@wordpress/hooks'; import { getBlockDefaultClassName, - getActiveBlockVariation, + getBlockVariationClassName, } from '@wordpress/blocks'; /** @@ -32,16 +32,12 @@ export function addGeneratedClassName( extraProps, blockType, attributes ) { generatedClassNames.push( getBlockDefaultClassName( blockType.name ) ); } if ( hasVariationClassNameSupport( blockType ) ) { - const activeVariation = getActiveBlockVariation( + const variationClassName = getBlockVariationClassName( blockType.name, attributes ); - if ( activeVariation ) { - generatedClassNames.push( - getBlockDefaultClassName( blockType.name ) + - '-' + - activeVariation.name - ); + if ( variationClassName ) { + generatedClassNames.push( variationClassName ); } } if ( typeof extraProps.className === 'string' ) { From 0af2defde91962bbe44574f95e76c988202324fa Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 10 Jul 2024 12:17:13 +0200 Subject: [PATCH 25/41] Update docs --- packages/blocks/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/blocks/README.md b/packages/blocks/README.md index d724f986b0ca81..b28263c91acc72 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -198,6 +198,21 @@ _Returns_ - `Array`: Block settings. +### getBlockVariationClassName + +Returns a block variation specific classname. + +If the given block matches a variation, the classname will be the block's default classname with the variation name appended (separated by a hyphen). + +_Parameters_ + +- _blockName_ `string`: The block name. +- _attributes_ `Object`: Block attributes. + +_Returns_ + +- `string|null`: The block variation classname, or null if the block doesn't match any variation. + ### getChildBlockNames Returns an array with the child blocks of a given block. From 962a5ae082e84647702c8319c542c1a90e1434d6 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 10 Jul 2024 13:59:03 +0200 Subject: [PATCH 26/41] Missing comma --- packages/blocks/src/api/test/serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/blocks/src/api/test/serializer.js b/packages/blocks/src/api/test/serializer.js index dedd255141c3fe..3b6f5be5f544ed 100644 --- a/packages/blocks/src/api/test/serializer.js +++ b/packages/blocks/src/api/test/serializer.js @@ -497,7 +497,7 @@ describe( 'block serializer', () => { type: 'string', default: 'apple', }, - } + }, }; const variations = [ { From 173bef220999ddffd8c834b7973f17fc1cdcdac2 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 10 Jul 2024 15:26:23 +0200 Subject: [PATCH 27/41] Add docs --- .../block-api/block-supports.md | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/reference-guides/block-api/block-supports.md b/docs/reference-guides/block-api/block-supports.md index a15191c19ffb73..5caace618082b7 100644 --- a/docs/reference-guides/block-api/block-supports.md +++ b/docs/reference-guides/block-api/block-supports.md @@ -176,8 +176,11 @@ attributes: { ## className -- Type: `boolean` +- Type: `boolean` or `Object` - Default value: `true` +- Subproperties: + - `block`: type `boolean`, default value `false` + - `variation`: type `boolean`, default value `true` By default, the class `.wp-block-your-block-name` is added to the root element of your saved markup. This helps by providing a consistent mechanism for styling blocks that themes and plugins can rely on. If, for whatever reason, a class is not desired on the markup, this functionality can be disabled. @@ -188,6 +191,32 @@ supports: { } ``` +### className.block + +The above is equivalent to the more verbose + +```js +supports: { + // Remove the support for the generated className. + className: { + block: false + } +} +``` + +### className.variation + +In the same vein, it is possible to have a variation-specific class added to a block (if the latter supports variations). E.g. if a block named `your/block-name` has a variation called `your-variation`, the following will add the class `.wp-block-your-block-name-your-variation`: + +```js +supports: { + // Add block variation-specific className. + className: { + variation: true + } +} +``` + ## color - Type: `Object` From 5cccab753c8dc183ee05653620c694d27c192ca9 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 10 Jul 2024 15:43:38 +0200 Subject: [PATCH 28/41] Change default to true --- .../block-api/block-supports.md | 2 +- packages/block-editor/src/hooks/supports.js | 17 +++++++++-- .../src/hooks/test/generated-class-name.js | 28 +++++++++++++++---- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/docs/reference-guides/block-api/block-supports.md b/docs/reference-guides/block-api/block-supports.md index 5caace618082b7..0fb3ba5769ebc3 100644 --- a/docs/reference-guides/block-api/block-supports.md +++ b/docs/reference-guides/block-api/block-supports.md @@ -179,7 +179,7 @@ attributes: { - Type: `boolean` or `Object` - Default value: `true` - Subproperties: - - `block`: type `boolean`, default value `false` + - `block`: type `boolean`, default value `true` - `variation`: type `boolean`, default value `true` By default, the class `.wp-block-your-block-name` is added to the root element of your saved markup. This helps by providing a consistent mechanism for styling blocks that themes and plugins can rely on. If, for whatever reason, a class is not desired on the markup, this functionality can be disabled. diff --git a/packages/block-editor/src/hooks/supports.js b/packages/block-editor/src/hooks/supports.js index b1f83d0427b3e9..da02a8287d2683 100644 --- a/packages/block-editor/src/hooks/supports.js +++ b/packages/block-editor/src/hooks/supports.js @@ -346,9 +346,20 @@ export const hasStyleSupport = ( nameOrType ) => * @param {string|Object} nameOrType Block name or type object. * @return {boolean} Whether the block supports the feature. */ -export const hasBlockClassNameSupport = ( nameOrType ) => - getBlockSupport( nameOrType, 'className', true ) === true || - hasBlockSupport( nameOrType, 'className.block', false ); +export const hasBlockClassNameSupport = ( nameOrType ) => { + const classNameSupport = getBlockSupport( nameOrType, 'className', true ); + + if ( classNameSupport === true || classNameSupport === false ) { + return classNameSupport; + } + + // classNameSupport can be an object. If it doesn't have a block key, + // we default to true. + return ( + ! Object.hasOwn( classNameSupport, 'block' ) || + classNameSupport.block === true + ); +}; /** * Returns true if the block defines support for variation class name. diff --git a/packages/block-editor/src/hooks/test/generated-class-name.js b/packages/block-editor/src/hooks/test/generated-class-name.js index da7b855fd4f5cd..1622bce5892b91 100644 --- a/packages/block-editor/src/hooks/test/generated-class-name.js +++ b/packages/block-editor/src/hooks/test/generated-class-name.js @@ -76,6 +76,24 @@ describe( 'generated className', () => { expect( extraProps ).not.toHaveProperty( 'className' ); } ); + it( 'should do nothing if the block settings opt out of generated className support via the block property', () => { + const attributes = { className: 'foo' }; + const extraProps = addSaveProps( + {}, + { + ...blockSettings, + supports: { + className: { + block: false, + }, + }, + }, + attributes + ); + + expect( extraProps ).not.toHaveProperty( 'className' ); + } ); + it( 'should inject the generated className', () => { const attributes = { className: 'bar' }; const extraProps = addSaveProps( @@ -115,7 +133,7 @@ describe( 'generated className', () => { expect( extraProps ).not.toHaveProperty( 'className' ); } ); - it( 'should inject the generated variation className', () => { + it( 'should inject generated classNames for both block and variation', () => { const attributes = { className: 'bar', fruit: 'banana' }; const extraProps = addSaveProps( { className: 'foo' }, @@ -132,11 +150,11 @@ describe( 'generated className', () => { ); expect( extraProps.className ).toBe( - 'wp-block-produce-fruit-banana foo' + 'wp-block-produce-fruit wp-block-produce-fruit-banana foo' ); } ); - it( 'should inject generated classNames for both block and variation', () => { + it( 'should only inject the generated variation className if the block property is explicitly set to false', () => { const attributes = { className: 'bar', fruit: 'banana' }; const extraProps = addSaveProps( { className: 'foo' }, @@ -145,7 +163,7 @@ describe( 'generated className', () => { variations, supports: { className: { - block: true, + block: false, variation: true, }, }, @@ -154,7 +172,7 @@ describe( 'generated className', () => { ); expect( extraProps.className ).toBe( - 'wp-block-produce-fruit wp-block-produce-fruit-banana foo' + 'wp-block-produce-fruit-banana foo' ); } ); } ); From cff8fcc21e44fffbaad80b0c476ea06d54549eca Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 10 Jul 2024 16:15:42 +0200 Subject: [PATCH 29/41] Fix variation default value in docs --- docs/reference-guides/block-api/block-supports.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference-guides/block-api/block-supports.md b/docs/reference-guides/block-api/block-supports.md index 0fb3ba5769ebc3..3b0a35edc5cfbe 100644 --- a/docs/reference-guides/block-api/block-supports.md +++ b/docs/reference-guides/block-api/block-supports.md @@ -180,7 +180,7 @@ attributes: { - Default value: `true` - Subproperties: - `block`: type `boolean`, default value `true` - - `variation`: type `boolean`, default value `true` + - `variation`: type `boolean`, default value `false` By default, the class `.wp-block-your-block-name` is added to the root element of your saved markup. This helps by providing a consistent mechanism for styling blocks that themes and plugins can rely on. If, for whatever reason, a class is not desired on the markup, this functionality can be disabled. From 50a0044b568412468fa740ce8e7457e864e552ac Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Tue, 23 Jul 2024 17:15:29 +0200 Subject: [PATCH 30/41] typeof classNameSupport === 'boolean' instead of comparing it to `true` or `false` Co-authored-by: Nik Tsekouras --- packages/block-editor/src/hooks/supports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/supports.js b/packages/block-editor/src/hooks/supports.js index da02a8287d2683..43c7efa1ffae79 100644 --- a/packages/block-editor/src/hooks/supports.js +++ b/packages/block-editor/src/hooks/supports.js @@ -349,7 +349,7 @@ export const hasStyleSupport = ( nameOrType ) => export const hasBlockClassNameSupport = ( nameOrType ) => { const classNameSupport = getBlockSupport( nameOrType, 'className', true ); - if ( classNameSupport === true || classNameSupport === false ) { + if ( typeof classNameSupport === 'boolean' ) { return classNameSupport; } From 0d3416309bdbbdbf3555a0134c3f9768c6c5e0d1 Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Tue, 23 Jul 2024 17:16:00 +0200 Subject: [PATCH 31/41] Backticks Co-authored-by: Nik Tsekouras --- packages/block-editor/src/hooks/supports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/supports.js b/packages/block-editor/src/hooks/supports.js index 43c7efa1ffae79..923629f9ffda5d 100644 --- a/packages/block-editor/src/hooks/supports.js +++ b/packages/block-editor/src/hooks/supports.js @@ -353,7 +353,7 @@ export const hasBlockClassNameSupport = ( nameOrType ) => { return classNameSupport; } - // classNameSupport can be an object. If it doesn't have a block key, + // classNameSupport can be an object. If it doesn't have a `block` key, // we default to true. return ( ! Object.hasOwn( classNameSupport, 'block' ) || From aaaa855f9874fb6a0190afc8bc52edce38eb9a23 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 23 Jul 2024 17:42:16 +0200 Subject: [PATCH 32/41] Bail early --- packages/block-editor/src/hooks/generated-class-name.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/generated-class-name.js b/packages/block-editor/src/hooks/generated-class-name.js index 3f88775ea08e69..71d8bd9f21359a 100644 --- a/packages/block-editor/src/hooks/generated-class-name.js +++ b/packages/block-editor/src/hooks/generated-class-name.js @@ -40,6 +40,11 @@ export function addGeneratedClassName( extraProps, blockType, attributes ) { generatedClassNames.push( variationClassName ); } } + + if ( generatedClassNames.length === 0 ) { + return extraProps; + } + if ( typeof extraProps.className === 'string' ) { // We have some extra classes and want to add the default classname // We use a Set to prevent duplicate classnames. @@ -51,7 +56,7 @@ export function addGeneratedClassName( extraProps, blockType, attributes ) { ] .join( ' ' ) .trim(); - } else if ( generatedClassNames.length ) { + } else { // There is no string in the className variable, // so we just dump the default name(s) in there. extraProps.className = generatedClassNames.join( ' ' ); From e819f54cc392fb7a1fa300a63b1a2434e26babe6 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 23 Jul 2024 17:45:38 +0200 Subject: [PATCH 33/41] Remove unnecessary export --- packages/blocks/src/api/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/blocks/src/api/index.js b/packages/blocks/src/api/index.js index beb31d038e466c..0b440a5a2ca30e 100644 --- a/packages/blocks/src/api/index.js +++ b/packages/blocks/src/api/index.js @@ -137,7 +137,6 @@ export { getBlockSupport, hasBlockSupport, getBlockVariations, - getActiveBlockVariation, isReusableBlock, isTemplatePart, getChildBlockNames, From 7cf6f8e85a8017ac1cf6c898f526904e05a698ea Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 23 Jul 2024 18:19:00 +0200 Subject: [PATCH 34/41] Add note that the getBlockDefaultClassName filter also affects variation class names --- docs/reference-guides/filters/block-filters.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/reference-guides/filters/block-filters.md b/docs/reference-guides/filters/block-filters.md index 637cecadf1402b..b1a2372577366b 100644 --- a/docs/reference-guides/filters/block-filters.md +++ b/docs/reference-guides/filters/block-filters.md @@ -270,7 +270,7 @@ To avoid this validation error, use `render_block` server-side to modify existin ### `blocks.getBlockDefaultClassName` -Generated HTML classes for blocks follow the `wp-block-{name}` nomenclature. This filter allows to provide an alternative class name. +[Generated HTML classes for blocks](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#classname) follow the `wp-block-{name}` nomenclature. This filter allows to provide an alternative class name. ```js // Our filter function. @@ -286,6 +286,8 @@ wp.hooks.addFilter( ); ``` +If a block has opted into [block support for generated block _variation_ specific class names](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#classname), the filter also affects those. With the above example, if the `core/code` block has a `php` variation, it would get `my-plugin-code-php` as its variation specific class name (instead of the default `wp-block-code-php`). + ### `blocks.switchToBlockType.transformedBlock` Used to filter an individual transform result from block transformation. All of the original blocks are passed since transformations are many-to-many, not one-to-one. From 6ad4153b9b515aab809fa0a92ee85460a376097e Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 23 Jul 2024 18:32:07 +0200 Subject: [PATCH 35/41] Remove unnecessary check for blockName --- packages/block-editor/src/components/block-list/block.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 5053342e585ec8..75532b49517028 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -602,7 +602,7 @@ function BlockListBlockProvider( props ) { getSettings(); const hasLightBlockWrapper = blockType?.apiVersion > 1; const defaultClassNames = []; - if ( hasLightBlockWrapper && blockName ) { + if ( hasLightBlockWrapper ) { defaultClassNames.push( getBlockDefaultClassName( blockName ) ); if ( hasVariationClassNameSupport( blockType ) ) { From bc3fb00dee22586c4ef583f46982e0093cc151d7 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 23 Jul 2024 18:47:51 +0200 Subject: [PATCH 36/41] Add more notes on block default classname filter --- packages/blocks/README.md | 4 ++++ packages/blocks/src/api/serializer.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/blocks/README.md b/packages/blocks/README.md index b28263c91acc72..ed10bf8f456ef3 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -118,6 +118,8 @@ _Returns_ Returns the block's default classname from its name. +The return value can be filtered using the `blocks.getBlockDefaultClassName` filter. + _Parameters_ - _blockName_ `string`: The block name. @@ -204,6 +206,8 @@ Returns a block variation specific classname. If the given block matches a variation, the classname will be the block's default classname with the variation name appended (separated by a hyphen). +Note that the block's default classname is affected by the `blocks.getBlockDefaultClassName` filter. + _Parameters_ - _blockName_ `string`: The block name. diff --git a/packages/blocks/src/api/serializer.js b/packages/blocks/src/api/serializer.js index 2bf203baad143d..f65206c8e604ce 100644 --- a/packages/blocks/src/api/serializer.js +++ b/packages/blocks/src/api/serializer.js @@ -34,6 +34,8 @@ import { isUnmodifiedDefaultBlock, normalizeBlockType } from './utils'; /** * Returns the block's default classname from its name. * + * The return value can be filtered using the `blocks.getBlockDefaultClassName` filter. + * * @param {string} blockName The block name. * * @return {string} The block's default class. @@ -57,6 +59,8 @@ export function getBlockDefaultClassName( blockName ) { * If the given block matches a variation, the classname will be the block's default classname * with the variation name appended (separated by a hyphen). * + * Note that the block's default classname is affected by the `blocks.getBlockDefaultClassName` filter. + * * @param {string} blockName The block name. * @param {Object} attributes Block attributes. * From a37f5d34fbb47f69300c3c518e08a7a6cc61aedc Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 23 Jul 2024 18:56:12 +0200 Subject: [PATCH 37/41] Move description before type in schema --- schemas/json/block.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/schemas/json/block.json b/schemas/json/block.json index 21f4030d336b13..a9f009ddd6a721 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -262,12 +262,12 @@ "type": "object", "properties": { "block": { - "type": "boolean", - "description": "Add the .wp-block-your-block-name class to the block's wrapper element" + "description": "Add the .wp-block-your-block-name class to the block's wrapper element", + "type": "boolean" }, "variation": { - "type": "boolean", - "description": "Add the .wp-block-your-block-name-your-block-variation class to the block's wrapper element" + "description": "Add the .wp-block-your-block-name-your-block-variation class to the block's wrapper element", + "type": "boolean" } } } From 25f7a71463fc29f2334827ea2393c2053b337e8c Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Wed, 11 Sep 2024 17:45:04 +0200 Subject: [PATCH 38/41] toEqual -> toBe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Greg Ziółkowski --- packages/block-editor/src/hooks/test/supports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/test/supports.js b/packages/block-editor/src/hooks/test/supports.js index 102dcbc957535b..97be6b1004ff89 100644 --- a/packages/block-editor/src/hooks/test/supports.js +++ b/packages/block-editor/src/hooks/test/supports.js @@ -13,7 +13,7 @@ describe( 'hasBlockClassNameSupport', () => { const block = { name: blockName, }; - expect( hasBlockClassNameSupport( block ) ).toEqual( true ); + expect( hasBlockClassNameSupport( block ) ).toBe( true ); } ); it( 'should return false if the block does not support className', () => { From 6f016b30d6d30803de0a7f18fa74742d260d5ff3 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 17:45:44 +0200 Subject: [PATCH 39/41] toEqual -> toBe --- packages/block-editor/src/hooks/test/supports.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/hooks/test/supports.js b/packages/block-editor/src/hooks/test/supports.js index 97be6b1004ff89..8e4295cdee8f60 100644 --- a/packages/block-editor/src/hooks/test/supports.js +++ b/packages/block-editor/src/hooks/test/supports.js @@ -23,7 +23,7 @@ describe( 'hasBlockClassNameSupport', () => { className: false, }, }; - expect( hasBlockClassNameSupport( block ) ).toEqual( false ); + expect( hasBlockClassNameSupport( block ) ).toBe( false ); } ); it( 'should reflect the nested supports property if true', () => { @@ -35,7 +35,7 @@ describe( 'hasBlockClassNameSupport', () => { }, }, }; - expect( hasBlockClassNameSupport( block ) ).toEqual( true ); + expect( hasBlockClassNameSupport( block ) ).toBe( true ); } ); it( 'should reflect the nested supports property if false', () => { @@ -47,7 +47,7 @@ describe( 'hasBlockClassNameSupport', () => { }, }, }; - expect( hasBlockClassNameSupport( block ) ).toEqual( false ); + expect( hasBlockClassNameSupport( block ) ).toBe( false ); } ); } ); @@ -58,7 +58,7 @@ describe( 'hasVariationClassNameSupport', () => { const block = { name: blockName, }; - expect( hasVariationClassNameSupport( block ) ).toEqual( false ); + expect( hasVariationClassNameSupport( block ) ).toBe( false ); } ); it( 'should return false if the block does not explicitly support variation class names', () => { @@ -68,7 +68,7 @@ describe( 'hasVariationClassNameSupport', () => { className: true, }, }; - expect( hasVariationClassNameSupport( block ) ).toEqual( false ); + expect( hasVariationClassNameSupport( block ) ).toBe( false ); } ); it( 'should reflect the nested supports property if true', () => { @@ -80,7 +80,7 @@ describe( 'hasVariationClassNameSupport', () => { }, }, }; - expect( hasVariationClassNameSupport( block ) ).toEqual( true ); + expect( hasVariationClassNameSupport( block ) ).toBe( true ); } ); it( 'should reflect the nested supports property if false', () => { @@ -92,6 +92,6 @@ describe( 'hasVariationClassNameSupport', () => { }, }, }; - expect( hasVariationClassNameSupport( block ) ).toEqual( false ); + expect( hasVariationClassNameSupport( block ) ).toBe( false ); } ); } ); From d369a9781113f3b535a104b68e67ecd08ccdcad7 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 12 Sep 2024 16:53:43 +0200 Subject: [PATCH 40/41] Use __ instead of - to append variation name --- docs/reference-guides/block-api/block-supports.md | 2 +- packages/block-editor/src/hooks/test/generated-class-name.js | 4 ++-- packages/blocks/README.md | 2 +- packages/blocks/src/api/serializer.js | 4 ++-- packages/blocks/src/api/test/serializer.js | 2 +- schemas/json/block.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/reference-guides/block-api/block-supports.md b/docs/reference-guides/block-api/block-supports.md index 3b0a35edc5cfbe..f92eacbda1a531 100644 --- a/docs/reference-guides/block-api/block-supports.md +++ b/docs/reference-guides/block-api/block-supports.md @@ -206,7 +206,7 @@ supports: { ### className.variation -In the same vein, it is possible to have a variation-specific class added to a block (if the latter supports variations). E.g. if a block named `your/block-name` has a variation called `your-variation`, the following will add the class `.wp-block-your-block-name-your-variation`: +In the same vein, it is possible to have a variation-specific class added to a block (if the latter supports variations). E.g. if a block named `your/block-name` has a variation called `your-variation`, the following will add the class `.wp-block-your-block-name__your-variation`: ```js supports: { diff --git a/packages/block-editor/src/hooks/test/generated-class-name.js b/packages/block-editor/src/hooks/test/generated-class-name.js index 1622bce5892b91..3b17d0abc42bd9 100644 --- a/packages/block-editor/src/hooks/test/generated-class-name.js +++ b/packages/block-editor/src/hooks/test/generated-class-name.js @@ -150,7 +150,7 @@ describe( 'generated className', () => { ); expect( extraProps.className ).toBe( - 'wp-block-produce-fruit wp-block-produce-fruit-banana foo' + 'wp-block-produce-fruit wp-block-produce-fruit__banana foo' ); } ); @@ -172,7 +172,7 @@ describe( 'generated className', () => { ); expect( extraProps.className ).toBe( - 'wp-block-produce-fruit-banana foo' + 'wp-block-produce-fruit__banana foo' ); } ); } ); diff --git a/packages/blocks/README.md b/packages/blocks/README.md index ed10bf8f456ef3..8659f869e3a547 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -204,7 +204,7 @@ _Returns_ Returns a block variation specific classname. -If the given block matches a variation, the classname will be the block's default classname with the variation name appended (separated by a hyphen). +If the given block matches a variation, the classname will be the block's default classname with the variation name appended (separated by a double underscore, i.e. `__`). Note that the block's default classname is affected by the `blocks.getBlockDefaultClassName` filter. diff --git a/packages/blocks/src/api/serializer.js b/packages/blocks/src/api/serializer.js index f65206c8e604ce..526b91a4cfa37b 100644 --- a/packages/blocks/src/api/serializer.js +++ b/packages/blocks/src/api/serializer.js @@ -57,7 +57,7 @@ export function getBlockDefaultClassName( blockName ) { * Returns a block variation specific classname. * * If the given block matches a variation, the classname will be the block's default classname - * with the variation name appended (separated by a hyphen). + * with the variation name appended (separated by a double underscore, i.e. `__`). * * Note that the block's default classname is affected by the `blocks.getBlockDefaultClassName` filter. * @@ -72,7 +72,7 @@ export function getBlockVariationClassName( blockName, attributes ) { return null; } - return getBlockDefaultClassName( blockName ) + '-' + activeVariation.name; + return getBlockDefaultClassName( blockName ) + '__' + activeVariation.name; } /** diff --git a/packages/blocks/src/api/test/serializer.js b/packages/blocks/src/api/test/serializer.js index 3b6f5be5f544ed..14480b78c33d7b 100644 --- a/packages/blocks/src/api/test/serializer.js +++ b/packages/blocks/src/api/test/serializer.js @@ -541,7 +541,7 @@ describe( 'block serializer', () => { getBlockVariationClassName( 'core/fruit', { fruit: 'banana', } ) - ).toBe( 'wp-block-fruit-banana' ); + ).toBe( 'wp-block-fruit__banana' ); } ); } ); } ); diff --git a/schemas/json/block.json b/schemas/json/block.json index a9f009ddd6a721..49f57627f27e01 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -266,7 +266,7 @@ "type": "boolean" }, "variation": { - "description": "Add the .wp-block-your-block-name-your-block-variation class to the block's wrapper element", + "description": "Add the .wp-block-your-block-name__your-block-variation class to the block's wrapper element", "type": "boolean" } } From 7350ced386185f2ef635796aa26ab4eae41422ed Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 17 Sep 2024 09:05:08 +0200 Subject: [PATCH 41/41] Missed one test --- packages/block-editor/src/components/block-edit/test/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-edit/test/edit.js b/packages/block-editor/src/components/block-edit/test/edit.js index 45b819ca57965b..8747da0f4bf7a9 100644 --- a/packages/block-editor/src/components/block-edit/test/edit.js +++ b/packages/block-editor/src/components/block-edit/test/edit.js @@ -124,7 +124,7 @@ describe( 'Edit', () => { const editElement = screen.getByTestId( 'foo-bar' ); expect( editElement ).toHaveClass( 'wp-block-test-block' ); - expect( editElement ).toHaveClass( 'wp-block-test-block-variation' ); + expect( editElement ).toHaveClass( 'wp-block-test-block__variation' ); } ); it( 'should assign context', () => {