From 32a6a17dd9200356142417e6c2b2fd3d40f5ab8e Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 14 May 2018 09:45:58 +0100 Subject: [PATCH] Blocks: Introduce block definitions and implementations --- blocks/api/registration.js | 16 ++++++++++++++-- blocks/store/actions.js | 14 ++++++++++++++ blocks/store/reducer.js | 23 +++++++++++++++++++++++ blocks/store/selectors.js | 33 +++++++++++++++++++++++++++++---- 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/blocks/api/registration.js b/blocks/api/registration.js index c2def36311ae5..1abaeb8140a56 100644 --- a/blocks/api/registration.js +++ b/blocks/api/registration.js @@ -3,7 +3,7 @@ /** * External dependencies */ -import { get, isFunction, some } from 'lodash'; +import { get, isFunction, some, pick, omit, mapValues } from 'lodash'; /** * WordPress dependencies @@ -137,7 +137,19 @@ export function registerBlockType( name, settings ) { settings.icon = 'block-default'; } - dispatch( 'core/blocks' ).addBlockTypes( settings ); + const blockTypeDefinition = omit( settings, [ 'transforms', 'edit', 'save', 'icon', 'getEditWrapperProps' ] ); + blockTypeDefinition.attributes = mapValues( + settings.attributes, + ( attribute ) => pick( attribute, [ 'type', 'default' ] ) + ); + const blockTypeImplementation = pick( settings, [ 'name', 'transforms', 'edit', 'save', 'icon', 'getEditWrapperProps' ] ); + blockTypeImplementation.attributes = mapValues( + settings.attributes, + ( attribute ) => omit( attribute, [ 'type', 'default' ] ) + ); + + dispatch( 'core/blocks' ).addBlockTypes( blockTypeDefinition ); + dispatch( 'core/blocks' ).implementBlockTypes( blockTypeImplementation ); return settings; } diff --git a/blocks/store/actions.js b/blocks/store/actions.js index a97ab4e1d52e3..c743f81d47623 100644 --- a/blocks/store/actions.js +++ b/blocks/store/actions.js @@ -17,6 +17,20 @@ export function addBlockTypes( blockTypes ) { }; } +/** + * Returns an action object used in signalling that block types have been added. + * + * @param {Array|Object} implementations Block types implementations. + * + * @return {Object} Action object. + */ +export function implementBlockTypes( implementations ) { + return { + type: 'IMPLEMENT_BLOCK_TYPES', + implementations: castArray( implementations ), + }; +} + /** * Returns an action object used to remove a registered block type. * diff --git a/blocks/store/reducer.js b/blocks/store/reducer.js index c1623ae38692d..32581a3fb2914 100644 --- a/blocks/store/reducer.js +++ b/blocks/store/reducer.js @@ -43,6 +43,28 @@ export function blockTypes( state = {}, action ) { return state; } +/** + * Reducer managing the block type implementations + * + * @param {Object} state Current state. + * @param {Object} action Dispatched action. + * + * @return {Object} Updated state. + */ +export function implementations( state = {}, action ) { + switch ( action.type ) { + case 'IMPLEMENT_BLOCK_TYPES': + return { + ...state, + ...keyBy( action.implementations, 'name' ), + }; + case 'REMOVE_BLOCK_TYPES': + return omit( state, action.names ); + } + + return state; +} + /** * Higher-order Reducer creating a reducer keeping track of given block name. * @@ -91,6 +113,7 @@ export function categories( state = DEFAULT_CATEGORIES, action ) { export default combineReducers( { blockTypes, + implementations, defaultBlockName, fallbackBlockName, categories, diff --git a/blocks/store/selectors.js b/blocks/store/selectors.js index a777f83d777df..903476144c38c 100644 --- a/blocks/store/selectors.js +++ b/blocks/store/selectors.js @@ -2,6 +2,7 @@ * External dependencies */ import createSelector from 'rememo'; +import { mapValues, compact } from 'lodash'; /** * Returns all the available block types. @@ -11,9 +12,10 @@ import createSelector from 'rememo'; * @return {Array} Block Types. */ export const getBlockTypes = createSelector( - ( state ) => Object.values( state.blockTypes ), + ( state ) => compact( Object.values( state.blockTypes ).map( ( { name } ) => getBlockType( state, name ) ) ), ( state ) => [ state.blockTypes, + state.implementations, ] ); @@ -25,9 +27,32 @@ export const getBlockTypes = createSelector( * * @return {Object?} Block Type. */ -export function getBlockType( state, name ) { - return state.blockTypes[ name ]; -} +export const getBlockType = createSelector( + ( state, name ) => { + const blockTypeDefinition = state.blockTypes[ name ]; + const blockTypeImplementation = state.implementations[ name ]; + + if ( ! blockTypeDefinition || ! blockTypeImplementation ) { + return null; + } + + return { + ...blockTypeDefinition, + ...blockTypeImplementation, + attributes: mapValues( blockTypeDefinition.attributes, ( attribute, key ) => { + const implementationAttribute = blockTypeImplementation.attributes ? blockTypeImplementation.attributes[ key ] : {}; + return { + ...attribute, + ...implementationAttribute, + }; + } ), + }; + }, + ( state ) => [ + state.blockTypes, + state.implementations, + ] +); /** * Returns all the available categories.