Added token dragging from side bar into map view

This commit is contained in:
Mitchell McCaffrey 2020-03-20 11:05:40 +11:00
parent a22b3231fb
commit 81d311eb7f
8 changed files with 501 additions and 68 deletions

View File

@ -7,12 +7,13 @@
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"hookrouter": "^1.2.3",
"interactjs": "^1.9.7",
"peerjs": "^1.2.0",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"react-draggable": "^4.2.0",
"react-modal": "^3.11.2",
"react-scripts": "3.4.0",
"shortid": "^2.2.15",
"theme-ui": "^0.3.1"
},
"scripts": {

View File

@ -1,9 +1,36 @@
import React from "react";
import { Image, Flex } from "theme-ui";
import { Image, Flex, Box } from "theme-ui";
function Map({ imageSource }) {
import Token from "../components/Token";
function Map({ imageSource, tokens }) {
return (
<Flex sx={{ justifyContent: "center", flexGrow: 1 }} bg="background">
<Flex
className="map"
sx={{ justifyContent: "center", flexGrow: 1 }}
bg="background"
>
<Box
sx={{
position: "absolute",
top: 0,
left: 0,
right: 0,
userSelect: "none"
}}
>
{Object.values(tokens).map(token => (
<Box
key={token.id}
sx={{
position: "absolute",
transform: `translate(${token.x}px, ${token.y}px)`
}}
>
<Token image={token.image} className="map-token" />
</Box>
))}
</Box>
<Image src={imageSource} sx={{ objectFit: "contain" }} />
</Flex>
);

View File

@ -0,0 +1,126 @@
import React, { useEffect, useRef, useState } from "react";
import ReactDOM from "react-dom";
import { Image, Box } from "theme-ui";
import interact from "interactjs";
import usePortal from "../helpers/usePortal";
function ProxyToken({ tokenClassName, onProxyDragEnd }) {
const proxyContainer = usePortal("root");
const [imageSource, setImageSource] = useState("");
const imageRef = useRef();
const proxyOnMap = useRef(false);
useEffect(() => {
interact(`.${tokenClassName}`).draggable({
listeners: {
start: event => {
let target = event.target;
// Hide the token and copy it's image to the proxy
target.style.opacity = "0.25";
setImageSource(target.src);
let proxy = imageRef.current;
if (proxy) {
// Find and set the initial offset of the token to the proxy
const proxyRect = proxy.getBoundingClientRect();
const targetRect = target.getBoundingClientRect();
const xOffset = targetRect.left - proxyRect.left;
const yOffset = targetRect.top - proxyRect.top;
proxy.style.transform = `translate(${xOffset}px, ${yOffset}px)`;
proxy.setAttribute("data-x", xOffset);
proxy.setAttribute("data-y", yOffset);
}
},
move: event => {
let proxy = imageRef.current;
// Move the proxy based off of the movment of the token
if (proxy) {
// keep the dragged position in the data-x/data-y attributes
const x =
(parseFloat(proxy.getAttribute("data-x")) || 0) + event.dx;
const y =
(parseFloat(proxy.getAttribute("data-y")) || 0) + event.dy;
proxy.style.transform = `translate(${x}px, ${y}px)`;
// Check whether the proxy is on the right or left hand side of the screen
// if not set proxyOnMap to true
if (proxyContainer) {
const proxyContainerRect = proxyContainer.getBoundingClientRect();
const proxyRect = proxy.getBoundingClientRect();
proxyOnMap.current =
proxyContainerRect.right - proxyRect.right > 80 &&
proxyRect.left > 192;
}
// update the posiion attributes
proxy.setAttribute("data-x", x);
proxy.setAttribute("data-y", y);
}
},
end: event => {
let target = event.target;
let proxy = imageRef.current;
if (proxy) {
if (onProxyDragEnd) {
const endX = parseFloat(proxy.getAttribute("data-x")) || 0;
const endY = parseFloat(proxy.getAttribute("data-y")) || 0;
onProxyDragEnd(proxyOnMap.current, {
image: imageSource,
x: endX,
y: endY
});
}
// Reset the proxy position
proxy.style.transform = "translate(0px, 0px)";
proxy.setAttribute("data-x", 0);
proxy.setAttribute("data-y", 0);
}
// Show the token
target.style.opacity = "1";
setImageSource("");
}
}
});
}, [imageSource, onProxyDragEnd, tokenClassName, proxyContainer]);
if (!imageSource) {
return null;
}
// Create a portal to allow the proxy to move past the bounds of the token
return ReactDOM.createPortal(
<Box
sx={{
width: "100vw",
height: "100vh",
position: "absolute",
overflow: "hidden",
top: 0,
left: 0
}}
>
<Image
p={2}
src={imageSource}
sx={{
width: "64px",
height: "64px",
touchAction: "none",
userSelect: "none",
position: "absolute"
}}
ref={imageRef}
/>
</Box>,
proxyContainer
);
}
export default ProxyToken;

View File

@ -1,18 +1,17 @@
import React from "react";
import Draggable from "react-draggable";
import { Image } from "theme-ui";
function Token({ onDrag, position }) {
function Token({ image, className }) {
return (
<Draggable onDrag={onDrag} position={position}>
<div
style={{
borderRadius: "50%",
width: "50px",
height: "50px",
background: "blue"
}}
></div>
</Draggable>
<Image
p={2}
className={className}
src={image}
sx={{
width: "64px",
height: "64px"
}}
/>
);
}

View File

@ -1,31 +1,43 @@
import React from "react";
import { Flex, Image } from "theme-ui";
import { Flex } from "theme-ui";
import shortid from "shortid";
import * as tokens from "../tokens";
// import Token from "./Token";
import Token from "./Token";
import ProxyToken from "./ProxyToken";
function Tokens({ onCreateMapToken }) {
const tokenClassName = "list-token";
function handleProxyDragEnd(isOnMap, token) {
if (isOnMap && onCreateMapToken) {
// Give the token an id
onCreateMapToken({ id: shortid.generate(), ...token });
}
}
function Tokens() {
return (
<Flex
bg="background"
sx={{
width: "80px",
minWidth: "80px",
flexDirection: "column",
overflow: "auto"
}}
px={2}
>
{Object.entries(tokens).map(([id, image]) => (
<Image
p={2}
key={id}
src={image}
sx={{ width: "64px", height: "64px" }}
/>
))}
</Flex>
<>
<Flex
bg="background"
sx={{
width: "80px",
minWidth: "80px",
flexDirection: "column",
overflow: "auto"
}}
px={2}
>
{Object.entries(tokens).map(([id, image]) => (
<Token key={id} image={image} className={tokenClassName} />
))}
</Flex>
<ProxyToken
tokenClassName={tokenClassName}
onProxyDragEnd={handleProxyDragEnd}
/>
</>
);
}

85
src/helpers/usePortal.js Normal file
View File

@ -0,0 +1,85 @@
import { useRef, useEffect } from "react";
// Based on https://www.jayfreestone.com/writing/react-portals-with-hooks/
/**
* Creates DOM element to be used as React root.
* @returns {HTMLElement}
*/
function createRootElement(id) {
const rootContainer = document.createElement("div");
rootContainer.setAttribute("id", id);
return rootContainer;
}
/**
* Appends element as last child of body.
* @param {HTMLElement} rootElem
*/
function addRootElement(rootElem) {
document.body.insertBefore(
rootElem,
document.body.lastElementChild.nextElementSibling
);
}
/**
* Hook to create a React Portal.
* Automatically handles creating and tearing-down the root elements (no SRR
* makes this trivial), so there is no need to ensure the parent target already
* exists.
* @example
* const target = usePortal(id, [id]);
* return createPortal(children, target);
* @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);
useEffect(
function setupElement() {
// Look for existing target dom element to append to
const existingParent = document.querySelector(`#${id}`);
// Parent is either a new root or the existing dom element
const parentElem = existingParent || createRootElement(id);
// If there is no existing DOM element, add a new one.
if (!existingParent) {
addRootElement(parentElem);
}
// Add the detached element to the parent
parentElem.appendChild(rootElemRef.current);
return function removeElement() {
rootElemRef.current.remove();
if (parentElem.childNodes.length === -1) {
parentElem.remove();
}
};
},
[id]
);
/**
* It's important we evaluate this lazily:
* - We need first render to contain the DOM element, so it shouldn't happen
* in useEffect. We would normally put this in the constructor().
* - We can't do 'const rootElemRef = useRef(document.createElement('div))',
* since this will run every single render (that's a lot).
* - We want the ref to consistently point to the same DOM element and only
* ever run once.
* @link https://reactjs.org/docs/hooks-faq.html#how-to-create-expensive-objects-lazily
*/
function getRootElem() {
if (!rootElemRef.current) {
rootElemRef.current = document.createElement("div");
}
return rootElemRef.current;
}
return getRootElem();
}
export default usePortal;

View File

@ -10,7 +10,6 @@ import { Box, Flex } from "theme-ui";
import GameContext from "../contexts/GameContext";
import useSession from "../helpers/useSession";
import Token from "../components/Token";
import Party from "../components/Party";
import Tokens from "../components/Tokens";
import Map from "../components/Map";
@ -42,6 +41,18 @@ function Game() {
}
}
const [mapTokens, setMapTokens] = useState({});
function handleCreateMapToken(token) {
setMapTokens(prevMapTokens => ({
...prevMapTokens,
[token.id]: token
}));
for (let connection of Object.values(connections)) {
connection.send({ id: "token", data: token });
}
}
function handleConnectionOpen(connection) {
connection.on("data", data => {
if (data.id === "image") {
@ -50,7 +61,11 @@ function Game() {
setImageSource(URL.createObjectURL(imageDataRef.current));
}
if (data.id === "token") {
setTokenPosition(data.data);
const token = data.data;
setMapTokens(prevMapTokens => ({
...prevMapTokens,
[token.id]: token
}));
}
});
}
@ -59,17 +74,7 @@ function Game() {
if (imageSource) {
connection.send({ id: "image", data: imageDataRef.current });
}
connection.send({ id: "token", data: tokenPosition });
}
const [tokenPosition, setTokenPosition] = useState({ x: 0, y: 0 });
function handleTokenDrag(event, data) {
const position = { x: data.x, y: data.y };
setTokenPosition(position);
for (let connection of Object.values(connections)) {
connection.send({ id: "token", data: position });
}
connection.send({ id: "token", data: mapTokens });
}
return (
@ -89,9 +94,8 @@ function Game() {
sx={{ justifyContent: "space-between", flexGrow: 1, height: "100%" }}
>
<Party streams={streams} localStreamId={peerId} />
<Map imageSource={imageSource} />
<Tokens />
{/* <Token onDrag={handleTokenDrag} position={tokenPosition} /> */}
<Map imageSource={imageSource} tokens={mapTokens} />
<Tokens onCreateMapToken={handleCreateMapToken} />
</Flex>
</Flex>
);

207
yarn.lock
View File

@ -1048,6 +1048,178 @@
dependencies:
"@hapi/hoek" "^8.3.0"
"@interactjs/actions@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/actions/-/actions-1.9.7.tgz#b015931f406e090e48d3244343cf7b2cc53c90f1"
integrity sha512-j5+2Cj1Ra3/0BgfCqL7hKGw7kOZyOBg3HXi+EJ9AT0sJzetjwsRt5YlvCm9URH8XcY7sNlFi8gD5mPFjD8DZaw==
optionalDependencies:
"@interactjs/interact" "1.9.7"
"@interactjs/arrange@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/arrange/-/arrange-1.9.7.tgz#42323ce4b1af905d6e4ab76fc066cd1573bd41ee"
integrity sha512-gXcj4Gti3WsRmJ4Ohr5toUl7AjsBOY6Ik5SX69X3AZKrQpDJfkNBcOZJ/AlAPLXIwjBV8rRQiddYgB+SXCJcBg==
"@interactjs/auto-scroll@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/auto-scroll/-/auto-scroll-1.9.7.tgz#e6c2e67b6ed43dd0dd6a84e96b5d1389a20a647a"
integrity sha512-/753R5h8z1VQ/aS5VsqI6C0V6fwb3934tP7s+htHL27aPVxyz20kfZVd74t5BmPSUAxAyDqwNVZ1vgjGLCSyAQ==
optionalDependencies:
"@interactjs/interact" "1.9.7"
"@interactjs/auto-start@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/auto-start/-/auto-start-1.9.7.tgz#4afa53c7c869170cb3a01a0019aa30791b3c5d18"
integrity sha512-fKn7Yrl6idw7gxbAC0zvcQLSTsUE9WGs71+Y9WVj+ICQMkTO19ci9Y1lCBdo1AP/njLaQp8yPbHoUe5pI7eW6w==
optionalDependencies:
"@interactjs/interact" "1.9.7"
"@interactjs/clone@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/clone/-/clone-1.9.7.tgz#fdde8307835cecadd9e29f597ecff890d03167fc"
integrity sha512-GNlGh5sKVFYcpOn7Z3HNOLItBdzG3f6t38soUowCmNv4Rd19nmnXkvKKVhfodjfBk26fsdXFI6EZ3iduzYsmAg==
"@interactjs/components@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/components/-/components-1.9.7.tgz#40ec9889fd1e94d07c67001b36dd39d113b3e762"
integrity sha512-TdNlJVbKKLy2ZmNtpjhxQkQls1SqXXFSyY4JfAGRG23UOOMrjoG4+56RAe4tlOpHSIIfEER5skvgBSv6UFajHw==
"@interactjs/core@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/core/-/core-1.9.7.tgz#1fdf924c369df23ffe1300af9c945f2651538043"
integrity sha512-fN7OfPNU9jgS+hEqe0+OJvJjp/XgNE9lkuCnH57/xtT4nfDca/43BkE57bNoEXhM9Ym5js2Ium+MbUTUVyZ+3A==
"@interactjs/dev-tools@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/dev-tools/-/dev-tools-1.9.7.tgz#91eab3f10806b84b95c313ef5f06408c2d3251cf"
integrity sha512-LhLeLZw2joG13j3hUAuhmC9HTsVCnUEggcScgCcpY/SQRA51JCCM9lEcXnwTxTxd02v6A/tueoyUdONm2lniCA==
dependencies:
"@interactjs/utils" "1.9.7"
optionalDependencies:
"@interactjs/interact" "1.9.7"
"@interactjs/feedback@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/feedback/-/feedback-1.9.7.tgz#0e3ea3c8e863fdf89d8afee0a1ae5838e9f13d09"
integrity sha512-CcgTv2mhCWpH0w6Fq12K6kiV1BSozt8Rdy02yXg927ruKChr7pIQvvZP7TpxfZoBFCN9JJxN3KvQpcfsUQsafQ==
"@interactjs/inertia@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/inertia/-/inertia-1.9.7.tgz#e8c8ed702bd23d0182a1a0ddbca4be7419826511"
integrity sha512-WeVKgztqODjE+fbYuIayJv4cdqwBz4wJ45RC2qYhYWhzsHL0LUbJhEs6sCnV3q+2wZEVMdB8oURh8tnqECBIGg==
dependencies:
"@interactjs/offset" "1.9.7"
optionalDependencies:
"@interactjs/interact" "1.9.7"
"@interactjs/interact@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/interact/-/interact-1.9.7.tgz#be988cfb15b13f2cfc0aa68ce826761d49f46e8a"
integrity sha512-BocTUB8TfZ3USuN1s7xP+3Uhvb7dnZFNTfr3Ux6Nv2BxKLMz/bIU2fZhYAHw7xApIMKfYyRuUNxSyGM5iyCaEA==
dependencies:
"@interactjs/core" "1.9.7"
"@interactjs/types" "1.9.7"
"@interactjs/utils" "1.9.7"
"@interactjs/interactjs@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/interactjs/-/interactjs-1.9.7.tgz#995b6d9b4abd03a84b02c887315768ab2421b35c"
integrity sha512-D3wdlwUQRS8t8r7TopYlkjKsONxazrZu8R4DBL+czUrm26Il/0427+uoV92iMgDUZpw5fYLt1dzqzozUL/y6Dw==
dependencies:
"@interactjs/actions" "1.9.7"
"@interactjs/arrange" "1.9.7"
"@interactjs/auto-scroll" "1.9.7"
"@interactjs/auto-start" "1.9.7"
"@interactjs/clone" "1.9.7"
"@interactjs/components" "1.9.7"
"@interactjs/core" "1.9.7"
"@interactjs/dev-tools" "1.9.7"
"@interactjs/feedback" "1.9.7"
"@interactjs/inertia" "1.9.7"
"@interactjs/interact" "1.9.7"
"@interactjs/modifiers" "1.9.7"
"@interactjs/multi-target" "1.9.7"
"@interactjs/offset" "1.9.7"
"@interactjs/pointer-events" "1.9.7"
"@interactjs/reflow" "1.9.7"
"@interactjs/types" "1.9.7"
"@interactjs/utils" "1.9.7"
"@interactjs/vue" "1.9.7"
"@interactjs/modifiers@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/modifiers/-/modifiers-1.9.7.tgz#dcb37e3782c91d7f8b28008d68ec5ebc26101e7a"
integrity sha512-1trdJ6E85DiUn2u0zvqLYt77aoug0VYDg8c1GyzcLm64t8CYw+PggTQKqhy+kJiKb30QsgUuhsR5aQdlotguew==
dependencies:
"@interactjs/snappers" "1.9.7"
optionalDependencies:
"@interactjs/interact" "1.9.7"
"@interactjs/multi-target@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/multi-target/-/multi-target-1.9.7.tgz#bb4de8612f6a649e18d40b93ed5461cde72f79ee"
integrity sha512-hqw4sCKYxUZV00u0ikEM66t6zrCP8t3TDgDPrph274LmEUIdfGrCsv7xWLIEdke63h0pt3lO1V5H8N/rMoGs0A==
"@interactjs/offset@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/offset/-/offset-1.9.7.tgz#5a2aec0f25781bd1728c71fe8c16a55edc3f5b8e"
integrity sha512-IMCizwVDk2hj8yNNTfLnqdK9GuSlFSS8GxK2ZGUGNSQSPh3b6vrkkIrxwA/qHjDGUUuDP+ZWvlAF4D0/OAc74g==
optionalDependencies:
"@interactjs/interact" "1.9.7"
"@interactjs/pointer-events@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/pointer-events/-/pointer-events-1.9.7.tgz#5a0e0daff1c322c6cbff8cbb8052c531d66d1aad"
integrity sha512-Vl/+GTVnZlw8DQ7YN7D1oIIZLiqPL/KgdfRrGHSidsLmo/WJNM2TsJJsJcRMY/IiEQrtTvp/fSKG6rNWyzIr5w==
optionalDependencies:
"@interactjs/interact" "1.9.7"
"@interactjs/reflow@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/reflow/-/reflow-1.9.7.tgz#77494d83e1a13236ca841adba997faaaf6eb633c"
integrity sha512-npuIadX3YBoFFqJbM+LQZgPyw/IYq3HwYM2WNi8Bc/feCy1Ia12uF4Lwi5Rj+8jcA5FyInHzZXBUJCcHO1zaFQ==
optionalDependencies:
"@interactjs/interact" "1.9.7"
"@interactjs/snappers@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/snappers/-/snappers-1.9.7.tgz#b2f3752ab25c886cd5ae1f4c0478964b9b8b652e"
integrity sha512-EfKsgTi8yCtNWRHSU2INfMob5eMUBY8Wrh53tszgh94JstyKwlmzG2mH6eGwdN7pU3//h0AM4ThuqOmbIYUPCw==
"@interactjs/symbol-tree@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/symbol-tree/-/symbol-tree-1.9.7.tgz#2aec371ded47be71cfa359305da959b382de66ff"
integrity sha512-zLRpXVtzq/TxG6MwT1FhkBNoFGZlYxNd52RZ6Wy5XyPAsxaZoXqNzDUT6See/xe2X80gzvT78dkT5uKSUE3I2w==
"@interactjs/types@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/types/-/types-1.9.7.tgz#6e7a8bc26d99bd5f324312950b948b936f6d42e0"
integrity sha512-Z6fPHp2JjCYg4SJ/DhaIqelY1WA6Oppw87PscOM+28jPc2q5pTUMlFzAY0QQlF43t4PFiCAZVhmBGZzgMfyF0A==
dependencies:
"@interactjs/actions" "1.9.7"
"@interactjs/arrange" "1.9.7"
"@interactjs/auto-scroll" "1.9.7"
"@interactjs/auto-start" "1.9.7"
"@interactjs/core" "1.9.7"
"@interactjs/dev-tools" "1.9.7"
"@interactjs/inertia" "1.9.7"
"@interactjs/modifiers" "1.9.7"
"@interactjs/pointer-events" "1.9.7"
"@interactjs/reflow" "1.9.7"
"@interactjs/snappers" "1.9.7"
"@interactjs/symbol-tree" "1.9.7"
"@interactjs/utils" "1.9.7"
"@interactjs/utils@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/utils/-/utils-1.9.7.tgz#390f574c5b8adbf9cc527affb686d9233d241eec"
integrity sha512-7/j0UmeuBHi20FHlqKN9KbndulLEuTiPIPID5nEw+1F/jMKucn3uPIXfruSkbcGswltqTCR0QHhICMLXhFRVhw==
"@interactjs/vue@1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@interactjs/vue/-/vue-1.9.7.tgz#9942407a144b4cd9d1f264ccaaf43d75f5a00a60"
integrity sha512-Y1mjCB5tGxsaUkfYP/i1dIoBRnxkDpvZtmfKp38u1SRt3QCfNznKf4252QC7RBTSgIL/Cohi8c/oAq++ZpkTSQ==
"@jest/console@^24.7.1", "@jest/console@^24.9.0":
version "24.9.0"
resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0"
@ -2984,11 +3156,6 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
classnames@^2.2.5:
version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
clean-css@^4.2.1:
version "4.2.3"
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
@ -5480,6 +5647,14 @@ inquirer@7.0.4, inquirer@^7.0.0:
strip-ansi "^5.1.0"
through "^2.3.6"
interactjs@^1.9.7:
version "1.9.7"
resolved "https://registry.yarnpkg.com/interactjs/-/interactjs-1.9.7.tgz#ebcbc3cab9c63f4cd66aa650a5918bcc2aaeeead"
integrity sha512-X8Y4iSeFdy8bnFkbrDJ5C/HwGKCgLUHhOdfvxLsx/f1YlYZ23qBA4aYoB74Qw0CG/mMenYiOFLxbDIaly8hhzQ==
dependencies:
"@interactjs/interactjs" "1.9.7"
"@interactjs/types" "1.9.7"
internal-ip@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
@ -7035,6 +7210,11 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
nanoid@^2.1.0:
version "2.1.11"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@ -8586,7 +8766,7 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.3"
prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -8792,14 +8972,6 @@ react-dom@^16.13.0:
prop-types "^15.6.2"
scheduler "^0.19.0"
react-draggable@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.2.0.tgz#40cc5209082ca7d613104bf6daf31372cc0e1114"
integrity sha512-5wFq//gEoeTYprnd4ze8GrFc+Rbnx+9RkOMR3vk4EbWxj02U6L6T3yrlKeiw4X5CtjD2ma2+b3WujghcXNRzkw==
dependencies:
classnames "^2.2.5"
prop-types "^15.6.0"
react-error-overlay@^6.0.6:
version "6.0.6"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.6.tgz#ac4d9dc4c1b5c536c2c312bf66aa2b09bfa384e2"
@ -9604,6 +9776,13 @@ shellwords@^0.1.1:
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
shortid@^2.2.15:
version "2.2.15"
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.15.tgz#2b902eaa93a69b11120373cd42a1f1fe4437c122"
integrity sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==
dependencies:
nanoid "^2.1.0"
signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"