Skip to content

Commit

Permalink
Block Library: Update Columns block to use Patterns API (#18283)
Browse files Browse the repository at this point in the history
* Block library: Refactor Columns block to use Patterns API

* Blocks: Add support for the default block pattern

* Components: Add size prop to the IconButton component

* Change the behavior of the selector which returns the default block pattern

* Block editor: Extract BLockPatternPicker component

* Abstract columns picker selection with __experimentalBlockPatternPicker

* Use Icon component to unify the way icons are handled
  • Loading branch information
gziolo committed Nov 29, 2019
1 parent c65477e commit ae327b2
Show file tree
Hide file tree
Showing 20 changed files with 419 additions and 400 deletions.
67 changes: 67 additions & 0 deletions packages/block-editor/src/components/block-pattern-picker/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Button, IconButton, Placeholder } from '@wordpress/components';

function BlockPatternPicker( {
icon = 'layout',
label = __( 'Choose pattern' ),
instructions = __( 'Select a pattern to start with.' ),
patterns,
onSelect,
allowSkip,
} ) {
const classes = classnames( 'block-editor-block-pattern-picker', {
'has-many-patterns': patterns.length > 4,
} );

return (
<Placeholder
icon={ icon }
label={ label }
instructions={ instructions }
className={ classes }
>
{
/*
* Disable reason: The `list` ARIA role is redundant but
* Safari+VoiceOver won't announce the list otherwise.
*/
/* eslint-disable jsx-a11y/no-redundant-roles */
}
<ul className="block-editor-block-pattern-picker__patterns" role="list">
{ patterns.map( ( pattern ) => (
<li key={ pattern.name }>
<IconButton
isLarge
icon={ pattern.icon }
size={ 48 }
onClick={ () => onSelect( pattern ) }
className="block-editor-block-pattern-picker__pattern"
label={ pattern.label }
/>
</li>
) ) }
</ul>
{ /* eslint-enable jsx-a11y/no-redundant-roles */ }
{ allowSkip && (
<div className="block-editor-block-pattern-picker__skip">
<Button
isLink
onClick={ () => onSelect() }
>
{ __( 'Skip' ) }
</Button>
</div>
) }
</Placeholder>
);
}

export default BlockPatternPicker;
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
.block-editor-block-pattern-picker {
.components-placeholder__instructions {
// Defer to vertical margins applied by template picker options.
margin-bottom: 0;
}

.components-placeholder__fieldset {
// Options will render horizontally, but the immediate children of the
// fieldset are the options and the skip button, oriented vertically.
flex-direction: column;
}

&.has-many-patterns .components-placeholder__fieldset {
// Allow options to occupy a greater amount of the available space if
// many options exist.
max-width: 90%;
}
}

.block-editor-block-pattern-picker__patterns.block-editor-block-pattern-picker__patterns {
display: flex;
justify-content: center;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
margin: $grid-size-small 0;
list-style: none;

> li {
list-style: none;
margin: $grid-size;
flex-shrink: 1;
max-width: 100px;
}

.block-editor-block-pattern-picker__pattern {
padding: $grid-size;
}
}

.block-editor-block-pattern-picker__pattern {
width: 100%;

&.components-icon-button {
// Override default styles inherited from <IconButton /> to center
// icon horizontally.
justify-content: center;

&.is-default {
background-color: $white;
}
}

&.components-button {
// Override default styles inherited from <Button /> to allow button
// to grow vertically.
height: auto;
padding: 0;
}

&::before {
// Use `padding-bottom` trick to style element as perfect square.
content: "";
padding-bottom: 100%;
}

&:first-child {
margin-left: 0;
}

&:last-child {
margin-right: 0;
}
}
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 @@ -15,6 +15,7 @@ export { default as BlockFormatControls } from './block-format-controls';
export { default as BlockIcon } from './block-icon';
export { default as BlockNavigationDropdown } from './block-navigation/dropdown';
export { default as __experimentalBlockNavigationList } from './block-navigation/list';
export { default as __experimentalBlockPatternPicker } from './block-pattern-picker';
export { default as BlockVerticalAlignmentToolbar } from './block-vertical-alignment-toolbar';
export { default as ButtonBlockerAppender } from './button-block-appender';
export { default as ColorPalette } from './color-palette';
Expand Down
63 changes: 0 additions & 63 deletions packages/block-editor/src/components/inner-blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,69 +90,6 @@ const TEMPLATE = [ [ 'core/columns', {}, [

The previous example creates an InnerBlocks area containing two columns one with an image and the other with a paragraph.

### `__experimentalTemplateOptions`

* **Type:** `Array<Object>`

To present the user with a set of template choices for the inner blocks, you may provide an array of template options.

A template option is an object consisting of the following properties:

- `title` (`string`): A human-readable label which describes the template.
- `icon` (`WPElement|string`): An element or [Dashicon](https://developer.wordpress.org/resource/dashicons/) slug to show as a visual approximation of the template.
- `template` (`Array<Array>`): The template to apply when the option has been selected. See [`template` documentation](#template) for more information.

For the template placeholder selection to be displayed, you must render `InnerBlocks` with a `template` prop value of `null`. You may track this as state of your component, updating its value when receiving the selected template via `__experimentalOnSelectTemplateOption`.

```jsx
import { useState } from '@wordpress/element';

const TEMPLATE_OPTIONS = [
{
title: 'Two Columns',
icon: <svg />,
template: [
[ 'core/column', { width: 50 } ],
[ 'core/column', { width: 50 } ],
],
},
{
title: 'Three Columns',
icon: <svg />,
template: [
[ 'core/column', { width: 33.33 } ],
[ 'core/column', { width: 33.33 } ],
[ 'core/column', { width: 33.33 } ],
],
},
];

function edit() {
const [ template, setTemplate ] = useState( null );

return (
<InnerBlocks
template={ template }
__experimentalTemplateOptions={ TEMPLATE_OPTIONS }
__experimentalOnSelectTemplateOption={ setTemplate }
/>
);
}
```

### `__experimentalOnSelectTemplateOption`

* **Type:** `Function`

Callback function invoked when the user makes a template selection, used in combination with the `__experimentalTemplateOptions` props. The selected template is passed as the first and only argument. The value of the template may be `undefined` if the `__experimentalAllowTemplateOptionSkip` prop is passed to `InnerBlocks` and the user opts to skip template selection.

### `__experimentalAllowTemplateOptionSkip`

* **Type:** `Boolean`
* **Default:** `false`

Whether to include a button in the template selection placeholder to allow the user to skip selection, used in combination with the `__experimentalTemplateOptions` prop. When clicked, the `__experimentalOnSelectTemplateOption` callback will be passed an `undefined` value as the template.

### `templateInsertUpdatesSelection`
* **Type:** `Boolean`
* **Default:** `true`
Expand Down
25 changes: 6 additions & 19 deletions packages/block-editor/src/components/inner-blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import DefaultBlockAppender from './default-block-appender';
*/
import BlockList from '../block-list';
import { withBlockEditContext } from '../block-edit/context';
import TemplatePicker from './template-picker';

class InnerBlocks extends Component {
constructor() {
Expand Down Expand Up @@ -106,34 +105,22 @@ class InnerBlocks extends Component {
clientId,
hasOverlay,
renderAppender,
template,
__experimentalMoverDirection: moverDirection,
__experimentalTemplateOptions: templateOptions,
__experimentalOnSelectTemplateOption: onSelectTemplateOption,
__experimentalAllowTemplateOptionSkip: allowTemplateOptionSkip,
} = this.props;
const { templateInProcess } = this.state;

const isPlaceholder = template === null && !! templateOptions;

const classes = classnames( 'editor-inner-blocks block-editor-inner-blocks', {
'has-overlay': enableClickThrough && ( hasOverlay && ! isPlaceholder ),
'has-overlay': enableClickThrough && hasOverlay,
} );

return (
<div className={ classes }>
{ ! templateInProcess && (
isPlaceholder ?
<TemplatePicker
options={ templateOptions }
onSelect={ onSelectTemplateOption }
allowSkip={ allowTemplateOptionSkip }
/> :
<BlockList
rootClientId={ clientId }
renderAppender={ renderAppender }
__experimentalMoverDirection={ moverDirection }
/>
<BlockList
rootClientId={ clientId }
renderAppender={ renderAppender }
__experimentalMoverDirection={ moverDirection }
/>
) }
</div>
);
Expand Down
18 changes: 6 additions & 12 deletions packages/block-editor/src/components/inner-blocks/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,24 +106,18 @@ class InnerBlocks extends Component {
const {
clientId,
renderAppender,
template,
__experimentalTemplateOptions: templateOptions,
} = this.props;
const { templateInProcess } = this.state;

const isPlaceholder = template === null && !! templateOptions;

return (
<>
{ ! templateInProcess && (
isPlaceholder ?
null :
<BlockList
rootClientId={ clientId }
renderAppender={ renderAppender }
withFooter={ false }
isFullyBordered={ true }
/>
<BlockList
rootClientId={ clientId }
renderAppender={ renderAppender }
withFooter={ false }
isFullyBordered={ true }
/>
) }
</>
);
Expand Down
75 changes: 0 additions & 75 deletions packages/block-editor/src/components/inner-blocks/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,78 +17,3 @@
right: 0;
left: 0;
}

.block-editor-inner-blocks__template-picker {
.components-placeholder__instructions {
// Defer to vertical margins applied by template picker options.
margin-bottom: 0;
}

.components-placeholder__fieldset {
// Options will render horizontally, but the immediate children of the
// fieldset are the options and the skip button, oriented vertically.
flex-direction: column;
}

&.has-many-options .components-placeholder__fieldset {
// Allow options to occupy a greater amount of the available space if
// many options exist.
max-width: 90%;
}
}

.block-editor-inner-blocks__template-picker-options.block-editor-inner-blocks__template-picker-options {
display: flex;
justify-content: center;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
margin: $grid-size-small 0;
list-style: none;

> li {
list-style: none;
margin: $grid-size;
flex-shrink: 1;
max-width: 100px;
}

.block-editor-inner-blocks__template-picker-option {
padding: $grid-size;
}
}

.block-editor-inner-blocks__template-picker-option {
width: 100%;

&.components-icon-button {
// Override default styles inherited from <IconButton /> to center
// icon horizontally.
justify-content: center;

&.is-default {
background-color: $white;
}
}

&.components-button {
// Override default styles inherited from <Button /> to allow button
// to grow vertically.
height: auto;
padding: 0;
}

&::before {
// Use `padding-bottom` trick to style element as perfect square.
content: "";
padding-bottom: 100%;
}

&:first-child {
margin-left: 0;
}

&:last-child {
margin-right: 0;
}
}
Loading

0 comments on commit ae327b2

Please sign in to comment.