diff --git a/src/components/tile/SortableTile.js b/src/components/tile/SortableTile.js
index 1b2e15f..42e5c09 100644
--- a/src/components/tile/SortableTile.js
+++ b/src/components/tile/SortableTile.js
@@ -13,6 +13,7 @@ function SortableTile({
hidden,
children,
isDragging,
+ cursor,
}) {
const {
attributes,
@@ -29,7 +30,7 @@ function SortableTile({
});
const dragStyle = {
- cursor: "pointer",
+ cursor,
opacity: isDragging ? 0.25 : undefined,
};
@@ -92,4 +93,8 @@ function SortableTile({
);
}
+SortableTile.defaultProps = {
+ cursor: "pointer",
+};
+
export default SortableTile;
diff --git a/src/components/tile/SortableTiles.js b/src/components/tile/SortableTiles.js
index ad575af..d8ff37f 100644
--- a/src/components/tile/SortableTiles.js
+++ b/src/components/tile/SortableTiles.js
@@ -20,7 +20,7 @@ import {
import { useGroup } from "../../contexts/GroupContext";
function SortableTiles({ renderTile, subgroup }) {
- const { dragId, overId } = useTileDrag();
+ const { dragId, overId, dragCursor } = useTileDrag();
const {
groups: allGroups,
selectedGroupIds: allSelectedIds,
@@ -88,6 +88,7 @@ function SortableTiles({ renderTile, subgroup }) {
@@ -137,6 +138,7 @@ function SortableTiles({ renderTile, subgroup }) {
disableSorting={disableSorting}
hidden={group.id === openGroupId}
isDragging={isDragging}
+ cursor={dragCursor}
>
{renderSortableGroup(group, selectedGroups)}
diff --git a/src/components/tile/Tile.js b/src/components/tile/Tile.js
index 0904eb4..8ee58a5 100644
--- a/src/components/tile/Tile.js
+++ b/src/components/tile/Tile.js
@@ -24,7 +24,6 @@ function Tile({
borderRadius: "4px",
justifyContent: "center",
alignItems: "center",
- cursor: "pointer",
overflow: "hidden",
userSelect: "none",
}}
diff --git a/src/components/tile/TilesAddDroppable.js b/src/components/tile/TilesAddDroppable.js
new file mode 100644
index 0000000..7bd6cde
--- /dev/null
+++ b/src/components/tile/TilesAddDroppable.js
@@ -0,0 +1,54 @@
+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/TilesOverlay.js b/src/components/tile/TilesOverlay.js
index cb15c8a..e280013 100644
--- a/src/components/tile/TilesOverlay.js
+++ b/src/components/tile/TilesOverlay.js
@@ -1,14 +1,12 @@
import React, { useState } from "react";
-import { createPortal } from "react-dom";
import { Box, Close, Grid, useThemeUI } from "theme-ui";
import { useSpring, animated, config } from "react-spring";
import ReactResizeDetector from "react-resize-detector";
import SimpleBar from "simplebar-react";
import { useGroup } from "../../contexts/GroupContext";
-import { UNGROUP_ID_PREFIX } from "../../contexts/TileDragContext";
-import Droppable from "../drag/Droppable";
+import TilesUngroupDroppable from "./TilesUngroupDroppable";
import useResponsiveLayout from "../../hooks/useResponsiveLayout";
@@ -25,73 +23,47 @@ function TilesOverlay({ children }) {
config: config.gentle,
});
- const [containerSize, setContinerSize] = useState(0);
- function handleResize(width, height) {
+ const [containerSize, setContinerSize] = useState({ width: 0, height: 0 });
+ function handleContainerResize(width, height) {
const size = Math.min(width, height) - 16;
- setContinerSize(size);
+ setContinerSize({ width: size, height: size });
}
- function renderUngroupBoxes() {
- return createPortal(
-
-
-
-
-
-
,
- document.body
- );
+ const [overlaySize, setOverlaySize] = useState({ width: 0, height: 0 });
+ function handleOverlayResize(width, height) {
+ setOverlaySize({ width, height });
}
return (
<>
- {openGroupId && renderUngroupBoxes()}
{openGroupId && (
-
)}
-
+ {openGroupId && (
+
+
+
+ )}
+
+
+
+
+
+ ,
+ document.body
+ );
+}
+
+export default TilesUngroupDroppable;
diff --git a/src/components/token/SelectTokensButton.js b/src/components/token/SelectTokensButton.js
index 2792b02..503abd4 100644
--- a/src/components/token/SelectTokensButton.js
+++ b/src/components/token/SelectTokensButton.js
@@ -5,7 +5,7 @@ import SelectTokensIcon from "../../icons/SelectTokensIcon";
import SelectTokensModal from "../../modals/SelectTokensModal";
-function SelectTokensButton() {
+function SelectTokensButton({ onMapTokenStateCreate }) {
const [isModalOpen, setIsModalOpen] = useState(false);
function openModal() {
setIsModalOpen(true);
@@ -30,6 +30,7 @@ function SelectTokensButton() {
isOpen={isModalOpen}
onRequestClose={closeModal}
onDone={handleDone}
+ onMapTokenStateCreate={onMapTokenStateCreate}
/>
>
);
diff --git a/src/components/token/TokenBar.js b/src/components/token/TokenBar.js
index 3a75cdb..f00fea8 100644
--- a/src/components/token/TokenBar.js
+++ b/src/components/token/TokenBar.js
@@ -16,7 +16,10 @@ import { useTokenData } from "../../contexts/TokenDataContext";
import { useAuth } from "../../contexts/AuthContext";
import { useMapStage } from "../../contexts/MapStageContext";
-import { createTokenState } from "../../helpers/token";
+import {
+ createTokenState,
+ clientPositionToMapPosition,
+} from "../../helpers/token";
function TokenBar({ onMapTokenStateCreate }) {
const { userId } = useAuth();
@@ -41,38 +44,15 @@ function TokenBar({ onMapTokenStateCreate }) {
const mapStage = mapStageRef.current;
const dragOverlay = dragOverlayRef.current;
if (mapStage && dragOverlay) {
- const mapImage = mapStage.findOne("#mapImage");
- const map = document.querySelector(".map");
- const mapRect = map.getBoundingClientRect();
const dragRect = dragOverlay.getBoundingClientRect();
-
const dragPosition = {
x: dragRect.left + dragRect.width / 2,
y: dragRect.top + dragRect.height / 2,
};
-
- // Check map bounds
- if (dragPosition.x < mapRect.left || dragPosition.x > mapRect.right) {
- return;
- }
-
- // Convert relative to map rect
- const mapPosition = {
- x: dragPosition.x - mapRect.left,
- y: dragPosition.y - mapRect.top,
- };
-
- // Convert relative to map image
- const transform = mapImage.getAbsoluteTransform().copy().invert();
- const relativePosition = transform.point(mapPosition);
- const normalizedPosition = {
- x: relativePosition.x / mapImage.width(),
- y: relativePosition.y / mapImage.height(),
- };
-
+ const mapPosition = clientPositionToMapPosition(mapStage, dragPosition);
const token = tokensById[active.id];
- if (token) {
- const tokenState = createTokenState(token, normalizedPosition, userId);
+ if (token && mapPosition) {
+ const tokenState = createTokenState(token, mapPosition, userId);
onMapTokenStateCreate(tokenState);
}
}
@@ -143,7 +123,7 @@ function TokenBar({ onMapTokenStateCreate }) {
alignItems: "center",
}}
>
-
+
{createPortal(
group.id === over.id);
@@ -105,6 +119,7 @@ export function TileDragProvider({ children }) {
}
function customCollisionDetection(rects, rect) {
+ // Handle group rects
if (groupOpen) {
const ungroupRects = rects.filter(([id]) =>
id.startsWith(UNGROUP_ID_PREFIX)
@@ -115,12 +130,21 @@ export function TileDragProvider({ children }) {
}
}
+ // 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;
+ }
+
const otherRects = rects.filter(([id]) => id !== UNGROUP_ID_PREFIX);
return closestCenter(otherRects, rect);
}
- const value = { dragId, overId };
+ const value = { dragId, overId, dragCursor };
return (
mapRect.right)
+ ) {
+ return;
+ }
+
+ // Convert relative to map rect
+ const mapPosition = {
+ x: clientPosition.x - mapRect.left,
+ y: clientPosition.y - mapRect.top,
+ };
+
+ // Convert relative to map image
+ const transform = mapImage.getAbsoluteTransform().copy().invert();
+ const relativePosition = transform.point(mapPosition);
+ const normalizedPosition = {
+ x: relativePosition.x / mapImage.width(),
+ y: relativePosition.y / mapImage.height(),
+ };
+
+ return normalizedPosition;
+}
diff --git a/src/modals/SelectMapModal.js b/src/modals/SelectMapModal.js
index 7fbf618..65b66d3 100644
--- a/src/modals/SelectMapModal.js
+++ b/src/modals/SelectMapModal.js
@@ -1,6 +1,7 @@
import React, { useRef, useState } from "react";
import { Button, Flex, Label, Box } from "theme-ui";
import { useToasts } from "react-toast-notifications";
+import ReactResizeDetector from "react-resize-detector";
import EditMapModal from "./EditMapModal";
import ConfirmModal from "./ConfirmModal";
@@ -13,6 +14,7 @@ import MapTiles from "../components/map/MapTiles";
import TilesOverlay from "../components/tile/TilesOverlay";
import TilesContainer from "../components/tile/TilesContainer";
+import TilesAddDroppable from "../components/tile/TilesAddDroppable";
import { groupsFromIds, itemsFromGroups, findGroup } from "../helpers/group";
import { createMapFromFile } from "../helpers/map";
@@ -230,6 +232,11 @@ function SelectMapModal({
const layout = useResponsiveLayout();
+ const [modalSize, setModalSize] = useState({ width: 0, height: 0 });
+ function handleModalResize(width, height) {
+ setModalSize({ width, height });
+ }
+
return (
-
-
-
-
-
-
- setIsEditModalOpen(true)}
- onMapSelect={handleMapSelect}
- />
-
-
-
-
- setIsEditModalOpen(true)}
- onMapSelect={handleMapSelect}
- subgroup
- />
-
-
-
-
-
-
+
+
+
+
+
+
+ setIsEditModalOpen(true)}
+ onMapSelect={handleMapSelect}
+ />
+
+
+
+
+
+ setIsEditModalOpen(true)}
+ onMapSelect={handleMapSelect}
+ subgroup
+ />
+
+
+
+
+
+
+
{(isLoading || mapsLoading) && }
group.id === id && group.type === "group"
+ );
+ if (group) {
+ // Add all tokens of group
+ const items = getGroupItems(group);
+ for (let item of items) {
+ if (item.id in tokensById) {
+ onMapTokenStateCreate(
+ createTokenState(tokensById[item.id], position, userId)
+ );
+ position = Vector2.add(position, 0.01);
+ }
+ }
+ }
+ }
+ }
+ }
+
/**
* Shortcuts
*/
@@ -171,6 +227,11 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
const layout = useResponsiveLayout();
+ const [modalSize, setModalSize] = useState({ width: 0, height: 0 });
+ function handleModalResize(width, height) {
+ setModalSize({ width, height });
+ }
+
return (
-
-
-
-
-
-
- setIsEditModalOpen(true)}
- />
-
-
-
-
- setIsEditModalOpen(true)}
- subgroup
- />
-
-
-
-
-
-
-
+
+
+
+
+
+
+ setIsEditModalOpen(true)}
+ />
+
+
+
+
+
+ setIsEditModalOpen(true)}
+ subgroup
+ />
+
+
+
+
+
+
+
+
{(isLoading || tokensLoading) && }