/* global document */ import React, { useCallback, useEffect, useLayoutEffect, useRef, useState, } from "react"; import { findNodeHandle, ViewStyle } from "react-native"; import theme from "mazlo-theme"; import useScroll from "../../hooks/useScroll"; import { Button } from "../Button"; import { Icon } from "../Icon"; import { Portal as MenuPortal } from "../Portal"; import { Text } from "../Text"; import { View } from "../View"; import styles from "./styles"; type Offset = { x?: number; y?: number; }; export type Props = { alignHorizontal?: "left" | "right"; alignVertical?: "top" | "bottom"; headerComponent?: React.ReactNode; menuStyle?: ViewStyle; offset?: Offset; open?: boolean; dark?: boolean; decorated?: boolean; children: React.ReactNode; label: string; toggleIconComponent?: React.ReactNode; variant?: "blank" | "content"; }; const Menu = ({ alignHorizontal = "left", alignVertical = "bottom", headerComponent, menuStyle, open, offset, dark, decorated, children, label, toggleIconComponent, variant = "blank", }: Props) => { const node = useRef(); const menuNode = useRef(); const { x: offsetLeft = 0, y: offsetTop = 0 } = offset || {}; const [showOptions, setShowOptions] = useState(false); const menuOpen = open == null ? showOptions : open; const [layout, setLayout] = useState({ width: 0, height: 0, x: 0, y: 0 }); const { scrollX, scrollY } = useScroll(); useLayoutEffect(() => { const nodeHandle = findNodeHandle(node.current) as any; if (nodeHandle) { setLayout(nodeHandle.getBoundingClientRect().toJSON()); } }, [menuOpen, node.current, scrollX, scrollY]); const handleMouseDown = useCallback( (e) => { const currentNode = findNodeHandle(node.current) as any; const currentMenu = findNodeHandle(menuNode.current) as any; const portal = document.querySelector("#portal"); if ( currentNode && !currentNode.contains(e.target) && currentMenu && !currentMenu.contains(e.target) && portal && !portal.contains(e.target) ) { setShowOptions(false); } }, [node.current, menuNode.current] ); useEffect(() => { if (open == null) { if (menuOpen) { document.addEventListener("mousedown", handleMouseDown); } else { document.removeEventListener("mousedown", handleMouseDown); } return () => { document.removeEventListener("mousedown", handleMouseDown); }; } }, [open, menuOpen]); return ( {menuOpen && decorated && ( )} {menuOpen && ( {headerComponent} {children} )} ); }; export default Menu;