8889841cPK +K[z_: :
test/index.jsnu [ /**
* Internal dependencies
*/
import {
getRegisteredBlocks,
registerCheckoutBlock,
innerBlockAreas,
} from '../index';
describe( 'checkout blocks registry', () => {
const component = () => {
return null;
};
describe( 'registerCheckoutBlock', () => {
const invokeTest = ( blockName, options ) => () => {
return registerCheckoutBlock( blockName, options );
};
it( 'throws an error when registered block is missing `blockName`', () => {
expect(
invokeTest( {
metadata: {
name: null,
parent: innerBlockAreas.CHECKOUT_FIELDS,
},
component,
} )
).toThrowError( /blockName/ );
expect(
invokeTest( {
metadata: {
name: '',
parent: innerBlockAreas.CHECKOUT_FIELDS,
},
component,
} )
).toThrowError( /blockName/ );
} );
it( 'throws an error when registered block is missing a valid parent', () => {
expect(
invokeTest( {
metadata: {
name: 'test/block-name',
parent: [],
},
component,
} )
).toThrowError( /parent/ );
expect(
invokeTest( {
metadata: {
name: 'test/block-name',
parent: 'invalid-parent',
},
component,
} )
).toThrowError( /parent/ );
expect(
invokeTest( {
metadata: {
name: 'test/block-name',
parent: [
'invalid-parent',
innerBlockAreas.CHECKOUT_FIELDS,
],
},
component,
} )
).not.toThrowError( /parent/ );
} );
it( 'throws an error when registered block is missing `component`', () => {
expect(
invokeTest( {
metadata: {
name: 'test/block-name',
parent: innerBlockAreas.CHECKOUT_FIELDS,
},
} )
).toThrowError( /component/ );
} );
} );
describe( 'getRegisteredBlocks', () => {
it( 'gets an empty array when checkout area has no registered blocks', () => {
expect(
getRegisteredBlocks( innerBlockAreas.CONTACT_INFORMATION )
).toEqual( [] );
} );
it( 'gets an empty array when the area is not defined', () => {
expect( getRegisteredBlocks( 'not-defined' ) ).toEqual( [] );
} );
} );
} );
PK +K[=4m m index.tsnu [ export * from './get-registered-blocks';
export * from './register-checkout-block';
export * from './types';
PK +K[K.U U register-checkout-block.tsnu [ /**
* External dependencies
*/
import { registerBlockComponent } from '@woocommerce/blocks-registry';
/**
* Internal dependencies
*/
import {
assertBlockName,
assertBlockParent,
assertOption,
assertBlockComponent,
} from './utils';
import { registeredBlocks } from './registered-blocks';
import type { CheckoutBlockOptions } from './types';
/**
* Main API for registering a new checkout block within areas.
*/
export const registerCheckoutBlock = (
options: CheckoutBlockOptions
): void => {
assertOption( options, 'metadata', 'object' );
assertBlockName( options.metadata.name );
assertBlockParent( options.metadata.parent );
assertBlockComponent( options, 'component' );
/**
* This ensures the frontend component for the checkout block is available.
*/
registerBlockComponent( {
blockName: options.metadata.name as string,
component: options.component,
} );
// Infer the `force` value from whether the block is locked or not. But
// allow overriding it on block registration.
const force =
typeof options.force === 'boolean'
? options.force
: Boolean( options.metadata?.attributes?.lock?.default?.remove );
/**
* Store block metadata for later lookup.
*/
registeredBlocks[ options.metadata.name ] = {
blockName: options.metadata.name,
metadata: options.metadata,
component: options.component,
force,
};
};
PK +K[3 registered-blocks.tsnu [ /**
* Internal dependencies
*/
import type { RegisteredBlocks } from './types';
const registeredBlocks: RegisteredBlocks = {};
export { registeredBlocks };
PK +K[Oyc
c
utils.tsnu [ /**
* External dependencies
*/
import { isObject } from '@woocommerce/types';
/**
* Internal dependencies
*/
import { hasInnerBlocks } from './get-registered-blocks';
/**
* 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.
*/
export const assertType = (
optionName: string,
option: unknown,
expectedType: unknown
): void => {
const actualType = typeof option;
if ( actualType !== expectedType ) {
throw new Error(
`Incorrect value for the ${ optionName } argument when registering a checkout block. It was a ${ actualType }, but must be a ${ expectedType }.`
);
}
};
/**
* Validate the block name.
*
* @throws Will throw an error if the block name is invalid.
*/
export const assertBlockName = ( blockName: string ): void => {
assertType( 'blockName', blockName, 'string' );
if ( ! blockName ) {
throw new Error(
`Value for the blockName argument must not be empty.`
);
}
};
/**
* Validate the block parent.
*
* @throws Will throw an error if the block name is invalid.
*/
export const assertBlockParent = ( blockParent: string | string[] ): void => {
if ( typeof blockParent !== 'string' && ! Array.isArray( blockParent ) ) {
throw new Error(
`Incorrect value for the parent argument when registering a checkout block. It was a ${ typeof blockParent }, but must be a string or array of strings.`
);
}
if ( typeof blockParent === 'string' && ! hasInnerBlocks( blockParent ) ) {
throw new Error(
`When registering a checkout block, the parent must be a valid inner block area.`
);
}
if (
Array.isArray( blockParent ) &&
! blockParent.some( ( parent ) => hasInnerBlocks( parent ) )
) {
throw new Error(
`When registering a checkout block, the parent must be a valid inner block area.`
);
}
};
/**
* 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.
*/
export const assertOption = (
options: unknown,
optionName: string,
expectedType: string
): void => {
if ( ! isObject( options ) ) {
return;
}
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 }.`
);
}
};
/**
* 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.
*/
export const assertBlockComponent = (
options: Record< string, unknown >,
optionName: string
): void => {
const optionValue = options[ optionName ];
if ( optionValue ) {
if ( typeof optionValue === 'function' ) {
return;
}
if (
isObject( optionValue ) &&
optionValue.$$typeof &&
optionValue.$$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.`
);
};
PK +K[nG G types.tsnu [ /**
* External dependencies
*/
import type { LazyExoticComponent } from '@wordpress/element';
import type { BlockConfiguration } from '@wordpress/blocks';
import type { RegisteredBlockComponent } from '@woocommerce/types';
export enum innerBlockAreas {
CHECKOUT = 'woocommerce/checkout',
CHECKOUT_FIELDS = 'woocommerce/checkout-fields-block',
CHECKOUT_TOTALS = 'woocommerce/checkout-totals-block',
CONTACT_INFORMATION = 'woocommerce/checkout-contact-information-block',
SHIPPING_ADDRESS = 'woocommerce/checkout-shipping-address-block',
BILLING_ADDRESS = 'woocommerce/checkout-billing-address-block',
SHIPPING_METHOD = 'woocommerce/checkout-shipping-method-block',
SHIPPING_METHODS = 'woocommerce/checkout-shipping-methods-block',
PICKUP_LOCATION = 'woocommerce/checkout-pickup-options-block',
PAYMENT_METHODS = 'woocommerce/checkout-payment-methods-block',
CART = 'woocommerce/cart',
EMPTY_CART = 'woocommerce/empty-cart-block',
FILLED_CART = 'woocommerce/filled-cart-block',
CART_ITEMS = 'woocommerce/cart-items-block',
CART_CROSS_SELLS = 'woocommerce/cart-cross-sells-block',
CART_TOTALS = 'woocommerce/cart-totals-block',
MINI_CART = 'woocommerce/mini-cart-contents',
EMPTY_MINI_CART = 'woocommerce/empty-mini-cart-contents-block',
FILLED_MINI_CART = 'woocommerce/filled-mini-cart-contents-block',
MINI_CART_ITEMS = 'woocommerce/mini-cart-items-block',
MINI_CART_FOOTER = 'woocommerce/mini-cart-footer-block',
CART_ORDER_SUMMARY = 'woocommerce/cart-order-summary-block',
CHECKOUT_ORDER_SUMMARY = 'woocommerce/checkout-order-summary-block',
}
interface CheckoutBlockOptionsMetadata extends Partial< BlockConfiguration > {
name: string;
parent: string[];
}
export type RegisteredBlock = {
blockName: string;
metadata: CheckoutBlockOptionsMetadata;
component: RegisteredBlockComponent;
force: boolean;
};
export type RegisteredBlocks = Record< string, RegisteredBlock >;
export type CheckoutBlockOptions = {
metadata: CheckoutBlockOptionsMetadata;
force?: boolean;
component:
| LazyExoticComponent< React.ComponentType< unknown > >
| ( () => JSX.Element | null )
| null;
};
PK +K[Y%%c c inserter.pngnu [ PNG
IHDR ,i GiCCPICC Profile (1KBa
\Ĕh2"DԖWz/T-EC5MPC4/0$(ier@["o6̫DRu<30%F Wwr֍8~ә^J 0Z6`؈'HvLrõvg%p9-
J~W,N823ۦpQTlTCB3BAyՀ?0ߝvfc0x ]f.pUEh}ҴփjYp\B˰eH^? VeXIfMM * i D ASCII ScreenshotW iTXtXML:com.adobe.xmp
496
796
Screenshot
z) IDATxyCJf&STr2Se~+?LEe,,K2 ! $A@$B1;,6 $KW/t7Suy{nKvJŚ5kq
lm۶t+ѣGwܑΞ=yϝ;7}]wcǎy(8DDDD;8p`1cFӳAϿ?twիW 81bDꫯz""""7.9~z<; |4hРɷڃ#
&,Xʕ+ G3䓼eҤIW^ۯX"/{O^z){I;wd͛77۰oӨ˖-˿/ɗֱݻwDV