woocommerce/plugins/woocommerce-admin/client/customize-store/assembler-hub/hooks/use-popover-handler.ts

112 lines
2.5 KiB
TypeScript

/**
* External dependencies
*/
import { useState } from 'react';
/**
* Internal dependencies
*/
import { ENABLE_CLICK_CLASS } from './auto-block-preview-event-listener';
export enum PopoverStatus {
VISIBLE = 'VISIBLE',
HIDDEN = 'HIDDEN',
}
type VirtualElement = Pick< Element, 'getBoundingClientRect' >;
const generateGetBoundingClientRect = ( x = 0, y = 0 ) => {
return () => ( {
width: 0,
height: 0,
top: y,
right: x,
bottom: y,
left: x,
} );
};
let clickedClientId: string | null = null;
let hoveredClientId: string | null = null;
export const usePopoverHandler = () => {
const [ popoverStatus, setPopoverStatus ] = useState< PopoverStatus >(
PopoverStatus.HIDDEN
);
const defaultVirtualElement = {
getBoundingClientRect: generateGetBoundingClientRect(),
} as VirtualElement;
const [ virtualElement, setVirtualElement ] = useState< VirtualElement >(
defaultVirtualElement
);
const hidePopover = () => {
setPopoverStatus( PopoverStatus.HIDDEN );
clickedClientId = null;
hoveredClientId = null;
};
const updatePopoverPosition = ( {
event,
clickedBlockClientId,
hoveredBlockClientId,
}: {
event: MouseEvent;
clickedBlockClientId: string | null;
hoveredBlockClientId: string | null;
} ) => {
const iframe = window.document.querySelector(
'.woocommerce-customize-store-assembler > iframe[name="editor-canvas"]'
) as HTMLElement;
const target = event.target as HTMLElement;
// If the hover event is over elements with an ENABLE_CLICK_CLASS, hide the popover.
// This is because it's likely the "No Blocks" placeholder and we don't want the popover to show since its interactive.
if ( target.classList.contains( ENABLE_CLICK_CLASS ) ) {
hidePopover();
return;
}
clickedClientId =
clickedBlockClientId === null
? clickedClientId
: clickedBlockClientId;
hoveredClientId =
hoveredBlockClientId === null
? hoveredClientId
: hoveredBlockClientId;
if ( clickedClientId === hoveredClientId ) {
if ( popoverStatus === PopoverStatus.HIDDEN ) {
setPopoverStatus( PopoverStatus.VISIBLE );
}
const iframeRect = iframe.getBoundingClientRect();
const newElement = {
getBoundingClientRect: generateGetBoundingClientRect(
event.clientX + iframeRect.left,
event.clientY + iframeRect.top + 20
),
} as VirtualElement;
setVirtualElement( newElement );
return;
}
setPopoverStatus( PopoverStatus.HIDDEN );
clickedClientId = null;
};
return [
popoverStatus,
virtualElement,
updatePopoverPosition,
hidePopover,
setPopoverStatus,
] as const;
};