grungnet/src/hooks/useMapSelection.tsx

184 lines
5.3 KiB
TypeScript
Raw Permalink Normal View History

2021-07-22 05:24:35 +00:00
import { useEffect, useState } from "react";
import { v4 as uuid } from "uuid";
2021-07-22 06:40:43 +00:00
import SelectionDragOverlay from "../components/selection/SelectionDragOverlay";
2021-07-22 03:16:44 +00:00
import SelectionMenu from "../components/selection/SelectionMenu";
import SelectTool from "../components/tools/SelectTool";
import { useBlur, useKeyboard } from "../contexts/KeyboardContext";
import { useUserId } from "../contexts/UserIdContext";
import shortcuts from "../shortcuts";
2021-07-22 06:40:43 +00:00
import {
SelectionItemsChangeEventHandler,
2021-07-23 05:41:07 +00:00
SelectionItemsCreateEventHandler,
2021-07-22 06:40:43 +00:00
SelectionItemsRemoveEventHandler,
} from "../types/Events";
2021-07-22 03:16:44 +00:00
import { Map, MapToolId } from "../types/Map";
import { MapState } from "../types/MapState";
import { Note } from "../types/Note";
2021-07-22 03:16:44 +00:00
import { Selection } from "../types/Select";
import { SelectToolSettings } from "../types/Select";
import { TokenState } from "../types/TokenState";
2021-07-22 03:16:44 +00:00
function useMapSelection(
map: Map | null,
mapState: MapState | null,
2021-07-22 03:16:44 +00:00
onSelectionItemsChange: SelectionItemsChangeEventHandler,
2021-07-22 06:40:43 +00:00
onSelectionItemsRemove: SelectionItemsRemoveEventHandler,
2021-07-23 05:41:07 +00:00
onSelectionItemsCreate: SelectionItemsCreateEventHandler,
2021-07-22 03:16:44 +00:00
selectedToolId: MapToolId,
settings: SelectToolSettings
) {
const userId = useUserId();
const disabledTokens: Record<string, boolean> = {};
const disabledNotes: Record<string, boolean> = {};
if (mapState && map && map.owner !== userId) {
if (!mapState.editFlags.includes("tokens")) {
for (let token of Object.values(mapState.tokens)) {
if (token.owner !== userId) {
disabledTokens[token.id] = true;
}
}
}
if (!mapState.editFlags.includes("notes")) {
for (let note of Object.values(mapState.notes)) {
disabledNotes[note.id] = true;
}
}
}
2021-07-22 03:16:44 +00:00
const [isSelectionMenuOpen, setIsSelectionMenuOpen] =
useState<boolean>(false);
2021-07-22 06:40:43 +00:00
const [isSelectionDragging, setIsSelectionDragging] = useState(false);
2021-07-22 03:16:44 +00:00
const [selection, setSelection] = useState<Selection | null>(null);
function handleSelectionMenuOpen(open: boolean) {
setIsSelectionMenuOpen(open);
}
2021-07-22 05:24:35 +00:00
const active = selectedToolId === "select";
2021-07-23 05:43:32 +00:00
// Remove selection when changing tools
2021-07-22 05:24:35 +00:00
useEffect(() => {
if (!active) {
setSelection(null);
setIsSelectionMenuOpen(false);
}
}, [active]);
2021-07-23 05:43:32 +00:00
// Remove selection when changing maps
useEffect(() => {
setSelection(null);
setIsSelectionMenuOpen(false);
}, [map]);
2021-07-22 06:40:43 +00:00
function handleSelectionDragStart() {
if (duplicateSelection && selection) {
const tokenStates: TokenState[] = [];
const notes: Note[] = [];
for (let item of selection.items) {
if (item.type === "token") {
const token = mapState?.tokens[item.id];
if (token && !token.locked) {
tokenStates.push({ ...token, id: uuid() });
}
} else {
const note = mapState?.notes[item.id];
if (note && !note.locked) {
notes.push({ ...note, id: uuid() });
}
}
}
onSelectionItemsCreate(tokenStates, notes);
}
2021-07-22 06:40:43 +00:00
setIsSelectionDragging(true);
}
function handleSelectionDragEnd() {
setIsSelectionDragging(false);
}
function handleSelectionItemsRemove(
tokenStateIds: string[],
noteIds: string[]
) {
setSelection(null);
onSelectionItemsRemove(tokenStateIds, noteIds);
}
const [duplicateSelection, setDuplicateSelection] = useState(false);
function handleKeyDown(event: KeyboardEvent) {
if (shortcuts.duplicate(event)) {
setDuplicateSelection(true);
}
2021-08-09 22:14:59 +00:00
if (shortcuts.delete(event) && selection && active) {
const tokenIds: string[] = [];
const noteIds: string[] = [];
for (let item of selection.items) {
if (item.type === "token") {
tokenIds.push(item.id);
} else {
noteIds.push(item.id);
}
}
handleSelectionItemsRemove(tokenIds, noteIds);
setIsSelectionMenuOpen(false);
}
}
function handleKeyUp(event: KeyboardEvent) {
if (shortcuts.duplicate(event)) {
setDuplicateSelection(false);
}
}
function handleBlur() {
setDuplicateSelection(false);
}
useKeyboard(handleKeyDown, handleKeyUp);
useBlur(handleBlur);
const selectionTool = map ? (
2021-07-22 03:16:44 +00:00
<SelectTool
2021-07-22 05:24:35 +00:00
active={active}
2021-07-22 03:16:44 +00:00
toolSettings={settings}
onSelectionItemsChange={onSelectionItemsChange}
selection={selection}
onSelectionChange={setSelection}
onSelectionMenuOpen={handleSelectionMenuOpen}
2021-07-22 06:40:43 +00:00
onSelectionDragStart={handleSelectionDragStart}
onSelectionDragEnd={handleSelectionDragEnd}
disabledTokens={disabledTokens}
disabledNotes={disabledNotes}
map={map}
2021-07-22 03:16:44 +00:00
/>
) : null;
2021-07-22 03:16:44 +00:00
const selectionMenu = (
<SelectionMenu
isOpen={isSelectionMenuOpen}
2021-07-23 05:41:07 +00:00
active={active}
2021-07-22 03:16:44 +00:00
onRequestClose={() => setIsSelectionMenuOpen(false)}
2021-07-23 05:41:07 +00:00
onRequestOpen={() => setIsSelectionMenuOpen(true)}
2021-07-22 03:16:44 +00:00
selection={selection}
2021-07-23 05:41:07 +00:00
onSelectionChange={setSelection}
2021-07-22 03:16:44 +00:00
onSelectionItemsChange={onSelectionItemsChange}
2021-07-23 05:41:07 +00:00
onSelectionItemsCreate={onSelectionItemsCreate}
2021-07-22 03:16:44 +00:00
map={map}
mapState={mapState}
2021-07-22 03:16:44 +00:00
/>
);
2021-07-22 06:40:43 +00:00
const selectionDragOverlay = selection ? (
<SelectionDragOverlay
dragging={isSelectionDragging}
selection={selection}
onSelectionItemsRemove={handleSelectionItemsRemove}
/>
) : null;
return { selectionTool, selectionMenu, selectionDragOverlay };
2021-07-22 03:16:44 +00:00
}
export default useMapSelection;