11import {
2+ CSSProperties ,
23 PropsWithChildren ,
34 ReactNode ,
45 createContext ,
56 useCallback ,
67 useContext ,
78 useEffect ,
9+ useRef ,
10+ useState ,
811} from 'react' ;
912import styles from './styles.module.scss' ;
1013import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' ;
@@ -41,6 +44,10 @@ export default function ContextMenu({
4144 status : ContextMenuStatus ;
4245 onClose : ( ) => void ;
4346} > ) {
47+ const menuRef = useRef < HTMLDivElement > ( null ) ;
48+ const [ menuWidth , setMenuWidth ] = useState ( 0 ) ;
49+ const [ menuHeight , setMenuHeight ] = useState ( 0 ) ;
50+
4451 useEffect ( ( ) => {
4552 const onDocumentClicked = ( ) => {
4653 onClose ( ) ;
@@ -52,15 +59,29 @@ export default function ContextMenu({
5259 } ;
5360 } , [ onClose ] ) ;
5461
62+ useEffect ( ( ) => {
63+ if ( menuRef . current ) {
64+ const { width, height } = menuRef . current . getBoundingClientRect ( ) ;
65+ setMenuWidth ( width ) ;
66+ setMenuHeight ( height ) ;
67+ }
68+ } , [ status . open ] ) ;
69+
70+ const viewportWidth = window . innerWidth || document . documentElement . clientWidth ;
71+ const viewportHeight = window . innerHeight || document . documentElement . clientHeight ;
72+
73+ const menuStyle : CSSProperties = {
74+ visibility : status . open ? 'visible' : 'hidden' ,
75+ top : Math . min ( status . y , viewportHeight - menuHeight - 10 ) ,
76+ left : Math . min ( status . x , viewportWidth - menuWidth - 10 ) ,
77+ } ;
78+
5579 return (
5680 < ContextMenuContext . Provider value = { { handleClose : onClose } } >
5781 < div
82+ ref = { menuRef }
5883 className = { styles . contextMenu }
59- style = { {
60- visibility : status . open ? 'visible' : 'hidden' ,
61- top : status . y ,
62- left : status . x ,
63- } }
84+ style = { menuStyle }
6485 onMouseDown = { ( e ) => e . stopPropagation ( ) }
6586 >
6687 < ul > { children } </ ul >
0 commit comments