Fixed a possible bug with callbacks and map menus

also made it so clicking on a map control button with a sub menu open will close it
This commit is contained in:
Mitchell McCaffrey 2020-04-20 17:25:40 +10:00
parent 35523fd8ce
commit 0a1aed30b3
2 changed files with 42 additions and 13 deletions

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useRef } from "react";
import { Flex, Box, IconButton, Label } from "theme-ui"; import { Flex, Box, IconButton, Label } from "theme-ui";
import AddMapButton from "./AddMapButton"; import AddMapButton from "./AddMapButton";
@ -135,6 +135,9 @@ function MapControls({
function handleToolClick(event, tool) { function handleToolClick(event, tool) {
if (tool !== selectedTool) { if (tool !== selectedTool) {
onToolChange(tool); onToolChange(tool);
} else if (currentSubmenu) {
setCurrentSubmenu(null);
setCurrentSubmenuOptions({});
} else if (subMenus[tool]) { } else if (subMenus[tool]) {
const toolRect = event.target.getBoundingClientRect(); const toolRect = event.target.getBoundingClientRect();
setCurrentSubmenu(tool); setCurrentSubmenu(tool);
@ -143,6 +146,8 @@ function MapControls({
left: `${toolRect.left - 16}px`, left: `${toolRect.left - 16}px`,
top: `${toolRect.bottom - toolRect.height / 2}px`, top: `${toolRect.bottom - toolRect.height / 2}px`,
style: { transform: "translate(-100%, -50%)" }, style: { transform: "translate(-100%, -50%)" },
// Exclude this node from the sub menus auto close
excludeNode: event.target,
}); });
} }
} }
@ -161,6 +166,9 @@ function MapControls({
sx={{ height: "2px", width: "24px", borderRadius: "2px", opacity: 0.5 }} sx={{ height: "2px", width: "24px", borderRadius: "2px", opacity: 0.5 }}
></Box> ></Box>
); );
const expanedMenuRef = useRef();
return ( return (
<> <>
<Flex <Flex
@ -195,6 +203,7 @@ function MapControls({
borderRadius: "4px", borderRadius: "4px",
}} }}
p={2} p={2}
ref={expanedMenuRef}
> >
<AddMapButton onMapChange={onMapChange} /> <AddMapButton onMapChange={onMapChange} />
{divider} {divider}

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect, useState } from "react";
import Modal from "react-modal"; import Modal from "react-modal";
import { useThemeUI } from "theme-ui"; import { useThemeUI } from "theme-ui";
@ -13,19 +13,29 @@ function MapMenu({
right, right,
children, children,
style, style,
// A node to exclude from the pointer event for closing
excludeNode,
}) { }) {
function handleModalContent(node) { // Save modal node in state to ensure that the pointer listeners
if (node) { // are removed if the open state changed not from the onRequestClose
// Close modal if interacting with any other element // callback
function handlePointerDown(event) { const [modalContentNode, setModalContentNode] = useState(null);
const path = event.composedPath();
if (!path.includes(node)) {
onRequestClose();
document.body.removeEventListener("pointerdown", handlePointerDown);
}
}
document.body.addEventListener("pointerdown", handlePointerDown);
useEffect(() => {
// Close modal if interacting with any other element
function handlePointerDown(event) {
const path = event.composedPath();
if (
!path.includes(modalContentNode) &&
!(excludeNode && path.includes(excludeNode))
) {
onRequestClose();
document.body.removeEventListener("pointerdown", handlePointerDown);
}
}
if (modalContentNode) {
document.body.addEventListener("pointerdown", handlePointerDown);
// Check for wheel event to close modal as well // Check for wheel event to close modal as well
document.body.addEventListener( document.body.addEventListener(
"wheel", "wheel",
@ -35,6 +45,15 @@ function MapMenu({
{ once: true } { once: true }
); );
} }
return () => {
if (modalContentNode) {
document.body.removeEventListener("pointerdown", handlePointerDown);
}
};
}, [modalContentNode, excludeNode, onRequestClose]);
function handleModalContent(node) {
setModalContentNode(node);
onModalContent(node); onModalContent(node);
} }
@ -72,6 +91,7 @@ MapMenu.defaultProps = {
right: "initial", right: "initial",
bottom: "initial", bottom: "initial",
style: {}, style: {},
excludeNode: null,
}; };
export default MapMenu; export default MapMenu;