f1ow 0.1.5 → 1.0.0
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/components/Canvas/AnnotationsOverlay.d.ts +34 -0
- package/dist/components/shapes/TextLabel.d.ts +16 -0
- package/dist/f1ow.js +881 -419
- package/dist/f1ow.umd.cjs +880 -418
- package/dist/lib/FlowCanvasProps.d.ts +37 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/utils/camera.d.ts +1 -1
- package/dist/utils/connection.d.ts +26 -1
- package/dist/utils/dragSync.d.ts +50 -0
- package/dist/utils/labelMetrics.d.ts +49 -0
- package/package.json +107 -99
package/dist/f1ow.umd.cjs
CHANGED
|
@@ -886,6 +886,58 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
886
886
|
result.push(points[points.length - 2], points[points.length - 1]);
|
|
887
887
|
return result;
|
|
888
888
|
}
|
|
889
|
+
const CURVE_RATIO = 0.2;
|
|
890
|
+
function computeCurveControlPoint(start, end, ratio = CURVE_RATIO) {
|
|
891
|
+
const mx = (start.x + end.x) / 2;
|
|
892
|
+
const my = (start.y + end.y) / 2;
|
|
893
|
+
const dx = end.x - start.x;
|
|
894
|
+
const dy = end.y - start.y;
|
|
895
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
896
|
+
if (len2 === 0) return { x: mx, y: my };
|
|
897
|
+
const nx = -dy / len2;
|
|
898
|
+
const ny = dx / len2;
|
|
899
|
+
const offset = len2 * ratio;
|
|
900
|
+
return { x: mx + nx * offset, y: my + ny * offset };
|
|
901
|
+
}
|
|
902
|
+
function quadBezierAt(p0, cp, p2, t) {
|
|
903
|
+
const mt = 1 - t;
|
|
904
|
+
return {
|
|
905
|
+
x: mt * mt * p0.x + 2 * mt * t * cp.x + t * t * p2.x,
|
|
906
|
+
y: mt * mt * p0.y + 2 * mt * t * cp.y + t * t * p2.y
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
function quadBezierTangent(p0, cp, p2, t) {
|
|
910
|
+
const mt = 1 - t;
|
|
911
|
+
return {
|
|
912
|
+
x: 2 * mt * (cp.x - p0.x) + 2 * t * (p2.x - cp.x),
|
|
913
|
+
y: 2 * mt * (cp.y - p0.y) + 2 * t * (p2.y - cp.y)
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
function curveArrowPrev(start, cp, end, atEnd) {
|
|
917
|
+
if (atEnd) {
|
|
918
|
+
const tan = quadBezierTangent(start, cp, end, 1);
|
|
919
|
+
const len2 = Math.sqrt(tan.x * tan.x + tan.y * tan.y) || 1;
|
|
920
|
+
return { x: end.x - tan.x / len2 * 20, y: end.y - tan.y / len2 * 20 };
|
|
921
|
+
} else {
|
|
922
|
+
const tan = quadBezierTangent(start, cp, end, 0);
|
|
923
|
+
const len2 = Math.sqrt(tan.x * tan.x + tan.y * tan.y) || 1;
|
|
924
|
+
return { x: start.x + tan.x / len2 * 20, y: start.y + tan.y / len2 * 20 };
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
function curvatureFromDragPoint(start, end, dragWorld) {
|
|
928
|
+
const dx = end.x - start.x;
|
|
929
|
+
const dy = end.y - start.y;
|
|
930
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
931
|
+
if (len2 === 0) return CURVE_RATIO;
|
|
932
|
+
const nx = -dy / len2;
|
|
933
|
+
const ny = dx / len2;
|
|
934
|
+
const mx = (start.x + end.x) / 2;
|
|
935
|
+
const my = (start.y + end.y) / 2;
|
|
936
|
+
const vx = dragWorld.x - mx;
|
|
937
|
+
const vy = dragWorld.y - my;
|
|
938
|
+
const projDist = vx * nx + vy * ny;
|
|
939
|
+
return 2 * projDist / len2;
|
|
940
|
+
}
|
|
889
941
|
const CONNECTABLE_TYPES = /* @__PURE__ */ new Set(["rectangle", "ellipse", "diamond", "text", "image"]);
|
|
890
942
|
function isConnectable(el) {
|
|
891
943
|
return CONNECTABLE_TYPES.has(el.type);
|
|
@@ -1312,6 +1364,71 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
1312
1364
|
}
|
|
1313
1365
|
}
|
|
1314
1366
|
}
|
|
1367
|
+
function computeConnectorLabelPosition(connector, textWidth, textHeight) {
|
|
1368
|
+
const pts = connector.points;
|
|
1369
|
+
const startPt = { x: pts[0], y: pts[1] };
|
|
1370
|
+
const endPt = { x: pts[pts.length - 2], y: pts[pts.length - 1] };
|
|
1371
|
+
let midX;
|
|
1372
|
+
let midY;
|
|
1373
|
+
if (connector.lineType === "curved") {
|
|
1374
|
+
const curvature = connector.curvature ?? CURVE_RATIO;
|
|
1375
|
+
const cp = computeCurveControlPoint(startPt, endPt, curvature);
|
|
1376
|
+
const mid = quadBezierAt(startPt, cp, endPt, 0.5);
|
|
1377
|
+
midX = connector.x + mid.x;
|
|
1378
|
+
midY = connector.y + mid.y;
|
|
1379
|
+
} else if (connector.lineType === "elbow" && pts.length >= 4) {
|
|
1380
|
+
const segCount = pts.length / 2 - 1;
|
|
1381
|
+
let totalLen = 0;
|
|
1382
|
+
for (let i = 0; i < segCount; i++) {
|
|
1383
|
+
const dx = pts[(i + 1) * 2] - pts[i * 2];
|
|
1384
|
+
const dy = pts[(i + 1) * 2 + 1] - pts[i * 2 + 1];
|
|
1385
|
+
totalLen += Math.sqrt(dx * dx + dy * dy);
|
|
1386
|
+
}
|
|
1387
|
+
const half = totalLen / 2;
|
|
1388
|
+
let walked = 0;
|
|
1389
|
+
midX = connector.x + (startPt.x + endPt.x) / 2;
|
|
1390
|
+
midY = connector.y + (startPt.y + endPt.y) / 2;
|
|
1391
|
+
for (let i = 0; i < segCount; i++) {
|
|
1392
|
+
const ax = pts[i * 2], ay = pts[i * 2 + 1];
|
|
1393
|
+
const bx = pts[(i + 1) * 2], by = pts[(i + 1) * 2 + 1];
|
|
1394
|
+
const dx = bx - ax, dy = by - ay;
|
|
1395
|
+
const segLen = Math.sqrt(dx * dx + dy * dy);
|
|
1396
|
+
if (walked + segLen >= half && segLen > 0) {
|
|
1397
|
+
const t = (half - walked) / segLen;
|
|
1398
|
+
midX = connector.x + ax + dx * t;
|
|
1399
|
+
midY = connector.y + ay + dy * t;
|
|
1400
|
+
break;
|
|
1401
|
+
}
|
|
1402
|
+
walked += segLen;
|
|
1403
|
+
}
|
|
1404
|
+
} else {
|
|
1405
|
+
midX = connector.x + (startPt.x + endPt.x) / 2;
|
|
1406
|
+
midY = connector.y + (startPt.y + endPt.y) / 2;
|
|
1407
|
+
}
|
|
1408
|
+
return {
|
|
1409
|
+
x: midX - textWidth / 2,
|
|
1410
|
+
y: midY - textHeight / 2
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
function syncConnectorLabels(connectorIds, elMap) {
|
|
1414
|
+
const updates = [];
|
|
1415
|
+
for (const connId of connectorIds) {
|
|
1416
|
+
const conn = elMap.get(connId);
|
|
1417
|
+
if (!conn || conn.type !== "arrow" && conn.type !== "line") continue;
|
|
1418
|
+
if (!conn.boundElements) continue;
|
|
1419
|
+
const connector = conn;
|
|
1420
|
+
for (const be of conn.boundElements) {
|
|
1421
|
+
if (be.type !== "text") continue;
|
|
1422
|
+
const txt = elMap.get(be.id);
|
|
1423
|
+
if (!txt) continue;
|
|
1424
|
+
const textW = Math.max(10, txt.width || 60);
|
|
1425
|
+
const textH = txt.height || 30;
|
|
1426
|
+
const pos = computeConnectorLabelPosition(connector, textW, textH);
|
|
1427
|
+
updates.push({ id: txt.id, updates: { x: pos.x, y: pos.y } });
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
return updates;
|
|
1431
|
+
}
|
|
1315
1432
|
const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
1316
1433
|
let nanoid = (size = 21) => {
|
|
1317
1434
|
let id = "";
|
|
@@ -1836,7 +1953,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
1836
1953
|
function toSet(arr) {
|
|
1837
1954
|
return new Set(arr);
|
|
1838
1955
|
}
|
|
1839
|
-
const ZOOM_STEPS = [0.1, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4, 5];
|
|
1956
|
+
const ZOOM_STEPS = [0.1, 0.25, 0.33, 0.5, 0.67, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5];
|
|
1840
1957
|
const DEFAULT_ANIMATION_DURATION = 280;
|
|
1841
1958
|
function zoomAtPoint({ viewport, point, targetScale }) {
|
|
1842
1959
|
const clampedScale = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, targetScale));
|
|
@@ -2581,58 +2698,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2581
2698
|
return [];
|
|
2582
2699
|
}
|
|
2583
2700
|
}
|
|
2584
|
-
const CURVE_RATIO = 0.2;
|
|
2585
|
-
function computeCurveControlPoint(start, end, ratio = CURVE_RATIO) {
|
|
2586
|
-
const mx = (start.x + end.x) / 2;
|
|
2587
|
-
const my = (start.y + end.y) / 2;
|
|
2588
|
-
const dx = end.x - start.x;
|
|
2589
|
-
const dy = end.y - start.y;
|
|
2590
|
-
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
2591
|
-
if (len2 === 0) return { x: mx, y: my };
|
|
2592
|
-
const nx = -dy / len2;
|
|
2593
|
-
const ny = dx / len2;
|
|
2594
|
-
const offset = len2 * ratio;
|
|
2595
|
-
return { x: mx + nx * offset, y: my + ny * offset };
|
|
2596
|
-
}
|
|
2597
|
-
function quadBezierAt(p0, cp, p2, t) {
|
|
2598
|
-
const mt = 1 - t;
|
|
2599
|
-
return {
|
|
2600
|
-
x: mt * mt * p0.x + 2 * mt * t * cp.x + t * t * p2.x,
|
|
2601
|
-
y: mt * mt * p0.y + 2 * mt * t * cp.y + t * t * p2.y
|
|
2602
|
-
};
|
|
2603
|
-
}
|
|
2604
|
-
function quadBezierTangent(p0, cp, p2, t) {
|
|
2605
|
-
const mt = 1 - t;
|
|
2606
|
-
return {
|
|
2607
|
-
x: 2 * mt * (cp.x - p0.x) + 2 * t * (p2.x - cp.x),
|
|
2608
|
-
y: 2 * mt * (cp.y - p0.y) + 2 * t * (p2.y - cp.y)
|
|
2609
|
-
};
|
|
2610
|
-
}
|
|
2611
|
-
function curveArrowPrev(start, cp, end, atEnd) {
|
|
2612
|
-
if (atEnd) {
|
|
2613
|
-
const tan = quadBezierTangent(start, cp, end, 1);
|
|
2614
|
-
const len2 = Math.sqrt(tan.x * tan.x + tan.y * tan.y) || 1;
|
|
2615
|
-
return { x: end.x - tan.x / len2 * 20, y: end.y - tan.y / len2 * 20 };
|
|
2616
|
-
} else {
|
|
2617
|
-
const tan = quadBezierTangent(start, cp, end, 0);
|
|
2618
|
-
const len2 = Math.sqrt(tan.x * tan.x + tan.y * tan.y) || 1;
|
|
2619
|
-
return { x: start.x + tan.x / len2 * 20, y: start.y + tan.y / len2 * 20 };
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
function curvatureFromDragPoint(start, end, dragWorld) {
|
|
2623
|
-
const dx = end.x - start.x;
|
|
2624
|
-
const dy = end.y - start.y;
|
|
2625
|
-
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
2626
|
-
if (len2 === 0) return CURVE_RATIO;
|
|
2627
|
-
const nx = -dy / len2;
|
|
2628
|
-
const ny = dx / len2;
|
|
2629
|
-
const mx = (start.x + end.x) / 2;
|
|
2630
|
-
const my = (start.y + end.y) / 2;
|
|
2631
|
-
const vx = dragWorld.x - mx;
|
|
2632
|
-
const vy = dragWorld.y - my;
|
|
2633
|
-
const projDist = vx * nx + vy * ny;
|
|
2634
|
-
return 2 * projDist / len2;
|
|
2635
|
-
}
|
|
2636
2701
|
const selectTool = {
|
|
2637
2702
|
name: "select",
|
|
2638
2703
|
onMouseDown(e, pos, ctx) {
|
|
@@ -3335,7 +3400,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3335
3400
|
width: dims.width,
|
|
3336
3401
|
height: dims.height,
|
|
3337
3402
|
rotation: 0,
|
|
3338
|
-
style: { ...style, fillColor: "transparent" },
|
|
3403
|
+
style: { ...style, fillColor: "transparent", strokeColor: "transparent", strokeWidth: 0 },
|
|
3339
3404
|
isLocked: false,
|
|
3340
3405
|
isVisible: true,
|
|
3341
3406
|
boundElements: null,
|
|
@@ -5587,7 +5652,34 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5587
5652
|
);
|
|
5588
5653
|
};
|
|
5589
5654
|
const FreeDrawShape = React.memo(FreeDrawShape$1);
|
|
5590
|
-
const
|
|
5655
|
+
const LABEL_PADDING_H = 8;
|
|
5656
|
+
const LABEL_PADDING_V = 4;
|
|
5657
|
+
const LABEL_CORNER = 4;
|
|
5658
|
+
const LABEL_LINE_HEIGHT = 1.18;
|
|
5659
|
+
const LABEL_MIN_WIDTH = 10;
|
|
5660
|
+
let _measureCanvas$1 = null;
|
|
5661
|
+
function getMeasureCtx() {
|
|
5662
|
+
if (!_measureCanvas$1) {
|
|
5663
|
+
_measureCanvas$1 = document.createElement("canvas");
|
|
5664
|
+
}
|
|
5665
|
+
return _measureCanvas$1.getContext("2d");
|
|
5666
|
+
}
|
|
5667
|
+
function measureLabelText(text, fontSize, fontFamily) {
|
|
5668
|
+
const ctx = getMeasureCtx();
|
|
5669
|
+
ctx.font = `${fontSize}px ${fontFamily}`;
|
|
5670
|
+
const metrics = ctx.measureText(text || " ");
|
|
5671
|
+
return {
|
|
5672
|
+
width: Math.ceil(metrics.width),
|
|
5673
|
+
height: Math.ceil(fontSize * LABEL_LINE_HEIGHT)
|
|
5674
|
+
};
|
|
5675
|
+
}
|
|
5676
|
+
function computePillSize(textWidth, textHeight) {
|
|
5677
|
+
return {
|
|
5678
|
+
width: Math.max(LABEL_MIN_WIDTH, textWidth) + LABEL_PADDING_H * 2,
|
|
5679
|
+
height: textHeight + LABEL_PADDING_V * 2
|
|
5680
|
+
};
|
|
5681
|
+
}
|
|
5682
|
+
const LINE_HEIGHT = LABEL_LINE_HEIGHT;
|
|
5591
5683
|
const TextShape$1 = ({
|
|
5592
5684
|
element,
|
|
5593
5685
|
isSelected,
|
|
@@ -5604,6 +5696,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5604
5696
|
const { id, x, y, width, height, rotation, style, text, containerId, textAlign, verticalAlign, isLocked } = element;
|
|
5605
5697
|
const textRef = React.useRef(null);
|
|
5606
5698
|
const isEditingRef = React.useRef(false);
|
|
5699
|
+
const [isEditingState, setIsEditingState] = React.useState(false);
|
|
5607
5700
|
const autoEditDoneRef = React.useRef(false);
|
|
5608
5701
|
const isBound = !!containerId;
|
|
5609
5702
|
const isDraggable = !isBound && !isLocked && !isGrouped;
|
|
@@ -5612,36 +5705,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5612
5705
|
return allElements.find((el) => el.id === containerId) ?? null;
|
|
5613
5706
|
}, [containerId, allElements]);
|
|
5614
5707
|
const boundPos = React.useMemo(() => {
|
|
5615
|
-
var _a, _b;
|
|
5616
5708
|
if (!container) return { x, y };
|
|
5617
|
-
if (container.type === "arrow" || container.type === "line") {
|
|
5618
|
-
const conn = container;
|
|
5619
|
-
const pts = conn.points;
|
|
5620
|
-
const startPt = { x: pts[0], y: pts[1] };
|
|
5621
|
-
const endPt = { x: pts[pts.length - 2], y: pts[pts.length - 1] };
|
|
5622
|
-
let midX, midY;
|
|
5623
|
-
if (conn.lineType === "curved") {
|
|
5624
|
-
const cp = computeCurveControlPoint(startPt, endPt, conn.curvature ?? CURVE_RATIO);
|
|
5625
|
-
const mid = quadBezierAt(startPt, cp, endPt, 0.5);
|
|
5626
|
-
midX = conn.x + mid.x;
|
|
5627
|
-
midY = conn.y + mid.y;
|
|
5628
|
-
} else {
|
|
5629
|
-
midX = conn.x + (startPt.x + endPt.x) / 2;
|
|
5630
|
-
midY = conn.y + (startPt.y + endPt.y) / 2;
|
|
5631
|
-
}
|
|
5632
|
-
const textWidth2 = Math.max(80, width || 80);
|
|
5633
|
-
const textHeight = ((_a = textRef.current) == null ? void 0 : _a.height()) ?? height;
|
|
5634
|
-
return {
|
|
5635
|
-
x: midX - textWidth2 / 2,
|
|
5636
|
-
y: midY - textHeight / 2,
|
|
5637
|
-
width: textWidth2
|
|
5638
|
-
};
|
|
5639
|
-
}
|
|
5640
5709
|
const PADDING2 = 4;
|
|
5641
5710
|
const cw = container.width - PADDING2 * 2;
|
|
5642
5711
|
const textWidth = Math.max(20, cw);
|
|
5643
5712
|
const bx = container.x + PADDING2;
|
|
5644
|
-
const textActualHeight =
|
|
5713
|
+
const textActualHeight = height;
|
|
5645
5714
|
let by;
|
|
5646
5715
|
if (verticalAlign === "top") {
|
|
5647
5716
|
by = container.y + PADDING2;
|
|
@@ -5651,7 +5720,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5651
5720
|
by = container.y + (container.height - textActualHeight) / 2;
|
|
5652
5721
|
}
|
|
5653
5722
|
return { x: bx, y: by, width: textWidth };
|
|
5654
|
-
}, [container, x, y, height, verticalAlign]);
|
|
5723
|
+
}, [container, x, y, width, height, verticalAlign]);
|
|
5655
5724
|
const syncSize = React.useCallback(() => {
|
|
5656
5725
|
const node = textRef.current;
|
|
5657
5726
|
if (!node || isEditingRef.current) return;
|
|
@@ -5673,8 +5742,14 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5673
5742
|
onChange(id, updates);
|
|
5674
5743
|
}
|
|
5675
5744
|
}, [id, height, width, isBound, onChange]);
|
|
5745
|
+
const syncSizeInitRef = React.useRef(true);
|
|
5676
5746
|
React.useEffect(() => {
|
|
5677
|
-
|
|
5747
|
+
if (syncSizeInitRef.current) {
|
|
5748
|
+
syncSizeInitRef.current = false;
|
|
5749
|
+
if (text && height > 0) return;
|
|
5750
|
+
}
|
|
5751
|
+
const id2 = requestAnimationFrame(syncSize);
|
|
5752
|
+
return () => cancelAnimationFrame(id2);
|
|
5678
5753
|
}, [text, style.fontSize, style.fontFamily, syncSize]);
|
|
5679
5754
|
const openEditor = React.useCallback(() => {
|
|
5680
5755
|
const textNode = textRef.current;
|
|
@@ -5682,6 +5757,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5682
5757
|
const stage = textNode.getStage();
|
|
5683
5758
|
if (!stage) return;
|
|
5684
5759
|
isEditingRef.current = true;
|
|
5760
|
+
setIsEditingState(true);
|
|
5685
5761
|
onEditStart == null ? void 0 : onEditStart(id);
|
|
5686
5762
|
const stageContainer = stage.container();
|
|
5687
5763
|
const absTransform = textNode.getAbsoluteTransform().copy();
|
|
@@ -5704,7 +5780,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5704
5780
|
containerScreenH = container.height * stageScaleX;
|
|
5705
5781
|
}
|
|
5706
5782
|
const nodeWidth = textNode.width();
|
|
5707
|
-
const screenWidth = isBound ? containerScreenW - PADDING_SCREEN * 2 : Math.max(nodeWidth,
|
|
5783
|
+
const screenWidth = isBound ? containerScreenW - PADDING_SCREEN * 2 : Math.max(nodeWidth, 60) * stageScaleX;
|
|
5708
5784
|
const screenLeft = isBound ? containerScreenLeft + PADDING_SCREEN : absPos.x;
|
|
5709
5785
|
const originalText = text;
|
|
5710
5786
|
const textarea = document.createElement("textarea");
|
|
@@ -5778,7 +5854,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5778
5854
|
}
|
|
5779
5855
|
if (!isBound) {
|
|
5780
5856
|
textarea.style.width = "auto";
|
|
5781
|
-
|
|
5857
|
+
const minW = 100 * stageScaleX;
|
|
5858
|
+
textarea.style.width = `${Math.max(textarea.scrollWidth, minW)}px`;
|
|
5782
5859
|
}
|
|
5783
5860
|
};
|
|
5784
5861
|
textarea.addEventListener("input", autoGrow);
|
|
@@ -5791,6 +5868,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5791
5868
|
const finishEdit = () => {
|
|
5792
5869
|
if (!isEditingRef.current) return;
|
|
5793
5870
|
isEditingRef.current = false;
|
|
5871
|
+
setIsEditingState(false);
|
|
5794
5872
|
const newText = cancelled ? originalText : textarea.value;
|
|
5795
5873
|
const isEmpty = newText.trim() === "";
|
|
5796
5874
|
textarea.removeEventListener("input", autoGrow);
|
|
@@ -5806,9 +5884,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5806
5884
|
}
|
|
5807
5885
|
onEditEnd == null ? void 0 : onEditEnd(id, isEmpty);
|
|
5808
5886
|
};
|
|
5809
|
-
const handleBlur = () =>
|
|
5810
|
-
finishEdit();
|
|
5811
|
-
};
|
|
5887
|
+
const handleBlur = () => finishEdit();
|
|
5812
5888
|
const handleKeyDown = (e) => {
|
|
5813
5889
|
e.stopPropagation();
|
|
5814
5890
|
if (e.key === "Escape") {
|
|
@@ -5859,7 +5935,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5859
5935
|
wrap: isBound ? "word" : "none",
|
|
5860
5936
|
rotation: isBound ? (container == null ? void 0 : container.rotation) ?? rotation : rotation,
|
|
5861
5937
|
transformsEnabled: (isBound ? (container == null ? void 0 : container.rotation) ?? rotation : rotation) ? "all" : "position",
|
|
5862
|
-
visible: !
|
|
5938
|
+
visible: !isEditingState && !(autoEdit && !text),
|
|
5863
5939
|
opacity: text ? style.opacity : isBound ? 0 : 0.4,
|
|
5864
5940
|
draggable: isDraggable,
|
|
5865
5941
|
listening: !isBound,
|
|
@@ -5909,6 +5985,263 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5909
5985
|
);
|
|
5910
5986
|
};
|
|
5911
5987
|
const TextShape = React.memo(TextShape$1);
|
|
5988
|
+
const TextLabel$1 = ({
|
|
5989
|
+
element,
|
|
5990
|
+
connector,
|
|
5991
|
+
onChange,
|
|
5992
|
+
autoEdit,
|
|
5993
|
+
onEditStart,
|
|
5994
|
+
onEditEnd
|
|
5995
|
+
}) => {
|
|
5996
|
+
const { id, x, y, width, height, style, text } = element;
|
|
5997
|
+
const labelFontSize = style.fontSize * 0.9;
|
|
5998
|
+
const textRef = React.useRef(null);
|
|
5999
|
+
const bgRectRef = React.useRef(null);
|
|
6000
|
+
const isEditingRef = React.useRef(false);
|
|
6001
|
+
const [isEditingState, setIsEditingState] = React.useState(false);
|
|
6002
|
+
const autoEditDoneRef = React.useRef(false);
|
|
6003
|
+
const boundPos = React.useMemo(() => {
|
|
6004
|
+
const textWidth = Math.max(LABEL_MIN_WIDTH, width || 60);
|
|
6005
|
+
const pos = computeConnectorLabelPosition(connector, textWidth, height);
|
|
6006
|
+
return { x: pos.x, y: pos.y, width: textWidth };
|
|
6007
|
+
}, [connector, width, height]);
|
|
6008
|
+
const effectiveX = boundPos.x;
|
|
6009
|
+
const effectiveY = boundPos.y;
|
|
6010
|
+
const syncSize = React.useCallback(() => {
|
|
6011
|
+
const node = textRef.current;
|
|
6012
|
+
if (!node || isEditingRef.current) return;
|
|
6013
|
+
const measuredHeight = node.height();
|
|
6014
|
+
const updates = {};
|
|
6015
|
+
let needsUpdate = false;
|
|
6016
|
+
if (Math.abs(measuredHeight - height) > 1) {
|
|
6017
|
+
updates.height = measuredHeight;
|
|
6018
|
+
needsUpdate = true;
|
|
6019
|
+
}
|
|
6020
|
+
const measuredWidth = measureLabelText(text || " ", labelFontSize, style.fontFamily).width;
|
|
6021
|
+
if (Math.abs(measuredWidth - width) > 1) {
|
|
6022
|
+
updates.width = measuredWidth;
|
|
6023
|
+
needsUpdate = true;
|
|
6024
|
+
}
|
|
6025
|
+
if (needsUpdate) {
|
|
6026
|
+
onChange(id, updates);
|
|
6027
|
+
}
|
|
6028
|
+
}, [id, text, height, width, labelFontSize, style.fontFamily, onChange]);
|
|
6029
|
+
const syncSizeInitRef = React.useRef(true);
|
|
6030
|
+
React.useEffect(() => {
|
|
6031
|
+
if (syncSizeInitRef.current) {
|
|
6032
|
+
syncSizeInitRef.current = false;
|
|
6033
|
+
if (text && height > 0) return;
|
|
6034
|
+
}
|
|
6035
|
+
const rafId = requestAnimationFrame(syncSize);
|
|
6036
|
+
return () => cancelAnimationFrame(rafId);
|
|
6037
|
+
}, [text, labelFontSize, style.fontFamily, syncSize]);
|
|
6038
|
+
const openEditor = React.useCallback(() => {
|
|
6039
|
+
var _a;
|
|
6040
|
+
const textNode = textRef.current;
|
|
6041
|
+
if (!textNode || isEditingRef.current) return;
|
|
6042
|
+
const stage = textNode.getStage();
|
|
6043
|
+
if (!stage) return;
|
|
6044
|
+
isEditingRef.current = true;
|
|
6045
|
+
setIsEditingState(true);
|
|
6046
|
+
onEditStart == null ? void 0 : onEditStart(id);
|
|
6047
|
+
const stageContainer = stage.container();
|
|
6048
|
+
const absTransform = textNode.getAbsoluteTransform().copy();
|
|
6049
|
+
const absPos = absTransform.point({ x: 0, y: 0 });
|
|
6050
|
+
const stageScaleX = stage.scaleX();
|
|
6051
|
+
const screenFontSize = labelFontSize * stageScaleX;
|
|
6052
|
+
const nodeWidth = textNode.width();
|
|
6053
|
+
const scaledPadH = LABEL_PADDING_H * stageScaleX;
|
|
6054
|
+
const scaledPadV = LABEL_PADDING_V * stageScaleX;
|
|
6055
|
+
const initMeasured = measureLabelText(text || " ", labelFontSize, style.fontFamily);
|
|
6056
|
+
const initPillW = Math.max(LABEL_MIN_WIDTH, initMeasured.width) * stageScaleX + scaledPadH * 2;
|
|
6057
|
+
const initPillH = initMeasured.height * stageScaleX + scaledPadV * 2;
|
|
6058
|
+
const connMidScreenX = absPos.x + nodeWidth * stageScaleX / 2;
|
|
6059
|
+
const connMidScreenY = absPos.y + textNode.height() * stageScaleX / 2;
|
|
6060
|
+
const originalText = text;
|
|
6061
|
+
const textarea = document.createElement("textarea");
|
|
6062
|
+
stageContainer.appendChild(textarea);
|
|
6063
|
+
textarea.value = text;
|
|
6064
|
+
textarea.style.position = "absolute";
|
|
6065
|
+
textarea.style.top = `${connMidScreenY - initPillH / 2}px`;
|
|
6066
|
+
textarea.style.left = `${connMidScreenX - initPillW / 2}px`;
|
|
6067
|
+
textarea.style.width = `${initPillW}px`;
|
|
6068
|
+
textarea.style.height = `${initPillH}px`;
|
|
6069
|
+
textarea.style.fontSize = `${screenFontSize}px`;
|
|
6070
|
+
textarea.style.fontFamily = style.fontFamily;
|
|
6071
|
+
textarea.style.color = style.strokeColor;
|
|
6072
|
+
textarea.style.lineHeight = `${LABEL_LINE_HEIGHT}`;
|
|
6073
|
+
textarea.style.border = "none";
|
|
6074
|
+
textarea.style.margin = "0";
|
|
6075
|
+
textarea.style.outline = "none";
|
|
6076
|
+
textarea.style.resize = "none";
|
|
6077
|
+
textarea.style.overflow = "hidden";
|
|
6078
|
+
textarea.style.zIndex = "1000";
|
|
6079
|
+
textarea.rows = 1;
|
|
6080
|
+
textarea.style.minHeight = `${Math.max(20, screenFontSize * LABEL_LINE_HEIGHT)}px`;
|
|
6081
|
+
textarea.style.boxSizing = "border-box";
|
|
6082
|
+
textarea.style.transformOrigin = "left top";
|
|
6083
|
+
textarea.style.letterSpacing = "normal";
|
|
6084
|
+
textarea.style.caretColor = style.strokeColor;
|
|
6085
|
+
textarea.style.background = "#f8f9fa";
|
|
6086
|
+
textarea.style.borderRadius = `${LABEL_CORNER * stageScaleX}px`;
|
|
6087
|
+
textarea.style.padding = `${scaledPadV}px ${scaledPadH}px`;
|
|
6088
|
+
textarea.style.textAlign = "center";
|
|
6089
|
+
textarea.style.whiteSpace = "nowrap";
|
|
6090
|
+
textarea.style.wordBreak = "normal";
|
|
6091
|
+
const autoGrow = () => {
|
|
6092
|
+
const currentText = textarea.value || " ";
|
|
6093
|
+
const measured = measureLabelText(currentText, labelFontSize, style.fontFamily);
|
|
6094
|
+
const newTextW = Math.max(LABEL_MIN_WIDTH, measured.width) * stageScaleX;
|
|
6095
|
+
const pillW = newTextW + scaledPadH * 2;
|
|
6096
|
+
const pillH = measured.height * stageScaleX + scaledPadV * 2;
|
|
6097
|
+
textarea.style.width = `${pillW}px`;
|
|
6098
|
+
textarea.style.height = `${pillH}px`;
|
|
6099
|
+
textarea.style.left = `${connMidScreenX - pillW / 2}px`;
|
|
6100
|
+
textarea.style.top = `${connMidScreenY - pillH / 2}px`;
|
|
6101
|
+
};
|
|
6102
|
+
textarea.addEventListener("input", autoGrow);
|
|
6103
|
+
requestAnimationFrame(autoGrow);
|
|
6104
|
+
textNode.hide();
|
|
6105
|
+
(_a = bgRectRef.current) == null ? void 0 : _a.hide();
|
|
6106
|
+
stage.batchDraw();
|
|
6107
|
+
textarea.focus();
|
|
6108
|
+
textarea.select();
|
|
6109
|
+
let cancelled = false;
|
|
6110
|
+
const finishEdit = () => {
|
|
6111
|
+
var _a2;
|
|
6112
|
+
if (!isEditingRef.current) return;
|
|
6113
|
+
isEditingRef.current = false;
|
|
6114
|
+
setIsEditingState(false);
|
|
6115
|
+
const newText = cancelled ? originalText : textarea.value;
|
|
6116
|
+
const isEmpty = newText.trim() === "";
|
|
6117
|
+
textarea.removeEventListener("input", autoGrow);
|
|
6118
|
+
textarea.removeEventListener("blur", handleBlur);
|
|
6119
|
+
textarea.removeEventListener("keydown", handleKeyDown);
|
|
6120
|
+
if (textarea.parentNode) {
|
|
6121
|
+
textarea.parentNode.removeChild(textarea);
|
|
6122
|
+
}
|
|
6123
|
+
textNode.show();
|
|
6124
|
+
(_a2 = bgRectRef.current) == null ? void 0 : _a2.show();
|
|
6125
|
+
stage.batchDraw();
|
|
6126
|
+
if (!cancelled) {
|
|
6127
|
+
const measured = measureLabelText(newText || " ", labelFontSize, style.fontFamily);
|
|
6128
|
+
onChange(id, {
|
|
6129
|
+
text: newText,
|
|
6130
|
+
width: measured.width,
|
|
6131
|
+
height: measured.height
|
|
6132
|
+
});
|
|
6133
|
+
}
|
|
6134
|
+
onEditEnd == null ? void 0 : onEditEnd(id, isEmpty);
|
|
6135
|
+
};
|
|
6136
|
+
const handleBlur = () => finishEdit();
|
|
6137
|
+
const handleKeyDown = (e) => {
|
|
6138
|
+
e.stopPropagation();
|
|
6139
|
+
if (e.key === "Escape") {
|
|
6140
|
+
cancelled = true;
|
|
6141
|
+
textarea.blur();
|
|
6142
|
+
}
|
|
6143
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
6144
|
+
e.preventDefault();
|
|
6145
|
+
textarea.blur();
|
|
6146
|
+
}
|
|
6147
|
+
if (e.key === "Tab") {
|
|
6148
|
+
e.preventDefault();
|
|
6149
|
+
textarea.blur();
|
|
6150
|
+
}
|
|
6151
|
+
};
|
|
6152
|
+
textarea.addEventListener("blur", handleBlur);
|
|
6153
|
+
textarea.addEventListener("keydown", handleKeyDown);
|
|
6154
|
+
}, [id, text, style, onChange, onEditStart, onEditEnd]);
|
|
6155
|
+
React.useEffect(() => {
|
|
6156
|
+
if (!autoEdit) {
|
|
6157
|
+
autoEditDoneRef.current = false;
|
|
6158
|
+
}
|
|
6159
|
+
}, [autoEdit]);
|
|
6160
|
+
React.useEffect(() => {
|
|
6161
|
+
if (autoEdit && !autoEditDoneRef.current && textRef.current) {
|
|
6162
|
+
autoEditDoneRef.current = true;
|
|
6163
|
+
openEditor();
|
|
6164
|
+
}
|
|
6165
|
+
}, [autoEdit, openEditor]);
|
|
6166
|
+
const pillTextW = Math.max(LABEL_MIN_WIDTH, width || 60);
|
|
6167
|
+
const labelW = pillTextW + LABEL_PADDING_H * 2;
|
|
6168
|
+
const labelH = height + LABEL_PADDING_V * 2;
|
|
6169
|
+
const isVisible = !isEditingState && !(autoEdit && !text);
|
|
6170
|
+
const labelOpacity = text ? style.opacity : 0;
|
|
6171
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6172
|
+
reactKonva.Group,
|
|
6173
|
+
{
|
|
6174
|
+
x: (effectiveX ?? 0) - LABEL_PADDING_H,
|
|
6175
|
+
y: (effectiveY ?? 0) - LABEL_PADDING_V,
|
|
6176
|
+
visible: isVisible,
|
|
6177
|
+
opacity: labelOpacity,
|
|
6178
|
+
listening: false,
|
|
6179
|
+
perfectDrawEnabled: false,
|
|
6180
|
+
children: [
|
|
6181
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6182
|
+
reactKonva.Rect,
|
|
6183
|
+
{
|
|
6184
|
+
ref: bgRectRef,
|
|
6185
|
+
width: labelW,
|
|
6186
|
+
height: labelH,
|
|
6187
|
+
fill: "#f8f9fa",
|
|
6188
|
+
cornerRadius: LABEL_CORNER,
|
|
6189
|
+
listening: false,
|
|
6190
|
+
perfectDrawEnabled: false
|
|
6191
|
+
}
|
|
6192
|
+
),
|
|
6193
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6194
|
+
reactKonva.Text,
|
|
6195
|
+
{
|
|
6196
|
+
ref: textRef,
|
|
6197
|
+
id,
|
|
6198
|
+
x: LABEL_PADDING_H,
|
|
6199
|
+
y: LABEL_PADDING_V,
|
|
6200
|
+
text: text || "",
|
|
6201
|
+
fontSize: labelFontSize,
|
|
6202
|
+
fontFamily: style.fontFamily,
|
|
6203
|
+
fill: style.strokeColor,
|
|
6204
|
+
lineHeight: LABEL_LINE_HEIGHT,
|
|
6205
|
+
wrap: "none",
|
|
6206
|
+
listening: false,
|
|
6207
|
+
perfectDrawEnabled: false,
|
|
6208
|
+
onDblClick: openEditor,
|
|
6209
|
+
onDblTap: openEditor
|
|
6210
|
+
}
|
|
6211
|
+
)
|
|
6212
|
+
]
|
|
6213
|
+
}
|
|
6214
|
+
);
|
|
6215
|
+
};
|
|
6216
|
+
const TextLabel = React.memo(TextLabel$1);
|
|
6217
|
+
const IMAGE_CACHE_LIMIT = 50;
|
|
6218
|
+
const _imgCache = /* @__PURE__ */ new Map();
|
|
6219
|
+
function cachedLoadImage(src, onLoad, onError) {
|
|
6220
|
+
const cached = _imgCache.get(src);
|
|
6221
|
+
if (cached) {
|
|
6222
|
+
onLoad(cached);
|
|
6223
|
+
return () => {
|
|
6224
|
+
};
|
|
6225
|
+
}
|
|
6226
|
+
const img = new window.Image();
|
|
6227
|
+
if (!src.startsWith("data:")) {
|
|
6228
|
+
img.crossOrigin = "anonymous";
|
|
6229
|
+
}
|
|
6230
|
+
img.onload = () => {
|
|
6231
|
+
if (_imgCache.size >= IMAGE_CACHE_LIMIT) {
|
|
6232
|
+
const oldest = _imgCache.keys().next().value;
|
|
6233
|
+
if (oldest !== void 0) _imgCache.delete(oldest);
|
|
6234
|
+
}
|
|
6235
|
+
_imgCache.set(src, img);
|
|
6236
|
+
onLoad(img);
|
|
6237
|
+
};
|
|
6238
|
+
img.onerror = () => onError();
|
|
6239
|
+
img.src = src;
|
|
6240
|
+
return () => {
|
|
6241
|
+
img.onload = null;
|
|
6242
|
+
img.onerror = null;
|
|
6243
|
+
};
|
|
6244
|
+
}
|
|
5912
6245
|
const ImageShape$1 = ({
|
|
5913
6246
|
element,
|
|
5914
6247
|
isSelected,
|
|
@@ -5921,8 +6254,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5921
6254
|
onDragSnap
|
|
5922
6255
|
}) => {
|
|
5923
6256
|
const { id, x, y, width, height, rotation, src, style, crop, cornerRadius, scaleMode, isLocked } = element;
|
|
5924
|
-
const [image, setImage] = React.useState(null);
|
|
5925
|
-
const [loadError, setLoadError] = React.useState(
|
|
6257
|
+
const [image, setImage] = React.useState(() => _imgCache.get(src) ?? null);
|
|
6258
|
+
const [loadError, setLoadError] = React.useState(() => !src);
|
|
5926
6259
|
const [liveSize, setLiveSize] = React.useState({ w: width, h: height });
|
|
5927
6260
|
React.useEffect(() => {
|
|
5928
6261
|
setLiveSize({ w: width, h: height });
|
|
@@ -5935,21 +6268,17 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5935
6268
|
setLoadError(true);
|
|
5936
6269
|
return;
|
|
5937
6270
|
}
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
return () => {
|
|
5950
|
-
img.onload = null;
|
|
5951
|
-
img.onerror = null;
|
|
5952
|
-
};
|
|
6271
|
+
return cachedLoadImage(
|
|
6272
|
+
src,
|
|
6273
|
+
(img) => {
|
|
6274
|
+
setImage(img);
|
|
6275
|
+
setLoadError(false);
|
|
6276
|
+
},
|
|
6277
|
+
() => {
|
|
6278
|
+
setImage(null);
|
|
6279
|
+
setLoadError(true);
|
|
6280
|
+
}
|
|
6281
|
+
);
|
|
5953
6282
|
}, [src]);
|
|
5954
6283
|
const handleDragMove = React.useCallback((e) => {
|
|
5955
6284
|
let nx = e.target.x(), ny = e.target.y();
|
|
@@ -6091,13 +6420,14 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6091
6420
|
shadowBlur: isSelected ? 6 : 0,
|
|
6092
6421
|
shadowOpacity: isSelected ? 0.5 : 0,
|
|
6093
6422
|
children: [
|
|
6094
|
-
|
|
6423
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6095
6424
|
reactKonva.Rect,
|
|
6096
6425
|
{
|
|
6097
6426
|
width: rw,
|
|
6098
6427
|
height: rh,
|
|
6099
|
-
fill: style.fillColor === "transparent" ? void 0 : style.fillColor,
|
|
6100
|
-
cornerRadius
|
|
6428
|
+
fill: scaleMode === "fit" ? style.fillColor === "transparent" ? void 0 : style.fillColor : "transparent",
|
|
6429
|
+
cornerRadius,
|
|
6430
|
+
perfectDrawEnabled: false
|
|
6101
6431
|
}
|
|
6102
6432
|
),
|
|
6103
6433
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -6189,7 +6519,22 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6189
6519
|
return /* @__PURE__ */ jsxRuntime.jsx(ArrowShape, { element, isSelected, isEditing, isGrouped, onSelect, onChange, onDragMove, onDoubleClick, gridSnap, allElements });
|
|
6190
6520
|
case "freedraw":
|
|
6191
6521
|
return /* @__PURE__ */ jsxRuntime.jsx(FreeDrawShape, { element, isSelected, isGrouped, onSelect, onChange, onDragMove, onDoubleClick, gridSnap, onDragSnap });
|
|
6192
|
-
case "text":
|
|
6522
|
+
case "text": {
|
|
6523
|
+
const connContainer = element.containerId && allElements ? allElements.find((el) => el.id === element.containerId) : null;
|
|
6524
|
+
const isConnectorLabel = connContainer && (connContainer.type === "arrow" || connContainer.type === "line");
|
|
6525
|
+
if (isConnectorLabel) {
|
|
6526
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6527
|
+
TextLabel,
|
|
6528
|
+
{
|
|
6529
|
+
element,
|
|
6530
|
+
connector: connContainer,
|
|
6531
|
+
onChange,
|
|
6532
|
+
autoEdit: autoEditText,
|
|
6533
|
+
onEditStart: onTextEditStart,
|
|
6534
|
+
onEditEnd: onTextEditEnd
|
|
6535
|
+
}
|
|
6536
|
+
);
|
|
6537
|
+
}
|
|
6193
6538
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6194
6539
|
TextShape,
|
|
6195
6540
|
{
|
|
@@ -6206,6 +6551,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6206
6551
|
gridSnap
|
|
6207
6552
|
}
|
|
6208
6553
|
);
|
|
6554
|
+
}
|
|
6209
6555
|
case "image":
|
|
6210
6556
|
return /* @__PURE__ */ jsxRuntime.jsx(ImageShape, { element, isSelected, isGrouped, onSelect, onChange, onDragMove, onDoubleClick, gridSnap, onDragSnap });
|
|
6211
6557
|
default:
|
|
@@ -6542,6 +6888,23 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6542
6888
|
const isCurved = "lineType" in element && element.lineType === "curved";
|
|
6543
6889
|
const isElbow = "lineType" in element && element.lineType === "elbow";
|
|
6544
6890
|
const endpointsOnly = isCurved || isElbow;
|
|
6891
|
+
const labelRect = React.useMemo(() => {
|
|
6892
|
+
if (!element.boundElements) return null;
|
|
6893
|
+
for (const be of element.boundElements) {
|
|
6894
|
+
if (be.type !== "text") continue;
|
|
6895
|
+
const txt = allElements.find((e) => e.id === be.id);
|
|
6896
|
+
if (!txt || !txt.text) continue;
|
|
6897
|
+
const textW = Math.max(LABEL_MIN_WIDTH, txt.width || 60);
|
|
6898
|
+
const textH = txt.height || 30;
|
|
6899
|
+
return {
|
|
6900
|
+
x: txt.x - LABEL_PADDING_H,
|
|
6901
|
+
y: txt.y - LABEL_PADDING_V,
|
|
6902
|
+
w: textW + LABEL_PADDING_H * 2,
|
|
6903
|
+
h: textH + LABEL_PADDING_V * 2
|
|
6904
|
+
};
|
|
6905
|
+
}
|
|
6906
|
+
return null;
|
|
6907
|
+
}, [element.boundElements, allElements]);
|
|
6545
6908
|
const isEndpoint = React.useCallback(
|
|
6546
6909
|
(idx) => idx === 0 || idx === pairs.length - 1,
|
|
6547
6910
|
[pairs.length]
|
|
@@ -6721,6 +7084,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6721
7084
|
!endpointsOnly && pairs.length >= 2 && pairs.slice(0, -1).map((pt, segIdx) => {
|
|
6722
7085
|
const next = pairs[segIdx + 1];
|
|
6723
7086
|
const mid = midpoint$1(pt, next);
|
|
7087
|
+
if (labelRect) {
|
|
7088
|
+
const wx = x + mid.x, wy = y + mid.y;
|
|
7089
|
+
if (wx >= labelRect.x && wx <= labelRect.x + labelRect.w && wy >= labelRect.y && wy <= labelRect.y + labelRect.h) {
|
|
7090
|
+
return null;
|
|
7091
|
+
}
|
|
7092
|
+
}
|
|
6724
7093
|
const isHovered = hoveredMidpointIndex === segIdx;
|
|
6725
7094
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6726
7095
|
reactKonva.Circle,
|
|
@@ -6777,6 +7146,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6777
7146
|
const curvature = element.curvature ?? CURVE_RATIO;
|
|
6778
7147
|
const cp = computeCurveControlPoint(localStart, localEnd, curvature);
|
|
6779
7148
|
const curveMid = quadBezierAt(localStart, cp, localEnd, 0.5);
|
|
7149
|
+
if (labelRect) {
|
|
7150
|
+
const wx = x + curveMid.x, wy = y + curveMid.y;
|
|
7151
|
+
if (wx >= labelRect.x && wx <= labelRect.x + labelRect.w && wy >= labelRect.y && wy <= labelRect.y + labelRect.h) {
|
|
7152
|
+
return null;
|
|
7153
|
+
}
|
|
7154
|
+
}
|
|
6780
7155
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6781
7156
|
reactKonva.Circle,
|
|
6782
7157
|
{
|
|
@@ -8376,28 +8751,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
8376
8751
|
] }) });
|
|
8377
8752
|
};
|
|
8378
8753
|
const SvgIcon = ({ children, color, size = 12 }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children });
|
|
8379
|
-
const LayerIcons = {
|
|
8380
|
-
sendToBack: (color) => /* @__PURE__ */ jsxRuntime.jsxs(SvgIcon, { color, children: [
|
|
8381
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 3v4a1 1 0 0 0 1 1h4" }),
|
|
8382
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2z", opacity: "0.3" }),
|
|
8383
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "12 12 12 18" }),
|
|
8384
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 15 12 18 15 15" })
|
|
8385
|
-
] }),
|
|
8386
|
-
sendBackward: (color) => /* @__PURE__ */ jsxRuntime.jsxs(SvgIcon, { color, children: [
|
|
8387
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
8388
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "19 12 12 19 5 12" })
|
|
8389
|
-
] }),
|
|
8390
|
-
bringForward: (color) => /* @__PURE__ */ jsxRuntime.jsxs(SvgIcon, { color, children: [
|
|
8391
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "19", x2: "12", y2: "5" }),
|
|
8392
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "5 12 12 5 19 12" })
|
|
8393
|
-
] }),
|
|
8394
|
-
bringToFront: (color) => /* @__PURE__ */ jsxRuntime.jsxs(SvgIcon, { color, children: [
|
|
8395
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 3v4a1 1 0 0 0 1 1h4" }),
|
|
8396
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2z", opacity: "0.3" }),
|
|
8397
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "12 18 12 12" }),
|
|
8398
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 15 12 12 15 15" })
|
|
8399
|
-
] })
|
|
8400
|
-
};
|
|
8401
8754
|
const ActionIcons = {
|
|
8402
8755
|
duplicate: (color) => /* @__PURE__ */ jsxRuntime.jsxs(SvgIcon, { color, children: [
|
|
8403
8756
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "8", y: "8", width: "12", height: "12", rx: "2" }),
|
|
@@ -8431,10 +8784,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
8431
8784
|
const toggleLockElements = useCanvasStore((s) => s.toggleLockElements);
|
|
8432
8785
|
const deleteElements = useCanvasStore((s) => s.deleteElements);
|
|
8433
8786
|
const duplicateElements = useCanvasStore((s) => s.duplicateElements);
|
|
8434
|
-
const bringToFront = useCanvasStore((s) => s.bringToFront);
|
|
8435
|
-
const sendToBack = useCanvasStore((s) => s.sendToBack);
|
|
8436
|
-
const bringForward = useCanvasStore((s) => s.bringForward);
|
|
8437
|
-
const sendBackward = useCanvasStore((s) => s.sendBackward);
|
|
8438
8787
|
const activeTool = useCanvasStore((s) => s.activeTool);
|
|
8439
8788
|
const currentLineType = useCanvasStore((s) => s.currentLineType);
|
|
8440
8789
|
const setCurrentLineType = useCanvasStore((s) => s.setCurrentLineType);
|
|
@@ -8927,31 +9276,22 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
8927
9276
|
{
|
|
8928
9277
|
theme,
|
|
8929
9278
|
style: { width: "100%", padding: "5px 0", borderRadius: 4 },
|
|
8930
|
-
onClick: () => {
|
|
8931
|
-
const
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
var _a;
|
|
8936
|
-
const file = (_a = input.files) == null ? void 0 : _a[0];
|
|
9279
|
+
onClick: async () => {
|
|
9280
|
+
const targetId = selectedImage.id;
|
|
9281
|
+
try {
|
|
9282
|
+
const files = await openImageFilePicker();
|
|
9283
|
+
const file = files[0];
|
|
8937
9284
|
if (!file) return;
|
|
8938
|
-
const
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
img.
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
|
|
8948
|
-
pushHistory();
|
|
8949
|
-
};
|
|
8950
|
-
img.src = dataURL;
|
|
8951
|
-
};
|
|
8952
|
-
reader.readAsDataURL(file);
|
|
8953
|
-
};
|
|
8954
|
-
input.click();
|
|
9285
|
+
const dataURL = await fileToDataURL(file);
|
|
9286
|
+
const img = await loadImage(dataURL);
|
|
9287
|
+
updateElement(targetId, {
|
|
9288
|
+
src: dataURL,
|
|
9289
|
+
naturalWidth: img.naturalWidth,
|
|
9290
|
+
naturalHeight: img.naturalHeight
|
|
9291
|
+
});
|
|
9292
|
+
pushHistory();
|
|
9293
|
+
} catch {
|
|
9294
|
+
}
|
|
8955
9295
|
},
|
|
8956
9296
|
children: "Replace Image…"
|
|
8957
9297
|
}
|
|
@@ -8959,27 +9299,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
8959
9299
|
] }),
|
|
8960
9300
|
hasSelection && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8961
9301
|
/* @__PURE__ */ jsxRuntime.jsx("hr", { style: dividerStyle }),
|
|
8962
|
-
/* @__PURE__ */ jsxRuntime.jsx(PanelSection, { label: "Layers", theme, children: /* @__PURE__ */ jsxRuntime.jsx(ButtonRow, { columns: 4, children: [
|
|
8963
|
-
{ fn: sendToBack, icon: LayerIcons.sendToBack, tip: "Send to back" },
|
|
8964
|
-
{ fn: sendBackward, icon: LayerIcons.sendBackward, tip: "Send backward" },
|
|
8965
|
-
{ fn: bringForward, icon: LayerIcons.bringForward, tip: "Bring forward" },
|
|
8966
|
-
{ fn: bringToFront, icon: LayerIcons.bringToFront, tip: "Bring to front" }
|
|
8967
|
-
].map(({ fn, icon, tip }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8968
|
-
PanelButton,
|
|
8969
|
-
{
|
|
8970
|
-
variant: "action",
|
|
8971
|
-
theme,
|
|
8972
|
-
title: tip,
|
|
8973
|
-
width: "100%",
|
|
8974
|
-
height: 32,
|
|
8975
|
-
onClick: () => {
|
|
8976
|
-
fn(selectedIds);
|
|
8977
|
-
pushHistory();
|
|
8978
|
-
},
|
|
8979
|
-
children: (hl) => icon(hl ? theme.activeToolColor : theme.textColor)
|
|
8980
|
-
},
|
|
8981
|
-
tip
|
|
8982
|
-
)) }) }),
|
|
8983
9302
|
/* @__PURE__ */ jsxRuntime.jsx(PanelSection, { label: "Actions", theme, children: /* @__PURE__ */ jsxRuntime.jsxs(ButtonRow, { columns: 4, children: [
|
|
8984
9303
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8985
9304
|
PanelButton,
|
|
@@ -9677,48 +9996,14 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
9677
9996
|
return result;
|
|
9678
9997
|
}
|
|
9679
9998
|
function useKeyboardShortcuts(enabled = true, containerRef) {
|
|
9680
|
-
const setActiveTool = useCanvasStore((s) => s.setActiveTool);
|
|
9681
|
-
const undo = useCanvasStore((s) => s.undo);
|
|
9682
|
-
const redo = useCanvasStore((s) => s.redo);
|
|
9683
|
-
const selectedIds = useCanvasStore((s) => s.selectedIds);
|
|
9684
|
-
const elements = useCanvasStore((s) => s.elements);
|
|
9685
|
-
const deleteElements = useCanvasStore((s) => s.deleteElements);
|
|
9686
|
-
const duplicateElements = useCanvasStore((s) => s.duplicateElements);
|
|
9687
|
-
const bringToFront = useCanvasStore((s) => s.bringToFront);
|
|
9688
|
-
const sendToBack = useCanvasStore((s) => s.sendToBack);
|
|
9689
|
-
const bringForward = useCanvasStore((s) => s.bringForward);
|
|
9690
|
-
const sendBackward = useCanvasStore((s) => s.sendBackward);
|
|
9691
|
-
const toggleGrid = useCanvasStore((s) => s.toggleGrid);
|
|
9692
|
-
const showGrid = useCanvasStore((s) => s.showGrid);
|
|
9693
|
-
const zoomIn = useCanvasStore((s) => s.zoomIn);
|
|
9694
|
-
const zoomOut = useCanvasStore((s) => s.zoomOut);
|
|
9695
|
-
const resetZoom = useCanvasStore((s) => s.resetZoom);
|
|
9696
|
-
const zoomToFit = useCanvasStore((s) => s.zoomToFit);
|
|
9697
|
-
const zoomToSelection = useCanvasStore((s) => s.zoomToSelection);
|
|
9698
|
-
const clearSelection = useCanvasStore((s) => s.clearSelection);
|
|
9699
|
-
const updateElement = useCanvasStore((s) => s.updateElement);
|
|
9700
|
-
const addElement = useCanvasStore((s) => s.addElement);
|
|
9701
|
-
const setSelectedIds = useCanvasStore((s) => s.setSelectedIds);
|
|
9702
|
-
const pushHistory = useCanvasStore((s) => s.pushHistory);
|
|
9703
|
-
const linearEdit = useLinearEditStore();
|
|
9704
9999
|
const copyElements = React.useCallback(() => {
|
|
10000
|
+
const { selectedIds, elements } = useCanvasStore.getState();
|
|
9705
10001
|
if (selectedIds.length === 0) return;
|
|
9706
10002
|
setClipboard(gatherElementsForCopy(selectedIds, elements));
|
|
9707
|
-
}, [
|
|
9708
|
-
const pasteElements = React.useCallback(() => {
|
|
9709
|
-
const clip = getClipboard();
|
|
9710
|
-
if (clip.length === 0) return;
|
|
9711
|
-
const PASTE_OFFSET = 20;
|
|
9712
|
-
const { clones, selectedCloneIds } = cloneAndRemapElements(clip, clip, PASTE_OFFSET);
|
|
9713
|
-
clones.forEach((el) => addElement(el));
|
|
9714
|
-
setSelectedIds(selectedCloneIds.length > 0 ? selectedCloneIds : clones.map((c) => c.id));
|
|
9715
|
-
pushHistory();
|
|
9716
|
-
setClipboard(
|
|
9717
|
-
clip.map((el) => ({ ...el, x: el.x + PASTE_OFFSET, y: el.y + PASTE_OFFSET }))
|
|
9718
|
-
);
|
|
9719
|
-
}, [addElement, setSelectedIds, pushHistory]);
|
|
10003
|
+
}, []);
|
|
9720
10004
|
const nudge = React.useCallback(
|
|
9721
10005
|
(dx, dy) => {
|
|
10006
|
+
const { selectedIds, elements, updateElement, pushHistory } = useCanvasStore.getState();
|
|
9722
10007
|
if (selectedIds.length === 0) return;
|
|
9723
10008
|
selectedIds.forEach((id) => {
|
|
9724
10009
|
const el = elements.find((e) => e.id === id);
|
|
@@ -9728,7 +10013,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
9728
10013
|
});
|
|
9729
10014
|
pushHistory();
|
|
9730
10015
|
},
|
|
9731
|
-
[
|
|
10016
|
+
[]
|
|
9732
10017
|
);
|
|
9733
10018
|
React.useEffect(() => {
|
|
9734
10019
|
if (!enabled) return;
|
|
@@ -9736,6 +10021,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
9736
10021
|
const tag = e.target.tagName;
|
|
9737
10022
|
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
|
|
9738
10023
|
const isCmd = e.metaKey || e.ctrlKey;
|
|
10024
|
+
const store = useCanvasStore.getState();
|
|
10025
|
+
const linearEdit = useLinearEditStore.getState();
|
|
9739
10026
|
if (!isCmd && !e.shiftKey) {
|
|
9740
10027
|
const toolMap = {
|
|
9741
10028
|
v: "select",
|
|
@@ -9753,30 +10040,29 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
9753
10040
|
const tool = toolMap[e.key.toLowerCase()];
|
|
9754
10041
|
if (tool) {
|
|
9755
10042
|
e.preventDefault();
|
|
9756
|
-
setActiveTool(tool);
|
|
10043
|
+
store.setActiveTool(tool);
|
|
9757
10044
|
return;
|
|
9758
10045
|
}
|
|
9759
10046
|
}
|
|
9760
10047
|
if (isCmd && e.key === "z" && !e.shiftKey) {
|
|
9761
10048
|
e.preventDefault();
|
|
9762
|
-
undo();
|
|
10049
|
+
store.undo();
|
|
9763
10050
|
return;
|
|
9764
10051
|
}
|
|
9765
10052
|
if (isCmd && e.key === "z" && e.shiftKey) {
|
|
9766
10053
|
e.preventDefault();
|
|
9767
|
-
redo();
|
|
10054
|
+
store.redo();
|
|
9768
10055
|
return;
|
|
9769
10056
|
}
|
|
9770
10057
|
if (isCmd && e.key === "y") {
|
|
9771
10058
|
e.preventDefault();
|
|
9772
|
-
redo();
|
|
10059
|
+
store.redo();
|
|
9773
10060
|
return;
|
|
9774
10061
|
}
|
|
9775
10062
|
if ((e.key === "Delete" || e.key === "Backspace") && !isCmd) {
|
|
9776
10063
|
if (linearEdit.isEditing && linearEdit.selectedPointIndices.length > 0) {
|
|
9777
10064
|
e.preventDefault();
|
|
9778
|
-
const
|
|
9779
|
-
const el = elements2.find((e2) => e2.id === linearEdit.elementId);
|
|
10065
|
+
const el = store.elements.find((e2) => e2.id === linearEdit.elementId);
|
|
9780
10066
|
if (el) {
|
|
9781
10067
|
const pointCount = el.points.length / 2;
|
|
9782
10068
|
const indicesToDelete = new Set(linearEdit.selectedPointIndices);
|
|
@@ -9814,75 +10100,75 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
9814
10100
|
if (indicesToDelete.has(pointCount - 1)) {
|
|
9815
10101
|
pointUpdates.endBinding = null;
|
|
9816
10102
|
}
|
|
9817
|
-
|
|
9818
|
-
|
|
10103
|
+
store.updateElement(el.id, pointUpdates);
|
|
10104
|
+
store.pushHistory();
|
|
9819
10105
|
linearEdit.setSelectedPoints([]);
|
|
9820
10106
|
}
|
|
9821
10107
|
}
|
|
9822
10108
|
return;
|
|
9823
10109
|
}
|
|
9824
|
-
if (selectedIds.length > 0) {
|
|
10110
|
+
if (store.selectedIds.length > 0) {
|
|
9825
10111
|
e.preventDefault();
|
|
9826
|
-
const unlocked = selectedIds.filter((sid) => {
|
|
9827
|
-
const el = elements.find((e2) => e2.id === sid);
|
|
10112
|
+
const unlocked = store.selectedIds.filter((sid) => {
|
|
10113
|
+
const el = store.elements.find((e2) => e2.id === sid);
|
|
9828
10114
|
return el && !el.isLocked;
|
|
9829
10115
|
});
|
|
9830
|
-
if (unlocked.length > 0) deleteElements(unlocked);
|
|
10116
|
+
if (unlocked.length > 0) store.deleteElements(unlocked);
|
|
9831
10117
|
}
|
|
9832
10118
|
return;
|
|
9833
10119
|
}
|
|
9834
10120
|
if (isCmd && e.key === "d") {
|
|
9835
10121
|
e.preventDefault();
|
|
9836
|
-
if (selectedIds.length > 0) {
|
|
9837
|
-
duplicateElements(selectedIds);
|
|
10122
|
+
if (store.selectedIds.length > 0) {
|
|
10123
|
+
store.duplicateElements(store.selectedIds);
|
|
9838
10124
|
}
|
|
9839
10125
|
return;
|
|
9840
10126
|
}
|
|
9841
10127
|
if (e.key === "]" && isCmd && e.shiftKey) {
|
|
9842
10128
|
e.preventDefault();
|
|
9843
|
-
bringToFront(selectedIds);
|
|
10129
|
+
store.bringToFront(store.selectedIds);
|
|
9844
10130
|
return;
|
|
9845
10131
|
}
|
|
9846
10132
|
if (e.key === "[" && isCmd && e.shiftKey) {
|
|
9847
10133
|
e.preventDefault();
|
|
9848
|
-
sendToBack(selectedIds);
|
|
10134
|
+
store.sendToBack(store.selectedIds);
|
|
9849
10135
|
return;
|
|
9850
10136
|
}
|
|
9851
10137
|
if (e.key === "]" && isCmd && !e.shiftKey) {
|
|
9852
10138
|
e.preventDefault();
|
|
9853
|
-
bringForward(selectedIds);
|
|
10139
|
+
store.bringForward(store.selectedIds);
|
|
9854
10140
|
return;
|
|
9855
10141
|
}
|
|
9856
10142
|
if (e.key === "[" && isCmd && !e.shiftKey) {
|
|
9857
10143
|
e.preventDefault();
|
|
9858
|
-
sendBackward(selectedIds);
|
|
10144
|
+
store.sendBackward(store.selectedIds);
|
|
9859
10145
|
return;
|
|
9860
10146
|
}
|
|
9861
10147
|
if (e.key === "g" && !isCmd) {
|
|
9862
10148
|
e.preventDefault();
|
|
9863
|
-
toggleGrid();
|
|
10149
|
+
store.toggleGrid();
|
|
9864
10150
|
return;
|
|
9865
10151
|
}
|
|
9866
10152
|
if (isCmd && (e.key === "=" || e.key === "+")) {
|
|
9867
10153
|
e.preventDefault();
|
|
9868
|
-
zoomIn();
|
|
10154
|
+
store.zoomIn();
|
|
9869
10155
|
return;
|
|
9870
10156
|
}
|
|
9871
10157
|
if (isCmd && e.key === "-") {
|
|
9872
10158
|
e.preventDefault();
|
|
9873
|
-
zoomOut();
|
|
10159
|
+
store.zoomOut();
|
|
9874
10160
|
return;
|
|
9875
10161
|
}
|
|
9876
10162
|
if (isCmd && e.key === "0") {
|
|
9877
10163
|
e.preventDefault();
|
|
9878
|
-
resetZoom();
|
|
10164
|
+
store.resetZoom();
|
|
9879
10165
|
return;
|
|
9880
10166
|
}
|
|
9881
10167
|
if (isCmd && e.shiftKey && e.key === "1") {
|
|
9882
10168
|
e.preventDefault();
|
|
9883
10169
|
if (containerRef == null ? void 0 : containerRef.current) {
|
|
9884
10170
|
const rect = containerRef.current.getBoundingClientRect();
|
|
9885
|
-
zoomToFit(rect.width, rect.height, void 0, { animate: true });
|
|
10171
|
+
store.zoomToFit(rect.width, rect.height, void 0, { animate: true });
|
|
9886
10172
|
}
|
|
9887
10173
|
return;
|
|
9888
10174
|
}
|
|
@@ -9890,14 +10176,14 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
9890
10176
|
e.preventDefault();
|
|
9891
10177
|
if (containerRef == null ? void 0 : containerRef.current) {
|
|
9892
10178
|
const rect = containerRef.current.getBoundingClientRect();
|
|
9893
|
-
zoomToSelection(rect.width, rect.height, { animate: true });
|
|
10179
|
+
store.zoomToSelection(rect.width, rect.height, { animate: true });
|
|
9894
10180
|
}
|
|
9895
10181
|
return;
|
|
9896
10182
|
}
|
|
9897
10183
|
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key) && !isCmd) {
|
|
9898
|
-
if (selectedIds.length > 0 && !linearEdit.isEditing) {
|
|
10184
|
+
if (store.selectedIds.length > 0 && !linearEdit.isEditing) {
|
|
9899
10185
|
e.preventDefault();
|
|
9900
|
-
const baseStep = showGrid ? GRID_SIZE : 1;
|
|
10186
|
+
const baseStep = store.showGrid ? GRID_SIZE : 1;
|
|
9901
10187
|
const step = e.shiftKey ? baseStep * 10 : baseStep;
|
|
9902
10188
|
const dx = e.key === "ArrowLeft" ? -step : e.key === "ArrowRight" ? step : 0;
|
|
9903
10189
|
const dy = e.key === "ArrowUp" ? -step : e.key === "ArrowDown" ? step : 0;
|
|
@@ -9906,7 +10192,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
9906
10192
|
}
|
|
9907
10193
|
}
|
|
9908
10194
|
if (isCmd && e.key === "c") {
|
|
9909
|
-
if (selectedIds.length > 0) {
|
|
10195
|
+
if (store.selectedIds.length > 0) {
|
|
9910
10196
|
e.preventDefault();
|
|
9911
10197
|
copyElements();
|
|
9912
10198
|
}
|
|
@@ -9916,34 +10202,31 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
9916
10202
|
return;
|
|
9917
10203
|
}
|
|
9918
10204
|
if (isCmd && e.key === "x") {
|
|
9919
|
-
if (selectedIds.length > 0) {
|
|
10205
|
+
if (store.selectedIds.length > 0) {
|
|
9920
10206
|
e.preventDefault();
|
|
9921
10207
|
copyElements();
|
|
9922
|
-
deleteElements(selectedIds);
|
|
10208
|
+
store.deleteElements(store.selectedIds);
|
|
9923
10209
|
}
|
|
9924
10210
|
return;
|
|
9925
10211
|
}
|
|
9926
10212
|
if (isCmd && e.key === "g" && !e.shiftKey) {
|
|
9927
10213
|
e.preventDefault();
|
|
9928
|
-
if (selectedIds.length >= 2) {
|
|
9929
|
-
|
|
9930
|
-
groupElements(selectedIds);
|
|
10214
|
+
if (store.selectedIds.length >= 2) {
|
|
10215
|
+
store.groupElements(store.selectedIds);
|
|
9931
10216
|
}
|
|
9932
10217
|
return;
|
|
9933
10218
|
}
|
|
9934
10219
|
if (isCmd && e.key === "g" && e.shiftKey) {
|
|
9935
10220
|
e.preventDefault();
|
|
9936
|
-
if (selectedIds.length > 0) {
|
|
9937
|
-
|
|
9938
|
-
ungroupElements(selectedIds);
|
|
10221
|
+
if (store.selectedIds.length > 0) {
|
|
10222
|
+
store.ungroupElements(store.selectedIds);
|
|
9939
10223
|
}
|
|
9940
10224
|
return;
|
|
9941
10225
|
}
|
|
9942
10226
|
if (isCmd && e.shiftKey && e.key === "l") {
|
|
9943
10227
|
e.preventDefault();
|
|
9944
|
-
if (selectedIds.length > 0) {
|
|
9945
|
-
|
|
9946
|
-
toggleLockElements(selectedIds);
|
|
10228
|
+
if (store.selectedIds.length > 0) {
|
|
10229
|
+
store.toggleLockElements(store.selectedIds);
|
|
9947
10230
|
}
|
|
9948
10231
|
return;
|
|
9949
10232
|
}
|
|
@@ -9953,46 +10236,20 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
9953
10236
|
linearEdit.exitEditMode();
|
|
9954
10237
|
return;
|
|
9955
10238
|
}
|
|
9956
|
-
clearSelection();
|
|
9957
|
-
setActiveTool("select");
|
|
10239
|
+
store.clearSelection();
|
|
10240
|
+
store.setActiveTool("select");
|
|
9958
10241
|
return;
|
|
9959
10242
|
}
|
|
9960
10243
|
if (isCmd && e.key === "a") {
|
|
9961
10244
|
e.preventDefault();
|
|
9962
|
-
const { elements
|
|
9963
|
-
|
|
10245
|
+
const { elements, setSelectedIds } = useCanvasStore.getState();
|
|
10246
|
+
setSelectedIds(elements.map((el) => el.id));
|
|
9964
10247
|
return;
|
|
9965
10248
|
}
|
|
9966
10249
|
};
|
|
9967
10250
|
window.addEventListener("keydown", handleKeyDown);
|
|
9968
10251
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
9969
|
-
}, [
|
|
9970
|
-
enabled,
|
|
9971
|
-
setActiveTool,
|
|
9972
|
-
undo,
|
|
9973
|
-
redo,
|
|
9974
|
-
selectedIds,
|
|
9975
|
-
elements,
|
|
9976
|
-
deleteElements,
|
|
9977
|
-
duplicateElements,
|
|
9978
|
-
bringToFront,
|
|
9979
|
-
sendToBack,
|
|
9980
|
-
bringForward,
|
|
9981
|
-
sendBackward,
|
|
9982
|
-
toggleGrid,
|
|
9983
|
-
showGrid,
|
|
9984
|
-
zoomIn,
|
|
9985
|
-
zoomOut,
|
|
9986
|
-
resetZoom,
|
|
9987
|
-
zoomToFit,
|
|
9988
|
-
zoomToSelection,
|
|
9989
|
-
containerRef,
|
|
9990
|
-
clearSelection,
|
|
9991
|
-
linearEdit,
|
|
9992
|
-
nudge,
|
|
9993
|
-
copyElements,
|
|
9994
|
-
pasteElements
|
|
9995
|
-
]);
|
|
10252
|
+
}, [enabled, containerRef, nudge, copyElements]);
|
|
9996
10253
|
}
|
|
9997
10254
|
function quickselect(arr, k, left = 0, right = arr.length - 1, compare = defaultCompare) {
|
|
9998
10255
|
while (right > left) {
|
|
@@ -10954,6 +11211,70 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
10954
11211
|
_config = void 0;
|
|
10955
11212
|
}
|
|
10956
11213
|
}
|
|
11214
|
+
const BOUND_TEXT_PADDING = 4;
|
|
11215
|
+
const CONTAINER_TYPES = /* @__PURE__ */ new Set([
|
|
11216
|
+
"rectangle",
|
|
11217
|
+
"ellipse",
|
|
11218
|
+
"diamond",
|
|
11219
|
+
"image"
|
|
11220
|
+
]);
|
|
11221
|
+
function computeBoundTextPosition(container, text) {
|
|
11222
|
+
const tw = Math.max(20, container.width - BOUND_TEXT_PADDING * 2);
|
|
11223
|
+
let ty;
|
|
11224
|
+
if (text.verticalAlign === "top") {
|
|
11225
|
+
ty = container.y + BOUND_TEXT_PADDING;
|
|
11226
|
+
} else if (text.verticalAlign === "bottom") {
|
|
11227
|
+
ty = container.y + container.height - text.height - BOUND_TEXT_PADDING;
|
|
11228
|
+
} else {
|
|
11229
|
+
ty = container.y + (container.height - text.height) / 2;
|
|
11230
|
+
}
|
|
11231
|
+
return { x: container.x + BOUND_TEXT_PADDING, y: ty, width: tw };
|
|
11232
|
+
}
|
|
11233
|
+
function syncAfterDrag(movedIds, elements, skipIds) {
|
|
11234
|
+
const elMap = /* @__PURE__ */ new Map();
|
|
11235
|
+
for (const el of elements) elMap.set(el.id, el);
|
|
11236
|
+
const updates = [];
|
|
11237
|
+
const processedConnectors = /* @__PURE__ */ new Set();
|
|
11238
|
+
for (const id of movedIds) {
|
|
11239
|
+
const connectors = findConnectorsForElement(id, elements);
|
|
11240
|
+
for (const conn of connectors) {
|
|
11241
|
+
if (processedConnectors.has(conn.id)) continue;
|
|
11242
|
+
processedConnectors.add(conn.id);
|
|
11243
|
+
if (skipIds == null ? void 0 : skipIds.has(conn.id)) continue;
|
|
11244
|
+
const freshConn = elMap.get(conn.id);
|
|
11245
|
+
if (!freshConn) continue;
|
|
11246
|
+
const recomputed = recomputeBoundPoints(freshConn, elements);
|
|
11247
|
+
if (recomputed) updates.push({ id: freshConn.id, updates: recomputed });
|
|
11248
|
+
}
|
|
11249
|
+
const el = elMap.get(id);
|
|
11250
|
+
if ((el == null ? void 0 : el.boundElements) && CONTAINER_TYPES.has(el.type)) {
|
|
11251
|
+
for (const be of el.boundElements) {
|
|
11252
|
+
if (be.type !== "text") continue;
|
|
11253
|
+
if (skipIds == null ? void 0 : skipIds.has(be.id)) continue;
|
|
11254
|
+
const txt = elMap.get(be.id);
|
|
11255
|
+
if (!txt) continue;
|
|
11256
|
+
updates.push({ id: be.id, updates: computeBoundTextPosition(el, txt) });
|
|
11257
|
+
}
|
|
11258
|
+
}
|
|
11259
|
+
}
|
|
11260
|
+
if (processedConnectors.size > 0 && updates.length > 0) {
|
|
11261
|
+
const tempMap = new Map(elMap);
|
|
11262
|
+
for (const u of updates) {
|
|
11263
|
+
const existing = tempMap.get(u.id);
|
|
11264
|
+
if (existing) {
|
|
11265
|
+
tempMap.set(u.id, { ...existing, ...u.updates });
|
|
11266
|
+
}
|
|
11267
|
+
}
|
|
11268
|
+
const labelUpdates = syncConnectorLabels(
|
|
11269
|
+
processedConnectors,
|
|
11270
|
+
tempMap
|
|
11271
|
+
);
|
|
11272
|
+
for (const lu of labelUpdates) {
|
|
11273
|
+
updates.push(lu);
|
|
11274
|
+
}
|
|
11275
|
+
}
|
|
11276
|
+
return { updates, processedConnectorIds: processedConnectors };
|
|
11277
|
+
}
|
|
10957
11278
|
const DEFAULT_THEME = {
|
|
10958
11279
|
canvasBackground: "#f8f9fa",
|
|
10959
11280
|
gridColor: "#e5e5e5",
|
|
@@ -11674,6 +11995,86 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
11674
11995
|
}) });
|
|
11675
11996
|
};
|
|
11676
11997
|
const CursorOverlay = React.memo(CursorOverlay$1);
|
|
11998
|
+
const AnnotationItem = React.memo(({
|
|
11999
|
+
element: el,
|
|
12000
|
+
viewport,
|
|
12001
|
+
renderAnnotation
|
|
12002
|
+
}) => {
|
|
12003
|
+
const screenX = el.x * viewport.scale + viewport.x;
|
|
12004
|
+
const screenY = el.y * viewport.scale + viewport.y;
|
|
12005
|
+
const screenW = el.width * viewport.scale;
|
|
12006
|
+
const screenH = el.height * viewport.scale;
|
|
12007
|
+
const ctx = {
|
|
12008
|
+
element: el,
|
|
12009
|
+
screenBounds: { x: screenX, y: screenY, width: screenW, height: screenH },
|
|
12010
|
+
scale: viewport.scale
|
|
12011
|
+
};
|
|
12012
|
+
const annotation = renderAnnotation(ctx);
|
|
12013
|
+
if (!annotation) return null;
|
|
12014
|
+
const transforms = [`scale(${viewport.scale})`];
|
|
12015
|
+
if (el.rotation) transforms.push(`rotate(${el.rotation}deg)`);
|
|
12016
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12017
|
+
"div",
|
|
12018
|
+
{
|
|
12019
|
+
style: {
|
|
12020
|
+
position: "absolute",
|
|
12021
|
+
left: screenX,
|
|
12022
|
+
top: screenY,
|
|
12023
|
+
width: el.width,
|
|
12024
|
+
// world-space; CSS scale handles screen sizing
|
|
12025
|
+
height: el.height,
|
|
12026
|
+
// world-space
|
|
12027
|
+
pointerEvents: "none",
|
|
12028
|
+
transform: transforms.join(" "),
|
|
12029
|
+
transformOrigin: "top left"
|
|
12030
|
+
},
|
|
12031
|
+
children: annotation
|
|
12032
|
+
}
|
|
12033
|
+
);
|
|
12034
|
+
});
|
|
12035
|
+
AnnotationItem.displayName = "AnnotationItem";
|
|
12036
|
+
const CONTAINER_STYLE = {
|
|
12037
|
+
position: "absolute",
|
|
12038
|
+
top: 0,
|
|
12039
|
+
left: 0,
|
|
12040
|
+
width: "100%",
|
|
12041
|
+
height: "100%",
|
|
12042
|
+
pointerEvents: "none",
|
|
12043
|
+
overflow: "hidden",
|
|
12044
|
+
zIndex: 10
|
|
12045
|
+
};
|
|
12046
|
+
const AnnotationsOverlay = React.memo(({
|
|
12047
|
+
elements,
|
|
12048
|
+
viewport,
|
|
12049
|
+
containerWidth,
|
|
12050
|
+
containerHeight,
|
|
12051
|
+
renderAnnotation
|
|
12052
|
+
}) => {
|
|
12053
|
+
const visibleElements = React.useMemo(() => {
|
|
12054
|
+
const margin = 100;
|
|
12055
|
+
return elements.filter((el) => {
|
|
12056
|
+
if (el.type === "text" && el.containerId) return false;
|
|
12057
|
+
if (!el.isVisible) return false;
|
|
12058
|
+
const sx = el.x * viewport.scale + viewport.x;
|
|
12059
|
+
const sy = el.y * viewport.scale + viewport.y;
|
|
12060
|
+
const sw = el.width * viewport.scale;
|
|
12061
|
+
const sh = el.height * viewport.scale;
|
|
12062
|
+
if (sx + sw < -margin || sy + sh < -margin) return false;
|
|
12063
|
+
if (sx > containerWidth + margin || sy > containerHeight + margin) return false;
|
|
12064
|
+
return true;
|
|
12065
|
+
});
|
|
12066
|
+
}, [elements, viewport.scale, viewport.x, viewport.y, containerWidth, containerHeight]);
|
|
12067
|
+
if (visibleElements.length === 0) return null;
|
|
12068
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: CONTAINER_STYLE, children: visibleElements.map((el) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12069
|
+
AnnotationItem,
|
|
12070
|
+
{
|
|
12071
|
+
element: el,
|
|
12072
|
+
viewport,
|
|
12073
|
+
renderAnnotation
|
|
12074
|
+
},
|
|
12075
|
+
el.id
|
|
12076
|
+
)) });
|
|
12077
|
+
});
|
|
11677
12078
|
Konva.showWarnings = false;
|
|
11678
12079
|
function arraysShallowEqual(a, b) {
|
|
11679
12080
|
if (a.length !== b.length) return false;
|
|
@@ -11700,9 +12101,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
11700
12101
|
onGroupDragEnd
|
|
11701
12102
|
}) => {
|
|
11702
12103
|
const layerRef = React.useRef(null);
|
|
11703
|
-
React.
|
|
12104
|
+
React.useLayoutEffect(() => {
|
|
11704
12105
|
const layer = layerRef.current;
|
|
11705
|
-
if (!layer
|
|
12106
|
+
if (!layer) return;
|
|
12107
|
+
layer.clearCache();
|
|
12108
|
+
if (elements.length === 0) return;
|
|
11706
12109
|
const dpr2 = window.devicePixelRatio || 1;
|
|
11707
12110
|
const cachePixelRatio = dpr2 * Math.max(1, viewportScale);
|
|
11708
12111
|
const rafId = requestAnimationFrame(() => {
|
|
@@ -11721,7 +12124,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
11721
12124
|
});
|
|
11722
12125
|
return () => {
|
|
11723
12126
|
cancelAnimationFrame(rafId);
|
|
11724
|
-
layer.clearCache();
|
|
11725
12127
|
};
|
|
11726
12128
|
}, [elements, viewportScale, autoEditTextId]);
|
|
11727
12129
|
const { ungrouped, groups } = React.useMemo(() => {
|
|
@@ -11872,6 +12274,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
11872
12274
|
className,
|
|
11873
12275
|
contextMenuItems: contextMenuItemsProp,
|
|
11874
12276
|
renderContextMenu,
|
|
12277
|
+
renderAnnotation,
|
|
11875
12278
|
collaboration: collaborationConfig,
|
|
11876
12279
|
workerConfig,
|
|
11877
12280
|
customElementTypes
|
|
@@ -11930,7 +12333,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
11930
12333
|
const { isDraggingPoint: isLinearDragging, elementId: linearEditId } = linearEdit;
|
|
11931
12334
|
const prevResolvedRef = React.useRef([]);
|
|
11932
12335
|
const resolvedElements = React.useMemo(() => {
|
|
12336
|
+
var _a, _b;
|
|
11933
12337
|
let result = null;
|
|
12338
|
+
const changedConnectorIds = /* @__PURE__ */ new Set();
|
|
11934
12339
|
for (let i = 0; i < elements.length; i++) {
|
|
11935
12340
|
const el = elements[i];
|
|
11936
12341
|
if (el.type !== "line" && el.type !== "arrow") {
|
|
@@ -11939,10 +12344,18 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
11939
12344
|
}
|
|
11940
12345
|
const conn = el;
|
|
11941
12346
|
if (!conn.startBinding && !conn.endBinding) {
|
|
12347
|
+
if ((_a = conn.boundElements) == null ? void 0 : _a.some((be) => be.type === "text")) {
|
|
12348
|
+
changedConnectorIds.add(conn.id);
|
|
12349
|
+
if (!result) result = elements.slice(0, i);
|
|
12350
|
+
}
|
|
11942
12351
|
if (result) result[i] = el;
|
|
11943
12352
|
continue;
|
|
11944
12353
|
}
|
|
11945
12354
|
if (isLinearDragging && linearEditId === el.id) {
|
|
12355
|
+
if ((_b = conn.boundElements) == null ? void 0 : _b.some((be) => be.type === "text")) {
|
|
12356
|
+
if (!result) result = elements.slice(0, i);
|
|
12357
|
+
changedConnectorIds.add(conn.id);
|
|
12358
|
+
}
|
|
11946
12359
|
if (result) result[i] = el;
|
|
11947
12360
|
continue;
|
|
11948
12361
|
}
|
|
@@ -11952,10 +12365,31 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
11952
12365
|
result = elements.slice(0, i);
|
|
11953
12366
|
}
|
|
11954
12367
|
result[i] = { ...conn, ...recomputed };
|
|
12368
|
+
changedConnectorIds.add(conn.id);
|
|
11955
12369
|
} else {
|
|
11956
12370
|
if (result) result[i] = el;
|
|
11957
12371
|
}
|
|
11958
12372
|
}
|
|
12373
|
+
if (changedConnectorIds.size > 0 && result) {
|
|
12374
|
+
const patchMap = /* @__PURE__ */ new Map();
|
|
12375
|
+
for (const el of result) patchMap.set(el.id, el);
|
|
12376
|
+
for (const connId of changedConnectorIds) {
|
|
12377
|
+
const conn = patchMap.get(connId);
|
|
12378
|
+
if (!(conn == null ? void 0 : conn.boundElements)) continue;
|
|
12379
|
+
for (const be of conn.boundElements) {
|
|
12380
|
+
if (be.type !== "text") continue;
|
|
12381
|
+
const txtIdx = result.findIndex((e) => e.id === be.id);
|
|
12382
|
+
if (txtIdx === -1) continue;
|
|
12383
|
+
const txt = result[txtIdx];
|
|
12384
|
+
const textW = Math.max(10, txt.width || 60);
|
|
12385
|
+
const textH = txt.height || 30;
|
|
12386
|
+
const pos = computeConnectorLabelPosition(conn, textW, textH);
|
|
12387
|
+
if (Math.abs(txt.x - pos.x) > 0.01 || Math.abs(txt.y - pos.y) > 0.01) {
|
|
12388
|
+
result[txtIdx] = { ...txt, x: pos.x, y: pos.y };
|
|
12389
|
+
}
|
|
12390
|
+
}
|
|
12391
|
+
}
|
|
12392
|
+
}
|
|
11959
12393
|
const finalResult = result ?? elements;
|
|
11960
12394
|
const prev = prevResolvedRef.current;
|
|
11961
12395
|
if (finalResult.length === prev.length) {
|
|
@@ -11987,7 +12421,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
11987
12421
|
const prevStaticRef = React.useRef([]);
|
|
11988
12422
|
const prevInteractiveRef = React.useRef([]);
|
|
11989
12423
|
const { staticElements, interactiveElements } = React.useMemo(() => {
|
|
11990
|
-
var _a, _b;
|
|
12424
|
+
var _a, _b, _c, _d;
|
|
11991
12425
|
let effectiveSelected = drawingElementId ? /* @__PURE__ */ new Set([...selectedIdsSet, drawingElementId]) : selectedIdsSet;
|
|
11992
12426
|
if (effectiveSelected.size > 0) {
|
|
11993
12427
|
const expanded = new Set(effectiveSelected);
|
|
@@ -12001,6 +12435,32 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12001
12435
|
}
|
|
12002
12436
|
}
|
|
12003
12437
|
}
|
|
12438
|
+
for (const el of visibleElements) {
|
|
12439
|
+
if (!expanded.has(el.id)) continue;
|
|
12440
|
+
if (el.boundElements) {
|
|
12441
|
+
for (const be of el.boundElements) {
|
|
12442
|
+
if (be.type === "text") expanded.add(be.id);
|
|
12443
|
+
}
|
|
12444
|
+
}
|
|
12445
|
+
if (el.type === "text" && el.containerId) {
|
|
12446
|
+
expanded.add(el.containerId);
|
|
12447
|
+
}
|
|
12448
|
+
}
|
|
12449
|
+
for (const el of visibleElements) {
|
|
12450
|
+
if (el.type !== "line" && el.type !== "arrow") continue;
|
|
12451
|
+
if (expanded.has(el.id)) continue;
|
|
12452
|
+
const conn = el;
|
|
12453
|
+
const startBound = (_c = conn.startBinding) == null ? void 0 : _c.elementId;
|
|
12454
|
+
const endBound = (_d = conn.endBinding) == null ? void 0 : _d.elementId;
|
|
12455
|
+
if (startBound && expanded.has(startBound) || endBound && expanded.has(endBound)) {
|
|
12456
|
+
expanded.add(el.id);
|
|
12457
|
+
if (el.boundElements) {
|
|
12458
|
+
for (const be of el.boundElements) {
|
|
12459
|
+
if (be.type === "text") expanded.add(be.id);
|
|
12460
|
+
}
|
|
12461
|
+
}
|
|
12462
|
+
}
|
|
12463
|
+
}
|
|
12004
12464
|
if (expanded.size !== effectiveSelected.size) {
|
|
12005
12465
|
effectiveSelected = expanded;
|
|
12006
12466
|
}
|
|
@@ -12159,7 +12619,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12159
12619
|
const files = getImageFilesFromDataTransfer(e.dataTransfer);
|
|
12160
12620
|
if (files.length === 0) return;
|
|
12161
12621
|
const rect = container.getBoundingClientRect();
|
|
12162
|
-
stageRef.current;
|
|
12163
12622
|
const vp = useCanvasStore.getState().viewport;
|
|
12164
12623
|
const dropX = (e.clientX - rect.left - vp.x) / vp.scale;
|
|
12165
12624
|
const dropY = (e.clientY - rect.top - vp.y) / vp.scale;
|
|
@@ -12325,6 +12784,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12325
12784
|
if (!pos) return;
|
|
12326
12785
|
if (contextMenu) setContextMenu(null);
|
|
12327
12786
|
if (ctx.activeTool === "hand" || isSpacePanning) return;
|
|
12787
|
+
if (editingTextId) {
|
|
12788
|
+
const activeEl = document.activeElement;
|
|
12789
|
+
if ((activeEl == null ? void 0 : activeEl.tagName) === "TEXTAREA") {
|
|
12790
|
+
activeEl.blur();
|
|
12791
|
+
}
|
|
12792
|
+
}
|
|
12328
12793
|
const handler = getToolHandler(ctx.activeTool);
|
|
12329
12794
|
handler == null ? void 0 : handler.onMouseDown(e, pos, ctx);
|
|
12330
12795
|
if (currentElementIdRef.current) {
|
|
@@ -12332,7 +12797,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12332
12797
|
}
|
|
12333
12798
|
},
|
|
12334
12799
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
12335
|
-
[readOnly, contextMenu, isSpacePanning]
|
|
12800
|
+
[readOnly, contextMenu, isSpacePanning, editingTextId]
|
|
12336
12801
|
);
|
|
12337
12802
|
const handleMouseMoveCore = React.useCallback((e) => {
|
|
12338
12803
|
if (spaceKeyRef.current) return;
|
|
@@ -12379,7 +12844,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12379
12844
|
if (!stage) return;
|
|
12380
12845
|
const pointer = stage.getPointerPosition();
|
|
12381
12846
|
if (!pointer) return;
|
|
12382
|
-
const scaleBy = 1.
|
|
12847
|
+
const scaleBy = 1.02;
|
|
12383
12848
|
const dir2 = e.evt.deltaY > 0 ? -1 : 1;
|
|
12384
12849
|
const targetScale = Math.min(MAX_ZOOM, Math.max(
|
|
12385
12850
|
MIN_ZOOM,
|
|
@@ -12389,13 +12854,14 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12389
12854
|
},
|
|
12390
12855
|
[viewport, setViewport]
|
|
12391
12856
|
);
|
|
12392
|
-
const
|
|
12857
|
+
const handleStageDragMove = React.useCallback(
|
|
12393
12858
|
(e) => {
|
|
12394
12859
|
if (activeTool !== "hand" && !spaceKeyRef.current && !isSpacePanning) return;
|
|
12395
12860
|
setViewport({ x: e.target.x(), y: e.target.y() });
|
|
12396
12861
|
},
|
|
12397
12862
|
[activeTool, setViewport, isSpacePanning]
|
|
12398
12863
|
);
|
|
12864
|
+
const handleStageDragEnd = handleStageDragMove;
|
|
12399
12865
|
const handleElementSelect = React.useCallback(
|
|
12400
12866
|
(id) => {
|
|
12401
12867
|
var _a;
|
|
@@ -12443,6 +12909,32 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12443
12909
|
useCanvasStore.getState().batchUpdateElements(updates);
|
|
12444
12910
|
}, []);
|
|
12445
12911
|
const unboundConnectorIdsRef = React.useRef(/* @__PURE__ */ new Set());
|
|
12912
|
+
const syncBoundTextNodes = React.useCallback(
|
|
12913
|
+
(el, newX, newY, newW, newH) => {
|
|
12914
|
+
var _a, _b;
|
|
12915
|
+
if (!el.boundElements || !stageRef.current) return;
|
|
12916
|
+
if (!CONTAINER_TYPES.has(el.type)) return;
|
|
12917
|
+
const elements2 = useCanvasStore.getState().elements;
|
|
12918
|
+
const shapeW = newW ?? el.width;
|
|
12919
|
+
const shapeH = newH ?? el.height;
|
|
12920
|
+
for (const be of el.boundElements) {
|
|
12921
|
+
if (be.type !== "text") continue;
|
|
12922
|
+
const txt = elements2.find((e) => e.id === be.id);
|
|
12923
|
+
if (!txt) continue;
|
|
12924
|
+
const textNode = stageRef.current.findOne("#" + be.id);
|
|
12925
|
+
if (!textNode) continue;
|
|
12926
|
+
const textNodeH = ((_a = textNode.height) == null ? void 0 : _a.call(textNode)) ?? txt.height;
|
|
12927
|
+
const pos = computeBoundTextPosition(
|
|
12928
|
+
{ x: newX, y: newY, width: shapeW, height: shapeH },
|
|
12929
|
+
{ height: textNodeH, verticalAlign: txt.verticalAlign }
|
|
12930
|
+
);
|
|
12931
|
+
(_b = textNode.width) == null ? void 0 : _b.call(textNode, pos.width);
|
|
12932
|
+
textNode.x(pos.x);
|
|
12933
|
+
textNode.y(pos.y);
|
|
12934
|
+
}
|
|
12935
|
+
},
|
|
12936
|
+
[]
|
|
12937
|
+
);
|
|
12446
12938
|
const handleElementDragMove = React.useCallback(
|
|
12447
12939
|
(id, updates) => {
|
|
12448
12940
|
if (readOnly) return;
|
|
@@ -12453,6 +12945,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12453
12945
|
const { elements: elements2, selectedIds: selectedIds2 } = useCanvasStore.getState();
|
|
12454
12946
|
if (selectedIds2.length > MULTI_DRAG_STORE_SKIP_THRESHOLD) {
|
|
12455
12947
|
isMultiDragSkippingRef.current = true;
|
|
12948
|
+
const el2 = elements2.find((e) => e.id === id);
|
|
12949
|
+
if (el2) {
|
|
12950
|
+
const nx = updates.x ?? el2.x;
|
|
12951
|
+
const ny = updates.y ?? el2.y;
|
|
12952
|
+
syncBoundTextNodes(el2, nx, ny);
|
|
12953
|
+
}
|
|
12456
12954
|
return;
|
|
12457
12955
|
}
|
|
12458
12956
|
isMultiDragSkippingRef.current = false;
|
|
@@ -12479,12 +12977,19 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12479
12977
|
}
|
|
12480
12978
|
if (!dragBatchRef.current) dragBatchRef.current = /* @__PURE__ */ new Map();
|
|
12481
12979
|
dragBatchRef.current.set(id, updates);
|
|
12980
|
+
if (el) {
|
|
12981
|
+
const nx = updates.x ?? el.x;
|
|
12982
|
+
const ny = updates.y ?? el.y;
|
|
12983
|
+
const nw = updates.width;
|
|
12984
|
+
const nh = updates.height;
|
|
12985
|
+
syncBoundTextNodes(el, nx, ny, nw, nh);
|
|
12986
|
+
}
|
|
12482
12987
|
if (!dragFlushScheduledRef.current) {
|
|
12483
12988
|
dragFlushScheduledRef.current = true;
|
|
12484
12989
|
queueMicrotask(flushDragBatch);
|
|
12485
12990
|
}
|
|
12486
12991
|
},
|
|
12487
|
-
[readOnly, flushDragBatch]
|
|
12992
|
+
[readOnly, flushDragBatch, syncBoundTextNodes]
|
|
12488
12993
|
);
|
|
12489
12994
|
const handleDragSnap = React.useCallback(
|
|
12490
12995
|
(id, bounds) => {
|
|
@@ -12516,39 +13021,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12516
13021
|
store2.batchUpdateElements(entries.map(([id, upd]) => ({ id, updates: upd })));
|
|
12517
13022
|
setAlignGuides([]);
|
|
12518
13023
|
const freshElements = useCanvasStore.getState().elements;
|
|
12519
|
-
const
|
|
12520
|
-
for (const
|
|
12521
|
-
const
|
|
12522
|
-
|
|
12523
|
-
|
|
12524
|
-
unboundConnectorIdsRef.current.delete(id);
|
|
12525
|
-
const connectors = findConnectorsForElement(id, freshElements);
|
|
12526
|
-
for (const conn of connectors) {
|
|
12527
|
-
if (processedConnectors.has(conn.id)) continue;
|
|
12528
|
-
processedConnectors.add(conn.id);
|
|
12529
|
-
const freshConn = elMap.get(conn.id);
|
|
12530
|
-
if (!freshConn) continue;
|
|
12531
|
-
const recomputed = recomputeBoundPoints(freshConn, freshElements);
|
|
12532
|
-
if (recomputed) connectorUpdates.push({ id: freshConn.id, updates: recomputed });
|
|
12533
|
-
}
|
|
12534
|
-
const el = elMap.get(id);
|
|
12535
|
-
if ((el == null ? void 0 : el.boundElements) && ["rectangle", "ellipse", "diamond", "image"].includes(el.type)) {
|
|
12536
|
-
const PADDING2 = 4;
|
|
12537
|
-
for (const be of el.boundElements) {
|
|
12538
|
-
if (be.type !== "text") continue;
|
|
12539
|
-
const txt = elMap.get(be.id);
|
|
12540
|
-
if (!txt) continue;
|
|
12541
|
-
const tw = Math.max(20, el.width - PADDING2 * 2);
|
|
12542
|
-
let ty;
|
|
12543
|
-
if (txt.verticalAlign === "top") ty = el.y + PADDING2;
|
|
12544
|
-
else if (txt.verticalAlign === "bottom") ty = el.y + el.height - txt.height - PADDING2;
|
|
12545
|
-
else ty = el.y + (el.height - txt.height) / 2;
|
|
12546
|
-
connectorUpdates.push({ id: be.id, updates: { x: el.x + PADDING2, y: ty, width: tw } });
|
|
12547
|
-
}
|
|
12548
|
-
}
|
|
12549
|
-
}
|
|
12550
|
-
if (connectorUpdates.length > 0) {
|
|
12551
|
-
useCanvasStore.getState().batchUpdateElements(connectorUpdates);
|
|
13024
|
+
const movedIds = entries.map(([id]) => id);
|
|
13025
|
+
for (const id of movedIds) unboundConnectorIdsRef.current.delete(id);
|
|
13026
|
+
const { updates: syncUpdates } = syncAfterDrag(movedIds, freshElements);
|
|
13027
|
+
if (syncUpdates.length > 0) {
|
|
13028
|
+
useCanvasStore.getState().batchUpdateElements(syncUpdates);
|
|
12552
13029
|
}
|
|
12553
13030
|
useCanvasStore.getState().pushHistory();
|
|
12554
13031
|
if (savedPixelRatioRef.current !== null) {
|
|
@@ -12573,46 +13050,22 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12573
13050
|
setAlignGuides([]);
|
|
12574
13051
|
unboundConnectorIdsRef.current.delete(id);
|
|
12575
13052
|
const freshElements = useCanvasStore.getState().elements;
|
|
13053
|
+
const { updates: syncUpdates } = syncAfterDrag([id], freshElements);
|
|
13054
|
+
for (const su of syncUpdates) updateElement(su.id, su.updates);
|
|
12576
13055
|
const elMap = /* @__PURE__ */ new Map();
|
|
12577
|
-
for (const e of
|
|
12578
|
-
const connectors = findConnectorsForElement(id, freshElements);
|
|
12579
|
-
for (const conn of connectors) {
|
|
12580
|
-
const freshConn = elMap.get(conn.id);
|
|
12581
|
-
if (!freshConn) continue;
|
|
12582
|
-
const recomputed = recomputeBoundPoints(freshConn, freshElements);
|
|
12583
|
-
if (recomputed) updateElement(freshConn.id, recomputed);
|
|
12584
|
-
}
|
|
13056
|
+
for (const e of useCanvasStore.getState().elements) elMap.set(e.id, e);
|
|
12585
13057
|
const el = elMap.get(id);
|
|
12586
|
-
if ((el == null ? void 0 : el.boundElements) && ["rectangle", "ellipse", "diamond", "image"].includes(el.type)) {
|
|
12587
|
-
const PADDING2 = 4;
|
|
12588
|
-
for (const be of el.boundElements) {
|
|
12589
|
-
if (be.type !== "text") continue;
|
|
12590
|
-
const txt = elMap.get(be.id);
|
|
12591
|
-
if (!txt) continue;
|
|
12592
|
-
const tw = Math.max(20, el.width - PADDING2 * 2);
|
|
12593
|
-
let ty;
|
|
12594
|
-
if (txt.verticalAlign === "top") ty = el.y + PADDING2;
|
|
12595
|
-
else if (txt.verticalAlign === "bottom") ty = el.y + el.height - txt.height - PADDING2;
|
|
12596
|
-
else ty = el.y + (el.height - txt.height) / 2;
|
|
12597
|
-
updateElement(be.id, { x: el.x + PADDING2, y: ty, width: tw });
|
|
12598
|
-
}
|
|
12599
|
-
}
|
|
12600
13058
|
if ((el == null ? void 0 : el.type) === "text") {
|
|
12601
13059
|
const txt = el;
|
|
12602
13060
|
if (txt.containerId) {
|
|
12603
13061
|
const ctr = elMap.get(txt.containerId);
|
|
12604
|
-
if (ctr &&
|
|
12605
|
-
const
|
|
12606
|
-
const minH = txt.height + PADDING2 * 2;
|
|
13062
|
+
if (ctr && CONTAINER_TYPES.has(ctr.type)) {
|
|
13063
|
+
const minH = txt.height + BOUND_TEXT_PADDING * 2;
|
|
12607
13064
|
if (ctr.height < minH) {
|
|
12608
13065
|
updateElement(ctr.id, { height: minH });
|
|
12609
13066
|
const updatedElements = useCanvasStore.getState().elements;
|
|
12610
|
-
|
|
12611
|
-
|
|
12612
|
-
if (!fc) continue;
|
|
12613
|
-
const r = recomputeBoundPoints(fc, updatedElements);
|
|
12614
|
-
if (r) updateElement(fc.id, r);
|
|
12615
|
-
}
|
|
13067
|
+
const { updates: resizeSync } = syncAfterDrag([ctr.id], updatedElements);
|
|
13068
|
+
for (const su of resizeSync) updateElement(su.id, su.updates);
|
|
12616
13069
|
}
|
|
12617
13070
|
}
|
|
12618
13071
|
}
|
|
@@ -12643,41 +13096,15 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12643
13096
|
}));
|
|
12644
13097
|
store2.batchUpdateElements(posUpdates);
|
|
12645
13098
|
const freshElements = useCanvasStore.getState().elements;
|
|
12646
|
-
const elMap = /* @__PURE__ */ new Map();
|
|
12647
|
-
for (const el of freshElements) elMap.set(el.id, el);
|
|
12648
13099
|
const memberIds = new Set(members.map((m) => m.id));
|
|
12649
|
-
const
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
const freshConn = elMap.get(conn.id);
|
|
12658
|
-
if (!freshConn) continue;
|
|
12659
|
-
const recomputed = recomputeBoundPoints(freshConn, freshElements);
|
|
12660
|
-
if (recomputed) connectorUpdates.push({ id: freshConn.id, updates: recomputed });
|
|
12661
|
-
}
|
|
12662
|
-
const el = elMap.get(member.id);
|
|
12663
|
-
if ((el == null ? void 0 : el.boundElements) && ["rectangle", "ellipse", "diamond", "image"].includes(el.type)) {
|
|
12664
|
-
const PADDING2 = 4;
|
|
12665
|
-
for (const be of el.boundElements) {
|
|
12666
|
-
if (be.type !== "text") continue;
|
|
12667
|
-
if (memberIds.has(be.id)) continue;
|
|
12668
|
-
const txt = elMap.get(be.id);
|
|
12669
|
-
if (!txt) continue;
|
|
12670
|
-
const tw = Math.max(20, el.width - PADDING2 * 2);
|
|
12671
|
-
let ty;
|
|
12672
|
-
if (txt.verticalAlign === "top") ty = el.y + PADDING2;
|
|
12673
|
-
else if (txt.verticalAlign === "bottom") ty = el.y + el.height - txt.height - PADDING2;
|
|
12674
|
-
else ty = el.y + (el.height - txt.height) / 2;
|
|
12675
|
-
connectorUpdates.push({ id: be.id, updates: { x: el.x + PADDING2, y: ty, width: tw } });
|
|
12676
|
-
}
|
|
12677
|
-
}
|
|
12678
|
-
}
|
|
12679
|
-
if (connectorUpdates.length > 0) {
|
|
12680
|
-
useCanvasStore.getState().batchUpdateElements(connectorUpdates);
|
|
13100
|
+
const { updates: syncUpdates } = syncAfterDrag(
|
|
13101
|
+
memberIds,
|
|
13102
|
+
freshElements,
|
|
13103
|
+
memberIds
|
|
13104
|
+
// skip group-internal connectors & text (already moved)
|
|
13105
|
+
);
|
|
13106
|
+
if (syncUpdates.length > 0) {
|
|
13107
|
+
useCanvasStore.getState().batchUpdateElements(syncUpdates);
|
|
12681
13108
|
}
|
|
12682
13109
|
store2.pushHistory();
|
|
12683
13110
|
},
|
|
@@ -12708,24 +13135,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12708
13135
|
}
|
|
12709
13136
|
const textId = generateId();
|
|
12710
13137
|
const conn = el;
|
|
12711
|
-
const
|
|
12712
|
-
const startPt = { x: pts[0], y: pts[1] };
|
|
12713
|
-
const endPt = { x: pts[pts.length - 2], y: pts[pts.length - 1] };
|
|
12714
|
-
let midX, midY;
|
|
12715
|
-
if (conn.lineType === "curved") {
|
|
12716
|
-
const cp = computeCurveControlPoint(startPt, endPt, conn.curvature ?? CURVE_RATIO);
|
|
12717
|
-
const mid = quadBezierAt(startPt, cp, endPt, 0.5);
|
|
12718
|
-
midX = conn.x + mid.x;
|
|
12719
|
-
midY = conn.y + mid.y;
|
|
12720
|
-
} else {
|
|
12721
|
-
midX = conn.x + (startPt.x + endPt.x) / 2;
|
|
12722
|
-
midY = conn.y + (startPt.y + endPt.y) / 2;
|
|
12723
|
-
}
|
|
13138
|
+
const labelPos = computeConnectorLabelPosition(conn, 100, 30);
|
|
12724
13139
|
const textEl = {
|
|
12725
13140
|
id: textId,
|
|
12726
13141
|
type: "text",
|
|
12727
|
-
x:
|
|
12728
|
-
y:
|
|
13142
|
+
x: labelPos.x,
|
|
13143
|
+
y: labelPos.y,
|
|
12729
13144
|
width: 100,
|
|
12730
13145
|
height: 30,
|
|
12731
13146
|
rotation: 0,
|
|
@@ -12751,7 +13166,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12751
13166
|
if (el.type === "rectangle" || el.type === "ellipse" || el.type === "diamond" || el.type === "image") {
|
|
12752
13167
|
const existingTextBinding = (_b = el.boundElements) == null ? void 0 : _b.find((be) => be.type === "text");
|
|
12753
13168
|
if (existingTextBinding) {
|
|
12754
|
-
setSel([existingTextBinding.id]);
|
|
13169
|
+
setSel([existingTextBinding.id, id]);
|
|
12755
13170
|
setAutoEditTextId(existingTextBinding.id);
|
|
12756
13171
|
return;
|
|
12757
13172
|
}
|
|
@@ -12779,7 +13194,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12779
13194
|
update(id, {
|
|
12780
13195
|
boundElements: [...currentBound, { id: textId, type: "text" }]
|
|
12781
13196
|
});
|
|
12782
|
-
setSel([textId]);
|
|
13197
|
+
setSel([textId, id]);
|
|
12783
13198
|
setAutoEditTextId(textId);
|
|
12784
13199
|
return;
|
|
12785
13200
|
}
|
|
@@ -12830,11 +13245,17 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12830
13245
|
(id, isEmpty) => {
|
|
12831
13246
|
setEditingTextId(null);
|
|
12832
13247
|
setAutoEditTextId(null);
|
|
13248
|
+
const {
|
|
13249
|
+
elements: els,
|
|
13250
|
+
selectedIds: currentSel,
|
|
13251
|
+
setSelectedIds: setSel,
|
|
13252
|
+
updateElement: update,
|
|
13253
|
+
deleteElements: del
|
|
13254
|
+
} = useCanvasStore.getState();
|
|
13255
|
+
const textEl = els.find((e) => e.id === id);
|
|
13256
|
+
const containerId = (textEl == null ? void 0 : textEl.type) === "text" ? textEl.containerId : null;
|
|
12833
13257
|
if (isEmpty) {
|
|
12834
|
-
|
|
12835
|
-
const textEl = els.find((e) => e.id === id);
|
|
12836
|
-
if ((textEl == null ? void 0 : textEl.type) === "text" && textEl.containerId) {
|
|
12837
|
-
const containerId = textEl.containerId;
|
|
13258
|
+
if (containerId) {
|
|
12838
13259
|
const container = els.find((e) => e.id === containerId);
|
|
12839
13260
|
if (container == null ? void 0 : container.boundElements) {
|
|
12840
13261
|
update(containerId, {
|
|
@@ -12847,6 +13268,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12847
13268
|
} else {
|
|
12848
13269
|
useCanvasStore.getState().pushHistory();
|
|
12849
13270
|
}
|
|
13271
|
+
if (containerId && currentSel.includes(containerId)) {
|
|
13272
|
+
setSel([containerId]);
|
|
13273
|
+
} else if (containerId) {
|
|
13274
|
+
setSel(currentSel.filter((sid) => sid !== id));
|
|
13275
|
+
}
|
|
12850
13276
|
},
|
|
12851
13277
|
[onElementDelete]
|
|
12852
13278
|
);
|
|
@@ -12914,6 +13340,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12914
13340
|
);
|
|
12915
13341
|
const contextMenuItems = React.useMemo(() => {
|
|
12916
13342
|
var _a;
|
|
13343
|
+
if (!contextMenu) return [];
|
|
12917
13344
|
const hasSelection = selectedIds.length > 0;
|
|
12918
13345
|
const isMac = navigator.platform.includes("Mac");
|
|
12919
13346
|
const mod = isMac ? "⌘" : "Ctrl+";
|
|
@@ -13215,6 +13642,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
13215
13642
|
onMouseMove: handleMouseMove,
|
|
13216
13643
|
onMouseUp: handleMouseUp,
|
|
13217
13644
|
onWheel: handleWheel,
|
|
13645
|
+
onDragMove: handleStageDragMove,
|
|
13218
13646
|
onDragEnd: handleStageDragEnd,
|
|
13219
13647
|
onTouchStart: handleMouseDown,
|
|
13220
13648
|
onTouchMove: handleMouseMove,
|
|
@@ -13276,6 +13704,10 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
13276
13704
|
if (el.type === "line" || el.type === "arrow") return false;
|
|
13277
13705
|
if (el.type === "text" && el.containerId) return false;
|
|
13278
13706
|
if (sid === editingTextId) return false;
|
|
13707
|
+
if (editingTextId) {
|
|
13708
|
+
const editingEl = resolvedElementMap.get(editingTextId);
|
|
13709
|
+
if ((editingEl == null ? void 0 : editingEl.type) === "text" && editingEl.containerId === sid) return false;
|
|
13710
|
+
}
|
|
13279
13711
|
return true;
|
|
13280
13712
|
});
|
|
13281
13713
|
if (transformableIds.length === 0) return null;
|
|
@@ -13391,6 +13823,16 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
13391
13823
|
theme
|
|
13392
13824
|
}
|
|
13393
13825
|
)),
|
|
13826
|
+
renderAnnotation && /* @__PURE__ */ jsxRuntime.jsx(
|
|
13827
|
+
AnnotationsOverlay,
|
|
13828
|
+
{
|
|
13829
|
+
elements: resolvedElements,
|
|
13830
|
+
viewport,
|
|
13831
|
+
containerWidth: dimensions.width,
|
|
13832
|
+
containerHeight: dimensions.height,
|
|
13833
|
+
renderAnnotation
|
|
13834
|
+
}
|
|
13835
|
+
),
|
|
13394
13836
|
showStatusBar && /* @__PURE__ */ jsxRuntime.jsx(StatusBar, { theme })
|
|
13395
13837
|
]
|
|
13396
13838
|
}
|
|
@@ -13398,9 +13840,17 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
13398
13840
|
});
|
|
13399
13841
|
FlowCanvas.displayName = "FlowCanvas";
|
|
13400
13842
|
const StatusBar = React.memo(({ theme }) => {
|
|
13401
|
-
const elementCount = useCanvasStore(
|
|
13843
|
+
const elementCount = useCanvasStore(
|
|
13844
|
+
(s) => s.elements.filter((el) => !(el.type === "text" && el.containerId)).length
|
|
13845
|
+
);
|
|
13402
13846
|
const activeTool = useCanvasStore((s) => s.activeTool);
|
|
13403
|
-
const selectedCount = useCanvasStore((s) =>
|
|
13847
|
+
const selectedCount = useCanvasStore((s) => {
|
|
13848
|
+
const els = s.elements;
|
|
13849
|
+
return s.selectedIds.filter((id) => {
|
|
13850
|
+
const el = els.find((e) => e.id === id);
|
|
13851
|
+
return el && !(el.type === "text" && el.containerId);
|
|
13852
|
+
}).length;
|
|
13853
|
+
});
|
|
13404
13854
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13405
13855
|
"div",
|
|
13406
13856
|
{
|
|
@@ -13605,6 +14055,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
13605
14055
|
}
|
|
13606
14056
|
const DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
13607
14057
|
const BASE = DIGITS.length;
|
|
14058
|
+
function trimTrailingZeros(s) {
|
|
14059
|
+
let end = s.length;
|
|
14060
|
+
while (end > 0 && s[end - 1] === "0") end--;
|
|
14061
|
+
return end === s.length ? s : s.slice(0, end);
|
|
14062
|
+
}
|
|
13608
14063
|
const SMALLEST_CHAR = DIGITS[0];
|
|
13609
14064
|
const LARGEST_CHAR = DIGITS[BASE - 1];
|
|
13610
14065
|
function midChar(a, b) {
|
|
@@ -13677,7 +14132,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
13677
14132
|
if (mid !== null) {
|
|
13678
14133
|
return commonPrefix + mid;
|
|
13679
14134
|
}
|
|
13680
|
-
return commonPrefix + aPad[i] + incrementKey(aPad.slice(i + 1)
|
|
14135
|
+
return commonPrefix + aPad[i] + incrementKey(trimTrailingZeros(aPad.slice(i + 1)) || SMALLEST_CHAR);
|
|
13681
14136
|
}
|
|
13682
14137
|
return a + DIGITS[Math.floor(BASE / 2)];
|
|
13683
14138
|
}
|
|
@@ -15310,6 +15765,11 @@ void main() {
|
|
|
15310
15765
|
exports2.ExportWorkerManager = ExportWorkerManager;
|
|
15311
15766
|
exports2.FILL_COLORS = FILL_COLORS;
|
|
15312
15767
|
exports2.FlowCanvas = FlowCanvas;
|
|
15768
|
+
exports2.LABEL_CORNER = LABEL_CORNER;
|
|
15769
|
+
exports2.LABEL_LINE_HEIGHT = LABEL_LINE_HEIGHT;
|
|
15770
|
+
exports2.LABEL_MIN_WIDTH = LABEL_MIN_WIDTH;
|
|
15771
|
+
exports2.LABEL_PADDING_H = LABEL_PADDING_H;
|
|
15772
|
+
exports2.LABEL_PADDING_V = LABEL_PADDING_V;
|
|
15313
15773
|
exports2.LINE_TYPES = LINE_TYPES;
|
|
15314
15774
|
exports2.OperationLog = OperationLog;
|
|
15315
15775
|
exports2.ROUGHNESS_CONFIGS = ROUGHNESS_CONFIGS;
|
|
@@ -15347,6 +15807,7 @@ void main() {
|
|
|
15347
15807
|
exports2.computeElbowRoute = computeElbowRoute;
|
|
15348
15808
|
exports2.computeFixedPoint = computeFixedPoint;
|
|
15349
15809
|
exports2.computeImageElementDimensions = computeImageElementDimensions;
|
|
15810
|
+
exports2.computePillSize = computePillSize;
|
|
15350
15811
|
exports2.computeZoomToFit = computeZoomToFit;
|
|
15351
15812
|
exports2.createCollaborationProvider = createCollaborationProvider;
|
|
15352
15813
|
exports2.createImageElement = createImageElement;
|
|
@@ -15411,6 +15872,7 @@ void main() {
|
|
|
15411
15872
|
exports2.isValidFractionalIndex = isValidFractionalIndex;
|
|
15412
15873
|
exports2.isWorkerSupported = isWorkerSupported;
|
|
15413
15874
|
exports2.loadImage = loadImage;
|
|
15875
|
+
exports2.measureLabelText = measureLabelText;
|
|
15414
15876
|
exports2.normalizeRect = normalizeRect;
|
|
15415
15877
|
exports2.onStatusChange = onStatusChange;
|
|
15416
15878
|
exports2.opAdd = opAdd;
|