diff --git a/src/components/canvas/Canvas.tsx b/src/components/canvas/Canvas.tsx index 10856c2..f67c739 100644 --- a/src/components/canvas/Canvas.tsx +++ b/src/components/canvas/Canvas.tsx @@ -13,6 +13,7 @@ import { ToolContext } from "@/context/Tool"; import { useTextures } from "@/hooks/useTextures"; import { useBlockData } from "@/hooks/useBlockData"; +import { useClipboard } from "@/hooks/useClipboard"; import { useMoveTool } from "@/hooks/tools/move"; import { useRectangleSelectTool } from "@/hooks/tools/rectangle-select"; @@ -25,7 +26,6 @@ import { useEyedropperTool } from "@/hooks/tools/eyedropper"; import { useZoomTool } from "@/hooks/tools/zoom"; import * as selection from "@/utils/selection"; -import * as clipboard from "@/utils/clipboard"; import Blocks from "./Blocks"; import Cursor from "./Cursor"; @@ -67,6 +67,8 @@ function Canvas() { const startBlocksRef = useRef([]); const startSelectionCoordsRef = useRef([]); + const clipboard = useClipboard(); + const zoom = useCallback( (newScale: number) => { setScale(newScale); @@ -300,11 +302,11 @@ function Canvas() { break; case "c": if (!e.ctrlKey) return; - clipboard.copy(selectionCoords, blocks); + clipboard.copy(); break; case "v": if (!e.ctrlKey) return; - clipboard.paste(setSelectionLayerBlocks, setSelectionCoords, setTool); + clipboard.paste(); break; case "1": setTool("hand"); @@ -360,11 +362,12 @@ function Canvas() { selectionLayerBlocks, canvasSize, blockData, + clipboard, setBlocks, - setCssCursor, setSelectionCoords, setSelectionLayerBlocks, setTool, + addHistory, redo, undo, ] diff --git a/src/components/menubar/EditMenu.tsx b/src/components/menubar/EditMenu.tsx index a434dbc..56d1034 100644 --- a/src/components/menubar/EditMenu.tsx +++ b/src/components/menubar/EditMenu.tsx @@ -3,17 +3,17 @@ import { useContext } from "react"; import { CanvasContext } from "@/context/Canvas"; import { HistoryContext } from "@/context/History"; import { SelectionContext } from "@/context/Selection"; -import { ToolContext } from "@/context/Tool"; -import * as clipboard from "@/utils/clipboard"; +import { useClipboard } from "@/hooks/useClipboard"; import { MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger } from "@/components/ui/menubar"; function EditMenu() { - const { blocks, setBlocks } = useContext(CanvasContext); + const { setBlocks } = useContext(CanvasContext); const { undo, redo, isUndoAvailable, isRedoAvailable } = useContext(HistoryContext); - const { selectionCoords, setSelectionCoords, setSelectionLayerBlocks } = useContext(SelectionContext); - const { setTool } = useContext(ToolContext); + const { selectionCoords } = useContext(SelectionContext); + + const clipboard = useClipboard(); const cut = () => { setBlocks((prev) => prev.filter((b) => !selectionCoords.some(([x2, y2]) => x2 === b.x && y2 === b.y))); @@ -33,11 +33,11 @@ function EditMenu() { - clipboard.copy(selectionCoords, blocks)}> + Copy Ctrl C - clipboard.paste(setSelectionLayerBlocks, setSelectionCoords, setTool)}> + Paste Ctrl V diff --git a/src/hooks/useClipboard.ts b/src/hooks/useClipboard.ts new file mode 100644 index 0000000..4f29bb6 --- /dev/null +++ b/src/hooks/useClipboard.ts @@ -0,0 +1,38 @@ +import { useContext } from "react"; + +import { CanvasContext } from "@/context/Canvas"; +import { SelectionContext } from "@/context/Selection"; +import { ToolContext } from "@/context/Tool"; + +export function useClipboard() { + const { blocks } = useContext(CanvasContext); + const { selectionCoords, setSelectionCoords, setSelectionLayerBlocks } = useContext(SelectionContext); + const { setTool } = useContext(ToolContext); + + function copy() { + const selectorBlocks = selectionCoords.map(([x, y]) => blocks.find((block) => block.x === x && block.y === y)).filter(Boolean); + navigator.clipboard.writeText(JSON.stringify(selectorBlocks)); + } + + async function paste() { + try { + const clipboardText = await navigator.clipboard.readText(); + const clipboardBlocks = JSON.parse(clipboardText); + + // Check if pasted object is of type Block[] + if ( + !Array.isArray(clipboardBlocks) || + !clipboardBlocks.every((block) => typeof block.x === "number" && typeof block.y === "number" && typeof block.name === "string") + ) + return; + + setSelectionLayerBlocks(clipboardBlocks); + setSelectionCoords(clipboardBlocks.map(({ x, y }) => [x, y])); + setTool("move"); + } catch (error) { + console.error("Failed to read/parse clipboard:", error); + } + } + + return { copy, paste }; +} diff --git a/src/utils/clipboard.ts b/src/utils/clipboard.ts deleted file mode 100644 index 9a69fa8..0000000 --- a/src/utils/clipboard.ts +++ /dev/null @@ -1,37 +0,0 @@ -export function copy(selectionCoords: CoordinateArray, blocks: Block[]) { - // Get all blocks within selection - const selectorBlocks = selectionCoords - .map((coord) => { - const [x, y] = coord; - return blocks.find((block) => block.x === x && block.y === y); - }) - .filter((block) => block !== undefined); - - // Write to clipboard - navigator.clipboard.writeText(JSON.stringify(selectorBlocks)); -} - -export async function paste( - setSelectionLayerBlocks: React.Dispatch>, - setSelectionCoords: React.Dispatch>, - setTool: React.Dispatch> -) { - try { - // Read clipboard then parse it - const clipboardText = await navigator.clipboard.readText(); - const clipboardBlocks = JSON.parse(clipboardText); - - // Check if pasted object is of type Block[] - if ( - !Array.isArray(clipboardBlocks) || - !clipboardBlocks.every((block) => typeof block.x === "number" && typeof block.y === "number" && typeof block.name === "string") - ) - return; - - setSelectionLayerBlocks(clipboardBlocks); - setSelectionCoords(clipboardBlocks.map((block) => [block.x, block.y])); - setTool("move"); - } catch (error) { - console.error("Failed to read/parse clipboard:", error); - } -}