Fix tile drag cancel with modal open
This commit is contained in:
parent
63f77059f1
commit
a8c355f251
@ -6,6 +6,7 @@ import {
|
|||||||
DragOverlay,
|
DragOverlay,
|
||||||
DndContext,
|
DndContext,
|
||||||
PointerSensor,
|
PointerSensor,
|
||||||
|
KeyboardSensor,
|
||||||
useSensor,
|
useSensor,
|
||||||
useSensors,
|
useSensors,
|
||||||
} from "@dnd-kit/core";
|
} from "@dnd-kit/core";
|
||||||
@ -45,7 +46,8 @@ function TokenBar({ onMapTokensStateCreate }) {
|
|||||||
const pointerSensor = useSensor(PointerSensor, {
|
const pointerSensor = useSensor(PointerSensor, {
|
||||||
activationConstraint: { distance: 5 },
|
activationConstraint: { distance: 5 },
|
||||||
});
|
});
|
||||||
const sensors = useSensors(pointerSensor);
|
const keyboardSensor = useSensor(KeyboardSensor);
|
||||||
|
const sensors = useSensors(pointerSensor, keyboardSensor);
|
||||||
|
|
||||||
function handleDragStart({ active }) {
|
function handleDragStart({ active }) {
|
||||||
setDragId(active.id);
|
setDragId(active.id);
|
||||||
@ -93,6 +95,10 @@ function TokenBar({ onMapTokensStateCreate }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleDragCancel() {
|
||||||
|
setDragId(null);
|
||||||
|
}
|
||||||
|
|
||||||
function renderToken(group, draggable = true) {
|
function renderToken(group, draggable = true) {
|
||||||
if (group.type === "item") {
|
if (group.type === "item") {
|
||||||
const token = tokensById[group.id];
|
const token = tokensById[group.id];
|
||||||
@ -132,6 +138,7 @@ function TokenBar({ onMapTokensStateCreate }) {
|
|||||||
<DndContext
|
<DndContext
|
||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
|
onDragCancel={handleDragCancel}
|
||||||
autoScroll={false}
|
autoScroll={false}
|
||||||
sensors={sensors}
|
sensors={sensors}
|
||||||
>
|
>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { useState, useContext } from "react";
|
import React, { useState, useContext } from "react";
|
||||||
import {
|
import {
|
||||||
DndContext,
|
DndContext,
|
||||||
MouseSensor,
|
PointerSensor,
|
||||||
TouchSensor,
|
KeyboardSensor,
|
||||||
useSensor,
|
useSensor,
|
||||||
useSensors,
|
useSensors,
|
||||||
closestCenter,
|
closestCenter,
|
||||||
@ -38,7 +38,13 @@ function rectIntersection(rects, point) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TileDragProvider({ onDragAdd, children }) {
|
export function TileDragProvider({
|
||||||
|
onDragAdd,
|
||||||
|
onDragStart,
|
||||||
|
onDragEnd,
|
||||||
|
onDragCancel,
|
||||||
|
children,
|
||||||
|
}) {
|
||||||
const {
|
const {
|
||||||
groups,
|
groups,
|
||||||
activeGroups,
|
activeGroups,
|
||||||
@ -50,29 +56,32 @@ export function TileDragProvider({ onDragAdd, children }) {
|
|||||||
filter,
|
filter,
|
||||||
} = useGroup();
|
} = useGroup();
|
||||||
|
|
||||||
const mouseSensor = useSensor(MouseSensor, {
|
const pointerSensor = useSensor(PointerSensor, {
|
||||||
activationConstraint: { delay: 250, tolerance: 5 },
|
|
||||||
});
|
|
||||||
const touchSensor = useSensor(TouchSensor, {
|
|
||||||
activationConstraint: { delay: 250, tolerance: 5 },
|
activationConstraint: { delay: 250, tolerance: 5 },
|
||||||
});
|
});
|
||||||
|
const keyboardSensor = useSensor(KeyboardSensor);
|
||||||
|
|
||||||
const sensors = useSensors(mouseSensor, touchSensor);
|
const sensors = useSensors(pointerSensor, keyboardSensor);
|
||||||
|
|
||||||
const [dragId, setDragId] = useState();
|
const [dragId, setDragId] = useState();
|
||||||
const [overId, setOverId] = useState();
|
const [overId, setOverId] = useState();
|
||||||
const [dragCursor, setDragCursor] = useState("pointer");
|
const [dragCursor, setDragCursor] = useState("pointer");
|
||||||
|
|
||||||
function handleDragStart({ active, over }) {
|
function handleDragStart(event) {
|
||||||
|
const { active, over } = event;
|
||||||
setDragId(active.id);
|
setDragId(active.id);
|
||||||
setOverId(over?.id);
|
setOverId(over?.id);
|
||||||
if (!selectedGroupIds.includes(active.id)) {
|
if (!selectedGroupIds.includes(active.id)) {
|
||||||
onGroupSelect(active.id);
|
onGroupSelect(active.id);
|
||||||
}
|
}
|
||||||
setDragCursor("grabbing");
|
setDragCursor("grabbing");
|
||||||
|
|
||||||
|
onDragStart && onDragStart(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDragOver({ over }) {
|
function handleDragOver(event) {
|
||||||
|
const { over } = event;
|
||||||
|
|
||||||
setOverId(over?.id);
|
setOverId(over?.id);
|
||||||
if (over) {
|
if (over) {
|
||||||
if (
|
if (
|
||||||
@ -88,56 +97,64 @@ export function TileDragProvider({ onDragAdd, children }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDragEnd({ active, over }) {
|
function handleDragEnd(event) {
|
||||||
|
const { active, over } = event;
|
||||||
|
|
||||||
setDragId();
|
setDragId();
|
||||||
setOverId();
|
setOverId();
|
||||||
setDragCursor("pointer");
|
setDragCursor("pointer");
|
||||||
if (!active || !over || active.id === over.id) {
|
if (active && over && active.id !== over.id) {
|
||||||
return;
|
let selectedIndices = selectedGroupIds.map((groupId) =>
|
||||||
|
activeGroups.findIndex((group) => group.id === groupId)
|
||||||
|
);
|
||||||
|
// Maintain current group sorting
|
||||||
|
selectedIndices = selectedIndices.sort((a, b) => a - b);
|
||||||
|
|
||||||
|
if (over.id.startsWith(GROUP_ID_PREFIX)) {
|
||||||
|
onGroupSelect();
|
||||||
|
// Handle tile group
|
||||||
|
const overId = over.id.slice(9);
|
||||||
|
if (overId !== active.id) {
|
||||||
|
const overGroupIndex = activeGroups.findIndex(
|
||||||
|
(group) => group.id === overId
|
||||||
|
);
|
||||||
|
onGroupsChange(
|
||||||
|
moveGroupsInto(activeGroups, overGroupIndex, selectedIndices),
|
||||||
|
openGroupId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (over.id === UNGROUP_ID) {
|
||||||
|
onGroupSelect();
|
||||||
|
// Handle tile ungroup
|
||||||
|
const newGroups = ungroup(groups, openGroupId, selectedIndices);
|
||||||
|
// Close group if it was removed
|
||||||
|
if (!newGroups.find((group) => group.id === openGroupId)) {
|
||||||
|
onGroupClose();
|
||||||
|
}
|
||||||
|
onGroupsChange(newGroups);
|
||||||
|
} 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
|
||||||
|
const overGroupIndex = activeGroups.findIndex(
|
||||||
|
(group) => group.id === over.id
|
||||||
|
);
|
||||||
|
onGroupsChange(
|
||||||
|
moveGroups(activeGroups, overGroupIndex, selectedIndices),
|
||||||
|
openGroupId
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let selectedIndices = selectedGroupIds.map((groupId) =>
|
onDragEnd && onDragEnd(event);
|
||||||
activeGroups.findIndex((group) => group.id === groupId)
|
}
|
||||||
);
|
|
||||||
// Maintain current group sorting
|
|
||||||
selectedIndices = selectedIndices.sort((a, b) => a - b);
|
|
||||||
|
|
||||||
if (over.id.startsWith(GROUP_ID_PREFIX)) {
|
function handleDragCancel(event) {
|
||||||
onGroupSelect();
|
setDragId();
|
||||||
// Handle tile group
|
setOverId();
|
||||||
const overId = over.id.slice(9);
|
setDragCursor("pointer");
|
||||||
if (overId === active.id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const overGroupIndex = activeGroups.findIndex(
|
onDragCancel && onDragCancel(event);
|
||||||
(group) => group.id === overId
|
|
||||||
);
|
|
||||||
onGroupsChange(
|
|
||||||
moveGroupsInto(activeGroups, overGroupIndex, selectedIndices),
|
|
||||||
openGroupId
|
|
||||||
);
|
|
||||||
} else if (over.id === UNGROUP_ID) {
|
|
||||||
onGroupSelect();
|
|
||||||
// Handle tile ungroup
|
|
||||||
const newGroups = ungroup(groups, openGroupId, selectedIndices);
|
|
||||||
// Close group if it was removed
|
|
||||||
if (!newGroups.find((group) => group.id === openGroupId)) {
|
|
||||||
onGroupClose();
|
|
||||||
}
|
|
||||||
onGroupsChange(newGroups);
|
|
||||||
} 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
|
|
||||||
const overGroupIndex = activeGroups.findIndex(
|
|
||||||
(group) => group.id === over.id
|
|
||||||
);
|
|
||||||
onGroupsChange(
|
|
||||||
moveGroups(activeGroups, overGroupIndex, selectedIndices),
|
|
||||||
openGroupId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function customCollisionDetection(rects, rect) {
|
function customCollisionDetection(rects, rect) {
|
||||||
@ -183,6 +200,7 @@ export function TileDragProvider({ onDragAdd, children }) {
|
|||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
onDragOver={handleDragOver}
|
onDragOver={handleDragOver}
|
||||||
|
onDragCancel={handleDragCancel}
|
||||||
sensors={sensors}
|
sensors={sensors}
|
||||||
collisionDetection={customCollisionDetection}
|
collisionDetection={customCollisionDetection}
|
||||||
>
|
>
|
||||||
|
@ -168,6 +168,8 @@ function SelectMapModal({
|
|||||||
|
|
||||||
const [editingMapId, setEditingMapId] = useState();
|
const [editingMapId, setEditingMapId] = useState();
|
||||||
|
|
||||||
|
const [isDraggingMap, setIsDraggingMap] = useState(false);
|
||||||
|
|
||||||
const [canAddDraggedMap, setCanAddDraggedMap] = useState(false);
|
const [canAddDraggedMap, setCanAddDraggedMap] = useState(false);
|
||||||
function handleGroupsSelect(groupIds) {
|
function handleGroupsSelect(groupIds) {
|
||||||
if (groupIds.length === 1) {
|
if (groupIds.length === 1) {
|
||||||
@ -197,6 +199,7 @@ function SelectMapModal({
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onRequestClose={handleClose}
|
onRequestClose={handleClose}
|
||||||
style={{ maxWidth: layout.modalSize, width: "calc(100% - 16px)" }}
|
style={{ maxWidth: layout.modalSize, width: "calc(100% - 16px)" }}
|
||||||
|
shouldCloseOnEsc={!isDraggingMap}
|
||||||
>
|
>
|
||||||
<ImageDrop onDrop={handleImagesUpload} dropText="Drop map to import">
|
<ImageDrop onDrop={handleImagesUpload} dropText="Drop map to import">
|
||||||
<input
|
<input
|
||||||
@ -229,7 +232,12 @@ function SelectMapModal({
|
|||||||
</Label>
|
</Label>
|
||||||
<TileActionBar onAdd={openImageDialog} addTitle="Import Map(s)" />
|
<TileActionBar onAdd={openImageDialog} addTitle="Import Map(s)" />
|
||||||
<Box sx={{ position: "relative" }}>
|
<Box sx={{ position: "relative" }}>
|
||||||
<TileDragProvider onDragAdd={canAddDraggedMap && handleDragAdd}>
|
<TileDragProvider
|
||||||
|
onDragAdd={canAddDraggedMap && handleDragAdd}
|
||||||
|
onDragStart={() => setIsDraggingMap(true)}
|
||||||
|
onDragEnd={() => setIsDraggingMap(false)}
|
||||||
|
onDragCancel={() => setIsDraggingMap(false)}
|
||||||
|
>
|
||||||
<TilesContainer>
|
<TilesContainer>
|
||||||
<MapTiles
|
<MapTiles
|
||||||
maps={maps}
|
maps={maps}
|
||||||
@ -238,7 +246,12 @@ function SelectMapModal({
|
|||||||
/>
|
/>
|
||||||
</TilesContainer>
|
</TilesContainer>
|
||||||
</TileDragProvider>
|
</TileDragProvider>
|
||||||
<TileDragProvider onDragAdd={canAddDraggedMap && handleDragAdd}>
|
<TileDragProvider
|
||||||
|
onDragAdd={canAddDraggedMap && handleDragAdd}
|
||||||
|
onDragStart={() => setIsDraggingMap(true)}
|
||||||
|
onDragEnd={() => setIsDraggingMap(false)}
|
||||||
|
onDragCancel={() => setIsDraggingMap(false)}
|
||||||
|
>
|
||||||
<TilesOverlay modalSize={modalSize}>
|
<TilesOverlay modalSize={modalSize}>
|
||||||
<MapTiles
|
<MapTiles
|
||||||
maps={maps}
|
maps={maps}
|
||||||
|
@ -139,6 +139,8 @@ function SelectTokensModal({ isOpen, onRequestClose, onMapTokensStateCreate }) {
|
|||||||
*/
|
*/
|
||||||
const [editingTokenId, setEditingTokenId] = useState();
|
const [editingTokenId, setEditingTokenId] = useState();
|
||||||
|
|
||||||
|
const [isDraggingToken, setIsDraggingToken] = useState(false);
|
||||||
|
|
||||||
const mapStageRef = useMapStage();
|
const mapStageRef = useMapStage();
|
||||||
function handleTokensAddToMap(groupIds, rect) {
|
function handleTokensAddToMap(groupIds, rect) {
|
||||||
let clientPosition = new Vector2(
|
let clientPosition = new Vector2(
|
||||||
@ -198,6 +200,7 @@ function SelectTokensModal({ isOpen, onRequestClose, onMapTokensStateCreate }) {
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onRequestClose={onRequestClose}
|
onRequestClose={onRequestClose}
|
||||||
style={{ maxWidth: layout.modalSize, width: "calc(100% - 16px)" }}
|
style={{ maxWidth: layout.modalSize, width: "calc(100% - 16px)" }}
|
||||||
|
shouldCloseOnEsc={!isDraggingToken}
|
||||||
>
|
>
|
||||||
<ImageDrop onDrop={handleImagesUpload} dropText="Drop token to import">
|
<ImageDrop onDrop={handleImagesUpload} dropText="Drop token to import">
|
||||||
<input
|
<input
|
||||||
@ -232,7 +235,12 @@ function SelectTokensModal({ isOpen, onRequestClose, onMapTokensStateCreate }) {
|
|||||||
addTitle="Import Token(s)"
|
addTitle="Import Token(s)"
|
||||||
/>
|
/>
|
||||||
<Box sx={{ position: "relative" }}>
|
<Box sx={{ position: "relative" }}>
|
||||||
<TileDragProvider onDragAdd={handleTokensAddToMap}>
|
<TileDragProvider
|
||||||
|
onDragAdd={handleTokensAddToMap}
|
||||||
|
onDragStart={() => setIsDraggingToken(true)}
|
||||||
|
onDragEnd={() => setIsDraggingToken(false)}
|
||||||
|
onDragCancel={() => setIsDraggingToken(false)}
|
||||||
|
>
|
||||||
<TilesContainer>
|
<TilesContainer>
|
||||||
<TokenTiles
|
<TokenTiles
|
||||||
tokens={tokens}
|
tokens={tokens}
|
||||||
@ -240,7 +248,12 @@ function SelectTokensModal({ isOpen, onRequestClose, onMapTokensStateCreate }) {
|
|||||||
/>
|
/>
|
||||||
</TilesContainer>
|
</TilesContainer>
|
||||||
</TileDragProvider>
|
</TileDragProvider>
|
||||||
<TileDragProvider onDragAdd={handleTokensAddToMap}>
|
<TileDragProvider
|
||||||
|
onDragAdd={handleTokensAddToMap}
|
||||||
|
onDragStart={() => setIsDraggingToken(true)}
|
||||||
|
onDragEnd={() => setIsDraggingToken(false)}
|
||||||
|
onDragCancel={() => setIsDraggingToken(false)}
|
||||||
|
>
|
||||||
<TilesOverlay modalSize={modalSize}>
|
<TilesOverlay modalSize={modalSize}>
|
||||||
<TokenTiles
|
<TokenTiles
|
||||||
tokens={tokens}
|
tokens={tokens}
|
||||||
|
Loading…
Reference in New Issue
Block a user