From 82301e617e981277937f9a9c4d13166dbe8204ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Tue, 15 Mar 2022 14:57:54 +0100 Subject: [PATCH 1/4] The initial attempt to bring innerblocks into the search block --- packages/block-library/src/search/edit.js | 97 ++++++++++------------- 1 file changed, 41 insertions(+), 56 deletions(-) diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index f9480ddecb8308..e6fd9929e6d18a 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -15,9 +15,10 @@ import { __experimentalUnitControl as UnitControl, __experimentalUseColorProps as useColorProps, store as blockEditorStore, + useInnerBlocksProps, } from '@wordpress/block-editor'; import { useDispatch, useSelect } from '@wordpress/data'; -import { useEffect } from '@wordpress/element'; +import { useEffect, useMemo } from '@wordpress/element'; import { ToolbarDropdownMenu, ToolbarGroup, @@ -236,54 +237,43 @@ export default function SearchEdit( { ); }; - const renderButton = () => { - // If the button is inside the wrapper, the wrapper gets the border color styles/classes, not the button. - const buttonClasses = classnames( - 'wp-block-search__button', - colorProps.className, - isButtonPositionInside ? undefined : borderProps.className, - buttonUseIcon ? 'has-icon' : undefined - ); - const buttonStyles = { - ...colorProps.style, - ...( isButtonPositionInside - ? { borderRadius } - : borderProps.style ), - }; - - return ( - <> - { buttonUseIcon && ( - - ) } - - { ! buttonUseIcon && ( - - setAttributes( { buttonText: html } ) - } - /> - ) } - - ); - }; + const ALLOWED_BLOCKS = [ 'core/button' ]; + const blockProps = useBlockProps( { + className: getBlockClassNames(), + } ); + const innerBlocksProps = useInnerBlocksProps( blockProps, { + orientation: 'horizontal', + renderAppender: false, + template: [ + [ + 'core/button', + { + text: [ + buttonUseIcon ? : false, // get the icon to render + 'Search', + ], + className: classnames( + { + [ borderProps.className ]: isButtonPositionInside, + }, + colorProps.className + ), + style: { + ...( isButtonPositionInside + ? { borderRadius } + : borderProps.style ), + }, + }, + [], + ], + ], + templateLock: 'all', + allowedBlocks: ALLOWED_BLOCKS, + onChange: ( html ) => { + setAttributes( { buttonText: html } ); + }, + } ); + const button =
; const controls = ( <> @@ -439,10 +429,6 @@ export default function SearchEdit( { return styles; }; - const blockProps = useBlockProps( { - className: getBlockClassNames(), - } ); - return (
{ controls } @@ -457,7 +443,6 @@ export default function SearchEdit( { onChange={ ( html ) => setAttributes( { label: html } ) } /> ) } - { renderTextField() } - { renderButton() } + { button } ) } - { hasOnlyButton && renderButton() } + { hasOnlyButton && button } { hasNoButton && renderTextField() }
From 45a82a3e1d70d4201c66bb9162040e8d65aed919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Tue, 15 Mar 2022 18:02:08 +0100 Subject: [PATCH 2/4] Update inner blocks based on the parent block --- packages/block-library/src/search/edit.js | 112 ++++++++++++++++------ 1 file changed, 84 insertions(+), 28 deletions(-) diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index e6fd9929e6d18a..2c63d87c882a4e 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -18,7 +18,7 @@ import { useInnerBlocksProps, } from '@wordpress/block-editor'; import { useDispatch, useSelect } from '@wordpress/data'; -import { useEffect, useMemo } from '@wordpress/element'; +import { useEffect, useMemo, useCallback } from '@wordpress/element'; import { ToolbarDropdownMenu, ToolbarGroup, @@ -52,6 +52,8 @@ import { MIN_WIDTH, MIN_WIDTH_UNIT, } from './utils.js'; +import { cloneBlock, createBlock } from '@wordpress/blocks'; +import { useEntityBlockEditor } from '@wordpress/core-data'; // Used to calculate border radius adjustment to avoid "fat" corners when // button is placed inside wrapper. @@ -241,37 +243,91 @@ export default function SearchEdit( { const blockProps = useBlockProps( { className: getBlockClassNames(), } ); - const innerBlocksProps = useInnerBlocksProps( blockProps, { - orientation: 'horizontal', - renderAppender: false, - template: [ - [ - 'core/button', - { - text: [ - buttonUseIcon ? : false, // get the icon to render - 'Search', - ], - className: classnames( + + const { getBlocks } = useSelect( blockEditorStore ); + const hasInnerBlocks = useSelect( + ( select ) => + select( blockEditorStore ).getBlocks( clientId ).length > 0, + [ clientId ] + ); + const { replaceInnerBlocks } = useDispatch( blockEditorStore ); + useEffect( () => { + if ( ! hasInnerBlocks ) { + replaceInnerBlocks( + clientId, + [ + createBlock( + 'core/button', { - [ borderProps.className ]: isButtonPositionInside, + text: [ + buttonUseIcon ? ( + + ) : ( + false + ), // todo: get the icon to render + buttonUseIcon ? 'icon' : false, + 'Search', + ], + className: classnames( + { + [ borderProps.className ]: isButtonPositionInside, + }, + colorProps.className + ), + style: { + ...( isButtonPositionInside + ? { borderRadius } + : borderProps.style ), + }, }, - colorProps.className + [] ), - style: { - ...( isButtonPositionInside - ? { borderRadius } - : borderProps.style ), - }, - }, - [], - ], - ], - templateLock: 'all', - allowedBlocks: ALLOWED_BLOCKS, - onChange: ( html ) => { - setAttributes( { buttonText: html } ); + ], + true + ); + } + }, [ hasInnerBlocks, clientId ] ); + + const updateButtonAttrs = useCallback( + ( mapper ) => { + const prevBlocks = getBlocks( clientId ); + const nextBlocks = prevBlocks + .map( ( block ) => cloneBlock( block ) ) + .map( ( block ) => ( { + ...block, + attributes: mapper( block.attributes ), + } ) ); + replaceInnerBlocks( clientId, nextBlocks ); }, + [ clientId ] + ); + + useEffect( () => { + updateButtonAttrs( ( prev ) => ( { + ...prev, + className: classnames( prev.className, { + [ borderProps.className ]: isButtonPositionInside, + // How to use colorProps.className ? + } ), + style: isButtonPositionInside + ? { borderRadius } + : borderProps.style, + text: buttonUseIcon + ? [ , 'icon', prev.text ] + : prev.text.slice( 2 ), // super naive for now + } ) ); + }, [ + isButtonPositionInside, + buttonUseIcon, + // colorProps, TODO + // borderProps, + clientId, + ] ); + + const innerBlocksProps = useInnerBlocksProps( blockProps, { + orientation: 'horizontal', + renderAppender: false, + allowedBlocks: ALLOWED_BLOCKS, } ); const button =
; From 8cad486fbcc4533dd9784ab7075e68a7d764d95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Wed, 16 Mar 2022 16:29:08 +0100 Subject: [PATCH 3/4] Synchronize the border and padding properties of the search block to the button block --- packages/block-library/src/search/edit.js | 108 ++++++++-------------- 1 file changed, 38 insertions(+), 70 deletions(-) diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index 2c63d87c882a4e..09c7f12a21ef3a 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -18,7 +18,7 @@ import { useInnerBlocksProps, } from '@wordpress/block-editor'; import { useDispatch, useSelect } from '@wordpress/data'; -import { useEffect, useMemo, useCallback } from '@wordpress/element'; +import { useEffect, useMemo } from '@wordpress/element'; import { ToolbarDropdownMenu, ToolbarGroup, @@ -33,7 +33,6 @@ import { import { useInstanceId } from '@wordpress/compose'; import { Icon, search } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; -import { __unstableStripHTML as stripHTML } from '@wordpress/dom'; /** * Internal dependencies @@ -52,8 +51,7 @@ import { MIN_WIDTH, MIN_WIDTH_UNIT, } from './utils.js'; -import { cloneBlock, createBlock } from '@wordpress/blocks'; -import { useEntityBlockEditor } from '@wordpress/core-data'; +import { createBlock } from '@wordpress/blocks'; // Used to calculate border radius adjustment to avoid "fat" corners when // button is placed inside wrapper. @@ -250,83 +248,53 @@ export default function SearchEdit( { select( blockEditorStore ).getBlocks( clientId ).length > 0, [ clientId ] ); - const { replaceInnerBlocks } = useDispatch( blockEditorStore ); - useEffect( () => { - if ( ! hasInnerBlocks ) { - replaceInnerBlocks( - clientId, - [ - createBlock( - 'core/button', - { - text: [ - buttonUseIcon ? ( - - ) : ( - false - ), // todo: get the icon to render - buttonUseIcon ? 'icon' : false, - 'Search', - ], - className: classnames( - { - [ borderProps.className ]: isButtonPositionInside, - }, - colorProps.className - ), - style: { - ...( isButtonPositionInside - ? { borderRadius } - : borderProps.style ), - }, - }, - [] - ), - ], - true - ); - } - }, [ hasInnerBlocks, clientId ] ); - - const updateButtonAttrs = useCallback( - ( mapper ) => { - const prevBlocks = getBlocks( clientId ); - const nextBlocks = prevBlocks - .map( ( block ) => cloneBlock( block ) ) - .map( ( block ) => ( { - ...block, - attributes: mapper( block.attributes ), - } ) ); - replaceInnerBlocks( clientId, nextBlocks ); + + // borderColor, style, backgroundColor, textColor, gradient + const getNextButtonAttrs = ( prevAttrs = {} ) => ( { + borderColor: isButtonPositionInside ? attributes.borderColor : {}, + style: { + ...attributes.style, + ...( isButtonPositionInside ? { borderRadius } : {} ), }, - [ clientId ] - ); + backgroundColor: attributes.backgroundColor, + textColor: attributes.textColor, + gradient: attributes.gradient, + text: [ + // TODO: get that icon to render: + buttonUseIcon ? : false, + buttonUseIcon ? 'icon' : false, + // Naive for now: + prevAttrs.text + ? prevAttrs.text[ prevAttrs.text.length - 1 ] + : 'Search', + ], + } ); - useEffect( () => { - updateButtonAttrs( ( prev ) => ( { - ...prev, - className: classnames( prev.className, { - [ borderProps.className ]: isButtonPositionInside, - // How to use colorProps.className ? - } ), - style: isButtonPositionInside - ? { borderRadius } - : borderProps.style, - text: buttonUseIcon - ? [ , 'icon', prev.text ] - : prev.text.slice( 2 ), // super naive for now - } ) ); + const template = useMemo( + () => [ [ 'core/button', getNextButtonAttrs() ] ], + [] + ); + const value = useMemo( () => { + const prevAttrs = getBlocks( clientId )[ 0 ]?.attributes; + const nextAttrs = getNextButtonAttrs( prevAttrs ); + return [ createBlock( 'core/button', nextAttrs, [] ) ]; }, [ isButtonPositionInside, buttonUseIcon, - // colorProps, TODO - // borderProps, + colorProps, + borderProps, + hasInnerBlocks, clientId, ] ); const innerBlocksProps = useInnerBlocksProps( blockProps, { orientation: 'horizontal', renderAppender: false, + value, + onChange: () => {}, + onInput: () => {}, + template, + templateLock: 'all', allowedBlocks: ALLOWED_BLOCKS, } ); const button =
; From e9f7e26adc900b465ea3c2fdd00d4b01038a2f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Thu, 17 Mar 2022 16:58:28 +0100 Subject: [PATCH 4/4] Trick the editor into thinking the search block is selected when interacting with the inner button block --- packages/block-editor/src/store/reducer.js | 9 +++++ packages/block-library/src/search/edit.js | 43 ++++++++++------------ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 76e015b796128c..10b2002c1879fe 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1276,6 +1276,15 @@ function selectionHelper( state = {}, action ) { * @return {boolean} Updated state. */ export function selection( state = {}, action ) { + if ( + action.clientId === + document.querySelector( '.wp-block-button' )?.dataset?.block + ) { + action.clientId = document.querySelector( + '.wp-block-search' + )?.dataset?.block; + } + switch ( action.type ) { case 'SELECTION_CHANGE': return { diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index 09c7f12a21ef3a..48c659fb827d00 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -51,7 +51,7 @@ import { MIN_WIDTH, MIN_WIDTH_UNIT, } from './utils.js'; -import { createBlock } from '@wordpress/blocks'; +import { cloneBlock } from '@wordpress/blocks'; // Used to calculate border radius adjustment to avoid "fat" corners when // button is placed inside wrapper. @@ -72,7 +72,6 @@ export default function SearchEdit( { width, widthUnit, align, - buttonText, buttonPosition, buttonUseIcon, style, @@ -90,9 +89,10 @@ export default function SearchEdit( { }, [ clientId ] ); - const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( - blockEditorStore - ); + const { + __unstableMarkNextChangeAsNotPersistent, + replaceInnerBlocks, + } = useDispatch( blockEditorStore ); useEffect( () => { if ( ! insertedInNavigationBlock ) return; // This side-effect should not create an undo level. @@ -259,30 +259,29 @@ export default function SearchEdit( { backgroundColor: attributes.backgroundColor, textColor: attributes.textColor, gradient: attributes.gradient, - text: [ - // TODO: get that icon to render: - buttonUseIcon ? : false, - buttonUseIcon ? 'icon' : false, - // Naive for now: - prevAttrs.text - ? prevAttrs.text[ prevAttrs.text.length - 1 ] - : 'Search', - ], + // TODO: Use icon when needed + text: prevAttrs.text || 'Search', } ); const template = useMemo( () => [ [ 'core/button', getNextButtonAttrs() ] ], [] ); - const value = useMemo( () => { - const prevAttrs = getBlocks( clientId )[ 0 ]?.attributes; - const nextAttrs = getNextButtonAttrs( prevAttrs ); - return [ createBlock( 'core/button', nextAttrs, [] ) ]; + useEffect( () => { + const prevBlock = getBlocks( clientId )[ 0 ]; + const nextBlock = cloneBlock( + prevBlock, + getNextButtonAttrs( prevBlock?.attributes ), + [] + ); + replaceInnerBlocks( clientId, [ nextBlock ] ); }, [ isButtonPositionInside, buttonUseIcon, - colorProps, - borderProps, + // Must serialize these two, they are new objects each time and + // keep triggering the effect + JSON.stringify( colorProps ), + JSON.stringify( borderProps ), hasInnerBlocks, clientId, ] ); @@ -290,11 +289,7 @@ export default function SearchEdit( { const innerBlocksProps = useInnerBlocksProps( blockProps, { orientation: 'horizontal', renderAppender: false, - value, - onChange: () => {}, - onInput: () => {}, template, - templateLock: 'all', allowedBlocks: ALLOWED_BLOCKS, } ); const button =
;