Clone the template to render the contents on every drawer open

This commit is contained in:
Sam Seay 2024-09-06 14:00:52 +08:00
parent f930a2af5b
commit fadebe8302
No known key found for this signature in database
GPG Key ID: 2223711A9151668A
5 changed files with 103 additions and 27 deletions

View File

@ -8,6 +8,7 @@ import lazyLoadScript, {
isScriptTagInDOM,
} from '@woocommerce/base-utils/lazy-load-script';
import {
ReactRootWithContainer,
getNavigationType,
translateJQueryEventToNative,
} from '@woocommerce/base-utils';
@ -32,15 +33,19 @@ interface dependencyData {
translations?: string;
}
interface State {
root: ReactRootWithContainer[] | undefined;
displayQuantityBadgeStyle: string;
priceAriaLabel: string;
}
interface Store {
state: {
displayQuantityBadgeStyle: string;
priceAriaLabel: string;
};
state: State;
callbacks: {
initialize: () => void;
toggleDrawerOpen: ( event: Event ) => void;
loadScripts: () => Promise< void >;
closeDrawer: () => void;
};
}
@ -100,23 +105,23 @@ const loadScripts = async () => {
}
};
const renderContents = async () => {
const renderContents = async ( state: State ) => {
const { renderMiniCartContents } = await import(
'./render-mini-cart-contents'
);
const container = document.querySelector< HTMLDivElement >(
const templateContainer = document.querySelector< HTMLDivElement >(
'.wc-block-mini-cart-interactivity__template-part'
);
if ( container ) {
container.style.display = 'block';
renderMiniCartContents( container );
if ( templateContainer ) {
state.root = renderMiniCartContents( templateContainer );
}
};
store< Store >( 'woocommerce/mini-cart-interactivity', {
const { state } = store< Store >( 'woocommerce/mini-cart-interactivity', {
state: {
root: undefined,
get displayQuantityBadgeStyle() {
const context = getContext< Context >();
return context.cartItemCount > 0 ? 'flex' : 'none';
@ -198,10 +203,21 @@ store< Store >( 'woocommerce/mini-cart-interactivity', {
context.drawerOpen = ! context.drawerOpen;
if ( context.drawerOpen ) {
await renderContents();
if ( state.root ) {
state.root.forEach( ( root ) => {
root.root.unmount();
} );
}
await renderContents( state );
}
},
closeDrawer: () => {
const context = getContext< Context >();
context.drawerOpen = false;
},
loadScripts: async () => {
const context = getContext< Context >();

View File

@ -0,0 +1,24 @@
/**
* External dependencies
*/
import { CartEventsProvider } from '@woocommerce/base-context';
/**
* Internal dependencies
*/
import '../../mini-cart/mini-cart-contents/inner-blocks/register-components';
type MiniCartContentsBlockProps = {
attributes: Record< string, unknown >;
children: JSX.Element | JSX.Element[];
};
export const MiniCartContentsBlock = (
props: MiniCartContentsBlockProps
): JSX.Element => {
const { children } = props;
console.log( 'MiniCartContentsBlock', children );
return <CartEventsProvider>{ children }</CartEventsProvider>;
};

View File

@ -7,22 +7,32 @@ import { getRegisteredBlockComponents } from '@woocommerce/blocks-registry';
* Internal dependencies
*/
import { renderParentBlock } from '../../atomic/utils';
import { MiniCartContentsBlock } from '../mini-cart/mini-cart-contents/block';
import { MiniCartContentsBlock } from './mini-cart-contents/block';
import { attributes as miniCartContentsAttributes } from '../mini-cart/mini-cart-contents/attributes';
import { getValidBlockAttributes } from '../../base/utils';
import '../mini-cart/mini-cart-contents/inner-blocks/register-components';
const generateUniqueId = () => {
return (
Date.now().toString() + Math.floor( Math.random() * 10000 ).toString()
);
};
// We load this async so that we don't have to load the mini-cart block.
export const renderMiniCartContents = ( contentsNode: Element ) => {
const container = contentsNode.querySelector(
'.wp-block-woocommerce-mini-cart-contents'
export const renderMiniCartContents = ( templateElement: HTMLDivElement ) => {
const clonedTemplateNode = templateElement.cloneNode(
true
) as HTMLDivElement;
const uniqueId = `mini-cart-template-${ generateUniqueId() }`;
( clonedTemplateNode as HTMLElement ).id = uniqueId;
templateElement.insertAdjacentElement(
'afterend',
clonedTemplateNode as HTMLDivElement
);
if ( ! container ) {
return;
}
renderParentBlock( {
const root = renderParentBlock( {
Block: MiniCartContentsBlock,
blockName: 'woocommerce/mini-cart-contents',
getProps: ( el: Element ) => {
@ -34,9 +44,14 @@ export const renderMiniCartContents = ( contentsNode: Element ) => {
),
};
},
selector: '.wp-block-woocommerce-mini-cart-contents',
// TODO we should get the template but not render into the same container.
selector: `#${ uniqueId } .wp-block-woocommerce-mini-cart-contents`,
blockMap: getRegisteredBlockComponents(
'woocommerce/mini-cart-contents'
),
} );
clonedTemplateNode.style.display = 'block';
return root;
};

View File

@ -470,9 +470,9 @@ class MiniCartInteractivity extends AbstractBlock {
protected function get_template_part_contents_container( $template_contents ) {
ob_start();
?>
<div class="wc-block-mini-cart-interactivity__template-part" style="display:none">
<?php echo wp_kses_post( $template_contents ); ?>
</div>
<div class="wc-block-mini-cart-interactivity__template-part" style="display:none">
<?php echo wp_kses_post( $template_contents ); ?>
</div>
<?php
return ob_get_clean();
}
@ -508,6 +508,7 @@ class MiniCartInteractivity extends AbstractBlock {
);
$interactivity_namespace = wp_json_encode( array( 'namespace' => $this->get_full_block_name() ), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP );
$close_button = Drawer::render_close_button( 'woocommerce/mini-cart-interactivity::callbacks.closeDrawer' );
ob_start();
?>
@ -522,7 +523,7 @@ class MiniCartInteractivity extends AbstractBlock {
echo Drawer::render(
array(
'is_initially_open' => false,
'children' => $this->get_template_part_contents_container( $template_part_contents ),
'children' => $close_button . $this->get_template_part_contents_container( $template_part_contents ),
// TODO - clean up this concept.
'is_open_context_property' => 'woocommerce/mini-cart-interactivity::context.drawerOpen',
'on_open' => 'woocommerce/mini-cart-interactivity::actions.renderMiniCart',

View File

@ -27,14 +27,15 @@ class Drawer {
'isOpenContextProperty' => $props['is_open_context_property'] ?? 'woocommerce/interactivity-drawer',
);
$button_aria_label = __( 'Close', 'woocommerce' );
ob_start();
?>
<div data-wc-body data-wc-init="actions.initialize" data-wc-interactive="<?php echo esc_attr( $namespace ); ?>" data-wc-context="<?php echo esc_attr( wp_json_encode( $context ) ); ?>" >
<div tab-index="0" data-wc-bind--class="state.slideClasses" class="wc-block-components-drawer__screen-overlay wc-block-components-drawer__screen-overlay--is-hidden" >
<div class="wc-block-components-drawer" role="dialog" tab-index="-1">
<div class="wc-block-components-drawer__content" role="document">
<!-- TODO: CloseButtonPortal -->
<div class="wc-block-components-drawer__content" role="document">
<?php echo $props['children']; ?>
</div>
</div>
@ -43,4 +44,23 @@ class Drawer {
<?php
return ob_get_clean();
}
/**
* Render the close button. Allows you to customize where it's rendered.
*
* @param string $on_close_action The action to perform when the close button is clicked.
*
* @return string
*/
public static function render_close_button( $on_close_action ) {
ob_start();
?>
<div class="wc-block-components-drawer__close-wrapper">
<button data-wc-on--click="<?php echo esc_attr( $on_close_action ); ?>" class="wc-block-components-button wp-element-button wc-block-components-drawer__close contained" aria-label="Close" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z"></path></svg>
</button>
</div>
<?php
return ob_get_clean();
}
}