Skip to content

Commit

Permalink
Display Block Information by matching block variations (#27469)
Browse files Browse the repository at this point in the history
* getBlockTypeWithVariationInfo selector, BlockDescription component and first changes to display the proper info

* revert BlockCard component and make the passed attributes top level with depracation

* remove BlockDescription

* change InserterPreviewPanel to use BlockCard with passing top level properties

* create new custom hook for block's display information

* use new hook in BlockInspector

* revert BlockIcon and augment BlockTitle

* Navigation List View update

* remove previous selector

* refactor BlockSwitcher to function component and use the new hook

* change hook

* use CreateSelector and declare WPBlockDisplayInformation typedef

* revert BlockSwitcher to handle in separate PR

* remove getBlockDisplayInformation selector

* add `isActive` API for block variations to use for trying to find a match

* doc for `isActive` in block variation

* jsdoc fix

* address review feedback part 1

* fix BlockTitle tests

* rename hook to `useBlockDisplayInformation`

* fix export

* useBlockDisplayInformation README

* move login in useSelect

* e2e tests

* blockTitle extra safeguard that existed before

* Update docs

Co-authored-by: Greg Ziółkowski <[email protected]>

* Update docs

Co-authored-by: Greg Ziółkowski <[email protected]>

* Update docs

Co-authored-by: Greg Ziółkowski <[email protected]>

* Update docs

Co-authored-by: Greg Ziółkowski <[email protected]>

* rewordings

* remove experimental status

* small refactoring

Co-authored-by: Greg Ziółkowski <[email protected]>
  • Loading branch information
ntsekouras and gziolo authored Dec 23, 2020
1 parent 9e48e87 commit 4b14897
Show file tree
Hide file tree
Showing 16 changed files with 345 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ example: {

#### variations (optional)

- **Type:** `Object[]`
- **Type:** `Object[]`

Similarly to how the block's style variations can be declared, a block type can define block variations that the user can pick from. The difference is that, rather than changing only the visual appearance, this field provides a way to apply initial custom attributes and inner blocks at the time when a block is inserted.

Expand Down Expand Up @@ -256,19 +256,20 @@ variations: [

An object describing a variation defined for the block type can contain the following fields:

- `name` (type `string`) – The unique and machine-readable name.
- `title` (type `string`) – A human-readable variation title.
- `description` (optional, type `string`) – A detailed variation description.
- `icon` (optional, type `string` | `Object`) – An icon helping to visualize the variation. It can have the same shape as the block type.
- `isDefault` (optional, type `boolean`) – Indicates whether the current variation is the default one. Defaults to `false`.
- `attributes` (optional, type `Object`) – Values that override block attributes.
- `innerBlocks` (optional, type `Array[]`) – Initial configuration of nested blocks.
- `example` (optional, type `Object`) – Example provides structured data for the block preview. You can set to `undefined` to disable the preview shown for the block type.
- `scope` (optional, type `WPBlockVariationScope[]`) - the list of scopes where the variation is applicable. When not provided, it defaults to `block` and `inserter`. Available options:
- `inserter` - Block Variation is shown on the inserter.
- `block` - Used by blocks to filter specific block variations. Mostly used in Placeholder patterns like `Columns` block.
- `transform` - Block Variation will be shown in the component for Block Variations transformations.
- `keywords` (optional, type `string[]`) - An array of terms (which can be translated) that help users discover the variation while searching.
- `name` (type `string`) – The unique and machine-readable name.
- `title` (type `string`) – A human-readable variation title.
- `description` (optional, type `string`) – A detailed variation description.
- `icon` (optional, type `string` | `Object`) – An icon helping to visualize the variation. It can have the same shape as the block type.
- `isDefault` (optional, type `boolean`) – Indicates whether the current variation is the default one. Defaults to `false`.
- `attributes` (optional, type `Object`) – Values that override block attributes.
- `innerBlocks` (optional, type `Array[]`) – Initial configuration of nested blocks.
- `example` (optional, type `Object`) – Example provides structured data for the block preview. You can set to `undefined` to disable the preview shown for the block type.
- `scope` (optional, type `WPBlockVariationScope[]`) - the list of scopes where the variation is applicable. When not provided, it defaults to `block` and `inserter`. Available options:
- `inserter` - Block Variation is shown on the inserter.
- `block` - Used by blocks to filter specific block variations. Mostly used in Placeholder patterns like `Columns` block.
- `transform` - Block Variation will be shown in the component for Block Variations transformations.
- `keywords` (optional, type `string[]`) - An array of terms (which can be translated) that help users discover the variation while searching.
- `isActive` (optional, type `Function`) - A function that accepts a block's attributes and the variation's attributes and determines if a variation is active. This function doesn't try to find a match dynamically based on all block's attributes, as in many cases some attributes are irrelevant. An example would be for `embed` block where we only care about `providerNameSlug` attribute's value.

It's also possible to override the default block style variation using the `className` attribute when defining block variations.

Expand All @@ -278,15 +279,17 @@ variations: [
name: 'blue',
title: __( 'Blue Quote' ),
isDefault: true,
attributes: { className: 'is-style-blue-quote' },
attributes: { color: 'blue', className: 'is-style-blue-quote' },
icon: 'format-quote',
isActive: ( blockAttributes, variationAttributes ) =>
blockAttributes.color === variationAttributes.color
},
],
```

#### supports (optional)

- ***Type:*** `Object`
- **_Type:_** `Object`

Supports contains as set of options to control features used in the editor. See the [the supports documentation](/docs/designers-developers/developers/block-api/block-supports.md) for more details.

Expand Down
24 changes: 22 additions & 2 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import {
BlockEditorProvider,
BlockList,
WritingFlow,
ObserveTyping
ObserveTyping,
} from '@wordpress/block-editor';
import { SlotFillProvider, Popover } from '@wordpress/components';
import { useState } from '@wordpress/element';

function MyEditorComponent () {
function MyEditorComponent() {
const [ blocks, updateBlocks ] = useState( [] );

return (
Expand Down Expand Up @@ -568,6 +568,26 @@ _Related_

- <https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/url-popover/README.md>

<a name="useBlockDisplayInformation" href="#useBlockDisplayInformation">#</a> **useBlockDisplayInformation**

Hook used to try to find a matching block variation and return
the appropriate information for display reasons. In order to
to try to find a match we need to things:
1\. Block's client id to extract it's current attributes.
2\. A block variation should have set `isActive` prop to a proper function.

If for any reason a block variaton match cannot be found,
the returned information come from the Block Type.
If no blockType is found with the provided clientId, returns null.

_Parameters_

- _clientId_ `string`: Block's client id.

_Returns_

- `?WPBlockDisplayInformation`: Block's display information, or `null` when the block or its type not found.

<a name="useBlockEditContext" href="#useBlockEditContext">#</a> **useBlockEditContext**

Undocumented declaration.
Expand Down
13 changes: 12 additions & 1 deletion packages/block-editor/src/components/block-card/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
/**
* WordPress dependencies
*/
import deprecated from '@wordpress/deprecated';

/**
* Internal dependencies
*/
import BlockIcon from '../block-icon';

function BlockCard( { blockType: { icon, title, description } } ) {
function BlockCard( { title, icon, description, blockType } ) {
if ( blockType ) {
deprecated( '`blockType` property in `BlockCard component`', {
alternative: '`title, icon and description` properties',
} );
( { title, icon, description } = blockType );
}
return (
<div className="block-editor-block-card">
<BlockIcon icon={ icon } showColors />
Expand Down
30 changes: 23 additions & 7 deletions packages/block-editor/src/components/block-inspector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import BlockStyles from '../block-styles';
import MultiSelectionInspector from '../multi-selection-inspector';
import DefaultStylePicker from '../default-style-picker';
import BlockVariationTransforms from '../block-variation-transforms';
import useBlockDisplayInformation from '../use-block-display-information';

const BlockInspector = ( {
blockType,
count,
Expand Down Expand Up @@ -64,22 +66,36 @@ const BlockInspector = ( {
}
return null;
}
return (
<BlockInspectorSingleBlock
clientId={ selectedBlockClientId }
blockName={ blockType.name }
hasBlockStyles={ hasBlockStyles }
bubblesVirtually={ bubblesVirtually }
/>
);
};

const BlockInspectorSingleBlock = ( {
clientId,
blockName,
hasBlockStyles,
bubblesVirtually,
} ) => {
const blockInformation = useBlockDisplayInformation( clientId );
return (
<div className="block-editor-block-inspector">
<BlockCard blockType={ blockType } />
<BlockVariationTransforms blockClientId={ selectedBlockClientId } />
<BlockCard { ...blockInformation } />
<BlockVariationTransforms blockClientId={ clientId } />
{ hasBlockStyles && (
<div>
<PanelBody title={ __( 'Styles' ) }>
<BlockStyles clientId={ selectedBlockClientId } />
<BlockStyles clientId={ clientId } />
{ hasBlockSupport(
blockType.name,
blockName,
'defaultStylePicker',
true
) && (
<DefaultStylePicker blockName={ blockType.name } />
) }
) && <DefaultStylePicker blockName={ blockName } /> }
</PanelBody>
</div>
) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ import { __ } from '@wordpress/i18n';
* Internal dependencies
*/
import BlockIcon from '../block-icon';
import useBlockDisplayInformation from '../use-block-display-information';
import { getBlockPositionDescription } from './utils';

function BlockNavigationBlockSelectButton(
{
className,
block,
block: { clientId, name, attributes },
isSelected,
onClick,
position,
Expand All @@ -38,12 +39,15 @@ function BlockNavigationBlockSelectButton(
},
ref
) {
const { name, attributes } = block;

const blockType = getBlockType( name );
const blockDisplayName = getBlockLabel( blockType, attributes );
const blockInformation = useBlockDisplayInformation( clientId );
const instanceId = useInstanceId( BlockNavigationBlockSelectButton );
const descriptionId = `block-navigation-block-select-button__${ instanceId }`;
const blockType = getBlockType( name );
const blockLabel = getBlockLabel( blockType, attributes );
// If label is defined we prioritize it over possible possible
// block variation match title.
const blockDisplayName =
blockLabel !== blockType.title ? blockLabel : blockInformation?.title;
const blockPositionDescription = getBlockPositionDescription(
position,
siblingBlockCount,
Expand All @@ -66,7 +70,7 @@ function BlockNavigationBlockSelectButton(
onDragEnd={ onDragEnd }
draggable={ draggable }
>
<BlockIcon icon={ blockType.icon } showColors />
<BlockIcon icon={ blockInformation.icon } showColors />
{ blockDisplayName }
{ isSelected && (
<VisuallyHidden>
Expand Down
27 changes: 13 additions & 14 deletions packages/block-editor/src/components/block-title/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import {
__experimentalGetBlockLabel as getBlockLabel,
} from '@wordpress/blocks';

/**
* Internal dependencies
*/
import useBlockDisplayInformation from '../use-block-display-information';

/**
* Renders the block's configured title as a string, or empty if the title
* cannot be determined.
Expand Down Expand Up @@ -44,22 +49,16 @@ export default function BlockTitle( { clientId } ) {
[ clientId ]
);

if ( ! name ) {
return null;
}

const blockInformation = useBlockDisplayInformation( clientId );
if ( ! name || ! blockInformation ) return null;
const blockType = getBlockType( name );
if ( ! blockType ) {
return null;
}

const { title } = blockType;
const label = getBlockLabel( blockType, attributes );

// Label will often fall back to the title if no label is defined for the
// Label will fallback to the title if no label is defined for the
// current label context. We do not want "Paragraph: Paragraph".
if ( label !== title ) {
return `${ title }: ${ truncate( label, { length: 15 } ) }`;
// If label is defined we prioritize it over possible possible
// block variation match title.
if ( label !== blockType.title ) {
return `${ blockType.title }: ${ truncate( label, { length: 15 } ) }`;
}
return title;
return blockInformation.title;
}
19 changes: 12 additions & 7 deletions packages/block-editor/src/components/block-title/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ jest.mock( '@wordpress/blocks', () => {
};
} );

jest.mock( '../../use-block-display-information', () => {
const resultsMap = {
'id-name-exists': { title: 'Block Title' },
'id-name-with-label': { title: 'Block With Label' },
'id-name-with-long-label': { title: 'Block With Long Label' },
};
return jest.fn( ( clientId ) => resultsMap[ clientId ] );
} );

jest.mock( '@wordpress/data/src/components/use-select', () => {
// This allows us to tweak the returned value on each test
const mock = jest.fn();
Expand Down Expand Up @@ -81,9 +90,7 @@ describe( 'BlockTitle', () => {
attributes: null,
} ) );

const wrapper = shallow(
<BlockTitle clientId="afd1cb17-2c08-4e7a-91be-007ba7ddc3a1" />
);
const wrapper = shallow( <BlockTitle clientId="id-name-exists" /> );

expect( wrapper.text() ).toBe( 'Block Title' );
} );
Expand All @@ -94,9 +101,7 @@ describe( 'BlockTitle', () => {
attributes: null,
} ) );

const wrapper = shallow(
<BlockTitle clientId="afd1cb17-2c08-4e7a-91be-007ba7ddc3a1" />
);
const wrapper = shallow( <BlockTitle clientId="id-name-with-label" /> );

expect( wrapper.text() ).toBe( 'Block With Label: Test Label' );
} );
Expand All @@ -108,7 +113,7 @@ describe( 'BlockTitle', () => {
} ) );

const wrapper = shallow(
<BlockTitle clientId="afd1cb17-2c08-4e7a-91be-007ba7ddc3a1" />
<BlockTitle clientId="id-name-with-long-label" />
);

expect( wrapper.text() ).toBe(
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export {
export { default as Warning } from './warning';
export { default as WritingFlow } from './writing-flow';
export { useCanvasClickRedirect as __unstableUseCanvasClickRedirect } from './use-canvas-click-redirect';
export { default as useBlockDisplayInformation } from './use-block-display-information';

/*
* State Related Components
Expand Down
21 changes: 13 additions & 8 deletions packages/block-editor/src/components/inserter/preview-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ import BlockCard from '../block-card';
import BlockPreview from '../block-preview';

function InserterPreviewPanel( { item } ) {
const hoveredItemBlockType = getBlockType( item.name );
const { name, title, icon, description, initialAttributes } = item;
const hoveredItemBlockType = getBlockType( name );
const isReusable = isReusableBlock( item );
return (
<div className="block-editor-inserter__preview-container">
<div className="block-editor-inserter__preview">
{ isReusableBlock( item ) || hoveredItemBlockType.example ? (
{ isReusable || hoveredItemBlockType.example ? (
<div className="block-editor-inserter__preview-content">
<BlockPreview
__experimentalPadding={ 16 }
Expand All @@ -34,16 +36,13 @@ function InserterPreviewPanel( { item } ) {
attributes: {
...hoveredItemBlockType.example
.attributes,
...item.initialAttributes,
...initialAttributes,
},
innerBlocks:
hoveredItemBlockType.example
.innerBlocks,
} )
: createBlock(
item.name,
item.initialAttributes
)
: createBlock( name, initialAttributes )
}
/>
</div>
Expand All @@ -53,7 +52,13 @@ function InserterPreviewPanel( { item } ) {
</div>
) }
</div>
{ ! isReusableBlock( item ) && <BlockCard blockType={ item } /> }
{ ! isReusable && (
<BlockCard
title={ title }
icon={ icon }
description={ description }
/>
) }
</div>
);
}
Expand Down
Loading

0 comments on commit 4b14897

Please sign in to comment.