Action pane use Gesture

This commit is contained in:
Jeremie Pardou-Piquemal 2020-12-05 17:59:06 +01:00 committed by Jérémie Pardou-Piquemal
parent d6926dbca0
commit 59e802fc14
3 changed files with 48 additions and 105 deletions

View file

@ -10,6 +10,8 @@ import { useItems } from "./Items";
import { useSetRecoilState, useRecoilCallback } from "recoil";
import { insideClass, hasClass } from "../../utils";
import Gesture from "./Gesture";
const ActionPane = ({ children }) => {
const { putItemsOnTop, moveItems } = useItems();
@ -20,76 +22,38 @@ const ActionPane = ({ children }) => {
const actionRef = React.useRef({});
const onMouseDown = useRecoilCallback(
({ snapshot }) => async (e) => {
if (!e.isPrimary) {
return;
}
const {
target,
pointerId,
currentTarget,
ctrlKey,
metaKey,
clientX,
clientY,
button,
} = e;
if (button === 0 && !e.altKey) {
// Allow text selection instead of moving
if (["INPUT", "TEXTAREA"].includes(target.tagName)) return;
({ snapshot }) => async ({ target, ctrlKey, metaKey, event }) => {
// Allow text selection instead of moving
if (["INPUT", "TEXTAREA"].includes(target.tagName)) return;
const { top, left } = currentTarget.getBoundingClientRect();
const foundElement = insideClass(target, "item");
const foundElement = insideClass(target, "item");
if (foundElement && !hasClass(foundElement, "locked")) {
event.stopPropagation();
const selectedItems = await snapshot.getPromise(selectedItemsAtom);
if (foundElement && !hasClass(foundElement, "locked")) {
e.stopPropagation();
const panZoomRotate = await snapshot.getPromise(PanZoomRotateAtom);
const selectedItems = await snapshot.getPromise(selectedItemsAtom);
const point = {
x: (clientX - left) / panZoomRotate.scale,
y: (clientY - top) / panZoomRotate.scale,
};
if (!selectedItems.includes(foundElement.id)) {
if (ctrlKey || metaKey) {
setSelectedItems((prev) => [...prev, foundElement.id]);
} else {
setSelectedItems([foundElement.id]);
}
}
actionRef.current.moving = true;
actionRef.current.onTop = false;
actionRef.current.startX = point.x;
actionRef.current.startY = point.y;
actionRef.current.prevX = point.x;
actionRef.current.prevY = point.y;
actionRef.current.itemId = foundElement.id;
wrapperRef.current.style.cursor = "move";
try {
currentTarget.setPointerCapture(pointerId);
} catch (e) {
console.log("Fail to capture pointer", e);
if (!selectedItems.includes(foundElement.id)) {
if (ctrlKey || metaKey) {
setSelectedItems((prev) => [...prev, foundElement.id]);
} else {
setSelectedItems([foundElement.id]);
}
}
Object.assign(actionRef.current, {
moving: true,
onTop: false,
remainX: 0,
remainY: 0,
});
}
},
[setSelectedItems]
);
const onMouseMove = useRecoilCallback(
({ snapshot }) => async (e) => {
({ snapshot }) => async ({ deltaX, deltaY }) => {
if (actionRef.current.moving) {
if (!e.isPrimary) {
return;
}
const { clientX, clientY, currentTarget } = e;
const { top, left } = currentTarget.getBoundingClientRect();
const panZoomRotate = await snapshot.getPromise(PanZoomRotateAtom);
const selectedItems = await snapshot.getPromise(selectedItemsAtom);
const { gridSize: boardGridSize = 1 } = await snapshot.getPromise(
@ -97,15 +61,10 @@ const ActionPane = ({ children }) => {
);
const gridSize = boardGridSize || 1; // avoid 0 grid size
const currentX = (clientX - left) / panZoomRotate.scale;
const currentY = (clientY - top) / panZoomRotate.scale;
let realMoveX =
Math.round((currentX - actionRef.current.prevX) / gridSize) *
gridSize;
let realMoveY =
Math.round((currentY - actionRef.current.prevY) / gridSize) *
gridSize;
const moveX = actionRef.current.remainX + deltaX / panZoomRotate.scale;
const moveY = actionRef.current.remainY + deltaY / panZoomRotate.scale;
const realMoveX = Math.round(moveX / gridSize) * gridSize;
const realMoveY = Math.round(moveY / gridSize) * gridSize;
if (realMoveX || realMoveY) {
// Put items on top of others on first move
@ -124,41 +83,32 @@ const ActionPane = ({ children }) => {
gridSize
);
actionRef.current.prevX += realMoveX;
actionRef.current.prevY += realMoveY;
setBoardState((prev) =>
!prev.movingItems ? { ...prev, movingItems: true } : prev
);
}
actionRef.current.remainX = moveX - realMoveX;
actionRef.current.remainY = moveY - realMoveY;
}
},
[moveItems, putItemsOnTop, setBoardState]
);
const onMouseUp = React.useCallback(
(e) => {
if (!e.isPrimary) {
return;
}
if (actionRef.current.moving) {
actionRef.current = { moving: false };
wrapperRef.current.style.cursor = "auto";
setBoardState((prev) => ({ ...prev, movingItems: false }));
}
},
[setBoardState]
);
const onMouseUp = React.useCallback(() => {
if (actionRef.current.moving) {
actionRef.current = { moving: false };
setBoardState((prev) => ({ ...prev, movingItems: false }));
}
}, [setBoardState]);
return (
<div
onPointerDown={onMouseDown}
onPointerMove={onMouseMove}
onPointerUp={onMouseUp}
style={{ touchAction: "none" }}
ref={wrapperRef}
<Gesture
onDragStart={onMouseDown}
onDrag={onMouseMove}
onDragEnd={onMouseUp}
>
{children}
</div>
<div ref={wrapperRef}>{children}</div>
</Gesture>
);
};

View file

@ -174,8 +174,7 @@ const PanZoomRotate = ({ children, moveFirst }) => {
};
}, []);
const onZoom = (e) => {
const { clientX, clientY, scale } = e;
const onZoom = ({ clientX, clientY, scale }) => {
setScale((prevScale) => {
let newScale = prevScale.scale * scale;
if (newScale > 8) {
@ -193,8 +192,7 @@ const PanZoomRotate = ({ children, moveFirst }) => {
});
};
const onPan = (e) => {
const { deltaX, deltaY } = e;
const onPan = ({ deltaX, deltaY }) => {
setDim((prevDim) => {
return {
...prevDim,
@ -204,14 +202,14 @@ const PanZoomRotate = ({ children, moveFirst }) => {
});
};
const onDrag = (e) => {
const { target } = e;
const onDrag = (state) => {
const { target } = state;
const outsideItem =
!insideClass(target, "item") || insideClass(target, "locked");
if (moveFirst && outsideItem) {
onPan(e);
onPan(state);
}
};

View file

@ -113,9 +113,7 @@ const Selector = ({ children, moveFirst }) => {
};
}, [setSelected, emptySelection]);
const onDragStart = (e) => {
const { button, altKey, ctrlKey, metaKey, target } = e;
const onDragStart = ({ button, altKey, ctrlKey, metaKey, target }) => {
const outsideItem =
!insideClass(target, "item") || insideClass(target, "locked");
@ -133,9 +131,7 @@ const Selector = ({ children, moveFirst }) => {
};
const onDrag = useRecoilCallback(
({ snapshot }) => async (e) => {
const { distanceY, distanceX, startX, startY } = e;
({ snapshot }) => async ({ distanceY, distanceX, startX, startY }) => {
if (stateRef.current.moving) {
const { top, left } = wrapperRef.current.getBoundingClientRect();
@ -178,8 +174,7 @@ const Selector = ({ children, moveFirst }) => {
};
const onTap = React.useCallback(
(e) => {
const { target } = e;
({ target }) => {
if (
(!insideClass(target, "item") || insideClass(target, "locked")) &&
insideClass(target, "board")