Skip to content

Commit

Permalink
Add Columns template options, support InnerBlock templateOptions (#16129
Browse files Browse the repository at this point in the history
)
  • Loading branch information
aduth authored and youknowriad committed Jun 24, 2019
1 parent c3f65fb commit 855be79
Show file tree
Hide file tree
Showing 24 changed files with 433 additions and 80 deletions.
63 changes: 63 additions & 0 deletions packages/block-editor/src/components/inner-blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,69 @@ 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
24 changes: 19 additions & 5 deletions packages/block-editor/src/components/inner-blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ 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 All @@ -48,6 +49,7 @@ class InnerBlocks extends Component {
if ( innerBlocks.length === 0 || this.getTemplateLock() === 'all' ) {
this.synchronizeBlocksWithTemplate();
}

if ( this.state.templateInProcess ) {
this.setState( {
templateInProcess: false,
Expand Down Expand Up @@ -107,20 +109,32 @@ class InnerBlocks extends Component {
clientId,
hasOverlay,
renderAppender,
template,
__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': hasOverlay,
'has-overlay': hasOverlay && ! isPlaceholder,
} );

return (
<div className={ classes }>
{ ! templateInProcess && (
<BlockList
rootClientId={ clientId }
renderAppender={ renderAppender }
/>
isPlaceholder ?
<TemplatePicker
options={ templateOptions }
onSelect={ onSelectTemplateOption }
allowSkip={ allowTemplateOptionSkip }
/> :
<BlockList
rootClientId={ clientId }
renderAppender={ renderAppender }
/>
) }
</div>
);
Expand Down
71 changes: 71 additions & 0 deletions packages/block-editor/src/components/inner-blocks/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,74 @@
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;
flex-direction: row;
flex-wrap: nowrap;
width: 100%;
margin: $grid-size-large 0;
list-style: none;

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

.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;
}
}
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 InnerBlocksTemplatePicker( {
options,
onSelect,
allowSkip,
} ) {
const classes = classnames( 'block-editor-inner-blocks__template-picker', {
'has-many-options': options.length > 4,
} );

const instructions = allowSkip ?
__( 'Select a layout to start with, or make one yourself.' ) :
__( 'Select a layout to start with.' );

return (
<Placeholder
icon="layout"
label={ __( 'Choose Layout' ) }
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-inner-blocks__template-picker-options" role="list">
{ options.map( ( templateOption, index ) => (
<li key={ index }>
<IconButton
isLarge
icon={ templateOption.icon }
onClick={ () => onSelect( templateOption.template ) }
className="block-editor-inner-blocks__template-picker-option"
label={ templateOption.title }
/>
</li>
) ) }
</ul>
{ /* eslint-enable jsx-a11y/no-redundant-roles */ }
{ allowSkip && (
<div className="block-editor-inner-blocks__template-picker-skip">
<Button
isLink
onClick={ () => onSelect( undefined ) }
>
{ __( 'Skip' ) }
</Button>
</div>
) }
</Placeholder>
);
}

export default InnerBlocksTemplatePicker;
4 changes: 0 additions & 4 deletions packages/block-library/src/columns/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
"name": "core/columns",
"category": "layout",
"attributes": {
"columns": {
"type": "number",
"default": 2
},
"verticalAlignment": {
"type": "string"
}
Expand Down
34 changes: 33 additions & 1 deletion packages/block-library/src/columns/deprecated.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* External dependencies
*/
import { omit } from 'lodash';
import classnames from 'classnames';

/**
* WordPress dependencies
*/
Expand Down Expand Up @@ -82,7 +88,7 @@ export default [
) );

return [
attributes,
omit( attributes, [ 'columns' ] ),
migratedInnerBlocks,
];
},
Expand All @@ -96,4 +102,30 @@ export default [
);
},
},
{
attributes: {
columns: {
type: 'number',
default: 2,
},
},
migrate( attributes, innerBlocks ) {
attributes = omit( attributes, [ 'columns' ] );

return [ attributes, innerBlocks ];
},
save( { attributes } ) {
const { verticalAlignment, columns } = attributes;

const wrapperClasses = classnames( `has-${ columns }-columns`, {
[ `are-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment,
} );

return (
<div className={ wrapperClasses }>
<InnerBlocks.Content />
</div>
);
},
},
];
Loading

0 comments on commit 855be79

Please sign in to comment.