Typescript
This commit is contained in:
parent
d80bfa2f1e
commit
c7b8990a7b
@ -102,6 +102,7 @@
|
||||
"@types/lodash.get": "^4.4.6",
|
||||
"@types/lodash.set": "^4.3.6",
|
||||
"@types/node": "^15.6.0",
|
||||
"@types/normalize-wheel": "^1.0.0",
|
||||
"@types/react": "^17.0.6",
|
||||
"@types/react-dom": "^17.0.5",
|
||||
"@types/react-modal": "^3.12.0",
|
||||
|
@ -23,6 +23,8 @@ import MapGrid from "./MapGrid";
|
||||
import MapGridEditor from "./MapGridEditor";
|
||||
import { Map } from "../../types/Map";
|
||||
import { GridInset } from "../../types/Grid";
|
||||
import { Stage as StageType } from "konva/types/Stage";
|
||||
import { Layer as LayerType } from "konva/types/Layer";
|
||||
|
||||
type MapSettingsChangeEventHandler = (change: Partial<Map>) => void;
|
||||
|
||||
@ -41,8 +43,8 @@ function MapEditor({ map, onSettingsChange }: MapEditorProps) {
|
||||
const defaultInset = getGridDefaultInset(map.grid, map.width, map.height);
|
||||
|
||||
const stageTranslateRef = useRef({ x: 0, y: 0 });
|
||||
const mapStageRef = useRef();
|
||||
const mapLayerRef = useRef();
|
||||
const mapStageRef = useRef<StageType>(null);
|
||||
const mapLayerRef = useRef<LayerType>(null);
|
||||
const [preventMapInteraction, setPreventMapInteraction] = useState(false);
|
||||
|
||||
function handleResize(width?: number, height?: number): void {
|
||||
@ -55,7 +57,7 @@ function MapEditor({ map, onSettingsChange }: MapEditorProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const containerRef = useRef(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
usePreventOverscroll(containerRef);
|
||||
|
||||
const [mapWidth, mapHeight] = useImageCenter(
|
||||
|
@ -309,7 +309,7 @@ type DefaultData = {
|
||||
export function useDataURL(
|
||||
data: FileData | DefaultData,
|
||||
defaultSources: Record<string, string>,
|
||||
unknownSource: string | undefined,
|
||||
unknownSource: string | undefined = undefined,
|
||||
thumbnail = false
|
||||
) {
|
||||
const [assetId, setAssetId] = useState<string>();
|
||||
|
@ -7,7 +7,7 @@ import { useKeyboard, useBlur } from "./KeyboardContext";
|
||||
import { getGroupItems, groupsFromIds } from "../helpers/group";
|
||||
|
||||
import shortcuts from "../shortcuts";
|
||||
import { Group, GroupContainer, GroupItem } from "../types/Group";
|
||||
import { Group, GroupItem } from "../types/Group";
|
||||
|
||||
export type GroupSelectMode = "single" | "multiple" | "range";
|
||||
export type GroupSelectModeChangeEventHandler = (
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useContext } from "react";
|
||||
import { Stage } from "konva/types/Stage";
|
||||
|
||||
type MapStage = React.MutableRefObject<Stage | null>;
|
||||
export type MapStage = React.MutableRefObject<Stage | null>;
|
||||
|
||||
const MapStageContext = React.createContext<MapStage | undefined>(undefined);
|
||||
export const MapStageProvider = MapStageContext.Provider;
|
||||
|
@ -1,26 +1,24 @@
|
||||
import { Layer } from "konva/types/Layer";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
type useImageCenterProps = {
|
||||
data:
|
||||
stageRef:
|
||||
stageWidth: number;
|
||||
stageHeight: number;
|
||||
stageTranslateRef:
|
||||
setStageScale:
|
||||
imageLayerRef:
|
||||
containerRef:
|
||||
responsive?: boolean
|
||||
}
|
||||
import { MapStage } from "../contexts/MapStageContext";
|
||||
import Vector2 from "../helpers/Vector2";
|
||||
|
||||
type ImageData = {
|
||||
id: string;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
function useImageCenter(
|
||||
data,
|
||||
stageRef,
|
||||
stageWidth,
|
||||
stageHeight,
|
||||
stageTranslateRef,
|
||||
setStageScale,
|
||||
imageLayerRef,
|
||||
containerRef,
|
||||
data: ImageData,
|
||||
stageRef: MapStage,
|
||||
stageWidth: number,
|
||||
stageHeight: number,
|
||||
stageTranslateRef: React.MutableRefObject<Vector2>,
|
||||
setStageScale: React.Dispatch<React.SetStateAction<number>>,
|
||||
imageLayerRef: React.RefObject<Layer>,
|
||||
containerRef: React.RefObject<HTMLDivElement>,
|
||||
responsive = false
|
||||
) {
|
||||
const stageRatio = stageWidth / stageHeight;
|
||||
@ -37,7 +35,7 @@ function useImageCenter(
|
||||
}
|
||||
|
||||
// Reset image translate and stage scale
|
||||
const previousDataIdRef = useRef();
|
||||
const previousDataIdRef = useRef<string>();
|
||||
const previousStageRatioRef = useRef(stageRatio);
|
||||
useEffect(() => {
|
||||
if (!data) {
|
||||
@ -45,7 +43,12 @@ function useImageCenter(
|
||||
}
|
||||
|
||||
const layer = imageLayerRef.current;
|
||||
const containerRect = containerRef.current.getBoundingClientRect();
|
||||
const container = containerRef.current;
|
||||
const stage = stageRef.current;
|
||||
if (!container || !stage) {
|
||||
return;
|
||||
}
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const previousDataId = previousDataIdRef.current;
|
||||
const previousStageRatio = previousStageRatioRef.current;
|
||||
|
||||
@ -68,7 +71,7 @@ function useImageCenter(
|
||||
};
|
||||
}
|
||||
layer.position(newTranslate);
|
||||
stageRef.current.position({ x: 0, y: 0 });
|
||||
stage.position({ x: 0, y: 0 });
|
||||
stageTranslateRef.current = { x: 0, y: 0 };
|
||||
|
||||
setStageScale(1);
|
@ -5,14 +5,16 @@ import { useDataURL } from "../contexts/AssetsContext";
|
||||
|
||||
import { mapSources as defaultMapSources } from "../maps";
|
||||
|
||||
function useMapImage(map) {
|
||||
import { Map } from "../types/Map";
|
||||
|
||||
function useMapImage(map: Map) {
|
||||
const mapURL = useDataURL(map, defaultMapSources);
|
||||
const [mapImage, mapImageStatus] = useImage(mapURL);
|
||||
const [mapImage, mapImageStatus] = useImage(mapURL || "");
|
||||
|
||||
// Create a map source that only updates when the image is fully loaded
|
||||
const [loadedMapImage, setLoadedMapImage] = useState();
|
||||
const [loadedMapImage, setLoadedMapImage] = useState<HTMLImageElement>();
|
||||
useEffect(() => {
|
||||
if (mapImageStatus === "loaded") {
|
||||
if (mapImageStatus === "loaded" && mapImage) {
|
||||
setLoadedMapImage(mapImage);
|
||||
}
|
||||
}, [mapImage, mapImageStatus]);
|
@ -6,7 +6,7 @@ import { useRef, useEffect } from "react";
|
||||
* Creates DOM element to be used as React root.
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
function createRootElement(id) {
|
||||
function createRootElement(id: string) {
|
||||
const rootContainer = document.createElement("div");
|
||||
rootContainer.setAttribute("id", id);
|
||||
return rootContainer;
|
||||
@ -16,11 +16,13 @@ function createRootElement(id) {
|
||||
* Appends element as last child of body.
|
||||
* @param {HTMLElement} rootElem
|
||||
*/
|
||||
function addRootElement(rootElem) {
|
||||
document.body.insertBefore(
|
||||
rootElem,
|
||||
document.body.lastElementChild.nextElementSibling
|
||||
);
|
||||
function addRootElement(rootElem: HTMLElement) {
|
||||
if (document.body.lastElementChild) {
|
||||
document.body.insertBefore(
|
||||
rootElem,
|
||||
document.body.lastElementChild?.nextElementSibling
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -34,13 +36,15 @@ function addRootElement(rootElem) {
|
||||
* @param {String} id The id of the target container, e.g 'modal' or 'spotlight'
|
||||
* @returns {HTMLElement} The DOM node to use as the Portal target.
|
||||
*/
|
||||
function usePortal(id) {
|
||||
const rootElemRef = useRef(null);
|
||||
function usePortal(id: string): HTMLElement {
|
||||
const rootElemRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
useEffect(
|
||||
function setupElement() {
|
||||
// Look for existing target dom element to append to
|
||||
const existingParent = document.querySelector(`#${id}`);
|
||||
const existingParent: HTMLElement | null = document.querySelector(
|
||||
`#${id}`
|
||||
);
|
||||
// Parent is either a new root or the existing dom element
|
||||
const parentElem = existingParent || createRootElement(id);
|
||||
|
||||
@ -50,10 +54,10 @@ function usePortal(id) {
|
||||
}
|
||||
|
||||
// Add the detached element to the parent
|
||||
parentElem.appendChild(rootElemRef.current);
|
||||
rootElemRef.current && parentElem.appendChild(rootElemRef.current);
|
||||
|
||||
return function removeElement() {
|
||||
rootElemRef.current.remove();
|
||||
rootElemRef.current && rootElemRef.current.remove();
|
||||
if (parentElem.childNodes.length === -1) {
|
||||
parentElem.remove();
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import { useEffect } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
function usePreventOverscroll(elementRef) {
|
||||
function usePreventOverscroll(elementRef: React.RefObject<HTMLElement>) {
|
||||
useEffect(() => {
|
||||
// Stop overscroll on chrome and safari
|
||||
// also stop pinch to zoom on chrome
|
||||
function preventOverscroll(event) {
|
||||
function preventOverscroll(event: WheelEvent) {
|
||||
event.preventDefault();
|
||||
}
|
||||
const element = elementRef.current;
|
@ -1,11 +1,8 @@
|
||||
function usePreventSelect() {
|
||||
function clearSelection() {
|
||||
if (window.getSelection) {
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
if (document.selection) {
|
||||
document.selection.empty();
|
||||
}
|
||||
window?.getSelection()?.removeAllRanges();
|
||||
// @ts-ignore
|
||||
document?.selection?.empty();
|
||||
}
|
||||
function preventSelect() {
|
||||
clearSelection();
|
@ -1,9 +1,9 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
function usePreventTouch(elementRef) {
|
||||
function usePreventTouch(elementRef: React.RefObject<HTMLElement>) {
|
||||
useEffect(() => {
|
||||
// Stop 3d touch
|
||||
function prevent3DTouch(event) {
|
||||
function prevent3DTouch(event: TouchEvent) {
|
||||
event.preventDefault();
|
||||
}
|
||||
const element = elementRef.current;
|
@ -1,7 +1,7 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
function usePrevious(value) {
|
||||
const ref = useRef();
|
||||
function usePrevious<T>(value: T): T {
|
||||
const ref = useRef<T>(value);
|
||||
useEffect(() => {
|
||||
ref.current = value;
|
||||
}, [value]);
|
@ -1,35 +1,42 @@
|
||||
import { useRef, useEffect, useState } from "react";
|
||||
import { useGesture } from "react-use-gesture";
|
||||
import { Handlers } from "react-use-gesture/dist/types";
|
||||
import normalizeWheel from "normalize-wheel";
|
||||
import { Stage } from "konva/types/Stage";
|
||||
import { Layer } from "konva/types/Layer";
|
||||
|
||||
import { useKeyboard, useBlur } from "../contexts/KeyboardContext";
|
||||
|
||||
import shortcuts from "../shortcuts";
|
||||
|
||||
import Vector2 from "../helpers/Vector2";
|
||||
|
||||
const wheelZoomSpeed = -1;
|
||||
const touchZoomSpeed = 0.005;
|
||||
const minZoom = 0.1;
|
||||
|
||||
type StageScaleChangeEventHandler = (newScale: number) => void;
|
||||
|
||||
function useStageInteraction(
|
||||
stage,
|
||||
stageScale,
|
||||
onStageScaleChange,
|
||||
stageTranslateRef,
|
||||
layer,
|
||||
stage: Stage,
|
||||
stageScale: number,
|
||||
onStageScaleChange: StageScaleChangeEventHandler,
|
||||
stageTranslateRef: React.MutableRefObject<Vector2>,
|
||||
layer: Layer,
|
||||
maxZoom = 10,
|
||||
tool = "move",
|
||||
preventInteraction = false,
|
||||
gesture = {}
|
||||
gesture: Handlers = {}
|
||||
) {
|
||||
const isInteractingWithCanvas = useRef(false);
|
||||
const pinchPreviousDistanceRef = useRef();
|
||||
const pinchPreviousOriginRef = useRef();
|
||||
const pinchPreviousDistanceRef = useRef<number>(0);
|
||||
const pinchPreviousOriginRef = useRef<Vector2>({ x: 0, y: 0 });
|
||||
|
||||
const [zoomSpeed, setZoomSpeed] = useState(1);
|
||||
|
||||
// Prevent accessibility pinch to zoom on Mac
|
||||
useEffect(() => {
|
||||
function handleGesture(e) {
|
||||
function handleGesture(e: Event) {
|
||||
e.preventDefault();
|
||||
}
|
||||
window.addEventListener("gesturestart", handleGesture);
|
||||
@ -69,16 +76,18 @@ function useStageInteraction(
|
||||
|
||||
// Center on pointer
|
||||
const pointer = stage.getPointerPosition();
|
||||
const newTranslate = {
|
||||
x: pointer.x - ((pointer.x - stage.x()) / stageScale) * newScale,
|
||||
y: pointer.y - ((pointer.y - stage.y()) / stageScale) * newScale,
|
||||
};
|
||||
if (pointer) {
|
||||
const newTranslate = {
|
||||
x: pointer.x - ((pointer.x - stage.x()) / stageScale) * newScale,
|
||||
y: pointer.y - ((pointer.y - stage.y()) / stageScale) * newScale,
|
||||
};
|
||||
|
||||
stage.position(newTranslate);
|
||||
stage.position(newTranslate);
|
||||
|
||||
stageTranslateRef.current = newTranslate;
|
||||
stageTranslateRef.current = newTranslate;
|
||||
|
||||
onStageScaleChange(newScale);
|
||||
onStageScaleChange(newScale);
|
||||
}
|
||||
}
|
||||
|
||||
gesture.onWheel && gesture.onWheel(props);
|
||||
@ -186,7 +195,7 @@ function useStageInteraction(
|
||||
}
|
||||
);
|
||||
|
||||
function handleKeyDown(event) {
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
// TODO: Find better way to detect whether keyboard event should fire.
|
||||
// This one fires on all open stages
|
||||
if (preventInteraction) {
|
||||
@ -222,7 +231,7 @@ function useStageInteraction(
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyUp(event) {
|
||||
function handleKeyUp(event: KeyboardEvent) {
|
||||
if (shortcuts.stagePrecisionZoom(event)) {
|
||||
setZoomSpeed(1);
|
||||
}
|
@ -3038,6 +3038,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
|
||||
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
|
||||
|
||||
"@types/normalize-wheel@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/normalize-wheel/-/normalize-wheel-1.0.0.tgz#d973b53557dc59c6136b5b737ae930e9218cb452"
|
||||
integrity sha512-SzWYVzP7Q8w4/976Gi3a6+J/8/VNTq6AW7wDafXorr1MYTxyZqJTbUvwQt1hiG3PXyFUMIKr+s6q3+MLz2c/TQ==
|
||||
|
||||
"@types/offscreencanvas@~2019.3.0":
|
||||
version "2019.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz#3336428ec7e9180cf4566dfea5da04eb586a6553"
|
||||
|
Loading…
x
Reference in New Issue
Block a user