Added shared grid context and moved away from calling useContext directly

This commit is contained in:
Mitchell McCaffrey
2021-02-06 13:32:38 +11:00
parent 8991be923e
commit f20173de35
60 changed files with 672 additions and 460 deletions
+10 -2
View File
@@ -1,7 +1,7 @@
import React, { useState, useEffect, useContext } from "react";
import shortid from "shortid";
import DatabaseContext from "./DatabaseContext";
import { useDatabase } from "./DatabaseContext";
import FakeStorage from "../helpers/FakeStorage";
@@ -18,7 +18,7 @@ try {
}
export function AuthProvider({ children }) {
const { database, databaseStatus } = useContext(DatabaseContext);
const { database, databaseStatus } = useDatabase();
const [password, setPassword] = useState(storage.getItem("auth") || "");
@@ -57,4 +57,12 @@ export function AuthProvider({ children }) {
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
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;
+9 -1
View File
@@ -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;
+9 -1
View File
@@ -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;
+85
View File
@@ -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 (
<GridContext.Provider value={defaultValue}>
{children}
</GridContext.Provider>
);
}
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 <GridContext.Provider value={value}>{children}</GridContext.Provider>;
}
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;
+30 -1
View File
@@ -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;
+12 -4
View File
@@ -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;
+11 -1
View File
@@ -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;
+9 -1
View File
@@ -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;
+9 -1
View File
@@ -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;
+9 -1
View File
@@ -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;
+20 -4
View File
@@ -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 }) {
</PlayerStateContext.Provider>
);
}
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;
}
+9 -1
View File
@@ -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;
+12 -4
View File
@@ -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;