Show the drawer contents.
This commit is contained in:
parent
a1f98466bb
commit
f930a2af5b
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue