Converted /modals to typescript
This commit is contained in:
458
src/components/map/Map.tsx
Normal file
458
src/components/map/Map.tsx
Normal file
@@ -0,0 +1,458 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import MapControls from "./MapControls";
|
||||
import MapInteraction from "./MapInteraction";
|
||||
import MapTokens from "./MapTokens";
|
||||
import MapDrawing from "./MapDrawing";
|
||||
import MapFog from "./MapFog";
|
||||
import MapGrid from "./MapGrid";
|
||||
import MapMeasure from "./MapMeasure";
|
||||
import NetworkedMapPointer from "../../network/NetworkedMapPointer";
|
||||
import MapNotes from "./MapNotes";
|
||||
|
||||
import { useTokenData } from "../../contexts/TokenDataContext";
|
||||
import { useSettings } from "../../contexts/SettingsContext";
|
||||
|
||||
import TokenMenu from "../token/TokenMenu";
|
||||
import TokenDragOverlay from "../token/TokenDragOverlay";
|
||||
import NoteMenu from "../note/NoteMenu";
|
||||
import NoteDragOverlay from "../note/NoteDragOverlay";
|
||||
|
||||
import {
|
||||
AddShapeAction,
|
||||
CutShapeAction,
|
||||
EditShapeAction,
|
||||
RemoveShapeAction,
|
||||
} from "../../actions";
|
||||
import { Fog, Path, Shape } from "../../helpers/drawing";
|
||||
import Session from "../../network/Session";
|
||||
import { Grid } from "../../helpers/grid";
|
||||
import { ImageFile } from "../../helpers/image";
|
||||
|
||||
type Resolutions = Record<string, ImageFile>
|
||||
|
||||
export type Map = {
|
||||
id: string,
|
||||
name: string,
|
||||
owner: string,
|
||||
file: Uint8Array,
|
||||
quality: string,
|
||||
resolutions: Resolutions,
|
||||
grid: Grid,
|
||||
group: string,
|
||||
width: number,
|
||||
height: number,
|
||||
type: string,
|
||||
lastUsed: number,
|
||||
lastModified: number,
|
||||
created: number,
|
||||
showGrid: boolean,
|
||||
snapToGrid: boolean,
|
||||
thumbnail: ImageFile,
|
||||
}
|
||||
|
||||
export type Note = {
|
||||
id: string,
|
||||
color: string,
|
||||
lastModified: number,
|
||||
lastModifiedBy: string,
|
||||
locked: boolean,
|
||||
size: number,
|
||||
text: string,
|
||||
textOnly: boolean,
|
||||
visible: boolean,
|
||||
x: number,
|
||||
y: number,
|
||||
}
|
||||
|
||||
export type TokenState = {
|
||||
id: string,
|
||||
tokenId: string,
|
||||
owner: string,
|
||||
size: number,
|
||||
label: string,
|
||||
status: string[],
|
||||
x: number,
|
||||
y: number,
|
||||
lastModifiedBy: string,
|
||||
lastModified: number,
|
||||
rotation: number,
|
||||
locked: boolean,
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
interface PathId extends Path {
|
||||
id: string
|
||||
}
|
||||
|
||||
interface ShapeId extends Shape {
|
||||
id: string
|
||||
}
|
||||
export type MapState = {
|
||||
tokens: Record<string, TokenState>,
|
||||
drawShapes: PathId | ShapeId,
|
||||
fogShapes: Fog[],
|
||||
editFlags: string[],
|
||||
notes: Note[],
|
||||
mapId: string,
|
||||
}
|
||||
|
||||
function Map({
|
||||
map,
|
||||
mapState,
|
||||
mapActions,
|
||||
onMapTokenStateChange,
|
||||
onMapTokenStateRemove,
|
||||
onMapChange,
|
||||
onMapReset,
|
||||
onMapDraw,
|
||||
onMapDrawUndo,
|
||||
onMapDrawRedo,
|
||||
onFogDraw,
|
||||
onFogDrawUndo,
|
||||
onFogDrawRedo,
|
||||
onMapNoteChange,
|
||||
onMapNoteRemove,
|
||||
allowMapDrawing,
|
||||
allowFogDrawing,
|
||||
allowMapChange,
|
||||
allowNoteEditing,
|
||||
disabledTokens,
|
||||
session,
|
||||
}: {
|
||||
map: any
|
||||
mapState: MapState
|
||||
mapActions: any,
|
||||
onMapTokenStateChange: any,
|
||||
onMapTokenStateRemove: any,
|
||||
onMapChange: any,
|
||||
onMapReset: any,
|
||||
onMapDraw: any,
|
||||
onMapDrawUndo: any,
|
||||
onMapDrawRedo: any,
|
||||
onFogDraw: any,
|
||||
onFogDrawUndo: any,
|
||||
onFogDrawRedo: any,
|
||||
onMapNoteChange: any,
|
||||
onMapNoteRemove: any,
|
||||
allowMapDrawing: boolean,
|
||||
allowFogDrawing: boolean,
|
||||
allowMapChange: boolean,
|
||||
allowNoteEditing: boolean,
|
||||
disabledTokens: any,
|
||||
session: Session
|
||||
}) {
|
||||
const { tokensById } = useTokenData();
|
||||
|
||||
const [selectedToolId, setSelectedToolId] = useState("move");
|
||||
const { settings, setSettings }: { settings: any, setSettings: any} = useSettings();
|
||||
|
||||
function handleToolSettingChange(tool: any, change: any) {
|
||||
setSettings((prevSettings: any) => ({
|
||||
...prevSettings,
|
||||
[tool]: {
|
||||
...prevSettings[tool],
|
||||
...change,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
const drawShapes = Object.values(mapState?.drawShapes || {});
|
||||
const fogShapes = Object.values(mapState?.fogShapes || {});
|
||||
|
||||
function handleToolAction(action: string) {
|
||||
if (action === "eraseAll") {
|
||||
onMapDraw(new RemoveShapeAction(drawShapes.map((s) => s.id)));
|
||||
}
|
||||
if (action === "mapUndo") {
|
||||
onMapDrawUndo();
|
||||
}
|
||||
if (action === "mapRedo") {
|
||||
onMapDrawRedo();
|
||||
}
|
||||
if (action === "fogUndo") {
|
||||
onFogDrawUndo();
|
||||
}
|
||||
if (action === "fogRedo") {
|
||||
onFogDrawRedo();
|
||||
}
|
||||
}
|
||||
|
||||
function handleMapShapeAdd(shape: Shape) {
|
||||
onMapDraw(new AddShapeAction([shape]));
|
||||
}
|
||||
|
||||
function handleMapShapesRemove(shapeIds: string[]) {
|
||||
onMapDraw(new RemoveShapeAction(shapeIds));
|
||||
}
|
||||
|
||||
function handleFogShapesAdd(shapes: Shape[]) {
|
||||
onFogDraw(new AddShapeAction(shapes));
|
||||
}
|
||||
|
||||
function handleFogShapesCut(shapes: Shape[]) {
|
||||
onFogDraw(new CutShapeAction(shapes));
|
||||
}
|
||||
|
||||
function handleFogShapesRemove(shapeIds: string[]) {
|
||||
onFogDraw(new RemoveShapeAction(shapeIds));
|
||||
}
|
||||
|
||||
function handleFogShapesEdit(shapes: Shape[]) {
|
||||
onFogDraw(new EditShapeAction(shapes));
|
||||
}
|
||||
|
||||
const disabledControls = [];
|
||||
if (!allowMapDrawing) {
|
||||
disabledControls.push("drawing");
|
||||
}
|
||||
if (!map) {
|
||||
disabledControls.push("move");
|
||||
disabledControls.push("measure");
|
||||
disabledControls.push("pointer");
|
||||
}
|
||||
if (!allowFogDrawing) {
|
||||
disabledControls.push("fog");
|
||||
}
|
||||
if (!allowMapChange) {
|
||||
disabledControls.push("map");
|
||||
}
|
||||
if (!allowNoteEditing) {
|
||||
disabledControls.push("note");
|
||||
}
|
||||
|
||||
const disabledSettings: { fog: any[], drawing: any[]} = { fog: [], drawing: [] };
|
||||
if (drawShapes.length === 0) {
|
||||
disabledSettings.drawing.push("erase");
|
||||
}
|
||||
if (!mapState || mapActions.mapDrawActionIndex < 0) {
|
||||
disabledSettings.drawing.push("undo");
|
||||
}
|
||||
if (
|
||||
!mapState ||
|
||||
mapActions.mapDrawActionIndex === mapActions.mapDrawActions.length - 1
|
||||
) {
|
||||
disabledSettings.drawing.push("redo");
|
||||
}
|
||||
if (!mapState || mapActions.fogDrawActionIndex < 0) {
|
||||
disabledSettings.fog.push("undo");
|
||||
}
|
||||
if (
|
||||
!mapState ||
|
||||
mapActions.fogDrawActionIndex === mapActions.fogDrawActions.length - 1
|
||||
) {
|
||||
disabledSettings.fog.push("redo");
|
||||
}
|
||||
|
||||
const mapControls = (
|
||||
<MapControls
|
||||
onMapChange={onMapChange}
|
||||
onMapReset={onMapReset}
|
||||
currentMap={map}
|
||||
currentMapState={mapState}
|
||||
onSelectedToolChange={setSelectedToolId}
|
||||
selectedToolId={selectedToolId}
|
||||
toolSettings={settings}
|
||||
onToolSettingChange={handleToolSettingChange}
|
||||
onToolAction={handleToolAction}
|
||||
disabledControls={disabledControls}
|
||||
disabledSettings={disabledSettings}
|
||||
/>
|
||||
);
|
||||
|
||||
const [isTokenMenuOpen, setIsTokenMenuOpen]: [ isTokenMenuOpen: boolean, setIsTokenMenuOpen: React.Dispatch<React.SetStateAction<boolean>>] = useState<boolean>(false);
|
||||
const [tokenMenuOptions, setTokenMenuOptions]: [ tokenMenuOptions: any, setTokenMenuOptions: any ] = useState({});
|
||||
const [tokenDraggingOptions, setTokenDraggingOptions]: [ tokenDraggingOptions: any, setTokenDragginOptions: any ] = useState();
|
||||
function handleTokenMenuOpen(tokenStateId: string, tokenImage: any) {
|
||||
setTokenMenuOptions({ tokenStateId, tokenImage });
|
||||
setIsTokenMenuOpen(true);
|
||||
}
|
||||
|
||||
const mapTokens = map && mapState && (
|
||||
<MapTokens
|
||||
map={map}
|
||||
mapState={mapState}
|
||||
tokenDraggingOptions={tokenDraggingOptions}
|
||||
setTokenDraggingOptions={setTokenDraggingOptions}
|
||||
onMapTokenStateChange={onMapTokenStateChange}
|
||||
handleTokenMenuOpen={handleTokenMenuOpen}
|
||||
selectedToolId={selectedToolId}
|
||||
disabledTokens={disabledTokens}
|
||||
/>
|
||||
);
|
||||
|
||||
const tokenMenu = (
|
||||
<TokenMenu
|
||||
isOpen={isTokenMenuOpen}
|
||||
onRequestClose={() => setIsTokenMenuOpen(false)}
|
||||
onTokenStateChange={onMapTokenStateChange}
|
||||
tokenState={mapState && mapState.tokens[tokenMenuOptions.tokenStateId]}
|
||||
tokenImage={tokenMenuOptions.tokenImage}
|
||||
map={map}
|
||||
/>
|
||||
);
|
||||
|
||||
const tokenDragOverlay = tokenDraggingOptions && (
|
||||
<TokenDragOverlay
|
||||
onTokenStateRemove={(state: any) => {
|
||||
onMapTokenStateRemove(state);
|
||||
setTokenDraggingOptions(null);
|
||||
}}
|
||||
onTokenStateChange={onMapTokenStateChange}
|
||||
tokenState={tokenDraggingOptions && tokenDraggingOptions.tokenState}
|
||||
tokenGroup={tokenDraggingOptions && tokenDraggingOptions.tokenGroup}
|
||||
dragging={!!(tokenDraggingOptions && tokenDraggingOptions.dragging)}
|
||||
token={tokensById[tokenDraggingOptions.tokenState.tokenId]}
|
||||
/>
|
||||
);
|
||||
|
||||
const mapDrawing = (
|
||||
<MapDrawing
|
||||
map={map}
|
||||
shapes={drawShapes}
|
||||
onShapeAdd={handleMapShapeAdd}
|
||||
onShapesRemove={handleMapShapesRemove}
|
||||
active={selectedToolId === "drawing"}
|
||||
toolSettings={settings.drawing}
|
||||
/>
|
||||
);
|
||||
|
||||
const mapFog = (
|
||||
<MapFog
|
||||
map={map}
|
||||
shapes={fogShapes}
|
||||
onShapesAdd={handleFogShapesAdd}
|
||||
onShapesCut={handleFogShapesCut}
|
||||
onShapesRemove={handleFogShapesRemove}
|
||||
onShapesEdit={handleFogShapesEdit}
|
||||
active={selectedToolId === "fog"}
|
||||
toolSettings={settings.fog}
|
||||
editable={allowFogDrawing && !settings.fog.preview}
|
||||
/>
|
||||
);
|
||||
|
||||
const mapGrid = map && map.showGrid && <MapGrid map={map} />;
|
||||
|
||||
const mapMeasure = (
|
||||
<MapMeasure
|
||||
map={map}
|
||||
active={selectedToolId === "measure"}
|
||||
/>
|
||||
);
|
||||
|
||||
const mapPointer = (
|
||||
<NetworkedMapPointer
|
||||
active={selectedToolId === "pointer"}
|
||||
session={session}
|
||||
/>
|
||||
);
|
||||
|
||||
const [isNoteMenuOpen, setIsNoteMenuOpen] = useState<boolean>(false);
|
||||
const [noteMenuOptions, setNoteMenuOptions] = useState<any>({});
|
||||
const [noteDraggingOptions, setNoteDraggingOptions]= useState<any>();
|
||||
function handleNoteMenuOpen(noteId: string, noteNode: any) {
|
||||
setNoteMenuOptions({ noteId, noteNode });
|
||||
setIsNoteMenuOpen(true);
|
||||
}
|
||||
|
||||
function sortNotes(a: any, b: any, noteDraggingOptions: any) {
|
||||
if (
|
||||
noteDraggingOptions &&
|
||||
noteDraggingOptions.dragging &&
|
||||
noteDraggingOptions.noteId === a.id
|
||||
) {
|
||||
// If dragging token `a` move above
|
||||
return 1;
|
||||
} else if (
|
||||
noteDraggingOptions &&
|
||||
noteDraggingOptions.dragging &&
|
||||
noteDraggingOptions.noteId === b.id
|
||||
) {
|
||||
// If dragging token `b` move above
|
||||
return -1;
|
||||
} else {
|
||||
// Else sort so last modified is on top
|
||||
return a.lastModified - b.lastModified;
|
||||
}
|
||||
}
|
||||
|
||||
const mapNotes = (
|
||||
<MapNotes
|
||||
map={map}
|
||||
active={selectedToolId === "note"}
|
||||
onNoteAdd={onMapNoteChange}
|
||||
onNoteChange={onMapNoteChange}
|
||||
notes={
|
||||
mapState
|
||||
? Object.values(mapState.notes).sort((a, b) =>
|
||||
sortNotes(a, b, noteDraggingOptions)
|
||||
)
|
||||
: []
|
||||
}
|
||||
onNoteMenuOpen={handleNoteMenuOpen}
|
||||
draggable={
|
||||
allowNoteEditing &&
|
||||
(selectedToolId === "note" || selectedToolId === "move")
|
||||
}
|
||||
onNoteDragStart={(e: any, noteId: any) =>
|
||||
setNoteDraggingOptions({ dragging: true, noteId, noteGroup: e.target })
|
||||
}
|
||||
onNoteDragEnd={() =>
|
||||
setNoteDraggingOptions({ ...noteDraggingOptions, dragging: false })
|
||||
}
|
||||
fadeOnHover={selectedToolId === "drawing"}
|
||||
/>
|
||||
);
|
||||
|
||||
const noteMenu = (
|
||||
<NoteMenu
|
||||
isOpen={isNoteMenuOpen}
|
||||
onRequestClose={() => setIsNoteMenuOpen(false)}
|
||||
onNoteChange={onMapNoteChange}
|
||||
note={mapState && mapState.notes[noteMenuOptions.noteId]}
|
||||
noteNode={noteMenuOptions.noteNode}
|
||||
map={map}
|
||||
/>
|
||||
);
|
||||
|
||||
const noteDragOverlay = (
|
||||
<NoteDragOverlay
|
||||
dragging={!!(noteDraggingOptions && noteDraggingOptions.dragging)}
|
||||
noteGroup={noteDraggingOptions && noteDraggingOptions.noteGroup}
|
||||
noteId={noteDraggingOptions && noteDraggingOptions.noteId}
|
||||
onNoteRemove={(noteId: any) => {
|
||||
onMapNoteRemove(noteId);
|
||||
setNoteDraggingOptions(null);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<MapInteraction
|
||||
map={map}
|
||||
mapState={mapState}
|
||||
controls={
|
||||
<>
|
||||
{mapControls}
|
||||
{tokenMenu}
|
||||
{noteMenu}
|
||||
{tokenDragOverlay}
|
||||
{noteDragOverlay}
|
||||
</>
|
||||
}
|
||||
selectedToolId={selectedToolId}
|
||||
onSelectedToolChange={setSelectedToolId}
|
||||
disabledControls={disabledControls}
|
||||
>
|
||||
{mapGrid}
|
||||
{mapDrawing}
|
||||
{mapNotes}
|
||||
{mapTokens}
|
||||
{mapFog}
|
||||
{mapPointer}
|
||||
{mapMeasure}
|
||||
</MapInteraction>
|
||||
);
|
||||
}
|
||||
|
||||
export default Map;
|
||||
Reference in New Issue
Block a user