import * as React from 'react'; import Box, { BoxProps } from '@mui/material/Box'; import Typography from '@mui/material/Typography'; import { debounce } from '@mui/material/utils'; const PointerContext = React.createContext void)>(undefined); export const withPointer = ( Component: T, options: { id: string; name: string }, ) => { function WithPointer(props: object) { const root = React.useRef(null); const handleMouseOver = React.useContext(PointerContext); return ( {/* @ts-ignore */} { event.stopPropagation(); if (handleMouseOver && root.current) { handleMouseOver({ id: options.id, target: root.current, name: options.name, }); } }} /> ); } return WithPointer as T; }; export type Data = { id: null | string; name: null | string; target: null | HTMLElement }; export default function PointerContainer({ onElementChange, ...props }: BoxProps & { onElementChange?: (data: Data) => void }) { const container = React.useRef(null); const [data, setData] = React.useState({ id: null, name: null, target: null, }); const handleMouseOver = React.useMemo( () => debounce((elementData: Data) => { setData(elementData); }, 200), [], ); React.useEffect(() => { if (onElementChange) { onElementChange(data); } }, [data, onElementChange]); return ( handleMouseOver({ id: null, name: null, target: null })} sx={{ position: 'relative', ...props.sx }} > {props.children} {container.current && data.target && ( { const containerRect = container.current.getBoundingClientRect(); const targetRect = data.target.getBoundingClientRect(); return { top: targetRect.top - containerRect.top, left: targetRect.left - containerRect.left, width: `${targetRect.width}px`, height: `${targetRect.height}px`, }; })(), }} > {data.name} )} ); }