diff --git a/package.json b/package.json index 602eebd..91aa658 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "dependencies": { "@babylonjs/core": "^4.2.0", "@babylonjs/loaders": "^4.2.0", - "@dnd-kit/core": "3.0.2", - "@dnd-kit/sortable": "^3.0.1", + "@dnd-kit/core": "^3.0.4", + "@dnd-kit/sortable": "^3.1.0", "@mitchemmc/dexie-export-import": "^1.0.1", "@msgpack/msgpack": "^2.4.1", "@sentry/react": "^6.2.2", diff --git a/src/components/tile/TilesAddDroppable.js b/src/components/tile/TilesAddDroppable.js deleted file mode 100644 index 7bd6cde..0000000 --- a/src/components/tile/TilesAddDroppable.js +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; -import { createPortal } from "react-dom"; - -import Droppable from "../drag/Droppable"; - -import { ADD_TO_MAP_ID_PREFIX } from "../../contexts/TileDragContext"; - -function TilesAddDroppable({ containerSize }) { - return createPortal( -
- - - - -
, - document.body - ); -} - -export default TilesAddDroppable; diff --git a/src/components/tile/TilesContainer.js b/src/components/tile/TilesContainer.js index 8703ee5..005c48d 100644 --- a/src/components/tile/TilesContainer.js +++ b/src/components/tile/TilesContainer.js @@ -3,9 +3,12 @@ import { Grid, useThemeUI } from "theme-ui"; import SimpleBar from "simplebar-react"; import { useGroup } from "../../contexts/GroupContext"; +import { ADD_TO_MAP_ID } from "../../contexts/TileDragContext"; import useResponsiveLayout from "../../hooks/useResponsiveLayout"; +import Droppable from "../drag/Droppable"; + function TilesContainer({ children }) { const { onGroupSelect } = useGroup(); @@ -28,10 +31,19 @@ function TilesContainer({ children }) { sx={{ borderRadius: "4px", overflow: "hidden", + position: "relative", }} gap={2} columns={`repeat(${layout.tileGridColumns}, 1fr)`} > + {children} diff --git a/src/components/tile/TilesOverlay.js b/src/components/tile/TilesOverlay.js index 40215bf..0c7a81c 100644 --- a/src/components/tile/TilesOverlay.js +++ b/src/components/tile/TilesOverlay.js @@ -5,8 +5,7 @@ import ReactResizeDetector from "react-resize-detector"; import SimpleBar from "simplebar-react"; import { useGroup } from "../../contexts/GroupContext"; - -import TilesUngroupDroppable from "./TilesUngroupDroppable"; +import { UNGROUP_ID, ADD_TO_MAP_ID } from "../../contexts/TileDragContext"; import useResponsiveLayout from "../../hooks/useResponsiveLayout"; @@ -16,7 +15,9 @@ import GroupNameModal from "../../modals/GroupNameModal"; import { renameGroup } from "../../helpers/group"; -function TilesOverlay({ children }) { +import Droppable from "../drag/Droppable"; + +function TilesOverlay({ modalSize, children }) { const { groups, openGroupId, @@ -41,11 +42,6 @@ function TilesOverlay({ children }) { setContinerSize({ width: size, height: size }); } - const [overlaySize, setOverlaySize] = useState({ width: 0, height: 0 }); - function handleOverlayResize(width, height) { - setOverlaySize({ width, height }); - } - const [isGroupNameModalOpen, setIsGroupNameModalOpen] = useState(false); function handleGroupNameChange(name) { onGroupsChange(renameGroup(groups, openGroupId, name)); @@ -57,28 +53,16 @@ function TilesOverlay({ children }) { return ( <> {openGroupId && ( - )} - {openGroupId && ( - - - - )} + + {children} diff --git a/src/components/tile/TilesUngroupDroppable.js b/src/components/tile/TilesUngroupDroppable.js deleted file mode 100644 index 3363991..0000000 --- a/src/components/tile/TilesUngroupDroppable.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from "react"; -import { createPortal } from "react-dom"; - -import Droppable from "../drag/Droppable"; - -import { UNGROUP_ID_PREFIX } from "../../contexts/TileDragContext"; - -function TilesUngroupDroppable({ outerContainerSize, innerContainerSize }) { - const width = (outerContainerSize.width - innerContainerSize.width) / 2; - const height = (outerContainerSize.height - innerContainerSize.height) / 2; - - return createPortal( -
- - - - -
, - document.body - ); -} - -export default TilesUngroupDroppable; diff --git a/src/contexts/TileDragContext.js b/src/contexts/TileDragContext.js index 95aa1a8..767a213 100644 --- a/src/contexts/TileDragContext.js +++ b/src/contexts/TileDragContext.js @@ -6,7 +6,6 @@ import { useSensor, useSensors, closestCenter, - rectIntersection, } from "@dnd-kit/core"; import { useGroup } from "./GroupContext"; @@ -18,8 +17,26 @@ const TileDragContext = React.createContext(); export const BASE_SORTABLE_ID = "__base__"; export const GROUP_SORTABLE_ID = "__group__"; export const GROUP_ID_PREFIX = "__group__"; -export const UNGROUP_ID_PREFIX = "__ungroup__"; -export const ADD_TO_MAP_ID_PREFIX = "__add__"; +export const UNGROUP_ID = "__ungroup__"; +export const ADD_TO_MAP_ID = "__add__"; + +// Custom rectIntersect that takes a point +function rectIntersection(rects, point) { + for (let rect of rects) { + const [id, bounds] = rect; + if ( + id && + bounds && + point.x > bounds.offsetLeft && + point.x < bounds.offsetLeft + bounds.width && + point.y > bounds.offsetTop && + point.y < bounds.offsetTop + bounds.height + ) { + return id; + } + } + return null; +} export function TileDragProvider({ onDragAdd, children }) { const { @@ -59,11 +76,11 @@ export function TileDragProvider({ onDragAdd, children }) { setOverId(over?.id); if (over) { if ( - over.id.startsWith(UNGROUP_ID_PREFIX) || + over.id.startsWith(UNGROUP_ID) || over.id.startsWith(GROUP_ID_PREFIX) ) { setDragCursor("alias"); - } else if (over.id.startsWith(ADD_TO_MAP_ID_PREFIX)) { + } else if (over.id.startsWith(ADD_TO_MAP_ID)) { setDragCursor(onDragAdd ? "copy" : "no-drop"); } else { setDragCursor("grabbing"); @@ -100,7 +117,7 @@ export function TileDragProvider({ onDragAdd, children }) { moveGroupsInto(activeGroups, overGroupIndex, selectedIndices), openGroupId ); - } else if (over.id.startsWith(UNGROUP_ID_PREFIX)) { + } else if (over.id === UNGROUP_ID) { onGroupSelect(); // Handle tile ungroup const newGroups = ungroup(groups, openGroupId, selectedIndices); @@ -109,7 +126,7 @@ export function TileDragProvider({ onDragAdd, children }) { onGroupClose(); } onGroupsChange(newGroups); - } else if (over.id.startsWith(ADD_TO_MAP_ID_PREFIX)) { + } else if (over.id === ADD_TO_MAP_ID) { onDragAdd && onDragAdd(selectedGroupIds, over.rect); } else if (!filter) { // Hanlde tile move only if we have no filter @@ -124,27 +141,39 @@ export function TileDragProvider({ onDragAdd, children }) { } function customCollisionDetection(rects, rect) { - // Handle group rects - if (openGroupId) { - const ungroupRects = rects.filter(([id]) => - id.startsWith(UNGROUP_ID_PREFIX) - ); - const intersectingGroupRect = rectIntersection(ungroupRects, rect); - if (intersectingGroupRect) { - return intersectingGroupRect; + // Calculate rect bottom taking into account any scroll offset + const rectBottom = rect.top + rect.bottom - rect.offsetTop; + const rectCenter = { + x: rect.left + rect.width / 2, + y: rectBottom - rect.height / 2, + }; + + // Find whether out rect center is outside our add to map rect + const addRect = rects.find(([id]) => id === ADD_TO_MAP_ID); + if (addRect) { + const intersectingAddRect = rectIntersection([addRect], rectCenter); + if (!intersectingAddRect) { + return ADD_TO_MAP_ID; } } - // Handle add to map rects - const addRects = rects.filter(([id]) => - id.startsWith(ADD_TO_MAP_ID_PREFIX) - ); - const intersectingAddRect = rectIntersection(addRects, rect); - if (intersectingAddRect) { - return intersectingAddRect; + // Find whether out rect center is outside our ungroup rect + if (openGroupId) { + const ungroupRect = rects.find(([id]) => id === UNGROUP_ID); + if (ungroupRect) { + const intersectingGroupRect = rectIntersection( + [ungroupRect], + rectCenter + ); + if (!intersectingGroupRect) { + return UNGROUP_ID; + } + } } - const otherRects = rects.filter(([id]) => id !== UNGROUP_ID_PREFIX); + const otherRects = rects.filter( + ([id]) => id !== ADD_TO_MAP_ID && id !== UNGROUP_ID + ); return closestCenter(otherRects, rect); } diff --git a/src/modals/SelectMapModal.js b/src/modals/SelectMapModal.js index dab60d0..c67e14d 100644 --- a/src/modals/SelectMapModal.js +++ b/src/modals/SelectMapModal.js @@ -17,7 +17,6 @@ import SelectMapSelectButton from "../components/map/SelectMapSelectButton"; import TilesOverlay from "../components/tile/TilesOverlay"; import TilesContainer from "../components/tile/TilesContainer"; -import TilesAddDroppable from "../components/tile/TilesAddDroppable"; import TileActionBar from "../components/tile/TileActionBar"; import { findGroup, getItemNames } from "../helpers/group"; @@ -231,7 +230,6 @@ function SelectMapModal({ - - - + - - - +