Show the drawer contents.

This commit is contained in:
Sam Seay 2024-09-04 21:05:42 +08:00
parent a1f98466bb
commit f930a2af5b
No known key found for this signature in database
GPG Key ID: 2223711A9151668A
2 changed files with 8 additions and 254 deletions

View File

@ -41,7 +41,6 @@ interface Store {
initialize: () => void;
toggleDrawerOpen: ( event: Event ) => void;
loadScripts: () => Promise< void >;
renderMiniCart: () => Promise< void >;
};
}
@ -106,13 +105,12 @@ const renderContents = async () => {
'./render-mini-cart-contents'
);
const container = document.querySelector(
const container = document.querySelector< HTMLDivElement >(
'.wc-block-mini-cart-interactivity__template-part'
);
console.log( 'renderContents', container );
if ( container ) {
container.style.display = 'block';
renderMiniCartContents( container );
}
};
@ -212,12 +210,6 @@ store< Store >( 'woocommerce/mini-cart-interactivity', {
await loadScripts();
}
// Remove adding to cart event handler.
document.body.removeEventListener(
'wc-blocks_adding_to_cart',
loadScripts
);
document.body.addEventListener(
'wc-mini-cart-interactivity-close-drawer',
() => {
@ -225,6 +217,12 @@ store< Store >( 'woocommerce/mini-cart-interactivity', {
}
);
// Remove adding to cart event handler.
document.body.removeEventListener(
'wc-blocks_adding_to_cart',
loadScripts
);
removeJQueryAddedToCartEvent();
removeJQueryRemovedFromCartEvent();
removeJQueryAddingToCartEvent();

View File

@ -1,244 +0,0 @@
/**
* External dependencies
*/
import { renderParentBlock } from '@woocommerce/atomic-utils';
import Drawer from '@woocommerce/base-components/drawer';
import { useStoreCart } from '@woocommerce/base-context/hooks';
import {
getValidBlockAttributes,
translateJQueryEventToNative,
} from '@woocommerce/base-utils';
import { getRegisteredBlockComponents } from '@woocommerce/blocks-registry';
import { isCartResponseTotals, isNumber } from '@woocommerce/types';
import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
import clsx from 'clsx';
import type { ReactRootWithContainer } from '@woocommerce/base-utils';
/**
* Internal dependencies
*/
import type { BlockAttributes } from '../mini-cart/types';
import { MiniCartContentsBlock } from '../mini-cart/mini-cart-contents/block';
import './style.scss';
import {
blockName,
attributes as miniCartContentsAttributes,
} from '../mini-cart/mini-cart-contents/attributes';
type Props = BlockAttributes & { onClose: () => void };
function getScrollbarWidth() {
return window.innerWidth - document.documentElement.clientWidth;
}
export const MiniCartDrawer = ( attributes: Props ): JSX.Element => {
const {
isInitiallyOpen = false,
contents = '',
addToCartBehaviour = 'none',
onClose,
} = attributes;
const {
cartItemsCount: cartItemsCountFromApi,
cartIsLoading,
cartTotals: cartTotalsFromApi,
} = useStoreCart();
const cartIsLoadingForTheFirstTime = useRef( cartIsLoading );
useEffect( () => {
if ( cartIsLoadingForTheFirstTime.current && ! cartIsLoading ) {
cartIsLoadingForTheFirstTime.current = false;
}
}, [ cartIsLoading, cartIsLoadingForTheFirstTime ] );
useEffect( () => {
if (
! cartIsLoading &&
isCartResponseTotals( cartTotalsFromApi ) &&
isNumber( cartItemsCountFromApi )
) {
// Save server data to local storage, so we can re-fetch it faster
// on the next page load.
localStorage.setItem(
'wc-blocks_mini_cart_totals',
JSON.stringify( {
totals: cartTotalsFromApi,
itemsCount: cartItemsCountFromApi,
} )
);
}
} );
const [ isOpen, setIsOpen ] = useState< boolean >( isInitiallyOpen );
// We already rendered the HTML drawer placeholder, so we want to skip the
// slide in animation.
const [ skipSlideIn, setSkipSlideIn ] =
useState< boolean >( isInitiallyOpen );
const [ contentsNode, setContentsNode ] = useState< HTMLDivElement | null >(
null
);
// Hack to force re-render when elements are not rendered in expected order.
const [ observerState, setObserverState ] = useState< boolean >( false );
const contentsRef = useCallback(
( node ) => {
setContentsNode( node );
if ( node ) {
const mutationObserver = new MutationObserver(
( mutationsList ) => {
for ( const mutation of mutationsList ) {
if ( mutation.type === 'childList' ) {
// Check if a child matching the selector exists
const childElement = node.querySelector(
'.wc-block-components-drawer__close-wrapper'
);
if ( childElement ) {
// Hack to force re-render when elements are not rendered in expected order.
setObserverState( ! observerState );
}
}
}
}
);
mutationObserver.observe( node, {
childList: true,
subtree: true,
} );
}
},
[ observerState ]
);
const rootRef = useRef< ReactRootWithContainer[] | null >( null );
useEffect( () => {
const body = document.querySelector( 'body' );
if ( body ) {
const scrollBarWidth = getScrollbarWidth();
if ( isOpen ) {
Object.assign( body.style, {
overflow: 'hidden',
paddingRight: scrollBarWidth + 'px',
} );
} else {
Object.assign( body.style, { overflow: '', paddingRight: 0 } );
}
}
}, [ isOpen ] );
useEffect( () => {
if ( contentsNode instanceof Element ) {
const container = contentsNode.querySelector(
'.wp-block-woocommerce-mini-cart-contents'
);
if ( ! container ) {
return;
}
if ( isOpen ) {
const renderedBlock = renderParentBlock( {
Block: MiniCartContentsBlock,
blockName,
getProps: ( el: Element ) => {
return {
attributes: getValidBlockAttributes(
miniCartContentsAttributes,
/* eslint-disable @typescript-eslint/no-explicit-any */
( el instanceof HTMLElement
? el.dataset
: {} ) as any
),
};
},
selector: '.wp-block-woocommerce-mini-cart-contents',
blockMap: getRegisteredBlockComponents( blockName ),
} );
rootRef.current = renderedBlock;
}
}
return () => {
if ( contentsNode instanceof Element && isOpen ) {
const unmountingContainer = contentsNode?.querySelector(
'.wp-block-woocommerce-mini-cart-contents'
);
if ( unmountingContainer ) {
const foundRoot = rootRef?.current?.find(
( { container } ) => unmountingContainer === container
);
if ( typeof foundRoot?.root?.unmount === 'function' ) {
setTimeout( () => {
foundRoot.root.unmount();
} );
}
}
}
};
}, [ isOpen, contentsNode ] );
useEffect( () => {
const openDrawer = () => {
setSkipSlideIn( false );
setIsOpen( true );
};
const openMiniCart = () => {
if ( addToCartBehaviour === 'open_drawer' ) {
openDrawer();
}
};
document.body.addEventListener(
'wc-mini-cart-interactivity-open-drawer',
openDrawer
);
// Make it so we can read jQuery events triggered by WC Core elements.
const removeJQueryAddedToCartEvent = translateJQueryEventToNative(
'added_to_cart',
'wc-blocks_added_to_cart'
);
document.body.addEventListener(
'wc-blocks_added_to_cart',
openMiniCart
);
return () => {
removeJQueryAddedToCartEvent();
document.body.removeEventListener(
'wc-blocks_added_to_cart',
openMiniCart
);
};
}, [ addToCartBehaviour ] );
return (
// We only render the drawer in this component now. The button is controlled by Interactivity API.
<>
<Drawer
className={ clsx( 'wc-block-mini-cart__drawer', 'is-mobile', {
'is-loading': cartIsLoading,
} ) }
isOpen={ isOpen }
onClose={ () => {
onClose();
setIsOpen( false );
} }
slideIn={ ! skipSlideIn }
>
<div
className="wc-block-mini-cart-interactivity__template-part"
ref={ contentsRef }
dangerouslySetInnerHTML={ { __html: contents } }
></div>
</Drawer>
</>
);
};