From cb239918410900b0d3187974750518aedeb6183e Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Tue, 11 Jan 2022 20:43:40 +0530 Subject: [PATCH] Add ReusableContextMenu component Signed-off-by: Ajay Bura --- .../context-menu/ReusableContextMenu.jsx | 84 +++++++++++++++++++ src/util/common.js | 21 ++++- 2 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/app/atoms/context-menu/ReusableContextMenu.jsx diff --git a/src/app/atoms/context-menu/ReusableContextMenu.jsx b/src/app/atoms/context-menu/ReusableContextMenu.jsx new file mode 100644 index 0000000..f3a3c0d --- /dev/null +++ b/src/app/atoms/context-menu/ReusableContextMenu.jsx @@ -0,0 +1,84 @@ +import React, { useState, useEffect, useRef } from 'react'; + +import cons from '../../../client/state/cons'; +import navigation from '../../../client/state/navigation'; + +import ContextMenu from './ContextMenu'; + +let key = null; +function ReusableContextMenu() { + const [data, setData] = useState(null); + const openerRef = useRef(null); + + const closeMenu = () => { + key = null; + if (data) openerRef.current.click(); + }; + + useEffect(() => { + if (data) { + const { cords } = data; + openerRef.current.style.transform = `translate(${cords.x}px, ${cords.y}px)`; + openerRef.current.style.width = `${cords.width}px`; + openerRef.current.style.height = `${cords.height}px`; + openerRef.current.click(); + } + const handleContextMenuOpen = (placement, cords, render) => { + if (key) { + closeMenu(); + return; + } + setData({ placement, cords, render }); + }; + navigation.on(cons.events.navigation.REUSABLE_CONTEXT_MENU_OPENED, handleContextMenuOpen); + return () => { + navigation.removeListener( + cons.events.navigation.REUSABLE_CONTEXT_MENU_OPENED, + handleContextMenuOpen, + ); + }; + }, [data]); + + const handleAfterToggle = (isVisible) => { + if (isVisible) { + key = Math.random(); + return; + } + if (setData) setData(null); + + if (key === null) return; + const copyKey = key; + setTimeout(() => { + if (key === copyKey) key = null; + }, 200); + }; + + return ( + ( + + )} + /> + ); +} + +export default ReusableContextMenu; diff --git a/src/util/common.js b/src/util/common.js index c374583..9142420 100644 --- a/src/util/common.js +++ b/src/util/common.js @@ -21,11 +21,28 @@ export function isInSameDay(dt2, dt1) { ); } -export function getEventCords(ev) { - const boxInfo = ev.target.getBoundingClientRect(); +/** + * @param {Event} ev + * @param {string} [targetSelector] element selector for Element.matches([selector]) + */ +export function getEventCords(ev, targetSelector) { + let boxInfo; + + const path = ev.nativeEvent.composedPath(); + const target = targetSelector + ? path.find((element) => element.matches?.(targetSelector)) + : null; + if (target) { + boxInfo = target.getBoundingClientRect(); + } else { + boxInfo = ev.target.getBoundingClientRect(); + } + return { x: boxInfo.x, y: boxInfo.y, + width: boxInfo.width, + height: boxInfo.height, detail: ev.detail, }; }