diff --git a/src/components/konva/Note.tsx b/src/components/konva/Note.tsx index 4274801..b6ecf6b 100644 --- a/src/components/konva/Note.tsx +++ b/src/components/konva/Note.tsx @@ -81,11 +81,12 @@ function Note({ const noteGroup = event.target; if (userId) { onNoteChange?.({ - ...note, - x: noteGroup.x() / mapWidth, - y: noteGroup.y() / mapHeight, - lastModifiedBy: userId, - lastModified: Date.now(), + [note.id]: { + x: noteGroup.x() / mapWidth, + y: noteGroup.y() / mapHeight, + lastModifiedBy: userId, + lastModified: Date.now(), + }, }); } onNoteDragEnd?.(event, note.id); diff --git a/src/components/map/Map.tsx b/src/components/map/Map.tsx index 2038861..25d1bb6 100644 --- a/src/components/map/Map.tsx +++ b/src/components/map/Map.tsx @@ -36,6 +36,7 @@ import { NoteChangeEventHandler, NoteRemoveEventHander, TokenStateChangeEventHandler, + NoteCreateEventHander, } from "../../types/Events"; import useMapTokens from "../../hooks/useMapTokens"; @@ -55,6 +56,7 @@ type MapProps = { onFogDraw: (action: Action) => void; onFogDrawUndo: () => void; onFogDrawRedo: () => void; + onMapNoteCreate: NoteCreateEventHander; onMapNoteChange: NoteChangeEventHandler; onMapNoteRemove: NoteRemoveEventHander; allowMapDrawing: boolean; @@ -79,6 +81,7 @@ function Map({ onFogDraw, onFogDrawUndo, onFogDrawRedo, + onMapNoteCreate, onMapNoteChange, onMapNoteRemove, allowMapDrawing, @@ -206,6 +209,7 @@ function Map({ const { notes, noteMenu, noteDragOverlay } = useMapNotes( map, mapState, + onMapNoteCreate, onMapNoteChange, onMapNoteRemove, selectedToolId, diff --git a/src/components/note/NoteDragOverlay.tsx b/src/components/note/NoteDragOverlay.tsx index 9e70efe..aaa0916 100644 --- a/src/components/note/NoteDragOverlay.tsx +++ b/src/components/note/NoteDragOverlay.tsx @@ -1,9 +1,10 @@ import Konva from "konva"; +import { NoteRemoveEventHander } from "../../types/Events"; import DragOverlay from "../map/DragOverlay"; type NoteDragOverlayProps = { - onNoteRemove: (noteId: string) => void; + onNoteRemove: NoteRemoveEventHander; noteId: string; noteGroup: Konva.Node; dragging: boolean; @@ -16,7 +17,7 @@ function NoteDragOverlay({ dragging, }: NoteDragOverlayProps) { function handleNoteRemove() { - onNoteRemove(noteId); + onNoteRemove([noteId]); } return ( diff --git a/src/components/note/NoteMenu.tsx b/src/components/note/NoteMenu.tsx index 04933ad..9f66b37 100644 --- a/src/components/note/NoteMenu.tsx +++ b/src/components/note/NoteMenu.tsx @@ -73,31 +73,31 @@ function NoteMenu({ function handleTextChange(event: React.ChangeEvent) { const text = event.target.value.substring(0, 1024); - note && onNoteChange({ ...note, text: text }); + note && onNoteChange({ [note.id]: { text: text } }); } function handleColorChange(color: Color) { if (!note) { return; } - onNoteChange({ ...note, color: color }); + onNoteChange({ [note.id]: { color: color } }); } function handleSizeChange(event: React.ChangeEvent) { const newSize = parseFloat(event.target.value); - note && onNoteChange({ ...note, size: newSize }); + note && onNoteChange({ [note.id]: { size: newSize } }); } function handleVisibleChange() { - note && onNoteChange({ ...note, visible: !note.visible }); + note && onNoteChange({ [note.id]: { visible: !note.visible } }); } function handleLockChange() { - note && onNoteChange({ ...note, locked: !note.locked }); + note && onNoteChange({ [note.id]: { locked: !note.locked } }); } function handleModeChange() { - note && onNoteChange({ ...note, textOnly: !note.textOnly }); + note && onNoteChange({ [note.id]: { textOnly: !note.textOnly } }); } function handleModalContent(node: HTMLElement) { diff --git a/src/components/token/TokenDragOverlay.tsx b/src/components/token/TokenDragOverlay.tsx index 176bd27..f91e204 100644 --- a/src/components/token/TokenDragOverlay.tsx +++ b/src/components/token/TokenDragOverlay.tsx @@ -18,7 +18,7 @@ function TokenDragOverlay({ dragging, }: TokenDragOverlayProps) { function handleTokenRemove() { - onTokenStateRemove(tokenState); + onTokenStateRemove([tokenState.id]); } return ( diff --git a/src/components/tools/NoteTool.tsx b/src/components/tools/NoteTool.tsx index 0fa98df..ce880dd 100644 --- a/src/components/tools/NoteTool.tsx +++ b/src/components/tools/NoteTool.tsx @@ -17,7 +17,7 @@ import Note from "../konva/Note"; import { Map } from "../../types/Map"; import { Note as NoteType } from "../../types/Note"; import { - NoteAddEventHander, + NoteCreateEventHander, NoteChangeEventHandler, NoteDragEventHandler, NoteMenuOpenEventHandler, @@ -28,7 +28,7 @@ const defaultNoteSize = 2; type MapNoteProps = { map: Map | null; active: boolean; - onNoteAdd: NoteAddEventHander; + onNoteCreate: NoteCreateEventHander; onNoteChange: NoteChangeEventHandler; notes: NoteType[]; onNoteMenuOpen: NoteMenuOpenEventHandler; @@ -41,7 +41,7 @@ type MapNoteProps = { function NoteTool({ map, active, - onNoteAdd, + onNoteCreate, onNoteChange, notes, onNoteMenuOpen, @@ -127,7 +127,7 @@ function NoteTool({ function handleBrushUp() { if (noteData && creatingNoteRef.current) { - onNoteAdd(noteData); + onNoteCreate([noteData]); onNoteMenuOpen(noteData.id, creatingNoteRef.current); } setNoteData(null); diff --git a/src/hooks/useMapNotes.tsx b/src/hooks/useMapNotes.tsx index aa6f99c..517f9ab 100644 --- a/src/hooks/useMapNotes.tsx +++ b/src/hooks/useMapNotes.tsx @@ -4,7 +4,11 @@ import { useState } from "react"; import NoteDragOverlay from "../components/note/NoteDragOverlay"; import NoteMenu from "../components/note/NoteMenu"; import NoteTool from "../components/tools/NoteTool"; -import { NoteChangeEventHandler, NoteRemoveEventHander } from "../types/Events"; +import { + NoteChangeEventHandler, + NoteCreateEventHander, + NoteRemoveEventHander, +} from "../types/Events"; import { Map, MapToolId } from "../types/Map"; import { MapState } from "../types/MapState"; import { Note, NoteDraggingOptions, NoteMenuOptions } from "../types/Note"; @@ -12,6 +16,7 @@ import { Note, NoteDraggingOptions, NoteMenuOptions } from "../types/Note"; function useMapNotes( map: Map | null, mapState: MapState | null, + onNoteCreate: NoteCreateEventHander, onNoteChange: NoteChangeEventHandler, onNoteRemove: NoteRemoveEventHander, selectedToolId: MapToolId, @@ -38,8 +43,8 @@ function useMapNotes( setNoteDraggingOptions({ ...noteDraggingOptions, dragging: false }); } - function handleNoteRemove(noteId: string) { - onNoteRemove(noteId); + function handleNoteRemove(noteIds: string[]) { + onNoteRemove(noteIds); setNoteDraggingOptions(undefined); } @@ -47,7 +52,7 @@ function useMapNotes( { if (!prevMapState) { return prevMapState; } + let newNotes = { ...prevMapState.notes }; + for (let note of notes) { + newNotes[note.id] = note; + } return { ...prevMapState, - notes: { - ...prevMapState.notes, - [note.id]: note, - }, + notes: newNotes, }; }); } - function handleNoteRemove(noteId: string) { + function handleNoteChange(changes: Record>) { + setCurrentMapState((prevMapState) => { + if (!prevMapState) { + return prevMapState; + } + let notes = { ...prevMapState.notes }; + for (let id in changes) { + if (id in notes) { + notes[id] = { ...notes[id], ...changes[id] } as Note; + } + } + return { + ...prevMapState, + notes, + }; + }); + } + + function handleNoteRemove(noteIds: string[]) { setCurrentMapState((prevMapState) => { if (!prevMapState) { return prevMapState; } return { ...prevMapState, - notes: omit(prevMapState.notes, [noteId]), + notes: omit(prevMapState.notes, noteIds), }; }); } @@ -415,7 +434,7 @@ function NetworkedMapAndTokens({ session }: { session: Session }) { } function handleMapTokenStateChange( - change: Record> + changes: Record> ) { if (!currentMapState) { return; @@ -425,9 +444,9 @@ function NetworkedMapAndTokens({ session }: { session: Session }) { return prevMapState; } let tokens = { ...prevMapState.tokens }; - for (let id in change) { + for (let id in changes) { if (id in tokens) { - tokens[id] = { ...tokens[id], ...change[id] } as TokenState; + tokens[id] = { ...tokens[id], ...changes[id] } as TokenState; } } @@ -438,13 +457,15 @@ function NetworkedMapAndTokens({ session }: { session: Session }) { }); } - function handleMapTokenStateRemove(tokenState: TokenState) { + function handleMapTokenStateRemove(tokenStateIds: string[]) { setCurrentMapState((prevMapState) => { if (!prevMapState) { return prevMapState; } - const { [tokenState.id]: old, ...rest } = prevMapState.tokens; - return { ...prevMapState, tokens: rest }; + return { + ...prevMapState, + tokens: omit(prevMapState.tokens, tokenStateIds), + }; }); } @@ -552,6 +573,7 @@ function NetworkedMapAndTokens({ session }: { session: Session }) { onFogDraw={handleFogDraw} onFogDrawUndo={handleFogDrawUndo} onFogDrawRedo={handleFogDrawRedo} + onMapNoteCreate={handleNoteCreate} onMapNoteChange={handleNoteChange} onMapNoteRemove={handleNoteRemove} allowMapDrawing={!!canEditMapDrawing} diff --git a/src/types/Events.ts b/src/types/Events.ts index 3881283..832d58a 100644 --- a/src/types/Events.ts +++ b/src/types/Events.ts @@ -22,7 +22,7 @@ export type DiceSelectEventHandler = (dice: DefaultDice) => void; export type RequestCloseEventHandler = () => void; export type TokensStateCreateHandler = (states: TokenState[]) => void; -export type TokenStateRemoveHandler = (state: TokenState) => void; +export type TokenStateRemoveHandler = (tokenStateIds: string[]) => void; export type TokenStateChangeEventHandler = ( changes: Record> ) => void; @@ -36,9 +36,11 @@ export type TokenDragEventHandler = ( tokenStateId: string ) => void; -export type NoteAddEventHander = (note: Note) => void; -export type NoteRemoveEventHander = (noteId: string) => void; -export type NoteChangeEventHandler = (note: Note) => void; +export type NoteCreateEventHander = (notes: Note[]) => void; +export type NoteRemoveEventHander = (noteIds: string[]) => void; +export type NoteChangeEventHandler = ( + changes: Record> +) => void; export type NoteMenuOpenEventHandler = ( noteId: string, noteNode: Konva.Node