Refactor Render Parent Block (https://github.com/woocommerce/woocommerce-blocks/pull/4325)
This commit is contained in:
parent
44b2003ec5
commit
a815993b40
|
@ -1,6 +1,5 @@
|
|||
export * from './get-block-map.js';
|
||||
export * from './create-blocks-from-template.js';
|
||||
export * from './render-parent-block.js';
|
||||
export * from './render-inner-blocks.js';
|
||||
export * from './get-block-map';
|
||||
export * from './create-blocks-from-template';
|
||||
export * from './render-parent-block';
|
||||
export * from './block-styling.js';
|
||||
export * from './render-standalone-blocks.js';
|
||||
export * from './render-standalone-blocks';
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Suspense, cloneElement, isValidElement } from '@wordpress/element';
|
||||
import parse from 'html-react-parser';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { getBlockMap } from './get-block-map';
|
||||
|
||||
/**
|
||||
* Replaces saved block HTML markup with Inner Block Components.
|
||||
*
|
||||
* @param {Object} props Render props.
|
||||
* @param {Array} props.children Children/inner blocks to render.
|
||||
* @param {string} props.blockName Parent Block Name used to get the block map and for keys.
|
||||
* @param {number} [props.depth] Depth of inner blocks being rendered.
|
||||
*/
|
||||
export const renderInnerBlocks = ( {
|
||||
children,
|
||||
blockName: parentBlockName,
|
||||
depth = 1,
|
||||
} ) => {
|
||||
const blockMap = getBlockMap( parentBlockName );
|
||||
|
||||
return Array.from( children ).map( ( el, index ) => {
|
||||
const componentProps = {
|
||||
...el.dataset,
|
||||
key: `${ parentBlockName }_${ depth }_${ index }`,
|
||||
};
|
||||
|
||||
const componentChildren =
|
||||
el.children && el.children.length
|
||||
? renderInnerBlocks( {
|
||||
children: el.children,
|
||||
blockName: parentBlockName,
|
||||
depth: depth + 1,
|
||||
} )
|
||||
: null;
|
||||
|
||||
const LayoutComponent =
|
||||
componentProps.blockName && blockMap[ componentProps.blockName ]
|
||||
? blockMap[ componentProps.blockName ]
|
||||
: null;
|
||||
|
||||
if ( ! LayoutComponent ) {
|
||||
const element = parse( el.outerHTML );
|
||||
|
||||
if ( isValidElement( element ) ) {
|
||||
return componentChildren
|
||||
? cloneElement( element, componentProps, componentChildren )
|
||||
: cloneElement( element, componentProps );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense
|
||||
key={ `${ parentBlockName }_${ depth }_${ index }_suspense` }
|
||||
fallback={ <div className="wc-block-placeholder" /> }
|
||||
>
|
||||
<LayoutComponent { ...componentProps }>
|
||||
{ componentChildren }
|
||||
</LayoutComponent>
|
||||
</Suspense>
|
||||
);
|
||||
} );
|
||||
};
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { renderFrontend } from '@woocommerce/base-utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { renderInnerBlocks } from './render-inner-blocks';
|
||||
|
||||
/**
|
||||
* Renders a block component in the place of a specified set of selectors.
|
||||
*
|
||||
* @param {Object} props Render props.
|
||||
* @param {Function} props.Block React component to use as a replacement.
|
||||
* @param {string} props.selector CSS selector to match the elements to replace.
|
||||
* @param {string} [props.blockName] Optional Block Name. Used for inner block component mapping.
|
||||
* @param {Function} [props.getProps] Function to generate the props object for the block.
|
||||
*/
|
||||
export const renderParentBlock = ( {
|
||||
Block,
|
||||
selector,
|
||||
blockName = '',
|
||||
getProps = () => {},
|
||||
} ) => {
|
||||
const getPropsWithChildren = ( el, i ) => {
|
||||
const children =
|
||||
el.children && el.children.length
|
||||
? renderInnerBlocks( {
|
||||
blockName,
|
||||
children: el.children,
|
||||
} )
|
||||
: null;
|
||||
return { ...getProps( el, i ), children };
|
||||
};
|
||||
renderFrontend( {
|
||||
Block,
|
||||
selector,
|
||||
getProps: getPropsWithChildren,
|
||||
} );
|
||||
};
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { renderFrontend } from '@woocommerce/base-utils';
|
||||
import {
|
||||
Fragment,
|
||||
Suspense,
|
||||
cloneElement,
|
||||
isValidElement,
|
||||
} from '@wordpress/element';
|
||||
import parse from 'html-react-parser';
|
||||
|
||||
interface renderBlockProps {
|
||||
// Parent Block Name. Used for inner block component mapping.
|
||||
blockName: string;
|
||||
// Map of block names to block components for children.
|
||||
blockMap: Record< string, React.ReactNode >;
|
||||
// Wrapper for inner components.
|
||||
blockWrapper?: React.ReactNode;
|
||||
}
|
||||
|
||||
interface renderParentBlockProps extends renderBlockProps {
|
||||
// React component to use as a replacement.
|
||||
Block: React.FunctionComponent;
|
||||
// CSS selector to match the elements to replace.
|
||||
selector: string;
|
||||
// Function to generate the props object for the block.
|
||||
getProps: ( el: Element, i: number ) => Record< string, unknown >;
|
||||
}
|
||||
|
||||
interface renderInnerBlockProps extends renderBlockProps {
|
||||
children: HTMLCollection;
|
||||
depth?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces saved block HTML markup with Inner Block Components.
|
||||
*/
|
||||
const renderInnerBlocks = ( {
|
||||
blockName: parentBlockName,
|
||||
blockMap,
|
||||
blockWrapper,
|
||||
depth = 1,
|
||||
children,
|
||||
}: renderInnerBlockProps ): ( JSX.Element | null )[] | null => {
|
||||
return Array.from( children ).map( ( el: Element, index: number ) => {
|
||||
const { blockName = '', ...componentProps } = {
|
||||
key: `${ parentBlockName }_${ depth }_${ index }`,
|
||||
...( el instanceof HTMLElement ? el.dataset : {} ),
|
||||
};
|
||||
|
||||
const componentChildren =
|
||||
el.children && el.children.length
|
||||
? renderInnerBlocks( {
|
||||
children: el.children,
|
||||
blockName: parentBlockName,
|
||||
blockMap,
|
||||
depth: depth + 1,
|
||||
blockWrapper,
|
||||
} )
|
||||
: null;
|
||||
|
||||
const LayoutComponent =
|
||||
blockName && blockMap[ blockName ]
|
||||
? ( blockMap[ blockName ] as React.ElementType )
|
||||
: null;
|
||||
|
||||
if ( ! LayoutComponent ) {
|
||||
const element = parse( el.outerHTML );
|
||||
|
||||
if ( isValidElement( element ) ) {
|
||||
return componentChildren
|
||||
? cloneElement( element, componentProps, componentChildren )
|
||||
: cloneElement( element, componentProps );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const LayoutComponentWrapper = ( blockWrapper
|
||||
? blockWrapper
|
||||
: Fragment ) as React.ElementType;
|
||||
|
||||
return (
|
||||
<Suspense
|
||||
key={ `${ parentBlockName }_${ depth }_${ index }_suspense` }
|
||||
fallback={ <div className="wc-block-placeholder" /> }
|
||||
>
|
||||
<LayoutComponentWrapper>
|
||||
<LayoutComponent { ...componentProps }>
|
||||
{ componentChildren }
|
||||
</LayoutComponent>
|
||||
</LayoutComponentWrapper>
|
||||
</Suspense>
|
||||
);
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a block component in the place of a specified set of selectors.
|
||||
*/
|
||||
export const renderParentBlock = ( {
|
||||
Block,
|
||||
selector,
|
||||
blockName,
|
||||
getProps = () => ( {} ),
|
||||
blockMap,
|
||||
blockWrapper,
|
||||
}: renderParentBlockProps ): void => {
|
||||
const getPropsWithChildren = ( el: Element, i: number ) => {
|
||||
const children =
|
||||
el.children && el.children.length
|
||||
? renderInnerBlocks( {
|
||||
blockName,
|
||||
blockMap,
|
||||
children: el.children,
|
||||
blockWrapper,
|
||||
} )
|
||||
: null;
|
||||
return { ...getProps( el, i ), children };
|
||||
};
|
||||
renderFrontend( {
|
||||
Block,
|
||||
selector,
|
||||
getProps: getPropsWithChildren,
|
||||
} );
|
||||
};
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
import { getValidBlockAttributes } from '@woocommerce/base-utils';
|
||||
import {
|
||||
getBlockMap,
|
||||
renderParentBlock,
|
||||
renderStandaloneBlocks,
|
||||
} from '@woocommerce/atomic-utils';
|
||||
|
@ -25,6 +26,7 @@ renderParentBlock( {
|
|||
blockName: BLOCK_NAME,
|
||||
selector: '.wp-block-woocommerce-single-product',
|
||||
getProps,
|
||||
blockMap: getBlockMap( BLOCK_NAME ),
|
||||
} );
|
||||
|
||||
renderStandaloneBlocks();
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
// eslint-disable-next-line camelcase
|
||||
declare let __webpack_public_path__: string;
|
Loading…
Reference in New Issue