Skip to content

Instantly share code, notes, and snippets.

@georgeh
Created September 18, 2018 20:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save georgeh/5a914ed92994010bf1164c07e26452b2 to your computer and use it in GitHub Desktop.
Save georgeh/5a914ed92994010bf1164c07e26452b2 to your computer and use it in GitHub Desktop.
/**
* External dependencies
*/
import { times, property, omit } from 'lodash';
import classnames from 'classnames';
import memoize from 'memize';
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { PanelBody, RangeControl } from '@wordpress/components';
import { Fragment } from '@wordpress/element';
import { createBlock } from '@wordpress/blocks';
import {
InspectorControls,
InnerBlocks,
} from '@wordpress/editor';
/**
* Allowed blocks constant is passed to InnerBlocks precisely as specified here.
* The contents of the array should never change.
* The array should contain the name of each block that is allowed.
* In columns block, the only block we allow is 'core/column'.
*
* @constant
* @type {string[]}
*/
const ALLOWED_BLOCKS = [ 'core/column' ];
/**
* Returns the layouts configuration for a given number of columns.
*
* @param {number} columns Number of columns.
*
* @return {Object[]} Columns layout configuration.
*/
const getColumnsTemplate = memoize( ( columns ) => {
return times( columns, () => [ 'core/column' ] );
} );
export const name = 'core/columns';
export const settings = {
title: sprintf(
/* translators: Block title modifier */
__( '%1$s (%2$s)' ),
__( 'Columns' ),
__( 'beta' )
),
icon: <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="none" d="M0 0h24v24H0V0z" /><g><path d="M21 4H3L2 5v14l1 1h18l1-1V5l-1-1zM8 18H4V6h4v12zm6 0h-4V6h4v12zm6 0h-4V6h4v12z" /></g></svg>,
category: 'layout',
attributes: {
columns: {
type: 'number',
default: 2,
},
},
description: __( 'Add a block that displays content in multiple columns, then add whatever content blocks you’d like.' ),
supports: {
align: [ 'wide', 'full' ],
},
deprecated: [
{
attributes: {
columns: {
type: 'number',
default: 2,
},
},
isEligible( attributes, innerBlocks ) {
return innerBlocks.some( property( [ 'attributes', 'layout' ] ) );
},
migrate( attributes, innerBlocks ) {
function withoutLayout( block ) {
return {
...block,
attributes: omit( block.attributes, [ 'layout' ] ),
};
}
const columns = innerBlocks.reduce( ( result, innerBlock ) => {
const { layout } = innerBlock.attributes;
let columnIndex, columnMatch;
if ( layout && ( columnMatch = layout.match( /^column-(\d+)$/ ) ) ) {
columnIndex = Number( columnMatch[ 1 ] ) - 1;
} else {
columnIndex = 0;
}
if ( ! result[ columnIndex ] ) {
result[ columnIndex ] = [];
}
result[ columnIndex ].push( withoutLayout( innerBlock ) );
return result;
}, [] );
const migratedInnerBlocks = columns.map( ( columnBlocks ) => (
createBlock( 'core/column', {}, columnBlocks )
) );
return [
attributes,
migratedInnerBlocks,
];
},
save( { attributes } ) {
const { columns } = attributes;
return (
<div className={ `has-${ columns }-columns` }>
<InnerBlocks.Content />
</div>
);
},
},
],
edit( { attributes, setAttributes, className } ) {
const { columns } = attributes;
const classes = classnames( className, `has-${ columns }-columns` );
return (
<Fragment>
<InspectorControls>
<PanelBody>
<RangeControl
label={ __( 'Columns' ) }
value={ columns }
onChange={ ( nextColumns ) => {
setAttributes( {
columns: nextColumns,
} );
} }
min={ 2 }
max={ 6 }
/>
</PanelBody>
</InspectorControls>
<div className={ classes }>
<InnerBlocks
template={ getColumnsTemplate( columns ) }
templateLock="all"
allowedBlocks={ ALLOWED_BLOCKS } />
</div>
</Fragment>
);
},
save( { attributes } ) {
const { columns } = attributes;
return (
<div className={ `has-${ columns }-columns` }>
<InnerBlocks.Content />
</div>
);
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment