initial commit
This commit is contained in:
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import deprecated from '@wordpress/deprecated';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { registeredBlockComponents } from './registered-block-components-init';
|
||||
|
||||
/**
|
||||
* Get all Registered Block Components.
|
||||
*
|
||||
* WooCommerce Blocks allows React Components to be used on the frontend of the store in place of
|
||||
* Blocks instead of just serving static content.
|
||||
*
|
||||
* This gets all registered Block Components so we know which Blocks map to which React Components.
|
||||
*
|
||||
* @param {string} context Current context (a named parent Block). If Block Components were only
|
||||
* registered under a certain context, those Components will be returned,
|
||||
* as well as any Components registered under all contexts.
|
||||
* @return {Object} List of React Components registered under the provided context.
|
||||
*/
|
||||
export function getRegisteredBlockComponents( context ) {
|
||||
const parentInnerBlocks =
|
||||
typeof registeredBlockComponents[ context ] === 'object' &&
|
||||
Object.keys( registeredBlockComponents[ context ] ).length > 0
|
||||
? registeredBlockComponents[ context ]
|
||||
: {};
|
||||
|
||||
return {
|
||||
...parentInnerBlocks,
|
||||
...registeredBlockComponents.any,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of getRegisteredBlockComponents kept for backwards compatibility.
|
||||
*
|
||||
* @param {string} main Name of the parent block to retrieve children of.
|
||||
* @return {Object} List of registered inner blocks.
|
||||
*/
|
||||
export function getRegisteredInnerBlocks( main ) {
|
||||
deprecated( 'getRegisteredInnerBlocks', {
|
||||
version: '2.8.0',
|
||||
alternative: 'getRegisteredBlockComponents',
|
||||
plugin: 'WooCommerce Blocks',
|
||||
} );
|
||||
return getRegisteredBlockComponents( main );
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
export * from './get-registered-block-components';
|
||||
export * from './register-block-component';
|
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import deprecated from '@wordpress/deprecated';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { registeredBlockComponents } from './registered-block-components-init';
|
||||
|
||||
/**
|
||||
* Register a Block Component.
|
||||
*
|
||||
* WooCommerce Blocks allows React Components to be used on the frontend of the store in place of
|
||||
* Blocks instead of just serving static content.
|
||||
*
|
||||
* Registering a Block Component allows you to define which React Component should be used in place
|
||||
* of a registered Block. The Component, when rendered, will be passed all Block Attributes.
|
||||
*
|
||||
* @param {Object} options Options to use when registering the block.
|
||||
* @param {Function} options.component React component that will be rendered, or the return value from React.lazy if
|
||||
* dynamically imported.
|
||||
* @param {string} options.blockName Name of the block that this component belongs to.
|
||||
* @param {string} [options.context] To make this component available only under a certain context
|
||||
* (named parent Block) define it here. If left blank, the
|
||||
* Component will be available for all contexts.
|
||||
*/
|
||||
export function registerBlockComponent( options ) {
|
||||
if ( ! options.context ) {
|
||||
options.context = 'any';
|
||||
}
|
||||
assertOption( options, 'context', 'string' );
|
||||
assertOption( options, 'blockName', 'string' );
|
||||
assertBlockComponent( options, 'component' );
|
||||
|
||||
const { context, blockName, component } = options;
|
||||
|
||||
if ( ! registeredBlockComponents[ context ] ) {
|
||||
registeredBlockComponents[ context ] = {};
|
||||
}
|
||||
|
||||
registeredBlockComponents[ context ][ blockName ] = component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that an option is a valid react element or lazy callback. Otherwise, throws an error.
|
||||
*
|
||||
* @throws Will throw an error if the type of the option doesn't match the expected type.
|
||||
* @param {Object} options Object containing the option to validate.
|
||||
* @param {string} optionName Name of the option to validate.
|
||||
*/
|
||||
const assertBlockComponent = ( options, optionName ) => {
|
||||
if ( options[ optionName ] ) {
|
||||
if ( typeof options[ optionName ] === 'function' ) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
options[ optionName ].$$typeof &&
|
||||
options[ optionName ].$$typeof === Symbol.for( 'react.lazy' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`Incorrect value for the ${ optionName } argument when registering a block component. Component must be a valid React Element or Lazy callback.`
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asserts that an option is of the given type. Otherwise, throws an error.
|
||||
*
|
||||
* @throws Will throw an error if the type of the option doesn't match the expected type.
|
||||
* @param {Object} options Object containing the option to validate.
|
||||
* @param {string} optionName Name of the option to validate.
|
||||
* @param {string} expectedType Type expected for the option.
|
||||
*/
|
||||
const assertOption = ( options, optionName, expectedType ) => {
|
||||
const actualType = typeof options[ optionName ];
|
||||
if ( actualType !== expectedType ) {
|
||||
throw new Error(
|
||||
`Incorrect value for the ${ optionName } argument when registering a block component. It was a ${ actualType }, but must be a ${ expectedType }.`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Alias of registerBlockComponent kept for backwards compatibility.
|
||||
*
|
||||
* @param {Object} options Options to use when registering the block.
|
||||
* @param {string} options.main Name of the parent block.
|
||||
* @param {string} options.blockName Name of the child block being registered.
|
||||
* @param {Function} options.component React component used to render the child block.
|
||||
*/
|
||||
export function registerInnerBlock( options ) {
|
||||
deprecated( 'registerInnerBlock', {
|
||||
version: '2.8.0',
|
||||
alternative: 'registerBlockComponent',
|
||||
plugin: 'WooCommerce Blocks',
|
||||
hint: '"main" has been replaced with "context" and is now optional.',
|
||||
} );
|
||||
assertOption( options, 'main', 'string' );
|
||||
registerBlockComponent( {
|
||||
...options,
|
||||
context: options.main,
|
||||
} );
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
const registeredBlockComponents = {};
|
||||
|
||||
export { registeredBlockComponents };
|
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
getRegisteredBlockComponents,
|
||||
registerBlockComponent,
|
||||
registerInnerBlock,
|
||||
getRegisteredInnerBlocks,
|
||||
} from '../index';
|
||||
|
||||
describe( 'blocks registry', () => {
|
||||
const context = '@woocommerce/all-products';
|
||||
const blockName = '@woocommerce-extension/price-level';
|
||||
const component = () => {
|
||||
return null;
|
||||
};
|
||||
|
||||
describe( 'registerBlockComponent', () => {
|
||||
const invokeTest = ( args ) => () => {
|
||||
return registerBlockComponent( args );
|
||||
};
|
||||
it( 'throws an error when registered block is missing `blockName`', () => {
|
||||
expect( invokeTest( { context, blockName: null } ) ).toThrowError(
|
||||
/blockName/
|
||||
);
|
||||
} );
|
||||
it( 'throws an error when registered block is missing `component`', () => {
|
||||
expect(
|
||||
invokeTest( { context, blockName, component: null } )
|
||||
).toThrowError( /component/ );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'getRegisteredBlockComponents', () => {
|
||||
it( 'gets an empty object when context has no inner blocks', () => {
|
||||
expect(
|
||||
getRegisteredBlockComponents( '@woocommerce/all-products' )
|
||||
).toEqual( {} );
|
||||
} );
|
||||
it( 'gets a block that was successfully registered', () => {
|
||||
registerBlockComponent( { context, blockName, component } );
|
||||
expect(
|
||||
getRegisteredBlockComponents( '@woocommerce/all-products' )
|
||||
).toEqual( { [ blockName ]: component } );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'registerInnerBlock (deprecated)', () => {
|
||||
const invokeTest = ( args ) => () => {
|
||||
registerInnerBlock( args );
|
||||
};
|
||||
|
||||
it( 'throws an error when registered block is missing `main`', () => {
|
||||
const options = { main: null };
|
||||
expect( invokeTest( options ) ).toThrowError( /main/ );
|
||||
expect( console ).toHaveWarned();
|
||||
} );
|
||||
it( 'throws an error when registered block is missing `blockName`', () => {
|
||||
const options = { main: context, blockName: null };
|
||||
expect( invokeTest( options ) ).toThrowError( /blockName/ );
|
||||
} );
|
||||
it( 'throws an error when registered block is missing `component`', () => {
|
||||
const options = { main: context, blockName, component: null };
|
||||
expect( invokeTest( options ) ).toThrowError( /component/ );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'getRegisteredInnerBlocks (deprecated)', () => {
|
||||
it( 'gets an empty object when parent has no inner blocks', () => {
|
||||
expect(
|
||||
getRegisteredInnerBlocks( '@woocommerce/test-parent' )
|
||||
).toEqual( {} );
|
||||
expect( console ).toHaveWarned();
|
||||
} );
|
||||
it( 'gets a block that was successfully registered', () => {
|
||||
registerBlockComponent( { context, blockName, component } );
|
||||
expect(
|
||||
getRegisteredInnerBlocks( '@woocommerce/all-products' )
|
||||
).toEqual( {
|
||||
[ blockName ]: component,
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
} );
|
Reference in New Issue
Block a user