Skip to content

Commit

Permalink
Suggest block pattern transformations that are contextual to the curr…
Browse files Browse the repository at this point in the history
…ently selected 'simple' blocks (no InnerBlocks) (#30469)

* spin off from #29890 for simple blocks without InnerBlocks

* __experimentalGetBlockAttributesNamesByRole tests

* update patterns

* useTransformedPatterns and refactoring part 1

* getMatchingBlockByName tests + and other jsdoc

* getPatternTransformedBlocks + transformMatchingBlock tests

* add role:content to more blocks + a couple test patterns

* pattern list padding

* rename role to __experimentalRole

* Update docs suggestion

Co-authored-by: Miguel Fonseca <[email protected]>

* fix tests + docs

* change patterns

* update social pattern

Co-authored-by: James Koster <[email protected]>
Co-authored-by: Miguel Fonseca <[email protected]>
  • Loading branch information
3 people authored Apr 13, 2021
1 parent 3e8ac5a commit 5c1e913
Show file tree
Hide file tree
Showing 20 changed files with 1,113 additions and 23 deletions.
26 changes: 26 additions & 0 deletions lib/block-patterns.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,29 @@
<!-- /wp:group -->',
)
);

// Initial block patterns to be used in block transformations with patterns.
register_block_pattern(
'paragraph/large-with-background-color',
array(
'title' => __( 'Large Paragraph with background color', 'gutenberg' ),
'blockTypes' => array( 'core/paragraph' ),
'viewportWidth' => 500,
'content' => '<!-- wp:paragraph {"style":{"color":{"link":"#FFFFFF","text":"#FFFFFF","background":"#000000"},"typography":{"lineHeight":"1.3","fontSize":"26px"}}} -->
<p class="has-text-color has-background has-link-color" style="--wp--style--color--link:#FFFFFF;background-color:#000000;color:#FFFFFF;font-size:26px;line-height:1.3">The whole series of my life appeared to me as a dream; I sometimes doubted if indeed it were all true, for it never presented itself to my mind with the force of reality.</p>
<!-- /wp:paragraph -->',
)
);
register_block_pattern(
'social-links/shared-background-color',
array(
'title' => __( 'Social links with a shared background color', 'gutenberg' ),
'blockTypes' => array( 'core/social-links' ),
'viewportWidth' => 500,
'content' => '<!-- wp:social-links {"customIconColor":"#ffffff","iconColorValue":"#ffffff","customIconBackgroundColor":"#3962e3","iconBackgroundColorValue":"#3962e3","className":"has-icon-color"} -->
<ul class="wp-block-social-links has-icon-color has-icon-background-color"><!-- wp:social-link {"url":"https://wordpress.org","service":"wordpress"} /-->
<!-- wp:social-link {"url":"#","service":"chain"} /-->
<!-- wp:social-link {"url":"#","service":"mail"} /--></ul>
<!-- /wp:social-links -->',
)
);
46 changes: 37 additions & 9 deletions packages/block-editor/src/components/block-switcher/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import BlockIcon from '../block-icon';
import BlockTitle from '../block-title';
import BlockTransformationsMenu from './block-transformations-menu';
import BlockStylesMenu from './block-styles-menu';
import PatternTransformationsMenu from './pattern-transformations-menu';

export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => {
const { replaceBlocks } = useDispatch( blockEditorStore );
Expand All @@ -40,12 +41,14 @@ export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => {
hasBlockStyles,
icon,
blockTitle,
patterns,
} = useSelect(
( select ) => {
const { getBlockRootClientId, getBlockTransformItems } = select(
blockEditorStore
);

const {
getBlockRootClientId,
getBlockTransformItems,
__experimentalGetPatternTransformItems,
} = select( blockEditorStore );
const { getBlockStyles, getBlockType } = select( blocksStore );
const rootClientId = getBlockRootClientId(
castArray( clientIds )[ 0 ]
Expand All @@ -66,7 +69,6 @@ export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => {
? getBlockType( firstBlockName )?.icon
: stack;
}

return {
possibleBlockTransformations: getBlockTransformItems(
blocks,
Expand All @@ -75,6 +77,10 @@ export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => {
hasBlockStyles: !! styles?.length,
icon: _icon,
blockTitle: getBlockType( firstBlockName ).title,
patterns: __experimentalGetPatternTransformItems(
blocks,
rootClientId
),
};
},
[ clientIds, blocks, blockInformation?.icon ]
Expand All @@ -83,9 +89,14 @@ export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => {
const isReusable = blocks.length === 1 && isReusableBlock( blocks[ 0 ] );
const isTemplate = blocks.length === 1 && isTemplatePart( blocks[ 0 ] );

const onTransform = ( name ) =>
// Simple block tranformation based on the `Block Transforms` API.
const onBlockTransform = ( name ) =>
replaceBlocks( clientIds, switchToBlockType( blocks, name ) );
// Pattern transformation through the `Patterns` API.
const onPatternTransform = ( transformedBlocks ) =>
replaceBlocks( clientIds, transformedBlocks );
const hasPossibleBlockTransformations = !! possibleBlockTransformations.length;
const hasPatternTransformation = !! patterns?.length;
if ( ! hasBlockStyles && ! hasPossibleBlockTransformations ) {
return (
<ToolbarGroup>
Expand Down Expand Up @@ -114,6 +125,10 @@ export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => {
blocks.length
);

const showDropDown =
hasBlockStyles ||
hasPossibleBlockTransformations ||
hasPatternTransformation;
return (
<ToolbarGroup>
<ToolbarItem>
Expand Down Expand Up @@ -147,9 +162,22 @@ export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => {
menuProps={ { orientation: 'both' } }
>
{ ( { onClose } ) =>
( hasBlockStyles ||
hasPossibleBlockTransformations ) && (
showDropDown && (
<div className="block-editor-block-switcher__container">
{ hasPatternTransformation && (
<PatternTransformationsMenu
blocks={ blocks }
patterns={ patterns }
onSelect={ (
transformedBlocks
) => {
onPatternTransform(
transformedBlocks
);
onClose();
} }
/>
) }
{ hasPossibleBlockTransformations && (
<BlockTransformationsMenu
className="block-editor-block-switcher__transforms__menugroup"
Expand All @@ -158,7 +186,7 @@ export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => {
}
blocks={ blocks }
onSelect={ ( name ) => {
onTransform( name );
onBlockTransform( name );
onClose();
} }
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { useInstanceId } from '@wordpress/compose';
import { chevronRight } from '@wordpress/icons';

import {
MenuGroup,
MenuItem,
Popover,
VisuallyHidden,
__unstableComposite as Composite,
__unstableUseCompositeState as useCompositeState,
__unstableCompositeItem as CompositeItem,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import BlockPreview from '../block-preview';
import useTransformedPatterns from './use-transformed-patterns';

function PatternTransformationsMenu( {
blocks,
patterns: statePatterns,
onSelect,
} ) {
const [ showTransforms, setShowTransforms ] = useState( false );
const patterns = useTransformedPatterns( statePatterns, blocks );
if ( ! patterns.length ) return null;

return (
<MenuGroup className="block-editor-block-switcher__pattern__transforms__menugroup">
{ showTransforms && (
<PreviewPatternsPopover
patterns={ patterns }
onSelect={ onSelect }
/>
) }
<MenuItem
onClick={ ( event ) => {
event.preventDefault();
setShowTransforms( ! showTransforms );
} }
icon={ chevronRight }
>
{ __( 'Patterns' ) }
</MenuItem>
</MenuGroup>
);
}

function PreviewPatternsPopover( { patterns, onSelect } ) {
return (
<div className="block-editor-block-switcher__popover__preview__parent">
<div className="block-editor-block-switcher__popover__preview__container">
<Popover
className="block-editor-block-switcher__preview__popover"
position="bottom right"
>
<div className="block-editor-block-switcher__preview">
<div className="block-editor-block-switcher__preview-title">
{ __( 'Preview' ) }
</div>
<BlockPatternsList
patterns={ patterns }
onSelect={ onSelect }
/>
</div>
</Popover>
</div>
</div>
);
}

function BlockPatternsList( { patterns, onSelect } ) {
const composite = useCompositeState();
return (
<Composite
{ ...composite }
role="listbox"
className="block-editor-block-switcher__preview-patterns-container"
aria-label={ __( 'Patterns list' ) }
>
{ patterns.map( ( pattern ) => (
<BlockPattern
key={ pattern.name }
pattern={ pattern }
onSelect={ onSelect }
composite={ composite }
/>
) ) }
</Composite>
);
}

function BlockPattern( { pattern, onSelect, composite } ) {
// TODO check pattern/preview width...
const baseClassName =
'block-editor-block-switcher__preview-patterns-container';
const descriptionId = useInstanceId(
BlockPattern,
`${ baseClassName }-list__item-description`
);
return (
<div
className={ `${ baseClassName }-list__list-item` }
aria-label={ pattern.title }
aria-describedby={ pattern.description ? descriptionId : undefined }
>
<CompositeItem
role="option"
as="div"
{ ...composite }
className={ `${ baseClassName }-list__item` }
onClick={ () => onSelect( pattern.transformedBlocks ) }
>
<BlockPreview
blocks={ pattern.transformedBlocks }
viewportWidth={ pattern.viewportWidth || 500 }
/>
<div className={ `${ baseClassName }-list__item-title` }>
{ pattern.title }
</div>
</CompositeItem>
{ !! pattern.description && (
<VisuallyHidden id={ descriptionId }>
{ pattern.description }
</VisuallyHidden>
) }
</div>
);
}

export default PatternTransformationsMenu;
41 changes: 40 additions & 1 deletion packages/block-editor/src/components/block-switcher/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@
padding: 0;

.components-menu-group {
padding: $grid-unit-20;
margin: 0;
}
}
Expand Down Expand Up @@ -149,6 +148,7 @@
.block-editor-block-switcher__preview {
width: 300px;
height: auto;
max-height: 500px;
padding: $grid-unit-20;
}
}
Expand Down Expand Up @@ -182,3 +182,42 @@
}
}
}

.block-editor-block-switcher__preview-patterns-container {
padding-bottom: $grid-unit-20;

.block-editor-block-switcher__preview-patterns-container-list__list-item {
margin-top: $grid-unit-20;

.block-editor-block-preview__container {
cursor: pointer;
}

.block-editor-block-switcher__preview-patterns-container-list__item {
height: 100%;
border-radius: $radius-block-ui;
transition: all 0.05s ease-in-out;
position: relative;
border: $border-width solid transparent;

&:hover,
&:focus {
box-shadow: inset 0 0 0 1px $white, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);

// Windows High Contrast mode will show this outline, but not the box-shadow.
outline: 2px solid transparent;
}

&:hover {
box-shadow: inset 0 0 0 1px $white, 0 0 0 var(--wp-admin-border-width-focus) $gray-900;
}

.block-editor-block-switcher__preview-patterns-container-list__item-title {
padding: $grid-unit-05;
font-size: 12px;
text-align: center;
cursor: pointer;
}
}
}
}
Loading

0 comments on commit 5c1e913

Please sign in to comment.