feat: press enter to confirm selection
also clean up useEffect(s) and useRef(s)
This commit is contained in:
parent
f17b2b9f42
commit
4b59e9b4be
3 changed files with 97 additions and 85 deletions
|
|
@ -11,7 +11,7 @@ import { ThemeContext } from "@/context/Theme";
|
|||
import { ToolContext } from "@/context/Tool";
|
||||
|
||||
import { useTextures } from "@/hooks/useTextures";
|
||||
import { isInSelection } from "@/utils/selection";
|
||||
import { confirmSelection, isInSelection } from "@/utils/selection";
|
||||
|
||||
import Blocks from "./Blocks";
|
||||
import Cursor from "./Cursor";
|
||||
|
|
@ -51,7 +51,6 @@ function Canvas() {
|
|||
const holdingAltRef = useRef(false);
|
||||
const holdingShiftRef = useRef(false);
|
||||
const oldToolRef = useRef<Tool>();
|
||||
const selectionCoordsRef = useRef<CoordinateArray>(selectionCoords);
|
||||
|
||||
const visibleArea = useMemo(() => {
|
||||
const blockSize = 16 * scale;
|
||||
|
|
@ -383,8 +382,15 @@ function Canvas() {
|
|||
}
|
||||
}, [tool, holdingAltRef, scale, mouseCoords, blocks, setSelectionCoords, setSelectedBlock, zoom]);
|
||||
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
const onKeyDown = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
switch (e.key) {
|
||||
case "Escape":
|
||||
setSelectionLayerBlocks([]);
|
||||
break;
|
||||
case "Enter":
|
||||
confirmSelection(blocks, selectionLayerBlocks, setBlocks, setSelectionLayerBlocks);
|
||||
break;
|
||||
case " ": // Space
|
||||
setDragging(true);
|
||||
oldToolRef.current = tool;
|
||||
|
|
@ -399,7 +405,7 @@ function Canvas() {
|
|||
if (tool === "zoom") setCssCursor("zoom-out");
|
||||
break;
|
||||
case "Delete": {
|
||||
setBlocks((prev) => prev.filter((b) => !selectionCoordsRef.current.some(([x2, y2]) => x2 === b.x && y2 === b.y)));
|
||||
setBlocks((prev) => prev.filter((b) => !selectionCoords.some(([x2, y2]) => x2 === b.x && y2 === b.y)));
|
||||
break;
|
||||
}
|
||||
case "1":
|
||||
|
|
@ -430,9 +436,12 @@ function Canvas() {
|
|||
setTool("zoom");
|
||||
break;
|
||||
}
|
||||
};
|
||||
},
|
||||
[tool, blocks, selectionCoords, selectionLayerBlocks, setBlocks, setCssCursor, setSelectionLayerBlocks, setTool]
|
||||
);
|
||||
|
||||
const onKeyUp = (e: KeyboardEvent) => {
|
||||
const onKeyUp = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
switch (e.key) {
|
||||
case " ": // Space
|
||||
if (!oldToolRef.current) return;
|
||||
|
|
@ -448,11 +457,9 @@ function Canvas() {
|
|||
setCssCursor("zoom-in");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
selectionCoordsRef.current = selectionCoords;
|
||||
}, [selectionCoords]);
|
||||
},
|
||||
[setCssCursor, setTool]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const container = stageContainerRef.current;
|
||||
|
|
@ -470,8 +477,7 @@ function Canvas() {
|
|||
|
||||
resizeCanvas();
|
||||
return () => resizeObserver.disconnect();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [stageContainerRef]);
|
||||
}, [stageContainerRef, setStageSize]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("keydown", onKeyDown);
|
||||
|
|
@ -484,8 +490,7 @@ function Canvas() {
|
|||
window.removeEventListener("keydown", onKeyDown);
|
||||
window.removeEventListener("keyup", onKeyUp);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
}, [onKeyDown, onKeyUp]);
|
||||
|
||||
return (
|
||||
<div ref={stageContainerRef} style={{ cursor: cssCursor }} className="relative w-full h-full bg-zinc-200 dark:bg-black">
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import { CheckIcon, XIcon } from "lucide-react";
|
|||
import { CanvasContext } from "@/context/Canvas";
|
||||
import { SelectionContext } from "@/context/Selection";
|
||||
|
||||
import { confirmSelection } from "@/utils/selection";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
function SelectionBar() {
|
||||
|
|
@ -12,14 +14,6 @@ function SelectionBar() {
|
|||
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
const confirmSelection = () => {
|
||||
const combinedBlocks = [...blocks, ...layerBlocks];
|
||||
const uniqueBlocks = Array.from(new Map(combinedBlocks.map((block) => [`${block.x},${block.y}`, block])).values());
|
||||
|
||||
setBlocks(uniqueBlocks);
|
||||
setLayerBlocks([]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setIsVisible(layerBlocks.length !== 0);
|
||||
}, [layerBlocks]);
|
||||
|
|
@ -35,7 +29,7 @@ function SelectionBar() {
|
|||
<XIcon />
|
||||
</Button>
|
||||
<span className="mx-2 text-[0.85rem]">Confirm selection?</span>
|
||||
<Button variant="ghost" className="w-8 h-8" onClick={confirmSelection}>
|
||||
<Button variant="ghost" className="w-8 h-8" onClick={() => confirmSelection(blocks, layerBlocks, setBlocks, setLayerBlocks)}>
|
||||
<CheckIcon />
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,20 @@
|
|||
// Check if a block is within the selection
|
||||
export const isInSelection = (selection: CoordinateArray, x: number, y: number): boolean => {
|
||||
export function isInSelection(selection: CoordinateArray, x: number, y: number): boolean {
|
||||
if (selection.length !== 0) {
|
||||
return selection.some(([x2, y2]) => x2 === x && y2 === y);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
export function confirmSelection(
|
||||
blocks: Block[],
|
||||
layerBlocks: Block[],
|
||||
setBlocks: React.Dispatch<React.SetStateAction<Block[]>>,
|
||||
setLayerBlocks: React.Dispatch<React.SetStateAction<Block[]>>
|
||||
) {
|
||||
const combinedBlocks = [...blocks, ...layerBlocks];
|
||||
const uniqueBlocks = Array.from(new Map(combinedBlocks.map((block) => [`${block.x},${block.y}`, block])).values());
|
||||
|
||||
setBlocks(uniqueBlocks);
|
||||
setLayerBlocks([]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue