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:
parent
075a98d444
commit
cdecf7c633
@ -20,7 +20,7 @@ import {
|
|||||||
import ColorPalette from "../ColorPicker";
|
import ColorPalette from "../ColorPicker";
|
||||||
import { useTranslation } from "react-i18next";
|
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 [hovered, setHovered] = useState(false);
|
||||||
const { layout } = useLayout();
|
const { layout } = useLayout();
|
||||||
const { settings } = useSettings();
|
const { settings } = useSettings();
|
||||||
@ -35,8 +35,8 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
|
|||||||
y: data.y,
|
y: data.y,
|
||||||
width: data.width,
|
width: data.width,
|
||||||
height: data.height,
|
height: data.height,
|
||||||
mouseX: e.clientX / transform.zoom,
|
pointerX: e.clientX / transform.zoom,
|
||||||
mouseY: e.clientY / transform.zoom,
|
pointerY: e.clientY / transform.zoom,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,8 +85,8 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<g
|
<g
|
||||||
onMouseEnter={() => setHovered(true)}
|
onPointerEnter={(e) => e.isPrimary && setHovered(true)}
|
||||||
onMouseLeave={() => setHovered(false)}
|
onPointerLeave={(e) => e.isPrimary &&setHovered(false)}
|
||||||
>
|
>
|
||||||
<foreignObject
|
<foreignObject
|
||||||
key={data.id}
|
key={data.id}
|
||||||
@ -94,7 +94,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
|
|||||||
y={data.y}
|
y={data.y}
|
||||||
width={data.width > 0 ? data.width : 0}
|
width={data.width > 0 ? data.width : 0}
|
||||||
height={data.height > 0 ? data.height : 0}
|
height={data.height > 0 ? data.height : 0}
|
||||||
onMouseDown={onMouseDown}
|
onPointerDown={onPointerDown}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`border-2 ${
|
className={`border-2 ${
|
||||||
@ -149,7 +149,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
|
|||||||
stroke="#5891db"
|
stroke="#5891db"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
cursor="nwse-resize"
|
cursor="nwse-resize"
|
||||||
onMouseDown={(e) => handleResize(e, "tl")}
|
onPointerDown={(e) => e.isPrimary && handleResize(e, "tl")}
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
cx={data.x + data.width}
|
cx={data.x + data.width}
|
||||||
@ -159,7 +159,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
|
|||||||
stroke="#5891db"
|
stroke="#5891db"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
cursor="nesw-resize"
|
cursor="nesw-resize"
|
||||||
onMouseDown={(e) => handleResize(e, "tr")}
|
onPointerDown={(e) => e.isPrimary && handleResize(e, "tr")}
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
cx={data.x}
|
cx={data.x}
|
||||||
@ -169,7 +169,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
|
|||||||
stroke="#5891db"
|
stroke="#5891db"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
cursor="nesw-resize"
|
cursor="nesw-resize"
|
||||||
onMouseDown={(e) => handleResize(e, "bl")}
|
onPointerDown={(e) => e.isPrimary && handleResize(e, "bl")}
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
cx={data.x + data.width}
|
cx={data.x + data.width}
|
||||||
@ -179,7 +179,7 @@ export default function Area({ data, onMouseDown, setResize, setInitCoords }) {
|
|||||||
stroke="#5891db"
|
stroke="#5891db"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
cursor="nwse-resize"
|
cursor="nwse-resize"
|
||||||
onMouseDown={(e) => handleResize(e, "br")}
|
onPointerDown={(e) => e.isPrimary && handleResize(e, "br")}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -68,14 +68,21 @@ export default function Canvas() {
|
|||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
mouseX: 0,
|
pointerX: 0,
|
||||||
mouseY: 0,
|
pointerY: 0,
|
||||||
});
|
});
|
||||||
const [cursor, setCursor] = useState("default");
|
const [cursor, setCursor] = useState("default");
|
||||||
|
|
||||||
const canvas = useRef(null);
|
const canvas = useRef(null);
|
||||||
|
|
||||||
const handleMouseDownOnElement = (e, id, type) => {
|
/**
|
||||||
|
* @param {PointerEvent} e
|
||||||
|
* @param {*} id
|
||||||
|
* @param {ObjectType[keyof ObjectType]} type
|
||||||
|
*/
|
||||||
|
const handlePointerDownOnElement = (e, id, type) => {
|
||||||
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
const { clientX, clientY } = e;
|
const { clientX, clientY } = e;
|
||||||
if (type === ObjectType.TABLE) {
|
if (type === ObjectType.TABLE) {
|
||||||
const table = tables.find((t) => t.id === id);
|
const table = tables.find((t) => t.id === id);
|
||||||
@ -122,7 +129,12 @@ export default function Canvas() {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseMove = (e) => {
|
/**
|
||||||
|
* @param {PointerEvent} e
|
||||||
|
*/
|
||||||
|
const handlePointerMove = (e) => {
|
||||||
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
if (linking) {
|
if (linking) {
|
||||||
const rect = canvas.current.getBoundingClientRect();
|
const rect = canvas.current.getBoundingClientRect();
|
||||||
setLinkingLine({
|
setLinkingLine({
|
||||||
@ -164,34 +176,39 @@ export default function Canvas() {
|
|||||||
} else if (areaResize.id !== -1) {
|
} else if (areaResize.id !== -1) {
|
||||||
if (areaResize.dir === "none") return;
|
if (areaResize.dir === "none") return;
|
||||||
let newDims = { ...initCoords };
|
let newDims = { ...initCoords };
|
||||||
delete newDims.mouseX;
|
delete newDims.pointerX;
|
||||||
delete newDims.mouseY;
|
delete newDims.pointerY;
|
||||||
const mouseX = e.clientX / transform.zoom;
|
const pointerX = e.clientX / transform.zoom;
|
||||||
const mouseY = e.clientY / transform.zoom;
|
const pointerY = e.clientY / transform.zoom;
|
||||||
setPanning({ isPanning: false, x: 0, y: 0 });
|
setPanning({ isPanning: false, x: 0, y: 0 });
|
||||||
if (areaResize.dir === "br") {
|
if (areaResize.dir === "br") {
|
||||||
newDims.width = initCoords.width + (mouseX - initCoords.mouseX);
|
newDims.width = initCoords.width + (pointerX - initCoords.pointerX);
|
||||||
newDims.height = initCoords.height + (mouseY - initCoords.mouseY);
|
newDims.height = initCoords.height + (pointerY - initCoords.pointerY);
|
||||||
} else if (areaResize.dir === "tl") {
|
} else if (areaResize.dir === "tl") {
|
||||||
newDims.x = initCoords.x + (mouseX - initCoords.mouseX);
|
newDims.x = initCoords.x + (pointerX - initCoords.pointerX);
|
||||||
newDims.y = initCoords.y + (mouseY - initCoords.mouseY);
|
newDims.y = initCoords.y + (pointerY - initCoords.pointerY);
|
||||||
newDims.width = initCoords.width - (mouseX - initCoords.mouseX);
|
newDims.width = initCoords.width - (pointerX - initCoords.pointerX);
|
||||||
newDims.height = initCoords.height - (mouseY - initCoords.mouseY);
|
newDims.height = initCoords.height - (pointerY - initCoords.pointerY);
|
||||||
} else if (areaResize.dir === "tr") {
|
} else if (areaResize.dir === "tr") {
|
||||||
newDims.y = initCoords.y + (mouseY - initCoords.mouseY);
|
newDims.y = initCoords.y + (pointerY - initCoords.pointerY);
|
||||||
newDims.width = initCoords.width + (mouseX - initCoords.mouseX);
|
newDims.width = initCoords.width + (pointerX - initCoords.pointerX);
|
||||||
newDims.height = initCoords.height - (mouseY - initCoords.mouseY);
|
newDims.height = initCoords.height - (pointerY - initCoords.pointerY);
|
||||||
} else if (areaResize.dir === "bl") {
|
} else if (areaResize.dir === "bl") {
|
||||||
newDims.x = initCoords.x + (mouseX - initCoords.mouseX);
|
newDims.x = initCoords.x + (pointerX - initCoords.pointerX);
|
||||||
newDims.width = initCoords.width - (mouseX - initCoords.mouseX);
|
newDims.width = initCoords.width - (pointerX - initCoords.pointerX);
|
||||||
newDims.height = initCoords.height + (mouseY - initCoords.mouseY);
|
newDims.height = initCoords.height + (pointerY - initCoords.pointerY);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateArea(areaResize.id, { ...newDims });
|
updateArea(areaResize.id, { ...newDims });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseDown = (e) => {
|
/**
|
||||||
|
* @param {PointerEvent} e
|
||||||
|
*/
|
||||||
|
const handlePointerDown = (e) => {
|
||||||
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
// don't pan if the sidesheet for editing a table is open
|
// don't pan if the sidesheet for editing a table is open
|
||||||
if (
|
if (
|
||||||
selectedElement.element === ObjectType.TABLE &&
|
selectedElement.element === ObjectType.TABLE &&
|
||||||
@ -268,7 +285,12 @@ export default function Canvas() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseUp = () => {
|
/**
|
||||||
|
* @param {PointerEvent} e
|
||||||
|
*/
|
||||||
|
const handlePointerUp = (e) => {
|
||||||
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
if (coordsDidUpdate(dragging.element)) {
|
if (coordsDidUpdate(dragging.element)) {
|
||||||
const info = getMovedElementDetails();
|
const info = getMovedElementDetails();
|
||||||
setUndoStack((prev) => [
|
setUndoStack((prev) => [
|
||||||
@ -344,8 +366,8 @@ export default function Canvas() {
|
|||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
mouseX: 0,
|
pointerX: 0,
|
||||||
mouseY: 0,
|
pointerY: 0,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -411,12 +433,12 @@ export default function Canvas() {
|
|||||||
const theme = localStorage.getItem("theme");
|
const theme = localStorage.getItem("theme");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-grow h-full" id="canvas">
|
<div className="flex-grow h-full touch-none" id="canvas">
|
||||||
<div ref={canvas} className="w-full h-full">
|
<div ref={canvas} className="w-full h-full">
|
||||||
<svg
|
<svg
|
||||||
onMouseMove={handleMouseMove}
|
onPointerMove={handlePointerMove}
|
||||||
onMouseDown={handleMouseDown}
|
onPointerDown={handlePointerDown}
|
||||||
onMouseUp={handleMouseUp}
|
onPointerUp={handlePointerUp}
|
||||||
className="w-full h-full"
|
className="w-full h-full"
|
||||||
style={{
|
style={{
|
||||||
cursor: cursor,
|
cursor: cursor,
|
||||||
@ -464,8 +486,8 @@ export default function Canvas() {
|
|||||||
<Area
|
<Area
|
||||||
key={a.id}
|
key={a.id}
|
||||||
data={a}
|
data={a}
|
||||||
onMouseDown={(e) =>
|
onPointerDown={(e) =>
|
||||||
handleMouseDownOnElement(e, a.id, ObjectType.AREA)
|
handlePointerDownOnElement(e, a.id, ObjectType.AREA)
|
||||||
}
|
}
|
||||||
setResize={setAreaResize}
|
setResize={setAreaResize}
|
||||||
setInitCoords={setInitCoords}
|
setInitCoords={setInitCoords}
|
||||||
@ -481,8 +503,8 @@ export default function Canvas() {
|
|||||||
setHoveredTable={setHoveredTable}
|
setHoveredTable={setHoveredTable}
|
||||||
handleGripField={handleGripField}
|
handleGripField={handleGripField}
|
||||||
setLinkingLine={setLinkingLine}
|
setLinkingLine={setLinkingLine}
|
||||||
onMouseDown={(e) =>
|
onPointerDown={(e) =>
|
||||||
handleMouseDownOnElement(e, table.id, ObjectType.TABLE)
|
handlePointerDownOnElement(e, table.id, ObjectType.TABLE)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@ -497,8 +519,8 @@ export default function Canvas() {
|
|||||||
<Note
|
<Note
|
||||||
key={n.id}
|
key={n.id}
|
||||||
data={n}
|
data={n}
|
||||||
onMouseDown={(e) =>
|
onPointerDown={(e) =>
|
||||||
handleMouseDownOnElement(e, n.id, ObjectType.NOTE)
|
handlePointerDownOnElement(e, n.id, ObjectType.NOTE)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
} from "../../hooks";
|
} from "../../hooks";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export default function Note({ data, onMouseDown }) {
|
export default function Note({ data, onPointerDown }) {
|
||||||
const w = 180;
|
const w = 180;
|
||||||
const r = 3;
|
const r = 3;
|
||||||
const fold = 24;
|
const fold = 24;
|
||||||
@ -83,8 +83,8 @@ export default function Note({ data, onMouseDown }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<g
|
<g
|
||||||
onMouseEnter={() => setHovered(true)}
|
onPointerEnter={(e) => e.isPrimary && setHovered(true)}
|
||||||
onMouseLeave={() => setHovered(false)}
|
onPointerLeave={(e) => e.isPrimary && setHovered(false)}
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d={`M${data.x + fold} ${data.y} L${data.x + w - r} ${
|
d={`M${data.x + fold} ${data.y} L${data.x + w - r} ${
|
||||||
@ -133,7 +133,7 @@ export default function Note({ data, onMouseDown }) {
|
|||||||
y={data.y}
|
y={data.y}
|
||||||
width={w}
|
width={w}
|
||||||
height={data.height}
|
height={data.height}
|
||||||
onMouseDown={onMouseDown}
|
onPointerDown={onPointerDown}
|
||||||
>
|
>
|
||||||
<div className="text-gray-900 select-none w-full h-full cursor-move px-3 py-2">
|
<div className="text-gray-900 select-none w-full h-full cursor-move px-3 py-2">
|
||||||
<div className="flex justify-between gap-1 w-full">
|
<div className="flex justify-between gap-1 w-full">
|
||||||
|
@ -22,7 +22,7 @@ export default function Table(props) {
|
|||||||
const [hoveredField, setHoveredField] = useState(-1);
|
const [hoveredField, setHoveredField] = useState(-1);
|
||||||
const {
|
const {
|
||||||
tableData,
|
tableData,
|
||||||
onMouseDown,
|
onPointerDown,
|
||||||
setHoveredTable,
|
setHoveredTable,
|
||||||
handleGripField,
|
handleGripField,
|
||||||
setLinkingLine,
|
setLinkingLine,
|
||||||
@ -67,7 +67,7 @@ export default function Table(props) {
|
|||||||
width={settings.tableWidth}
|
width={settings.tableWidth}
|
||||||
height={height}
|
height={height}
|
||||||
className="group drop-shadow-lg rounded-md cursor-move"
|
className="group drop-shadow-lg rounded-md cursor-move"
|
||||||
onMouseDown={onMouseDown}
|
onPointerDown={onPointerDown}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
onDoubleClick={openEditor}
|
onDoubleClick={openEditor}
|
||||||
@ -266,14 +266,18 @@ export default function Table(props) {
|
|||||||
? ""
|
? ""
|
||||||
: "border-b border-gray-400"
|
: "border-b border-gray-400"
|
||||||
} group h-[36px] px-2 py-1 flex justify-between items-center gap-1 w-full overflow-hidden`}
|
} group h-[36px] px-2 py-1 flex justify-between items-center gap-1 w-full overflow-hidden`}
|
||||||
onMouseEnter={() => {
|
onPointerEnter={(e) => {
|
||||||
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
setHoveredField(index);
|
setHoveredField(index);
|
||||||
setHoveredTable({
|
setHoveredTable({
|
||||||
tableId: tableData.id,
|
tableId: tableData.id,
|
||||||
field: index,
|
field: index,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onMouseLeave={() => {
|
onPointerLeave={(e) => {
|
||||||
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
setHoveredField(-1);
|
setHoveredField(-1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -284,7 +288,9 @@ export default function Table(props) {
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="flex-shrink-0 w-[10px] h-[10px] bg-[#2f68adcc] rounded-full"
|
className="flex-shrink-0 w-[10px] h-[10px] bg-[#2f68adcc] rounded-full"
|
||||||
onMouseDown={() => {
|
onPointerDown={(e) => {
|
||||||
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
handleGripField(index);
|
handleGripField(index);
|
||||||
setLinkingLine((prev) => ({
|
setLinkingLine((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
@ -1526,8 +1526,8 @@ export default function ControlPanel({
|
|||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className="text-xl me-1"
|
className="text-xl me-1"
|
||||||
onMouseEnter={() => setShowEditName(true)}
|
onPointerEnter={(e) => e.isPrimary && setShowEditName(true)}
|
||||||
onMouseLeave={() => setShowEditName(false)}
|
onPointerLeave={(e) => e.isPrimary && setShowEditName(false)}
|
||||||
onClick={() => setModal(MODAL.RENAME)}
|
onClick={() => setModal(MODAL.RENAME)}
|
||||||
>
|
>
|
||||||
{window.name.split(" ")[0] === "t" ? "Templates/" : "Diagrams/"}
|
{window.name.split(" ")[0] === "t" ? "Templates/" : "Diagrams/"}
|
||||||
|
@ -83,7 +83,7 @@ export default function SidePanel({ width, resize, setResize }) {
|
|||||||
className={`flex justify-center items-center p-1 h-auto hover-2 cursor-col-resize ${
|
className={`flex justify-center items-center p-1 h-auto hover-2 cursor-col-resize ${
|
||||||
resize && "bg-semi-grey-2"
|
resize && "bg-semi-grey-2"
|
||||||
}`}
|
}`}
|
||||||
onMouseDown={() => setResize(true)}
|
onPointerDown={(e) => e.isPrimary && setResize(true)}
|
||||||
>
|
>
|
||||||
<div className="w-1 border-x border-color h-1/6" />
|
<div className="w-1 border-x border-color h-1/6" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,9 +24,9 @@ function Table({ table, grab }) {
|
|||||||
width={tableWidth}
|
width={tableWidth}
|
||||||
height={height}
|
height={height}
|
||||||
className="drop-shadow-lg rounded-md cursor-move"
|
className="drop-shadow-lg rounded-md cursor-move"
|
||||||
onMouseDown={grab}
|
onPointerDown={(e) => e.isPrimary && grab(e)}
|
||||||
onMouseEnter={() => setIsHovered(true)}
|
onPointerEnter={(e) => e.isPrimary && setIsHovered(true)}
|
||||||
onMouseLeave={() => setIsHovered(false)}
|
onPointerLeave={(e) => e.isPrimary && setIsHovered(false)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`border-2 ${
|
className={`border-2 ${
|
||||||
@ -46,8 +46,8 @@ function Table({ table, grab }) {
|
|||||||
className={`${
|
className={`${
|
||||||
i === table.fields.length - 1 ? "" : "border-b border-gray-400"
|
i === table.fields.length - 1 ? "" : "border-b border-gray-400"
|
||||||
} h-[36px] px-2 py-1 flex justify-between`}
|
} h-[36px] px-2 py-1 flex justify-between`}
|
||||||
onMouseEnter={() => setHoveredField(i)}
|
onPointerEnter={(e) => e.isPrimary && setHoveredField(i)}
|
||||||
onMouseLeave={() => setHoveredField(-1)}
|
onPointerLeave={(e) => e.isPrimary && setHoveredField(-1)}
|
||||||
>
|
>
|
||||||
<div className={hoveredField === i ? "text-zinc-500" : ""}>
|
<div className={hoveredField === i ? "text-zinc-500" : ""}>
|
||||||
<button
|
<button
|
||||||
@ -185,9 +185,9 @@ export default function SimpleCanvas({ diagram, zoom }) {
|
|||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
className="w-full h-full cursor-grab"
|
className="w-full h-full cursor-grab"
|
||||||
onMouseUp={releaseTable}
|
onPointerUp={(e) => e.isPrimary && releaseTable()}
|
||||||
onMouseMove={moveTable}
|
onPointerMove={(e) => e.isPrimary && moveTable()}
|
||||||
onMouseLeave={releaseTable}
|
onPointerLeave={(e) => e.isPrimary && releaseTable()}
|
||||||
>
|
>
|
||||||
<defs>
|
<defs>
|
||||||
<pattern
|
<pattern
|
||||||
|
@ -349,9 +349,9 @@ export default function WorkSpace() {
|
|||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="flex h-full overflow-y-auto"
|
className="flex h-full overflow-y-auto"
|
||||||
onMouseUp={() => setResize(false)}
|
onPointerUp={(e) => e.isPrimary && setResize(false)}
|
||||||
onMouseLeave={() => setResize(false)}
|
onPointerLeave={(e) => e.isPrimary && setResize(false)}
|
||||||
onMouseMove={handleResize}
|
onPointerMove={(e) => e.isPrimary && handleResize(e)}
|
||||||
>
|
>
|
||||||
{layout.sidebar && (
|
{layout.sidebar && (
|
||||||
<SidePanel resize={resize} setResize={setResize} width={width} />
|
<SidePanel resize={resize} setResize={setResize} width={width} />
|
||||||
|
Loading…
Reference in New Issue
Block a user