Add ReusableContextMenu component
Signed-off-by: Ajay Bura <ajbura@gmail.com>
This commit is contained in:
parent
769d24d196
commit
cb23991841
2 changed files with 103 additions and 2 deletions
84
src/app/atoms/context-menu/ReusableContextMenu.jsx
Normal file
84
src/app/atoms/context-menu/ReusableContextMenu.jsx
Normal file
|
@ -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 (
|
||||
<ContextMenu
|
||||
afterToggle={handleAfterToggle}
|
||||
placement={data?.placement || 'right'}
|
||||
content={data?.render(closeMenu) ?? ''}
|
||||
render={(toggleMenu) => (
|
||||
<input
|
||||
ref={openerRef}
|
||||
onClick={toggleMenu}
|
||||
type="button"
|
||||
style={{
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
backgroundColor: 'transparent',
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
padding: 0,
|
||||
border: 'none',
|
||||
visibility: 'hidden',
|
||||
appearance: 'none',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReusableContextMenu;
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue