Typescript
This commit is contained in:
parent
49b8caa2d7
commit
569ed696fc
|
@ -100,6 +100,7 @@
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
"@types/lodash.clonedeep": "^4.5.6",
|
"@types/lodash.clonedeep": "^4.5.6",
|
||||||
"@types/lodash.get": "^4.4.6",
|
"@types/lodash.get": "^4.4.6",
|
||||||
|
"@types/lodash.set": "^4.3.6",
|
||||||
"@types/node": "^15.6.0",
|
"@types/node": "^15.6.0",
|
||||||
"@types/react": "^17.0.6",
|
"@types/react": "^17.0.6",
|
||||||
"@types/react-dom": "^17.0.5",
|
"@types/react-dom": "^17.0.5",
|
||||||
|
|
|
@ -5,12 +5,13 @@ import DiceTile from "./DiceTile";
|
||||||
|
|
||||||
import useResponsiveLayout from "../../hooks/useResponsiveLayout";
|
import useResponsiveLayout from "../../hooks/useResponsiveLayout";
|
||||||
import { DefaultDice } from "../../types/Dice";
|
import { DefaultDice } from "../../types/Dice";
|
||||||
|
import { DiceSelectEventHandler } from "../../types/Events";
|
||||||
|
|
||||||
type DiceTileProps = {
|
type DiceTileProps = {
|
||||||
dice: DefaultDice[];
|
dice: DefaultDice[];
|
||||||
onDiceSelect: (dice: DefaultDice) => void;
|
onDiceSelect: DiceSelectEventHandler;
|
||||||
selectedDice: DefaultDice;
|
selectedDice: DefaultDice;
|
||||||
onDone: (dice: DefaultDice) => void;
|
onDone: DiceSelectEventHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
function DiceTiles({
|
function DiceTiles({
|
||||||
|
|
|
@ -1,26 +1,38 @@
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Box, IconButton } from "theme-ui";
|
import { Box, IconButton } from "theme-ui";
|
||||||
|
import { Node } from "konva/types/Node";
|
||||||
|
|
||||||
import RemoveTokenIcon from "../../icons/RemoveTokenIcon";
|
import RemoveTokenIcon from "../../icons/RemoveTokenIcon";
|
||||||
|
|
||||||
function DragOverlay({ dragging, node, onRemove }) {
|
type DragOverlayProps = {
|
||||||
|
dragging: boolean;
|
||||||
|
node: Node;
|
||||||
|
onRemove: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function DragOverlay({ dragging, node, onRemove }: DragOverlayProps) {
|
||||||
const [isRemoveHovered, setIsRemoveHovered] = useState(false);
|
const [isRemoveHovered, setIsRemoveHovered] = useState(false);
|
||||||
const removeTokenRef = useRef();
|
const removeTokenRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// Detect token hover on remove icon manually to support touch devices
|
// Detect token hover on remove icon manually to support touch devices
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const map = document.querySelector(".map");
|
|
||||||
const mapRect = map.getBoundingClientRect();
|
|
||||||
|
|
||||||
function detectRemoveHover() {
|
function detectRemoveHover() {
|
||||||
if (!node || !dragging || !removeTokenRef.current) {
|
if (!node || !dragging || !removeTokenRef.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const map = document.querySelector(".map");
|
||||||
|
if (!map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const mapRect = map.getBoundingClientRect();
|
||||||
const stage = node.getStage();
|
const stage = node.getStage();
|
||||||
if (!stage) {
|
if (!stage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const pointerPosition = stage.getPointerPosition();
|
const pointerPosition = stage.getPointerPosition();
|
||||||
|
if (!pointerPosition) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const screenSpacePointerPosition = {
|
const screenSpacePointerPosition = {
|
||||||
x: pointerPosition.x + mapRect.left,
|
x: pointerPosition.x + mapRect.left,
|
||||||
y: pointerPosition.y + mapRect.top,
|
y: pointerPosition.y + mapRect.top,
|
||||||
|
@ -41,7 +53,7 @@ function DragOverlay({ dragging, node, onRemove }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let handler;
|
let handler: NodeJS.Timeout;
|
||||||
if (node && dragging) {
|
if (node && dragging) {
|
||||||
handler = setInterval(detectRemoveHover, 100);
|
handler = setInterval(detectRemoveHover, 100);
|
||||||
}
|
}
|
|
@ -21,6 +21,22 @@ import FullScreenExitIcon from "../../icons/FullScreenExitIcon";
|
||||||
import NoteToolIcon from "../../icons/NoteToolIcon";
|
import NoteToolIcon from "../../icons/NoteToolIcon";
|
||||||
|
|
||||||
import useSetting from "../../hooks/useSetting";
|
import useSetting from "../../hooks/useSetting";
|
||||||
|
import { Map } from "../../types/Map";
|
||||||
|
import { MapState } from "../../types/MapState";
|
||||||
|
|
||||||
|
type MapControlsProps = {
|
||||||
|
onMapChange: () => void;
|
||||||
|
onMapReset: () => void;
|
||||||
|
currentMap?: Map;
|
||||||
|
currentMapState?: MapState;
|
||||||
|
selectedToolId: string;
|
||||||
|
onSelectedToolChange: () => void;
|
||||||
|
toolSettings: any;
|
||||||
|
onToolSettingChange: () => void;
|
||||||
|
onToolAction: () => void;
|
||||||
|
disabledControls: string[];
|
||||||
|
disabledSettings: string[];
|
||||||
|
};
|
||||||
|
|
||||||
function MapContols({
|
function MapContols({
|
||||||
onMapChange,
|
onMapChange,
|
||||||
|
@ -34,7 +50,7 @@ function MapContols({
|
||||||
onToolAction,
|
onToolAction,
|
||||||
disabledControls,
|
disabledControls,
|
||||||
disabledSettings,
|
disabledSettings,
|
||||||
}) {
|
}: MapControlsProps) {
|
||||||
const [isExpanded, setIsExpanded] = useState(true);
|
const [isExpanded, setIsExpanded] = useState(true);
|
||||||
const [fullScreen, setFullScreen] = useSetting("map.fullScreen");
|
const [fullScreen, setFullScreen] = useSetting("map.fullScreen");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Flex, Close, IconButton } from "theme-ui";
|
import { Flex, Close, IconButton } from "theme-ui";
|
||||||
|
|
||||||
import { groupsFromIds, itemsFromGroups } from "../../helpers/group";
|
import { groupsFromIds, itemsFromGroups } from "../../helpers/group";
|
||||||
|
@ -13,8 +13,27 @@ import { useMapData } from "../../contexts/MapDataContext";
|
||||||
import { useKeyboard } from "../../contexts/KeyboardContext";
|
import { useKeyboard } from "../../contexts/KeyboardContext";
|
||||||
|
|
||||||
import shortcuts from "../../shortcuts";
|
import shortcuts from "../../shortcuts";
|
||||||
|
import { Map } from "../../types/Map";
|
||||||
|
import {
|
||||||
|
MapChangeEventHandler,
|
||||||
|
MapResetEventHandler,
|
||||||
|
} from "../../types/Events";
|
||||||
|
|
||||||
function MapEditBar({ currentMap, disabled, onMapChange, onMapReset, onLoad }) {
|
type MapEditBarProps = {
|
||||||
|
currentMap?: Map;
|
||||||
|
disabled: boolean;
|
||||||
|
onMapChange: MapChangeEventHandler;
|
||||||
|
onMapReset: MapResetEventHandler;
|
||||||
|
onLoad: (loading: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function MapEditBar({
|
||||||
|
currentMap,
|
||||||
|
disabled,
|
||||||
|
onMapChange,
|
||||||
|
onMapReset,
|
||||||
|
onLoad,
|
||||||
|
}: MapEditBarProps) {
|
||||||
const [hasMapState, setHasMapState] = useState(false);
|
const [hasMapState, setHasMapState] = useState(false);
|
||||||
|
|
||||||
const { maps, mapStates, removeMaps, resetMap } = useMapData();
|
const { maps, mapStates, removeMaps, resetMap } = useMapData();
|
||||||
|
@ -56,11 +75,11 @@ function MapEditBar({ currentMap, disabled, onMapChange, onMapReset, onLoad }) {
|
||||||
setIsMapsRemoveModalOpen(false);
|
setIsMapsRemoveModalOpen(false);
|
||||||
const selectedMaps = getSelectedMaps();
|
const selectedMaps = getSelectedMaps();
|
||||||
const selectedMapIds = selectedMaps.map((map) => map.id);
|
const selectedMapIds = selectedMaps.map((map) => map.id);
|
||||||
onGroupSelect();
|
onGroupSelect(undefined);
|
||||||
await removeMaps(selectedMapIds);
|
await removeMaps(selectedMapIds);
|
||||||
// Removed the map from the map screen if needed
|
// Removed the map from the map screen if needed
|
||||||
if (currentMap && selectedMapIds.includes(currentMap.id)) {
|
if (currentMap && selectedMapIds.includes(currentMap.id)) {
|
||||||
onMapChange(null, null);
|
onMapChange(undefined, undefined);
|
||||||
}
|
}
|
||||||
onLoad(false);
|
onLoad(false);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +103,7 @@ function MapEditBar({ currentMap, disabled, onMapChange, onMapReset, onLoad }) {
|
||||||
/**
|
/**
|
||||||
* Shortcuts
|
* Shortcuts
|
||||||
*/
|
*/
|
||||||
function handleKeyDown(event) {
|
function handleKeyDown(event: KeyboardEvent) {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +136,7 @@ function MapEditBar({ currentMap, disabled, onMapChange, onMapReset, onLoad }) {
|
||||||
<Close
|
<Close
|
||||||
title="Clear Selection"
|
title="Clear Selection"
|
||||||
aria-label="Clear Selection"
|
aria-label="Clear Selection"
|
||||||
onClick={() => onGroupSelect()}
|
onClick={() => onGroupSelect(undefined)}
|
||||||
/>
|
/>
|
||||||
<Flex>
|
<Flex>
|
||||||
<IconButton
|
<IconButton
|
|
@ -11,37 +11,58 @@ import { useDatabase } from "./DatabaseContext";
|
||||||
|
|
||||||
import { Map } from "../types/Map";
|
import { Map } from "../types/Map";
|
||||||
import { MapState } from "../types/MapState";
|
import { MapState } from "../types/MapState";
|
||||||
import { Note } from "../types/Note";
|
|
||||||
|
|
||||||
import { removeGroupsItems } from "../helpers/group";
|
import { removeGroupsItems } from "../helpers/group";
|
||||||
|
|
||||||
// TODO: fix differences in types between default maps and imported maps
|
import { Group } from "../types/Group";
|
||||||
|
|
||||||
|
export type AddMapEventHandler = (map: Map) => Promise<void>;
|
||||||
|
export type RemoveMapsEventHandler = (ids: string[]) => Promise<void>;
|
||||||
|
export type ResetMapEventHandler = (id: string) => Promise<MapState>;
|
||||||
|
export type UpdateMapEventHanlder = (
|
||||||
|
id: string,
|
||||||
|
update: Partial<Map>
|
||||||
|
) => Promise<void>;
|
||||||
|
export type UpdateMapStateEventHandler = (
|
||||||
|
id: string,
|
||||||
|
update: Partial<MapState>
|
||||||
|
) => Promise<void>;
|
||||||
|
export type GetMapStateEventHandler = (
|
||||||
|
id: string
|
||||||
|
) => Promise<MapState | undefined>;
|
||||||
|
export type GetMapEventHandler = (id: string) => Promise<Map | undefined>;
|
||||||
|
export type UpdateMapGroupsEventHandler = (groups: Group[]) => Promise<void>;
|
||||||
|
|
||||||
type MapDataContext = {
|
type MapDataContext = {
|
||||||
maps: Array<Map>;
|
maps: Array<Map>;
|
||||||
mapStates: MapState[];
|
mapStates: MapState[];
|
||||||
addMap: (map: Map) => void;
|
/** Adds a map to the database, also adds an assosiated state and group for that map */
|
||||||
removeMaps: (ids: string[]) => void;
|
addMap: AddMapEventHandler;
|
||||||
resetMap: (id: string) => void;
|
removeMaps: RemoveMapsEventHandler;
|
||||||
updateMap: (id: string, update: Partial<Map>) => void;
|
resetMap: ResetMapEventHandler;
|
||||||
updateMapState: (id: string, update: Partial<MapState>) => void;
|
updateMap: UpdateMapEventHanlder;
|
||||||
getMapState: (id: string) => Promise<MapState>;
|
updateMapState: UpdateMapStateEventHandler;
|
||||||
getMap: (id: string) => Promise<Map | undefined>;
|
getMapState: GetMapStateEventHandler;
|
||||||
|
getMap: GetMapEventHandler;
|
||||||
mapsLoading: boolean;
|
mapsLoading: boolean;
|
||||||
updateMapGroups: (groups: any) => void;
|
updateMapGroups: UpdateMapGroupsEventHandler;
|
||||||
mapsById: Record<string, Map>;
|
mapsById: Record<string, Map>;
|
||||||
mapGroups: any[];
|
mapGroups: Group[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const MapDataContext =
|
const MapDataContext =
|
||||||
React.createContext<MapDataContext | undefined>(undefined);
|
React.createContext<MapDataContext | undefined>(undefined);
|
||||||
|
|
||||||
const defaultMapState = {
|
const defaultMapState: Pick<
|
||||||
|
MapState,
|
||||||
|
"tokens" | "drawShapes" | "fogShapes" | "editFlags" | "notes"
|
||||||
|
> = {
|
||||||
tokens: {},
|
tokens: {},
|
||||||
drawShapes: {},
|
drawShapes: {},
|
||||||
fogShapes: {},
|
fogShapes: {},
|
||||||
// Flags to determine what other people can edit
|
// Flags to determine what other people can edit
|
||||||
editFlags: ["drawing", "tokens", "notes", "fog"],
|
editFlags: ["drawing", "tokens", "notes", "fog"],
|
||||||
notes: {} as Note[],
|
notes: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function MapDataProvider({ children }: { children: React.ReactNode }) {
|
export function MapDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
|
@ -68,7 +89,7 @@ export function MapDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [mapGroups, setMapGroups] = useState([]);
|
const [mapGroups, setMapGroups] = useState<Group[]>([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function updateMapGroups() {
|
async function updateMapGroups() {
|
||||||
const group = await database?.table("groups").get("maps");
|
const group = await database?.table("groups").get("maps");
|
||||||
|
@ -79,27 +100,23 @@ export function MapDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
}
|
}
|
||||||
}, [mapGroupQuery, database]);
|
}, [mapGroupQuery, database]);
|
||||||
|
|
||||||
const getMap = useCallback(
|
const getMap = useCallback<GetMapEventHandler>(
|
||||||
async (mapId: string) => {
|
async (mapId) => {
|
||||||
let map = (await database?.table("maps").get(mapId)) as Map;
|
let map = await database?.table("maps").get(mapId);
|
||||||
return map;
|
return map;
|
||||||
},
|
},
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getMapState = useCallback(
|
const getMapState = useCallback<GetMapStateEventHandler>(
|
||||||
async (mapId) => {
|
async (mapId) => {
|
||||||
let mapState = (await database?.table("states").get(mapId)) as MapState;
|
let mapState = await database?.table("states").get(mapId);
|
||||||
return mapState;
|
return mapState;
|
||||||
},
|
},
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
const addMap = useCallback<AddMapEventHandler>(
|
||||||
* Adds a map to the database, also adds an assosiated state and group for that map
|
|
||||||
* @param {Object} map map to add
|
|
||||||
*/
|
|
||||||
const addMap = useCallback(
|
|
||||||
async (map) => {
|
async (map) => {
|
||||||
if (database) {
|
if (database) {
|
||||||
// Just update map database as react state will be updated with an Observable
|
// Just update map database as react state will be updated with an Observable
|
||||||
|
@ -115,7 +132,7 @@ export function MapDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeMaps = useCallback(
|
const removeMaps = useCallback<RemoveMapsEventHandler>(
|
||||||
async (ids) => {
|
async (ids) => {
|
||||||
if (database) {
|
if (database) {
|
||||||
const maps = await database.table("maps").bulkGet(ids);
|
const maps = await database.table("maps").bulkGet(ids);
|
||||||
|
@ -143,30 +160,30 @@ export function MapDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetMap = useCallback(
|
const resetMap = useCallback<ResetMapEventHandler>(
|
||||||
async (id) => {
|
async (id) => {
|
||||||
const state = { ...defaultMapState, mapId: id };
|
const state: MapState = { ...defaultMapState, mapId: id };
|
||||||
await database?.table("states").put(state);
|
await database?.table("states").put(state);
|
||||||
return state;
|
return state;
|
||||||
},
|
},
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateMap = useCallback(
|
const updateMap = useCallback<UpdateMapEventHanlder>(
|
||||||
async (id, update) => {
|
async (id, update) => {
|
||||||
await database?.table("maps").update(id, update);
|
await database?.table("maps").update(id, update);
|
||||||
},
|
},
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateMapState = useCallback(
|
const updateMapState = useCallback<UpdateMapStateEventHandler>(
|
||||||
async (id, update) => {
|
async (id, update) => {
|
||||||
await database?.table("states").update(id, update);
|
await database?.table("states").update(id, update);
|
||||||
},
|
},
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateMapGroups = useCallback(
|
const updateMapGroups = useCallback<UpdateMapGroupsEventHandler>(
|
||||||
async (groups) => {
|
async (groups) => {
|
||||||
// Update group state immediately to avoid animation delay
|
// Update group state immediately to avoid animation delay
|
||||||
setMapGroups(groups);
|
setMapGroups(groups);
|
||||||
|
|
|
@ -2,21 +2,26 @@ import React, { useState, useEffect, useContext } from "react";
|
||||||
|
|
||||||
import { getSettings } from "../settings";
|
import { getSettings } from "../settings";
|
||||||
|
|
||||||
const SettingsContext = React.createContext({
|
import { Settings } from "../types/Settings";
|
||||||
settings: {},
|
|
||||||
setSettings: () => {},
|
type SettingsContext = {
|
||||||
});
|
settings: Settings;
|
||||||
|
setSettings: React.Dispatch<React.SetStateAction<Settings>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SettingsContext =
|
||||||
|
React.createContext<SettingsContext | undefined>(undefined);
|
||||||
|
|
||||||
const settingsProvider = getSettings();
|
const settingsProvider = getSettings();
|
||||||
|
|
||||||
export function SettingsProvider({ children }: { children: any }) {
|
export function SettingsProvider({ children }: { children: any }) {
|
||||||
const [settings, setSettings] = useState(settingsProvider.getAll());
|
const [settings, setSettings] = useState<Settings>(settingsProvider.getAll());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
settingsProvider.setAll(settings);
|
settingsProvider.setAll(settings);
|
||||||
}, [settings]);
|
}, [settings]);
|
||||||
|
|
||||||
const value: { settings: any, setSettings: any} = {
|
const value = {
|
||||||
settings,
|
settings,
|
||||||
setSettings,
|
setSettings,
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,20 +9,37 @@ import { useLiveQuery } from "dexie-react-hooks";
|
||||||
|
|
||||||
import { useDatabase } from "./DatabaseContext";
|
import { useDatabase } from "./DatabaseContext";
|
||||||
|
|
||||||
import { Token } from "../tokens";
|
|
||||||
import { removeGroupsItems } from "../helpers/group";
|
import { removeGroupsItems } from "../helpers/group";
|
||||||
|
|
||||||
|
import { Token } from "../types/Token";
|
||||||
|
import { Group } from "../types/Group";
|
||||||
|
|
||||||
|
export type AddTokenEventHandler = (token: Token) => Promise<void>;
|
||||||
|
export type RemoveTokensEventHandler = (ids: string[]) => Promise<void>;
|
||||||
|
export type UpdateTokenEventHandler = (
|
||||||
|
id: string,
|
||||||
|
update: Partial<Token>
|
||||||
|
) => Promise<void>;
|
||||||
|
export type GetTokenEventHandler = (
|
||||||
|
tokenId: string
|
||||||
|
) => Promise<Token | undefined>;
|
||||||
|
export type UpdateTokenGroupsEventHandler = (groups: any[]) => Promise<void>;
|
||||||
|
export type UpdateTokensHiddenEventHandler = (
|
||||||
|
ids: string[],
|
||||||
|
hideInSidebar: boolean
|
||||||
|
) => Promise<void>;
|
||||||
|
|
||||||
type TokenDataContext = {
|
type TokenDataContext = {
|
||||||
tokens: Token[];
|
tokens: Token[];
|
||||||
addToken: (token: Token) => Promise<void>;
|
addToken: AddTokenEventHandler;
|
||||||
tokenGroups: any[];
|
tokenGroups: Group[];
|
||||||
removeTokens: (ids: string[]) => Promise<void>;
|
removeTokens: RemoveTokensEventHandler;
|
||||||
updateToken: (id: string, update: Partial<Token>) => Promise<void>;
|
updateToken: UpdateTokenEventHandler;
|
||||||
getToken: (tokenId: string) => Promise<Token | undefined>;
|
getToken: GetTokenEventHandler;
|
||||||
tokensById: Record<string, Token>;
|
tokensById: Record<string, Token>;
|
||||||
tokensLoading: boolean;
|
tokensLoading: boolean;
|
||||||
updateTokenGroups: (groups: any[]) => void;
|
updateTokenGroups: UpdateTokenGroupsEventHandler;
|
||||||
updateTokensHidden: (ids: string[], hideInSidebar: boolean) => void;
|
updateTokensHidden: UpdateTokensHiddenEventHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TokenDataContext =
|
const TokenDataContext =
|
||||||
|
@ -44,7 +61,7 @@ export function TokenDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [tokenGroups, setTokenGroups] = useState([]);
|
const [tokenGroups, setTokenGroups] = useState<Group[]>([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function updateTokenGroups() {
|
async function updateTokenGroups() {
|
||||||
const group = await database?.table("groups").get("tokens");
|
const group = await database?.table("groups").get("tokens");
|
||||||
|
@ -55,7 +72,7 @@ export function TokenDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
}
|
}
|
||||||
}, [tokenGroupQuery, database]);
|
}, [tokenGroupQuery, database]);
|
||||||
|
|
||||||
const getToken = useCallback(
|
const getToken = useCallback<GetTokenEventHandler>(
|
||||||
async (tokenId) => {
|
async (tokenId) => {
|
||||||
let token = await database?.table("tokens").get(tokenId);
|
let token = await database?.table("tokens").get(tokenId);
|
||||||
return token;
|
return token;
|
||||||
|
@ -64,7 +81,7 @@ export function TokenDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add token and add it to the token group
|
// Add token and add it to the token group
|
||||||
const addToken = useCallback(
|
const addToken = useCallback<AddTokenEventHandler>(
|
||||||
async (token) => {
|
async (token) => {
|
||||||
if (database) {
|
if (database) {
|
||||||
await database.table("tokens").add(token);
|
await database.table("tokens").add(token);
|
||||||
|
@ -77,7 +94,7 @@ export function TokenDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeTokens = useCallback(
|
const removeTokens = useCallback<RemoveTokensEventHandler>(
|
||||||
async (ids) => {
|
async (ids) => {
|
||||||
if (database) {
|
if (database) {
|
||||||
const tokens = await database.table("tokens").bulkGet(ids);
|
const tokens = await database.table("tokens").bulkGet(ids);
|
||||||
|
@ -100,14 +117,14 @@ export function TokenDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateToken = useCallback(
|
const updateToken = useCallback<UpdateTokenEventHandler>(
|
||||||
async (id, update) => {
|
async (id, update) => {
|
||||||
await database?.table("tokens").update(id, update);
|
await database?.table("tokens").update(id, update);
|
||||||
},
|
},
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateTokensHidden = useCallback(
|
const updateTokensHidden = useCallback<UpdateTokensHiddenEventHandler>(
|
||||||
async (ids: string[], hideInSidebar: boolean) => {
|
async (ids: string[], hideInSidebar: boolean) => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
ids.map((id) => database?.table("tokens").update(id, { hideInSidebar }))
|
ids.map((id) => database?.table("tokens").update(id, { hideInSidebar }))
|
||||||
|
@ -116,8 +133,8 @@ export function TokenDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
[database]
|
[database]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateTokenGroups = useCallback(
|
const updateTokenGroups = useCallback<UpdateTokenGroupsEventHandler>(
|
||||||
async (groups) => {
|
async (groups: Group[]) => {
|
||||||
// Update group state immediately to avoid animation delay
|
// Update group state immediately to avoid animation delay
|
||||||
setTokenGroups(groups);
|
setTokenGroups(groups);
|
||||||
await database?.table("groups").update("tokens", { items: groups });
|
await database?.table("groups").update("tokens", { items: groups });
|
||||||
|
|
|
@ -5,14 +5,14 @@ import { useSettings } from "../contexts/SettingsContext";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to get and set nested settings that are saved in local storage
|
* 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
|
* @param {string} path The path to the setting within the Settings object provided by the SettingsContext
|
||||||
*/
|
*/
|
||||||
function useSetting(path) {
|
function useSetting<Type>(path: string): [Type, (value: Type) => void] {
|
||||||
const { settings, setSettings } = useSettings();
|
const { settings, setSettings } = useSettings();
|
||||||
|
|
||||||
const setting = get(settings, path);
|
const setting = get(settings, path) as Type;
|
||||||
|
|
||||||
const setSetting = (value) =>
|
const setSetting = (value: Type) =>
|
||||||
setSettings((prev) => {
|
setSettings((prev) => {
|
||||||
const updated = set({ ...prev }, path, value);
|
const updated = set({ ...prev }, path, value);
|
||||||
return updated;
|
return updated;
|
|
@ -9,13 +9,16 @@ import TokenPreview from "../components/token/TokenPreview";
|
||||||
import { isEmpty } from "../helpers/shared";
|
import { isEmpty } from "../helpers/shared";
|
||||||
|
|
||||||
import useResponsiveLayout from "../hooks/useResponsiveLayout";
|
import useResponsiveLayout from "../hooks/useResponsiveLayout";
|
||||||
|
|
||||||
import { Token } from "../types/Token";
|
import { Token } from "../types/Token";
|
||||||
|
|
||||||
|
import { UpdateTokenEventHandler } from "../contexts/TokenDataContext";
|
||||||
|
|
||||||
type EditModalProps = {
|
type EditModalProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onDone: () => void;
|
onDone: () => void;
|
||||||
token: Token;
|
token: Token;
|
||||||
onUpdateToken: (id: string, update: Partial<Token>) => void;
|
onUpdateToken: UpdateTokenEventHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
function EditTokenModal({
|
function EditTokenModal({
|
||||||
|
|
|
@ -2,9 +2,11 @@ import { Box, Label, Flex, Button, Text } from "theme-ui";
|
||||||
|
|
||||||
import Modal from "../components/Modal";
|
import Modal from "../components/Modal";
|
||||||
|
|
||||||
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
|
|
||||||
type GameExpiredModalProps = {
|
type GameExpiredModalProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: () => void;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
function GameExpiredModal({ isOpen, onRequestClose }: GameExpiredModalProps) {
|
function GameExpiredModal({ isOpen, onRequestClose }: GameExpiredModalProps) {
|
||||||
|
|
|
@ -5,11 +5,13 @@ import Modal from "../components/Modal";
|
||||||
import Markdown from "../components/Markdown";
|
import Markdown from "../components/Markdown";
|
||||||
import Link from "../components/Link";
|
import Link from "../components/Link";
|
||||||
|
|
||||||
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
|
|
||||||
const gettingStarted = raw("../docs/howTo/gettingStarted.md");
|
const gettingStarted = raw("../docs/howTo/gettingStarted.md");
|
||||||
|
|
||||||
type GettingStartedModalProps = {
|
type GettingStartedModalProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: () => void;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
function GettingStartedModal({
|
function GettingStartedModal({
|
||||||
|
|
|
@ -3,11 +3,15 @@ import { Box, Input, Button, Label, Flex } from "theme-ui";
|
||||||
|
|
||||||
import Modal from "../components/Modal";
|
import Modal from "../components/Modal";
|
||||||
|
|
||||||
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
|
|
||||||
|
export type GroupNameEventHandler = (name: string) => void;
|
||||||
|
|
||||||
type GroupNameModalProps = {
|
type GroupNameModalProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: () => void;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
name: string;
|
name: string;
|
||||||
onSubmit: (name: string) => void;
|
onSubmit: GroupNameEventHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
function GroupNameModal({
|
function GroupNameModal({
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { Map } from "../types/Map";
|
||||||
import { MapState } from "../types/MapState";
|
import { MapState } from "../types/MapState";
|
||||||
import { Token } from "../types/Token";
|
import { Token } from "../types/Token";
|
||||||
import { Group } from "../types/Group";
|
import { Group } from "../types/Group";
|
||||||
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
|
|
||||||
const importDBName = "OwlbearRodeoImportDB";
|
const importDBName = "OwlbearRodeoImportDB";
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ function ImportExportModal({
|
||||||
onRequestClose,
|
onRequestClose,
|
||||||
}: {
|
}: {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: () => void;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
}) {
|
}) {
|
||||||
const { worker } = useDatabase();
|
const { worker } = useDatabase();
|
||||||
const userId = useUserId();
|
const userId = useUserId();
|
||||||
|
|
|
@ -4,9 +4,11 @@ import { useHistory } from "react-router-dom";
|
||||||
|
|
||||||
import Modal from "../components/Modal";
|
import Modal from "../components/Modal";
|
||||||
|
|
||||||
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
|
|
||||||
type JoinModalProps = {
|
type JoinModalProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: () => void;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
function JoinModal({ isOpen, onRequestClose }: JoinModalProps) {
|
function JoinModal({ isOpen, onRequestClose }: JoinModalProps) {
|
||||||
|
|
|
@ -12,21 +12,7 @@ import { Map } from "../types/Map";
|
||||||
import { Group, GroupContainer } from "../types/Group";
|
import { Group, GroupContainer } from "../types/Group";
|
||||||
import { MapState } from "../types/MapState";
|
import { MapState } from "../types/MapState";
|
||||||
import { Token } from "../types/Token";
|
import { Token } from "../types/Token";
|
||||||
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
type SelectDataProps = {
|
|
||||||
isOpen: boolean;
|
|
||||||
onRequestClose: () => void;
|
|
||||||
onConfirm: (
|
|
||||||
checkedMaps: SelectData[],
|
|
||||||
checkedTokens: SelectData[],
|
|
||||||
checkedMapGroups: Group[],
|
|
||||||
checkedTokenGroups: Group[]
|
|
||||||
) => void;
|
|
||||||
confirmText: string;
|
|
||||||
label: string;
|
|
||||||
databaseName: string;
|
|
||||||
filter: (table: string, data: Map | MapState | Token, id: string) => boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type SelectData = {
|
export type SelectData = {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -35,6 +21,23 @@ export type SelectData = {
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ConfirmDataEventHandler = (
|
||||||
|
checkedMaps: SelectData[],
|
||||||
|
checkedTokens: SelectData[],
|
||||||
|
checkedMapGroups: Group[],
|
||||||
|
checkedTokenGroups: Group[]
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
type SelectDataProps = {
|
||||||
|
isOpen: boolean;
|
||||||
|
onRequestClose: RequestCloseEventHandler;
|
||||||
|
onConfirm: ConfirmDataEventHandler;
|
||||||
|
confirmText: string;
|
||||||
|
label: string;
|
||||||
|
databaseName: string;
|
||||||
|
filter: (table: string, data: Map | MapState | Token, id: string) => boolean;
|
||||||
|
};
|
||||||
|
|
||||||
type DataRecord = Record<string, SelectData>;
|
type DataRecord = Record<string, SelectData>;
|
||||||
|
|
||||||
function SelectDataModal({
|
function SelectDataModal({
|
||||||
|
|
|
@ -8,12 +8,16 @@ import { dice } from "../dice";
|
||||||
|
|
||||||
import useResponsiveLayout from "../hooks/useResponsiveLayout";
|
import useResponsiveLayout from "../hooks/useResponsiveLayout";
|
||||||
|
|
||||||
|
import {
|
||||||
|
DiceSelectEventHandler,
|
||||||
|
RequestCloseEventHandler,
|
||||||
|
} from "../types/Events";
|
||||||
import { DefaultDice } from "../types/Dice";
|
import { DefaultDice } from "../types/Dice";
|
||||||
|
|
||||||
type SelectDiceProps = {
|
type SelectDiceProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: () => void;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
onDone: (dice: DefaultDice) => void;
|
onDone: DiceSelectEventHandler;
|
||||||
defaultDice: DefaultDice;
|
defaultDice: DefaultDice;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,17 @@ import { GroupProvider } from "../contexts/GroupContext";
|
||||||
import { TileDragProvider } from "../contexts/TileDragContext";
|
import { TileDragProvider } from "../contexts/TileDragContext";
|
||||||
|
|
||||||
import { Map } from "../types/Map";
|
import { Map } from "../types/Map";
|
||||||
import { MapState } from "../types/MapState";
|
import {
|
||||||
|
MapChangeEventHandler,
|
||||||
|
MapResetEventHandler,
|
||||||
|
RequestCloseEventHandler,
|
||||||
|
} from "../types/Events";
|
||||||
|
|
||||||
type SelectMapProps = {
|
type SelectMapProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onDone: () => void;
|
onDone: RequestCloseEventHandler;
|
||||||
onMapChange: (map?: Map, mapState?: MapState) => void;
|
onMapChange: MapChangeEventHandler;
|
||||||
onMapReset: (newState: MapState) => void;
|
onMapReset: MapResetEventHandler;
|
||||||
currentMap?: Map;
|
currentMap?: Map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -294,7 +298,7 @@ function SelectMapModal({
|
||||||
</TileDragProvider>
|
</TileDragProvider>
|
||||||
<MapEditBar
|
<MapEditBar
|
||||||
currentMap={currentMap}
|
currentMap={currentMap}
|
||||||
disabled={isLoading || editingMapId}
|
disabled={isLoading || !!editingMapId}
|
||||||
onMapChange={onMapChange}
|
onMapChange={onMapChange}
|
||||||
onMapReset={onMapReset}
|
onMapReset={onMapReset}
|
||||||
onLoad={setIsLoading}
|
onLoad={setIsLoading}
|
||||||
|
|
|
@ -36,11 +36,15 @@ import { TileDragProvider } from "../contexts/TileDragContext";
|
||||||
import { useMapStage } from "../contexts/MapStageContext";
|
import { useMapStage } from "../contexts/MapStageContext";
|
||||||
|
|
||||||
import { TokenState } from "../types/TokenState";
|
import { TokenState } from "../types/TokenState";
|
||||||
|
import {
|
||||||
|
MapTokensStateCreateHandler,
|
||||||
|
RequestCloseEventHandler,
|
||||||
|
} from "../types/Events";
|
||||||
|
|
||||||
type SelectTokensModalProps = {
|
type SelectTokensModalProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: () => void;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
onMapTokensStateCreate: (states: TokenState[]) => void;
|
onMapTokensStateCreate: MapTokensStateCreateHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
function SelectTokensModal({
|
function SelectTokensModal({
|
||||||
|
|
|
@ -21,24 +21,27 @@ import useSetting from "../hooks/useSetting";
|
||||||
|
|
||||||
import ConfirmModal from "./ConfirmModal";
|
import ConfirmModal from "./ConfirmModal";
|
||||||
import ImportExportModal from "./ImportExportModal";
|
import ImportExportModal from "./ImportExportModal";
|
||||||
import { MapState } from "../components/map/Map";
|
|
||||||
|
import { MapState } from "../types/MapState";
|
||||||
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
|
|
||||||
function SettingsModal({
|
function SettingsModal({
|
||||||
isOpen,
|
isOpen,
|
||||||
onRequestClose,
|
onRequestClose,
|
||||||
}: {
|
}: {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: () => void;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
}) {
|
}) {
|
||||||
const { database, databaseStatus } = useDatabase();
|
const { database, databaseStatus } = useDatabase();
|
||||||
const userId = useUserId();
|
const userId = useUserId();
|
||||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||||
const [labelSize, setLabelSize] = useSetting("map.labelSize");
|
const [labelSize, setLabelSize] = useSetting<number>("map.labelSize");
|
||||||
const [gridSnappingSensitivity, setGridSnappingSensitivity] = useSetting(
|
const [gridSnappingSensitivity, setGridSnappingSensitivity] =
|
||||||
"map.gridSnappingSensitivity"
|
useSetting<number>("map.gridSnappingSensitivity");
|
||||||
);
|
const [showFogGuides, setShowFogGuides] =
|
||||||
const [showFogGuides, setShowFogGuides] = useSetting("fog.showGuides");
|
useSetting<boolean>("fog.showGuides");
|
||||||
const [fogEditOpacity, setFogEditOpacity] = useSetting("fog.editOpacity");
|
const [fogEditOpacity, setFogEditOpacity] =
|
||||||
|
useSetting<number>("fog.editOpacity");
|
||||||
const [storageEstimate, setStorageEstimate] = useState<StorageEstimate>();
|
const [storageEstimate, setStorageEstimate] = useState<StorageEstimate>();
|
||||||
const [isImportExportModalOpen, setIsImportExportModalOpen] = useState(false);
|
const [isImportExportModalOpen, setIsImportExportModalOpen] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
|
@ -9,7 +9,15 @@ import useSetting from "../hooks/useSetting";
|
||||||
|
|
||||||
import Modal from "../components/Modal";
|
import Modal from "../components/Modal";
|
||||||
|
|
||||||
function StartModal({ isOpen, onRequestClose }: { isOpen: boolean, onRequestClose: () => void}) {
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
|
|
||||||
|
function StartModal({
|
||||||
|
isOpen,
|
||||||
|
onRequestClose,
|
||||||
|
}: {
|
||||||
|
isOpen: boolean;
|
||||||
|
onRequestClose: RequestCloseEventHandler;
|
||||||
|
}) {
|
||||||
let history = useHistory();
|
let history = useHistory();
|
||||||
const { password, setPassword } = useAuth();
|
const { password, setPassword } = useAuth();
|
||||||
|
|
||||||
|
@ -17,7 +25,7 @@ function StartModal({ isOpen, onRequestClose }: { isOpen: boolean, onRequestClos
|
||||||
setPassword(event.target.value);
|
setPassword(event.target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [usePassword, setUsePassword] = useSetting("game.usePassword");
|
const [usePassword, setUsePassword] = useSetting<boolean>("game.usePassword");
|
||||||
function handleUsePasswordChange(event: ChangeEvent<HTMLInputElement>) {
|
function handleUsePasswordChange(event: ChangeEvent<HTMLInputElement>) {
|
||||||
setUsePassword(event.target.checked);
|
setUsePassword(event.target.checked);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,22 @@ import { Box, Text, Button, Label, Flex } from "theme-ui";
|
||||||
|
|
||||||
import Modal from "../components/Modal";
|
import Modal from "../components/Modal";
|
||||||
|
|
||||||
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
|
|
||||||
|
export type StreamStartEventHandler = () => void;
|
||||||
|
export type StreamEndEventHandler = (stream: MediaStream) => void;
|
||||||
|
|
||||||
type StartStreamProps = {
|
type StartStreamProps = {
|
||||||
isOpen: boolean,
|
isOpen: boolean;
|
||||||
onRequestClose: () => void,
|
onRequestClose: RequestCloseEventHandler;
|
||||||
isSupported: boolean,
|
isSupported: boolean;
|
||||||
unavailableMessage: JSX.Element,
|
unavailableMessage: JSX.Element;
|
||||||
stream: MediaStream,
|
stream: MediaStream;
|
||||||
noAudioTrack: boolean,
|
noAudioTrack: boolean;
|
||||||
noAudioMessage: JSX.Element,
|
noAudioMessage: JSX.Element;
|
||||||
onStreamStart: any,
|
onStreamStart: StreamStartEventHandler;
|
||||||
onStreamEnd: any,
|
onStreamEnd: StreamEndEventHandler;
|
||||||
}
|
};
|
||||||
|
|
||||||
function StartStreamModal({
|
function StartStreamModal({
|
||||||
isOpen,
|
isOpen,
|
||||||
|
|
|
@ -7,13 +7,19 @@ import { getHMSDuration, getDurationHMS } from "../helpers/timer";
|
||||||
|
|
||||||
import useSetting from "../hooks/useSetting";
|
import useSetting from "../hooks/useSetting";
|
||||||
|
|
||||||
|
import { RequestCloseEventHandler } from "../types/Events";
|
||||||
|
import { Timer } from "../types/Timer";
|
||||||
|
|
||||||
|
export type TimerStartEventHandler = (event: Timer) => void;
|
||||||
|
export type TimerStopEventHandler = () => void;
|
||||||
|
|
||||||
type StartTimerProps = {
|
type StartTimerProps = {
|
||||||
isOpen: boolean,
|
isOpen: boolean;
|
||||||
onRequestClose: () => void,
|
onRequestClose: RequestCloseEventHandler;
|
||||||
onTimerStart: any,
|
onTimerStart: TimerStartEventHandler;
|
||||||
onTimerStop: any,
|
onTimerStop: TimerStopEventHandler;
|
||||||
timer: any,
|
timer?: Timer;
|
||||||
}
|
};
|
||||||
|
|
||||||
function StartTimerModal({
|
function StartTimerModal({
|
||||||
isOpen,
|
isOpen,
|
||||||
|
@ -27,9 +33,9 @@ function StartTimerModal({
|
||||||
inputRef.current && inputRef.current.focus();
|
inputRef.current && inputRef.current.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
const [hour, setHour] = useSetting("timer.hour");
|
const [hour, setHour] = useSetting<number>("timer.hour");
|
||||||
const [minute, setMinute] = useSetting("timer.minute");
|
const [minute, setMinute] = useSetting<number>("timer.minute");
|
||||||
const [second, setSecond] = useSetting("timer.second");
|
const [second, setSecond] = useSetting<number>("timer.second");
|
||||||
|
|
||||||
function handleSubmit(event: ChangeEvent<HTMLInputElement>) {
|
function handleSubmit(event: ChangeEvent<HTMLInputElement>) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -85,10 +91,10 @@ function StartTimerModal({
|
||||||
</Text>
|
</Text>
|
||||||
<Input
|
<Input
|
||||||
sx={inputStyle}
|
sx={inputStyle}
|
||||||
value={`${timer ? timerHMS.hour : hour}`}
|
value={`${timerHMS ? timerHMS.hour : hour}`}
|
||||||
onChange={(e) => setHour(parseValue(e.target.value, 24))}
|
onChange={(e) => setHour(parseValue(e.target.value, 24))}
|
||||||
type="number"
|
type="number"
|
||||||
disabled={timer}
|
disabled={!!timer}
|
||||||
min={0}
|
min={0}
|
||||||
max={24}
|
max={24}
|
||||||
/>
|
/>
|
||||||
|
@ -97,11 +103,11 @@ function StartTimerModal({
|
||||||
</Text>
|
</Text>
|
||||||
<Input
|
<Input
|
||||||
sx={inputStyle}
|
sx={inputStyle}
|
||||||
value={`${timer ? timerHMS.minute : minute}`}
|
value={`${timerHMS ? timerHMS.minute : minute}`}
|
||||||
onChange={(e) => setMinute(parseValue(e.target.value, 59))}
|
onChange={(e) => setMinute(parseValue(e.target.value, 59))}
|
||||||
type="number"
|
type="number"
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
disabled={timer}
|
disabled={!!timer}
|
||||||
min={0}
|
min={0}
|
||||||
max={59}
|
max={59}
|
||||||
/>
|
/>
|
||||||
|
@ -110,10 +116,10 @@ function StartTimerModal({
|
||||||
</Text>
|
</Text>
|
||||||
<Input
|
<Input
|
||||||
sx={inputStyle}
|
sx={inputStyle}
|
||||||
value={`${timer ? timerHMS.second : second}`}
|
value={`${timerHMS ? timerHMS.second : second}`}
|
||||||
onChange={(e) => setSecond(parseValue(e.target.value, 59))}
|
onChange={(e) => setSecond(parseValue(e.target.value, 59))}
|
||||||
type="number"
|
type="number"
|
||||||
disabled={timer}
|
disabled={!!timer}
|
||||||
min={0}
|
min={0}
|
||||||
max={59}
|
max={59}
|
||||||
/>
|
/>
|
||||||
|
|
14
src/types/Events.ts
Normal file
14
src/types/Events.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { DefaultDice } from "./Dice";
|
||||||
|
import { Map } from "./Map";
|
||||||
|
import { MapState } from "./MapState";
|
||||||
|
import { TokenState } from "./TokenState";
|
||||||
|
|
||||||
|
export type MapChangeEventHandler = (map?: Map, mapState?: MapState) => void;
|
||||||
|
|
||||||
|
export type MapResetEventHandler = (newState: MapState) => void;
|
||||||
|
|
||||||
|
export type DiceSelectEventHandler = (dice: DefaultDice) => void;
|
||||||
|
|
||||||
|
export type RequestCloseEventHandler = () => void;
|
||||||
|
|
||||||
|
export type MapTokensStateCreateHandler = (states: TokenState[]) => void;
|
|
@ -2998,6 +2998,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/lodash" "*"
|
"@types/lodash" "*"
|
||||||
|
|
||||||
|
"@types/lodash.set@^4.3.6":
|
||||||
|
version "4.3.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/lodash.set/-/lodash.set-4.3.6.tgz#33e635c2323f855359225df6a5c8c6f1f1908264"
|
||||||
|
integrity sha512-ZeGDDlnRYTvS31Laij0RsSaguIUSBTYIlJFKL3vm3T2OAZAQj2YpSvVWJc0WiG4jqg9fGX6PAPGvDqBcHfSgFg==
|
||||||
|
dependencies:
|
||||||
|
"@types/lodash" "*"
|
||||||
|
|
||||||
"@types/lodash@*":
|
"@types/lodash@*":
|
||||||
version "4.14.170"
|
version "4.14.170"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6"
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user