From ce51ab14d75c4d085038b9a3e7917629394010a5 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 17 Oct 2024 12:24:02 +0300 Subject: [PATCH 1/5] Iterate zoom out shuffle into a more visual control --- .../components/block-toolbar/change-design.js | 134 ++++++++++++++++++ .../src/components/block-toolbar/shuffle.js | 111 --------------- .../src/components/block-toolbar/style.scss | 15 ++ 3 files changed, 149 insertions(+), 111 deletions(-) create mode 100644 packages/block-editor/src/components/block-toolbar/change-design.js delete mode 100644 packages/block-editor/src/components/block-toolbar/shuffle.js diff --git a/packages/block-editor/src/components/block-toolbar/change-design.js b/packages/block-editor/src/components/block-toolbar/change-design.js new file mode 100644 index 00000000000000..9f18f81374d6eb --- /dev/null +++ b/packages/block-editor/src/components/block-toolbar/change-design.js @@ -0,0 +1,134 @@ +/** + * WordPress dependencies + */ +import { + ToolbarButton, + ToolbarGroup, + Dropdown, + __experimentalDropdownContentWrapper as DropdownContentWrapper, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { cloneBlock } from '@wordpress/blocks'; +import { useMemo } from '@wordpress/element'; +import { useAsyncList } from '@wordpress/compose'; +import { useSelect, useDispatch } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../store'; +import BlockPatternsList from '../block-patterns-list'; + +const EMPTY_ARRAY = []; +const MAX_PATTERNS_TO_SHOW = 6; +const POPOVER_PROPS = { + placement: 'bottom-start', +}; + +export default function ChangeDesign( { clientId } ) { + const { categories, currentPatternName, patterns } = useSelect( + ( select ) => { + const { + getBlockAttributes, + getBlockRootClientId, + __experimentalGetAllowedPatterns, + } = select( blockEditorStore ); + const attributes = getBlockAttributes( clientId ); + const _categories = attributes?.metadata?.categories || EMPTY_ARRAY; + const rootBlock = getBlockRootClientId( clientId ); + + // Calling `__experimentalGetAllowedPatterns` is expensive. + // Checking if the block can be changed prevents unnecessary selector calls. + // See: https://github.com/WordPress/gutenberg/pull/64736. + const _patterns = + _categories.length > 0 + ? __experimentalGetAllowedPatterns( rootBlock ) + : EMPTY_ARRAY; + return { + categories: _categories, + currentPatternName: attributes?.metadata?.patternName, + patterns: _patterns, + }; + }, + [ clientId ] + ); + const { replaceBlocks } = useDispatch( blockEditorStore ); + const sameCategoryPatternsWithSingleWrapper = useMemo( () => { + if ( categories.length === 0 || ! patterns || patterns.length === 0 ) { + return EMPTY_ARRAY; + } + return patterns + .filter( ( pattern ) => { + const isCorePattern = + pattern.source === 'core' || + ( pattern.source?.startsWith( 'pattern-directory' ) && + pattern.source !== 'pattern-directory/theme' ); + return ( + // Check if the pattern has only one top level block, + // otherwise we may switch to a pattern that doesn't have replacement suggestions. + pattern.blocks.length === 1 && + // We exclude the core patterns and pattern directory patterns that are not theme patterns. + ! isCorePattern && + // Exclude current pattern. + currentPatternName !== pattern.name && + pattern.categories?.some( ( category ) => { + return categories.includes( category ); + } ) && + // Check if the pattern is not a synced pattern. + ( pattern.syncStatus === 'unsynced' || ! pattern.id ) + ); + } ) + .slice( 0, MAX_PATTERNS_TO_SHOW ); + }, [ categories, currentPatternName, patterns ] ); + + const currentShownPatterns = useAsyncList( + sameCategoryPatternsWithSingleWrapper + ); + + if ( sameCategoryPatternsWithSingleWrapper.length < 2 ) { + return null; + } + + const onClickPattern = ( pattern ) => { + const newBlocks = ( pattern.blocks ?? [] ).map( ( block ) => { + return cloneBlock( block ); + } ); + newBlocks[ 0 ].attributes.metadata = { + ...newBlocks[ 0 ].attributes.metadata, + categories, + }; + replaceBlocks( clientId, newBlocks ); + }; + + return ( + { + return ( + + onToggle( ! isOpen ) } + aria-expanded={ isOpen } + > + { __( 'Change Design' ) } + + + ); + } } + renderContent={ () => ( + + + + ) } + /> + ); +} diff --git a/packages/block-editor/src/components/block-toolbar/shuffle.js b/packages/block-editor/src/components/block-toolbar/shuffle.js deleted file mode 100644 index 954c7ff22d68ce..00000000000000 --- a/packages/block-editor/src/components/block-toolbar/shuffle.js +++ /dev/null @@ -1,111 +0,0 @@ -/** - * WordPress dependencies - */ -import { shuffle } from '@wordpress/icons'; -import { ToolbarButton, ToolbarGroup } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { useMemo } from '@wordpress/element'; -import { useSelect, useDispatch } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { store as blockEditorStore } from '../../store'; - -const EMPTY_ARRAY = []; - -function Container( props ) { - return ( - - - - ); -} - -export default function Shuffle( { clientId, as = Container } ) { - const { categories, patterns, patternName } = useSelect( - ( select ) => { - const { - getBlockAttributes, - getBlockRootClientId, - __experimentalGetAllowedPatterns, - } = select( blockEditorStore ); - const attributes = getBlockAttributes( clientId ); - const _categories = attributes?.metadata?.categories || EMPTY_ARRAY; - const _patternName = attributes?.metadata?.patternName; - const rootBlock = getBlockRootClientId( clientId ); - - // Calling `__experimentalGetAllowedPatterns` is expensive. - // Checking if the block can be shuffled prevents unnecessary selector calls. - // See: https://github.com/WordPress/gutenberg/pull/64736. - const _patterns = - _categories.length > 0 - ? __experimentalGetAllowedPatterns( rootBlock ) - : EMPTY_ARRAY; - return { - categories: _categories, - patterns: _patterns, - patternName: _patternName, - }; - }, - [ clientId ] - ); - const { replaceBlocks } = useDispatch( blockEditorStore ); - const sameCategoryPatternsWithSingleWrapper = useMemo( () => { - if ( categories.length === 0 || ! patterns || patterns.length === 0 ) { - return EMPTY_ARRAY; - } - return patterns.filter( ( pattern ) => { - const isCorePattern = - pattern.source === 'core' || - ( pattern.source?.startsWith( 'pattern-directory' ) && - pattern.source !== 'pattern-directory/theme' ); - return ( - // Check if the pattern has only one top level block, - // otherwise we may shuffle to pattern that will not allow to continue shuffling. - pattern.blocks.length === 1 && - // We exclude the core patterns and pattern directory patterns that are not theme patterns. - ! isCorePattern && - pattern.categories?.some( ( category ) => { - return categories.includes( category ); - } ) && - // Check if the pattern is not a synced pattern. - ( pattern.syncStatus === 'unsynced' || ! pattern.id ) - ); - } ); - }, [ categories, patterns ] ); - - if ( sameCategoryPatternsWithSingleWrapper.length < 2 ) { - return null; - } - - function getNextPattern() { - const numberOfPatterns = sameCategoryPatternsWithSingleWrapper.length; - const patternIndex = sameCategoryPatternsWithSingleWrapper.findIndex( - ( { name } ) => name === patternName - ); - const nextPatternIndex = - patternIndex + 1 < numberOfPatterns ? patternIndex + 1 : 0; - return sameCategoryPatternsWithSingleWrapper[ nextPatternIndex ]; - } - - const ComponentToUse = as; - return ( - { - const nextPattern = getNextPattern(); - nextPattern.blocks[ 0 ].attributes = { - ...nextPattern.blocks[ 0 ].attributes, - metadata: { - ...nextPattern.blocks[ 0 ].attributes.metadata, - categories, - }, - }; - replaceBlocks( clientId, nextPattern.blocks ); - } } - /> - ); -} diff --git a/packages/block-editor/src/components/block-toolbar/style.scss b/packages/block-editor/src/components/block-toolbar/style.scss index ae03eeed1a817c..f6d53e6ad1e96d 100644 --- a/packages/block-editor/src/components/block-toolbar/style.scss +++ b/packages/block-editor/src/components/block-toolbar/style.scss @@ -285,3 +285,18 @@ } } } + +.block-editor-block-toolbar-change-design-content-wrapper { + width: 350px; // Same with quick inserter results. + .block-editor-block-patterns-list { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: $grid-unit-10; + .block-editor-block-patterns-list__list-item { + margin-bottom: 0; + } + .block-editor-inserter__media-list__list-item { + min-height: 100px; + } + } +} From 95d620a7fd94d0bfd2fc2568b2734785c555c1e6 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 17 Oct 2024 13:25:46 +0300 Subject: [PATCH 2/5] fix from rebase --- .../src/components/block-toolbar/change-design.js | 1 - .../src/components/block-toolbar/index.js | 11 +++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/block-toolbar/change-design.js b/packages/block-editor/src/components/block-toolbar/change-design.js index 9f18f81374d6eb..a33eeedccd71f1 100644 --- a/packages/block-editor/src/components/block-toolbar/change-design.js +++ b/packages/block-editor/src/components/block-toolbar/change-design.js @@ -108,7 +108,6 @@ export default function ChangeDesign( { clientId } ) { onToggle( ! isOpen ) } aria-expanded={ isOpen } > diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index d6a0985fef3610..5e7ae73a7bb7fa 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -16,7 +16,7 @@ import { isReusableBlock, isTemplatePart, } from '@wordpress/blocks'; -import { ToolbarGroup, ToolbarButton } from '@wordpress/components'; +import { ToolbarGroup } from '@wordpress/components'; /** * Internal dependencies @@ -35,7 +35,7 @@ import { store as blockEditorStore } from '../../store'; import __unstableBlockNameContext from './block-name-context'; import NavigableToolbar from '../navigable-toolbar'; import { useHasBlockToolbar } from './use-has-block-toolbar'; -import Shuffle from './shuffle'; +import ChangeDesign from './change-design'; import { unlock } from '../../lock-unlock'; /** @@ -211,12 +211,7 @@ export function PrivateBlockToolbar( { shouldShowVisualToolbar && isMultiToolbar && } { showShuffleButton && ( - - - + ) } { shouldShowVisualToolbar && ( <> From e681dae4349d3035400e91de8622950a57bd116d Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 17 Oct 2024 14:00:42 +0300 Subject: [PATCH 3/5] change label case --- .../block-editor/src/components/block-toolbar/change-design.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-toolbar/change-design.js b/packages/block-editor/src/components/block-toolbar/change-design.js index a33eeedccd71f1..3e57ba6e0095c3 100644 --- a/packages/block-editor/src/components/block-toolbar/change-design.js +++ b/packages/block-editor/src/components/block-toolbar/change-design.js @@ -111,7 +111,7 @@ export default function ChangeDesign( { clientId } ) { onClick={ () => onToggle( ! isOpen ) } aria-expanded={ isOpen } > - { __( 'Change Design' ) } + { __( 'Change design' ) } ); From c92892691f0d0bd581dd352d552052c49ee470c6 Mon Sep 17 00:00:00 2001 From: Rich Tabor Date: Thu, 17 Oct 2024 09:01:06 -0400 Subject: [PATCH 4/5] remove unnecessary isActive other text toolbar buttons do not do this. --- .../block-editor/src/components/block-toolbar/change-design.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-editor/src/components/block-toolbar/change-design.js b/packages/block-editor/src/components/block-toolbar/change-design.js index 3e57ba6e0095c3..ec1461e2ed5bc3 100644 --- a/packages/block-editor/src/components/block-toolbar/change-design.js +++ b/packages/block-editor/src/components/block-toolbar/change-design.js @@ -107,7 +107,6 @@ export default function ChangeDesign( { clientId } ) { return ( onToggle( ! isOpen ) } aria-expanded={ isOpen } > From ce8309c5b3a9ed7012a328c06edffbc412da0685 Mon Sep 17 00:00:00 2001 From: Rich Tabor Date: Thu, 17 Oct 2024 09:12:51 -0400 Subject: [PATCH 5/5] tweak sizing to line up with button --- .../src/components/block-toolbar/change-design.js | 3 ++- .../block-editor/src/components/block-toolbar/style.scss | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/block-toolbar/change-design.js b/packages/block-editor/src/components/block-toolbar/change-design.js index ec1461e2ed5bc3..ecfeff6cb1ed3e 100644 --- a/packages/block-editor/src/components/block-toolbar/change-design.js +++ b/packages/block-editor/src/components/block-toolbar/change-design.js @@ -118,12 +118,13 @@ export default function ChangeDesign( { clientId } ) { renderContent={ () => ( ) } diff --git a/packages/block-editor/src/components/block-toolbar/style.scss b/packages/block-editor/src/components/block-toolbar/style.scss index f6d53e6ad1e96d..26bf71356925e9 100644 --- a/packages/block-editor/src/components/block-toolbar/style.scss +++ b/packages/block-editor/src/components/block-toolbar/style.scss @@ -287,11 +287,12 @@ } .block-editor-block-toolbar-change-design-content-wrapper { - width: 350px; // Same with quick inserter results. + padding: $grid-unit-15; + width: 320px; .block-editor-block-patterns-list { display: grid; grid-template-columns: 1fr 1fr; - grid-gap: $grid-unit-10; + grid-gap: $grid-unit-15; .block-editor-block-patterns-list__list-item { margin-bottom: 0; }