feat: add basic touchscreen support

This is basically a migration from mouse events to
[pointer events](
  https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
).

The `PointerEvent` interface inherits all of the `MouseEvent`
properties, meaning that existing code can essentially be left
as-is. The only major change is making sure we only respond to the
"primary" pointer.

Known issues include:
* stylus hover is not detected
* touchscreens do not have a concept of hover, making it difficult
  to e.g. resize areas
* no touch gesture support, e.g. "pinch-to-zoom"
This commit is contained in:
Felix Zedén Yverås
2024-06-26 20:43:56 +02:00
parent 075a98d444
commit cdecf7c633
8 changed files with 95 additions and 67 deletions

View File

@@ -20,7 +20,7 @@ import {
import ColorPalette from "../ColorPicker";
import { useTranslation } from "react-i18next";
export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
export default function Area({ data, onPointerDown, setResize, setInitCoords }) {
const [hovered, setHovered] = useState(false);
const { layout } = useLayout();
const { settings } = useSettings();
@@ -35,8 +35,8 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
y: data.y,
width: data.width,
height: data.height,
mouseX: e.clientX / transform.zoom,
mouseY: e.clientY / transform.zoom,
pointerX: e.clientX / transform.zoom,
pointerY: e.clientY / transform.zoom,
});
};
@@ -85,8 +85,8 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
return (
<g
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
onPointerEnter={(e) => e.isPrimary && setHovered(true)}
onPointerLeave={(e) => e.isPrimary &&setHovered(false)}
>
<foreignObject
key={data.id}
@@ -94,7 +94,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
y={data.y}
width={data.width > 0 ? data.width : 0}
height={data.height > 0 ? data.height : 0}
onMouseDown={onMouseDown}
onPointerDown={onPointerDown}
>
<div
className={`border-2 ${
@@ -149,7 +149,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
stroke="#5891db"
strokeWidth={2}
cursor="nwse-resize"
onMouseDown={(e) => handleResize(e, "tl")}
onPointerDown={(e) => e.isPrimary && handleResize(e, "tl")}
/>
<circle
cx={data.x + data.width}
@@ -159,7 +159,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
stroke="#5891db"
strokeWidth={2}
cursor="nesw-resize"
onMouseDown={(e) => handleResize(e, "tr")}
onPointerDown={(e) => e.isPrimary && handleResize(e, "tr")}
/>
<circle
cx={data.x}
@@ -169,7 +169,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
stroke="#5891db"
strokeWidth={2}
cursor="nesw-resize"
onMouseDown={(e) => handleResize(e, "bl")}
onPointerDown={(e) => e.isPrimary && handleResize(e, "bl")}
/>
<circle
cx={data.x + data.width}
@@ -179,7 +179,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
stroke="#5891db"
strokeWidth={2}
cursor="nwse-resize"
onMouseDown={(e) => handleResize(e, "br")}
onPointerDown={(e) => e.isPrimary && handleResize(e, "br")}
/>
</>
)}