Typescript

This commit is contained in:
Mitchell McCaffrey 2021-07-17 18:18:57 +10:00
parent 2a053f4854
commit a4363e542c
30 changed files with 247 additions and 163 deletions

View File

@ -99,6 +99,7 @@
"@types/deep-diff": "^1.0.0",
"@types/file-saver": "^2.0.2",
"@types/jest": "^26.0.23",
"@types/lodash.chunk": "^4.2.6",
"@types/lodash.clonedeep": "^4.5.6",
"@types/lodash.get": "^4.4.6",
"@types/lodash.set": "^4.3.6",

View File

@ -18,11 +18,13 @@ import SelectDiceButton from "./SelectDiceButton";
import Divider from "../Divider";
import Dice from "../../dice/Dice";
import { dice } from "../../dice";
import useSetting from "../../hooks/useSetting";
import { DefaultDice, DiceRoll, DiceType } from "../../types/Dice";
import Dice from "../../dice/Dice";
import { DiceShareChangeEventHandler } from "../../types/Events";
type DiceButtonsProps = {
diceRolls: DiceRoll[];
@ -31,7 +33,7 @@ type DiceButtonsProps = {
diceTraySize: "single" | "double";
onDiceTraySizeChange: (newSize: "single" | "double") => void;
shareDice: boolean;
onShareDiceChange: (value: boolean) => void;
onShareDiceChange: DiceShareChangeEventHandler;
loading: boolean;
};

View File

@ -3,6 +3,7 @@ import { Vector3 } from "@babylonjs/core/Maths/math";
import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight";
import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator";
import { CubeTexture } from "@babylonjs/core/Materials/Textures/cubeTexture";
import { Scene } from "@babylonjs/core";
import { Box } from "theme-ui";
// @ts-ignore
@ -19,16 +20,21 @@ import DiceTray from "../../dice/diceTray/DiceTray";
import { useDiceLoading } from "../../contexts/DiceLoadingContext";
import { getDiceRoll } from "../../helpers/dice";
import useSetting from "../../hooks/useSetting";
import { DefaultDice, DiceMesh, DiceRoll, DiceType } from "../../types/Dice";
import { Scene } from "@babylonjs/core";
import {
DiceRollsChangeEventHandler,
DiceShareChangeEventHandler,
} from "../../types/Events";
type DiceTrayOverlayProps = {
isOpen: boolean;
shareDice: boolean;
onShareDiceChange: () => void;
onShareDiceChange: DiceShareChangeEventHandler;
diceRolls: DiceRoll[];
onDiceRollsChange: (newRolls: DiceRoll[]) => void;
onDiceRollsChange: DiceRollsChangeEventHandler;
};
function DiceTrayOverlay({

View File

@ -12,7 +12,6 @@ import MapMeasure from "./MapMeasure";
import NetworkedMapPointer from "../../network/NetworkedMapPointer";
import MapNotes from "./MapNotes";
import { useTokenData } from "../../contexts/TokenDataContext";
import { useSettings } from "../../contexts/SettingsContext";
import TokenMenu from "../token/TokenMenu";
@ -29,13 +28,12 @@ import {
import Session from "../../network/Session";
import { Drawing, DrawingState } from "../../types/Drawing";
import { Fog, FogState } from "../../types/Fog";
import { Map, MapActions, MapToolId } from "../../types/Map";
import { Map as MapType, MapActions, MapToolId } from "../../types/Map";
import { MapState } from "../../types/MapState";
import { Settings } from "../../types/Settings";
import {
MapChangeEventHandler,
MapResetEventHandler,
MapTokensStateCreateHandler,
MapTokenStateRemoveHandler,
NoteChangeEventHandler,
NoteRemoveEventHander,
@ -47,7 +45,7 @@ import { TokenDraggingOptions, TokenMenuOptions } from "../../types/Token";
import { Note, NoteDraggingOptions, NoteMenuOptions } from "../../types/Note";
type MapProps = {
map: Map | null;
map: MapType | null;
mapState: MapState | null;
mapActions: MapActions;
onMapTokenStateChange: TokenStateChangeEventHandler;
@ -95,8 +93,6 @@ function Map({
}: MapProps) {
const { addToast } = useToasts();
const { tokensById } = useTokenData();
const [selectedToolId, setSelectedToolId] = useState<MapToolId>("move");
const { settings, setSettings } = useSettings();

View File

@ -193,7 +193,11 @@ function MapInteraction({
return (
<MapInteractionProvider value={mapInteraction}>
<GridProvider grid={map?.grid} width={mapWidth} height={mapHeight}>
<GridProvider
grid={map?.grid || null}
width={mapWidth}
height={mapHeight}
>
<Box
sx={{
position: "relative",

View File

@ -52,7 +52,7 @@ function MapMeasure({ map, active }: MapMeasureProps) {
useState<MeasureData | null>(null);
const [isBrushDown, setIsBrushDown] = useState(false);
const gridScale = parseGridScale(active && grid.measurement.scale);
const gridScale = parseGridScale(active ? grid.measurement.scale : null);
const snapPositionToGrid = useGridSnapping(
grid.measurement.type === "euclidean" ? 0 : 1,

View File

@ -1,4 +1,3 @@
import React from "react";
import { Grid } from "theme-ui";
import Tile from "../tile/Tile";

View File

@ -9,15 +9,14 @@ type MapTileImageProps = {
} & ImageProps;
function MapTileImage({ map, ...props }: MapTileImageProps) {
const mapURL = useDataURL(
map,
defaultMapSources,
undefined,
map.type === "file"
);
const mapURL = useDataURL(
map,
defaultMapSources,
undefined,
map.type === "file"
);
return <Image src={mapURL} {...props} />;
}
);
return <Image src={mapURL} {...props} />;
}
export default MapTileImage;

View File

@ -26,11 +26,14 @@ import { useKeyboard } from "../../../contexts/KeyboardContext";
import shortcuts from "../../../shortcuts";
import { DrawingToolSettings, DrawingToolType } from "../../../types/Drawing";
import {
DrawingToolSettings as DrawingToolSettingsType,
DrawingToolType,
} from "../../../types/Drawing";
type DrawingToolSettingsProps = {
settings: DrawingToolSettings;
onSettingChange: (change: Partial<DrawingToolSettings>) => void;
settings: DrawingToolSettingsType;
onSettingChange: (change: Partial<DrawingToolSettingsType>) => void;
onToolAction: (action: string) => void;
disabledActions: string[];
};

View File

@ -23,11 +23,14 @@ import { useKeyboard } from "../../../contexts/KeyboardContext";
import shortcuts from "../../../shortcuts";
import { FogToolSettings, FogToolType } from "../../../types/Fog";
import {
FogToolSettings as FogToolSettingsType,
FogToolType,
} from "../../../types/Fog";
type FogToolSettingsProps = {
settings: FogToolSettings;
onSettingChange: (change: Partial<FogToolSettings>) => void;
settings: FogToolSettingsType;
onSettingChange: (change: Partial<FogToolSettingsType>) => void;
onToolAction: (action: string) => void;
disabledActions: string[];
};

View File

@ -2,11 +2,11 @@ import { Flex } from "theme-ui";
import ColorControl from "./ColorControl";
import { PointerToolSettings } from "../../../types/Pointer";
import { PointerToolSettings as PointerToolSettingsType } from "../../../types/Pointer";
type PointerToolSettingsProps = {
settings: PointerToolSettings;
onSettingChange: (change: Partial<PointerToolSettings>) => void;
settings: PointerToolSettingsType;
onSettingChange: (change: Partial<PointerToolSettingsType>) => void;
};
function PointerToolSettings({

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import { useState } from "react";
import { IconButton } from "theme-ui";
import AddPartyMemberModal from "../../modals/AddPartyMemberModal";

View File

@ -1,16 +1,18 @@
import React, { useState, useEffect, ChangeEvent } from "react";
import { useState, useEffect, ChangeEvent, FormEvent } from "react";
import { IconButton } from "theme-ui";
import ChangeNicknameModal from "../../modals/ChangeNicknameModal";
import ChangeNicknameIcon from "../../icons/ChangeNicknameIcon";
type ChangeNicknameButtonProps = {
nickname: string;
onChange: (nickname: string) => void;
};
function ChangeNicknameButton({
nickname,
onChange,
}: {
nickname: string;
onChange;
}) {
}: ChangeNicknameButtonProps) {
const [isChangeModalOpen, setIsChangeModalOpen] = useState(false);
function openModal() {
setIsChangeModalOpen(true);
@ -25,7 +27,7 @@ function ChangeNicknameButton({
setChangedNickname(nickname);
}, [nickname]);
function handleChangeSubmit(event: Event) {
function handleChangeSubmit(event: FormEvent) {
event.preventDefault();
onChange(changedNickname);
closeModal();

View File

@ -1,14 +1,13 @@
import { Flex, Box, Text } from "theme-ui";
import { DiceRoll as DiceRollType, DiceType } from "../../types/Dice";
function DiceRoll({
rolls,
type,
children,
}: {
rolls;
type: string;
children;
}) {
type DiceRollProps = {
rolls: DiceRollType[];
type: DiceType;
children: React.ReactNode;
};
function DiceRoll({ rolls, type, children }: DiceRollProps) {
return (
<Flex sx={{ flexWrap: "wrap" }}>
<Box sx={{ transform: "scale(0.8)" }}>{children}</Box>

View File

@ -13,8 +13,9 @@ import D100Icon from "../../icons/D100Icon";
import DiceRoll from "./DiceRoll";
import { getDiceRollTotal } from "../../helpers/dice";
import { DiceRoll as DiceRollType, DiceType } from "../../types/Dice";
const diceIcons = [
const diceIcons: { type: DiceType; Icon: React.ElementType }[] = [
{ type: "d20", Icon: D20Icon },
{ type: "d12", Icon: D12Icon },
{ type: "d10", Icon: D10Icon },
@ -24,7 +25,11 @@ const diceIcons = [
{ type: "d100", Icon: D100Icon },
];
function DiceRolls({ rolls }: { rolls }) {
type DiceRollsProps = {
rolls: DiceRollType[];
};
function DiceRolls({ rolls }: DiceRollsProps) {
const total = getDiceRollTotal(rolls);
const [expanded, setExpanded] = useState<boolean>(false);

View File

@ -9,19 +9,27 @@ import useSetting from "../../hooks/useSetting";
import LoadingOverlay from "../LoadingOverlay";
import {
DiceShareChangeEventHandler,
DiceRollsChangeEventHandler,
} from "../../types/Events";
import { DiceRoll } from "../../types/Dice";
const DiceTrayOverlay = React.lazy(() => import("../dice/DiceTrayOverlay"));
type DiceTrayButtonProps = {
shareDice: boolean;
onShareDiceChange: DiceShareChangeEventHandler;
diceRolls: DiceRoll[];
onDiceRollsChange: DiceRollsChangeEventHandler;
};
function DiceTrayButton({
shareDice,
onShareDiceChange,
diceRolls,
onDiceRollsChange,
}: {
shareDice: boolean;
onShareDiceChange;
diceRolls: [];
onDiceRollsChange;
}) {
}: DiceTrayButtonProps) {
const [isExpanded, setIsExpanded] = useState(false);
const [fullScreen] = useSetting("map.fullScreen");

View File

@ -2,17 +2,15 @@ import { Text, Flex } from "theme-ui";
import Stream from "./Stream";
import DiceRolls from "./DiceRolls";
import { DiceRoll } from "../../types/Dice";
// TODO: check if stream is a required or optional param
function Nickname({
nickname,
stream,
diceRolls,
}: {
type NicknameProps = {
nickname: string;
stream?;
diceRolls;
}) {
stream?: MediaStream;
diceRolls?: DiceRoll[];
};
function Nickname({ nickname, stream, diceRolls }: NicknameProps) {
return (
<Flex sx={{ flexDirection: "column" }}>
<Text

View File

@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import { useEffect } from "react";
import { Flex, Box, Text } from "theme-ui";
import SimpleBar from "simplebar-react";
@ -15,6 +15,20 @@ import useSetting from "../../hooks/useSetting";
import { useParty } from "../../contexts/PartyContext";
import { usePlayerState, usePlayerUpdater } from "../../contexts/PlayerContext";
import { DiceRoll } from "../../types/Dice";
import {
StreamEndEventHandler,
StreamStartEventHandler,
} from "../../types/Events";
import { Timer as TimerType } from "../../types/Timer";
type PartyProps = {
gameId: string;
stream: MediaStream | null;
partyStreams: Record<string, MediaStream>;
onStreamStart: StreamStartEventHandler;
onStreamEnd: StreamEndEventHandler;
};
function Party({
gameId,
@ -22,33 +36,27 @@ function Party({
partyStreams,
onStreamStart,
onStreamEnd,
}: {
gameId: string;
stream;
partyStreams;
onStreamStart;
onStreamEnd;
}) {
}: PartyProps) {
const setPlayerState = usePlayerUpdater();
const playerState = usePlayerState();
const partyState = useParty();
const [fullScreen] = useSetting<boolean>("map.fullScreen");
const [shareDice, setShareDice] = useSetting("dice.shareDice");
const [shareDice, setShareDice] = useSetting<boolean>("dice.shareDice");
function handleTimerStart(newTimer: PartyTimer) {
function handleTimerStart(newTimer: TimerType) {
setPlayerState((prevState) => ({ ...prevState, timer: newTimer }));
}
function handleTimerStop() {
setPlayerState((prevState) => ({ ...prevState, timer: null }));
setPlayerState((prevState) => ({ ...prevState, timer: undefined }));
}
useEffect(() => {
let prevTime = performance.now();
let request = requestAnimationFrame(update);
let counter = 0;
function update(time) {
function update(time: number) {
request = requestAnimationFrame(update);
const deltaTime = time - prevTime;
prevTime = time;
@ -57,12 +65,12 @@ function Party({
counter += deltaTime;
// Update timer every second
if (counter > 1000) {
const newTimer: PartyTimer = {
const newTimer: TimerType = {
...playerState.timer,
current: playerState.timer.current - counter,
};
if (newTimer.current < 0) {
setPlayerState((prevState) => ({ ...prevState, timer: null }));
setPlayerState((prevState) => ({ ...prevState, timer: undefined }));
} else {
setPlayerState((prevState) => ({ ...prevState, timer: newTimer }));
}
@ -79,9 +87,9 @@ function Party({
setPlayerState((prevState) => ({ ...prevState, nickname: newNickname }));
}
function handleDiceRollsChange(newDiceRolls: number[]) {
function handleDiceRollsChange(newDiceRolls: DiceRoll[]) {
setPlayerState(
(prevState: PlayerDice) => ({
(prevState) => ({
...prevState,
dice: { share: shareDice, rolls: newDiceRolls },
}),
@ -91,7 +99,7 @@ function Party({
function handleShareDiceChange(newShareDice: boolean) {
setShareDice(newShareDice);
setPlayerState((prevState: PlayerInfo) => ({
setPlayerState((prevState) => ({
...prevState,
dice: { ...prevState.dice, share: newShareDice },
}));
@ -134,17 +142,16 @@ function Party({
height: "calc(100% - 232px)",
}}
>
{/* TODO: check if stream is required here */}
<Nickname
nickname={`${playerState.nickname} (you)`}
diceRolls={shareDice && playerState.dice.rolls}
diceRolls={shareDice ? playerState.dice.rolls : undefined}
/>
{Object.entries(partyState).map(([id, { nickname, dice }]) => (
<Nickname
nickname={nickname}
key={id}
stream={partyStreams[id]}
diceRolls={dice.share && dice.rolls}
diceRolls={dice.share ? dice.rolls : undefined}
/>
))}
{playerState.timer && <Timer timer={playerState.timer} index={0} />}

View File

@ -1,20 +1,26 @@
import React, { useState } from "react";
import { useState } from "react";
import { IconButton, Box, Text } from "theme-ui";
import adapter from "webrtc-adapter";
import Link from "../Link";
import StartStreamModal from "../../modals/StartStreamModal";
import {
StreamEndEventHandler,
StreamStartEventHandler,
} from "../../types/Events";
type StartStreamProps = {
onStreamStart: StreamStartEventHandler;
onStreamEnd: StreamEndEventHandler;
stream: MediaStream | null;
};
function StartStreamButton({
onStreamStart,
onStreamEnd,
stream,
}: {
onStreamStart;
onStreamEnd;
stream;
}) {
}: StartStreamProps) {
const [isStreamModalOpoen, setIsStreamModalOpen] = useState(false);
function openModal() {
setIsStreamModalOpen(true);
@ -53,7 +59,7 @@ function StartStreamButton({
function handleStreamStart() {
// Must be defined this way in typescript due to open issue - https://github.com/microsoft/TypeScript/issues/33232
const mediaDevices = navigator.mediaDevices;
const mediaDevices: any = navigator.mediaDevices;
mediaDevices
.getDisplayMedia({
video: true,
@ -63,7 +69,7 @@ function StartStreamButton({
echoCancellation: false,
},
})
.then((localStream: { getTracks }) => {
.then((localStream: MediaStream) => {
const tracks = localStream.getTracks();
const hasAudio = tracks.some(

View File

@ -1,18 +1,25 @@
import React, { useState } from "react";
import { useState } from "react";
import { IconButton } from "theme-ui";
import StartTimerModal from "../../modals/StartTimerModal";
import StartTimerIcon from "../../icons/StartTimerIcon";
import {
TimerStartEventHandler,
TimerStopEventHandler,
} from "../../types/Events";
import { Timer } from "../../types/Timer";
type StartTimerButtonProps = {
onTimerStart: TimerStartEventHandler;
onTimerStop: TimerStopEventHandler;
timer?: Timer;
};
function StartTimerButton({
onTimerStart,
onTimerStop,
timer,
}: {
onTimerStart;
onTimerStop;
timer;
}) {
}: StartTimerButtonProps) {
const [isTimerModalOpen, setIsTimerModalOpen] = useState(false);
function openModal() {

View File

@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect, ChangeEvent } from "react";
import { useState, useRef, useEffect, ChangeEvent } from "react";
import { Text, IconButton, Box, Flex } from "theme-ui";
import StreamMuteIcon from "../../icons/StreamMuteIcon";
@ -6,18 +6,17 @@ import StreamMuteIcon from "../../icons/StreamMuteIcon";
import Banner from "../banner/Banner";
import Slider from "../Slider";
function Stream({
stream,
nickname,
}: {
type StreamProps = {
stream: MediaStream;
nickname: string;
}) {
};
function Stream({ stream, nickname }: StreamProps) {
const [streamVolume, setStreamVolume] = useState(1);
const [showStreamInteractBanner, setShowStreamInteractBanner] =
useState(false);
const [streamMuted, setStreamMuted] = useState(false);
const audioRef = useRef();
const audioRef = useRef<HTMLAudioElement>(null);
useEffect(() => {
if (audioRef.current) {
@ -59,17 +58,21 @@ function Stream({
const [isVolumeControlAvailable, setIsVolumeControlAvailable] =
useState(true);
useEffect(() => {
let audio = audioRef.current;
function checkVolumeControlAvailable() {
const audio = audioRef.current;
if (!audio) {
return;
}
const checkVolumeControlAvailable = () => {
const prevVolume = audio.volume;
// Set volume to 0.5, then check if the value actually stuck 100ms later
audio.volume = 0.5;
setTimeout(() => {
setIsVolumeControlAvailable(audio.volume === 0.5);
audio.volume = prevVolume;
// TODO: check if this supposed to be a number or number[]
if (audio) {
setIsVolumeControlAvailable(audio.volume === 0.5);
audio.volume = prevVolume;
}
}, 100);
}
};
audio.addEventListener("playing", checkVolumeControlAvailable);
@ -79,7 +82,7 @@ function Stream({
}, []);
// Use an audio context gain node to control volume to go past 100%
const audioGainRef = useRef();
const audioGainRef = useRef<GainNode>();
useEffect(() => {
let audioContext: AudioContext;
if (stream && !streamMuted && isVolumeControlAvailable && audioGainRef) {

View File

@ -1,11 +1,17 @@
import React, { useEffect, useRef } from "react";
import { useEffect, useRef } from "react";
import ReactDOM from "react-dom";
import { Box, Progress } from "theme-ui";
import usePortal from "../../hooks/usePortal";
import { Timer as TimerType } from "../../types/Timer";
function Timer({ timer, index }: { timer; index: number }) {
const progressBarRef = useRef();
type TimerProps = {
timer?: TimerType;
index: number;
};
function Timer({ timer, index }: TimerProps) {
const progressBarRef = useRef<HTMLProgressElement>(null);
useEffect(() => {
if (progressBarRef.current && timer) {
@ -16,7 +22,7 @@ function Timer({ timer, index }: { timer; index: number }) {
useEffect(() => {
let request = requestAnimationFrame(animate);
let previousTime = performance.now();
function animate(time) {
function animate(time: number) {
request = requestAnimationFrame(animate);
const deltaTime = time - previousTime;
previousTime = time;

View File

@ -23,7 +23,6 @@ export type CustomDragEndEvent = DragEndWithOverlayEvent & DragEndEvent;
type CustomDragProps = {
onDragEnd?: (event: CustomDragEndEvent) => void;
;
};
function DragPositionMonitor({ onDragEnd }: CustomDragProps) {

View File

@ -66,21 +66,25 @@ export const GridCellPixelOffsetContext = React.createContext(
const defaultStrokeWidth = 1 / 10;
type GridProviderProps = {
grid: Grid | null;
width: number;
height: number;
children: React.ReactNode;
};
export function GridProvider({
grid: inputGrid,
width,
height,
children,
}: {
grid: Grid;
width: number;
height: number;
children: React.ReactNode;
}) {
let grid = inputGrid;
}: GridProviderProps) {
let grid: Grid;
if (!grid.size.x || !grid.size.y) {
if (!inputGrid || !inputGrid.size.x || !inputGrid.size.y) {
grid = defaultValue.grid;
} else {
grid = inputGrid;
}
const [gridPixelSize, setGridPixelSize] = useState(

View File

@ -359,24 +359,22 @@ export function gridDistance(
* @returns {GridScale}
*/
export function parseGridScale(scale: string): GridScale {
export function parseGridScale(scale: string | null): GridScale {
if (typeof scale === "string") {
const match = scale.match(/(\d*)(\.\d*)?([a-zA-Z]*)/);
// TODO: handle case where match is not found
if (!match) {
throw Error;
}
const integer = parseFloat(match[1]);
const fractional = parseFloat(match[2]);
const unit = match[3] || "";
if (!isNaN(integer) && !isNaN(fractional)) {
return {
multiplier: integer + fractional,
unit: unit,
digits: match[2].length - 1,
};
} else if (!isNaN(integer) && isNaN(fractional)) {
return { multiplier: integer, unit: unit, digits: 0 };
if (match) {
const integer = parseFloat(match[1]);
const fractional = parseFloat(match[2]);
const unit = match[3] || "";
if (!isNaN(integer) && !isNaN(fractional)) {
return {
multiplier: integer + fractional,
unit: unit,
digits: match[2].length - 1,
};
} else if (!isNaN(integer) && isNaN(fractional)) {
return { multiplier: integer, unit: unit, digits: 0 };
}
}
}
return { multiplier: 1, unit: "", digits: 0 };

View File

@ -2,20 +2,22 @@ import { Box, Text, Button, Label, Flex } from "theme-ui";
import Modal from "../components/Modal";
import { RequestCloseEventHandler } from "../types/Events";
import {
RequestCloseEventHandler,
StreamEndEventHandler,
} from "../types/Events";
export type StreamStartEventHandler = () => void;
export type StreamEndEventHandler = (stream: MediaStream) => void;
export type StreamOpenAndStartEventHandler = () => void;
type StartStreamProps = {
isOpen: boolean;
onRequestClose: RequestCloseEventHandler;
isSupported: boolean;
unavailableMessage: JSX.Element;
stream: MediaStream;
stream: MediaStream | null;
noAudioTrack: boolean;
noAudioMessage: JSX.Element;
onStreamStart: StreamStartEventHandler;
onStreamStart: StreamOpenAndStartEventHandler;
onStreamEnd: StreamEndEventHandler;
};

View File

@ -7,12 +7,13 @@ import { getHMSDuration, getDurationHMS } from "../helpers/timer";
import useSetting from "../hooks/useSetting";
import { RequestCloseEventHandler } from "../types/Events";
import {
RequestCloseEventHandler,
TimerStartEventHandler,
TimerStopEventHandler,
} from "../types/Events";
import { Timer } from "../types/Timer";
export type TimerStartEventHandler = (event: Timer) => void;
export type TimerStopEventHandler = () => void;
type StartTimerProps = {
isOpen: boolean;
onRequestClose: RequestCloseEventHandler;

View File

@ -1,8 +1,9 @@
import Konva from "konva";
import { DefaultDice } from "./Dice";
import { DefaultDice, DiceRoll } from "./Dice";
import { Map } from "./Map";
import { MapState } from "./MapState";
import { Note } from "./Note";
import { Timer } from "./Timer";
import { Token } from "./Token";
import { TokenState } from "./TokenState";
@ -43,3 +44,12 @@ export type NoteDragEventHandler = (
event: Konva.KonvaEventObject<DragEvent>,
noteId: string
) => void;
export type DiceShareChangeEventHandler = (share: boolean) => void;
export type DiceRollsChangeEventHandler = (newRolls: DiceRoll[]) => void;
export type StreamStartEventHandler = (stream: MediaStream) => void;
export type StreamEndEventHandler = (stream: MediaStream) => void;
export type TimerStartEventHandler = (event: Timer) => void;
export type TimerStopEventHandler = () => void;

View File

@ -22,7 +22,10 @@ import { Group, GroupContainer } from "./types/Group";
export type UpgradeEventHandler = (versionNumber: number) => void;
type VersionCallback = (version: Version, onUpgrade?: UpgradeEventHandler);
type VersionCallback = (
version: Version,
onUpgrade?: UpgradeEventHandler
) => void;
/**
* Mapping of version number to their upgrade function
@ -285,7 +288,7 @@ export const versions: Record<number, VersionCallback> = {
v.stores({}).upgrade(async (tx) => {
onUpgrade?.(15);
const tokens = await Dexie.waitFor(tx.table("tokens").toArray());
let tokenSizes: Record<string, {width: number, height: number}> = {};
let tokenSizes: Record<string, { width: number; height: number }> = {};
for (let token of tokens) {
const url = URL.createObjectURL(new Blob([token.file]));
let image = new Image();
@ -775,7 +778,7 @@ export const versions: Record<number, VersionCallback> = {
34(v, onUpgrade) {
v.stores({ groups: "id" }).upgrade(async (tx) => {
onUpgrade?.(34);
function groupItems(items: {id: string, group: string}[]) {
function groupItems(items: { id: string; group: string }[]) {
let groups: Group[] = [];
let subGroups: Record<string, GroupContainer> = {};
for (let item of items) {
@ -841,7 +844,11 @@ export const latestVersion = 36;
* @param {number=} upTo version number to load up to, latest version if undefined
* @param {UpgradeEventHandler=} onUpgrade
*/
export function loadVersions(db: Dexie, upTo: number | undefined = latestVersion, onUpgrade: UpgradeEventHandler | undefined) {
export function loadVersions(
db: Dexie,
upTo: number | undefined = latestVersion,
onUpgrade: UpgradeEventHandler | undefined
) {
for (let versionNumber = 1; versionNumber <= upTo; versionNumber++) {
versions[versionNumber](db.version(versionNumber), onUpgrade);
}
@ -883,12 +890,12 @@ function convertOldActionsToShapes(actions: any[], actionIndex: number) {
}
// Helper to create a thumbnail for a file in a db
async function createDataThumbnail(data: any) : Promise<{
file: Uint8Array,
width: number,
height: number,
type: "file",
id: "thumbnail",
async function createDataThumbnail(data: any): Promise<{
file: Uint8Array;
width: number;
height: number;
type: "file";
id: "thumbnail";
}> {
let url: string;
if (data?.resolutions?.low?.file) {
@ -917,7 +924,9 @@ async function createDataThumbnail(data: any) : Promise<{
);
}
async function createDataOutline(data: any) : Promise<{id: string, outline: Outline}> {
async function createDataOutline(
data: any
): Promise<{ id: string; outline: Outline }> {
const url = URL.createObjectURL(new Blob([data.file]));
return await Dexie.waitFor(
new Promise((resolve) => {

View File

@ -3069,6 +3069,13 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/lodash.chunk@^4.2.6":
version "4.2.6"
resolved "https://registry.yarnpkg.com/@types/lodash.chunk/-/lodash.chunk-4.2.6.tgz#9d35f05360b0298715d7f3d9efb34dd4f77e5d2a"
integrity sha512-SPlusB7jxXyGcTXYcUdWr7WmhArO/rmTq54VN88iKMxGUhyg79I4Q8n4riGn3kjaTjOJrVlHhxgX/d7woak5BQ==
dependencies:
"@types/lodash" "*"
"@types/lodash.clonedeep@^4.5.6":
version "4.5.6"
resolved "https://registry.yarnpkg.com/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz#3b6c40a0affe0799a2ce823b440a6cf33571d32b"