@tsdraw/react 0.9.3 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +144 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +145 -14
- package/dist/index.js.map +1 -1
- package/dist/tsdraw.css +32 -10
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -10,6 +10,7 @@ function SelectionOverlay({
|
|
|
10
10
|
selectionBrush,
|
|
11
11
|
selectionBounds,
|
|
12
12
|
selectionRotationDeg,
|
|
13
|
+
vertexHandleScreenPositions,
|
|
13
14
|
currentTool,
|
|
14
15
|
selectedCount,
|
|
15
16
|
onRotatePointerDown,
|
|
@@ -37,7 +38,8 @@ function SelectionOverlay({
|
|
|
37
38
|
top: selectionBounds.top,
|
|
38
39
|
width: selectionBounds.width,
|
|
39
40
|
height: selectionBounds.height,
|
|
40
|
-
transform: `rotate(${selectionRotationDeg}deg)
|
|
41
|
+
transform: `rotate(${selectionRotationDeg}deg)`,
|
|
42
|
+
transformOrigin: "center center"
|
|
41
43
|
},
|
|
42
44
|
children: [
|
|
43
45
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "tsdraw-selection-bounds" }),
|
|
@@ -95,7 +97,15 @@ function SelectionOverlay({
|
|
|
95
97
|
] })
|
|
96
98
|
]
|
|
97
99
|
}
|
|
98
|
-
)
|
|
100
|
+
),
|
|
101
|
+
currentTool === "select" && vertexHandleScreenPositions.map((pos, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
102
|
+
"div",
|
|
103
|
+
{
|
|
104
|
+
className: "tsdraw-vertex-handle",
|
|
105
|
+
style: { position: "absolute", left: pos.left, top: pos.top, transform: "translate(-50%, -50%)", pointerEvents: "none", zIndex: 95 }
|
|
106
|
+
},
|
|
107
|
+
`vertex-${index.toString()}`
|
|
108
|
+
))
|
|
99
109
|
] });
|
|
100
110
|
}
|
|
101
111
|
function parseAnchor(anchor) {
|
|
@@ -454,6 +464,7 @@ function getCanvasCursor(currentTool, state) {
|
|
|
454
464
|
if (state.isRotatingSelection) return "grabbing";
|
|
455
465
|
if (state.isResizingSelection) return "nwse-resize";
|
|
456
466
|
if (state.isMovingSelection) return "grabbing";
|
|
467
|
+
if (state.isDraggingVertex) return "grabbing";
|
|
457
468
|
if (state.isHoveringSelectionBounds) return "move";
|
|
458
469
|
return "default";
|
|
459
470
|
}
|
|
@@ -896,6 +907,16 @@ function toScreenRect(editor, bounds) {
|
|
|
896
907
|
height: Math.max(0, maxY - minY)
|
|
897
908
|
};
|
|
898
909
|
}
|
|
910
|
+
function selectionCenteredOnRotation(editor, startBoundsPage, centerPage) {
|
|
911
|
+
const startScreen = toScreenRect(editor, startBoundsPage);
|
|
912
|
+
const centerScreen = core.pageToScreen(editor.viewport, centerPage.x, centerPage.y);
|
|
913
|
+
return {
|
|
914
|
+
left: centerScreen.x - startScreen.width / 2,
|
|
915
|
+
top: centerScreen.y - startScreen.height / 2,
|
|
916
|
+
width: startScreen.width,
|
|
917
|
+
height: startScreen.height
|
|
918
|
+
};
|
|
919
|
+
}
|
|
899
920
|
function resolveDrawColor(colorStyle, theme) {
|
|
900
921
|
return core.resolveThemeColor(colorStyle, theme);
|
|
901
922
|
}
|
|
@@ -911,6 +932,11 @@ function getHandlePagePoint(bounds, handle) {
|
|
|
911
932
|
return { x: bounds.maxX, y: bounds.maxY };
|
|
912
933
|
}
|
|
913
934
|
}
|
|
935
|
+
function resolveAutoShapeOption(input) {
|
|
936
|
+
if (input === false) return { enabled: false };
|
|
937
|
+
if (input === true || input == null) return { enabled: true };
|
|
938
|
+
return { enabled: input.enabled ?? true, ...input };
|
|
939
|
+
}
|
|
914
940
|
var ZOOM_WHEEL_CAP = 10;
|
|
915
941
|
var VIEW_ONLY_TOOLS = /* @__PURE__ */ new Set(["select", "hand"]);
|
|
916
942
|
function useTsdrawCanvasController(options = {}) {
|
|
@@ -922,6 +948,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
922
948
|
const touchOptionsRef = react.useRef(options.touchOptions);
|
|
923
949
|
const keyboardShortcutsRef = react.useRef(options.keyboardShortcuts);
|
|
924
950
|
const penOptionsRef = react.useRef(options.penOptions);
|
|
951
|
+
const autoShapeRef = react.useRef(options.autoShape);
|
|
925
952
|
const backgroundRef = react.useRef(options.background);
|
|
926
953
|
const readOnlyRef = react.useRef(options.readOnly ?? false);
|
|
927
954
|
const containerRef = react.useRef(null);
|
|
@@ -950,7 +977,8 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
950
977
|
center: null,
|
|
951
978
|
startAngle: 0,
|
|
952
979
|
startSelectionRotationDeg: 0,
|
|
953
|
-
startShapes: /* @__PURE__ */ new Map()
|
|
980
|
+
startShapes: /* @__PURE__ */ new Map(),
|
|
981
|
+
startBoundsPage: null
|
|
954
982
|
});
|
|
955
983
|
const selectDragRef = react.useRef({
|
|
956
984
|
mode: "none",
|
|
@@ -972,6 +1000,8 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
972
1000
|
const [isMovingSelection, setIsMovingSelection] = react.useState(false);
|
|
973
1001
|
const [isResizingSelection, setIsResizingSelection] = react.useState(false);
|
|
974
1002
|
const [isRotatingSelection, setIsRotatingSelection] = react.useState(false);
|
|
1003
|
+
const [isDraggingVertex, setIsDraggingVertex] = react.useState(false);
|
|
1004
|
+
const [vertexHandleScreenPositions, setVertexHandleScreenPositions] = react.useState([]);
|
|
975
1005
|
const [canUndo, setCanUndo] = react.useState(false);
|
|
976
1006
|
const [canRedo, setCanRedo] = react.useState(false);
|
|
977
1007
|
const [isPersistenceReady, setIsPersistenceReady] = react.useState(!options.persistenceKey);
|
|
@@ -1004,6 +1034,11 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1004
1034
|
react.useEffect(() => {
|
|
1005
1035
|
penOptionsRef.current = options.penOptions;
|
|
1006
1036
|
}, [options.penOptions]);
|
|
1037
|
+
react.useEffect(() => {
|
|
1038
|
+
autoShapeRef.current = options.autoShape;
|
|
1039
|
+
const editor = editorRef.current;
|
|
1040
|
+
if (editor) editor.setAutoShape(resolveAutoShapeOption(options.autoShape));
|
|
1041
|
+
}, [options.autoShape]);
|
|
1007
1042
|
react.useEffect(() => {
|
|
1008
1043
|
backgroundRef.current = options.background;
|
|
1009
1044
|
}, [options.background]);
|
|
@@ -1060,9 +1095,12 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1060
1095
|
setIsMovingSelection(false);
|
|
1061
1096
|
setIsResizingSelection(false);
|
|
1062
1097
|
setIsRotatingSelection(false);
|
|
1098
|
+
setIsDraggingVertex(false);
|
|
1063
1099
|
selectDragRef.current.mode = "none";
|
|
1100
|
+
selectDragRef.current.vertexRefs = void 0;
|
|
1101
|
+
selectDragRef.current.vertexSnapshots = void 0;
|
|
1064
1102
|
resizeRef.current = { handle: null, startBounds: null, startShapes: /* @__PURE__ */ new Map(), cursorHandleOffset: { x: 0, y: 0 } };
|
|
1065
|
-
rotateRef.current = { center: null, startAngle: 0, startSelectionRotationDeg: 0, startShapes: /* @__PURE__ */ new Map() };
|
|
1103
|
+
rotateRef.current = { center: null, startAngle: 0, startSelectionRotationDeg: 0, startShapes: /* @__PURE__ */ new Map(), startBoundsPage: null };
|
|
1066
1104
|
}, []);
|
|
1067
1105
|
const handleResizePointerDown = react.useCallback(
|
|
1068
1106
|
(e, handle) => {
|
|
@@ -1116,8 +1154,10 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1116
1154
|
center,
|
|
1117
1155
|
startAngle: Math.atan2(p.y - center.y, p.x - center.x),
|
|
1118
1156
|
startSelectionRotationDeg: selectionRotationRef.current,
|
|
1119
|
-
startShapes: core.buildTransformSnapshots(editor, selectedShapeIdsRef.current)
|
|
1157
|
+
startShapes: core.buildTransformSnapshots(editor, selectedShapeIdsRef.current),
|
|
1158
|
+
startBoundsPage: bounds
|
|
1120
1159
|
};
|
|
1160
|
+
setSelectionBounds(selectionCenteredOnRotation(editor, bounds, center));
|
|
1121
1161
|
isPointerActiveRef.current = true;
|
|
1122
1162
|
activePointerIdsRef.current.add(e.pointerId);
|
|
1123
1163
|
canvas.setPointerCapture(e.pointerId);
|
|
@@ -1142,7 +1182,8 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1142
1182
|
const editor = new core.Editor({
|
|
1143
1183
|
toolDefinitions: options.toolDefinitions,
|
|
1144
1184
|
initialToolId: initialTool,
|
|
1145
|
-
zoomRange: cameraOpts?.zoomRange
|
|
1185
|
+
zoomRange: cameraOpts?.zoomRange,
|
|
1186
|
+
autoShape: resolveAutoShapeOption(autoShapeRef.current)
|
|
1146
1187
|
});
|
|
1147
1188
|
editor.renderer.setTheme(options.theme ?? "light");
|
|
1148
1189
|
if (!editor.tools.hasTool(initialTool)) {
|
|
@@ -1382,6 +1423,30 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1382
1423
|
const pressure = (first.pressure ?? 0.5) * pressureSensitivity;
|
|
1383
1424
|
const isPen = first.pointerType === "pen" || hasRealPressure(first.pressure);
|
|
1384
1425
|
if (currentToolRef.current === "select") {
|
|
1426
|
+
if (!readOnlyRef.current) {
|
|
1427
|
+
const zoom = editor.viewport.zoom;
|
|
1428
|
+
const marginPage = 12 / zoom;
|
|
1429
|
+
const clusterTolerance = 20 / zoom;
|
|
1430
|
+
const vertexHit = core.findVertexHit(editor, { x, y }, marginPage, clusterTolerance);
|
|
1431
|
+
if (vertexHit) {
|
|
1432
|
+
const involvedIds = [...new Set(vertexHit.refs.map((r) => r.shapeId))];
|
|
1433
|
+
selectDragRef.current = {
|
|
1434
|
+
mode: "vertex",
|
|
1435
|
+
startPage: { x, y },
|
|
1436
|
+
currentPage: { x, y },
|
|
1437
|
+
startPositions: /* @__PURE__ */ new Map(),
|
|
1438
|
+
additive: false,
|
|
1439
|
+
initialSelection: [...selectedShapeIdsRef.current],
|
|
1440
|
+
vertexRefs: vertexHit.refs,
|
|
1441
|
+
vertexSnapshots: vertexHit.snapshots
|
|
1442
|
+
};
|
|
1443
|
+
setIsDraggingVertex(true);
|
|
1444
|
+
setSelectedShapeIds(involvedIds);
|
|
1445
|
+
selectedShapeIdsRef.current = involvedIds;
|
|
1446
|
+
refreshSelectionBounds(editor, involvedIds);
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1385
1450
|
const hit = core.getTopShapeAtPoint(editor, { x, y });
|
|
1386
1451
|
const isHitSelected = !!(hit && selectedShapeIdsRef.current.includes(hit.id));
|
|
1387
1452
|
const isInsideSelectionBounds = (() => {
|
|
@@ -1397,7 +1462,8 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1397
1462
|
currentPage: { x, y },
|
|
1398
1463
|
startPositions: core.buildStartPositions(editor, selectedShapeIdsRef.current),
|
|
1399
1464
|
additive: false,
|
|
1400
|
-
initialSelection: [...selectedShapeIdsRef.current]
|
|
1465
|
+
initialSelection: [...selectedShapeIdsRef.current],
|
|
1466
|
+
moveFromEmptyInsideBounds: isInsideSelectionBounds && !hit
|
|
1401
1467
|
};
|
|
1402
1468
|
setIsMovingSelection(true);
|
|
1403
1469
|
return;
|
|
@@ -1453,13 +1519,14 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1453
1519
|
const mode = selectDragRef.current.mode;
|
|
1454
1520
|
const { x: px, y: py } = editor.input.getCurrentPagePoint();
|
|
1455
1521
|
if (mode === "rotate") {
|
|
1456
|
-
const { center, startAngle, startSelectionRotationDeg, startShapes } = rotateRef.current;
|
|
1457
|
-
if (!center) return;
|
|
1522
|
+
const { center, startAngle, startSelectionRotationDeg, startShapes, startBoundsPage } = rotateRef.current;
|
|
1523
|
+
if (!center || !startBoundsPage) return;
|
|
1458
1524
|
const angle = Math.atan2(py - center.y, px - center.x);
|
|
1459
1525
|
const delta = angle - startAngle;
|
|
1460
1526
|
setSelectionRotationDeg(startSelectionRotationDeg + delta * 180 / Math.PI);
|
|
1461
1527
|
core.applyRotation(editor, startShapes, center, delta);
|
|
1462
1528
|
render();
|
|
1529
|
+
setSelectionBounds(selectionCenteredOnRotation(editor, startBoundsPage, center));
|
|
1463
1530
|
return;
|
|
1464
1531
|
}
|
|
1465
1532
|
if (mode === "resize") {
|
|
@@ -1477,6 +1544,20 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1477
1544
|
refreshSelectionBounds(editor);
|
|
1478
1545
|
return;
|
|
1479
1546
|
}
|
|
1547
|
+
if (mode === "vertex") {
|
|
1548
|
+
const drag = selectDragRef.current;
|
|
1549
|
+
const refs = drag.vertexRefs;
|
|
1550
|
+
const snapshots = drag.vertexSnapshots;
|
|
1551
|
+
if (refs && snapshots) {
|
|
1552
|
+
core.applyVertexDrag(editor, snapshots, refs, {
|
|
1553
|
+
x: px - drag.startPage.x,
|
|
1554
|
+
y: py - drag.startPage.y
|
|
1555
|
+
});
|
|
1556
|
+
render();
|
|
1557
|
+
refreshSelectionBounds(editor);
|
|
1558
|
+
}
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1480
1561
|
if (mode === "marquee") {
|
|
1481
1562
|
selectDragRef.current.currentPage = { x: px, y: py };
|
|
1482
1563
|
const pageRect = core.normalizeSelectionBounds(selectDragRef.current.startPage, selectDragRef.current.currentPage);
|
|
@@ -1514,7 +1595,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1514
1595
|
setIsRotatingSelection(false);
|
|
1515
1596
|
selectDragRef.current.mode = "none";
|
|
1516
1597
|
setSelectionRotationDeg(0);
|
|
1517
|
-
rotateRef.current = { center: null, startAngle: 0, startSelectionRotationDeg: 0, startShapes: /* @__PURE__ */ new Map() };
|
|
1598
|
+
rotateRef.current = { center: null, startAngle: 0, startSelectionRotationDeg: 0, startShapes: /* @__PURE__ */ new Map(), startBoundsPage: null };
|
|
1518
1599
|
render();
|
|
1519
1600
|
refreshSelectionBounds(editor);
|
|
1520
1601
|
editor.endHistoryEntry();
|
|
@@ -1532,6 +1613,24 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1532
1613
|
if (drag.mode === "move") {
|
|
1533
1614
|
setIsMovingSelection(false);
|
|
1534
1615
|
selectDragRef.current.mode = "none";
|
|
1616
|
+
const distSq = (x - drag.startPage.x) ** 2 + (y - drag.startPage.y) ** 2;
|
|
1617
|
+
if (drag.moveFromEmptyInsideBounds && distSq < 4) {
|
|
1618
|
+
setSelectedShapeIds([]);
|
|
1619
|
+
selectedShapeIdsRef.current = [];
|
|
1620
|
+
setSelectionBounds(null);
|
|
1621
|
+
} else {
|
|
1622
|
+
refreshSelectionBounds(editor);
|
|
1623
|
+
}
|
|
1624
|
+
selectDragRef.current.moveFromEmptyInsideBounds = void 0;
|
|
1625
|
+
render();
|
|
1626
|
+
editor.endHistoryEntry();
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
if (drag.mode === "vertex") {
|
|
1630
|
+
setIsDraggingVertex(false);
|
|
1631
|
+
selectDragRef.current.mode = "none";
|
|
1632
|
+
selectDragRef.current.vertexRefs = void 0;
|
|
1633
|
+
selectDragRef.current.vertexSnapshots = void 0;
|
|
1535
1634
|
render();
|
|
1536
1635
|
refreshSelectionBounds(editor);
|
|
1537
1636
|
editor.endHistoryEntry();
|
|
@@ -1610,9 +1709,21 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1610
1709
|
editor.input.pointerUp();
|
|
1611
1710
|
if (currentToolRef.current === "select") {
|
|
1612
1711
|
const drag = selectDragRef.current;
|
|
1613
|
-
if (drag.mode === "rotate")
|
|
1712
|
+
if (drag.mode === "rotate") {
|
|
1713
|
+
setIsRotatingSelection(false);
|
|
1714
|
+
setSelectionRotationDeg(0);
|
|
1715
|
+
rotateRef.current = { center: null, startAngle: 0, startSelectionRotationDeg: 0, startShapes: /* @__PURE__ */ new Map(), startBoundsPage: null };
|
|
1716
|
+
}
|
|
1614
1717
|
if (drag.mode === "resize") setIsResizingSelection(false);
|
|
1615
|
-
if (drag.mode === "move")
|
|
1718
|
+
if (drag.mode === "move") {
|
|
1719
|
+
setIsMovingSelection(false);
|
|
1720
|
+
selectDragRef.current.moveFromEmptyInsideBounds = void 0;
|
|
1721
|
+
}
|
|
1722
|
+
if (drag.mode === "vertex") {
|
|
1723
|
+
setIsDraggingVertex(false);
|
|
1724
|
+
selectDragRef.current.vertexRefs = void 0;
|
|
1725
|
+
selectDragRef.current.vertexSnapshots = void 0;
|
|
1726
|
+
}
|
|
1616
1727
|
if (drag.mode === "marquee") setSelectionBrush(null);
|
|
1617
1728
|
if (drag.mode !== "none") {
|
|
1618
1729
|
selectDragRef.current.mode = "none";
|
|
@@ -1949,10 +2060,25 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1949
2060
|
}, [render]);
|
|
1950
2061
|
const isHoveringSelectionBounds = isPointerInsideCanvas && currentTool === "select" && selectedShapeIds.length > 0 && selectionBounds != null && pointerScreenPoint.x >= selectionBounds.left && pointerScreenPoint.x <= selectionBounds.left + selectionBounds.width && pointerScreenPoint.y >= selectionBounds.top && pointerScreenPoint.y <= selectionBounds.top + selectionBounds.height;
|
|
1951
2062
|
const showToolOverlay = isPointerInsideCanvas && (currentTool === "pen" || currentTool === "eraser");
|
|
2063
|
+
react.useEffect(() => {
|
|
2064
|
+
const editor = editorRef.current;
|
|
2065
|
+
if (!editor || currentTool !== "select" || selectedShapeIds.length === 0) {
|
|
2066
|
+
setVertexHandleScreenPositions([]);
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
const pagePts = core.getVertexHandlePagePositions(editor, selectedShapeIds);
|
|
2070
|
+
setVertexHandleScreenPositions(
|
|
2071
|
+
pagePts.map((pg) => {
|
|
2072
|
+
const s = core.pageToScreen(editor.viewport, pg.x, pg.y);
|
|
2073
|
+
return { left: s.x, top: s.y };
|
|
2074
|
+
})
|
|
2075
|
+
);
|
|
2076
|
+
}, [currentTool, selectedShapeIds, selectionBounds, selectionRotationDeg, isPersistenceReady]);
|
|
1952
2077
|
const canvasCursor = getCanvasCursor(currentTool, {
|
|
1953
2078
|
isMovingSelection,
|
|
1954
2079
|
isResizingSelection,
|
|
1955
2080
|
isRotatingSelection,
|
|
2081
|
+
isDraggingVertex,
|
|
1956
2082
|
isHoveringSelectionBounds,
|
|
1957
2083
|
showToolOverlay
|
|
1958
2084
|
});
|
|
@@ -1962,7 +2088,8 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1962
2088
|
showToolOverlay,
|
|
1963
2089
|
isMovingSelection,
|
|
1964
2090
|
isResizingSelection,
|
|
1965
|
-
isRotatingSelection
|
|
2091
|
+
isRotatingSelection,
|
|
2092
|
+
isDraggingVertex
|
|
1966
2093
|
};
|
|
1967
2094
|
const toolOverlay = {
|
|
1968
2095
|
visible: showToolOverlay,
|
|
@@ -1985,6 +2112,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1985
2112
|
selectionBrush,
|
|
1986
2113
|
selectionBounds,
|
|
1987
2114
|
selectionRotationDeg,
|
|
2115
|
+
vertexHandleScreenPositions,
|
|
1988
2116
|
canvasCursor,
|
|
1989
2117
|
cursorContext,
|
|
1990
2118
|
toolOverlay,
|
|
@@ -2095,6 +2223,7 @@ function Tsdraw(props) {
|
|
|
2095
2223
|
selectionBrush,
|
|
2096
2224
|
selectionBounds,
|
|
2097
2225
|
selectionRotationDeg,
|
|
2226
|
+
vertexHandleScreenPositions,
|
|
2098
2227
|
canvasCursor: defaultCanvasCursor,
|
|
2099
2228
|
cursorContext,
|
|
2100
2229
|
toolOverlay,
|
|
@@ -2117,6 +2246,7 @@ function Tsdraw(props) {
|
|
|
2117
2246
|
touchOptions: props.touchOptions,
|
|
2118
2247
|
keyboardShortcuts: props.keyboardShortcuts,
|
|
2119
2248
|
penOptions: props.penOptions,
|
|
2249
|
+
autoShape: props.autoShape,
|
|
2120
2250
|
background: props.background,
|
|
2121
2251
|
readOnly: props.readOnly,
|
|
2122
2252
|
autoFocus: props.autoFocus,
|
|
@@ -2275,6 +2405,7 @@ function Tsdraw(props) {
|
|
|
2275
2405
|
selectionBrush,
|
|
2276
2406
|
selectionBounds,
|
|
2277
2407
|
selectionRotationDeg,
|
|
2408
|
+
vertexHandleScreenPositions,
|
|
2278
2409
|
currentTool,
|
|
2279
2410
|
selectedCount: selectedShapeIds.length,
|
|
2280
2411
|
onRotatePointerDown: handleRotatePointerDown,
|