From 49b8caa2d7955a19edff6fdaf17ca7e20b551f2a Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Fri, 9 Jul 2021 22:06:32 +1000 Subject: [PATCH] Add type to controls and change colour types --- ...phaBlendToggle.js => AlphaBlendToggle.tsx} | 11 ++- .../{ColorControl.js => ColorControl.tsx} | 26 +++-- ...oolSettings.js => DrawingToolSettings.tsx} | 19 +++- .../{FogCutToggle.js => FogCutToggle.tsx} | 13 ++- ...gPreviewToggle.js => FogPreviewToggle.tsx} | 11 ++- ...FogToolSettings.js => FogToolSettings.tsx} | 22 +++-- ...ltilayerToggle.js => MultilayerToggle.tsx} | 13 ++- ...oolSettings.js => PointerToolSettings.tsx} | 13 ++- .../{RedoButton.js => RedoButton.tsx} | 7 +- .../{ToolSection.js => ToolSection.tsx} | 48 ++++++--- .../{UndoButton.js => UndoButton.tsx} | 7 +- src/contexts/GroupContext.tsx | 4 +- src/contexts/KeyboardContext.tsx | 11 +-- src/helpers/colors.ts | 23 ++--- src/modals/SelectMapModal.tsx | 33 ++++--- src/modals/SelectTokensModal.tsx | 12 ++- src/shortcuts.ts | 98 ++++++++----------- src/types/Drawing.ts | 3 +- src/types/Fog.ts | 3 +- src/types/Note.ts | 4 +- src/types/Pointer.ts | 5 +- 21 files changed, 238 insertions(+), 148 deletions(-) rename src/components/map/controls/{AlphaBlendToggle.js => AlphaBlendToggle.tsx} (71%) rename src/components/map/controls/{ColorControl.js => ColorControl.tsx} (77%) rename src/components/map/controls/{DrawingToolSettings.js => DrawingToolSettings.tsx} (89%) rename src/components/map/controls/{FogCutToggle.js => FogCutToggle.tsx} (71%) rename src/components/map/controls/{FogPreviewToggle.js => FogPreviewToggle.tsx} (73%) rename src/components/map/controls/{FogToolSettings.js => FogToolSettings.tsx} (89%) rename src/components/map/controls/{MultilayerToggle.js => MultilayerToggle.tsx} (71%) rename src/components/map/controls/{PointerToolSettings.js => PointerToolSettings.tsx} (55%) rename src/components/map/controls/{RedoButton.js => RedoButton.tsx} (73%) rename src/components/map/controls/{ToolSection.js => ToolSection.tsx} (74%) rename src/components/map/controls/{UndoButton.js => UndoButton.tsx} (72%) diff --git a/src/components/map/controls/AlphaBlendToggle.js b/src/components/map/controls/AlphaBlendToggle.tsx similarity index 71% rename from src/components/map/controls/AlphaBlendToggle.js rename to src/components/map/controls/AlphaBlendToggle.tsx index ff0f276..7ae0400 100644 --- a/src/components/map/controls/AlphaBlendToggle.js +++ b/src/components/map/controls/AlphaBlendToggle.tsx @@ -1,10 +1,17 @@ -import React from "react"; import { IconButton } from "theme-ui"; import BlendOnIcon from "../../../icons/BlendOnIcon"; import BlendOffIcon from "../../../icons/BlendOffIcon"; -function AlphaBlendToggle({ useBlending, onBlendingChange }) { +type AlphaBlendToggleProps = { + useBlending: boolean; + onBlendingChange: (useBlending: boolean) => void; +}; + +function AlphaBlendToggle({ + useBlending, + onBlendingChange, +}: AlphaBlendToggleProps) { return ( ; +} & SxProp; + +function ColorCircle({ color, selected, onClick, sx }: ColorCircleProps) { return ( void; + exclude: Color[]; +}; + +function ColorControl({ color, onColorChange, exclude }: ColorControlProps) { const [showColorMenu, setShowColorMenu] = useState(false); const [colorMenuOptions, setColorMenuOptions] = useState({}); - function handleControlClick(event) { + function handleControlClick(event: React.MouseEvent) { if (showColorMenu) { setShowColorMenu(false); setColorMenuOptions({}); } else { setShowColorMenu(true); - const rect = event.target.getBoundingClientRect(); + const rect = event.currentTarget.getBoundingClientRect(); setColorMenuOptions({ // Align the right of the submenu to the left of the tool and center vertically left: `${rect.left + rect.width / 2}px`, top: `${rect.bottom + 16}px`, style: { transform: "translateX(-50%)" }, // Exclude this node from the sub menus auto close - excludeNode: event.target, + excludeNode: event.currentTarget, }); } } diff --git a/src/components/map/controls/DrawingToolSettings.js b/src/components/map/controls/DrawingToolSettings.tsx similarity index 89% rename from src/components/map/controls/DrawingToolSettings.js rename to src/components/map/controls/DrawingToolSettings.tsx index 2537e3f..5853b67 100644 --- a/src/components/map/controls/DrawingToolSettings.js +++ b/src/components/map/controls/DrawingToolSettings.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import { useEffect } from "react"; import { Flex, IconButton } from "theme-ui"; import { useMedia } from "react-media"; @@ -26,14 +26,23 @@ import { useKeyboard } from "../../../contexts/KeyboardContext"; import shortcuts from "../../../shortcuts"; +import { DrawingToolSettings, DrawingToolType } from "../../../types/Drawing"; + +type DrawingToolSettingsProps = { + settings: DrawingToolSettings; + onSettingChange: (change: Partial) => void; + onToolAction: (action: string) => void; + disabledActions: string[]; +}; + function DrawingToolSettings({ settings, onSettingChange, onToolAction, disabledActions, -}) { +}: DrawingToolSettingsProps) { // Keyboard shotcuts - function handleKeyDown(event) { + function handleKeyDown(event: KeyboardEvent) { if (shortcuts.drawBrush(event)) { onSettingChange({ type: "brush" }); } else if (shortcuts.drawPaint(event)) { @@ -115,7 +124,9 @@ function DrawingToolSettings({ onSettingChange({ type: tool.id })} + onToolClick={(tool) => + onSettingChange({ type: tool.id as DrawingToolType }) + } collapse={isSmallScreen} /> diff --git a/src/components/map/controls/FogCutToggle.js b/src/components/map/controls/FogCutToggle.tsx similarity index 71% rename from src/components/map/controls/FogCutToggle.js rename to src/components/map/controls/FogCutToggle.tsx index d401e59..a99b133 100644 --- a/src/components/map/controls/FogCutToggle.js +++ b/src/components/map/controls/FogCutToggle.tsx @@ -1,10 +1,19 @@ -import React from "react"; import { IconButton } from "theme-ui"; import CutOnIcon from "../../../icons/FogCutOnIcon"; import CutOffIcon from "../../../icons/FogCutOffIcon"; -function FogCutToggle({ useFogCut, onFogCutChange, disabled }) { +type FogCutToggleProps = { + useFogCut: boolean; + onFogCutChange: (useFogCut: boolean) => void; + disabled?: boolean; +}; + +function FogCutToggle({ + useFogCut, + onFogCutChange, + disabled, +}: FogCutToggleProps) { return ( void; +}; + +function FogPreviewToggle({ + useFogPreview, + onFogPreviewChange, +}: FogPreviewToggleProps) { return ( ) => void; + onToolAction: (action: string) => void; + disabledActions: string[]; +}; + +function FogToolSettings({ settings, onSettingChange, onToolAction, disabledActions, -}) { +}: FogToolSettingsProps) { // Keyboard shortcuts - function handleKeyDown(event) { + function handleKeyDown(event: KeyboardEvent) { if (shortcuts.fogPolygon(event)) { onSettingChange({ type: "polygon" }); } else if (shortcuts.fogBrush(event)) { @@ -86,7 +94,9 @@ function BrushToolSettings({ onSettingChange({ type: tool.id })} + onToolClick={(tool) => + onSettingChange({ type: tool.id as FogToolType }) + } collapse={isSmallScreen} /> @@ -134,4 +144,4 @@ function BrushToolSettings({ ); } -export default BrushToolSettings; +export default FogToolSettings; diff --git a/src/components/map/controls/MultilayerToggle.js b/src/components/map/controls/MultilayerToggle.tsx similarity index 71% rename from src/components/map/controls/MultilayerToggle.js rename to src/components/map/controls/MultilayerToggle.tsx index 590e310..5abd153 100644 --- a/src/components/map/controls/MultilayerToggle.js +++ b/src/components/map/controls/MultilayerToggle.tsx @@ -1,10 +1,19 @@ -import React from "react"; import { IconButton } from "theme-ui"; import MultilayerOnIcon from "../../../icons/FogMultilayerOnIcon"; import MultilayerOffIcon from "../../../icons/FogMultilayerOffIcon"; -function MultilayerToggle({ multilayer, onMultilayerChange, disabled }) { +type MultilayerToggleProps = { + multilayer: boolean; + onMultilayerChange: (multilayer: boolean) => void; + disabled?: boolean; +}; + +function MultilayerToggle({ + multilayer, + onMultilayerChange, + disabled, +}: MultilayerToggleProps) { return ( ) => void; +}; + +function PointerToolSettings({ + settings, + onSettingChange, +}: PointerToolSettingsProps) { return ( ; + disabled?: boolean; +}; + +function RedoButton({ onClick, disabled }: RedoButtonProps) { return ( void; +}; + // Section of map tools with the option to collapse into a vertical list -function ToolSection({ collapse, tools, onToolClick }) { +function ToolSection({ collapse, tools, onToolClick }: ToolSectionProps) { const [showMore, setShowMore] = useState(false); - const [collapsedTool, setCollapsedTool] = useState(); + const [collapsedTool, setCollapsedTool] = useState(); useEffect(() => { const selectedTool = tools.find((tool) => tool.isSelected); @@ -20,7 +34,7 @@ function ToolSection({ collapse, tools, onToolClick }) { } }, [tools]); - function handleToolClick(tool) { + function handleToolClick(tool: Tool) { if (collapse && tool.isSelected) { setShowMore(!showMore); } else if (collapse && !tool.isSelected) { @@ -29,7 +43,7 @@ function ToolSection({ collapse, tools, onToolClick }) { onToolClick(tool); } - function renderTool(tool) { + function renderTool(tool: Tool) { return ( ); } else { - return tools.map((tool) => ( - handleToolClick(tool)} - key={tool.id} - isSelected={tool.isSelected} - disabled={tool.disabled} - > - {tool.icon} - - )); + return ( + <> + {tools.map((tool) => ( + handleToolClick(tool)} + key={tool.id} + isSelected={tool.isSelected} + disabled={tool.disabled} + > + {tool.icon} + + ))} + + ); } } diff --git a/src/components/map/controls/UndoButton.js b/src/components/map/controls/UndoButton.tsx similarity index 72% rename from src/components/map/controls/UndoButton.js rename to src/components/map/controls/UndoButton.tsx index 93232d7..f223c7c 100644 --- a/src/components/map/controls/UndoButton.js +++ b/src/components/map/controls/UndoButton.tsx @@ -5,7 +5,12 @@ import UndoIcon from "../../../icons/UndoIcon"; import { isMacLike } from "../../../helpers/shared"; -function UndoButton({ onClick, disabled }) { +type UndoButtonProps = { + onClick?: React.MouseEventHandler; + disabled?: boolean; +}; + +function UndoButton({ onClick, disabled }: UndoButtonProps) { return ( { function handleKeyDown(event: Event) { @@ -45,11 +45,10 @@ export function KeyboardProvider({ children }: { children: any}) { ); } -/** - * @param {KeyboardEvent} onKeyDown - * @param {KeyboardEvent} onKeyUp - */ -export function useKeyboard(onKeyDown: (...args: any[]) => void, onKeyUp: (...args: any[]) => void) { +export function useKeyboard( + onKeyDown?: (event: KeyboardEvent) => void, + onKeyUp?: (event: KeyboardEvent) => void +) { const context = useContext(KeyboardContext); if (context === undefined) { throw new Error("useKeyboard must be used within a KeyboardProvider"); diff --git a/src/helpers/colors.ts b/src/helpers/colors.ts index 7acc610..a89fd18 100644 --- a/src/helpers/colors.ts +++ b/src/helpers/colors.ts @@ -1,20 +1,5 @@ -export type Colors = { - blue: string; - orange: string; - red: string; - yellow: string; - purple: string; - green: string; - pink: string; - teal: string; - black: string; - darkGray: string; - lightGray: string; - white: string; -} - // Colors used for the game for theme general UI colors look at theme.js -const colors: Colors = { +const colors = { blue: "rgb(26, 106, 255)", orange: "rgb(255, 116, 51)", red: "rgb(255, 77, 77)", @@ -29,6 +14,10 @@ const colors: Colors = { white: "rgb(255, 255, 255)", }; -export const colorOptions = Object.keys(colors); +export type Colors = typeof colors; + +export type Color = keyof Colors; + +export const colorOptions = Object.keys(colors) as Color[]; export default colors; diff --git a/src/modals/SelectMapModal.tsx b/src/modals/SelectMapModal.tsx index 60be250..85ff501 100644 --- a/src/modals/SelectMapModal.tsx +++ b/src/modals/SelectMapModal.tsx @@ -30,12 +30,15 @@ import { useAssets } from "../contexts/AssetsContext"; import { GroupProvider } from "../contexts/GroupContext"; import { TileDragProvider } from "../contexts/TileDragContext"; +import { Map } from "../types/Map"; +import { MapState } from "../types/MapState"; + type SelectMapProps = { isOpen: boolean; - onDone: any; - onMapChange: any; - onMapReset: any; - currentMap: any; + onDone: () => void; + onMapChange: (map?: Map, mapState?: MapState) => void; + onMapReset: (newState: MapState) => void; + currentMap?: Map; }; function SelectMapModal({ @@ -79,9 +82,9 @@ function SelectMapModal({ const [isLargeImageWarningModalOpen, setShowLargeImageWarning] = useState(false); - const largeImageWarningFiles = useRef(); + const largeImageWarningFiles = useRef(); - async function handleImagesUpload(files: any) { + async function handleImagesUpload(files: File[]) { if (navigator.storage) { // Attempt to enable persistant storage await navigator.storage.persist(); @@ -132,8 +135,10 @@ function SelectMapModal({ async function handleLargeImageWarningConfirm() { setShowLargeImageWarning(false); const files = largeImageWarningFiles.current; - for (let file of files) { - await handleImageUpload(file); + if (files) { + for (let file of files) { + await handleImageUpload(file); + } } largeImageWarningFiles.current = undefined; clearFileInput(); @@ -171,7 +176,7 @@ function SelectMapModal({ onMapChange(map, mapState); setIsLoading(false); } else { - onMapChange(null, null); + onMapChange(undefined, undefined); } onDone(); } @@ -220,9 +225,15 @@ function SelectMapModal({ }} shouldCloseOnEsc={!isDraggingMap} > - + handleImagesUpload(files)} + dropText="Drop map to import" + > handleImagesUpload(event.target.files)} + onChange={(event) => + event.target.files && + handleImagesUpload(Array.from(event.target.files)) + } type="file" accept="image/jpeg, image/gif, image/png, image/webp" style={{ display: "none" }} diff --git a/src/modals/SelectTokensModal.tsx b/src/modals/SelectTokensModal.tsx index bc3cac8..4e9cfb7 100644 --- a/src/modals/SelectTokensModal.tsx +++ b/src/modals/SelectTokensModal.tsx @@ -79,7 +79,7 @@ function SelectTokensModal({ useState(false); const largeImageWarningFiles = useRef(); - async function handleImagesUpload(files: FileList) { + async function handleImagesUpload(files: File[]) { if (navigator.storage) { // Attempt to enable persistant storage await navigator.storage.persist(); @@ -231,10 +231,14 @@ function SelectTokensModal({ }} shouldCloseOnEsc={!isDraggingToken} > - + handleImagesUpload(files)} + dropText="Drop token to import" + > ) => - event.target.files && handleImagesUpload(event.target.files) + onChange={(event) => + event.target.files && + handleImagesUpload(Array.from(event.target.files)) } type="file" accept="image/jpeg, image/gif, image/png, image/webp" diff --git a/src/shortcuts.ts b/src/shortcuts.ts index fe4947a..b8deaa1 100644 --- a/src/shortcuts.ts +++ b/src/shortcuts.ts @@ -19,96 +19,76 @@ function singleKey(event: KeyboardEvent, key: string): boolean { ); } -/** - * @param {Keyboard} event - * @returns {string | boolean} - */ -function undo(event: KeyboardEvent): string | boolean { +function undo(event: KeyboardEvent): boolean { const { key, ctrlKey, metaKey, shiftKey } = event; return (key === "z" || key === "Z") && (ctrlKey || metaKey) && !shiftKey; } -/** - * @param {Keyboard} event - * @returns {string | boolean} - */ -function redo(event: KeyboardEvent): string | boolean { +function redo(event: KeyboardEvent): boolean { const { key, ctrlKey, metaKey, shiftKey } = event; return (key === "z" || key === "Z") && (ctrlKey || metaKey) && shiftKey; } -/** - * @param {Keyboard} event - * @returns {string | boolean} - */ -function zoomIn(event: KeyboardEvent): string | boolean { +function zoomIn(event: KeyboardEvent): boolean { const { key, ctrlKey, metaKey } = event; return (key === "=" || key === "+") && !ctrlKey && !metaKey; } -/** - * @param {Keyboard} event - * @returns {string | boolean} - */ -function zoomOut(event: KeyboardEvent): string | boolean { +function zoomOut(event: KeyboardEvent): boolean { const { key, ctrlKey, metaKey } = event; return (key === "-" || key === "_") && !ctrlKey && !metaKey; } -/** - * @callback shortcut - * @param {KeyboardEvent} event - * @returns {boolean} - */ +type Shortcut = (event: KeyboardEvent) => boolean; /** * @type {Object.} */ -const shortcuts = { +const shortcuts: Record = { // Tools - move: (event: KeyboardEvent) => singleKey(event, " "), - moveTool: (event: KeyboardEvent) => singleKey(event, "w"), - drawingTool: (event: KeyboardEvent) => singleKey(event, "d"), - fogTool: (event: KeyboardEvent) => singleKey(event, "f"), - measureTool: (event: KeyboardEvent) => singleKey(event, "m"), - pointerTool: (event: KeyboardEvent) => singleKey(event, "q"), - noteTool: (event: KeyboardEvent) => singleKey(event, "n"), + move: (event) => singleKey(event, " "), + moveTool: (event) => singleKey(event, "w"), + drawingTool: (event) => singleKey(event, "d"), + fogTool: (event) => singleKey(event, "f"), + measureTool: (event) => singleKey(event, "m"), + pointerTool: (event) => singleKey(event, "q"), + noteTool: (event) => singleKey(event, "n"), // Map editor - gridNudgeUp: ({ key }: { key: string}) => key === "ArrowUp", - gridNudgeLeft: ({ key }: { key: string }) => key === "ArrowLeft", - gridNudgeRight: ({ key }: { key: string }) => key === "ArrowRight", - gridNudgeDown: ({ key }: { key: string }) => key === "ArrowDown", + gridNudgeUp: ({ key }) => key === "ArrowUp", + gridNudgeLeft: ({ key }) => key === "ArrowLeft", + gridNudgeRight: ({ key }) => key === "ArrowRight", + gridNudgeDown: ({ key }) => key === "ArrowDown", // Drawing tool - drawBrush: (event: KeyboardEvent) => singleKey(event, "b"), - drawPaint: (event: KeyboardEvent) => singleKey(event, "p"), - drawLine: (event: KeyboardEvent) => singleKey(event, "l"), - drawRect: (event: KeyboardEvent) => singleKey(event, "r"), - drawCircle: (event: KeyboardEvent) => singleKey(event, "c"), - drawTriangle: (event: KeyboardEvent) => singleKey(event, "t"), - drawErase: (event: KeyboardEvent) => singleKey(event, "e"), - drawBlend: (event: KeyboardEvent) => singleKey(event, "o"), + drawBrush: (event) => singleKey(event, "b"), + drawPaint: (event) => singleKey(event, "p"), + drawLine: (event) => singleKey(event, "l"), + drawRect: (event) => singleKey(event, "r"), + drawCircle: (event) => singleKey(event, "c"), + drawTriangle: (event) => singleKey(event, "t"), + drawErase: (event) => singleKey(event, "e"), + drawBlend: (event) => singleKey(event, "o"), // Fog tool - fogPolygon: (event: KeyboardEvent) => singleKey(event, "p"), - fogRectangle: (event: KeyboardEvent) => singleKey(event, "r"), - fogBrush: (event: KeyboardEvent) => singleKey(event, "b"), - fogToggle: (event: KeyboardEvent) => singleKey(event, "t"), - fogErase: (event: KeyboardEvent) => singleKey(event, "e"), - fogLayer: (event: KeyboardEvent) => singleKey(event, "l"), - fogPreview: (event: KeyboardEvent) => singleKey(event, "f"), - fogCut: (event: KeyboardEvent) => singleKey(event, "c"), - fogFinishPolygon: ({ key }: { key: string }) => key === "Enter", - fogCancelPolygon: ({ key }: { key: string }) => key === "Escape", + fogPolygon: (event) => singleKey(event, "p"), + fogRectangle: (event) => singleKey(event, "r"), + fogBrush: (event) => singleKey(event, "b"), + fogToggle: (event) => singleKey(event, "t"), + fogErase: (event) => singleKey(event, "e"), + fogLayer: (event) => singleKey(event, "l"), + fogPreview: (event) => singleKey(event, "f"), + fogCut: (event) => singleKey(event, "c"), + fogFinishPolygon: ({ key }) => key === "Enter", + fogCancelPolygon: ({ key }) => key === "Escape", // Stage interaction stageZoomIn: zoomIn, stageZoomOut: zoomOut, - stagePrecisionZoom: ({ key }: { key: string }) => key === "Shift", + stagePrecisionZoom: ({ key }) => key === "Shift", // Select - selectRange: ({ key }: { key: string }) => key === "Shift", - selectMultiple: ({ key }: { key: string }) => key === "Control" || key === "Meta", + selectRange: ({ key }) => key === "Shift", + selectMultiple: ({ key }) => key === "Control" || key === "Meta", // Common undo, redo, - delete: ({ key }: { key: string }) => key === "Backspace" || key === "Delete", + delete: ({ key }) => key === "Backspace" || key === "Delete", }; export default shortcuts; diff --git a/src/types/Drawing.ts b/src/types/Drawing.ts index fc8883d..868bc4e 100644 --- a/src/types/Drawing.ts +++ b/src/types/Drawing.ts @@ -1,4 +1,5 @@ import Vector2 from "../helpers/Vector2"; +import { Color } from "../helpers/colors"; export type DrawingToolType = | "brush" @@ -11,7 +12,7 @@ export type DrawingToolType = export type DrawingToolSettings = { type: DrawingToolType; - color: string; + color: Color; useBlending: boolean; }; diff --git a/src/types/Fog.ts b/src/types/Fog.ts index ba54f36..205cc01 100644 --- a/src/types/Fog.ts +++ b/src/types/Fog.ts @@ -1,4 +1,5 @@ import Vector2 from "../helpers/Vector2"; +import { Color } from "../helpers/colors"; export type FogToolType = | "polygon" @@ -20,7 +21,7 @@ export type FogData = { }; export type Fog = { - color: string; + color: Color; data: FogData; id: string; strokeWidth: number; diff --git a/src/types/Note.ts b/src/types/Note.ts index 4e1b02c..9ad3f5c 100644 --- a/src/types/Note.ts +++ b/src/types/Note.ts @@ -1,6 +1,8 @@ +import { Color } from "../helpers/colors"; + export type Note = { id: string; - color: string; + color: Color; lastModified: number; lastModifiedBy: string; locked: boolean; diff --git a/src/types/Pointer.ts b/src/types/Pointer.ts index 77e69b0..254cc4b 100644 --- a/src/types/Pointer.ts +++ b/src/types/Pointer.ts @@ -1,12 +1,13 @@ import Vector2 from "../helpers/Vector2"; +import { Color } from "../helpers/colors"; export type PointerToolSettings = { - color: string; + color: Color; }; export type PointerState = { position: Vector2; visible: boolean; id: string; - color: string; + color: Color; };