diff --git a/src/components/Grid.js b/src/components/Grid.js
index 9dda566..9eded3d 100644
--- a/src/components/Grid.js
+++ b/src/components/Grid.js
@@ -1,50 +1,43 @@
import React from "react";
import { Line, Group, RegularPolygon } from "react-konva";
-import { getStrokeWidth } from "../helpers/drawing";
import {
- getCellSize,
getCellLocation,
gridClipFunction,
shouldClipCell,
} from "../helpers/grid";
-function Grid({ grid, strokeWidth, width, height, stroke }) {
+import { useGrid } from "../contexts/GridContext";
+
+function Grid({ strokeWidth, stroke }) {
+ const {
+ grid,
+ gridStrokeWidth,
+ gridPixelSize,
+ gridOffset,
+ gridCellPixelSize,
+ } = useGrid();
+
if (!grid?.size.x || !grid?.size.y) {
return null;
}
- const gridSizeNormalized = {
- x: (grid.inset.bottomRight.x - grid.inset.topLeft.x) / grid.size.x,
- y: (grid.inset.bottomRight.y - grid.inset.topLeft.y) / grid.size.y,
- };
-
- const insetWidth = (grid.inset.bottomRight.x - grid.inset.topLeft.x) * width;
- const insetHeight =
- (grid.inset.bottomRight.y - grid.inset.topLeft.y) * height;
-
- const offsetX = grid.inset.topLeft.x * width * -1;
- const offsetY = grid.inset.topLeft.y * height * -1;
-
- const cellSize = getCellSize(grid, insetWidth, insetHeight);
-
const shapes = [];
if (grid.type === "square") {
for (let x = 1; x < grid.size.x; x++) {
shapes.push(
);
}
@@ -52,17 +45,16 @@ function Grid({ grid, strokeWidth, width, height, stroke }) {
shapes.push(
);
}
@@ -70,29 +62,24 @@ function Grid({ grid, strokeWidth, width, height, stroke }) {
// Start at -1 to overshoot the bounds of the grid to ensure all lines are drawn
for (let x = -1; x < grid.size.x; x++) {
for (let y = -1; y < grid.size.y; y++) {
- const cellLocation = getCellLocation(grid, x, y, cellSize);
+ const cellLocation = getCellLocation(grid, x, y, gridCellPixelSize);
shapes.push(
gridClipFunction(context, grid, x, y, cellSize))
+ ((context) =>
+ gridClipFunction(context, grid, x, y, gridCellPixelSize))
}
x={cellLocation.x}
y={cellLocation.y}
- offsetX={offsetX}
- offsetY={offsetY}
+ offset={gridOffset}
>
diff --git a/src/components/dice/DiceTrayOverlay.js b/src/components/dice/DiceTrayOverlay.js
index ce78dce..62028a3 100644
--- a/src/components/dice/DiceTrayOverlay.js
+++ b/src/components/dice/DiceTrayOverlay.js
@@ -1,10 +1,4 @@
-import React, {
- useRef,
- useCallback,
- useEffect,
- useContext,
- useState,
-} from "react";
+import React, { useRef, useCallback, useEffect, useState } from "react";
import { Vector3 } from "@babylonjs/core/Maths/math";
import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight";
import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator";
@@ -21,7 +15,7 @@ import DiceResults from "./DiceResults";
import DiceTray from "../../dice/diceTray/DiceTray";
-import DiceLoadingContext from "../../contexts/DiceLoadingContext";
+import { useDiceLoading } from "../../contexts/DiceLoadingContext";
import { getDiceRoll } from "../../helpers/dice";
import useSetting from "../../hooks/useSetting";
@@ -43,9 +37,7 @@ function DiceTrayOverlay({
const diceTrayRef = useRef();
const [diceTraySize, setDiceTraySize] = useState("single");
- const { assetLoadStart, assetLoadFinish, isLoading } = useContext(
- DiceLoadingContext
- );
+ const { assetLoadStart, assetLoadFinish, isLoading } = useDiceLoading();
const [fullScreen] = useSetting("map.fullScreen");
function handleAssetLoadStart() {
diff --git a/src/components/map/Map.js b/src/components/map/Map.js
index edae871..6c06d5d 100644
--- a/src/components/map/Map.js
+++ b/src/components/map/Map.js
@@ -1,4 +1,4 @@
-import React, { useState, useContext } from "react";
+import React, { useState } from "react";
import { Group } from "react-konva";
import MapControls from "./MapControls";
@@ -11,8 +11,8 @@ import MapMeasure from "./MapMeasure";
import NetworkedMapPointer from "../../network/NetworkedMapPointer";
import MapNotes from "./MapNotes";
-import TokenDataContext from "../../contexts/TokenDataContext";
-import SettingsContext from "../../contexts/SettingsContext";
+import { useTokenData } from "../../contexts/TokenDataContext";
+import { useSettings } from "../../contexts/SettingsContext";
import TokenMenu from "../token/TokenMenu";
import TokenDragOverlay from "../token/TokenDragOverlay";
@@ -49,19 +49,10 @@ function Map({
disabledTokens,
session,
}) {
- const { tokensById } = useContext(TokenDataContext);
-
- const gridX = map && map.grid.size.x;
- const gridY = map && map.grid.size.y;
- const inset = map && map.grid.inset;
- const gridSizeNormalized = {
- x: gridX ? (inset.bottomRight.x - inset.topLeft.x) / gridX : 0,
- y: gridY ? (inset.bottomRight.y - inset.topLeft.y) / gridY : 0,
- };
- const tokenSizePercent = gridSizeNormalized.x;
+ const { tokensById } = useTokenData();
const [selectedToolId, setSelectedToolId] = useState("pan");
- const { settings, setSettings } = useContext(SettingsContext);
+ const { settings, setSettings } = useSettings();
function handleToolSettingChange(tool, change) {
setSettings((prevSettings) => ({
@@ -243,7 +234,6 @@ function Map({
key={tokenState.id}
token={tokensById[tokenState.tokenId]}
tokenState={tokenState}
- tokenSizePercent={tokenSizePercent}
onTokenStateChange={onMapTokenStateChange}
onTokenMenuOpen={handleTokenMenuOpen}
onTokenDragStart={(e) =>
@@ -306,7 +296,6 @@ function Map({
onShapesRemove={handleMapShapesRemove}
active={selectedToolId === "drawing"}
toolSettings={settings.drawing}
- gridSize={gridSizeNormalized}
/>
);
@@ -320,7 +309,6 @@ function Map({
onShapesEdit={handleFogShapesEdit}
active={selectedToolId === "fog"}
toolSettings={settings.fog}
- gridSize={gridSizeNormalized}
editable={allowFogDrawing && !settings.fog.preview}
/>
);
@@ -331,7 +319,6 @@ function Map({
);
@@ -339,7 +326,6 @@ function Map({
const mapPointer = (
);
@@ -377,7 +363,6 @@ function Map({
);
@@ -239,12 +237,7 @@ function MapDrawing({
(acc, point) => [...acc, point.x * mapWidth, point.y * mapHeight],
[]
)}
- strokeWidth={getStrokeWidth(
- shape.strokeWidth,
- gridSize,
- mapWidth,
- mapHeight
- )}
+ strokeWidth={gridStrokeWidth * shape.strokeWidth}
stroke={colors[shape.color] || shape.color}
lineCap="round"
{...defaultProps}
diff --git a/src/components/map/MapEditor.js b/src/components/map/MapEditor.js
index 5744a78..134d55f 100644
--- a/src/components/map/MapEditor.js
+++ b/src/components/map/MapEditor.js
@@ -13,6 +13,7 @@ import { getGridDefaultInset, getGridMaxZoom } from "../../helpers/grid";
import { MapInteractionProvider } from "../../contexts/MapInteractionContext";
import KeyboardContext from "../../contexts/KeyboardContext";
+import { GridProvider } from "../../contexts/GridContext";
import ResetMapIcon from "../../icons/ResetMapIcon";
import GridOnIcon from "../../icons/GridOnIcon";
@@ -130,10 +131,14 @@ function MapEditor({ map, onSettingsChange }) {
{showGridControls && canEditGrid && (
- <>
+
- >
+
)}
diff --git a/src/components/map/MapFog.js b/src/components/map/MapFog.js
index ae7209b..c66d7c7 100644
--- a/src/components/map/MapFog.js
+++ b/src/components/map/MapFog.js
@@ -1,30 +1,24 @@
-import React, {
- useContext,
- useState,
- useEffect,
- useCallback,
- useRef,
-} from "react";
+import React, { useState, useEffect, useCallback, useRef } from "react";
import shortid from "shortid";
import { Group, Rect } from "react-konva";
import useImage from "use-image";
import diagonalPattern from "../../images/DiagonalPattern.png";
-import MapInteractionContext from "../../contexts/MapInteractionContext";
-import MapStageContext from "../../contexts/MapStageContext";
+import { useMapInteraction } from "../../contexts/MapInteractionContext";
+import { useMapStage } from "../../contexts/MapStageContext";
+import { useGrid } from "../../contexts/GridContext";
+import { useKeyboard } from "../../contexts/KeyboardContext";
import Vector2 from "../../helpers/Vector2";
import {
getFogBrushPosition,
simplifyPoints,
- getStrokeWidth,
mergeShapes,
} from "../../helpers/drawing";
import colors from "../../helpers/colors";
import { HoleyLine, Tick } from "../../helpers/konva";
-import useKeyboard from "../../hooks/useKeyboard";
import useDebounce from "../../hooks/useDebounce";
function MapFog({
@@ -36,13 +30,17 @@ function MapFog({
onShapesEdit,
active,
toolSettings,
- gridSize,
editable,
}) {
- const { stageScale, mapWidth, mapHeight, interactionEmitter } = useContext(
- MapInteractionContext
- );
- const mapStageRef = useContext(MapStageContext);
+ const {
+ stageScale,
+ mapWidth,
+ mapHeight,
+ interactionEmitter,
+ } = useMapInteraction();
+ const { gridCellNormalizedSize, gridStrokeWidth } = useGrid();
+ const mapStageRef = useMapStage();
+
const [drawingShape, setDrawingShape] = useState(null);
const [isBrushDown, setIsBrushDown] = useState(false);
const [editingShapes, setEditingShapes] = useState([]);
@@ -70,7 +68,7 @@ function MapFog({
map,
mapStage,
useGridSnapping,
- gridSize,
+ gridCellNormalizedSize,
toolSettings.useEdgeSnapping,
shapes
);
@@ -114,7 +112,7 @@ function MapFog({
map,
mapStage,
useGridSnapping,
- gridSize,
+ gridCellNormalizedSize,
toolSettings.useEdgeSnapping,
shapes
);
@@ -144,7 +142,7 @@ function MapFog({
map,
mapStage,
useGridSnapping,
- gridSize,
+ gridCellNormalizedSize,
toolSettings.useEdgeSnapping,
shapes,
prevPoints
@@ -185,7 +183,7 @@ function MapFog({
...drawingShape.data,
points: simplifyPoints(
drawingShape.data.points,
- gridSize,
+ gridCellNormalizedSize,
// Downscale fog as smoothing doesn't currently work with edge snapping
stageScale / 2
),
@@ -211,7 +209,7 @@ function MapFog({
map,
mapStage,
useGridSnapping,
- gridSize,
+ gridCellNormalizedSize,
toolSettings.useEdgeSnapping,
shapes
);
@@ -247,7 +245,7 @@ function MapFog({
map,
mapStage,
useGridSnapping,
- gridSize,
+ gridCellNormalizedSize,
toolSettings.useEdgeSnapping,
shapes
);
@@ -378,12 +376,7 @@ function MapFog({
closed
lineCap="round"
lineJoin="round"
- strokeWidth={getStrokeWidth(
- shape.strokeWidth,
- gridSize,
- mapWidth,
- mapHeight
- )}
+ strokeWidth={gridStrokeWidth * shape.strokeWidth}
opacity={editable ? 0.5 : 1}
fillPatternImage={patternImage}
fillPriority={active && !shape.visible ? "pattern" : "color"}
diff --git a/src/components/map/MapGrid.js b/src/components/map/MapGrid.js
index 4e7a2b1..119eb6e 100644
--- a/src/components/map/MapGrid.js
+++ b/src/components/map/MapGrid.js
@@ -1,8 +1,6 @@
-import React, { useContext, useEffect, useState } from "react";
+import React, { useEffect, useState } from "react";
import useImage from "use-image";
-import MapInteractionContext from "../../contexts/MapInteractionContext";
-
import useDataSource from "../../hooks/useDataSource";
import { mapSources as defaultMapSources } from "../../maps";
@@ -11,8 +9,6 @@ import { getImageLightness } from "../../helpers/image";
import Grid from "../Grid";
function MapGrid({ map, strokeWidth }) {
- const { mapWidth, mapHeight } = useContext(MapInteractionContext);
-
let mapSourceMap = map;
// Use lowest resolution for grid lightness
if (map && map.type === "file" && map.resolutions) {
@@ -34,13 +30,7 @@ function MapGrid({ map, strokeWidth }) {
}, [mapImage, mapLoadingStatus]);
return (
-
+
);
}
diff --git a/src/components/map/MapGridEditor.js b/src/components/map/MapGridEditor.js
index 6a2e689..a138442 100644
--- a/src/components/map/MapGridEditor.js
+++ b/src/components/map/MapGridEditor.js
@@ -1,19 +1,18 @@
-import React, { useContext, useRef } from "react";
+import React, { useRef } from "react";
import { Group, Circle, Rect } from "react-konva";
-import MapInteractionContext from "../../contexts/MapInteractionContext";
+import { useMapInteraction } from "../../contexts/MapInteractionContext";
+import { useKeyboard } from "../../contexts/KeyboardContext";
import Vector2 from "../../helpers/Vector2";
-import useKeyboard from "../../hooks/useKeyboard";
-
function MapGridEditor({ map, onGridChange }) {
const {
mapWidth,
mapHeight,
stageScale,
setPreventMapInteraction,
- } = useContext(MapInteractionContext);
+ } = useMapInteraction();
const mapSize = { x: mapWidth, y: mapHeight };
diff --git a/src/components/map/MapInteraction.js b/src/components/map/MapInteraction.js
index d6b865d..ce2fd31 100644
--- a/src/components/map/MapInteraction.js
+++ b/src/components/map/MapInteraction.js
@@ -6,19 +6,18 @@ import { EventEmitter } from "events";
import useMapImage from "../../hooks/useMapImage";
import usePreventOverscroll from "../../hooks/usePreventOverscroll";
-import useKeyboard from "../../hooks/useKeyboard";
import useStageInteraction from "../../hooks/useStageInteraction";
import useImageCenter from "../../hooks/useImageCenter";
import { getGridMaxZoom } from "../../helpers/grid";
import { MapInteractionProvider } from "../../contexts/MapInteractionContext";
-import MapStageContext, {
- MapStageProvider,
-} from "../../contexts/MapStageContext";
-import AuthContext from "../../contexts/AuthContext";
-import SettingsContext from "../../contexts/SettingsContext";
+import { MapStageProvider, useMapStage } from "../../contexts/MapStageContext";
+import AuthContext, { useAuth } from "../../contexts/AuthContext";
+import SettingsContext, { useSettings } from "../../contexts/SettingsContext";
import KeyboardContext from "../../contexts/KeyboardContext";
+import { GridProvider } from "../../contexts/GridContext";
+import { useKeyboard } from "../../contexts/KeyboardContext";
function MapInteraction({
map,
@@ -53,7 +52,7 @@ function MapInteraction({
// Avoid state udpates when panning the map by using a ref and updating the konva element directly
const stageTranslateRef = useRef({ x: 0, y: 0 });
- const mapStageRef = useContext(MapStageContext);
+ const mapStageRef = useMapStage();
const mapLayerRef = useRef();
const mapImageRef = useRef();
@@ -177,8 +176,8 @@ function MapInteraction({
}
}
- const auth = useContext(AuthContext);
- const settings = useContext(SettingsContext);
+ const auth = useAuth();
+ const settings = useSettings();
const mapInteraction = {
stageScale,
@@ -223,9 +222,15 @@ function MapInteraction({
-
- {mapLoaded && children}
-
+
+
+ {mapLoaded && children}
+
+
@@ -234,7 +239,9 @@ function MapInteraction({
- {controls}
+
+ {controls}
+
);
diff --git a/src/components/map/MapLoadingOverlay.js b/src/components/map/MapLoadingOverlay.js
index da9661a..e3b77b6 100644
--- a/src/components/map/MapLoadingOverlay.js
+++ b/src/components/map/MapLoadingOverlay.js
@@ -1,12 +1,12 @@
-import React, { useContext } from "react";
+import React from "react";
import { Box } from "theme-ui";
-import MapLoadingContext from "../../contexts/MapLoadingContext";
+import { useMapLoading } from "../../contexts/MapLoadingContext";
import LoadingBar from "../LoadingBar";
function MapLoadingOverlay() {
- const { isLoading, loadingProgressRef } = useContext(MapLoadingContext);
+ const { isLoading, loadingProgressRef } = useMapLoading();
return (
isLoading && (
diff --git a/src/components/map/MapMeasure.js b/src/components/map/MapMeasure.js
index 49e8d7e..169e91f 100644
--- a/src/components/map/MapMeasure.js
+++ b/src/components/map/MapMeasure.js
@@ -1,22 +1,26 @@
-import React, { useContext, useState, useEffect } from "react";
+import React, { useState, useEffect } from "react";
import { Group, Line, Text, Label, Tag } from "react-konva";
-import MapInteractionContext from "../../contexts/MapInteractionContext";
-import MapStageContext from "../../contexts/MapStageContext";
+import { useMapInteraction } from "../../contexts/MapInteractionContext";
+import { useMapStage } from "../../contexts/MapStageContext";
+import { useGrid } from "../../contexts/GridContext";
import {
getBrushPosition,
getDefaultShapeData,
getUpdatedShapeData,
- getStrokeWidth,
} from "../../helpers/drawing";
import Vector2 from "../../helpers/Vector2";
-function MapMeasure({ map, selectedToolSettings, active, gridSize }) {
- const { stageScale, mapWidth, mapHeight, interactionEmitter } = useContext(
- MapInteractionContext
- );
- const mapStageRef = useContext(MapStageContext);
+function MapMeasure({ map, selectedToolSettings, active }) {
+ const {
+ stageScale,
+ mapWidth,
+ mapHeight,
+ interactionEmitter,
+ } = useMapInteraction();
+ const { gridCellNormalizedSize, gridStrokeWidth } = useGrid();
+ const mapStageRef = useMapStage();
const [drawingShapeData, setDrawingShapeData] = useState(null);
const [isBrushDown, setIsBrushDown] = useState(false);
@@ -52,7 +56,7 @@ function MapMeasure({ map, selectedToolSettings, active, gridSize }) {
map,
mapStage,
map.snapToGrid,
- gridSize
+ gridCellNormalizedSize
);
const { points } = getDefaultShapeData("line", brushPosition);
const length = 0;
@@ -65,20 +69,26 @@ function MapMeasure({ map, selectedToolSettings, active, gridSize }) {
map,
mapStage,
map.snapToGrid,
- gridSize
+ gridCellNormalizedSize
);
if (isBrushDown && drawingShapeData) {
const { points } = getUpdatedShapeData(
"line",
drawingShapeData,
brushPosition,
- gridSize
+ gridCellNormalizedSize
);
// Round the grid positions to the nearest 0.1 to aviod floating point issues
const precision = { x: 0.1, y: 0.1 };
const length = Vector2.distance(
- Vector2.roundTo(Vector2.divide(points[0], gridSize), precision),
- Vector2.roundTo(Vector2.divide(points[1], gridSize), precision),
+ Vector2.roundTo(
+ Vector2.divide(points[0], gridCellNormalizedSize),
+ precision
+ ),
+ Vector2.roundTo(
+ Vector2.divide(points[1], gridCellNormalizedSize),
+ precision
+ ),
selectedToolSettings.type
);
setDrawingShapeData({
@@ -119,13 +129,13 @@ function MapMeasure({ map, selectedToolSettings, active, gridSize }) {
diff --git a/src/components/map/MapNotes.js b/src/components/map/MapNotes.js
index 82fb68d..4c60e13 100644
--- a/src/components/map/MapNotes.js
+++ b/src/components/map/MapNotes.js
@@ -1,10 +1,11 @@
-import React, { useContext, useState, useEffect, useRef } from "react";
+import React, { useState, useEffect, useRef } from "react";
import shortid from "shortid";
import { Group } from "react-konva";
-import MapInteractionContext from "../../contexts/MapInteractionContext";
-import MapStageContext from "../../contexts/MapStageContext";
-import AuthContext from "../../contexts/AuthContext";
+import { useMapInteraction } from "../../contexts/MapInteractionContext";
+import { useMapStage } from "../../contexts/MapStageContext";
+import { useAuth } from "../../contexts/AuthContext";
+import { useGrid } from "../../contexts/GridContext";
import { getBrushPosition } from "../../helpers/drawing";
@@ -15,7 +16,6 @@ const defaultNoteSize = 2;
function MapNotes({
map,
active,
- gridSize,
onNoteAdd,
onNoteChange,
notes,
@@ -25,9 +25,10 @@ function MapNotes({
onNoteDragEnd,
fadeOnHover,
}) {
- const { interactionEmitter } = useContext(MapInteractionContext);
- const { userId } = useContext(AuthContext);
- const mapStageRef = useContext(MapStageContext);
+ const { interactionEmitter } = useMapInteraction();
+ const { userId } = useAuth();
+ const { gridCellNormalizedSize } = useGrid();
+ const mapStageRef = useMapStage();
const [isBrushDown, setIsBrushDown] = useState(false);
const [noteData, setNoteData] = useState(null);
@@ -44,7 +45,7 @@ function MapNotes({
map,
mapStage,
map.snapToGrid,
- gridSize
+ gridCellNormalizedSize
);
setNoteData({
x: brushPosition.x,
@@ -68,7 +69,7 @@ function MapNotes({
map,
mapStage,
map.snapToGrid,
- gridSize
+ gridCellNormalizedSize
);
setNoteData((prev) => ({
...prev,
diff --git a/src/components/map/MapPointer.js b/src/components/map/MapPointer.js
index 6069f42..952ff11 100644
--- a/src/components/map/MapPointer.js
+++ b/src/components/map/MapPointer.js
@@ -1,10 +1,10 @@
-import React, { useContext, useEffect } from "react";
+import React, { useEffect } from "react";
import { Group } from "react-konva";
-import MapInteractionContext from "../../contexts/MapInteractionContext";
-import MapStageContext from "../../contexts/MapStageContext";
+import { useMapInteraction } from "../../contexts/MapInteractionContext";
+import { useMapStage } from "../../contexts/MapStageContext";
+import { useGrid } from "../../contexts/GridContext";
-import { getStrokeWidth } from "../../helpers/drawing";
import {
getRelativePointerPositionNormalized,
Trail,
@@ -14,7 +14,6 @@ import Vector2 from "../../helpers/Vector2";
import colors from "../../helpers/colors";
function MapPointer({
- gridSize,
active,
position,
onPointerDown,
@@ -23,10 +22,9 @@ function MapPointer({
visible,
color,
}) {
- const { mapWidth, mapHeight, interactionEmitter } = useContext(
- MapInteractionContext
- );
- const mapStageRef = useContext(MapStageContext);
+ const { mapWidth, mapHeight, interactionEmitter } = useMapInteraction();
+ const { gridStrokeWidth } = useGrid();
+ const mapStageRef = useMapStage();
useEffect(() => {
if (!active) {
@@ -63,7 +61,7 @@ function MapPointer({
};
});
- const size = getStrokeWidth(2, gridSize, mapWidth, mapHeight);
+ const size = 2 * gridStrokeWidth;
return (
diff --git a/src/components/map/MapTiles.js b/src/components/map/MapTiles.js
index 3aec65b..3b86589 100644
--- a/src/components/map/MapTiles.js
+++ b/src/components/map/MapTiles.js
@@ -1,4 +1,4 @@
-import React, { useContext } from "react";
+import React from "react";
import { Flex, Box, Text, IconButton, Close, Label } from "theme-ui";
import SimpleBar from "simplebar-react";
import Case from "case";
@@ -11,7 +11,7 @@ import MapTile from "./MapTile";
import Link from "../Link";
import FilterBar from "../FilterBar";
-import DatabaseContext from "../../contexts/DatabaseContext";
+import { useDatabase } from "../../contexts/DatabaseContext";
import useResponsiveLayout from "../../hooks/useResponsiveLayout";
@@ -32,7 +32,7 @@ function MapTiles({
onSearchChange,
onMapsGroup,
}) {
- const { databaseStatus } = useContext(DatabaseContext);
+ const { databaseStatus } = useDatabase();
const layout = useResponsiveLayout();
let hasMapState = false;
diff --git a/src/components/map/MapToken.js b/src/components/map/MapToken.js
index eccc1a1..c3e3dfd 100644
--- a/src/components/map/MapToken.js
+++ b/src/components/map/MapToken.js
@@ -1,4 +1,4 @@
-import React, { useContext, useState, useEffect, useRef } from "react";
+import React, { useState, useEffect, useRef } from "react";
import { Image as KonvaImage, Group } from "react-konva";
import { useSpring, animated } from "react-spring/konva";
import useImage from "use-image";
@@ -10,8 +10,9 @@ import usePrevious from "../../hooks/usePrevious";
import { snapNodeToGrid } from "../../helpers/grid";
-import AuthContext from "../../contexts/AuthContext";
-import MapInteractionContext from "../../contexts/MapInteractionContext";
+import { useAuth } from "../../contexts/AuthContext";
+import { useMapInteraction } from "../../contexts/MapInteractionContext";
+import { useGrid } from "../../contexts/GridContext";
import TokenStatus from "../token/TokenStatus";
import TokenLabel from "../token/TokenLabel";
@@ -23,7 +24,6 @@ const snappingThreshold = 1 / 7;
function MapToken({
token,
tokenState,
- tokenSizePercent,
onTokenStateChange,
onTokenMenuOpen,
onTokenDragStart,
@@ -33,13 +33,14 @@ function MapToken({
fadeOnHover,
map,
}) {
- const { userId } = useContext(AuthContext);
+ const { userId } = useAuth();
const {
setPreventMapInteraction,
mapWidth,
mapHeight,
stageScale,
- } = useContext(MapInteractionContext);
+ } = useMapInteraction();
+ const { gridCellPixelSize } = useGrid();
const tokenSource = useDataSource(token, tokenSources, unknownSource);
const [tokenSourceImage, tokenSourceStatus] = useImage(tokenSource);
@@ -182,9 +183,9 @@ function MapToken({
}
}
- const tokenWidth = tokenSizePercent * mapWidth * tokenState.size;
+ const tokenWidth = gridCellPixelSize.width * tokenState.size;
const tokenHeight =
- tokenSizePercent * (mapWidth / tokenAspectRatio) * tokenState.size;
+ (gridCellPixelSize.width / tokenAspectRatio) * tokenState.size;
const debouncedStageScale = useDebounce(stageScale, 50);
const imageRef = useRef();
diff --git a/src/components/map/SelectMapButton.js b/src/components/map/SelectMapButton.js
index 7bf63b8..8484ee9 100644
--- a/src/components/map/SelectMapButton.js
+++ b/src/components/map/SelectMapButton.js
@@ -1,11 +1,11 @@
-import React, { useState, useContext } from "react";
+import React, { useState } from "react";
import { IconButton } from "theme-ui";
import SelectMapModal from "../../modals/SelectMapModal";
import SelectMapIcon from "../../icons/SelectMapIcon";
-import MapDataContext from "../../contexts/MapDataContext";
-import AuthContext from "../../contexts/AuthContext";
+import { useMapData } from "../../contexts/MapDataContext";
+import { useAuth } from "../../contexts/AuthContext";
function SelectMapButton({
onMapChange,
@@ -16,8 +16,8 @@ function SelectMapButton({
}) {
const [isModalOpen, setIsModalOpen] = useState(false);
- const { updateMapState } = useContext(MapDataContext);
- const { userId } = useContext(AuthContext);
+ const { updateMapState } = useMapData();
+ const { userId } = useAuth();
function openModal() {
if (currentMapState && currentMap && currentMap.owner === userId) {
updateMapState(currentMapState.mapId, currentMapState);
diff --git a/src/components/map/controls/DrawingToolSettings.js b/src/components/map/controls/DrawingToolSettings.js
index 4c79b81..429766b 100644
--- a/src/components/map/controls/DrawingToolSettings.js
+++ b/src/components/map/controls/DrawingToolSettings.js
@@ -22,7 +22,7 @@ import RedoButton from "./RedoButton";
import Divider from "../../Divider";
-import useKeyboard from "../../../hooks/useKeyboard";
+import { useKeyboard } from "../../../contexts/KeyboardContext";
function DrawingToolSettings({
settings,
diff --git a/src/components/map/controls/FogToolSettings.js b/src/components/map/controls/FogToolSettings.js
index dc67012..acdf51f 100644
--- a/src/components/map/controls/FogToolSettings.js
+++ b/src/components/map/controls/FogToolSettings.js
@@ -20,7 +20,7 @@ import ToolSection from "./ToolSection";
import Divider from "../../Divider";
-import useKeyboard from "../../../hooks/useKeyboard";
+import { useKeyboard } from "../../../contexts/KeyboardContext";
function BrushToolSettings({
settings,
diff --git a/src/components/map/controls/MeasureToolSettings.js b/src/components/map/controls/MeasureToolSettings.js
index cd24d2b..e1a7a18 100644
--- a/src/components/map/controls/MeasureToolSettings.js
+++ b/src/components/map/controls/MeasureToolSettings.js
@@ -9,7 +9,7 @@ import MeasureAlternatingIcon from "../../../icons/MeasureAlternatingIcon";
import Divider from "../../Divider";
-import useKeyboard from "../../../hooks/useKeyboard";
+import { useKeyboard } from "../../../contexts/KeyboardContext";
function MeasureToolSettings({ settings, onSettingChange }) {
// Keyboard shortcuts
diff --git a/src/components/note/Note.js b/src/components/note/Note.js
index d096275..1005286 100644
--- a/src/components/note/Note.js
+++ b/src/components/note/Note.js
@@ -1,9 +1,10 @@
-import React, { useContext, useEffect, useState, useRef } from "react";
+import React, { useEffect, useState, useRef } from "react";
import { Rect, Text } from "react-konva";
import { useSpring, animated } from "react-spring/konva";
-import AuthContext from "../../contexts/AuthContext";
-import MapInteractionContext from "../../contexts/MapInteractionContext";
+import { useAuth } from "../../contexts/AuthContext";
+import { useMapInteraction } from "../../contexts/MapInteractionContext";
+import { useGrid } from "../../contexts/GridContext";
import { snapNodeToGrid } from "../../helpers/grid";
import colors from "../../helpers/colors";
@@ -22,12 +23,11 @@ function Note({
onNoteDragEnd,
fadeOnHover,
}) {
- const { userId } = useContext(AuthContext);
- const { mapWidth, mapHeight, setPreventMapInteraction } = useContext(
- MapInteractionContext
- );
+ const { userId } = useAuth();
+ const { mapWidth, mapHeight, setPreventMapInteraction } = useMapInteraction();
+ const { gridCellPixelSize } = useGrid();
- const noteWidth = map && (mapWidth / map.grid.size.x) * note.size;
+ const noteWidth = gridCellPixelSize.width * note.size;
const noteHeight = noteWidth;
const notePadding = noteWidth / 10;
diff --git a/src/components/note/NoteMenu.js b/src/components/note/NoteMenu.js
index 7d5bc38..9d30af0 100644
--- a/src/components/note/NoteMenu.js
+++ b/src/components/note/NoteMenu.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState, useContext } from "react";
+import React, { useEffect, useState } from "react";
import { Box, Flex, Text, IconButton, Textarea } from "theme-ui";
import Slider from "../Slider";
@@ -16,7 +16,7 @@ import HideIcon from "../../icons/TokenHideIcon";
import NoteIcon from "../../icons/NoteToolIcon";
import TextIcon from "../../icons/NoteTextIcon";
-import AuthContext from "../../contexts/AuthContext";
+import { useAuth } from "../../contexts/AuthContext";
const defaultNoteMaxSize = 6;
@@ -28,7 +28,7 @@ function NoteMenu({
onNoteChange,
map,
}) {
- const { userId } = useContext(AuthContext);
+ const { userId } = useAuth();
const wasOpen = usePrevious(isOpen);
diff --git a/src/components/party/Party.js b/src/components/party/Party.js
index c81edd2..8e58feb 100644
--- a/src/components/party/Party.js
+++ b/src/components/party/Party.js
@@ -1,4 +1,4 @@
-import React, { useContext, useEffect } from "react";
+import React, { useEffect } from "react";
import { Flex, Box, Text } from "theme-ui";
import SimpleBar from "simplebar-react";
@@ -13,16 +13,13 @@ import DiceTrayButton from "./DiceTrayButton";
import useSetting from "../../hooks/useSetting";
-import PartyContext from "../../contexts/PartyContext";
-import {
- PlayerUpdaterContext,
- PlayerStateContext,
-} from "../../contexts/PlayerContext";
+import { useParty } from "../../contexts/PartyContext";
+import { usePlayerState, usePlayerUpdater } from "../../contexts/PlayerContext";
function Party({ gameId, stream, partyStreams, onStreamStart, onStreamEnd }) {
- const setPlayerState = useContext(PlayerUpdaterContext);
- const playerState = useContext(PlayerStateContext);
- const partyState = useContext(PartyContext);
+ const setPlayerState = usePlayerUpdater();
+ const playerState = usePlayerState();
+ const partyState = useParty();
const [fullScreen] = useSetting("map.fullScreen");
const [shareDice, setShareDice] = useSetting("dice.shareDice");
diff --git a/src/components/token/ProxyToken.js b/src/components/token/ProxyToken.js
index 0ce751a..989e8fe 100644
--- a/src/components/token/ProxyToken.js
+++ b/src/components/token/ProxyToken.js
@@ -1,11 +1,11 @@
-import React, { useEffect, useRef, useState, useContext } from "react";
+import React, { useEffect, useRef, useState } from "react";
import ReactDOM from "react-dom";
import { Image, Box } from "theme-ui";
import interact from "interactjs";
import usePortal from "../../hooks/usePortal";
-import MapStageContext from "../../contexts/MapStageContext";
+import { useMapStage } from "../../contexts/MapStageContext";
/**
* @callback onProxyDragEnd
@@ -34,7 +34,7 @@ function ProxyToken({ tokenClassName, onProxyDragEnd, tokens }) {
}, [tokens]);
const proxyOnMap = useRef(false);
- const mapStageRef = useContext(MapStageContext);
+ const mapStageRef = useMapStage();
useEffect(() => {
interact(`.${tokenClassName}`).draggable({
diff --git a/src/components/token/TokenDragOverlay.js b/src/components/token/TokenDragOverlay.js
index 4d90e9a..467967f 100644
--- a/src/components/token/TokenDragOverlay.js
+++ b/src/components/token/TokenDragOverlay.js
@@ -1,7 +1,7 @@
-import React, { useContext } from "react";
+import React from "react";
-import AuthContext from "../../contexts/AuthContext";
-import MapInteractionContext from "../../contexts/MapInteractionContext";
+import { useAuth } from "../../contexts/AuthContext";
+import { useMapInteraction } from "../../contexts/MapInteractionContext";
import DragOverlay from "../DragOverlay";
@@ -14,8 +14,8 @@ function TokenDragOverlay({
dragging,
mapState,
}) {
- const { userId } = useContext(AuthContext);
- const { mapWidth, mapHeight } = useContext(MapInteractionContext);
+ const { userId } = useAuth();
+ const { mapWidth, mapHeight } = useMapInteraction();
function handleTokenRemove() {
// Handle other tokens when a vehicle gets deleted
diff --git a/src/components/token/TokenMenu.js b/src/components/token/TokenMenu.js
index d34f360..c9ff828 100644
--- a/src/components/token/TokenMenu.js
+++ b/src/components/token/TokenMenu.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState, useContext } from "react";
+import React, { useEffect, useState } from "react";
import { Box, Input, Flex, Text, IconButton } from "theme-ui";
import Slider from "../Slider";
@@ -14,7 +14,7 @@ import UnlockIcon from "../../icons/TokenUnlockIcon";
import ShowIcon from "../../icons/TokenShowIcon";
import HideIcon from "../../icons/TokenHideIcon";
-import AuthContext from "../../contexts/AuthContext";
+import { useAuth } from "../../contexts/AuthContext";
const defaultTokenMaxSize = 6;
function TokenMenu({
@@ -25,7 +25,7 @@ function TokenMenu({
onTokenStateChange,
map,
}) {
- const { userId } = useContext(AuthContext);
+ const { userId } = useAuth();
const wasOpen = usePrevious(isOpen);
diff --git a/src/components/token/TokenPreview.js b/src/components/token/TokenPreview.js
index 10b097f..e13b044 100644
--- a/src/components/token/TokenPreview.js
+++ b/src/components/token/TokenPreview.js
@@ -10,6 +10,8 @@ import useDataSource from "../../hooks/useDataSource";
import useImageCenter from "../../hooks/useImageCenter";
import useResponsiveLayout from "../../hooks/useResponsiveLayout";
+import { GridProvider } from "../../contexts/GridContext";
+
import GridOnIcon from "../../icons/GridOnIcon";
import GridOffIcon from "../../icons/GridOffIcon";
@@ -110,7 +112,7 @@ function TokenPreview({ token }) {
/>
{showGridPreview && (
-
+ >
+
+
{children};
}
+export function useAuth() {
+ const context = useContext(AuthContext);
+ if (context === undefined) {
+ throw new Error("useAuth must be used within a AuthProvider");
+ }
+ return context;
+}
+
export default AuthContext;
diff --git a/src/contexts/DatabaseContext.js b/src/contexts/DatabaseContext.js
index 323b49a..3eb32dd 100644
--- a/src/contexts/DatabaseContext.js
+++ b/src/contexts/DatabaseContext.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useContext } from "react";
import { Box, Text } from "theme-ui";
import Banner from "../components/Banner";
@@ -79,4 +79,12 @@ export function DatabaseProvider({ children }) {
);
}
+export function useDatabase() {
+ const context = useContext(DatabaseContext);
+ if (context === undefined) {
+ throw new Error("useDatabase must be used within a DatabaseProvider");
+ }
+ return context;
+}
+
export default DatabaseContext;
diff --git a/src/contexts/DiceLoadingContext.js b/src/contexts/DiceLoadingContext.js
index 4d75d40..8bc9ed3 100644
--- a/src/contexts/DiceLoadingContext.js
+++ b/src/contexts/DiceLoadingContext.js
@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React, { useState, useContext } from "react";
const DiceLoadingContext = React.createContext();
@@ -28,4 +28,12 @@ export function DiceLoadingProvider({ children }) {
);
}
+export function useDiceLoading() {
+ const context = useContext(DiceLoadingContext);
+ if (context === undefined) {
+ throw new Error("useDiceLoading must be used within a DiceLoadingProvider");
+ }
+ return context;
+}
+
export default DiceLoadingContext;
diff --git a/src/contexts/GridContext.js b/src/contexts/GridContext.js
new file mode 100644
index 0000000..215c231
--- /dev/null
+++ b/src/contexts/GridContext.js
@@ -0,0 +1,85 @@
+import React, { useContext } from "react";
+
+import Vector2 from "../helpers/Vector2";
+import Size from "../helpers/Size";
+import { getGridPixelSize, getCellPixelSize, Grid } from "../helpers/grid";
+
+/**
+ * @typedef GridContextValue
+ * @property {Grid} grid Base grid value
+ * @property {Size} gridPixelSize Size of the grid in pixels
+ * @property {Size} gridCellPixelSize Size of each cell in pixels
+ * @property {Size} gridCellNormalizedSize Size of each cell normalized to the grid
+ * @property {Vector2} gridOffset Offset of the grid from the top left in pixels
+ * @property {number} gridStrokeWidth Stroke width of the grid in pixels
+ */
+
+/**
+ * @type {GridContextValue}
+ */
+const defaultValue = {
+ grid: {
+ size: { x: 0, y: 0 },
+ inset: { topLeft: { x: 0, y: 0 }, bottomRight: { x: 1, y: 1 } },
+ type: "square",
+ },
+ gridPixelSize: new Size(0, 0),
+ gridCellPixelSize: new Size(0, 0, 0),
+ gridCellNormalizedSize: new Size(0, 0, 0),
+ gridOffset: { x: 0, y: 0 },
+ gridStrokeWidth: 0,
+};
+
+const GridContext = React.createContext(defaultValue);
+
+const defaultStrokeWidth = 1 / 10;
+
+export function GridProvider({ grid, width, height, children }) {
+ if (!grid?.size.x || !grid?.size.y) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ const gridPixelSize = getGridPixelSize(grid, width, height);
+ const gridCellPixelSize = getCellPixelSize(
+ grid,
+ gridPixelSize.width,
+ gridPixelSize.height
+ );
+ const gridCellNormalizedSize = new Size(
+ gridCellPixelSize.width / gridPixelSize.width,
+ gridCellPixelSize.height / gridPixelSize.height
+ );
+ const gridOffset = {
+ x: grid.inset.topLeft.x * width * -1,
+ y: grid.inset.topLeft.y * height * -1,
+ };
+ const gridStrokeWidth =
+ (gridCellPixelSize.width < gridCellPixelSize.height
+ ? gridCellPixelSize.width
+ : gridCellPixelSize.height) * defaultStrokeWidth;
+
+ const value = {
+ grid,
+ gridPixelSize,
+ gridCellPixelSize,
+ gridCellNormalizedSize,
+ gridOffset,
+ gridStrokeWidth,
+ };
+
+ return {children};
+}
+
+export function useGrid() {
+ const context = useContext(GridContext);
+ if (context === undefined) {
+ throw new Error("useGrid must be used within a GridProvider");
+ }
+ return context;
+}
+
+export default GridContext;
diff --git a/src/contexts/KeyboardContext.js b/src/contexts/KeyboardContext.js
index 8736f46..ec47dd9 100644
--- a/src/contexts/KeyboardContext.js
+++ b/src/contexts/KeyboardContext.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useState, useContext } from "react";
import { EventEmitter } from "events";
const KeyboardContext = React.createContext({ keyEmitter: new EventEmitter() });
@@ -45,4 +45,33 @@ export function KeyboardProvider({ children }) {
);
}
+/**
+ * @param {KeyboardEvent} onKeyDown
+ * @param {KeyboardEvent} onKeyUp
+ */
+export function useKeyboard(onKeyDown, onKeyUp) {
+ const context = useContext(KeyboardContext);
+ if (context === undefined) {
+ throw new Error("useKeyboard must be used within a KeyboardProvider");
+ }
+ const { keyEmitter } = context;
+ useEffect(() => {
+ if (onKeyDown) {
+ keyEmitter.on("keyDown", onKeyDown);
+ }
+ if (onKeyUp) {
+ keyEmitter.on("keyUp", onKeyUp);
+ }
+
+ return () => {
+ if (onKeyDown) {
+ keyEmitter.off("keyDown", onKeyDown);
+ }
+ if (onKeyUp) {
+ keyEmitter.off("keyUp", onKeyUp);
+ }
+ };
+ });
+}
+
export default KeyboardContext;
diff --git a/src/contexts/MapDataContext.js b/src/contexts/MapDataContext.js
index 5783adb..f94d375 100644
--- a/src/contexts/MapDataContext.js
+++ b/src/contexts/MapDataContext.js
@@ -8,8 +8,8 @@ import React, {
import * as Comlink from "comlink";
import { decode } from "@msgpack/msgpack";
-import AuthContext from "./AuthContext";
-import DatabaseContext from "./DatabaseContext";
+import { useAuth } from "./AuthContext";
+import { useDatabase } from "./DatabaseContext";
import DatabaseWorker from "worker-loader!../workers/DatabaseWorker"; // eslint-disable-line import/no-webpack-loader-syntax
@@ -32,8 +32,8 @@ const defaultMapState = {
const worker = Comlink.wrap(new DatabaseWorker());
export function MapDataProvider({ children }) {
- const { database, databaseStatus } = useContext(DatabaseContext);
- const { userId } = useContext(AuthContext);
+ const { database, databaseStatus } = useDatabase();
+ const { userId } = useAuth();
const [maps, setMaps] = useState([]);
const [mapStates, setMapStates] = useState([]);
@@ -303,4 +303,12 @@ export function MapDataProvider({ children }) {
);
}
+export function useMapData() {
+ const context = useContext(MapDataContext);
+ if (context === undefined) {
+ throw new Error("useMapData must be used within a MapDataProvider");
+ }
+ return context;
+}
+
export default MapDataContext;
diff --git a/src/contexts/MapInteractionContext.js b/src/contexts/MapInteractionContext.js
index cc8397b..905b1fe 100644
--- a/src/contexts/MapInteractionContext.js
+++ b/src/contexts/MapInteractionContext.js
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useContext } from "react";
const MapInteractionContext = React.createContext({
stageScale: 1,
@@ -11,4 +11,14 @@ const MapInteractionContext = React.createContext({
});
export const MapInteractionProvider = MapInteractionContext.Provider;
+export function useMapInteraction() {
+ const context = useContext(MapInteractionContext);
+ if (context === undefined) {
+ throw new Error(
+ "useMapInteraction must be used within a MapInteractionProvider"
+ );
+ }
+ return context;
+}
+
export default MapInteractionContext;
diff --git a/src/contexts/MapLoadingContext.js b/src/contexts/MapLoadingContext.js
index e413a09..94cb5b6 100644
--- a/src/contexts/MapLoadingContext.js
+++ b/src/contexts/MapLoadingContext.js
@@ -1,4 +1,4 @@
-import React, { useState, useRef } from "react";
+import React, { useState, useRef, useContext } from "react";
import { omit, isEmpty } from "../helpers/shared";
const MapLoadingContext = React.createContext();
@@ -53,4 +53,12 @@ export function MapLoadingProvider({ children }) {
);
}
+export function useMapLoading() {
+ const context = useContext(MapLoadingContext);
+ if (context === undefined) {
+ throw new Error("useMapLoading must be used within a MapLoadingProvider");
+ }
+ return context;
+}
+
export default MapLoadingContext;
diff --git a/src/contexts/MapStageContext.js b/src/contexts/MapStageContext.js
index e8f61d8..c5c3952 100644
--- a/src/contexts/MapStageContext.js
+++ b/src/contexts/MapStageContext.js
@@ -1,8 +1,16 @@
-import React from "react";
+import React, { useContext } from "react";
const MapStageContext = React.createContext({
mapStageRef: { current: null },
});
export const MapStageProvider = MapStageContext.Provider;
+export function useMapStage() {
+ const context = useContext(MapStageContext);
+ if (context === undefined) {
+ throw new Error("useMapStage must be used within a MapStageProvider");
+ }
+ return context;
+}
+
export default MapStageContext;
diff --git a/src/contexts/PartyContext.js b/src/contexts/PartyContext.js
index 1b90af7..905112e 100644
--- a/src/contexts/PartyContext.js
+++ b/src/contexts/PartyContext.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useContext } from "react";
const PartyContext = React.createContext();
@@ -27,4 +27,12 @@ export function PartyProvider({ session, children }) {
);
}
+export function useParty() {
+ const context = useContext(PartyContext);
+ if (context === undefined) {
+ throw new Error("useParty must be used within a PartyProvider");
+ }
+ return context;
+}
+
export default PartyContext;
diff --git a/src/contexts/PlayerContext.js b/src/contexts/PlayerContext.js
index 8764365..6a3af8f 100644
--- a/src/contexts/PlayerContext.js
+++ b/src/contexts/PlayerContext.js
@@ -1,7 +1,7 @@
import React, { useEffect, useContext } from "react";
-import DatabaseContext from "./DatabaseContext";
-import AuthContext from "./AuthContext";
+import { useDatabase } from "./DatabaseContext";
+import { useAuth } from "./AuthContext";
import { getRandomMonster } from "../helpers/monsters";
@@ -11,8 +11,8 @@ export const PlayerStateContext = React.createContext();
export const PlayerUpdaterContext = React.createContext(() => {});
export function PlayerProvider({ session, children }) {
- const { userId } = useContext(AuthContext);
- const { database, databaseStatus } = useContext(DatabaseContext);
+ const { userId } = useAuth();
+ const { database, databaseStatus } = useDatabase();
const [playerState, setPlayerState] = useNetworkedState(
{
@@ -93,3 +93,19 @@ export function PlayerProvider({ session, children }) {
);
}
+
+export function usePlayerState() {
+ const context = useContext(PlayerStateContext);
+ if (context === undefined) {
+ throw new Error("usePlayerState must be used within a PlayerProvider");
+ }
+ return context;
+}
+
+export function usePlayerUpdater() {
+ const context = useContext(PlayerUpdaterContext);
+ if (context === undefined) {
+ throw new Error("usePlayerUpdater must be used within a PlayerProvider");
+ }
+ return context;
+}
diff --git a/src/contexts/SettingsContext.js b/src/contexts/SettingsContext.js
index b396577..c9df1e7 100644
--- a/src/contexts/SettingsContext.js
+++ b/src/contexts/SettingsContext.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useContext } from "react";
import { getSettings } from "../settings";
@@ -28,4 +28,12 @@ export function SettingsProvider({ children }) {
);
}
+export function useSettings() {
+ const context = useContext(SettingsContext);
+ if (context === undefined) {
+ throw new Error("useSettings must be used within a SettingsProvider");
+ }
+ return context;
+}
+
export default SettingsContext;
diff --git a/src/contexts/TokenDataContext.js b/src/contexts/TokenDataContext.js
index 53a3940..ae81e02 100644
--- a/src/contexts/TokenDataContext.js
+++ b/src/contexts/TokenDataContext.js
@@ -8,8 +8,8 @@ import React, {
import * as Comlink from "comlink";
import { decode } from "@msgpack/msgpack";
-import AuthContext from "./AuthContext";
-import DatabaseContext from "./DatabaseContext";
+import { useAuth } from "./AuthContext";
+import { useDatabase } from "./DatabaseContext";
import DatabaseWorker from "worker-loader!../workers/DatabaseWorker"; // eslint-disable-line import/no-webpack-loader-syntax
@@ -22,8 +22,8 @@ const cachedTokenMax = 100;
const worker = Comlink.wrap(new DatabaseWorker());
export function TokenDataProvider({ children }) {
- const { database, databaseStatus } = useContext(DatabaseContext);
- const { userId } = useContext(AuthContext);
+ const { database, databaseStatus } = useDatabase();
+ const { userId } = useAuth();
const [tokens, setTokens] = useState([]);
const [tokensLoading, setTokensLoading] = useState(true);
@@ -224,4 +224,12 @@ export function TokenDataProvider({ children }) {
);
}
+export function useTokenData() {
+ const context = useContext(TokenDataContext);
+ if (context === undefined) {
+ throw new Error("useTokenData must be used within a TokenDataProvider");
+ }
+ return context;
+}
+
export default TokenDataContext;
diff --git a/src/helpers/Size.js b/src/helpers/Size.js
new file mode 100644
index 0000000..8330c45
--- /dev/null
+++ b/src/helpers/Size.js
@@ -0,0 +1,65 @@
+import Vector2 from "./Vector2";
+
+/**
+ * Wrapper for Vector2 that provides width, height and radius properties
+ */
+class Size extends Vector2 {
+ _radius;
+ /**
+ * @param {number} width
+ * @param {number} height
+ * @param {number=} radius Used to represent hexagon sizes
+ */
+ constructor(width, height, radius) {
+ super(width, height);
+ this._radius = radius;
+ }
+
+ /**
+ * @returns {number}
+ */
+ get width() {
+ return this.x;
+ }
+
+ /**
+ * @param {number} width
+ */
+ set width(width) {
+ this.x = width;
+ }
+
+ /**
+ * @returns {number}
+ */
+ get height() {
+ return this.y;
+ }
+
+ /**
+ * @param {number} height
+ */
+ set height(height) {
+ this.y = height;
+ }
+
+ /**
+ * @returns {number}
+ */
+ get radius() {
+ if (this._radius) {
+ return this._radius;
+ } else {
+ return Math.min(this.x, this.y) / 2;
+ }
+ }
+
+ /**
+ * @param {number} radius
+ */
+ set radius(radius) {
+ this._radius = radius;
+ }
+}
+
+export default Size;
diff --git a/src/helpers/Vector2.js b/src/helpers/Vector2.js
index 823d64b..01dce79 100644
--- a/src/helpers/Vector2.js
+++ b/src/helpers/Vector2.js
@@ -17,6 +17,15 @@ class Vector2 {
*/
y;
+ /**
+ * @param {number} x
+ * @param {number} y
+ */
+ constructor(x, y) {
+ this.x = x;
+ this.y = y;
+ }
+
/**
* @param {Vector2} p
* @returns {number} Length squared of `p`
@@ -385,7 +394,7 @@ class Vector2 {
* Returns the distance between two vectors
* @param {Vector2} a
* @param {Vector2} b
- * @param {string?} type - `chebyshev | euclidean | manhattan | alternating`
+ * @param {string=} type - `chebyshev | euclidean | manhattan | alternating`
*/
static distance(a, b, type = "euclidean") {
switch (type) {
diff --git a/src/helpers/drawing.js b/src/helpers/drawing.js
index bdd61b6..fdbd3a5 100644
--- a/src/helpers/drawing.js
+++ b/src/helpers/drawing.js
@@ -7,7 +7,12 @@ import { getRelativePointerPositionNormalized } from "./konva";
import { logError } from "./logging";
const snappingThreshold = 1 / 5;
-export function getBrushPosition(map, mapStage, useGridSnappning, gridSize) {
+export function getBrushPosition(
+ map,
+ mapStage,
+ useGridSnappning,
+ gridCellNormalizedSize
+) {
const mapImage = mapStage.findOne("#mapImage");
let position = getRelativePointerPositionNormalized(mapImage);
if (useGridSnappning) {
@@ -15,18 +20,21 @@ export function getBrushPosition(map, mapStage, useGridSnappning, gridSize) {
// Subtract offset to transform into offset space then add it back transform back
const offset = map.grid.inset.topLeft;
const gridSnap = Vector2.add(
- Vector2.roundTo(Vector2.subtract(position, offset), gridSize),
+ Vector2.roundTo(
+ Vector2.subtract(position, offset),
+ gridCellNormalizedSize
+ ),
offset
);
const gridDistance = Vector2.length(Vector2.subtract(gridSnap, position));
// Snap to center of grid
// Subtract offset and half size to transform it into offset half space then transform it back
- const halfSize = Vector2.multiply(gridSize, 0.5);
+ const halfSize = Vector2.multiply(gridCellNormalizedSize, 0.5);
const centerSnap = Vector2.add(
Vector2.add(
Vector2.roundTo(
Vector2.subtract(Vector2.subtract(position, offset), halfSize),
- gridSize
+ gridCellNormalizedSize
),
halfSize
),
@@ -35,7 +43,7 @@ export function getBrushPosition(map, mapStage, useGridSnappning, gridSize) {
const centerDistance = Vector2.length(
Vector2.subtract(centerSnap, position)
);
- const minGrid = Vector2.min(gridSize);
+ const minGrid = Vector2.min(gridCellNormalizedSize);
if (gridDistance < minGrid * snappingThreshold) {
position = gridSnap;
} else if (centerDistance < minGrid * snappingThreshold) {
@@ -49,14 +57,19 @@ export function getFogBrushPosition(
map,
mapStage,
useGridSnappning,
- gridSize,
+ gridCellNormalizedSize,
useEdgeSnapping,
fogShapes,
rectPoints
) {
- let position = getBrushPosition(map, mapStage, useGridSnappning, gridSize);
+ let position = getBrushPosition(
+ map,
+ mapStage,
+ useGridSnappning,
+ gridCellNormalizedSize
+ );
if (useEdgeSnapping) {
- const minGrid = Vector2.min(gridSize);
+ const minGrid = Vector2.min(gridCellNormalizedSize);
let closestDistance = Number.MAX_VALUE;
let closestPosition = position;
// Find the closest point on all fog shapes
@@ -139,18 +152,23 @@ export function getDefaultShapeData(type, brushPosition) {
}
}
-export function getGridScale(gridSize) {
- if (gridSize.x < gridSize.y) {
- return { x: gridSize.y / gridSize.x, y: 1 };
- } else if (gridSize.y < gridSize.x) {
- return { x: 1, y: gridSize.x / gridSize.y };
+export function getGridScale(cellSize) {
+ if (cellSize.x < cellSize.y) {
+ return { x: cellSize.y / cellSize.x, y: 1 };
+ } else if (cellSize.y < cellSize.x) {
+ return { x: 1, y: cellSize.x / cellSize.y };
} else {
return { x: 1, y: 1 };
}
}
-export function getUpdatedShapeData(type, data, brushPosition, gridSize) {
- const gridScale = getGridScale(gridSize);
+export function getUpdatedShapeData(
+ type,
+ data,
+ brushPosition,
+ gridCellNormalizedSize
+) {
+ const gridScale = getGridScale(gridCellNormalizedSize);
if (type === "line") {
return {
points: [data.points[0], { x: brushPosition.x, y: brushPosition.y }],
@@ -210,10 +228,10 @@ export function getStrokeWidth(multiplier, gridSize, mapWidth, mapHeight) {
}
const defaultSimplifySize = 1 / 100;
-export function simplifyPoints(points, gridSize, scale) {
+export function simplifyPoints(points, gridCellNormalizedSize, scale) {
return simplify(
points,
- (Vector2.min(gridSize) * defaultSimplifySize) / scale
+ (Vector2.min(gridCellNormalizedSize) * defaultSimplifySize) / scale
);
}
diff --git a/src/helpers/grid.js b/src/helpers/grid.js
index 554e2cc..29d5a44 100644
--- a/src/helpers/grid.js
+++ b/src/helpers/grid.js
@@ -1,5 +1,6 @@
import GridSizeModel from "../ml/gridSize/GridSizeModel";
import Vector2 from "./Vector2";
+import Size from "./Size";
import { logError } from "./logging";
@@ -8,52 +9,47 @@ const GRID_TYPE_NOT_IMPLEMENTED = new Error("Grid type not implemented");
/**
* @typedef GridInset
- * @property {Vector2} topLeft
- * @property {Vector2} bottomRight
+ * @property {Vector2} topLeft Top left position of the inset
+ * @property {Vector2} bottomRight Bottom right position of the inset
*/
/**
* @typedef Grid
- * @property {GridInset} inset
- * @property {Vector2} size
+ * @property {GridInset} inset The inset of the grid from the map
+ * @property {Vector2} size The number of columns and rows of the grid as `x` and `y`
* @property {("square"|"hexVertical"|"hexHorizontal")} type
*/
/**
- * @typedef CellSize
- * @property {number} width
- * @property {number} height
- * @property {number?} radius - Used for hex cell sizes
+ * Gets the size of a grid in pixels taking into account the inset
+ * @param {Grid} grid
+ * @param {number} baseWidth Width of the grid in pixels before inset
+ * @param {number} baseHeight Height of the grid in pixels before inset
+ * @returns {Size}
*/
+export function getGridPixelSize(grid, baseWidth, baseHeight) {
+ const width = (grid.inset.bottomRight.x - grid.inset.topLeft.x) * baseWidth;
+ const height = (grid.inset.bottomRight.y - grid.inset.topLeft.y) * baseHeight;
+ return new Size(width, height);
+}
/**
- * Gets the cell size for a grid taking into account inset and grid type
+ * Gets the cell size for a grid in pixels for each grid type
* @param {Grid} grid
- * @param {number} gridWidth
- * @param {number} gridHeight
- * @returns {CellSize}
+ * @param {number} gridWidth Width of the grid in pixels after inset
+ * @param {number} gridHeight Height of the grid in pixels after inset
+ * @returns {Size}
*/
-export function getCellSize(grid, gridWidth, gridHeight) {
+export function getCellPixelSize(grid, gridWidth, gridHeight) {
switch (grid.type) {
case "square":
- return {
- width: gridWidth / grid.size.x,
- height: gridHeight / grid.size.y,
- };
+ return new Size(gridWidth / grid.size.x, gridHeight / grid.size.y);
case "hexVertical":
const radiusVert = gridWidth / grid.size.x / SQRT3;
- return {
- width: radiusVert * SQRT3,
- height: radiusVert * 2,
- radius: radiusVert,
- };
+ return new Size(radiusVert * SQRT3, radiusVert * 2, radiusVert);
case "hexHorizontal":
const radiusHorz = gridHeight / grid.size.y / SQRT3;
- return {
- width: radiusHorz * 2,
- height: radiusHorz * SQRT3,
- radius: radiusHorz,
- };
+ return new Size(radiusHorz * 2, radiusHorz * SQRT3, radiusHorz);
default:
throw GRID_TYPE_NOT_IMPLEMENTED;
}
@@ -64,7 +60,7 @@ export function getCellSize(grid, gridWidth, gridHeight) {
* @param {Grid} grid
* @param {number} x X-axis location of the cell
* @param {number} y Y-axis location of the cell
- * @param {CellSize} cellSize
+ * @param {Size} cellSize Cell size in pixels
* @returns {Vector2}
*/
export function getCellLocation(grid, x, y, cellSize) {
@@ -111,11 +107,11 @@ export function shouldClipCell(grid, x, y) {
/**
* Canvas clip function for culling hex cells that overshoot/undershoot the grid
- * @param {CanvasRenderingContext2D} context
+ * @param {CanvasRenderingContext2D} context The canvas context of the clip function
* @param {Grid} grid
- * @param {number} x
- * @param {number} y
- * @param {CellSize} cellSize
+ * @param {number} x X-axis location of the cell
+ * @param {number} y Y-axis location of the cell
+ * @param {Size} cellSize Cell size in pixels
*/
export function gridClipFunction(context, grid, x, y, cellSize) {
// Clip the undershooting cells unless they are needed to fill out a specific grid type
@@ -138,7 +134,7 @@ export function gridClipFunction(context, grid, x, y, cellSize) {
/**
* Get the height of a grid based off of its width
* @param {Grid} grid
- * @param {number} gridWidth
+ * @param {number} gridWidth Width of the grid in pixels after inset
*/
function getGridHeightFromWidth(grid, gridWidth) {
switch (grid.type) {
@@ -157,22 +153,22 @@ function getGridHeightFromWidth(grid, gridWidth) {
/**
* Get the default inset for a grid
- * @param {Grid} grid
- * @param {number} gridWidth
- * @param {number} gridHeight
+ * @param {Grid} grid Grid with no inset property set
+ * @param {number} mapWidth Width of the map in pixels before inset
+ * @param {number} mapHeight Height of the map in pixels before inset
* @returns {GridInset}
*/
-export function getGridDefaultInset(grid, gridWidth, gridHeight) {
+export function getGridDefaultInset(grid, mapWidth, mapHeight) {
// Max the width of the inset and figure out the resulting height value
- const insetHeightNorm = getGridHeightFromWidth(grid, gridWidth) / gridHeight;
+ const insetHeightNorm = getGridHeightFromWidth(grid, mapWidth) / mapHeight;
return { topLeft: { x: 0, y: 0 }, bottomRight: { x: 1, y: insetHeightNorm } };
}
/**
* Get an updated inset for a grid when its size changes
- * @param {Grid} grid
- * @param {number} mapWidth
- * @param {number} mapHeight
+ * @param {Grid} grid Grid with an inset property set
+ * @param {number} mapWidth Width of the map in pixels before inset
+ * @param {number} mapHeight Height of the map in pixels before inset
* @returns {GridInset}
*/
export function getGridUpdatedInset(grid, mapWidth, mapHeight) {
@@ -348,7 +344,7 @@ async function gridSizeML(image, candidates) {
* @param {Image} image
* @returns {Vector2}
*/
-export async function getGridSize(image) {
+export async function getGridSizeFromImage(image) {
const candidates = dividers(image.width, image.height);
let prediction;
@@ -387,7 +383,7 @@ export function getGridMaxZoom(grid) {
* @param {Grid} grid
* @param {number} mapWidth
* @param {number} mapHeight
- * @param {Konva.node} node
+ * @param {Konva.Node} node
* @param {number} snappingThreshold 1 = Always snap, 0 = never snap
*/
export function snapNodeToGrid(
diff --git a/src/hooks/useKeyboard.js b/src/hooks/useKeyboard.js
deleted file mode 100644
index 5f20a20..0000000
--- a/src/hooks/useKeyboard.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { useEffect, useContext } from "react";
-
-import KeyboardContext from "../contexts/KeyboardContext";
-
-/**
- * @param {KeyboardEvent} onKeyDown
- * @param {KeyboardEvent} onKeyUp
- */
-function useKeyboard(onKeyDown, onKeyUp) {
- const { keyEmitter } = useContext(KeyboardContext);
- useEffect(() => {
- if (onKeyDown) {
- keyEmitter.on("keyDown", onKeyDown);
- }
- if (onKeyUp) {
- keyEmitter.on("keyUp", onKeyUp);
- }
-
- return () => {
- if (onKeyDown) {
- keyEmitter.off("keyDown", onKeyDown);
- }
- if (onKeyUp) {
- keyEmitter.off("keyUp", onKeyUp);
- }
- };
- });
-}
-
-export default useKeyboard;
diff --git a/src/hooks/useSetting.js b/src/hooks/useSetting.js
index ca38152..f8553e7 100644
--- a/src/hooks/useSetting.js
+++ b/src/hooks/useSetting.js
@@ -1,16 +1,14 @@
-import { useContext } from "react";
-
import get from "lodash.get";
import set from "lodash.set";
-import SettingsContext from "../contexts/SettingsContext";
+import { useSettings } from "../contexts/SettingsContext";
/**
* Helper to get and set nested settings that are saved in local storage
* @param {String} path The path to the setting within the Settings object provided by the SettingsContext
*/
function useSetting(path) {
- const { settings, setSettings } = useContext(SettingsContext);
+ const { settings, setSettings } = useSettings();
const setting = get(settings, path);
diff --git a/src/modals/AuthModal.js b/src/modals/AuthModal.js
index e97b0a8..4e2dfdf 100644
--- a/src/modals/AuthModal.js
+++ b/src/modals/AuthModal.js
@@ -1,14 +1,12 @@
-import React, { useState, useContext, useRef } from "react";
+import React, { useState, useRef } from "react";
import { Box, Input, Button, Label, Flex } from "theme-ui";
-import AuthContext from "../contexts/AuthContext";
+import { useAuth } from "../contexts/AuthContext";
import Modal from "../components/Modal";
function AuthModal({ isOpen }) {
- const { password, setPassword, setAuthenticationStatus } = useContext(
- AuthContext
- );
+ const { password, setPassword, setAuthenticationStatus } = useAuth();
const [tmpPassword, setTempPassword] = useState(password);
function handleChange(event) {
diff --git a/src/modals/EditMapModal.js b/src/modals/EditMapModal.js
index 466ba5b..dcfc4ed 100644
--- a/src/modals/EditMapModal.js
+++ b/src/modals/EditMapModal.js
@@ -1,11 +1,11 @@
-import React, { useState, useContext } from "react";
+import React, { useState } from "react";
import { Button, Flex, Label } from "theme-ui";
import Modal from "../components/Modal";
import MapSettings from "../components/map/MapSettings";
import MapEditor from "../components/map/MapEditor";
-import MapDataContext from "../contexts/MapDataContext";
+import { useMapData } from "../contexts/MapDataContext";
import { isEmpty } from "../helpers/shared";
import { getGridDefaultInset } from "../helpers/grid";
@@ -13,7 +13,7 @@ import { getGridDefaultInset } from "../helpers/grid";
import useResponsiveLayout from "../hooks/useResponsiveLayout";
function EditMapModal({ isOpen, onDone, map, mapState }) {
- const { updateMap, updateMapState } = useContext(MapDataContext);
+ const { updateMap, updateMapState } = useMapData();
function handleClose() {
setMapSettingChanges({});
diff --git a/src/modals/EditTokenModal.js b/src/modals/EditTokenModal.js
index 860241f..345f44e 100644
--- a/src/modals/EditTokenModal.js
+++ b/src/modals/EditTokenModal.js
@@ -1,18 +1,18 @@
-import React, { useState, useContext } from "react";
+import React, { useState } from "react";
import { Button, Flex, Label } from "theme-ui";
import Modal from "../components/Modal";
import TokenSettings from "../components/token/TokenSettings";
import TokenPreview from "../components/token/TokenPreview";
-import TokenDataContext from "../contexts/TokenDataContext";
+import { useTokenData } from "../contexts/TokenDataContext";
import { isEmpty } from "../helpers/shared";
import useResponsiveLayout from "../hooks/useResponsiveLayout";
function EditTokenModal({ isOpen, onDone, token }) {
- const { updateToken } = useContext(TokenDataContext);
+ const { updateToken } = useTokenData();
function handleClose() {
setTokenSettingChanges({});
diff --git a/src/modals/ImportExportModal.js b/src/modals/ImportExportModal.js
index 5b91474..d719c46 100644
--- a/src/modals/ImportExportModal.js
+++ b/src/modals/ImportExportModal.js
@@ -1,4 +1,4 @@
-import React, { useRef, useState, useContext, useEffect } from "react";
+import React, { useRef, useState, useEffect } from "react";
import { Box, Label, Text, Button, Flex } from "theme-ui";
import streamSaver from "streamsaver";
import * as Comlink from "comlink";
@@ -7,14 +7,14 @@ import Modal from "../components/Modal";
import LoadingOverlay from "../components/LoadingOverlay";
import LoadingBar from "../components/LoadingBar";
-import DatabaseContext from "../contexts/DatabaseContext";
+import { useDatabase } from "../contexts/DatabaseContext";
import DatabaseWorker from "worker-loader!../workers/DatabaseWorker"; // eslint-disable-line import/no-webpack-loader-syntax
const worker = Comlink.wrap(new DatabaseWorker());
function ImportDatabaseModal({ isOpen, onRequestClose }) {
- const { database } = useContext(DatabaseContext);
+ const { database } = useDatabase();
const [isLoading, setIsLoading] = useState(false);
const backgroundTaskRunningRef = useRef(false);
diff --git a/src/modals/SelectMapModal.js b/src/modals/SelectMapModal.js
index 9882426..7cf1c74 100644
--- a/src/modals/SelectMapModal.js
+++ b/src/modals/SelectMapModal.js
@@ -1,4 +1,4 @@
-import React, { useRef, useState, useContext, useEffect } from "react";
+import React, { useRef, useState, useEffect } from "react";
import { Button, Flex, Label } from "theme-ui";
import shortid from "shortid";
import Case from "case";
@@ -17,16 +17,16 @@ import { resizeImage } from "../helpers/image";
import { useSearch, useGroup, handleItemSelect } from "../helpers/select";
import {
getGridDefaultInset,
- getGridSize,
+ getGridSizeFromImage,
gridSizeVaild,
} from "../helpers/grid";
import Vector2 from "../helpers/Vector2";
-import useKeyboard from "../hooks/useKeyboard";
import useResponsiveLayout from "../hooks/useResponsiveLayout";
-import MapDataContext from "../contexts/MapDataContext";
-import AuthContext from "../contexts/AuthContext";
+import { useMapData } from "../contexts/MapDataContext";
+import { useAuth } from "../contexts/AuthContext";
+import { useKeyboard } from "../contexts/KeyboardContext";
const defaultMapProps = {
showGrid: false,
@@ -54,7 +54,7 @@ function SelectMapModal({
// The map currently being view in the map screen
currentMap,
}) {
- const { userId } = useContext(AuthContext);
+ const { userId } = useAuth();
const {
ownedMaps,
mapStates,
@@ -64,7 +64,7 @@ function SelectMapModal({
updateMap,
updateMaps,
mapsLoading,
- } = useContext(MapDataContext);
+ } = useMapData();
/**
* Search
@@ -152,7 +152,7 @@ function SelectMapModal({
}
if (!gridSize) {
- gridSize = await getGridSize(image);
+ gridSize = await getGridSizeFromImage(image);
}
// Remove file extension
@@ -207,10 +207,9 @@ function SelectMapModal({
grid: {
size: gridSize,
inset: getGridDefaultInset(
+ { size: { x: gridSize.x, y: gridSize.y }, type: "square" },
image.width,
- image.height,
- gridSize.x,
- gridSize.y
+ image.height
),
type: "square",
},
diff --git a/src/modals/SelectTokensModal.js b/src/modals/SelectTokensModal.js
index ca920ce..7221a56 100644
--- a/src/modals/SelectTokensModal.js
+++ b/src/modals/SelectTokensModal.js
@@ -1,4 +1,4 @@
-import React, { useRef, useContext, useState, useEffect } from "react";
+import React, { useRef, useState, useEffect } from "react";
import { Flex, Label, Button } from "theme-ui";
import shortid from "shortid";
import Case from "case";
@@ -15,21 +15,21 @@ import LoadingOverlay from "../components/LoadingOverlay";
import blobToBuffer from "../helpers/blobToBuffer";
import { useSearch, useGroup, handleItemSelect } from "../helpers/select";
-import useKeyboard from "../hooks/useKeyboard";
import useResponsiveLayout from "../hooks/useResponsiveLayout";
-import TokenDataContext from "../contexts/TokenDataContext";
-import AuthContext from "../contexts/AuthContext";
+import { useTokenData } from "../contexts/TokenDataContext";
+import { useAuth } from "../contexts/AuthContext";
+import { useKeyboard } from "../contexts/KeyboardContext";
function SelectTokensModal({ isOpen, onRequestClose }) {
- const { userId } = useContext(AuthContext);
+ const { userId } = useAuth();
const {
ownedTokens,
addToken,
removeTokens,
updateTokens,
tokensLoading,
- } = useContext(TokenDataContext);
+ } = useTokenData();
/**
* Search
diff --git a/src/modals/SettingsModal.js b/src/modals/SettingsModal.js
index 6cf3901..e579922 100644
--- a/src/modals/SettingsModal.js
+++ b/src/modals/SettingsModal.js
@@ -1,4 +1,4 @@
-import React, { useState, useContext, useEffect } from "react";
+import React, { useState, useEffect } from "react";
import {
Label,
Flex,
@@ -13,8 +13,8 @@ import prettyBytes from "pretty-bytes";
import Modal from "../components/Modal";
import Slider from "../components/Slider";
-import AuthContext from "../contexts/AuthContext";
-import DatabaseContext from "../contexts/DatabaseContext";
+import { useAuth } from "../contexts/AuthContext";
+import { useDatabase } from "../contexts/DatabaseContext";
import useSetting from "../hooks/useSetting";
@@ -22,8 +22,8 @@ import ConfirmModal from "./ConfirmModal";
import ImportExportModal from "./ImportExportModal";
function SettingsModal({ isOpen, onRequestClose }) {
- const { database, databaseStatus } = useContext(DatabaseContext);
- const { userId } = useContext(AuthContext);
+ const { database, databaseStatus } = useDatabase();
+ const { userId } = useAuth();
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [labelSize, setLabelSize] = useSetting("map.labelSize");
const [storageEstimate, setStorageEstimate] = useState();
diff --git a/src/modals/StartModal.js b/src/modals/StartModal.js
index 87e1093..7aa23fd 100644
--- a/src/modals/StartModal.js
+++ b/src/modals/StartModal.js
@@ -1,9 +1,9 @@
-import React, { useContext, useRef } from "react";
+import React, { useRef } from "react";
import { Box, Label, Input, Button, Flex, Checkbox } from "theme-ui";
import { useHistory } from "react-router-dom";
import shortid from "shortid";
-import AuthContext from "../contexts/AuthContext";
+import { useAuth } from "../contexts/AuthContext";
import useSetting from "../hooks/useSetting";
@@ -11,7 +11,7 @@ import Modal from "../components/Modal";
function StartModal({ isOpen, onRequestClose }) {
let history = useHistory();
- const { password, setPassword } = useContext(AuthContext);
+ const { password, setPassword } = useAuth();
function handlePasswordChange(event) {
setPassword(event.target.value);
diff --git a/src/network/NetworkedMapAndTokens.js b/src/network/NetworkedMapAndTokens.js
index f54b7c1..538ba18 100644
--- a/src/network/NetworkedMapAndTokens.js
+++ b/src/network/NetworkedMapAndTokens.js
@@ -1,11 +1,11 @@
-import React, { useState, useContext, useEffect, useRef } from "react";
+import React, { useState, useEffect, useRef } from "react";
-import TokenDataContext from "../contexts/TokenDataContext";
-import MapDataContext from "../contexts/MapDataContext";
-import MapLoadingContext from "../contexts/MapLoadingContext";
-import AuthContext from "../contexts/AuthContext";
-import DatabaseContext from "../contexts/DatabaseContext";
-import PartyContext from "../contexts/PartyContext";
+import { useTokenData } from "../contexts/TokenDataContext";
+import { useMapData } from "../contexts/MapDataContext";
+import { useMapLoading } from "../contexts/MapLoadingContext";
+import { useAuth } from "../contexts/AuthContext";
+import { useDatabase } from "../contexts/DatabaseContext";
+import { useParty } from "../contexts/PartyContext";
import { omit } from "../helpers/shared";
@@ -35,21 +35,17 @@ const defaultMapActions = {
* @param {NetworkedMapProps} props
*/
function NetworkedMapAndTokens({ session }) {
- const { userId } = useContext(AuthContext);
- const partyState = useContext(PartyContext);
+ const { userId } = useAuth();
+ const partyState = useParty();
const {
assetLoadStart,
assetLoadFinish,
assetProgressUpdate,
isLoading,
- } = useContext(MapLoadingContext);
+ } = useMapLoading();
- const { putToken, updateToken, getTokenFromDB } = useContext(
- TokenDataContext
- );
- const { putMap, updateMap, getMapFromDB, updateMapState } = useContext(
- MapDataContext
- );
+ const { putToken, updateToken, getTokenFromDB } = useTokenData();
+ const { putMap, updateMap, getMapFromDB, updateMapState } = useMapData();
const [currentMap, setCurrentMap] = useState(null);
const [currentMapState, setCurrentMapState] = useNetworkedState(
@@ -193,7 +189,7 @@ function NetworkedMapAndTokens({ session }) {
* Map state
*/
- const { database } = useContext(DatabaseContext);
+ const { database } = useDatabase();
// Sync the map state to the database after 500ms of inactivity
const debouncedMapState = useDebounce(currentMapState, 500);
useEffect(() => {
diff --git a/src/network/NetworkedMapPointer.js b/src/network/NetworkedMapPointer.js
index d953239..6398eb1 100644
--- a/src/network/NetworkedMapPointer.js
+++ b/src/network/NetworkedMapPointer.js
@@ -1,7 +1,7 @@
-import React, { useState, useContext, useEffect, useRef } from "react";
+import React, { useState, useEffect, useRef } from "react";
import { Group } from "react-konva";
-import AuthContext from "../contexts/AuthContext";
+import { useAuth } from "../contexts/AuthContext";
import MapPointer from "../components/map/MapPointer";
import { isEmpty } from "../helpers/shared";
@@ -12,8 +12,8 @@ import useSetting from "../hooks/useSetting";
// Send pointer updates every 50ms (20fps)
const sendTickRate = 50;
-function NetworkedMapPointer({ session, active, gridSize }) {
- const { userId } = useContext(AuthContext);
+function NetworkedMapPointer({ session, active }) {
+ const { userId } = useAuth();
const [localPointerState, setLocalPointerState] = useState({});
const [pointerColor] = useSetting("pointer.color");
@@ -194,7 +194,6 @@ function NetworkedMapPointer({ session, active, gridSize }) {
{Object.values(localPointerState).map((pointer) => (
{
setPassword("");
}, [setPassword]);