diff --git a/src/components/ListToken.js b/src/components/ListToken.js
new file mode 100644
index 0000000..f90d3d0
--- /dev/null
+++ b/src/components/ListToken.js
@@ -0,0 +1,21 @@
+import React, { useRef } from "react";
+import { Image } from "theme-ui";
+
+import usePreventTouch from "../helpers/usePreventTouch";
+
+function ListToken({ image, className }) {
+ const imageRef = useRef();
+ // Stop touch to prevent 3d touch gesutre on iOS
+ usePreventTouch(imageRef);
+
+ return (
+
+ );
+}
+
+export default ListToken;
diff --git a/src/components/Map.js b/src/components/Map.js
index dc3ec02..6c9b811 100644
--- a/src/components/Map.js
+++ b/src/components/Map.js
@@ -2,9 +2,10 @@ import React, { useRef, useEffect, useState } from "react";
import { Box, Image } from "theme-ui";
import interact from "interactjs";
-import Token from "../components/Token";
import ProxyToken from "../components/ProxyToken";
import AddMapButton from "../components/AddMapButton";
+import TokenMenu from "../components/TokenMenu";
+import MapToken from "../components/MapToken";
const mapTokenClassName = "map-token";
const zoomSpeed = -0.005;
@@ -15,13 +16,13 @@ function Map({
mapSource,
mapData,
tokens,
- onMapTokenMove,
+ onMapTokenChange,
onMapTokenRemove,
- onMapChanged,
+ onMapChange,
}) {
function handleProxyDragEnd(isOnMap, token) {
- if (isOnMap && onMapTokenMove) {
- onMapTokenMove(token);
+ if (isOnMap && onMapTokenChange) {
+ onMapTokenChange(token);
}
if (!isOnMap && onMapTokenRemove) {
@@ -120,6 +121,64 @@ function Map({
const tokenSizePercent = (1 / rows) * 100;
const aspectRatio = (mapData && mapData.width / mapData.height) || 1;
+ const mapImage = (
+
+
+
+ );
+
+ const mapTokens = (
+
+ {Object.values(tokens).map((token) => (
+
+ ))}
+
+ );
+
+ const mapActions = (
+
+
+
+ );
+
return (
<>
-
-
-
-
- {Object.values(tokens).map((token) => (
-
-
-
- ))}
-
+ {mapImage}
+ {mapTokens}
-
-
-
+ {mapActions}
+
>
);
}
diff --git a/src/components/MapToken.js b/src/components/MapToken.js
new file mode 100644
index 0000000..fff70cb
--- /dev/null
+++ b/src/components/MapToken.js
@@ -0,0 +1,57 @@
+import React, { useRef } from "react";
+import { Box, Image } from "theme-ui";
+
+import TokenLabel from "./TokenLabel";
+
+import usePreventTouch from "../helpers/usePreventTouch";
+
+function MapToken({ token, tokenSizePercent, className }) {
+ const imageRef = useRef();
+ // Stop touch to prevent 3d touch gesutre on iOS
+ usePreventTouch(imageRef);
+
+ return (
+
+
+
+
+ {token.label && }
+
+
+
+ );
+}
+
+export default MapToken;
diff --git a/src/components/SizeInput.js b/src/components/NumberInput.js
similarity index 70%
rename from src/components/SizeInput.js
rename to src/components/NumberInput.js
index 799eefa..e6985f8 100644
--- a/src/components/SizeInput.js
+++ b/src/components/NumberInput.js
@@ -1,17 +1,17 @@
import React from "react";
import { Box, Flex, IconButton, Text } from "theme-ui";
-function SizeInput({ value, onChange }) {
+function NumberInput({ value, onChange, title, min, max }) {
return (
- Size
+ {title}
value > 1 && onChange(value - 1)}
+ aria-label={`Decrease ${title}`}
+ title={`Decrease ${title}`}
+ onClick={() => value > min && onChange(value - 1)}
>
-
+
{value}
onChange(value + 1)}
+ aria-label={`Increase ${title}`}
+ title={`Increase ${title}`}
+ onClick={() => value < max && onChange(value + 1)}
>
{
+ // Stop 3d touch
+ function prevent3DTouch(event) {
+ event.preventDefault();
+ }
+ const element = elementRef.current;
+ if (element) {
+ element.addEventListener("touchstart", prevent3DTouch, false);
+ }
+
+ return () => {
+ if (element) {
+ element.removeEventListener("touchstart", prevent3DTouch);
+ }
+ };
+ }, [elementRef.current]);
+}
+
+export default usePreventTouch;
diff --git a/src/images/TokenLabel.png b/src/images/TokenLabel.png
new file mode 100644
index 0000000..637ddab
Binary files /dev/null and b/src/images/TokenLabel.png differ
diff --git a/src/routes/Game.js b/src/routes/Game.js
index 8d4522c..ddc1e01 100644
--- a/src/routes/Game.js
+++ b/src/routes/Game.js
@@ -28,7 +28,7 @@ function Game() {
const [mapSource, setMapSource] = useState(null);
const mapDataRef = useRef(null);
- function handleMapChanged(mapData, mapSource) {
+ function handleMapChange(mapData, mapSource) {
mapDataRef.current = mapData;
setMapSource(mapSource);
for (let peer of Object.values(peers)) {
@@ -38,7 +38,7 @@ function Game() {
const [mapTokens, setMapTokens] = useState({});
- function handleEditMapToken(token) {
+ function handleMapTokenChange(token) {
if (!mapSource) {
return;
}
@@ -52,7 +52,7 @@ function Game() {
}
}
- function handleRemoveMapToken(token) {
+ function handleMapTokenRemove(token) {
setMapTokens((prevMapTokens) => {
const { [token.id]: old, ...rest } = prevMapTokens;
return rest;
@@ -213,11 +213,11 @@ function Game() {
mapSource={mapSource}
mapData={mapDataRef.current}
tokens={mapTokens}
- onMapTokenMove={handleEditMapToken}
- onMapTokenRemove={handleRemoveMapToken}
- onMapChanged={handleMapChanged}
+ onMapTokenChange={handleMapTokenChange}
+ onMapTokenRemove={handleMapTokenRemove}
+ onMapChange={handleMapChange}
/>
-
+
setPeerError(null)}>