import { useMemo , useEffect } from "react" ; import { createPortal } from "react-dom" ; import classnames from "classnames" ; import { useTypedSelector } from "../hooks" ; import * as Selectors from "../selectors" ; interface PortalProps { zIndex : number ; top : number ; left : number ; children : JSX . Element [ ] | JSX . Element ; } const Portal = ( props ) => { const node = useMemo ( ( ) => { const div = document . createElement ( "div" ) ; div . id = "webamp-context-menu" ; div . style . position = "absolute" ; div . style . top = "0" ; div . style . left = "0" ; div . style . zIndex = String ( props . zIndex + 1 ) ; return div ; } , [ props . zIndex ] ) ; useEffect ( ( ) => { document . body . appendChild ( node ) ; return ( ) => { document . body . removeChild ( node ) ; } ; } , [ node ] ) ; const style = { top : props . top , left : props . left , position : "absolute" , } ; return createPortal ( < div style = { style } > { props . children } < /div>, node); } ; export const Hr = ( ) => ( < li className = "hr" > < hr /> < /li>); interface ParentProps { label : string ; children : React . ReactNode ; } export const Parent = ( { children , label } ) => ( < li className = "parent" > < ul > { children } < /ul> { label } < /li>); interface LinkNodeProps { label : string ; href : string ; target ? : string ; } export const LinkNode = ( props ) => ( < li > < a { ... props } > { props . label } < /a> < /li>); interface NodeProps { label : string ; checked ? : boolean ; hotkey ? : string ; className ? : string ; onClick ? : ( ) => void ; } export const Node = ( props ) => { const { label , checked , className = "" , ... passThroughProps } = props ; return ( < li className = { classnames ( className , { checked } ) } { ... passThroughProps } > { label } < /li>); } ; interface ContextMenuProps { children : React . ReactNode ; offsetTop : number ; offsetLeft : number ; top ? : boolean ; bottom ? : boolean ; selected : boolean ; } export default function ContextMenu ( { children , offsetTop , offsetLeft , top , bottom , selected , } ) { const zIndex = useTypedSelector ( Selectors . getZIndex ) ; if ( ! selected ) { return null ; } return ( < Portal top = { offsetTop } left = { offsetLeft } zIndex = { zIndex } > < ul className = { classnames ( "context-menu" , { top , bottom } ) } > { children } < /ul> < /Portal>); }