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 AddMapButton from "./AddMapButton";
@ -135,6 +135,9 @@ function MapControls({
function handleToolClick(event, tool) {
if (tool !== selectedTool) {
onToolChange(tool);
} else if (currentSubmenu) {
setCurrentSubmenu(null);
setCurrentSubmenuOptions({});
} else if (subMenus[tool]) {
const toolRect = event.target.getBoundingClientRect();
setCurrentSubmenu(tool);
@ -143,6 +146,8 @@ function MapControls({
left: `${toolRect.left - 16}px`,
top: `${toolRect.bottom - toolRect.height / 2}px`,
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 }}
></Box>
);
const expanedMenuRef = useRef();
return (
<>
<Flex
@ -195,6 +203,7 @@ function MapControls({
borderRadius: "4px",
}}
p={2}
ref={expanedMenuRef}
>
<AddMapButton onMapChange={onMapChange} />
{divider}

View File

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