@elixpo/lixsketch 5.6.9 → 5.6.10
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/react/{CopyPaste-PPDS3AD6.js → CopyPaste-N4U2NTQT.js} +5 -5
- package/dist/react/{EventDispatcher-UV7LFSAS.js → EventDispatcher-J657SDW4.js} +12 -12
- package/dist/react/{EventDispatcher-UV7LFSAS.js.map → EventDispatcher-J657SDW4.js.map} +1 -1
- package/dist/react/{Frame-DELCMYV6.js → Frame-NHPESH4Y.js} +2 -2
- package/dist/react/IconShape-RN5HJDUF.js +10 -0
- package/dist/react/ImageShape-L7U64AVP.js +10 -0
- package/dist/react/Line-LPRTGPUQ.js +10 -0
- package/dist/react/{SceneSerializer-H6KMQCO2.js → SceneSerializer-Y6QABGZY.js} +5 -5
- package/dist/react/{Selection-CFWRGVKH.js → Selection-GCZWCNAR.js} +3 -3
- package/dist/react/{SketchEngine-UFLZJQXS.js → SketchEngine-PCMCE63L.js} +19 -19
- package/dist/react/{arrowTool-DO327FKU.js → arrowTool-UN3TNJFP.js} +2 -2
- package/dist/react/{chunk-O7KXLFZN.js → chunk-3FCIBY54.js} +2 -2
- package/dist/react/{chunk-6LWUR7XB.js → chunk-3PFVMNDJ.js} +3 -3
- package/dist/react/{chunk-6LWUR7XB.js.map → chunk-3PFVMNDJ.js.map} +1 -1
- package/dist/react/{chunk-2ALS5JGS.js → chunk-5XGQ3CMT.js} +2 -2
- package/dist/react/{chunk-KZBKYHZO.js → chunk-7NHZYKYB.js} +3 -3
- package/dist/react/{chunk-KZBKYHZO.js.map → chunk-7NHZYKYB.js.map} +1 -1
- package/dist/react/{chunk-I7TVGJFF.js → chunk-7WXEWDRL.js} +3 -3
- package/dist/react/{chunk-I7TVGJFF.js.map → chunk-7WXEWDRL.js.map} +1 -1
- package/dist/react/{chunk-CGMUXYPJ.js → chunk-JVHZVV5U.js} +3 -3
- package/dist/react/{chunk-CGMUXYPJ.js.map → chunk-JVHZVV5U.js.map} +1 -1
- package/dist/react/{chunk-37PF7FG2.js → chunk-KACRJ6AJ.js} +2 -2
- package/dist/react/{chunk-X5ENBMGL.js → chunk-KXLNEFN5.js} +2 -2
- package/dist/react/{chunk-X5ENBMGL.js.map → chunk-KXLNEFN5.js.map} +1 -1
- package/dist/react/{chunk-DODPOWNX.js → chunk-P5476S5I.js} +3 -3
- package/dist/react/{chunk-DODPOWNX.js.map → chunk-P5476S5I.js.map} +1 -1
- package/dist/react/{chunk-BOZEDUAF.js → chunk-TAJ5E6KI.js} +3 -3
- package/dist/react/chunk-TAJ5E6KI.js.map +7 -0
- package/dist/react/{chunk-KC26KJW4.js → chunk-UERV53R7.js} +2 -2
- package/dist/react/{chunk-7DD2JRBC.js → chunk-ULZW5PXM.js} +2 -2
- package/dist/react/{chunk-RK3NVAER.js → chunk-YHQ4ZAJQ.js} +4 -4
- package/dist/react/{chunk-RK3NVAER.js.map → chunk-YHQ4ZAJQ.js.map} +1 -1
- package/dist/react/{circleTool-NK4RVDAR.js → circleTool-YDTQDGYX.js} +3 -3
- package/dist/react/{codeTool-3WF4HEOW.js → codeTool-U6SYKHHD.js} +3 -3
- package/dist/react/{frameTool-VCNV2NG2.js → frameTool-VRI7OODN.js} +2 -2
- package/dist/react/{freehandTool-TBAOD46K.js → freehandTool-2ICCQHVY.js} +3 -3
- package/dist/react/{iconTool-65JCAKYF.js → iconTool-32D5NJ4I.js} +3 -3
- package/dist/react/{imageTool-UQZUBOK2.js → imageTool-Z6Y4OXBG.js} +3 -3
- package/dist/react/index.js +21 -9
- package/dist/react/index.js.map +2 -2
- package/dist/react/{lineTool-762KBYOM.js → lineTool-BUWVQ666.js} +3 -3
- package/dist/react/{rectangleTool-IQK3HZK6.js → rectangleTool-NJYG6Y6L.js} +3 -3
- package/dist/react/styles.css +4 -0
- package/dist/react/{textTool-ITG2SBJK.js → textTool-CIJCF4Z3.js} +4 -4
- package/package.json +1 -1
- package/src/react/components/sidebars/TextSidebar.jsx +10 -4
- package/src/react/store/useUIStore.js +1 -1
- package/src/react/styles.css +13 -0
- package/src/react/utils/canvasBackgrounds.js +11 -2
- package/src/shapes/Line.js +2 -2
- package/src/tools/arrowTool.js +1 -1
- package/src/tools/circleTool.js +1 -1
- package/src/tools/codeTool.js +1 -1
- package/src/tools/freehandTool.js +1 -1
- package/src/tools/lineTool.js +1 -1
- package/src/tools/rectangleTool.js +1 -1
- package/src/tools/shapeRecognitionTool.js +1 -1
- package/src/tools/textTool.js +1 -1
- package/dist/react/IconShape-PZHMZSLR.js +0 -10
- package/dist/react/ImageShape-ZMBZARRI.js +0 -10
- package/dist/react/Line-VPVPL6ET.js +0 -10
- package/dist/react/chunk-BOZEDUAF.js.map +0 -7
- /package/dist/react/{CopyPaste-PPDS3AD6.js.map → CopyPaste-N4U2NTQT.js.map} +0 -0
- /package/dist/react/{Frame-DELCMYV6.js.map → Frame-NHPESH4Y.js.map} +0 -0
- /package/dist/react/{IconShape-PZHMZSLR.js.map → IconShape-RN5HJDUF.js.map} +0 -0
- /package/dist/react/{ImageShape-ZMBZARRI.js.map → ImageShape-L7U64AVP.js.map} +0 -0
- /package/dist/react/{Line-VPVPL6ET.js.map → Line-LPRTGPUQ.js.map} +0 -0
- /package/dist/react/{SceneSerializer-H6KMQCO2.js.map → SceneSerializer-Y6QABGZY.js.map} +0 -0
- /package/dist/react/{Selection-CFWRGVKH.js.map → Selection-GCZWCNAR.js.map} +0 -0
- /package/dist/react/{SketchEngine-UFLZJQXS.js.map → SketchEngine-PCMCE63L.js.map} +0 -0
- /package/dist/react/{arrowTool-DO327FKU.js.map → arrowTool-UN3TNJFP.js.map} +0 -0
- /package/dist/react/{chunk-O7KXLFZN.js.map → chunk-3FCIBY54.js.map} +0 -0
- /package/dist/react/{chunk-2ALS5JGS.js.map → chunk-5XGQ3CMT.js.map} +0 -0
- /package/dist/react/{chunk-37PF7FG2.js.map → chunk-KACRJ6AJ.js.map} +0 -0
- /package/dist/react/{chunk-KC26KJW4.js.map → chunk-UERV53R7.js.map} +0 -0
- /package/dist/react/{chunk-7DD2JRBC.js.map → chunk-ULZW5PXM.js.map} +0 -0
- /package/dist/react/{circleTool-NK4RVDAR.js.map → circleTool-YDTQDGYX.js.map} +0 -0
- /package/dist/react/{codeTool-3WF4HEOW.js.map → codeTool-U6SYKHHD.js.map} +0 -0
- /package/dist/react/{frameTool-VCNV2NG2.js.map → frameTool-VRI7OODN.js.map} +0 -0
- /package/dist/react/{freehandTool-TBAOD46K.js.map → freehandTool-2ICCQHVY.js.map} +0 -0
- /package/dist/react/{iconTool-65JCAKYF.js.map → iconTool-32D5NJ4I.js.map} +0 -0
- /package/dist/react/{imageTool-UQZUBOK2.js.map → imageTool-Z6Y4OXBG.js.map} +0 -0
- /package/dist/react/{lineTool-762KBYOM.js.map → lineTool-BUWVQ666.js.map} +0 -0
- /package/dist/react/{rectangleTool-IQK3HZK6.js.map → rectangleTool-NJYG6Y6L.js.map} +0 -0
- /package/dist/react/{textTool-ITG2SBJK.js.map → textTool-CIJCF4Z3.js.map} +0 -0
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-MB7VS6MK.js";
|
|
5
5
|
import {
|
|
6
6
|
ImageShape
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ULZW5PXM.js";
|
|
8
8
|
import {
|
|
9
9
|
IconShape
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-5XGQ3CMT.js";
|
|
11
11
|
import {
|
|
12
12
|
Frame
|
|
13
13
|
} from "./chunk-ZNZAICWY.js";
|
|
@@ -31,8 +31,8 @@ import {
|
|
|
31
31
|
} from "./chunk-BT2EIJD4.js";
|
|
32
32
|
import {
|
|
33
33
|
Line
|
|
34
|
-
} from "./chunk-
|
|
35
|
-
import "./chunk-
|
|
34
|
+
} from "./chunk-TAJ5E6KI.js";
|
|
35
|
+
import "./chunk-KXLNEFN5.js";
|
|
36
36
|
import {
|
|
37
37
|
pushCreateAction
|
|
38
38
|
} from "./chunk-VZX55VQL.js";
|
|
@@ -604,4 +604,4 @@ export {
|
|
|
604
604
|
initCopyPaste,
|
|
605
605
|
pasteClipboard
|
|
606
606
|
};
|
|
607
|
-
//# sourceMappingURL=CopyPaste-
|
|
607
|
+
//# sourceMappingURL=CopyPaste-N4U2NTQT.js.map
|
|
@@ -4,22 +4,22 @@ import {
|
|
|
4
4
|
handleTextMouseDown,
|
|
5
5
|
handleTextMouseMove,
|
|
6
6
|
handleTextMouseUp
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YHQ4ZAJQ.js";
|
|
8
8
|
import {
|
|
9
9
|
handleCodeMouseDown,
|
|
10
10
|
handleCodeMouseMove,
|
|
11
11
|
handleCodeMouseUp
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-P5476S5I.js";
|
|
13
13
|
import {
|
|
14
14
|
handleMouseDownImage,
|
|
15
15
|
handleMouseMoveImage,
|
|
16
16
|
handleMouseUpImage
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-KACRJ6AJ.js";
|
|
18
18
|
import {
|
|
19
19
|
handleMouseDownIcon,
|
|
20
20
|
handleMouseMoveIcon,
|
|
21
21
|
handleMouseUpIcon
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-3FCIBY54.js";
|
|
23
23
|
import {
|
|
24
24
|
handleMouseDown as handleMouseDown4,
|
|
25
25
|
handleMouseMove as handleMouseMove4,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
handleMouseDown as handleMouseDown5,
|
|
30
30
|
handleMouseMove as handleMouseMove5,
|
|
31
31
|
handleMouseUp as handleMouseUp5
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-3PFVMNDJ.js";
|
|
33
33
|
import {
|
|
34
34
|
handleMultiSelectionMouseDown,
|
|
35
35
|
handleMultiSelectionMouseMove,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
isMultiSelecting,
|
|
38
38
|
multiSelection,
|
|
39
39
|
removeMultiSelectionRect
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-UERV53R7.js";
|
|
41
41
|
import {
|
|
42
42
|
Frame
|
|
43
43
|
} from "./chunk-ZNZAICWY.js";
|
|
@@ -45,17 +45,17 @@ import {
|
|
|
45
45
|
handleMouseDownRect,
|
|
46
46
|
handleMouseMoveRect,
|
|
47
47
|
handleMouseUpRect
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-7WXEWDRL.js";
|
|
49
49
|
import {
|
|
50
50
|
handleMouseDown as handleMouseDown2,
|
|
51
51
|
handleMouseMove as handleMouseMove2,
|
|
52
52
|
handleMouseUp as handleMouseUp2
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-7NHZYKYB.js";
|
|
54
54
|
import {
|
|
55
55
|
handleMouseDown as handleMouseDown3,
|
|
56
56
|
handleMouseMove as handleMouseMove3,
|
|
57
57
|
handleMouseUp as handleMouseUp3
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-JVHZVV5U.js";
|
|
59
59
|
import {
|
|
60
60
|
normalizeWebEmbedUrl
|
|
61
61
|
} from "./chunk-QZI4UIE5.js";
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
handleMouseDown,
|
|
66
66
|
handleMouseMove,
|
|
67
67
|
handleMouseUp
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-KXLNEFN5.js";
|
|
69
69
|
import {
|
|
70
70
|
pushCreateAction,
|
|
71
71
|
pushFrameAttachmentAction,
|
|
@@ -325,7 +325,7 @@ var previewPath = null;
|
|
|
325
325
|
var previewFrame = 0;
|
|
326
326
|
var latestPrediction = null;
|
|
327
327
|
function getThemeStroke() {
|
|
328
|
-
return document.body?.classList.contains("theme-dark") ? "#f7f4ff" : "#
|
|
328
|
+
return document.body?.classList.contains("theme-dark") ? "#f7f4ff" : "#000000";
|
|
329
329
|
}
|
|
330
330
|
function getSVGPoint(event) {
|
|
331
331
|
const viewBox = svg.viewBox.baseVal;
|
|
@@ -1247,4 +1247,4 @@ export {
|
|
|
1247
1247
|
handleMainMouseUp,
|
|
1248
1248
|
initEventDispatcher
|
|
1249
1249
|
};
|
|
1250
|
-
//# sourceMappingURL=EventDispatcher-
|
|
1250
|
+
//# sourceMappingURL=EventDispatcher-J657SDW4.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/tools/shapeRecognition.js", "../../src/tools/shapeRecognitionTool.js", "../../src/tools/paintBucketTool.js", "../../src/tools/lassoTool.js", "../../src/tools/webEmbedTool.js", "../../src/core/EventDispatcher.js"],
|
|
4
|
-
"sourcesContent": ["const MIN_SHAPE_SIZE = 8;\n\nexport const MAX_GESTURE_POINTS = 96;\n\nexport function distance(a, b) {\n return Math.hypot(b.x - a.x, b.y - a.y);\n}\n\nfunction orientedBounds(sample, angle) {\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n let minU = Infinity;\n let maxU = -Infinity;\n let minV = Infinity;\n let maxV = -Infinity;\n for (const point of sample) {\n const u = point.x * cos + point.y * sin;\n const v = -point.x * sin + point.y * cos;\n minU = Math.min(minU, u);\n maxU = Math.max(maxU, u);\n minV = Math.min(minV, v);\n maxV = Math.max(maxV, v);\n }\n const centerU = (minU + maxU) / 2;\n const centerV = (minV + maxV) / 2;\n return {\n center: {\n x: centerU * cos - centerV * sin,\n y: centerU * sin + centerV * cos,\n },\n width: Math.max(MIN_SHAPE_SIZE, maxU - minU),\n height: Math.max(MIN_SHAPE_SIZE, maxV - minV),\n angle,\n minU,\n maxU,\n minV,\n maxV,\n };\n}\n\nfunction principalAngle(sample) {\n let meanX = 0;\n let meanY = 0;\n for (const point of sample) {\n meanX += point.x;\n meanY += point.y;\n }\n meanX /= sample.length;\n meanY /= sample.length;\n let xx = 0;\n let yy = 0;\n let xy = 0;\n for (const point of sample) {\n const dx = point.x - meanX;\n const dy = point.y - meanY;\n xx += dx * dx;\n yy += dy * dy;\n xy += dx * dy;\n }\n if (Math.abs(xx - yy) + Math.abs(xy) < 0.001) return 0;\n return Math.atan2(2 * xy, xx - yy) / 2;\n}\n\nfunction rectangleAngle(sample) {\n let x = 0;\n let y = 0;\n for (let index = 1; index < sample.length; index += 1) {\n const dx = sample[index].x - sample[index - 1].x;\n const dy = sample[index].y - sample[index - 1].y;\n const length = Math.hypot(dx, dy);\n if (length === 0) continue;\n const angle = Math.atan2(dy, dx) * 4;\n x += Math.cos(angle) * length;\n y += Math.sin(angle) * length;\n }\n return Math.atan2(y, x) / 4;\n}\n\nfunction pointToSegmentDistance(point, start, end) {\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n const lengthSquared = dx * dx + dy * dy;\n if (lengthSquared === 0) return distance(point, start);\n const amount = Math.max(0, Math.min(1,\n ((point.x - start.x) * dx + (point.y - start.y) * dy) / lengthSquared));\n return Math.hypot(point.x - (start.x + dx * amount), point.y - (start.y + dy * amount));\n}\n\nfunction polygonError(sample, vertices, scale) {\n let total = 0;\n for (const point of sample) {\n let nearest = Infinity;\n for (let index = 0; index < vertices.length; index += 1) {\n nearest = Math.min(nearest, pointToSegmentDistance(\n point,\n vertices[index],\n vertices[(index + 1) % vertices.length],\n ));\n }\n total += nearest;\n }\n return total / sample.length / Math.max(scale, MIN_SHAPE_SIZE);\n}\n\nfunction polygonVertices(bounds, kind) {\n const cos = Math.cos(bounds.angle);\n const sin = Math.sin(bounds.angle);\n const toWorld = (u, v) => ({\n x: u * cos - v * sin,\n y: u * sin + v * cos,\n });\n const centerU = (bounds.minU + bounds.maxU) / 2;\n const centerV = (bounds.minV + bounds.maxV) / 2;\n const local = kind === 'triangle'\n ? [[centerU, bounds.minV], [bounds.maxU, bounds.maxV], [bounds.minU, bounds.maxV]]\n : kind === 'diamond'\n ? [[centerU, bounds.minV], [bounds.maxU, centerV], [centerU, bounds.maxV], [bounds.minU, centerV]]\n : [[bounds.minU, bounds.minV], [bounds.maxU, bounds.minV], [bounds.maxU, bounds.maxV], [bounds.minU, bounds.maxV]];\n return local.map(([u, v]) => toWorld(u, v));\n}\n\nfunction trianglePrediction(sample, pathLength) {\n const baseAngle = principalAngle(sample);\n let best = null;\n // Principal axes do not encode direction. Testing four quarter turns keeps\n // the fit rotation-independent while retaining a constant number of O(N)\n // passes over the capped gesture sample.\n for (let turn = 0; turn < 4; turn += 1) {\n const bounds = orientedBounds(sample, baseAngle + turn * Math.PI / 2);\n const vertices = polygonVertices(bounds, 'triangle');\n const error = polygonError(sample, vertices, Math.hypot(bounds.width, bounds.height));\n if (!best || error < best.error) best = { bounds, vertices, error };\n }\n if (!best || best.error > 0.045) return null;\n return {\n type: 'triangle',\n ...best.bounds,\n vertices: best.vertices,\n pathLength,\n };\n}\n\nfunction diamondPrediction(sample, pathLength) {\n const bounds = orientedBounds(sample, principalAngle(sample));\n const vertices = polygonVertices(bounds, 'diamond');\n const error = polygonError(sample, vertices, Math.hypot(bounds.width, bounds.height));\n if (error > 0.035) return null;\n return { type: 'diamond', ...bounds, vertices, pathLength };\n}\n\nfunction closedShapePrediction(sample, pathLength) {\n const triangle = trianglePrediction(sample, pathLength);\n if (triangle) return triangle;\n const fittedDiamond = diamondPrediction(sample, pathLength);\n if (fittedDiamond) return fittedDiamond;\n const rectBounds = orientedBounds(sample, rectangleAngle(sample));\n const ellipseBounds = orientedBounds(sample, principalAngle(sample));\n let rectangleError = 0;\n let ellipseError = 0;\n const rectCos = Math.cos(rectBounds.angle);\n const rectSin = Math.sin(rectBounds.angle);\n const ellipseCos = Math.cos(ellipseBounds.angle);\n const ellipseSin = Math.sin(ellipseBounds.angle);\n const rectHalfW = rectBounds.width / 2;\n const rectHalfH = rectBounds.height / 2;\n const ellipseHalfW = ellipseBounds.width / 2;\n const ellipseHalfH = ellipseBounds.height / 2;\n\n for (const point of sample) {\n const rectDx = point.x - rectBounds.center.x;\n const rectDy = point.y - rectBounds.center.y;\n const rectU = Math.abs(rectDx * rectCos + rectDy * rectSin) / rectHalfW;\n const rectV = Math.abs(-rectDx * rectSin + rectDy * rectCos) / rectHalfH;\n rectangleError += Math.min(Math.abs(1 - rectU), Math.abs(1 - rectV));\n const ellipseDx = point.x - ellipseBounds.center.x;\n const ellipseDy = point.y - ellipseBounds.center.y;\n const ellipseU = (ellipseDx * ellipseCos + ellipseDy * ellipseSin) / ellipseHalfW;\n const ellipseV = (-ellipseDx * ellipseSin + ellipseDy * ellipseCos) / ellipseHalfH;\n ellipseError += Math.abs(1 - Math.hypot(ellipseU, ellipseV));\n }\n\n rectangleError /= sample.length;\n ellipseError /= sample.length;\n const rectangle = rectangleError <= ellipseError * 1.08;\n const bestError = rectangle ? rectangleError : ellipseError;\n if (bestError > 0.24) {\n return { type: 'freehand', points: sample.map((point) => ({ ...point })), pathLength };\n }\n const bounds = rectangle ? rectBounds : ellipseBounds;\n const normalizedAngle = Math.abs(Math.atan2(Math.sin(rectBounds.angle * 2), Math.cos(rectBounds.angle * 2)) / 2);\n const diamond = rectangle && normalizedAngle >= Math.PI / 7;\n return {\n type: diamond ? 'diamond' : (rectangle ? 'rectangle' : 'circle'),\n ...bounds,\n ...(diamond ? { vertices: polygonVertices(rectBounds, 'rectangle') } : {}),\n pathLength,\n };\n}\n\nexport function capGestureSample(sample, maxPoints = MAX_GESTURE_POINTS) {\n if (!Array.isArray(sample) || sample.length <= maxPoints) return Array.isArray(sample) ? sample : [];\n if (maxPoints <= 1) return sample.slice(0, Math.max(0, maxPoints));\n const capped = [sample[0]];\n const step = (sample.length - 1) / (maxPoints - 1);\n for (let index = 1; index < maxPoints - 1; index += 1) {\n capped.push(sample[Math.round(index * step)]);\n }\n capped.push(sample[sample.length - 1]);\n return capped;\n}\n\nexport function predictDrawnShape(input) {\n const sample = capGestureSample(input);\n if (sample.length < 2) return null;\n const start = sample[0];\n let pathLength = 0;\n let farthestIndex = 1;\n let farthestDistance = 0;\n let minX = start.x;\n let maxX = start.x;\n let minY = start.y;\n let maxY = start.y;\n\n for (let index = 1; index < sample.length; index += 1) {\n pathLength += distance(sample[index - 1], sample[index]);\n const fromStart = distance(start, sample[index]);\n if (fromStart > farthestDistance) {\n farthestDistance = fromStart;\n farthestIndex = index;\n }\n minX = Math.min(minX, sample[index].x);\n maxX = Math.max(maxX, sample[index].x);\n minY = Math.min(minY, sample[index].y);\n maxY = Math.max(maxY, sample[index].y);\n }\n\n const diagonal = Math.max(MIN_SHAPE_SIZE, Math.hypot(maxX - minX, maxY - minY));\n const end = sample[sample.length - 1];\n const closed = sample.length >= 8 && distance(start, end) <= diagonal * 0.28 && pathLength >= diagonal * 1.85;\n if (closed) return closedShapePrediction(sample, pathLength);\n\n const tip = sample[farthestIndex];\n let afterTipLength = 0;\n for (let index = farthestIndex + 1; index < sample.length; index += 1) {\n afterTipLength += distance(sample[index - 1], sample[index]);\n }\n let shaftLength = 0;\n for (let index = 1; index <= farthestIndex; index += 1) {\n shaftLength += distance(sample[index - 1], sample[index]);\n }\n const arrow = farthestIndex >= Math.floor(sample.length * 0.45)\n && farthestIndex < sample.length - 2\n && afterTipLength >= diagonal * 0.18\n && distance(end, tip) <= diagonal * 0.48\n && farthestDistance / Math.max(shaftLength, 1) >= 0.86;\n const directDistance = distance(start, end);\n const line = !arrow && directDistance / Math.max(pathLength, 1) >= 0.92;\n\n if (!arrow && !line) {\n return { type: 'freehand', points: sample.map((point) => ({ ...point })), pathLength };\n }\n return {\n type: arrow ? 'arrow' : 'line',\n start: { ...start },\n end: arrow ? { ...tip } : { ...end },\n width: Math.max(MIN_SHAPE_SIZE, maxX - minX),\n height: Math.max(MIN_SHAPE_SIZE, maxY - minY),\n pathLength,\n };\n}\n", "/* eslint-disable */\nimport { pushCreateAction, pushFrameAttachmentAction } from '../core/UndoRedo.js';\nimport {\n MAX_GESTURE_POINTS,\n distance,\n predictDrawnShape,\n} from './shapeRecognition.js';\n\nexport {\n MAX_GESTURE_POINTS,\n capGestureSample,\n predictDrawnShape,\n} from './shapeRecognition.js';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst MIN_SCREEN_SAMPLE_PX = 4;\n\nlet drawing = false;\nlet points = [];\nlet previewPath = null;\nlet previewFrame = 0;\nlet latestPrediction = null;\n\nfunction getThemeStroke() {\n return document.body?.classList.contains('theme-dark') ? '#f7f4ff' : '#211a33';\n}\n\nfunction getSVGPoint(event) {\n const viewBox = svg.viewBox.baseVal;\n const rect = svg.getBoundingClientRect();\n return {\n x: viewBox.x + ((event.clientX - rect.left) / rect.width) * viewBox.width,\n y: viewBox.y + ((event.clientY - rect.top) / rect.height) * viewBox.height,\n pressure: event.pressure || 0.5,\n };\n}\n\nfunction rotatedPoint(center, x, y, angle) {\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n return { x: center.x + x * cos - y * sin, y: center.y + x * sin + y * cos };\n}\n\nfunction pathForPrediction(prediction) {\n if (!prediction) return '';\n if (prediction.type === 'rectangle') {\n const halfW = prediction.width / 2;\n const halfH = prediction.height / 2;\n const corners = [\n rotatedPoint(prediction.center, -halfW, -halfH, prediction.angle),\n rotatedPoint(prediction.center, halfW, -halfH, prediction.angle),\n rotatedPoint(prediction.center, halfW, halfH, prediction.angle),\n rotatedPoint(prediction.center, -halfW, halfH, prediction.angle),\n ];\n return `M ${corners[0].x} ${corners[0].y} L ${corners[1].x} ${corners[1].y} L ${corners[2].x} ${corners[2].y} L ${corners[3].x} ${corners[3].y} Z`;\n }\n if (prediction.type === 'circle') {\n const rx = prediction.width / 2;\n const ry = prediction.height / 2;\n const start = rotatedPoint(prediction.center, rx, 0, prediction.angle);\n const opposite = rotatedPoint(prediction.center, -rx, 0, prediction.angle);\n const rotation = prediction.angle * 180 / Math.PI;\n return `M ${start.x} ${start.y} A ${rx} ${ry} ${rotation} 1 0 ${opposite.x} ${opposite.y} A ${rx} ${ry} ${rotation} 1 0 ${start.x} ${start.y}`;\n }\n if (prediction.type === 'triangle' || prediction.type === 'diamond') {\n return prediction.vertices.reduce(\n (path, point, index) => `${path}${index === 0 ? 'M' : ' L'} ${point.x} ${point.y}`,\n '',\n ) + ' Z';\n }\n if (prediction.type === 'freehand') {\n if (!prediction.points.length) return '';\n return prediction.points.reduce((path, point, index) => `${path}${index === 0 ? 'M' : ' L'} ${point.x} ${point.y}`, '');\n }\n const { start, end } = prediction;\n let path = `M ${start.x} ${start.y} L ${end.x} ${end.y}`;\n if (prediction.type === 'arrow') {\n const angle = Math.atan2(end.y - start.y, end.x - start.x);\n const head = Math.min(24 / (window.currentZoom || 1), distance(start, end) * 0.25);\n const left = rotatedPoint(end, -head, head * 0.55, angle);\n const right = rotatedPoint(end, -head, -head * 0.55, angle);\n path += ` M ${left.x} ${left.y} L ${end.x} ${end.y} L ${right.x} ${right.y}`;\n }\n return path;\n}\n\nfunction ensurePreview() {\n if (previewPath?.isConnected) return;\n previewPath = document.createElementNS(SVG_NS, 'path');\n previewPath.dataset.recognitionPreview = 'true';\n previewPath.setAttribute('fill', 'rgba(148, 148, 158, 0.06)');\n previewPath.setAttribute('stroke', '#9696a0');\n previewPath.setAttribute('stroke-width', '2');\n previewPath.setAttribute('stroke-dasharray', '5 7');\n previewPath.setAttribute('stroke-linecap', 'round');\n previewPath.setAttribute('stroke-linejoin', 'round');\n previewPath.setAttribute('vector-effect', 'non-scaling-stroke');\n previewPath.setAttribute('pointer-events', 'none');\n svg.appendChild(previewPath);\n}\n\nfunction renderPreview() {\n previewFrame = 0;\n if (!drawing) return;\n latestPrediction = predictDrawnShape(points);\n ensurePreview();\n previewPath.setAttribute('d', pathForPrediction(latestPrediction));\n previewPath.setAttribute('fill', ['rectangle', 'circle', 'triangle', 'diamond'].includes(latestPrediction?.type)\n ? 'rgba(148, 148, 158, 0.06)'\n : 'none');\n}\n\nfunction schedulePreview() {\n if (!previewFrame) previewFrame = requestAnimationFrame(renderPreview);\n}\n\nfunction cleanupPreview() {\n if (previewFrame) cancelAnimationFrame(previewFrame);\n previewFrame = 0;\n previewPath?.remove();\n previewPath = null;\n}\n\nfunction currentStyle() {\n const settings = window.freehandToolSettings || {};\n const outline = settings.strokeStyle || 'solid';\n return {\n stroke: settings.strokeColor || getThemeStroke(),\n fill: 'transparent',\n fillStyle: 'none',\n strokeWidth: settings.strokeWidth || 2,\n strokeDasharray: outline === 'dashed' ? '10,10' : (outline === 'dotted' ? '2,8' : ''),\n outline,\n };\n}\n\nfunction attachToContainingFrame(shape) {\n for (let index = shapes.length - 1; index >= 0; index -= 1) {\n const frame = shapes[index];\n if (frame.shapeName !== 'frame' || typeof frame.isShapeInFrame !== 'function') continue;\n if (!frame.isShapeInFrame(shape)) continue;\n frame.addShapeToFrame(shape);\n pushFrameAttachmentAction(frame, shape, 'attach', null);\n break;\n }\n}\n\nfunction createPredictedShape(prediction) {\n if (!prediction) return null;\n const style = currentStyle();\n let shape = null;\n if (prediction.type === 'rectangle') {\n shape = new window.Rectangle(\n prediction.center.x - prediction.width / 2,\n prediction.center.y - prediction.height / 2,\n prediction.width,\n prediction.height,\n style,\n );\n shape.rotation = prediction.angle * 180 / Math.PI;\n shape.draw();\n } else if (prediction.type === 'circle') {\n shape = new window.Circle(\n prediction.center.x,\n prediction.center.y,\n prediction.width / 2,\n prediction.height / 2,\n style,\n );\n shape.rotation = prediction.angle * 180 / Math.PI;\n shape.draw();\n } else if (prediction.type === 'triangle' || prediction.type === 'diamond') {\n const polygonPoints = [...prediction.vertices, prediction.vertices[0]];\n shape = new window.FreehandStroke(\n polygonPoints.map((point) => [point.x, point.y, 0.5]),\n {\n stroke: 'transparent',\n fill: 'transparent',\n fillStyle: 'none',\n outlineStroke: style.stroke,\n outlineWidth: style.strokeWidth,\n closedFill: true,\n strokeWidth: style.strokeWidth,\n strokeStyle: style.outline,\n roughness: 0,\n },\n );\n shape.recognizedShapeType = prediction.type;\n } else if (prediction.type === 'freehand') {\n const brush = window.freehandToolSettings || {};\n shape = new window.FreehandStroke(\n prediction.points.map((point) => [point.x, point.y, point.pressure || 0.5]),\n {\n stroke: style.stroke,\n strokeWidth: style.strokeWidth,\n strokeStyle: style.outline,\n thinning: brush.thinning ?? 0.5,\n roughness: brush.roughness || 'smooth',\n strokeOpacity: brush.opacity ?? 1,\n },\n );\n } else if (prediction.type === 'arrow') {\n shape = new window.Arrow(prediction.start, prediction.end, {\n stroke: style.stroke,\n strokeWidth: style.strokeWidth,\n arrowOutlineStyle: style.outline,\n arrowCurved: 'straight',\n });\n } else {\n shape = new window.Line(prediction.start, prediction.end, {\n stroke: style.stroke,\n strokeWidth: style.strokeWidth,\n strokeDasharray: style.strokeDasharray,\n roughness: 1.5,\n bowing: 1,\n });\n }\n shapes.push(shape);\n pushCreateAction(shape);\n attachToContainingFrame(shape);\n return shape;\n}\n\nexport function handleShapeRecognitionDown(event) {\n if (!window.isShapeRecognitionToolActive || event.button !== 0) return;\n drawing = true;\n points = [getSVGPoint(event)];\n latestPrediction = null;\n ensurePreview();\n schedulePreview();\n}\n\nexport function handleShapeRecognitionMove(event) {\n if (!drawing || !window.isShapeRecognitionToolActive) return;\n const point = getSVGPoint(event);\n const last = points[points.length - 1];\n const threshold = MIN_SCREEN_SAMPLE_PX / (window.currentZoom || 1);\n if (distance(last, point) < threshold) return;\n if (points.length < MAX_GESTURE_POINTS) {\n points.push(point);\n } else {\n // Preserve the first point and evenly discard older detail. Memory and\n // recognition time stay constant even during very long gestures.\n points = [points[0], ...points.slice(2).filter((_, index) => index % 2 === 0), point];\n }\n schedulePreview();\n}\n\nexport function handleShapeRecognitionUp(event) {\n if (!drawing) return;\n drawing = false;\n const rect = svg.getBoundingClientRect();\n if (event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom) {\n const point = getSVGPoint(event);\n if (distance(points[points.length - 1], point) > 0) points.push(point);\n }\n latestPrediction = predictDrawnShape(points);\n cleanupPreview();\n\n const prediction = latestPrediction;\n points = [];\n latestPrediction = null;\n if (!prediction || prediction.pathLength < MIN_SHAPE_SIZE) return;\n\n const shape = createPredictedShape(prediction);\n if (!shape) return;\n if (window.__sketchStoreApi) window.__sketchStoreApi.setActiveTool('select', { afterDraw: true });\n currentShape = shape;\n if (shape.shapeName === 'freehandStroke' && typeof shape.selectStroke === 'function') {\n shape.selectStroke();\n } else {\n shape.isSelected = true;\n if (typeof shape.addAnchors === 'function') shape.addAnchors();\n }\n}\n\nexport function cancelShapeRecognition() {\n drawing = false;\n points = [];\n latestPrediction = null;\n cleanupPreview();\n}\n\nwindow.__cancelShapeRecognition = cancelShapeRecognition;\n", "/* eslint-disable */\nimport { pushOptionsChangeAction } from '../core/UndoRedo.js';\n\nconst OPTION_FILL_SHAPES = new Set(['rectangle', 'circle']);\n\nwindow.paintBucketSettings = window.paintBucketSettings || {\n fillColor: '#A98DEB',\n fillStyle: 'solid',\n};\n\nfunction getSVGPoint(event) {\n const viewBox = svg.viewBox.baseVal;\n const rect = svg.getBoundingClientRect();\n return {\n x: viewBox.x + ((event.clientX - rect.left) / rect.width) * viewBox.width,\n y: viewBox.y + ((event.clientY - rect.top) / rect.height) * viewBox.height,\n };\n}\n\nfunction isClosedFreehand(shape) {\n if (shape?.shapeName !== 'freehandStroke' || !Array.isArray(shape.points) || shape.points.length < 3) return false;\n if (shape.options?.closedFill) return true;\n const first = shape.points[0];\n const last = shape.points[shape.points.length - 1];\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const point of shape.points) {\n const x = Number(point[0]) || 0;\n const y = Number(point[1]) || 0;\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\n const diagonal = Math.hypot(maxX - minX, maxY - minY);\n const closeDistance = Math.hypot(last[0] - first[0], last[1] - first[1]);\n const tolerance = Math.max((shape.options?.strokeWidth || 2) * 2, Math.min(16, diagonal * 0.08));\n return diagonal > 0 && closeDistance <= tolerance;\n}\n\nexport function isPaintBucketFillable(shape) {\n return OPTION_FILL_SHAPES.has(shape?.shapeName)\n || shape?.shapeName === 'frame'\n || isClosedFreehand(shape);\n}\n\nfunction findShapeAt(x, y) {\n for (let index = shapes.length - 1; index >= 0; index -= 1) {\n const shape = shapes[index];\n if (typeof shape?.contains !== 'function') continue;\n if (shape.contains(x, y)) return shape;\n }\n return null;\n}\n\nexport function fillShape(shape, settings = window.paintBucketSettings) {\n if (!isPaintBucketFillable(shape)) return false;\n const transparent = settings.fillStyle === 'none' || settings.fillStyle === 'transparent';\n const nextFill = transparent ? 'transparent' : settings.fillColor;\n const nextStyle = transparent ? 'none' : settings.fillStyle;\n\n if (shape.shapeName === 'frame') {\n if (shape.fillColor === nextFill && shape.fillStyle === nextStyle) return false;\n const oldOptions = { ...shape.options, fillColor: shape.fillColor, fillStyle: shape.fillStyle };\n const newOptions = { ...shape.options, fillColor: nextFill, fillStyle: nextStyle };\n pushOptionsChangeAction(shape, oldOptions, newOptions);\n shape.fillColor = nextFill;\n shape.fillStyle = nextStyle;\n shape.options = { ...shape.options, fillColor: nextFill, fillStyle: nextStyle };\n shape.draw();\n return true;\n }\n\n const freehandOptions = shape.shapeName === 'freehandStroke'\n ? {\n closedFill: true,\n outlineStroke: shape.options.outlineStroke || shape.options.stroke,\n }\n : {};\n if (shape.options.fill === nextFill\n && shape.options.fillStyle === nextStyle\n && Object.entries(freehandOptions).every(([key, value]) => shape.options[key] === value)) return false;\n\n const oldOptions = { ...shape.options };\n const newOptions = { ...shape.options, ...freehandOptions, fill: nextFill, fillStyle: nextStyle };\n pushOptionsChangeAction(shape, oldOptions, newOptions);\n shape.options = newOptions;\n shape.draw();\n return true;\n}\n\nexport function handlePaintBucketDown(event) {\n if (!window.isPaintBucketToolActive || event.button !== 0) return;\n const { x, y } = getSVGPoint(event);\n const shape = findShapeAt(x, y);\n if (!shape) {\n window.dispatchEvent(new CustomEvent('lixsketch:bucket-miss'));\n return;\n }\n if (!isPaintBucketFillable(shape)) {\n window.dispatchEvent(new CustomEvent('lixsketch:bucket-not-fillable', {\n detail: { shapeID: shape.shapeID, shapeType: shape.shapeName },\n }));\n return;\n }\n if (!fillShape(shape)) return;\n window.dispatchEvent(new CustomEvent('lixsketch:bucket-filled', { detail: { shapeID: shape.shapeID } }));\n}\n", "/* eslint-disable */\n\nimport { multiSelection } from '../core/Selection.js';\n\nconst MAX_POINTS = 192;\nconst MIN_SAMPLE_PX = 4;\nlet points = [];\nlet preview = null;\nlet drawing = false;\n\nfunction coords(e) {\n const vb = svg.viewBox.baseVal;\n const rect = svg.getBoundingClientRect();\n return { x: vb.x + ((e.clientX - rect.left) / rect.width) * vb.width, y: vb.y + ((e.clientY - rect.top) / rect.height) * vb.height };\n}\n\nfunction pointInPolygon(point, polygon) {\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const a = polygon[i], b = polygon[j];\n if (((a.y > point.y) !== (b.y > point.y)) && point.x < ((b.x - a.x) * (point.y - a.y)) / ((b.y - a.y) || Number.EPSILON) + a.x) inside = !inside;\n }\n return inside;\n}\n\nfunction boundsPoints(shape) {\n if ((shape.shapeName === 'line' || shape.shapeName === 'arrow') && shape.startPoint && shape.endPoint) return [shape.startPoint, shape.endPoint];\n if (shape.shapeName === 'freehandStroke' && Array.isArray(shape.points)) {\n const step = Math.max(1, Math.ceil(shape.points.length / 16));\n return shape.points.filter((_, i) => i % step === 0).map((p) => ({ x: p[0], y: p[1] }));\n }\n let x = shape.x || 0, y = shape.y || 0, width = shape.width || 0, height = shape.height || 0;\n if (shape.shapeName === 'circle') { x = shape.x - shape.rx; y = shape.y - shape.ry; width = shape.rx * 2; height = shape.ry * 2; }\n if ((!width || !height) && shape.group?.getBBox) {\n try { const box = shape.group.getBBox(); x = box.x; y = box.y; width = box.width; height = box.height; } catch {}\n }\n const raw = [{ x, y }, { x: x + width, y }, { x: x + width, y: y + height }, { x, y: y + height }, { x: x + width / 2, y: y + height / 2 }];\n const rotation = Number(shape.rotation) || 0;\n if (!rotation) return raw;\n const cx = x + width / 2, cy = y + height / 2, angle = rotation * Math.PI / 180;\n return raw.map((p) => ({ x: cx + (p.x - cx) * Math.cos(angle) - (p.y - cy) * Math.sin(angle), y: cy + (p.x - cx) * Math.sin(angle) + (p.y - cy) * Math.cos(angle) }));\n}\n\nfunction cleanup() {\n preview?.remove(); preview = null; points = []; drawing = false;\n}\n\nexport function handleLassoDown(e) {\n if (!window.isLassoToolActive) return;\n cleanup(); multiSelection.clearSelection(); drawing = true; points = [coords(e)];\n preview = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n preview.setAttribute('fill', 'rgba(139, 118, 214, .10)'); preview.setAttribute('stroke', '#a78bfa');\n preview.setAttribute('stroke-dasharray', '5 4'); preview.setAttribute('vector-effect', 'non-scaling-stroke');\n preview.style.pointerEvents = 'none'; svg.appendChild(preview);\n}\n\nexport function handleLassoMove(e) {\n if (!drawing) return;\n const p = coords(e), last = points[points.length - 1];\n const min = MIN_SAMPLE_PX / (window.currentZoom || 1);\n if (Math.hypot(p.x - last.x, p.y - last.y) < min) return;\n if (points.length < MAX_POINTS) points.push(p); else points[points.length - 1] = p;\n preview?.setAttribute('d', `M ${points.map((v) => `${v.x} ${v.y}`).join(' L ')} Z`);\n}\n\nexport function handleLassoUp() {\n if (!drawing) return;\n const polygon = points.slice(); cleanup();\n // Switching tools clears selection state. Do that before applying the\n // lasso result so the newly selected shapes survive the tool transition.\n window.__sketchStoreApi?.setActiveTool('select', { afterDraw: true });\n if (polygon.length >= 3 && Array.isArray(window.shapes)) {\n const selected = window.shapes.filter((shape) => boundsPoints(shape).every((p) => pointInPolygon(p, polygon)));\n const filtered = selected.filter((shape) => !shape.parentFrame || !selected.includes(shape.parentFrame));\n // Apply the batch once; addShape() rebuilds controls per item and becomes\n // unnecessarily quadratic for a large lasso selection.\n filtered.forEach((shape) => { multiSelection.selectedShapes.add(shape); shape.isSelected = true; });\n if (filtered.length) multiSelection.updateControls();\n window.currentShape = filtered.length === 1 ? filtered[0] : null;\n }\n}\n\nexport function cancelLasso() { cleanup(); }\nwindow.__cancelLasso = cancelLasso;\n", "/* eslint-disable */\n\nimport { Frame } from '../shapes/Frame.js';\nimport { pushCreateAction } from '../core/UndoRedo.js';\nimport { normalizeWebEmbedUrl } from '../core/WebEmbedPolicy.js';\n\nlet frame = null, start = null;\nfunction coords(e) {\n const vb = svg.viewBox.baseVal, rect = svg.getBoundingClientRect();\n return { x: vb.x + ((e.clientX - rect.left) / rect.width) * vb.width, y: vb.y + ((e.clientY - rect.top) / rect.height) * vb.height };\n}\n\nexport function placeWebEmbed(urlValue) {\n const url = normalizeWebEmbedUrl(urlValue);\n if (!url || typeof svg === 'undefined') return null;\n\n // Complete the tool transition first because setActiveTool clears the\n // previous selection. The newly inserted frame should remain selected.\n window.__sketchStoreApi?.setActiveTool('select');\n const viewBox = svg.viewBox.baseVal;\n const width = Math.min(640, Math.max(320, viewBox.width * 0.56));\n const height = width * 9 / 16;\n const x = viewBox.x + (viewBox.width - width) / 2;\n const y = viewBox.y + (viewBox.height - height) / 2;\n const placedFrame = new Frame(x, y, width, height, {\n frameName: 'Web embed', frameType: 'web-embed', webEmbedURL: url,\n stroke: '#8b76d6', strokeWidth: 2,\n });\n shapes.push(placedFrame);\n pushCreateAction(placedFrame);\n currentShape = placedFrame;\n placedFrame.selectFrame();\n window.__pendingWebEmbedURL = null;\n return placedFrame;\n}\n\nexport function handleWebEmbedDown(e) {\n const url = normalizeWebEmbedUrl(window.__pendingWebEmbedURL);\n if (!window.isWebEmbedToolActive || !url) { window.__showWebEmbedModal?.(); return; }\n start = coords(e);\n frame = new Frame(start.x, start.y, 0, 0, { frameName: 'Web embed', frameType: 'web-embed', webEmbedURL: url, stroke: '#8b76d6', strokeWidth: 2 });\n shapes.push(frame); currentShape = frame;\n}\n\nexport function handleWebEmbedMove(e) {\n if (!frame || !start) return;\n const p = coords(e); frame.x = Math.min(start.x, p.x); frame.y = Math.min(start.y, p.y);\n frame.width = Math.abs(p.x - start.x); frame.height = Math.abs(p.y - start.y); frame.draw();\n}\n\nexport function handleWebEmbedUp() {\n if (!frame) return;\n if (frame.width < 40 || frame.height < 30) { frame.width = 560; frame.height = 315; }\n frame.draw(); pushCreateAction(frame);\n const placedFrame = frame;\n window.__pendingWebEmbedURL = null; frame = null; start = null;\n window.__sketchStoreApi?.setActiveTool('select', { afterDraw: true });\n currentShape = placedFrame; placedFrame.selectFrame();\n}\n\nwindow.__placeWebEmbed = placeWebEmbed;\n", "/* eslint-disable */\n// Event dispatcher - extracted from eventListeners.js\n// Central event routing for all tools\n\nimport { handleMouseDownRect, handleMouseMoveRect, handleMouseUpRect } from '../tools/rectangleTool.js';\nimport { handleMouseDownArrow, handleMouseMoveArrow, handleMouseUpArrow } from '../tools/arrowTool.js';\nimport { handleMouseDownCircle, handleMouseMoveCircle, handleMouseUpCircle } from '../tools/circleTool.js';\nimport { handleMouseUpImage, handleMouseDownImage, handleMouseMoveImage } from '../tools/imageTool.js';\nimport { handleMouseDownLine, handleMouseMoveLine, handleMouseUpLine } from '../tools/lineTool.js';\nimport { handleFreehandMouseDown, handleFreehandMouseMove, handleFreehandMouseUp } from '../tools/freehandTool.js';\nimport { handleTextMouseDown, handleTextMouseMove, handleTextMouseUp, enterEditMode } from '../tools/textTool.js';\nimport { handleMouseDownFrame, handleMouseMoveFrame, handleMouseUpFrame } from '../tools/frameTool.js';\nimport { handleMultiSelectionMouseDown, handleMultiSelectionMouseMove, handleMultiSelectionMouseUp, removeMultiSelectionRect, multiSelection, isMultiSelecting} from './Selection.js';\nimport { handleMouseDownIcon, handleMouseMoveIcon, handleMouseUpIcon } from '../tools/iconTool.js';\nimport { handleCodeMouseDown, handleCodeMouseMove, handleCodeMouseUp } from '../tools/codeTool.js';\nimport { handleShapeRecognitionDown, handleShapeRecognitionMove, handleShapeRecognitionUp } from '../tools/shapeRecognitionTool.js';\nimport { handlePaintBucketDown } from '../tools/paintBucketTool.js';\nimport { handleLassoDown, handleLassoMove, handleLassoUp } from '../tools/lassoTool.js';\nimport { handleWebEmbedDown, handleWebEmbedMove, handleWebEmbedUp } from '../tools/webEmbedTool.js';\n\n// === Auto-scroll when dragging near viewport edges ===\nconst EDGE_THRESHOLD = 40; // px from edge to start scrolling\nconst SCROLL_SPEED = 8; // base px per frame (scaled by zoom)\nlet _autoScrollRAF = null;\n\nfunction _autoScroll(e) {\n if (!(e.buttons & 1)) { _stopAutoScroll(); return; } // no primary button\n if (typeof currentViewBox === 'undefined' || typeof currentZoom === 'undefined') return;\n if (typeof isPanning !== 'undefined' && isPanning) return; // don't fight pan tool\n if (typeof isPanningToolActive !== 'undefined' && isPanningToolActive) return;\n\n const rect = svg.getBoundingClientRect();\n const mx = e.clientX - rect.left;\n const my = e.clientY - rect.top;\n\n let dx = 0, dy = 0;\n if (mx < EDGE_THRESHOLD) dx = -SCROLL_SPEED * (1 - mx / EDGE_THRESHOLD);\n else if (mx > rect.width - EDGE_THRESHOLD) dx = SCROLL_SPEED * (1 - (rect.width - mx) / EDGE_THRESHOLD);\n if (my < EDGE_THRESHOLD) dy = -SCROLL_SPEED * (1 - my / EDGE_THRESHOLD);\n else if (my > rect.height - EDGE_THRESHOLD) dy = SCROLL_SPEED * (1 - (rect.height - my) / EDGE_THRESHOLD);\n\n // Also scroll when cursor is outside the canvas entirely\n if (e.clientX < rect.left) dx = -SCROLL_SPEED;\n else if (e.clientX > rect.right) dx = SCROLL_SPEED;\n if (e.clientY < rect.top) dy = -SCROLL_SPEED;\n else if (e.clientY > rect.bottom) dy = SCROLL_SPEED;\n\n if (dx === 0 && dy === 0) { _stopAutoScroll(); return; }\n\n // Scale speed inversely with zoom so scrolling feels consistent\n const scale = 1 / currentZoom;\n currentViewBox.x += dx * scale;\n currentViewBox.y += dy * scale;\n svg.setAttribute('viewBox', `${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`);\n if (typeof freehandCanvas !== 'undefined' && freehandCanvas !== svg) {\n freehandCanvas.setAttribute('viewBox', `${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`);\n }\n}\n\nfunction _startAutoScroll() {\n if (_autoScrollRAF) return;\n const tick = () => {\n if (_lastDragEvent) _autoScroll(_lastDragEvent);\n _autoScrollRAF = requestAnimationFrame(tick);\n };\n _autoScrollRAF = requestAnimationFrame(tick);\n}\n\nfunction _stopAutoScroll() {\n if (_autoScrollRAF) {\n cancelAnimationFrame(_autoScrollRAF);\n _autoScrollRAF = null;\n }\n _lastDragEvent = null;\n}\n\nlet _lastDragEvent = null;\nlet _documentDragActive = false;\n\nfunction _onDocumentDragMove(e) {\n _lastDragEvent = e;\n // Clamp mouse coordinates to SVG bounds before forwarding to tool handlers,\n // so getSVGCoordsFromMouse doesn't produce extreme values when cursor is outside.\n const rect = svg.getBoundingClientRect();\n const clampedX = Math.max(rect.left, Math.min(rect.right, e.clientX));\n const clampedY = Math.max(rect.top, Math.min(rect.bottom, e.clientY));\n const clampedEvent = new PointerEvent(e.type, {\n clientX: clampedX,\n clientY: clampedY,\n buttons: e.buttons,\n button: e.button,\n ctrlKey: e.ctrlKey,\n shiftKey: e.shiftKey,\n altKey: e.altKey,\n metaKey: e.metaKey,\n });\n handleMainMouseMove(clampedEvent);\n}\n\nfunction _onDocumentDragUp(e) {\n _stopAutoScroll();\n document.removeEventListener('pointermove', _onDocumentDragMove);\n document.removeEventListener('pointerup', _onDocumentDragUp);\n _documentDragActive = false;\n // Finalize the operation\n handleMainMouseUp(e);\n}\n\nconst handleMainMouseDown = (e) => {\n if (!e.target) return;\n // Middle / right mouse buttons are reserved for panning and the\n // browser context menu; they should NOT trigger tool actions or the\n // multi-selection rectangle. Without this guard, middle-click-drag\n // simultaneously pans (handled in ZoomPan) and starts a selection\n // marquee.\n if (e.button === 1 || e.button === 2 || window.__spacePanActive) return;\n // Safety: remove any stray selection rectangle from a previous interrupted drag\n removeMultiSelectionRect();\n\n // For non-selection tools: deselect everything when clicking on empty canvas\n // (Selection tool handles its own deselection in handleMultiSelectionMouseDown)\n if (!isSelectionToolActive) {\n // Clear multi-selection for any tool switch\n if (multiSelection.selectedShapes.size > 0) {\n multiSelection.clearSelection();\n }\n // Deselect current individual shape when starting a new tool action\n if (currentShape && typeof currentShape.removeSelection === 'function') {\n currentShape.removeSelection();\n currentShape = null;\n }\n if (typeof disableAllSideBars === 'function') {\n disableAllSideBars();\n }\n }\n\n if (window.isLassoToolActive) {\n handleLassoDown(e);\n } else if (window.isWebEmbedToolActive) {\n handleWebEmbedDown(e);\n } else if (window.isShapeRecognitionToolActive) {\n handleShapeRecognitionDown(e);\n } else if (window.isPaintBucketToolActive) {\n handlePaintBucketDown(e);\n } else if (isSquareToolActive) {\n handleMouseDownRect(e);\n } else if (isArrowToolActive) {\n handleMouseDownArrow(e);\n } else if (isCircleToolActive) {\n handleMouseDownCircle(e);\n } else if (isImageToolActive) {\n handleMouseDownImage(e);\n } \n else if (isLineToolActive) {\n handleMouseDownLine(e);\n }\n else if (isPaintToolActive) {\n handleFreehandMouseDown(e);\n }\n else if (isTextToolActive) {\n // Text tool handles both text and code shapes based on target and mode\n const targetCodeGroup = e.target.closest('g[data-type=\"code-group\"]');\n const targetTextGroup = e.target.closest('g[data-type=\"text-group\"]');\n if (targetCodeGroup && !targetTextGroup) {\n handleCodeMouseDown(e);\n } else if (isTextInCodeMode && !targetTextGroup && !targetCodeGroup) {\n handleCodeMouseDown(e);\n } else {\n handleTextMouseDown(e);\n }\n }\n else if (isFrameToolActive) {\n handleMouseDownFrame(e);\n }\n else if (isIconToolActive) {\n handleMouseDownIcon(e);\n }\n else if (isSelectionToolActive) {\n // Try multi-selection first when selection tool is active\n if (handleMultiSelectionMouseDown(e)) {\n return; // Multi-selection handled the event\n }\n\n // Remember previous shape to detect deselection\n const prevShape = currentShape;\n let handled = false;\n\n // If multi-selection didn't handle it, proceed with shape-specific selection\n if (currentShape?.shapeName === 'rectangle') {\n handleMouseDownRect(e);\n handled = true;\n } else if (currentShape?.shapeName === 'arrow') {\n handleMouseDownArrow(e);\n handled = true;\n } else if (currentShape?.shapeName === 'circle') {\n handleMouseDownCircle(e);\n handled = true;\n } else if (currentShape?.shapeName === 'image') {\n handleMouseDownImage(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'line') {\n handleMouseDownLine(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'freehandStroke') {\n handleFreehandMouseDown(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'text') {\n handleTextMouseDown(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'frame') {\n handleMouseDownFrame(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'icon') {\n handleMouseDownIcon(e);\n handled = true;\n }\n else if( currentShape?.shapeName === 'code') {\n handleCodeMouseDown(e);\n handled = true;\n }\n\n // If the handler deselected (currentShape cleared) but didn't select something new,\n // fall through to try all handlers so clicking another shape type works\n if (handled && prevShape && !currentShape) {\n handled = false;\n }\n\n if (!handled) {\n const originalCurrentShape = currentShape;\n handleMouseDownRect(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownCircle(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownArrow(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownImage(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownLine(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleFreehandMouseDown(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleTextMouseDown(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownFrame(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownIcon(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleCodeMouseDown(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n if (currentShape === originalCurrentShape) {\n if (currentShape) {\n currentShape.removeSelection();\n currentShape = null;\n }\n }\n }\n }\n};\n\nconst handleMainMouseMove = (e) => {\n if (window.__spacePanPointerActive) return;\n // Auto-scroll when dragging near/past viewport edges (checked first so early returns don't skip it)\n if (e.buttons & 1) {\n _lastDragEvent = e;\n _startAutoScroll();\n } else {\n _stopAutoScroll();\n }\n\n if (window.isLassoToolActive) {\n handleLassoMove(e);\n } else if (window.isWebEmbedToolActive) {\n handleWebEmbedMove(e);\n } else if (window.isShapeRecognitionToolActive) {\n handleShapeRecognitionMove(e);\n } else if (window.isPaintBucketToolActive) {\n return;\n } else if (isSquareToolActive) {\n handleMouseMoveRect(e);\n } else if (isArrowToolActive) {\n handleMouseMoveArrow(e);\n } else if (isCircleToolActive) {\n handleMouseMoveCircle(e);\n } else if (isImageToolActive) {\n handleMouseMoveImage(e);\n } \n else if (isLineToolActive) {\n handleMouseMoveLine(e);\n }\n else if (isPaintToolActive) {\n handleFreehandMouseMove(e);\n }\n else if (isTextToolActive) {\n handleTextMouseMove(e);\n handleCodeMouseMove(e);\n }\n else if (isFrameToolActive) {\n handleMouseMoveFrame(e);\n }\n else if (isIconToolActive) {\n handleMouseMoveIcon(e);\n }\n else if (isSelectionToolActive) {\n // Handle multi-selection operations first - these take priority\n if (isMultiSelecting || multiSelection.isDragging || multiSelection.isResizing || multiSelection.isRotating) {\n if (handleMultiSelectionMouseMove(e)) {\n return; // Multi-selection handled the event\n }\n }\n \n // Shape-specific mouse move handling\n if (currentShape?.shapeName === 'rectangle') {\n handleMouseMoveRect(e);\n } else if (currentShape?.shapeName === 'arrow') {\n handleMouseMoveArrow(e);\n } else if (currentShape?.shapeName === 'circle') {\n handleMouseMoveCircle(e);\n } else if (currentShape?.shapeName === 'image') {\n handleMouseMoveImage(e);\n } \n else if (currentShape?.shapeName === 'line') {\n handleMouseMoveLine(e);\n }\n else if (currentShape?.shapeName === 'freehandStroke') {\n handleFreehandMouseMove(e);\n }\n else if (currentShape?.shapeName === 'text') {\n handleTextMouseMove(e);\n }\n else if (currentShape?.shapeName === 'frame') {\n handleMouseMoveFrame(e);\n }\n else if (currentShape?.shapeName === 'icon') {\n handleMouseMoveIcon(e);\n }\n else if (currentShape?.shapeName === 'code') {\n handleCodeMouseMove(e);\n }\n\n else {\n // Try multi-selection mouse move for cursor updates\n if (handleMultiSelectionMouseMove(e)) {\n return;\n }\n \n handleMouseMoveRect(e);\n handleMouseMoveArrow(e);\n handleMouseMoveCircle(e);\n handleMouseMoveImage(e);\n handleMouseMoveLine(e);\n handleFreehandMouseMove(e);\n handleTextMouseMove(e);\n handleMouseMoveFrame(e);\n handleMouseMoveIcon(e);\n handleCodeMouseMove(e);\n }\n }\n};\n\nconst handleMainMouseUp = (e) => {\n if (window.__spacePanPointerActive) return;\n _stopAutoScroll();\n if (window.isLassoToolActive) {\n handleLassoUp(e);\n } else if (window.isWebEmbedToolActive) {\n handleWebEmbedUp(e);\n } else if (window.isShapeRecognitionToolActive) {\n handleShapeRecognitionUp(e);\n } else if (window.isPaintBucketToolActive) {\n return;\n } else if (isSquareToolActive) {\n handleMouseUpRect(e);\n } else if (isArrowToolActive) {\n handleMouseUpArrow(e);\n } else if (isCircleToolActive) {\n handleMouseUpCircle(e);\n } else if (isImageToolActive) {\n handleMouseUpImage(e);\n } \n else if (isLineToolActive) { \n handleMouseUpLine(e);\n }\n else if (isPaintToolActive) {\n handleFreehandMouseUp(e);\n }\n else if (isTextToolActive) {\n handleTextMouseUp(e);\n handleCodeMouseUp(e);\n }\n else if (isFrameToolActive) {\n handleMouseUpFrame(e);\n }\n else if (isIconToolActive) {\n handleMouseUpIcon(e);\n }\n\n else if (isSelectionToolActive) {\n // Always try multi-selection cleanup first\n if (isMultiSelecting || multiSelection.isDragging || multiSelection.isResizing || multiSelection.isRotating) {\n handleMultiSelectionMouseUp(e);\n return;\n }\n\n // Shape-specific mouse up handling\n if (currentShape?.shapeName === 'rectangle') {\n handleMouseUpRect(e);\n } else if (currentShape?.shapeName === 'arrow') {\n handleMouseUpArrow(e);\n } else if (currentShape?.shapeName === 'circle') {\n handleMouseUpCircle(e);\n } else if (currentShape?.shapeName === 'image') {\n handleMouseUpImage(e);\n }\n else if (currentShape?.shapeName === 'line') {\n handleMouseUpLine(e);\n }\n else if (currentShape?.shapeName === 'freehandStroke') {\n handleFreehandMouseUp(e);\n }\n else if (currentShape?.shapeName === 'text') {\n handleTextMouseUp(e);\n }\n else if (currentShape?.shapeName === 'frame') {\n handleMouseUpFrame(e);\n }\n else if (currentShape?.shapeName === 'icon') {\n handleMouseUpIcon(e);\n }\n else if (currentShape?.shapeName === 'code') {\n handleCodeMouseUp(e);\n }\n\n else {\n handleMultiSelectionMouseUp(e);\n handleMouseUpRect(e);\n handleMouseUpArrow(e);\n handleMouseUpCircle(e);\n handleMouseUpImage(e);\n handleMouseUpLine(e);\n handleFreehandMouseUp(e);\n handleTextMouseUp(e);\n handleMouseUpFrame(e);\n handleMouseUpIcon(e);\n handleCodeMouseUp(e);\n }\n }\n};\n\nconst handleMainMouseLeave = (e) => {\n if (window.__spacePanPointerActive) return;\n // If the user is still holding the primary button (dragging outside the canvas),\n // keep auto-scrolling and don't finalize the operation yet.\n if (e.buttons & 1) {\n _lastDragEvent = e;\n _startAutoScroll();\n\n // Listen on document to continue receiving move events outside the SVG\n if (!_documentDragActive) {\n _documentDragActive = true;\n document.addEventListener('pointermove', _onDocumentDragMove);\n document.addEventListener('pointerup', _onDocumentDragUp);\n }\n return;\n }\n\n // Stop all active drawing tools when pointer leaves the canvas\n\n // Fire mouseUp for whichever tool is active to finalize/cancel the operation\n handleMainMouseUp(e);\n\n // Always clean up any stray selection rectangle when pointer leaves canvas\n removeMultiSelectionRect();\n\n // Eraser: force cleanup any lingering trail\n if (typeof window.forceCleanupEraserTrail === 'function') {\n window.forceCleanupEraserTrail();\n }\n\n // Laser: stop drawing and fade out active laser (globals from laserTool.js)\n if (typeof isDrawing !== 'undefined' && isDrawing) {\n isDrawing = false;\n if (typeof lasers !== 'undefined' && lasers.length > 0 && typeof fadeLaserTrail === 'function') {\n const lastLaser = lasers[lasers.length - 1];\n fadeLaserTrail(lastLaser);\n }\n }\n};\n\nlet _boundSvg = null;\n\nfunction _onMouseEnter(e) {\n // Cursor re-entered the SVG \u2014 stop document-level tracking, SVG handles events again\n if (_documentDragActive) {\n document.removeEventListener('pointermove', _onDocumentDragMove);\n document.removeEventListener('pointerup', _onDocumentDragUp);\n _documentDragActive = false;\n }\n}\n\nconst handleMainDblClick = (e) => {\n if (!e.target) return;\n // Double-click on a text group from any tool: enter text edit mode\n const targetTextGroup = e.target.closest('g[data-type=\"text-group\"]');\n if (targetTextGroup) {\n e.stopPropagation();\n enterEditMode(targetTextGroup);\n }\n};\n\nfunction initEventDispatcher(svgEl) {\n if (_boundSvg) cleanupEventDispatcher();\n const target = svgEl || svg;\n target.addEventListener('pointerdown', handleMainMouseDown);\n target.addEventListener('pointermove', handleMainMouseMove);\n target.addEventListener('pointerup', handleMainMouseUp);\n target.addEventListener('pointerleave', handleMainMouseLeave);\n target.addEventListener('pointerenter', _onMouseEnter);\n target.addEventListener('dblclick', handleMainDblClick);\n _boundSvg = target;\n}\n\nfunction cleanupEventDispatcher() {\n _stopAutoScroll();\n if (_documentDragActive) {\n document.removeEventListener('pointermove', _onDocumentDragMove);\n document.removeEventListener('pointerup', _onDocumentDragUp);\n _documentDragActive = false;\n }\n if (_boundSvg) {\n _boundSvg.removeEventListener('pointerdown', handleMainMouseDown);\n _boundSvg.removeEventListener('pointermove', handleMainMouseMove);\n _boundSvg.removeEventListener('pointerup', handleMainMouseUp);\n _boundSvg.removeEventListener('pointerleave', handleMainMouseLeave);\n _boundSvg.removeEventListener('pointerenter', _onMouseEnter);\n _boundSvg.removeEventListener('dblclick', handleMainDblClick);\n _boundSvg = null;\n }\n}\n\n// Auto-init if svg is already available (first load)\nif (typeof svg !== 'undefined' && svg) {\n initEventDispatcher(svg);\n}\n\nexport { handleMainMouseDown, handleMainMouseMove, handleMainMouseUp, handleMainMouseLeave, initEventDispatcher, cleanupEventDispatcher };\n"],
|
|
4
|
+
"sourcesContent": ["const MIN_SHAPE_SIZE = 8;\n\nexport const MAX_GESTURE_POINTS = 96;\n\nexport function distance(a, b) {\n return Math.hypot(b.x - a.x, b.y - a.y);\n}\n\nfunction orientedBounds(sample, angle) {\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n let minU = Infinity;\n let maxU = -Infinity;\n let minV = Infinity;\n let maxV = -Infinity;\n for (const point of sample) {\n const u = point.x * cos + point.y * sin;\n const v = -point.x * sin + point.y * cos;\n minU = Math.min(minU, u);\n maxU = Math.max(maxU, u);\n minV = Math.min(minV, v);\n maxV = Math.max(maxV, v);\n }\n const centerU = (minU + maxU) / 2;\n const centerV = (minV + maxV) / 2;\n return {\n center: {\n x: centerU * cos - centerV * sin,\n y: centerU * sin + centerV * cos,\n },\n width: Math.max(MIN_SHAPE_SIZE, maxU - minU),\n height: Math.max(MIN_SHAPE_SIZE, maxV - minV),\n angle,\n minU,\n maxU,\n minV,\n maxV,\n };\n}\n\nfunction principalAngle(sample) {\n let meanX = 0;\n let meanY = 0;\n for (const point of sample) {\n meanX += point.x;\n meanY += point.y;\n }\n meanX /= sample.length;\n meanY /= sample.length;\n let xx = 0;\n let yy = 0;\n let xy = 0;\n for (const point of sample) {\n const dx = point.x - meanX;\n const dy = point.y - meanY;\n xx += dx * dx;\n yy += dy * dy;\n xy += dx * dy;\n }\n if (Math.abs(xx - yy) + Math.abs(xy) < 0.001) return 0;\n return Math.atan2(2 * xy, xx - yy) / 2;\n}\n\nfunction rectangleAngle(sample) {\n let x = 0;\n let y = 0;\n for (let index = 1; index < sample.length; index += 1) {\n const dx = sample[index].x - sample[index - 1].x;\n const dy = sample[index].y - sample[index - 1].y;\n const length = Math.hypot(dx, dy);\n if (length === 0) continue;\n const angle = Math.atan2(dy, dx) * 4;\n x += Math.cos(angle) * length;\n y += Math.sin(angle) * length;\n }\n return Math.atan2(y, x) / 4;\n}\n\nfunction pointToSegmentDistance(point, start, end) {\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n const lengthSquared = dx * dx + dy * dy;\n if (lengthSquared === 0) return distance(point, start);\n const amount = Math.max(0, Math.min(1,\n ((point.x - start.x) * dx + (point.y - start.y) * dy) / lengthSquared));\n return Math.hypot(point.x - (start.x + dx * amount), point.y - (start.y + dy * amount));\n}\n\nfunction polygonError(sample, vertices, scale) {\n let total = 0;\n for (const point of sample) {\n let nearest = Infinity;\n for (let index = 0; index < vertices.length; index += 1) {\n nearest = Math.min(nearest, pointToSegmentDistance(\n point,\n vertices[index],\n vertices[(index + 1) % vertices.length],\n ));\n }\n total += nearest;\n }\n return total / sample.length / Math.max(scale, MIN_SHAPE_SIZE);\n}\n\nfunction polygonVertices(bounds, kind) {\n const cos = Math.cos(bounds.angle);\n const sin = Math.sin(bounds.angle);\n const toWorld = (u, v) => ({\n x: u * cos - v * sin,\n y: u * sin + v * cos,\n });\n const centerU = (bounds.minU + bounds.maxU) / 2;\n const centerV = (bounds.minV + bounds.maxV) / 2;\n const local = kind === 'triangle'\n ? [[centerU, bounds.minV], [bounds.maxU, bounds.maxV], [bounds.minU, bounds.maxV]]\n : kind === 'diamond'\n ? [[centerU, bounds.minV], [bounds.maxU, centerV], [centerU, bounds.maxV], [bounds.minU, centerV]]\n : [[bounds.minU, bounds.minV], [bounds.maxU, bounds.minV], [bounds.maxU, bounds.maxV], [bounds.minU, bounds.maxV]];\n return local.map(([u, v]) => toWorld(u, v));\n}\n\nfunction trianglePrediction(sample, pathLength) {\n const baseAngle = principalAngle(sample);\n let best = null;\n // Principal axes do not encode direction. Testing four quarter turns keeps\n // the fit rotation-independent while retaining a constant number of O(N)\n // passes over the capped gesture sample.\n for (let turn = 0; turn < 4; turn += 1) {\n const bounds = orientedBounds(sample, baseAngle + turn * Math.PI / 2);\n const vertices = polygonVertices(bounds, 'triangle');\n const error = polygonError(sample, vertices, Math.hypot(bounds.width, bounds.height));\n if (!best || error < best.error) best = { bounds, vertices, error };\n }\n if (!best || best.error > 0.045) return null;\n return {\n type: 'triangle',\n ...best.bounds,\n vertices: best.vertices,\n pathLength,\n };\n}\n\nfunction diamondPrediction(sample, pathLength) {\n const bounds = orientedBounds(sample, principalAngle(sample));\n const vertices = polygonVertices(bounds, 'diamond');\n const error = polygonError(sample, vertices, Math.hypot(bounds.width, bounds.height));\n if (error > 0.035) return null;\n return { type: 'diamond', ...bounds, vertices, pathLength };\n}\n\nfunction closedShapePrediction(sample, pathLength) {\n const triangle = trianglePrediction(sample, pathLength);\n if (triangle) return triangle;\n const fittedDiamond = diamondPrediction(sample, pathLength);\n if (fittedDiamond) return fittedDiamond;\n const rectBounds = orientedBounds(sample, rectangleAngle(sample));\n const ellipseBounds = orientedBounds(sample, principalAngle(sample));\n let rectangleError = 0;\n let ellipseError = 0;\n const rectCos = Math.cos(rectBounds.angle);\n const rectSin = Math.sin(rectBounds.angle);\n const ellipseCos = Math.cos(ellipseBounds.angle);\n const ellipseSin = Math.sin(ellipseBounds.angle);\n const rectHalfW = rectBounds.width / 2;\n const rectHalfH = rectBounds.height / 2;\n const ellipseHalfW = ellipseBounds.width / 2;\n const ellipseHalfH = ellipseBounds.height / 2;\n\n for (const point of sample) {\n const rectDx = point.x - rectBounds.center.x;\n const rectDy = point.y - rectBounds.center.y;\n const rectU = Math.abs(rectDx * rectCos + rectDy * rectSin) / rectHalfW;\n const rectV = Math.abs(-rectDx * rectSin + rectDy * rectCos) / rectHalfH;\n rectangleError += Math.min(Math.abs(1 - rectU), Math.abs(1 - rectV));\n const ellipseDx = point.x - ellipseBounds.center.x;\n const ellipseDy = point.y - ellipseBounds.center.y;\n const ellipseU = (ellipseDx * ellipseCos + ellipseDy * ellipseSin) / ellipseHalfW;\n const ellipseV = (-ellipseDx * ellipseSin + ellipseDy * ellipseCos) / ellipseHalfH;\n ellipseError += Math.abs(1 - Math.hypot(ellipseU, ellipseV));\n }\n\n rectangleError /= sample.length;\n ellipseError /= sample.length;\n const rectangle = rectangleError <= ellipseError * 1.08;\n const bestError = rectangle ? rectangleError : ellipseError;\n if (bestError > 0.24) {\n return { type: 'freehand', points: sample.map((point) => ({ ...point })), pathLength };\n }\n const bounds = rectangle ? rectBounds : ellipseBounds;\n const normalizedAngle = Math.abs(Math.atan2(Math.sin(rectBounds.angle * 2), Math.cos(rectBounds.angle * 2)) / 2);\n const diamond = rectangle && normalizedAngle >= Math.PI / 7;\n return {\n type: diamond ? 'diamond' : (rectangle ? 'rectangle' : 'circle'),\n ...bounds,\n ...(diamond ? { vertices: polygonVertices(rectBounds, 'rectangle') } : {}),\n pathLength,\n };\n}\n\nexport function capGestureSample(sample, maxPoints = MAX_GESTURE_POINTS) {\n if (!Array.isArray(sample) || sample.length <= maxPoints) return Array.isArray(sample) ? sample : [];\n if (maxPoints <= 1) return sample.slice(0, Math.max(0, maxPoints));\n const capped = [sample[0]];\n const step = (sample.length - 1) / (maxPoints - 1);\n for (let index = 1; index < maxPoints - 1; index += 1) {\n capped.push(sample[Math.round(index * step)]);\n }\n capped.push(sample[sample.length - 1]);\n return capped;\n}\n\nexport function predictDrawnShape(input) {\n const sample = capGestureSample(input);\n if (sample.length < 2) return null;\n const start = sample[0];\n let pathLength = 0;\n let farthestIndex = 1;\n let farthestDistance = 0;\n let minX = start.x;\n let maxX = start.x;\n let minY = start.y;\n let maxY = start.y;\n\n for (let index = 1; index < sample.length; index += 1) {\n pathLength += distance(sample[index - 1], sample[index]);\n const fromStart = distance(start, sample[index]);\n if (fromStart > farthestDistance) {\n farthestDistance = fromStart;\n farthestIndex = index;\n }\n minX = Math.min(minX, sample[index].x);\n maxX = Math.max(maxX, sample[index].x);\n minY = Math.min(minY, sample[index].y);\n maxY = Math.max(maxY, sample[index].y);\n }\n\n const diagonal = Math.max(MIN_SHAPE_SIZE, Math.hypot(maxX - minX, maxY - minY));\n const end = sample[sample.length - 1];\n const closed = sample.length >= 8 && distance(start, end) <= diagonal * 0.28 && pathLength >= diagonal * 1.85;\n if (closed) return closedShapePrediction(sample, pathLength);\n\n const tip = sample[farthestIndex];\n let afterTipLength = 0;\n for (let index = farthestIndex + 1; index < sample.length; index += 1) {\n afterTipLength += distance(sample[index - 1], sample[index]);\n }\n let shaftLength = 0;\n for (let index = 1; index <= farthestIndex; index += 1) {\n shaftLength += distance(sample[index - 1], sample[index]);\n }\n const arrow = farthestIndex >= Math.floor(sample.length * 0.45)\n && farthestIndex < sample.length - 2\n && afterTipLength >= diagonal * 0.18\n && distance(end, tip) <= diagonal * 0.48\n && farthestDistance / Math.max(shaftLength, 1) >= 0.86;\n const directDistance = distance(start, end);\n const line = !arrow && directDistance / Math.max(pathLength, 1) >= 0.92;\n\n if (!arrow && !line) {\n return { type: 'freehand', points: sample.map((point) => ({ ...point })), pathLength };\n }\n return {\n type: arrow ? 'arrow' : 'line',\n start: { ...start },\n end: arrow ? { ...tip } : { ...end },\n width: Math.max(MIN_SHAPE_SIZE, maxX - minX),\n height: Math.max(MIN_SHAPE_SIZE, maxY - minY),\n pathLength,\n };\n}\n", "/* eslint-disable */\nimport { pushCreateAction, pushFrameAttachmentAction } from '../core/UndoRedo.js';\nimport {\n MAX_GESTURE_POINTS,\n distance,\n predictDrawnShape,\n} from './shapeRecognition.js';\n\nexport {\n MAX_GESTURE_POINTS,\n capGestureSample,\n predictDrawnShape,\n} from './shapeRecognition.js';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst MIN_SCREEN_SAMPLE_PX = 4;\n\nlet drawing = false;\nlet points = [];\nlet previewPath = null;\nlet previewFrame = 0;\nlet latestPrediction = null;\n\nfunction getThemeStroke() {\n return document.body?.classList.contains('theme-dark') ? '#f7f4ff' : '#000000';\n}\n\nfunction getSVGPoint(event) {\n const viewBox = svg.viewBox.baseVal;\n const rect = svg.getBoundingClientRect();\n return {\n x: viewBox.x + ((event.clientX - rect.left) / rect.width) * viewBox.width,\n y: viewBox.y + ((event.clientY - rect.top) / rect.height) * viewBox.height,\n pressure: event.pressure || 0.5,\n };\n}\n\nfunction rotatedPoint(center, x, y, angle) {\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n return { x: center.x + x * cos - y * sin, y: center.y + x * sin + y * cos };\n}\n\nfunction pathForPrediction(prediction) {\n if (!prediction) return '';\n if (prediction.type === 'rectangle') {\n const halfW = prediction.width / 2;\n const halfH = prediction.height / 2;\n const corners = [\n rotatedPoint(prediction.center, -halfW, -halfH, prediction.angle),\n rotatedPoint(prediction.center, halfW, -halfH, prediction.angle),\n rotatedPoint(prediction.center, halfW, halfH, prediction.angle),\n rotatedPoint(prediction.center, -halfW, halfH, prediction.angle),\n ];\n return `M ${corners[0].x} ${corners[0].y} L ${corners[1].x} ${corners[1].y} L ${corners[2].x} ${corners[2].y} L ${corners[3].x} ${corners[3].y} Z`;\n }\n if (prediction.type === 'circle') {\n const rx = prediction.width / 2;\n const ry = prediction.height / 2;\n const start = rotatedPoint(prediction.center, rx, 0, prediction.angle);\n const opposite = rotatedPoint(prediction.center, -rx, 0, prediction.angle);\n const rotation = prediction.angle * 180 / Math.PI;\n return `M ${start.x} ${start.y} A ${rx} ${ry} ${rotation} 1 0 ${opposite.x} ${opposite.y} A ${rx} ${ry} ${rotation} 1 0 ${start.x} ${start.y}`;\n }\n if (prediction.type === 'triangle' || prediction.type === 'diamond') {\n return prediction.vertices.reduce(\n (path, point, index) => `${path}${index === 0 ? 'M' : ' L'} ${point.x} ${point.y}`,\n '',\n ) + ' Z';\n }\n if (prediction.type === 'freehand') {\n if (!prediction.points.length) return '';\n return prediction.points.reduce((path, point, index) => `${path}${index === 0 ? 'M' : ' L'} ${point.x} ${point.y}`, '');\n }\n const { start, end } = prediction;\n let path = `M ${start.x} ${start.y} L ${end.x} ${end.y}`;\n if (prediction.type === 'arrow') {\n const angle = Math.atan2(end.y - start.y, end.x - start.x);\n const head = Math.min(24 / (window.currentZoom || 1), distance(start, end) * 0.25);\n const left = rotatedPoint(end, -head, head * 0.55, angle);\n const right = rotatedPoint(end, -head, -head * 0.55, angle);\n path += ` M ${left.x} ${left.y} L ${end.x} ${end.y} L ${right.x} ${right.y}`;\n }\n return path;\n}\n\nfunction ensurePreview() {\n if (previewPath?.isConnected) return;\n previewPath = document.createElementNS(SVG_NS, 'path');\n previewPath.dataset.recognitionPreview = 'true';\n previewPath.setAttribute('fill', 'rgba(148, 148, 158, 0.06)');\n previewPath.setAttribute('stroke', '#9696a0');\n previewPath.setAttribute('stroke-width', '2');\n previewPath.setAttribute('stroke-dasharray', '5 7');\n previewPath.setAttribute('stroke-linecap', 'round');\n previewPath.setAttribute('stroke-linejoin', 'round');\n previewPath.setAttribute('vector-effect', 'non-scaling-stroke');\n previewPath.setAttribute('pointer-events', 'none');\n svg.appendChild(previewPath);\n}\n\nfunction renderPreview() {\n previewFrame = 0;\n if (!drawing) return;\n latestPrediction = predictDrawnShape(points);\n ensurePreview();\n previewPath.setAttribute('d', pathForPrediction(latestPrediction));\n previewPath.setAttribute('fill', ['rectangle', 'circle', 'triangle', 'diamond'].includes(latestPrediction?.type)\n ? 'rgba(148, 148, 158, 0.06)'\n : 'none');\n}\n\nfunction schedulePreview() {\n if (!previewFrame) previewFrame = requestAnimationFrame(renderPreview);\n}\n\nfunction cleanupPreview() {\n if (previewFrame) cancelAnimationFrame(previewFrame);\n previewFrame = 0;\n previewPath?.remove();\n previewPath = null;\n}\n\nfunction currentStyle() {\n const settings = window.freehandToolSettings || {};\n const outline = settings.strokeStyle || 'solid';\n return {\n stroke: settings.strokeColor || getThemeStroke(),\n fill: 'transparent',\n fillStyle: 'none',\n strokeWidth: settings.strokeWidth || 2,\n strokeDasharray: outline === 'dashed' ? '10,10' : (outline === 'dotted' ? '2,8' : ''),\n outline,\n };\n}\n\nfunction attachToContainingFrame(shape) {\n for (let index = shapes.length - 1; index >= 0; index -= 1) {\n const frame = shapes[index];\n if (frame.shapeName !== 'frame' || typeof frame.isShapeInFrame !== 'function') continue;\n if (!frame.isShapeInFrame(shape)) continue;\n frame.addShapeToFrame(shape);\n pushFrameAttachmentAction(frame, shape, 'attach', null);\n break;\n }\n}\n\nfunction createPredictedShape(prediction) {\n if (!prediction) return null;\n const style = currentStyle();\n let shape = null;\n if (prediction.type === 'rectangle') {\n shape = new window.Rectangle(\n prediction.center.x - prediction.width / 2,\n prediction.center.y - prediction.height / 2,\n prediction.width,\n prediction.height,\n style,\n );\n shape.rotation = prediction.angle * 180 / Math.PI;\n shape.draw();\n } else if (prediction.type === 'circle') {\n shape = new window.Circle(\n prediction.center.x,\n prediction.center.y,\n prediction.width / 2,\n prediction.height / 2,\n style,\n );\n shape.rotation = prediction.angle * 180 / Math.PI;\n shape.draw();\n } else if (prediction.type === 'triangle' || prediction.type === 'diamond') {\n const polygonPoints = [...prediction.vertices, prediction.vertices[0]];\n shape = new window.FreehandStroke(\n polygonPoints.map((point) => [point.x, point.y, 0.5]),\n {\n stroke: 'transparent',\n fill: 'transparent',\n fillStyle: 'none',\n outlineStroke: style.stroke,\n outlineWidth: style.strokeWidth,\n closedFill: true,\n strokeWidth: style.strokeWidth,\n strokeStyle: style.outline,\n roughness: 0,\n },\n );\n shape.recognizedShapeType = prediction.type;\n } else if (prediction.type === 'freehand') {\n const brush = window.freehandToolSettings || {};\n shape = new window.FreehandStroke(\n prediction.points.map((point) => [point.x, point.y, point.pressure || 0.5]),\n {\n stroke: style.stroke,\n strokeWidth: style.strokeWidth,\n strokeStyle: style.outline,\n thinning: brush.thinning ?? 0.5,\n roughness: brush.roughness || 'smooth',\n strokeOpacity: brush.opacity ?? 1,\n },\n );\n } else if (prediction.type === 'arrow') {\n shape = new window.Arrow(prediction.start, prediction.end, {\n stroke: style.stroke,\n strokeWidth: style.strokeWidth,\n arrowOutlineStyle: style.outline,\n arrowCurved: 'straight',\n });\n } else {\n shape = new window.Line(prediction.start, prediction.end, {\n stroke: style.stroke,\n strokeWidth: style.strokeWidth,\n strokeDasharray: style.strokeDasharray,\n roughness: 1.5,\n bowing: 1,\n });\n }\n shapes.push(shape);\n pushCreateAction(shape);\n attachToContainingFrame(shape);\n return shape;\n}\n\nexport function handleShapeRecognitionDown(event) {\n if (!window.isShapeRecognitionToolActive || event.button !== 0) return;\n drawing = true;\n points = [getSVGPoint(event)];\n latestPrediction = null;\n ensurePreview();\n schedulePreview();\n}\n\nexport function handleShapeRecognitionMove(event) {\n if (!drawing || !window.isShapeRecognitionToolActive) return;\n const point = getSVGPoint(event);\n const last = points[points.length - 1];\n const threshold = MIN_SCREEN_SAMPLE_PX / (window.currentZoom || 1);\n if (distance(last, point) < threshold) return;\n if (points.length < MAX_GESTURE_POINTS) {\n points.push(point);\n } else {\n // Preserve the first point and evenly discard older detail. Memory and\n // recognition time stay constant even during very long gestures.\n points = [points[0], ...points.slice(2).filter((_, index) => index % 2 === 0), point];\n }\n schedulePreview();\n}\n\nexport function handleShapeRecognitionUp(event) {\n if (!drawing) return;\n drawing = false;\n const rect = svg.getBoundingClientRect();\n if (event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom) {\n const point = getSVGPoint(event);\n if (distance(points[points.length - 1], point) > 0) points.push(point);\n }\n latestPrediction = predictDrawnShape(points);\n cleanupPreview();\n\n const prediction = latestPrediction;\n points = [];\n latestPrediction = null;\n if (!prediction || prediction.pathLength < MIN_SHAPE_SIZE) return;\n\n const shape = createPredictedShape(prediction);\n if (!shape) return;\n if (window.__sketchStoreApi) window.__sketchStoreApi.setActiveTool('select', { afterDraw: true });\n currentShape = shape;\n if (shape.shapeName === 'freehandStroke' && typeof shape.selectStroke === 'function') {\n shape.selectStroke();\n } else {\n shape.isSelected = true;\n if (typeof shape.addAnchors === 'function') shape.addAnchors();\n }\n}\n\nexport function cancelShapeRecognition() {\n drawing = false;\n points = [];\n latestPrediction = null;\n cleanupPreview();\n}\n\nwindow.__cancelShapeRecognition = cancelShapeRecognition;\n", "/* eslint-disable */\nimport { pushOptionsChangeAction } from '../core/UndoRedo.js';\n\nconst OPTION_FILL_SHAPES = new Set(['rectangle', 'circle']);\n\nwindow.paintBucketSettings = window.paintBucketSettings || {\n fillColor: '#A98DEB',\n fillStyle: 'solid',\n};\n\nfunction getSVGPoint(event) {\n const viewBox = svg.viewBox.baseVal;\n const rect = svg.getBoundingClientRect();\n return {\n x: viewBox.x + ((event.clientX - rect.left) / rect.width) * viewBox.width,\n y: viewBox.y + ((event.clientY - rect.top) / rect.height) * viewBox.height,\n };\n}\n\nfunction isClosedFreehand(shape) {\n if (shape?.shapeName !== 'freehandStroke' || !Array.isArray(shape.points) || shape.points.length < 3) return false;\n if (shape.options?.closedFill) return true;\n const first = shape.points[0];\n const last = shape.points[shape.points.length - 1];\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const point of shape.points) {\n const x = Number(point[0]) || 0;\n const y = Number(point[1]) || 0;\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\n const diagonal = Math.hypot(maxX - minX, maxY - minY);\n const closeDistance = Math.hypot(last[0] - first[0], last[1] - first[1]);\n const tolerance = Math.max((shape.options?.strokeWidth || 2) * 2, Math.min(16, diagonal * 0.08));\n return diagonal > 0 && closeDistance <= tolerance;\n}\n\nexport function isPaintBucketFillable(shape) {\n return OPTION_FILL_SHAPES.has(shape?.shapeName)\n || shape?.shapeName === 'frame'\n || isClosedFreehand(shape);\n}\n\nfunction findShapeAt(x, y) {\n for (let index = shapes.length - 1; index >= 0; index -= 1) {\n const shape = shapes[index];\n if (typeof shape?.contains !== 'function') continue;\n if (shape.contains(x, y)) return shape;\n }\n return null;\n}\n\nexport function fillShape(shape, settings = window.paintBucketSettings) {\n if (!isPaintBucketFillable(shape)) return false;\n const transparent = settings.fillStyle === 'none' || settings.fillStyle === 'transparent';\n const nextFill = transparent ? 'transparent' : settings.fillColor;\n const nextStyle = transparent ? 'none' : settings.fillStyle;\n\n if (shape.shapeName === 'frame') {\n if (shape.fillColor === nextFill && shape.fillStyle === nextStyle) return false;\n const oldOptions = { ...shape.options, fillColor: shape.fillColor, fillStyle: shape.fillStyle };\n const newOptions = { ...shape.options, fillColor: nextFill, fillStyle: nextStyle };\n pushOptionsChangeAction(shape, oldOptions, newOptions);\n shape.fillColor = nextFill;\n shape.fillStyle = nextStyle;\n shape.options = { ...shape.options, fillColor: nextFill, fillStyle: nextStyle };\n shape.draw();\n return true;\n }\n\n const freehandOptions = shape.shapeName === 'freehandStroke'\n ? {\n closedFill: true,\n outlineStroke: shape.options.outlineStroke || shape.options.stroke,\n }\n : {};\n if (shape.options.fill === nextFill\n && shape.options.fillStyle === nextStyle\n && Object.entries(freehandOptions).every(([key, value]) => shape.options[key] === value)) return false;\n\n const oldOptions = { ...shape.options };\n const newOptions = { ...shape.options, ...freehandOptions, fill: nextFill, fillStyle: nextStyle };\n pushOptionsChangeAction(shape, oldOptions, newOptions);\n shape.options = newOptions;\n shape.draw();\n return true;\n}\n\nexport function handlePaintBucketDown(event) {\n if (!window.isPaintBucketToolActive || event.button !== 0) return;\n const { x, y } = getSVGPoint(event);\n const shape = findShapeAt(x, y);\n if (!shape) {\n window.dispatchEvent(new CustomEvent('lixsketch:bucket-miss'));\n return;\n }\n if (!isPaintBucketFillable(shape)) {\n window.dispatchEvent(new CustomEvent('lixsketch:bucket-not-fillable', {\n detail: { shapeID: shape.shapeID, shapeType: shape.shapeName },\n }));\n return;\n }\n if (!fillShape(shape)) return;\n window.dispatchEvent(new CustomEvent('lixsketch:bucket-filled', { detail: { shapeID: shape.shapeID } }));\n}\n", "/* eslint-disable */\n\nimport { multiSelection } from '../core/Selection.js';\n\nconst MAX_POINTS = 192;\nconst MIN_SAMPLE_PX = 4;\nlet points = [];\nlet preview = null;\nlet drawing = false;\n\nfunction coords(e) {\n const vb = svg.viewBox.baseVal;\n const rect = svg.getBoundingClientRect();\n return { x: vb.x + ((e.clientX - rect.left) / rect.width) * vb.width, y: vb.y + ((e.clientY - rect.top) / rect.height) * vb.height };\n}\n\nfunction pointInPolygon(point, polygon) {\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const a = polygon[i], b = polygon[j];\n if (((a.y > point.y) !== (b.y > point.y)) && point.x < ((b.x - a.x) * (point.y - a.y)) / ((b.y - a.y) || Number.EPSILON) + a.x) inside = !inside;\n }\n return inside;\n}\n\nfunction boundsPoints(shape) {\n if ((shape.shapeName === 'line' || shape.shapeName === 'arrow') && shape.startPoint && shape.endPoint) return [shape.startPoint, shape.endPoint];\n if (shape.shapeName === 'freehandStroke' && Array.isArray(shape.points)) {\n const step = Math.max(1, Math.ceil(shape.points.length / 16));\n return shape.points.filter((_, i) => i % step === 0).map((p) => ({ x: p[0], y: p[1] }));\n }\n let x = shape.x || 0, y = shape.y || 0, width = shape.width || 0, height = shape.height || 0;\n if (shape.shapeName === 'circle') { x = shape.x - shape.rx; y = shape.y - shape.ry; width = shape.rx * 2; height = shape.ry * 2; }\n if ((!width || !height) && shape.group?.getBBox) {\n try { const box = shape.group.getBBox(); x = box.x; y = box.y; width = box.width; height = box.height; } catch {}\n }\n const raw = [{ x, y }, { x: x + width, y }, { x: x + width, y: y + height }, { x, y: y + height }, { x: x + width / 2, y: y + height / 2 }];\n const rotation = Number(shape.rotation) || 0;\n if (!rotation) return raw;\n const cx = x + width / 2, cy = y + height / 2, angle = rotation * Math.PI / 180;\n return raw.map((p) => ({ x: cx + (p.x - cx) * Math.cos(angle) - (p.y - cy) * Math.sin(angle), y: cy + (p.x - cx) * Math.sin(angle) + (p.y - cy) * Math.cos(angle) }));\n}\n\nfunction cleanup() {\n preview?.remove(); preview = null; points = []; drawing = false;\n}\n\nexport function handleLassoDown(e) {\n if (!window.isLassoToolActive) return;\n cleanup(); multiSelection.clearSelection(); drawing = true; points = [coords(e)];\n preview = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n preview.setAttribute('fill', 'rgba(139, 118, 214, .10)'); preview.setAttribute('stroke', '#a78bfa');\n preview.setAttribute('stroke-dasharray', '5 4'); preview.setAttribute('vector-effect', 'non-scaling-stroke');\n preview.style.pointerEvents = 'none'; svg.appendChild(preview);\n}\n\nexport function handleLassoMove(e) {\n if (!drawing) return;\n const p = coords(e), last = points[points.length - 1];\n const min = MIN_SAMPLE_PX / (window.currentZoom || 1);\n if (Math.hypot(p.x - last.x, p.y - last.y) < min) return;\n if (points.length < MAX_POINTS) points.push(p); else points[points.length - 1] = p;\n preview?.setAttribute('d', `M ${points.map((v) => `${v.x} ${v.y}`).join(' L ')} Z`);\n}\n\nexport function handleLassoUp() {\n if (!drawing) return;\n const polygon = points.slice(); cleanup();\n // Switching tools clears selection state. Do that before applying the\n // lasso result so the newly selected shapes survive the tool transition.\n window.__sketchStoreApi?.setActiveTool('select', { afterDraw: true });\n if (polygon.length >= 3 && Array.isArray(window.shapes)) {\n const selected = window.shapes.filter((shape) => boundsPoints(shape).every((p) => pointInPolygon(p, polygon)));\n const filtered = selected.filter((shape) => !shape.parentFrame || !selected.includes(shape.parentFrame));\n // Apply the batch once; addShape() rebuilds controls per item and becomes\n // unnecessarily quadratic for a large lasso selection.\n filtered.forEach((shape) => { multiSelection.selectedShapes.add(shape); shape.isSelected = true; });\n if (filtered.length) multiSelection.updateControls();\n window.currentShape = filtered.length === 1 ? filtered[0] : null;\n }\n}\n\nexport function cancelLasso() { cleanup(); }\nwindow.__cancelLasso = cancelLasso;\n", "/* eslint-disable */\n\nimport { Frame } from '../shapes/Frame.js';\nimport { pushCreateAction } from '../core/UndoRedo.js';\nimport { normalizeWebEmbedUrl } from '../core/WebEmbedPolicy.js';\n\nlet frame = null, start = null;\nfunction coords(e) {\n const vb = svg.viewBox.baseVal, rect = svg.getBoundingClientRect();\n return { x: vb.x + ((e.clientX - rect.left) / rect.width) * vb.width, y: vb.y + ((e.clientY - rect.top) / rect.height) * vb.height };\n}\n\nexport function placeWebEmbed(urlValue) {\n const url = normalizeWebEmbedUrl(urlValue);\n if (!url || typeof svg === 'undefined') return null;\n\n // Complete the tool transition first because setActiveTool clears the\n // previous selection. The newly inserted frame should remain selected.\n window.__sketchStoreApi?.setActiveTool('select');\n const viewBox = svg.viewBox.baseVal;\n const width = Math.min(640, Math.max(320, viewBox.width * 0.56));\n const height = width * 9 / 16;\n const x = viewBox.x + (viewBox.width - width) / 2;\n const y = viewBox.y + (viewBox.height - height) / 2;\n const placedFrame = new Frame(x, y, width, height, {\n frameName: 'Web embed', frameType: 'web-embed', webEmbedURL: url,\n stroke: '#8b76d6', strokeWidth: 2,\n });\n shapes.push(placedFrame);\n pushCreateAction(placedFrame);\n currentShape = placedFrame;\n placedFrame.selectFrame();\n window.__pendingWebEmbedURL = null;\n return placedFrame;\n}\n\nexport function handleWebEmbedDown(e) {\n const url = normalizeWebEmbedUrl(window.__pendingWebEmbedURL);\n if (!window.isWebEmbedToolActive || !url) { window.__showWebEmbedModal?.(); return; }\n start = coords(e);\n frame = new Frame(start.x, start.y, 0, 0, { frameName: 'Web embed', frameType: 'web-embed', webEmbedURL: url, stroke: '#8b76d6', strokeWidth: 2 });\n shapes.push(frame); currentShape = frame;\n}\n\nexport function handleWebEmbedMove(e) {\n if (!frame || !start) return;\n const p = coords(e); frame.x = Math.min(start.x, p.x); frame.y = Math.min(start.y, p.y);\n frame.width = Math.abs(p.x - start.x); frame.height = Math.abs(p.y - start.y); frame.draw();\n}\n\nexport function handleWebEmbedUp() {\n if (!frame) return;\n if (frame.width < 40 || frame.height < 30) { frame.width = 560; frame.height = 315; }\n frame.draw(); pushCreateAction(frame);\n const placedFrame = frame;\n window.__pendingWebEmbedURL = null; frame = null; start = null;\n window.__sketchStoreApi?.setActiveTool('select', { afterDraw: true });\n currentShape = placedFrame; placedFrame.selectFrame();\n}\n\nwindow.__placeWebEmbed = placeWebEmbed;\n", "/* eslint-disable */\n// Event dispatcher - extracted from eventListeners.js\n// Central event routing for all tools\n\nimport { handleMouseDownRect, handleMouseMoveRect, handleMouseUpRect } from '../tools/rectangleTool.js';\nimport { handleMouseDownArrow, handleMouseMoveArrow, handleMouseUpArrow } from '../tools/arrowTool.js';\nimport { handleMouseDownCircle, handleMouseMoveCircle, handleMouseUpCircle } from '../tools/circleTool.js';\nimport { handleMouseUpImage, handleMouseDownImage, handleMouseMoveImage } from '../tools/imageTool.js';\nimport { handleMouseDownLine, handleMouseMoveLine, handleMouseUpLine } from '../tools/lineTool.js';\nimport { handleFreehandMouseDown, handleFreehandMouseMove, handleFreehandMouseUp } from '../tools/freehandTool.js';\nimport { handleTextMouseDown, handleTextMouseMove, handleTextMouseUp, enterEditMode } from '../tools/textTool.js';\nimport { handleMouseDownFrame, handleMouseMoveFrame, handleMouseUpFrame } from '../tools/frameTool.js';\nimport { handleMultiSelectionMouseDown, handleMultiSelectionMouseMove, handleMultiSelectionMouseUp, removeMultiSelectionRect, multiSelection, isMultiSelecting} from './Selection.js';\nimport { handleMouseDownIcon, handleMouseMoveIcon, handleMouseUpIcon } from '../tools/iconTool.js';\nimport { handleCodeMouseDown, handleCodeMouseMove, handleCodeMouseUp } from '../tools/codeTool.js';\nimport { handleShapeRecognitionDown, handleShapeRecognitionMove, handleShapeRecognitionUp } from '../tools/shapeRecognitionTool.js';\nimport { handlePaintBucketDown } from '../tools/paintBucketTool.js';\nimport { handleLassoDown, handleLassoMove, handleLassoUp } from '../tools/lassoTool.js';\nimport { handleWebEmbedDown, handleWebEmbedMove, handleWebEmbedUp } from '../tools/webEmbedTool.js';\n\n// === Auto-scroll when dragging near viewport edges ===\nconst EDGE_THRESHOLD = 40; // px from edge to start scrolling\nconst SCROLL_SPEED = 8; // base px per frame (scaled by zoom)\nlet _autoScrollRAF = null;\n\nfunction _autoScroll(e) {\n if (!(e.buttons & 1)) { _stopAutoScroll(); return; } // no primary button\n if (typeof currentViewBox === 'undefined' || typeof currentZoom === 'undefined') return;\n if (typeof isPanning !== 'undefined' && isPanning) return; // don't fight pan tool\n if (typeof isPanningToolActive !== 'undefined' && isPanningToolActive) return;\n\n const rect = svg.getBoundingClientRect();\n const mx = e.clientX - rect.left;\n const my = e.clientY - rect.top;\n\n let dx = 0, dy = 0;\n if (mx < EDGE_THRESHOLD) dx = -SCROLL_SPEED * (1 - mx / EDGE_THRESHOLD);\n else if (mx > rect.width - EDGE_THRESHOLD) dx = SCROLL_SPEED * (1 - (rect.width - mx) / EDGE_THRESHOLD);\n if (my < EDGE_THRESHOLD) dy = -SCROLL_SPEED * (1 - my / EDGE_THRESHOLD);\n else if (my > rect.height - EDGE_THRESHOLD) dy = SCROLL_SPEED * (1 - (rect.height - my) / EDGE_THRESHOLD);\n\n // Also scroll when cursor is outside the canvas entirely\n if (e.clientX < rect.left) dx = -SCROLL_SPEED;\n else if (e.clientX > rect.right) dx = SCROLL_SPEED;\n if (e.clientY < rect.top) dy = -SCROLL_SPEED;\n else if (e.clientY > rect.bottom) dy = SCROLL_SPEED;\n\n if (dx === 0 && dy === 0) { _stopAutoScroll(); return; }\n\n // Scale speed inversely with zoom so scrolling feels consistent\n const scale = 1 / currentZoom;\n currentViewBox.x += dx * scale;\n currentViewBox.y += dy * scale;\n svg.setAttribute('viewBox', `${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`);\n if (typeof freehandCanvas !== 'undefined' && freehandCanvas !== svg) {\n freehandCanvas.setAttribute('viewBox', `${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`);\n }\n}\n\nfunction _startAutoScroll() {\n if (_autoScrollRAF) return;\n const tick = () => {\n if (_lastDragEvent) _autoScroll(_lastDragEvent);\n _autoScrollRAF = requestAnimationFrame(tick);\n };\n _autoScrollRAF = requestAnimationFrame(tick);\n}\n\nfunction _stopAutoScroll() {\n if (_autoScrollRAF) {\n cancelAnimationFrame(_autoScrollRAF);\n _autoScrollRAF = null;\n }\n _lastDragEvent = null;\n}\n\nlet _lastDragEvent = null;\nlet _documentDragActive = false;\n\nfunction _onDocumentDragMove(e) {\n _lastDragEvent = e;\n // Clamp mouse coordinates to SVG bounds before forwarding to tool handlers,\n // so getSVGCoordsFromMouse doesn't produce extreme values when cursor is outside.\n const rect = svg.getBoundingClientRect();\n const clampedX = Math.max(rect.left, Math.min(rect.right, e.clientX));\n const clampedY = Math.max(rect.top, Math.min(rect.bottom, e.clientY));\n const clampedEvent = new PointerEvent(e.type, {\n clientX: clampedX,\n clientY: clampedY,\n buttons: e.buttons,\n button: e.button,\n ctrlKey: e.ctrlKey,\n shiftKey: e.shiftKey,\n altKey: e.altKey,\n metaKey: e.metaKey,\n });\n handleMainMouseMove(clampedEvent);\n}\n\nfunction _onDocumentDragUp(e) {\n _stopAutoScroll();\n document.removeEventListener('pointermove', _onDocumentDragMove);\n document.removeEventListener('pointerup', _onDocumentDragUp);\n _documentDragActive = false;\n // Finalize the operation\n handleMainMouseUp(e);\n}\n\nconst handleMainMouseDown = (e) => {\n if (!e.target) return;\n // Middle / right mouse buttons are reserved for panning and the\n // browser context menu; they should NOT trigger tool actions or the\n // multi-selection rectangle. Without this guard, middle-click-drag\n // simultaneously pans (handled in ZoomPan) and starts a selection\n // marquee.\n if (e.button === 1 || e.button === 2 || window.__spacePanActive) return;\n // Safety: remove any stray selection rectangle from a previous interrupted drag\n removeMultiSelectionRect();\n\n // For non-selection tools: deselect everything when clicking on empty canvas\n // (Selection tool handles its own deselection in handleMultiSelectionMouseDown)\n if (!isSelectionToolActive) {\n // Clear multi-selection for any tool switch\n if (multiSelection.selectedShapes.size > 0) {\n multiSelection.clearSelection();\n }\n // Deselect current individual shape when starting a new tool action\n if (currentShape && typeof currentShape.removeSelection === 'function') {\n currentShape.removeSelection();\n currentShape = null;\n }\n if (typeof disableAllSideBars === 'function') {\n disableAllSideBars();\n }\n }\n\n if (window.isLassoToolActive) {\n handleLassoDown(e);\n } else if (window.isWebEmbedToolActive) {\n handleWebEmbedDown(e);\n } else if (window.isShapeRecognitionToolActive) {\n handleShapeRecognitionDown(e);\n } else if (window.isPaintBucketToolActive) {\n handlePaintBucketDown(e);\n } else if (isSquareToolActive) {\n handleMouseDownRect(e);\n } else if (isArrowToolActive) {\n handleMouseDownArrow(e);\n } else if (isCircleToolActive) {\n handleMouseDownCircle(e);\n } else if (isImageToolActive) {\n handleMouseDownImage(e);\n } \n else if (isLineToolActive) {\n handleMouseDownLine(e);\n }\n else if (isPaintToolActive) {\n handleFreehandMouseDown(e);\n }\n else if (isTextToolActive) {\n // Text tool handles both text and code shapes based on target and mode\n const targetCodeGroup = e.target.closest('g[data-type=\"code-group\"]');\n const targetTextGroup = e.target.closest('g[data-type=\"text-group\"]');\n if (targetCodeGroup && !targetTextGroup) {\n handleCodeMouseDown(e);\n } else if (isTextInCodeMode && !targetTextGroup && !targetCodeGroup) {\n handleCodeMouseDown(e);\n } else {\n handleTextMouseDown(e);\n }\n }\n else if (isFrameToolActive) {\n handleMouseDownFrame(e);\n }\n else if (isIconToolActive) {\n handleMouseDownIcon(e);\n }\n else if (isSelectionToolActive) {\n // Try multi-selection first when selection tool is active\n if (handleMultiSelectionMouseDown(e)) {\n return; // Multi-selection handled the event\n }\n\n // Remember previous shape to detect deselection\n const prevShape = currentShape;\n let handled = false;\n\n // If multi-selection didn't handle it, proceed with shape-specific selection\n if (currentShape?.shapeName === 'rectangle') {\n handleMouseDownRect(e);\n handled = true;\n } else if (currentShape?.shapeName === 'arrow') {\n handleMouseDownArrow(e);\n handled = true;\n } else if (currentShape?.shapeName === 'circle') {\n handleMouseDownCircle(e);\n handled = true;\n } else if (currentShape?.shapeName === 'image') {\n handleMouseDownImage(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'line') {\n handleMouseDownLine(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'freehandStroke') {\n handleFreehandMouseDown(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'text') {\n handleTextMouseDown(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'frame') {\n handleMouseDownFrame(e);\n handled = true;\n }\n else if (currentShape?.shapeName === 'icon') {\n handleMouseDownIcon(e);\n handled = true;\n }\n else if( currentShape?.shapeName === 'code') {\n handleCodeMouseDown(e);\n handled = true;\n }\n\n // If the handler deselected (currentShape cleared) but didn't select something new,\n // fall through to try all handlers so clicking another shape type works\n if (handled && prevShape && !currentShape) {\n handled = false;\n }\n\n if (!handled) {\n const originalCurrentShape = currentShape;\n handleMouseDownRect(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownCircle(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownArrow(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownImage(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownLine(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleFreehandMouseDown(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleTextMouseDown(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownFrame(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleMouseDownIcon(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n handleCodeMouseDown(e);\n if (currentShape && currentShape !== originalCurrentShape) return;\n if (currentShape === originalCurrentShape) {\n if (currentShape) {\n currentShape.removeSelection();\n currentShape = null;\n }\n }\n }\n }\n};\n\nconst handleMainMouseMove = (e) => {\n if (window.__spacePanPointerActive) return;\n // Auto-scroll when dragging near/past viewport edges (checked first so early returns don't skip it)\n if (e.buttons & 1) {\n _lastDragEvent = e;\n _startAutoScroll();\n } else {\n _stopAutoScroll();\n }\n\n if (window.isLassoToolActive) {\n handleLassoMove(e);\n } else if (window.isWebEmbedToolActive) {\n handleWebEmbedMove(e);\n } else if (window.isShapeRecognitionToolActive) {\n handleShapeRecognitionMove(e);\n } else if (window.isPaintBucketToolActive) {\n return;\n } else if (isSquareToolActive) {\n handleMouseMoveRect(e);\n } else if (isArrowToolActive) {\n handleMouseMoveArrow(e);\n } else if (isCircleToolActive) {\n handleMouseMoveCircle(e);\n } else if (isImageToolActive) {\n handleMouseMoveImage(e);\n } \n else if (isLineToolActive) {\n handleMouseMoveLine(e);\n }\n else if (isPaintToolActive) {\n handleFreehandMouseMove(e);\n }\n else if (isTextToolActive) {\n handleTextMouseMove(e);\n handleCodeMouseMove(e);\n }\n else if (isFrameToolActive) {\n handleMouseMoveFrame(e);\n }\n else if (isIconToolActive) {\n handleMouseMoveIcon(e);\n }\n else if (isSelectionToolActive) {\n // Handle multi-selection operations first - these take priority\n if (isMultiSelecting || multiSelection.isDragging || multiSelection.isResizing || multiSelection.isRotating) {\n if (handleMultiSelectionMouseMove(e)) {\n return; // Multi-selection handled the event\n }\n }\n \n // Shape-specific mouse move handling\n if (currentShape?.shapeName === 'rectangle') {\n handleMouseMoveRect(e);\n } else if (currentShape?.shapeName === 'arrow') {\n handleMouseMoveArrow(e);\n } else if (currentShape?.shapeName === 'circle') {\n handleMouseMoveCircle(e);\n } else if (currentShape?.shapeName === 'image') {\n handleMouseMoveImage(e);\n } \n else if (currentShape?.shapeName === 'line') {\n handleMouseMoveLine(e);\n }\n else if (currentShape?.shapeName === 'freehandStroke') {\n handleFreehandMouseMove(e);\n }\n else if (currentShape?.shapeName === 'text') {\n handleTextMouseMove(e);\n }\n else if (currentShape?.shapeName === 'frame') {\n handleMouseMoveFrame(e);\n }\n else if (currentShape?.shapeName === 'icon') {\n handleMouseMoveIcon(e);\n }\n else if (currentShape?.shapeName === 'code') {\n handleCodeMouseMove(e);\n }\n\n else {\n // Try multi-selection mouse move for cursor updates\n if (handleMultiSelectionMouseMove(e)) {\n return;\n }\n \n handleMouseMoveRect(e);\n handleMouseMoveArrow(e);\n handleMouseMoveCircle(e);\n handleMouseMoveImage(e);\n handleMouseMoveLine(e);\n handleFreehandMouseMove(e);\n handleTextMouseMove(e);\n handleMouseMoveFrame(e);\n handleMouseMoveIcon(e);\n handleCodeMouseMove(e);\n }\n }\n};\n\nconst handleMainMouseUp = (e) => {\n if (window.__spacePanPointerActive) return;\n _stopAutoScroll();\n if (window.isLassoToolActive) {\n handleLassoUp(e);\n } else if (window.isWebEmbedToolActive) {\n handleWebEmbedUp(e);\n } else if (window.isShapeRecognitionToolActive) {\n handleShapeRecognitionUp(e);\n } else if (window.isPaintBucketToolActive) {\n return;\n } else if (isSquareToolActive) {\n handleMouseUpRect(e);\n } else if (isArrowToolActive) {\n handleMouseUpArrow(e);\n } else if (isCircleToolActive) {\n handleMouseUpCircle(e);\n } else if (isImageToolActive) {\n handleMouseUpImage(e);\n } \n else if (isLineToolActive) { \n handleMouseUpLine(e);\n }\n else if (isPaintToolActive) {\n handleFreehandMouseUp(e);\n }\n else if (isTextToolActive) {\n handleTextMouseUp(e);\n handleCodeMouseUp(e);\n }\n else if (isFrameToolActive) {\n handleMouseUpFrame(e);\n }\n else if (isIconToolActive) {\n handleMouseUpIcon(e);\n }\n\n else if (isSelectionToolActive) {\n // Always try multi-selection cleanup first\n if (isMultiSelecting || multiSelection.isDragging || multiSelection.isResizing || multiSelection.isRotating) {\n handleMultiSelectionMouseUp(e);\n return;\n }\n\n // Shape-specific mouse up handling\n if (currentShape?.shapeName === 'rectangle') {\n handleMouseUpRect(e);\n } else if (currentShape?.shapeName === 'arrow') {\n handleMouseUpArrow(e);\n } else if (currentShape?.shapeName === 'circle') {\n handleMouseUpCircle(e);\n } else if (currentShape?.shapeName === 'image') {\n handleMouseUpImage(e);\n }\n else if (currentShape?.shapeName === 'line') {\n handleMouseUpLine(e);\n }\n else if (currentShape?.shapeName === 'freehandStroke') {\n handleFreehandMouseUp(e);\n }\n else if (currentShape?.shapeName === 'text') {\n handleTextMouseUp(e);\n }\n else if (currentShape?.shapeName === 'frame') {\n handleMouseUpFrame(e);\n }\n else if (currentShape?.shapeName === 'icon') {\n handleMouseUpIcon(e);\n }\n else if (currentShape?.shapeName === 'code') {\n handleCodeMouseUp(e);\n }\n\n else {\n handleMultiSelectionMouseUp(e);\n handleMouseUpRect(e);\n handleMouseUpArrow(e);\n handleMouseUpCircle(e);\n handleMouseUpImage(e);\n handleMouseUpLine(e);\n handleFreehandMouseUp(e);\n handleTextMouseUp(e);\n handleMouseUpFrame(e);\n handleMouseUpIcon(e);\n handleCodeMouseUp(e);\n }\n }\n};\n\nconst handleMainMouseLeave = (e) => {\n if (window.__spacePanPointerActive) return;\n // If the user is still holding the primary button (dragging outside the canvas),\n // keep auto-scrolling and don't finalize the operation yet.\n if (e.buttons & 1) {\n _lastDragEvent = e;\n _startAutoScroll();\n\n // Listen on document to continue receiving move events outside the SVG\n if (!_documentDragActive) {\n _documentDragActive = true;\n document.addEventListener('pointermove', _onDocumentDragMove);\n document.addEventListener('pointerup', _onDocumentDragUp);\n }\n return;\n }\n\n // Stop all active drawing tools when pointer leaves the canvas\n\n // Fire mouseUp for whichever tool is active to finalize/cancel the operation\n handleMainMouseUp(e);\n\n // Always clean up any stray selection rectangle when pointer leaves canvas\n removeMultiSelectionRect();\n\n // Eraser: force cleanup any lingering trail\n if (typeof window.forceCleanupEraserTrail === 'function') {\n window.forceCleanupEraserTrail();\n }\n\n // Laser: stop drawing and fade out active laser (globals from laserTool.js)\n if (typeof isDrawing !== 'undefined' && isDrawing) {\n isDrawing = false;\n if (typeof lasers !== 'undefined' && lasers.length > 0 && typeof fadeLaserTrail === 'function') {\n const lastLaser = lasers[lasers.length - 1];\n fadeLaserTrail(lastLaser);\n }\n }\n};\n\nlet _boundSvg = null;\n\nfunction _onMouseEnter(e) {\n // Cursor re-entered the SVG \u2014 stop document-level tracking, SVG handles events again\n if (_documentDragActive) {\n document.removeEventListener('pointermove', _onDocumentDragMove);\n document.removeEventListener('pointerup', _onDocumentDragUp);\n _documentDragActive = false;\n }\n}\n\nconst handleMainDblClick = (e) => {\n if (!e.target) return;\n // Double-click on a text group from any tool: enter text edit mode\n const targetTextGroup = e.target.closest('g[data-type=\"text-group\"]');\n if (targetTextGroup) {\n e.stopPropagation();\n enterEditMode(targetTextGroup);\n }\n};\n\nfunction initEventDispatcher(svgEl) {\n if (_boundSvg) cleanupEventDispatcher();\n const target = svgEl || svg;\n target.addEventListener('pointerdown', handleMainMouseDown);\n target.addEventListener('pointermove', handleMainMouseMove);\n target.addEventListener('pointerup', handleMainMouseUp);\n target.addEventListener('pointerleave', handleMainMouseLeave);\n target.addEventListener('pointerenter', _onMouseEnter);\n target.addEventListener('dblclick', handleMainDblClick);\n _boundSvg = target;\n}\n\nfunction cleanupEventDispatcher() {\n _stopAutoScroll();\n if (_documentDragActive) {\n document.removeEventListener('pointermove', _onDocumentDragMove);\n document.removeEventListener('pointerup', _onDocumentDragUp);\n _documentDragActive = false;\n }\n if (_boundSvg) {\n _boundSvg.removeEventListener('pointerdown', handleMainMouseDown);\n _boundSvg.removeEventListener('pointermove', handleMainMouseMove);\n _boundSvg.removeEventListener('pointerup', handleMainMouseUp);\n _boundSvg.removeEventListener('pointerleave', handleMainMouseLeave);\n _boundSvg.removeEventListener('pointerenter', _onMouseEnter);\n _boundSvg.removeEventListener('dblclick', handleMainDblClick);\n _boundSvg = null;\n }\n}\n\n// Auto-init if svg is already available (first load)\nif (typeof svg !== 'undefined' && svg) {\n initEventDispatcher(svg);\n}\n\nexport { handleMainMouseDown, handleMainMouseMove, handleMainMouseUp, handleMainMouseLeave, initEventDispatcher, cleanupEventDispatcher };\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["MIN_SHAPE_SIZE", "start", "start", "path", "frame", "getSVGPoint", "oldOptions", "newOptions", "points", "drawing", "coords", "handleMouseDown", "handleMouseMove", "handleMouseUp"]
|
|
7
7
|
}
|
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
Frame
|
|
4
4
|
} from "./chunk-ZNZAICWY.js";
|
|
5
5
|
import "./chunk-PAKA6HUX.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-KXLNEFN5.js";
|
|
7
7
|
import "./chunk-VZX55VQL.js";
|
|
8
8
|
export {
|
|
9
9
|
Frame
|
|
10
10
|
};
|
|
11
|
-
//# sourceMappingURL=Frame-
|
|
11
|
+
//# sourceMappingURL=Frame-NHPESH4Y.js.map
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-MB7VS6MK.js";
|
|
5
5
|
import {
|
|
6
6
|
ImageShape
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ULZW5PXM.js";
|
|
8
8
|
import {
|
|
9
9
|
IconShape
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-5XGQ3CMT.js";
|
|
11
11
|
import {
|
|
12
12
|
Frame
|
|
13
13
|
} from "./chunk-ZNZAICWY.js";
|
|
@@ -30,8 +30,8 @@ import {
|
|
|
30
30
|
} from "./chunk-BT2EIJD4.js";
|
|
31
31
|
import {
|
|
32
32
|
Line
|
|
33
|
-
} from "./chunk-
|
|
34
|
-
import "./chunk-
|
|
33
|
+
} from "./chunk-TAJ5E6KI.js";
|
|
34
|
+
import "./chunk-KXLNEFN5.js";
|
|
35
35
|
import {
|
|
36
36
|
clearUndoHistory,
|
|
37
37
|
pushCanvasResetAction
|
|
@@ -866,4 +866,4 @@ export {
|
|
|
866
866
|
uploadScene,
|
|
867
867
|
validateScene
|
|
868
868
|
};
|
|
869
|
-
//# sourceMappingURL=SceneSerializer-
|
|
869
|
+
//# sourceMappingURL=SceneSerializer-Y6QABGZY.js.map
|
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
removeMultiSelectionControls,
|
|
15
15
|
removeMultiSelectionRect,
|
|
16
16
|
selectShapesInRect
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-UERV53R7.js";
|
|
18
18
|
import "./chunk-PAKA6HUX.js";
|
|
19
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-KXLNEFN5.js";
|
|
20
20
|
import "./chunk-VZX55VQL.js";
|
|
21
21
|
export {
|
|
22
22
|
cancelActiveMultiSelectionDrag,
|
|
@@ -34,4 +34,4 @@ export {
|
|
|
34
34
|
removeMultiSelectionRect,
|
|
35
35
|
selectShapesInRect
|
|
36
36
|
};
|
|
37
|
-
//# sourceMappingURL=Selection-
|
|
37
|
+
//# sourceMappingURL=Selection-GCZWCNAR.js.map
|