@elixpo/lixsketch 5.6.10 → 5.6.11

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.
Files changed (156) hide show
  1. package/dist/react/{AIRenderer-R5M2CIDO.js → AIRenderer-JNEZYDYQ.js} +4 -4
  2. package/dist/react/Arrow-QMR77LGQ.js +9 -0
  3. package/dist/react/Circle-5WL5HZA5.js +11 -0
  4. package/dist/react/{CopyPaste-N4U2NTQT.js → CopyPaste-V7AY56H3.js} +74 -30
  5. package/dist/react/CopyPaste-V7AY56H3.js.map +7 -0
  6. package/dist/react/{EventDispatcher-J657SDW4.js → EventDispatcher-E4OJCMY6.js} +153 -56
  7. package/dist/react/{EventDispatcher-J657SDW4.js.map → EventDispatcher-E4OJCMY6.js.map} +3 -3
  8. package/dist/react/Frame-OZCDVPMI.js +11 -0
  9. package/dist/react/FreehandStroke-QSSYWBFK.js +9 -0
  10. package/dist/react/IconShape-HXUV4VRT.js +10 -0
  11. package/dist/react/ImageShape-JGLT2UGG.js +10 -0
  12. package/dist/react/Line-YONPLUYT.js +11 -0
  13. package/dist/react/{MermaidFlowchartRenderer-EL3Q2MNW.js → MermaidFlowchartRenderer-FSH43RUP.js} +26 -7
  14. package/dist/react/{MermaidFlowchartRenderer-EL3Q2MNW.js.map → MermaidFlowchartRenderer-FSH43RUP.js.map} +2 -2
  15. package/dist/react/{MermaidSequenceRenderer-K4KHHEVC.js → MermaidSequenceRenderer-FRPNOF2V.js} +11 -9
  16. package/dist/react/{MermaidSequenceRenderer-K4KHHEVC.js.map → MermaidSequenceRenderer-FRPNOF2V.js.map} +2 -2
  17. package/dist/react/{MermaidStructuredRenderer-6LN3WISP.js → MermaidStructuredRenderer-BZGQLRIH.js} +13 -6
  18. package/dist/react/{MermaidStructuredRenderer-6LN3WISP.js.map → MermaidStructuredRenderer-BZGQLRIH.js.map} +2 -2
  19. package/dist/react/Rectangle-7KMA3SC6.js +11 -0
  20. package/dist/react/{SceneSerializer-Y6QABGZY.js → SceneSerializer-7O72LEZP.js} +13 -12
  21. package/dist/react/{SceneSerializer-Y6QABGZY.js.map → SceneSerializer-7O72LEZP.js.map} +1 -1
  22. package/dist/react/{Selection-GCZWCNAR.js → Selection-S4FYSZIF.js} +5 -5
  23. package/dist/react/{SketchEngine-PCMCE63L.js → SketchEngine-VTWURP2K.js} +26 -26
  24. package/dist/react/{UndoRedo-RXO7YHA2.js → UndoRedo-YLQJ6DXW.js} +8 -2
  25. package/dist/react/{ZoomPan-RR7KUYZT.js → ZoomPan-AEKWKUCH.js} +2 -2
  26. package/dist/react/{arrowTool-UN3TNJFP.js → arrowTool-C4RDWQEX.js} +3 -3
  27. package/dist/react/{chunk-KXLNEFN5.js → chunk-2U47AU6Y.js} +2 -2
  28. package/dist/react/{chunk-YHQ4ZAJQ.js → chunk-75OPJOWN.js} +6 -6
  29. package/dist/react/chunk-75OPJOWN.js.map +7 -0
  30. package/dist/react/{chunk-P5476S5I.js → chunk-CWE5IFG7.js} +4 -4
  31. package/dist/react/{chunk-3FCIBY54.js → chunk-IS2MKWGH.js} +8 -7
  32. package/dist/react/chunk-IS2MKWGH.js.map +7 -0
  33. package/dist/react/{chunk-ZNZAICWY.js → chunk-JEHOEQ6Z.js} +13 -5
  34. package/dist/react/chunk-JEHOEQ6Z.js.map +7 -0
  35. package/dist/react/{chunk-TAJ5E6KI.js → chunk-JYBJXTLM.js} +39 -14
  36. package/dist/react/chunk-JYBJXTLM.js.map +7 -0
  37. package/dist/react/{chunk-3PFVMNDJ.js → chunk-LXEHYCKH.js} +3 -3
  38. package/dist/react/chunk-M7OYYJC6.js +17 -0
  39. package/dist/react/chunk-M7OYYJC6.js.map +7 -0
  40. package/dist/react/chunk-MS4TIQ6Z.js +131 -0
  41. package/dist/react/chunk-MS4TIQ6Z.js.map +7 -0
  42. package/dist/react/{chunk-5XGQ3CMT.js → chunk-OCJN32IL.js} +2 -2
  43. package/dist/react/{chunk-7NHZYKYB.js → chunk-P7VIYR6R.js} +7 -4
  44. package/dist/react/chunk-P7VIYR6R.js.map +7 -0
  45. package/dist/react/{chunk-UERV53R7.js → chunk-PX2635H5.js} +32 -10
  46. package/dist/react/chunk-PX2635H5.js.map +7 -0
  47. package/dist/react/{chunk-KACRJ6AJ.js → chunk-SDG4U7TP.js} +7 -6
  48. package/dist/react/chunk-SDG4U7TP.js.map +7 -0
  49. package/dist/react/{chunk-JVHZVV5U.js → chunk-STJERZ25.js} +7 -3
  50. package/dist/react/chunk-STJERZ25.js.map +7 -0
  51. package/dist/react/{chunk-VZPH7OAM.js → chunk-TCWCC4Z4.js} +7 -3
  52. package/dist/react/chunk-TCWCC4Z4.js.map +7 -0
  53. package/dist/react/{chunk-VZX55VQL.js → chunk-TFCBCWL5.js} +90 -33
  54. package/dist/react/chunk-TFCBCWL5.js.map +7 -0
  55. package/dist/react/{chunk-GQLXUZHQ.js → chunk-TWHJ6PJK.js} +5 -3
  56. package/dist/react/chunk-TWHJ6PJK.js.map +7 -0
  57. package/dist/react/{chunk-NH3NVSWT.js → chunk-UCOK4V5Z.js} +4 -3
  58. package/dist/react/{chunk-NH3NVSWT.js.map → chunk-UCOK4V5Z.js.map} +2 -2
  59. package/dist/react/{chunk-W7XUY4GR.js → chunk-VJDNKJBX.js} +56 -4
  60. package/dist/react/chunk-VJDNKJBX.js.map +7 -0
  61. package/dist/react/{chunk-BT2EIJD4.js → chunk-WCA3FGWE.js} +6 -3
  62. package/dist/react/chunk-WCA3FGWE.js.map +7 -0
  63. package/dist/react/{chunk-7WXEWDRL.js → chunk-Y3FJMYPX.js} +3 -3
  64. package/dist/react/{chunk-ULZW5PXM.js → chunk-YCGLGY4C.js} +2 -2
  65. package/dist/react/{circleTool-YDTQDGYX.js → circleTool-QQV2QEVF.js} +4 -4
  66. package/dist/react/{codeTool-U6SYKHHD.js → codeTool-PTCPSZ4L.js} +5 -5
  67. package/dist/react/{frameTool-VRI7OODN.js → frameTool-7GQPLU4Y.js} +4 -4
  68. package/dist/react/{freehandTool-2ICCQHVY.js → freehandTool-3RJXTVAK.js} +4 -4
  69. package/dist/react/{iconTool-32D5NJ4I.js → iconTool-DW5YJX7P.js} +5 -5
  70. package/dist/react/{imageTool-Z6Y4OXBG.js → imageTool-7GZQKWYT.js} +5 -5
  71. package/dist/react/index.js +49 -56
  72. package/dist/react/index.js.map +2 -2
  73. package/dist/react/{lineTool-BUWVQ666.js → lineTool-5CY7BHND.js} +4 -4
  74. package/dist/react/{rectangleTool-NJYG6Y6L.js → rectangleTool-DK4QL4QW.js} +4 -4
  75. package/dist/react/{textTool-CIJCF4Z3.js → textTool-GP5QQYF3.js} +6 -6
  76. package/package.json +1 -1
  77. package/src/core/CopyPaste.js +66 -18
  78. package/src/core/EventDispatcher.js +71 -47
  79. package/src/core/MermaidFlowchartRenderer.js +34 -8
  80. package/src/core/MermaidSequenceRenderer.js +10 -8
  81. package/src/core/MermaidStructuredRenderer.js +12 -5
  82. package/src/core/ScreenSpaceControls.js +102 -13
  83. package/src/core/Selection.js +26 -7
  84. package/src/core/SelectionGesture.js +50 -0
  85. package/src/core/UndoRedo.js +108 -35
  86. package/src/react/components/sidebars/CircleSidebar.jsx +11 -5
  87. package/src/react/components/sidebars/IconSidebar.jsx +10 -4
  88. package/src/react/components/sidebars/RectangleSidebar.jsx +11 -5
  89. package/src/react/components/sidebars/ShapeSidebar.jsx +29 -37
  90. package/src/react/store/useUIStore.js +7 -0
  91. package/src/shapes/Arrow.js +4 -3
  92. package/src/shapes/Circle.js +58 -2
  93. package/src/shapes/Frame.js +11 -4
  94. package/src/shapes/FreehandStroke.js +2 -1
  95. package/src/shapes/Line.js +45 -18
  96. package/src/shapes/Rectangle.js +3 -1
  97. package/src/tools/circleTool.js +4 -1
  98. package/src/tools/frameTool.js +3 -2
  99. package/src/tools/iconTool.js +4 -3
  100. package/src/tools/imageTool.js +3 -2
  101. package/src/tools/lineTool.js +4 -0
  102. package/src/tools/textTool.js +1 -1
  103. package/src/utils/themeColors.js +13 -0
  104. package/dist/react/Arrow-EF7ALH2Y.js +0 -8
  105. package/dist/react/Circle-HMM5PKJ2.js +0 -10
  106. package/dist/react/CopyPaste-N4U2NTQT.js.map +0 -7
  107. package/dist/react/Frame-NHPESH4Y.js +0 -11
  108. package/dist/react/FreehandStroke-WXIJKD5I.js +0 -9
  109. package/dist/react/IconShape-RN5HJDUF.js +0 -10
  110. package/dist/react/ImageShape-L7U64AVP.js +0 -10
  111. package/dist/react/Line-LPRTGPUQ.js +0 -10
  112. package/dist/react/Rectangle-4U4CD2ER.js +0 -10
  113. package/dist/react/chunk-3FCIBY54.js.map +0 -7
  114. package/dist/react/chunk-7NHZYKYB.js.map +0 -7
  115. package/dist/react/chunk-BT2EIJD4.js.map +0 -7
  116. package/dist/react/chunk-GQLXUZHQ.js.map +0 -7
  117. package/dist/react/chunk-JVHZVV5U.js.map +0 -7
  118. package/dist/react/chunk-KACRJ6AJ.js.map +0 -7
  119. package/dist/react/chunk-PAKA6HUX.js +0 -59
  120. package/dist/react/chunk-PAKA6HUX.js.map +0 -7
  121. package/dist/react/chunk-TAJ5E6KI.js.map +0 -7
  122. package/dist/react/chunk-UERV53R7.js.map +0 -7
  123. package/dist/react/chunk-VZPH7OAM.js.map +0 -7
  124. package/dist/react/chunk-VZX55VQL.js.map +0 -7
  125. package/dist/react/chunk-W7XUY4GR.js.map +0 -7
  126. package/dist/react/chunk-YHQ4ZAJQ.js.map +0 -7
  127. package/dist/react/chunk-ZNZAICWY.js.map +0 -7
  128. /package/dist/react/{AIRenderer-R5M2CIDO.js.map → AIRenderer-JNEZYDYQ.js.map} +0 -0
  129. /package/dist/react/{Arrow-EF7ALH2Y.js.map → Arrow-QMR77LGQ.js.map} +0 -0
  130. /package/dist/react/{Circle-HMM5PKJ2.js.map → Circle-5WL5HZA5.js.map} +0 -0
  131. /package/dist/react/{Frame-NHPESH4Y.js.map → Frame-OZCDVPMI.js.map} +0 -0
  132. /package/dist/react/{FreehandStroke-WXIJKD5I.js.map → FreehandStroke-QSSYWBFK.js.map} +0 -0
  133. /package/dist/react/{IconShape-RN5HJDUF.js.map → IconShape-HXUV4VRT.js.map} +0 -0
  134. /package/dist/react/{ImageShape-L7U64AVP.js.map → ImageShape-JGLT2UGG.js.map} +0 -0
  135. /package/dist/react/{Line-LPRTGPUQ.js.map → Line-YONPLUYT.js.map} +0 -0
  136. /package/dist/react/{Rectangle-4U4CD2ER.js.map → Rectangle-7KMA3SC6.js.map} +0 -0
  137. /package/dist/react/{Selection-GCZWCNAR.js.map → Selection-S4FYSZIF.js.map} +0 -0
  138. /package/dist/react/{SketchEngine-PCMCE63L.js.map → SketchEngine-VTWURP2K.js.map} +0 -0
  139. /package/dist/react/{UndoRedo-RXO7YHA2.js.map → UndoRedo-YLQJ6DXW.js.map} +0 -0
  140. /package/dist/react/{ZoomPan-RR7KUYZT.js.map → ZoomPan-AEKWKUCH.js.map} +0 -0
  141. /package/dist/react/{arrowTool-UN3TNJFP.js.map → arrowTool-C4RDWQEX.js.map} +0 -0
  142. /package/dist/react/{chunk-KXLNEFN5.js.map → chunk-2U47AU6Y.js.map} +0 -0
  143. /package/dist/react/{chunk-P5476S5I.js.map → chunk-CWE5IFG7.js.map} +0 -0
  144. /package/dist/react/{chunk-3PFVMNDJ.js.map → chunk-LXEHYCKH.js.map} +0 -0
  145. /package/dist/react/{chunk-5XGQ3CMT.js.map → chunk-OCJN32IL.js.map} +0 -0
  146. /package/dist/react/{chunk-7WXEWDRL.js.map → chunk-Y3FJMYPX.js.map} +0 -0
  147. /package/dist/react/{chunk-ULZW5PXM.js.map → chunk-YCGLGY4C.js.map} +0 -0
  148. /package/dist/react/{circleTool-YDTQDGYX.js.map → circleTool-QQV2QEVF.js.map} +0 -0
  149. /package/dist/react/{codeTool-U6SYKHHD.js.map → codeTool-PTCPSZ4L.js.map} +0 -0
  150. /package/dist/react/{frameTool-VRI7OODN.js.map → frameTool-7GQPLU4Y.js.map} +0 -0
  151. /package/dist/react/{freehandTool-2ICCQHVY.js.map → freehandTool-3RJXTVAK.js.map} +0 -0
  152. /package/dist/react/{iconTool-32D5NJ4I.js.map → iconTool-DW5YJX7P.js.map} +0 -0
  153. /package/dist/react/{imageTool-Z6Y4OXBG.js.map → imageTool-7GZQKWYT.js.map} +0 -0
  154. /package/dist/react/{lineTool-BUWVQ666.js.map → lineTool-5CY7BHND.js.map} +0 -0
  155. /package/dist/react/{rectangleTool-NJYG6Y6L.js.map → rectangleTool-DK4QL4QW.js.map} +0 -0
  156. /package/dist/react/{textTool-CIJCF4Z3.js.map → textTool-GP5QQYF3.js.map} +0 -0
@@ -1,7 +1,10 @@
1
1
  "use client";
2
+ import {
3
+ resolveThemeLabelColor
4
+ } from "./chunk-M7OYYJC6.js";
2
5
  import {
3
6
  updateAttachedArrows
4
- } from "./chunk-KXLNEFN5.js";
7
+ } from "./chunk-2U47AU6Y.js";
5
8
 
6
9
  // src/shapes/Line.js
7
10
  var rc = rough.svg(svg);
@@ -16,6 +19,9 @@ var Line = class {
16
19
  this.startPoint = startPoint;
17
20
  this.endPoint = endPoint;
18
21
  this.options = { ...options };
22
+ if (!Number.isInteger(this.options.seed) || this.options.seed <= 0) {
23
+ this.options.seed = Math.floor(Math.random() * 2147483647) + 1;
24
+ }
19
25
  this.group = document.createElementNS("http://www.w3.org/2000/svg", "g");
20
26
  this.isSelected = false;
21
27
  this.anchors = [];
@@ -28,11 +34,12 @@ var Line = class {
28
34
  this.parentFrame = null;
29
35
  this.label = options.label || "";
30
36
  this.labelElement = null;
31
- this.labelColor = options.labelColor || "#e0e0e0";
37
+ this.labelColor = resolveThemeLabelColor(options.labelColor);
32
38
  this.labelFontSize = options.labelFontSize || 12;
33
39
  this._isEditingLabel = false;
34
40
  this._hitArea = null;
35
41
  this._labelBg = null;
42
+ this._dragRenderFrame = null;
36
43
  svg.appendChild(this.group);
37
44
  this._setupLabelDblClick();
38
45
  this.draw();
@@ -368,7 +375,7 @@ var Line = class {
368
375
  });
369
376
  this.anchors = [];
370
377
  const anchorSize = 10 / (currentZoom || 1);
371
- const anchorStrokeWidth = 2 / (currentZoom || 1);
378
+ const anchorStrokeWidth = 2;
372
379
  const startAnchor = document.createElementNS("http://www.w3.org/2000/svg", "circle");
373
380
  startAnchor.setAttribute("cx", this.startPoint.x);
374
381
  startAnchor.setAttribute("cy", this.startPoint.y);
@@ -456,6 +463,33 @@ var Line = class {
456
463
  y: 2 * newY - 0.5 * (this.startPoint.y + this.endPoint.y)
457
464
  };
458
465
  }
466
+ this.scheduleDragRender();
467
+ }
468
+ scheduleDragRender() {
469
+ if (this._dragRenderFrame !== null) return;
470
+ if (typeof requestAnimationFrame !== "function") {
471
+ this.renderDragGeometry();
472
+ return;
473
+ }
474
+ this._dragRenderFrame = requestAnimationFrame(() => {
475
+ this._dragRenderFrame = null;
476
+ this.renderDragGeometry();
477
+ });
478
+ }
479
+ renderDragGeometry() {
480
+ this.updateLineElement();
481
+ this.updateAnchorPositions();
482
+ if (this._hitArea) {
483
+ const path = this.isCurved && this.controlPoint ? `M ${this.startPoint.x} ${this.startPoint.y} Q ${this.controlPoint.x} ${this.controlPoint.y} ${this.endPoint.x} ${this.endPoint.y}` : `M ${this.startPoint.x} ${this.startPoint.y} L ${this.endPoint.x} ${this.endPoint.y}`;
484
+ this._hitArea.setAttribute("d", path);
485
+ }
486
+ this._updateLabelElement();
487
+ }
488
+ finalizeMove() {
489
+ if (this._dragRenderFrame !== null && typeof cancelAnimationFrame === "function") {
490
+ cancelAnimationFrame(this._dragRenderFrame);
491
+ }
492
+ this._dragRenderFrame = null;
459
493
  this.draw();
460
494
  }
461
495
  updateLineElement() {
@@ -529,16 +563,7 @@ var Line = class {
529
563
  this.controlPoint.x += dx;
530
564
  this.controlPoint.y += dy;
531
565
  }
532
- this.updateLineElement();
533
- this.updateAnchorPositions();
534
- if (this._hitArea) {
535
- if (this.isCurved && this.controlPoint) {
536
- this._hitArea.setAttribute("d", `M ${this.startPoint.x} ${this.startPoint.y} Q ${this.controlPoint.x} ${this.controlPoint.y} ${this.endPoint.x} ${this.endPoint.y}`);
537
- } else {
538
- this._hitArea.setAttribute("d", `M ${this.startPoint.x} ${this.startPoint.y} L ${this.endPoint.x} ${this.endPoint.y}`);
539
- }
540
- }
541
- this._updateLabelElement();
566
+ this.scheduleDragRender();
542
567
  if (!this.isBeingMovedByFrame) {
543
568
  this.updateFrameContainment();
544
569
  }
@@ -625,4 +650,4 @@ var Line = class {
625
650
  export {
626
651
  Line
627
652
  };
628
- //# sourceMappingURL=chunk-TAJ5E6KI.js.map
653
+ //# sourceMappingURL=chunk-JYBJXTLM.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/shapes/Line.js"],
4
+ "sourcesContent": ["/* eslint-disable */\n// Line shape class - extracted from lineTool.js\n// Depends on globals: svg, shapes, rough, currentShape, currentZoom\nimport { updateAttachedArrows as updateArrowsForShape } from '../tools/arrowTool.js';\nimport { resolveThemeLabelColor } from '../utils/themeColors.js';\n\nconst rc = rough.svg(svg);\n// Issue #38 follow-up: read the default stroke from the active theme\n// instead of pinning to a single colour. White was invisible on the new\n// light canvas, black is invisible if the user toggles dark.\nfunction getThemeStroke() {\n if (typeof document === 'undefined') return '#fff';\n return document.body && document.body.classList.contains('theme-dark') ? '#fff' : '#000000';\n}\nconst lineStrokeWidth = 2;\nlet hoveredFrameLine = null;\n\nclass Line {\n constructor(startPoint, endPoint, options = {}) {\n this.startPoint = startPoint;\n this.endPoint = endPoint;\n this.options = { ...options };\n // RoughJS otherwise chooses a fresh random stroke on every redraw.\n // A stable per-line seed keeps the hand-drawn contour visually fixed\n // while its endpoints move.\n if (!Number.isInteger(this.options.seed) || this.options.seed <= 0) {\n this.options.seed = Math.floor(Math.random() * 0x7fffffff) + 1;\n }\n this.group = document.createElementNS('http://www.w3.org/2000/svg', 'g');\n this.isSelected = false;\n this.anchors = [];\n this.selectionOutline = null;\n this.shapeName = \"line\"; \n this.shapeID = `line-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`; \n this.group.setAttribute('id', this.shapeID);\n \n // Curve properties\n this.isCurved = false;\n this.controlPoint = null;\n \n // Frame attachment properties\n this.parentFrame = null;\n\n // Embedded label support\n this.label = options.label || '';\n this.labelElement = null;\n this.labelColor = resolveThemeLabelColor(options.labelColor);\n this.labelFontSize = options.labelFontSize || 12;\n this._isEditingLabel = false;\n this._hitArea = null;\n this._labelBg = null;\n this._dragRenderFrame = null;\n\n svg.appendChild(this.group);\n this._setupLabelDblClick();\n this.draw();\n }\n\n // Add position and dimension properties for frame compatibility\n get x() {\n return Math.min(this.startPoint.x, this.endPoint.x);\n }\n \n set x(value) {\n const currentX = this.x;\n const dx = value - currentX;\n this.startPoint.x += dx;\n this.endPoint.x += dx;\n if (this.controlPoint) {\n this.controlPoint.x += dx;\n }\n }\n \n get y() {\n return Math.min(this.startPoint.y, this.endPoint.y);\n }\n \n set y(value) {\n const currentY = this.y;\n const dy = value - currentY;\n this.startPoint.y += dy;\n this.endPoint.y += dy;\n if (this.controlPoint) {\n this.controlPoint.y += dy;\n }\n }\n \n get width() {\n return Math.abs(this.endPoint.x - this.startPoint.x);\n }\n \n set width(value) {\n const centerX = (this.startPoint.x + this.endPoint.x) / 2;\n this.startPoint.x = centerX - value / 2;\n this.endPoint.x = centerX + value / 2;\n }\n \n get height() {\n return Math.abs(this.endPoint.y - this.startPoint.y);\n }\n \n set height(value) {\n const centerY = (this.startPoint.y + this.endPoint.y) / 2;\n this.startPoint.y = centerY - value / 2;\n this.endPoint.y = centerY + value / 2;\n }\n\n initializeCurveControlPoint() {\n const midX = (this.startPoint.x + this.endPoint.x) / 2;\n const midY = (this.startPoint.y + this.endPoint.y) / 2;\n \n // Calculate perpendicular offset for curve\n const dx = this.endPoint.x - this.startPoint.x;\n const dy = this.endPoint.y - this.startPoint.y;\n const length = Math.sqrt(dx * dx + dy * dy);\n \n if (length === 0) {\n this.controlPoint = { x: midX, y: midY - 20 };\n return;\n }\n \n // Perpendicular vector\n const perpX = -dy / length;\n const perpY = dx / length;\n const curveOffset = 30; // Default curve amount\n \n this.controlPoint = {\n x: midX + perpX * curveOffset,\n y: midY + perpY * curveOffset\n };\n }\n\n draw() {\n // Clear existing elements but preserve label, hit area, and anchors during active resize\n const childrenToRemove = [];\n const preserveSet = this._skipAnchors ? new Set([...this.anchors, this.selectionOutline].filter(Boolean)) : null;\n for (let i = 0; i < this.group.children.length; i++) {\n const child = this.group.children[i];\n if (child !== this.labelElement && child !== this._hitArea && child !== this._labelBg) {\n if (preserveSet && preserveSet.has(child)) continue;\n childrenToRemove.push(child);\n }\n }\n childrenToRemove.forEach(child => this.group.removeChild(child));\n\n const rc = rough.svg(svg);\n let lineElement;\n\n if (this.isCurved && this.controlPoint) {\n const pathData = `M ${this.startPoint.x} ${this.startPoint.y} Q ${this.controlPoint.x} ${this.controlPoint.y} ${this.endPoint.x} ${this.endPoint.y}`;\n lineElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n lineElement.setAttribute('d', pathData);\n lineElement.setAttribute('stroke', this.options.stroke || getThemeStroke());\n lineElement.setAttribute('stroke-width', this.options.strokeWidth || lineStrokeWidth);\n lineElement.setAttribute('fill', 'none');\n lineElement.setAttribute('stroke-linecap', 'round');\n if (this.options.strokeDasharray) {\n lineElement.setAttribute('stroke-dasharray', this.options.strokeDasharray);\n }\n } else if (this.isBeingDrawn || this.options.strokeDasharray) {\n // Use plain SVG for lines being drawn OR dashed/dotted lines\n // (RoughJS ignores strokeDasharray, so dashed styles must bypass it)\n lineElement = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n lineElement.setAttribute('x1', this.startPoint.x);\n lineElement.setAttribute('y1', this.startPoint.y);\n lineElement.setAttribute('x2', this.endPoint.x);\n lineElement.setAttribute('y2', this.endPoint.y);\n lineElement.setAttribute('stroke', this.options.stroke || getThemeStroke());\n lineElement.setAttribute('stroke-width', this.options.strokeWidth || lineStrokeWidth);\n lineElement.setAttribute('stroke-linecap', 'round');\n if (this.options.strokeDasharray) {\n lineElement.setAttribute('stroke-dasharray', this.options.strokeDasharray);\n }\n } else {\n lineElement = rc.line(\n this.startPoint.x, this.startPoint.y,\n this.endPoint.x, this.endPoint.y,\n this.options\n );\n }\n\n this.element = lineElement;\n this.group.appendChild(lineElement);\n\n // Hit area - thicker invisible path for dblclick detection\n if (!this._hitArea) {\n this._hitArea = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n this._hitArea.setAttribute('fill', 'none');\n this._hitArea.setAttribute('stroke', 'transparent');\n this._hitArea.setAttribute('stroke-width', '20');\n this._hitArea.setAttribute('style', 'pointer-events: stroke;');\n this.group.appendChild(this._hitArea);\n }\n if (this.isCurved && this.controlPoint) {\n this._hitArea.setAttribute('d', `M ${this.startPoint.x} ${this.startPoint.y} Q ${this.controlPoint.x} ${this.controlPoint.y} ${this.endPoint.x} ${this.endPoint.y}`);\n } else {\n this._hitArea.setAttribute('d', `M ${this.startPoint.x} ${this.startPoint.y} L ${this.endPoint.x} ${this.endPoint.y}`);\n }\n\n // Update embedded label at midpoint\n this._updateLabelElement();\n\n if (this.isSelected) {\n if (this._skipAnchors) {\n this.updateSelectionControls();\n } else {\n this.addAnchors();\n }\n }\n }\n\n _getMidpoint() {\n if (this.isCurved && this.controlPoint) {\n // Quadratic bezier midpoint at t=0.5\n const t = 0.5;\n const mx = (1 - t) * (1 - t) * this.startPoint.x + 2 * (1 - t) * t * this.controlPoint.x + t * t * this.endPoint.x;\n const my = (1 - t) * (1 - t) * this.startPoint.y + 2 * (1 - t) * t * this.controlPoint.y + t * t * this.endPoint.y;\n return { x: mx, y: my };\n }\n return {\n x: (this.startPoint.x + this.endPoint.x) / 2,\n y: (this.startPoint.y + this.endPoint.y) / 2\n };\n }\n\n _updateLabelElement() {\n if (!this.label) {\n if (this.labelElement && this.labelElement.parentNode === this.group) {\n this.group.removeChild(this.labelElement);\n this.labelElement = null;\n }\n if (this._labelBg && this._labelBg.parentNode === this.group) {\n this.group.removeChild(this._labelBg);\n this._labelBg = null;\n }\n return;\n }\n\n if (!this.labelElement) {\n this.labelElement = document.createElementNS('http://www.w3.org/2000/svg', 'text');\n this.labelElement.setAttribute('class', 'shape-label');\n this.labelElement.setAttribute('pointer-events', 'none');\n }\n\n const mid = this._getMidpoint();\n this.labelElement.setAttribute('x', mid.x);\n this.labelElement.setAttribute('y', mid.y);\n this.labelElement.setAttribute('text-anchor', 'middle');\n this.labelElement.setAttribute('dominant-baseline', 'central');\n this.labelElement.setAttribute('fill', this.labelColor);\n this.labelElement.setAttribute('font-size', this.labelFontSize);\n this.labelElement.setAttribute('font-family', 'lixFont, sans-serif');\n this.labelElement.textContent = this.label;\n\n // Background knockout rect - hides the line behind the text\n const canvasBg = window.getComputedStyle(svg).backgroundColor || '#000';\n if (!this._labelBg) {\n this._labelBg = document.createElementNS('http://www.w3.org/2000/svg', 'rect');\n this._labelBg.setAttribute('pointer-events', 'none');\n }\n this._labelBg.setAttribute('fill', canvasBg);\n const hPadding = 4;\n const vPadding = 1;\n const charWidth = this.labelFontSize * 0.6;\n const bgW = this.label.length * charWidth + hPadding * 2;\n const bgH = this.labelFontSize + vPadding * 2;\n this._labelBg.setAttribute('x', mid.x - bgW / 2);\n this._labelBg.setAttribute('y', mid.y - bgH / 2);\n this._labelBg.setAttribute('width', bgW);\n this._labelBg.setAttribute('height', bgH);\n this._labelBg.setAttribute('rx', 2);\n\n // Re-append bg then text at end so they render ON TOP of the line path\n if (this._labelBg.parentNode === this.group) this.group.removeChild(this._labelBg);\n if (this.labelElement.parentNode === this.group) this.group.removeChild(this.labelElement);\n this.group.appendChild(this._labelBg);\n this.group.appendChild(this.labelElement);\n }\n\n _setupLabelDblClick() {\n this.group.addEventListener('dblclick', (e) => {\n e.stopPropagation();\n e.preventDefault();\n this.startLabelEdit();\n });\n }\n\n startLabelEdit() {\n if (this._isEditingLabel) return;\n this._isEditingLabel = true;\n\n if (this.labelElement) {\n this.labelElement.setAttribute('visibility', 'hidden');\n }\n if (this._labelBg) {\n this._labelBg.setAttribute('visibility', 'hidden');\n }\n\n // Get midpoint in screen coords via CTM\n const mid = this._getMidpoint();\n const ctm = this.group.getScreenCTM();\n if (!ctm) { this._isEditingLabel = false; return; }\n\n const pt = svg.createSVGPoint();\n pt.x = mid.x; pt.y = mid.y;\n const screenMid = pt.matrixTransform(ctm);\n\n const editW = 160;\n const editH = 28;\n\n // Create HTML overlay centered on the midpoint\n const overlay = document.createElement('div');\n overlay.className = 'shape-label-editor';\n overlay.style.cssText = `\n position: fixed; z-index: 10000;\n left: ${screenMid.x - editW / 2}px; top: ${screenMid.y - editH / 2}px;\n width: ${editW}px; height: ${editH}px;\n display: flex; align-items: center; justify-content: center;\n pointer-events: auto;\n `;\n\n const canvasBg = window.getComputedStyle(svg).backgroundColor || '#000';\n const input = document.createElement('div');\n input.setAttribute('contenteditable', 'true');\n input.style.cssText = `\n width: 100%; height: 100%;\n background: ${canvasBg}; border: none;\n outline: none; padding: 2px 6px;\n color: ${this.labelColor}; font-size: ${this.labelFontSize}px;\n font-family: lixFont, sans-serif; text-align: center;\n display: flex; align-items: center; justify-content: center;\n white-space: pre-wrap; word-break: break-word;\n cursor: text;\n `;\n if (this.label) {\n input.textContent = this.label;\n } else {\n input.innerHTML = '&nbsp;';\n }\n\n overlay.appendChild(input);\n document.body.appendChild(overlay);\n\n setTimeout(() => {\n input.focus();\n const sel = window.getSelection();\n const range = document.createRange();\n range.selectNodeContents(input);\n sel.removeAllRanges();\n sel.addRange(range);\n }, 10);\n\n const finishEdit = () => {\n const newText = input.textContent.trim().replace(/\\u00A0/g, '');\n this.label = newText;\n this._isEditingLabel = false;\n if (overlay.parentNode) overlay.parentNode.removeChild(overlay);\n if (this.labelElement) this.labelElement.removeAttribute('visibility');\n if (this._labelBg) this._labelBg.removeAttribute('visibility');\n this.draw();\n };\n\n input.addEventListener('blur', finishEdit);\n input.addEventListener('keydown', (e) => {\n e.stopPropagation();\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); input.blur(); }\n if (e.key === 'Escape') { input.textContent = this.label; input.blur(); }\n });\n input.addEventListener('pointerdown', (e) => e.stopPropagation());\n input.addEventListener('pointermove', (e) => e.stopPropagation());\n input.addEventListener('pointerup', (e) => e.stopPropagation());\n }\n\n setLabel(text, color, fontSize) {\n this.label = text || '';\n if (color) this.labelColor = color;\n if (fontSize) this.labelFontSize = fontSize;\n this.draw();\n }\n\n updateSelectionControls() {\n if (this.anchors.length === 0) return;\n\n // Update start anchor\n if (this.anchors[0]) {\n this.anchors[0].setAttribute('cx', this.startPoint.x);\n this.anchors[0].setAttribute('cy', this.startPoint.y);\n }\n\n // Update end anchor\n if (this.anchors[1]) {\n this.anchors[1].setAttribute('cx', this.endPoint.x);\n this.anchors[1].setAttribute('cy', this.endPoint.y);\n }\n\n // Update middle anchor\n if (this.anchors[2]) {\n const midX = (this.startPoint.x + this.endPoint.x) / 2;\n const midY = (this.startPoint.y + this.endPoint.y) / 2;\n let anchorMidX = midX, anchorMidY = midY;\n if (this.isCurved && this.controlPoint) {\n anchorMidX = 0.25 * this.startPoint.x + 0.5 * this.controlPoint.x + 0.25 * this.endPoint.x;\n anchorMidY = 0.25 * this.startPoint.y + 0.5 * this.controlPoint.y + 0.25 * this.endPoint.y;\n }\n this.anchors[2].setAttribute('cx', anchorMidX);\n this.anchors[2].setAttribute('cy', anchorMidY);\n }\n }\n\n selectLine() {\n this.isSelected = true;\n this.addAnchors();\n}\n\ndeselectLine() {\n this.isSelected = false;\n this.removeSelection();\n}\n\n// Update the complete removeSelection method\nremoveSelection() {\n // Remove anchors\n this.anchors.forEach(anchor => {\n if (anchor && anchor.parentNode === this.group) {\n this.group.removeChild(anchor);\n }\n });\n this.anchors = [];\n this.isSelected = false; // Only set to false when actually deselecting\n}\n\n addAnchors() {\n // Only remove existing anchors if they exist, don't call full removeSelection\n this.anchors.forEach(anchor => {\n if (anchor && anchor.parentNode === this.group) {\n this.group.removeChild(anchor);\n }\n });\n this.anchors = [];\n \n const anchorSize = 10 / (currentZoom || 1);\n const anchorStrokeWidth = 2;\n \n // Start point anchor\n const startAnchor = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\n startAnchor.setAttribute('cx', this.startPoint.x);\n startAnchor.setAttribute('cy', this.startPoint.y);\n startAnchor.setAttribute('r', anchorSize / 2);\n startAnchor.setAttribute('fill', '#121212');\n startAnchor.setAttribute('stroke', '#5B57D1');\n startAnchor.setAttribute('stroke-width', anchorStrokeWidth);\n startAnchor.setAttribute('vector-effect', 'non-scaling-stroke');\n startAnchor.setAttribute('class', 'anchor line-anchor');\n startAnchor.style.cursor = 'grab';\n startAnchor.style.pointerEvents = 'all';\n startAnchor.dataset.index = 0;\n this.group.appendChild(startAnchor);\n this.anchors[0] = startAnchor;\n\n // End point anchor\n const endAnchor = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\n endAnchor.setAttribute('cx', this.endPoint.x);\n endAnchor.setAttribute('cy', this.endPoint.y);\n endAnchor.setAttribute('r', anchorSize / 2);\n endAnchor.setAttribute('fill', '#121212');\n endAnchor.setAttribute('stroke', '#5B57D1');\n endAnchor.setAttribute('stroke-width', anchorStrokeWidth);\n endAnchor.setAttribute('vector-effect', 'non-scaling-stroke');\n endAnchor.setAttribute('class', 'anchor line-anchor');\n endAnchor.style.cursor = 'grab';\n endAnchor.style.pointerEvents = 'all';\n endAnchor.dataset.index = 1;\n this.group.appendChild(endAnchor);\n this.anchors[1] = endAnchor;\n\n // Middle anchor for curving - positioned ON the bezier curve at t=0.5\n const midX = (this.startPoint.x + this.endPoint.x) / 2;\n const midY = (this.startPoint.y + this.endPoint.y) / 2;\n let anchorMidX = midX, anchorMidY = midY;\n if (this.isCurved && this.controlPoint) {\n // Bezier point at t=0.5: 0.25*P0 + 0.5*CP + 0.25*P1\n anchorMidX = 0.25 * this.startPoint.x + 0.5 * this.controlPoint.x + 0.25 * this.endPoint.x;\n anchorMidY = 0.25 * this.startPoint.y + 0.5 * this.controlPoint.y + 0.25 * this.endPoint.y;\n }\n\n const middleAnchor = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\n middleAnchor.setAttribute('cx', anchorMidX);\n middleAnchor.setAttribute('cy', anchorMidY);\n middleAnchor.setAttribute('r', anchorSize / 2);\n middleAnchor.setAttribute('fill', this.isCurved ? '#5B57D1' : '#121212');\n middleAnchor.setAttribute('stroke', '#5B57D1');\n middleAnchor.setAttribute('stroke-width', anchorStrokeWidth);\n middleAnchor.setAttribute('vector-effect', 'non-scaling-stroke');\n middleAnchor.setAttribute('class', 'anchor line-middle-anchor');\n middleAnchor.style.cursor = 'grab';\n middleAnchor.style.pointerEvents = 'all';\n middleAnchor.dataset.index = 2;\n this.group.appendChild(middleAnchor);\n this.anchors[2] = middleAnchor;\n\n // Show line sidebar\n disableAllSideBars();\n lineSideBar.classList.remove(\"hidden\");\n if (window.__showSidebarForShape) window.__showSidebarForShape('line');\n this.updateSidebar();\n }\n\n isNearAnchor(x, y) {\n if (!this.isSelected) return null;\n const buffer = 15; // Increased buffer for easier selection\n const anchorSize = 10 / (currentZoom || 1);\n\n // Check anchors\n for (let i = 0; i < this.anchors.length; i++) {\n const anchor = this.anchors[i];\n if (anchor) {\n const anchorX = parseFloat(anchor.getAttribute('cx'));\n const anchorY = parseFloat(anchor.getAttribute('cy'));\n const distance = Math.sqrt(Math.pow(x - anchorX, 2) + Math.pow(y - anchorY, 2));\n if (distance <= anchorSize / 2 + buffer) {\n return { type: 'anchor', index: i };\n }\n }\n }\n \n return null;\n }\n\n updatePosition(anchorIndex, newX, newY) {\n if (anchorIndex === 0) {\n this.startPoint.x = newX;\n this.startPoint.y = newY;\n } else if (anchorIndex === 1) {\n this.endPoint.x = newX;\n this.endPoint.y = newY;\n } else if (anchorIndex === 2) {\n // Middle anchor - dragged position is ON the curve (bezier t=0.5)\n if (!this.isCurved) {\n this.isCurved = true;\n }\n // Invert bezier formula: CP = 2*M - 0.5*(P0+P1)\n this.controlPoint = {\n x: 2 * newX - 0.5 * (this.startPoint.x + this.endPoint.x),\n y: 2 * newY - 0.5 * (this.startPoint.y + this.endPoint.y)\n };\n }\n\n this.scheduleDragRender();\n }\n\n scheduleDragRender() {\n if (this._dragRenderFrame !== null) return;\n if (typeof requestAnimationFrame !== 'function') {\n this.renderDragGeometry();\n return;\n }\n this._dragRenderFrame = requestAnimationFrame(() => {\n this._dragRenderFrame = null;\n this.renderDragGeometry();\n });\n }\n\n renderDragGeometry() {\n this.updateLineElement();\n this.updateAnchorPositions();\n if (this._hitArea) {\n const path = this.isCurved && this.controlPoint\n ? `M ${this.startPoint.x} ${this.startPoint.y} Q ${this.controlPoint.x} ${this.controlPoint.y} ${this.endPoint.x} ${this.endPoint.y}`\n : `M ${this.startPoint.x} ${this.startPoint.y} L ${this.endPoint.x} ${this.endPoint.y}`;\n this._hitArea.setAttribute('d', path);\n }\n this._updateLabelElement();\n }\n\n finalizeMove() {\n if (this._dragRenderFrame !== null && typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(this._dragRenderFrame);\n }\n this._dragRenderFrame = null;\n this.draw();\n }\n\n updateLineElement() {\n // Update just the line element without rebuilding entire structure\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n\n const rc = rough.svg(svg);\n let lineElement;\n\n if (this.isCurved && this.controlPoint) {\n const pathData = `M ${this.startPoint.x} ${this.startPoint.y} Q ${this.controlPoint.x} ${this.controlPoint.y} ${this.endPoint.x} ${this.endPoint.y}`;\n lineElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n lineElement.setAttribute('d', pathData);\n lineElement.setAttribute('stroke', this.options.stroke || getThemeStroke());\n lineElement.setAttribute('stroke-width', this.options.strokeWidth || lineStrokeWidth);\n lineElement.setAttribute('fill', 'none');\n lineElement.setAttribute('stroke-linecap', 'round');\n if (this.options.strokeDasharray) {\n lineElement.setAttribute('stroke-dasharray', this.options.strokeDasharray);\n }\n } else if (this.options.strokeDasharray) {\n // Dashed/dotted lines must use plain SVG (RoughJS ignores strokeDasharray)\n lineElement = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n lineElement.setAttribute('x1', this.startPoint.x);\n lineElement.setAttribute('y1', this.startPoint.y);\n lineElement.setAttribute('x2', this.endPoint.x);\n lineElement.setAttribute('y2', this.endPoint.y);\n lineElement.setAttribute('stroke', this.options.stroke || getThemeStroke());\n lineElement.setAttribute('stroke-width', this.options.strokeWidth || lineStrokeWidth);\n lineElement.setAttribute('stroke-linecap', 'round');\n lineElement.setAttribute('stroke-dasharray', this.options.strokeDasharray);\n } else {\n lineElement = rc.line(\n this.startPoint.x, this.startPoint.y,\n this.endPoint.x, this.endPoint.y,\n this.options\n );\n }\n\n this.element = lineElement;\n this.group.insertBefore(lineElement, this.group.firstChild);\n }\n\n updateAnchorPositions() {\n // Update anchor positions without rebuilding them\n if (this.anchors[0]) {\n this.anchors[0].setAttribute('cx', this.startPoint.x);\n this.anchors[0].setAttribute('cy', this.startPoint.y);\n }\n if (this.anchors[1]) {\n this.anchors[1].setAttribute('cx', this.endPoint.x);\n this.anchors[1].setAttribute('cy', this.endPoint.y);\n }\n if (this.anchors[2]) {\n const midX = (this.startPoint.x + this.endPoint.x) / 2;\n const midY = (this.startPoint.y + this.endPoint.y) / 2;\n let anchorMidX = midX, anchorMidY = midY;\n if (this.isCurved && this.controlPoint) {\n // Bezier point at t=0.5: 0.25*P0 + 0.5*CP + 0.25*P1\n anchorMidX = 0.25 * this.startPoint.x + 0.5 * this.controlPoint.x + 0.25 * this.endPoint.x;\n anchorMidY = 0.25 * this.startPoint.y + 0.5 * this.controlPoint.y + 0.25 * this.endPoint.y;\n }\n this.anchors[2].setAttribute('cx', anchorMidX);\n this.anchors[2].setAttribute('cy', anchorMidY);\n this.anchors[2].setAttribute('fill', this.isCurved ? '#5B57D1' : '#121212');\n }\n }\n\n // Add move method for dragging the entire line\n move(dx, dy) {\n this.startPoint.x += dx;\n this.startPoint.y += dy;\n this.endPoint.x += dx;\n this.endPoint.y += dy;\n if (this.controlPoint) {\n this.controlPoint.x += dx;\n this.controlPoint.y += dy;\n }\n\n // Multiple pointer/snap updates in one browser frame collapse into a\n // single DOM + RoughJS update.\n this.scheduleDragRender();\n\n // Only update frame containment if not being moved by a parent frame\n if (!this.isBeingMovedByFrame) {\n this.updateFrameContainment();\n }\n\n this.updateAttachedArrows();\n }\n\n updateAttachedArrows() {\n updateArrowsForShape(this);\n }\n\n updateFrameContainment() {\n // Don't update if we're being moved by a frame\n if (this.isBeingMovedByFrame) return;\n \n let targetFrame = null;\n \n // Find which frame this shape is over\n shapes.forEach(shape => {\n if (shape.shapeName === 'frame' && shape.isShapeInFrame(this)) {\n targetFrame = shape;\n }\n });\n \n // If we have a parent frame and we're being dragged, temporarily remove clipping\n if (this.parentFrame) {\n this.parentFrame.temporarilyRemoveFromFrame(this);\n }\n \n // Update frame highlighting\n if (hoveredFrameLine && hoveredFrameLine !== targetFrame) {\n hoveredFrameLine.removeHighlight();\n }\n \n if (targetFrame && targetFrame !== hoveredFrameLine) {\n targetFrame.highlightFrame();\n }\n \n hoveredFrameLine = targetFrame;\n }\n\n contains(x, y) {\n const tolerance = 8 / (currentZoom || 1); // Slightly larger tolerance for easier selection\n \n if (this.isCurved && this.controlPoint) {\n return this.pointToQuadraticBezierDistance(x, y) <= tolerance;\n } else {\n return this.pointToLineDistance(x, y, this.startPoint.x, this.startPoint.y, this.endPoint.x, this.endPoint.y) <= tolerance;\n }\n }\n\n pointToQuadraticBezierDistance(x, y) {\n let minDistance = Infinity;\n const steps = 50; // Reduced steps for better performance\n\n for (let i = 0; i <= steps; i++) {\n const t = i / steps;\n const point = this.getQuadraticBezierPoint(t);\n const distance = Math.sqrt(Math.pow(x - point.x, 2) + Math.pow(y - point.y, 2));\n minDistance = Math.min(minDistance, distance);\n }\n\n return minDistance;\n }\n\n getQuadraticBezierPoint(t) {\n if (!this.controlPoint) return this.startPoint;\n \n const mt = 1 - t;\n return {\n x: mt * mt * this.startPoint.x + 2 * mt * t * this.controlPoint.x + t * t * this.endPoint.x,\n y: mt * mt * this.startPoint.y + 2 * mt * t * this.controlPoint.y + t * t * this.endPoint.y\n };\n }\n\n pointToLineDistance(x, y, x1, y1, x2, y2) {\n const A = x - x1;\n const B = y - y1;\n const C = x2 - x1;\n const D = y2 - y1;\n const dot = A * C + B * D;\n const lenSq = C * C + D * D;\n let param = -1;\n if (lenSq !== 0) param = dot / lenSq;\n let xx, yy;\n if (param < 0) {\n xx = x1;\n yy = y1;\n } else if (param > 1) {\n xx = x2;\n yy = y2;\n } else {\n xx = x1 + param * C;\n yy = y1 + param * D;\n }\n const dx = x - xx;\n const dy = y - yy;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n // No-op: React sidebar handles UI updates via Zustand store\n updateSidebar() {}\n}\n\nexport { Line };\n"],
5
+ "mappings": "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",
6
+ "names": ["rc"]
7
+ }
@@ -3,14 +3,14 @@ import {
3
3
  calculateSnap,
4
4
  clearSnapGuides,
5
5
  updateAttachedArrows
6
- } from "./chunk-KXLNEFN5.js";
6
+ } from "./chunk-2U47AU6Y.js";
7
7
  import {
8
8
  pushCreateAction,
9
9
  pushDeleteAction,
10
10
  pushFrameAttachmentAction,
11
11
  pushOptionsChangeAction,
12
12
  pushTransformAction
13
- } from "./chunk-VZX55VQL.js";
13
+ } from "./chunk-TFCBCWL5.js";
14
14
 
15
15
  // src/tools/freehandTool.js
16
16
  function getThemeStroke() {
@@ -561,4 +561,4 @@ export {
561
561
  handleMouseMove,
562
562
  handleMouseUp
563
563
  };
564
- //# sourceMappingURL=chunk-3PFVMNDJ.js.map
564
+ //# sourceMappingURL=chunk-LXEHYCKH.js.map
@@ -0,0 +1,17 @@
1
+ "use client";
2
+
3
+ // src/utils/themeColors.js
4
+ var LEGACY_LABEL_COLORS = /* @__PURE__ */ new Set(["#e0e0e0", "#e8e3f3"]);
5
+ function getThemeForeground() {
6
+ if (typeof document === "undefined") return "#ffffff";
7
+ return document.body?.classList.contains("theme-dark") ? "#ffffff" : "#000000";
8
+ }
9
+ function resolveThemeLabelColor(color) {
10
+ if (!color) return getThemeForeground();
11
+ return LEGACY_LABEL_COLORS.has(String(color).trim().toLowerCase()) ? getThemeForeground() : color;
12
+ }
13
+
14
+ export {
15
+ resolveThemeLabelColor
16
+ };
17
+ //# sourceMappingURL=chunk-M7OYYJC6.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/themeColors.js"],
4
+ "sourcesContent": ["const LEGACY_LABEL_COLORS = new Set(['#e0e0e0', '#e8e3f3'])\n\nexport function getThemeForeground() {\n if (typeof document === 'undefined') return '#ffffff'\n return document.body?.classList.contains('theme-dark') ? '#ffffff' : '#000000'\n}\n\nexport function resolveThemeLabelColor(color) {\n if (!color) return getThemeForeground()\n return LEGACY_LABEL_COLORS.has(String(color).trim().toLowerCase())\n ? getThemeForeground()\n : color\n}\n"],
5
+ "mappings": ";;;AAAA,IAAM,sBAAsB,oBAAI,IAAI,CAAC,WAAW,SAAS,CAAC;AAEnD,SAAS,qBAAqB;AACnC,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,SAAO,SAAS,MAAM,UAAU,SAAS,YAAY,IAAI,YAAY;AACvE;AAEO,SAAS,uBAAuB,OAAO;AAC5C,MAAI,CAAC,MAAO,QAAO,mBAAmB;AACtC,SAAO,oBAAoB,IAAI,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,IAC7D,mBAAmB,IACnB;AACN;",
6
+ "names": []
7
+ }
@@ -0,0 +1,131 @@
1
+ "use client";
2
+
3
+ // src/core/ScreenSpaceControls.js
4
+ var ROTATION_SELECTOR = '[data-screen-space-rotation-anchor="true"]';
5
+ var OUTLINE_SELECTOR = ".selection-outline, .selection-box, .multi-selection-outline";
6
+ var HANDLE_SELECTOR = ".anchor, .resize-anchor, .resize-handle, .multi-selection-anchor";
7
+ var SELECTION_CHROME = Object.freeze({
8
+ outlineWidth: 1.5,
9
+ outlineDash: "4 2",
10
+ handleSize: 10,
11
+ handleStrokeWidth: 2,
12
+ rotationRadius: 8,
13
+ rotationGap: 30
14
+ });
15
+ function getZoom() {
16
+ return Math.max(1e-3, Number(globalThis.window?.currentZoom) || 1);
17
+ }
18
+ function registerRotationAnchor(anchor, options = {}) {
19
+ if (!anchor) return;
20
+ const zoom = getZoom();
21
+ const radius = SELECTION_CHROME.rotationRadius;
22
+ const gap = SELECTION_CHROME.rotationGap;
23
+ const edgeY = Number(options.edgeY);
24
+ anchor.setAttribute("data-screen-space-rotation-anchor", "true");
25
+ anchor.setAttribute("data-screen-radius", String(radius));
26
+ anchor.setAttribute("data-screen-gap", String(gap));
27
+ anchor.setAttribute("data-applied-zoom", String(zoom));
28
+ anchor.setAttribute("r", String(radius / zoom));
29
+ anchor.setAttribute("stroke", "#5B57D1");
30
+ anchor.setAttribute("stroke-width", String(SELECTION_CHROME.handleStrokeWidth));
31
+ anchor.setAttribute("vector-effect", "non-scaling-stroke");
32
+ if (Number.isFinite(edgeY)) anchor.setAttribute("cy", String(edgeY - gap / zoom));
33
+ anchor.__rotationConnector = options.line || null;
34
+ anchor.__rotationConnectorEnd = options.lineEnd || "2";
35
+ syncRotationConnector(anchor);
36
+ }
37
+ function syncRotationConnector(anchor) {
38
+ const line = anchor.__rotationConnector;
39
+ if (!line) return;
40
+ const end = anchor.__rotationConnectorEnd === "1" ? "1" : "2";
41
+ line.setAttribute(`x${end}`, anchor.getAttribute("cx"));
42
+ line.setAttribute(`y${end}`, anchor.getAttribute("cy"));
43
+ line.setAttribute("stroke", "#5B57D1");
44
+ line.setAttribute("stroke-width", "1");
45
+ line.setAttribute("stroke-dasharray", SELECTION_CHROME.outlineDash);
46
+ line.setAttribute("vector-effect", "non-scaling-stroke");
47
+ }
48
+ function resizeHandleInScreenSpace(handle, zoom) {
49
+ const size = SELECTION_CHROME.handleSize / zoom;
50
+ const tagName = handle.tagName?.toLowerCase();
51
+ if (tagName === "rect") {
52
+ const oldWidth = Number(handle.getAttribute("width")) || size;
53
+ const oldHeight = Number(handle.getAttribute("height")) || size;
54
+ const centerX = (Number(handle.getAttribute("x")) || 0) + oldWidth / 2;
55
+ const centerY = (Number(handle.getAttribute("y")) || 0) + oldHeight / 2;
56
+ handle.setAttribute("x", String(centerX - size / 2));
57
+ handle.setAttribute("y", String(centerY - size / 2));
58
+ handle.setAttribute("width", String(size));
59
+ handle.setAttribute("height", String(size));
60
+ } else if (tagName === "circle" && !handle.matches(ROTATION_SELECTOR)) {
61
+ handle.setAttribute("r", String(size / 2));
62
+ }
63
+ handle.setAttribute("stroke", "#5B57D1");
64
+ handle.setAttribute("stroke-width", String(SELECTION_CHROME.handleStrokeWidth));
65
+ handle.setAttribute("vector-effect", "non-scaling-stroke");
66
+ }
67
+ function syncSelectionChromeToZoom(root = document) {
68
+ if (!root?.querySelectorAll) return;
69
+ const zoom = getZoom();
70
+ root.querySelectorAll(OUTLINE_SELECTOR).forEach((outline) => {
71
+ outline.setAttribute("fill", "none");
72
+ outline.setAttribute("stroke", "#5B57D1");
73
+ outline.setAttribute("stroke-width", String(SELECTION_CHROME.outlineWidth));
74
+ outline.setAttribute("stroke-dasharray", SELECTION_CHROME.outlineDash);
75
+ outline.setAttribute("vector-effect", "non-scaling-stroke");
76
+ });
77
+ root.querySelectorAll(HANDLE_SELECTOR).forEach((handle) => {
78
+ resizeHandleInScreenSpace(handle, zoom);
79
+ });
80
+ }
81
+ function syncRotationAnchorsToZoom() {
82
+ if (typeof document === "undefined") return;
83
+ const zoom = getZoom();
84
+ document.querySelectorAll(ROTATION_SELECTOR).forEach((anchor) => {
85
+ const previousZoom = Math.max(1e-3, Number(anchor.getAttribute("data-applied-zoom")) || zoom);
86
+ const radius = SELECTION_CHROME.rotationRadius;
87
+ const gap = SELECTION_CHROME.rotationGap;
88
+ if (Math.abs(previousZoom - zoom) >= 1e-6) {
89
+ const currentY = Number(anchor.getAttribute("cy")) || 0;
90
+ const edgeY = currentY + gap / previousZoom;
91
+ anchor.setAttribute("cy", String(edgeY - gap / zoom));
92
+ anchor.setAttribute("data-applied-zoom", String(zoom));
93
+ }
94
+ anchor.setAttribute("r", String(radius / zoom));
95
+ anchor.setAttribute("stroke", "#5B57D1");
96
+ anchor.setAttribute("stroke-width", String(SELECTION_CHROME.handleStrokeWidth));
97
+ anchor.setAttribute("vector-effect", "non-scaling-stroke");
98
+ syncRotationConnector(anchor);
99
+ });
100
+ syncSelectionChromeToZoom(document);
101
+ }
102
+ function installScreenSpaceControlSync(svgElement) {
103
+ if (!svgElement || typeof MutationObserver === "undefined") return;
104
+ window.__screenSpaceControlObserver?.disconnect?.();
105
+ let scheduled = false;
106
+ const scheduleSync = () => {
107
+ if (scheduled) return;
108
+ scheduled = true;
109
+ const run = () => {
110
+ scheduled = false;
111
+ syncRotationAnchorsToZoom();
112
+ };
113
+ if (typeof requestAnimationFrame === "function") requestAnimationFrame(run);
114
+ else queueMicrotask(run);
115
+ };
116
+ const observer = new MutationObserver(scheduleSync);
117
+ observer.observe(svgElement, {
118
+ attributes: true,
119
+ attributeFilter: ["viewBox"],
120
+ childList: true,
121
+ subtree: true
122
+ });
123
+ window.__screenSpaceControlObserver = observer;
124
+ scheduleSync();
125
+ }
126
+
127
+ export {
128
+ registerRotationAnchor,
129
+ installScreenSpaceControlSync
130
+ };
131
+ //# sourceMappingURL=chunk-MS4TIQ6Z.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/core/ScreenSpaceControls.js"],
4
+ "sourcesContent": ["/* eslint-disable */\n\nconst ROTATION_SELECTOR = '[data-screen-space-rotation-anchor=\"true\"]';\nconst OUTLINE_SELECTOR = '.selection-outline, .selection-box, .multi-selection-outline';\nconst HANDLE_SELECTOR = '.anchor, .resize-anchor, .resize-handle, .multi-selection-anchor';\n\nexport const SELECTION_CHROME = Object.freeze({\n outlineWidth: 1.5,\n outlineDash: '4 2',\n handleSize: 10,\n handleStrokeWidth: 2,\n rotationRadius: 8,\n rotationGap: 30,\n});\n\nexport function getSelectionChromeMetrics(zoom = 1) {\n const normalizedZoom = Math.max(0.001, Number(zoom) || 1);\n return {\n outlineWidth: SELECTION_CHROME.outlineWidth,\n outlineDash: SELECTION_CHROME.outlineDash,\n handleSize: SELECTION_CHROME.handleSize / normalizedZoom,\n rotationRadius: SELECTION_CHROME.rotationRadius / normalizedZoom,\n rotationGap: SELECTION_CHROME.rotationGap / normalizedZoom,\n };\n}\n\nfunction getZoom() {\n return Math.max(0.001, Number(globalThis.window?.currentZoom) || 1);\n}\n\nexport function registerRotationAnchor(anchor, options = {}) {\n if (!anchor) return;\n const zoom = getZoom();\n const radius = SELECTION_CHROME.rotationRadius;\n const gap = SELECTION_CHROME.rotationGap;\n const edgeY = Number(options.edgeY);\n\n anchor.setAttribute('data-screen-space-rotation-anchor', 'true');\n anchor.setAttribute('data-screen-radius', String(radius));\n anchor.setAttribute('data-screen-gap', String(gap));\n anchor.setAttribute('data-applied-zoom', String(zoom));\n anchor.setAttribute('r', String(radius / zoom));\n anchor.setAttribute('stroke', '#5B57D1');\n anchor.setAttribute('stroke-width', String(SELECTION_CHROME.handleStrokeWidth));\n anchor.setAttribute('vector-effect', 'non-scaling-stroke');\n if (Number.isFinite(edgeY)) anchor.setAttribute('cy', String(edgeY - gap / zoom));\n\n anchor.__rotationConnector = options.line || null;\n anchor.__rotationConnectorEnd = options.lineEnd || '2';\n syncRotationConnector(anchor);\n}\n\nfunction syncRotationConnector(anchor) {\n const line = anchor.__rotationConnector;\n if (!line) return;\n const end = anchor.__rotationConnectorEnd === '1' ? '1' : '2';\n line.setAttribute(`x${end}`, anchor.getAttribute('cx'));\n line.setAttribute(`y${end}`, anchor.getAttribute('cy'));\n line.setAttribute('stroke', '#5B57D1');\n line.setAttribute('stroke-width', '1');\n line.setAttribute('stroke-dasharray', SELECTION_CHROME.outlineDash);\n line.setAttribute('vector-effect', 'non-scaling-stroke');\n}\n\nfunction resizeHandleInScreenSpace(handle, zoom) {\n const size = SELECTION_CHROME.handleSize / zoom;\n const tagName = handle.tagName?.toLowerCase();\n\n if (tagName === 'rect') {\n const oldWidth = Number(handle.getAttribute('width')) || size;\n const oldHeight = Number(handle.getAttribute('height')) || size;\n const centerX = (Number(handle.getAttribute('x')) || 0) + oldWidth / 2;\n const centerY = (Number(handle.getAttribute('y')) || 0) + oldHeight / 2;\n handle.setAttribute('x', String(centerX - size / 2));\n handle.setAttribute('y', String(centerY - size / 2));\n handle.setAttribute('width', String(size));\n handle.setAttribute('height', String(size));\n } else if (tagName === 'circle' && !handle.matches(ROTATION_SELECTOR)) {\n handle.setAttribute('r', String(size / 2));\n }\n\n handle.setAttribute('stroke', '#5B57D1');\n handle.setAttribute('stroke-width', String(SELECTION_CHROME.handleStrokeWidth));\n handle.setAttribute('vector-effect', 'non-scaling-stroke');\n}\n\nexport function syncSelectionChromeToZoom(root = document) {\n if (!root?.querySelectorAll) return;\n const zoom = getZoom();\n\n root.querySelectorAll(OUTLINE_SELECTOR).forEach((outline) => {\n outline.setAttribute('fill', 'none');\n outline.setAttribute('stroke', '#5B57D1');\n outline.setAttribute('stroke-width', String(SELECTION_CHROME.outlineWidth));\n outline.setAttribute('stroke-dasharray', SELECTION_CHROME.outlineDash);\n outline.setAttribute('vector-effect', 'non-scaling-stroke');\n });\n\n root.querySelectorAll(HANDLE_SELECTOR).forEach((handle) => {\n resizeHandleInScreenSpace(handle, zoom);\n });\n}\n\nexport function syncRotationAnchorsToZoom() {\n if (typeof document === 'undefined') return;\n const zoom = getZoom();\n document.querySelectorAll(ROTATION_SELECTOR).forEach((anchor) => {\n const previousZoom = Math.max(0.001, Number(anchor.getAttribute('data-applied-zoom')) || zoom);\n const radius = SELECTION_CHROME.rotationRadius;\n const gap = SELECTION_CHROME.rotationGap;\n if (Math.abs(previousZoom - zoom) >= 0.000001) {\n const currentY = Number(anchor.getAttribute('cy')) || 0;\n const edgeY = currentY + gap / previousZoom;\n anchor.setAttribute('cy', String(edgeY - gap / zoom));\n anchor.setAttribute('data-applied-zoom', String(zoom));\n }\n anchor.setAttribute('r', String(radius / zoom));\n anchor.setAttribute('stroke', '#5B57D1');\n anchor.setAttribute('stroke-width', String(SELECTION_CHROME.handleStrokeWidth));\n anchor.setAttribute('vector-effect', 'non-scaling-stroke');\n syncRotationConnector(anchor);\n });\n syncSelectionChromeToZoom(document);\n}\n\nexport function installScreenSpaceControlSync(svgElement) {\n if (!svgElement || typeof MutationObserver === 'undefined') return;\n window.__screenSpaceControlObserver?.disconnect?.();\n let scheduled = false;\n const scheduleSync = () => {\n if (scheduled) return;\n scheduled = true;\n const run = () => {\n scheduled = false;\n syncRotationAnchorsToZoom();\n };\n if (typeof requestAnimationFrame === 'function') requestAnimationFrame(run);\n else queueMicrotask(run);\n };\n const observer = new MutationObserver(scheduleSync);\n observer.observe(svgElement, {\n attributes: true,\n attributeFilter: ['viewBox'],\n childList: true,\n subtree: true,\n });\n window.__screenSpaceControlObserver = observer;\n scheduleSync();\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  cleanupAttachments,
4
4
  updateAttachedArrows
5
- } from "./chunk-KXLNEFN5.js";
5
+ } from "./chunk-2U47AU6Y.js";
6
6
 
7
7
  // src/shapes/IconShape.js
8
8
  var isDragging = false;
@@ -220,4 +220,4 @@ var IconShape = class {
220
220
  export {
221
221
  IconShape
222
222
  };
223
- //# sourceMappingURL=chunk-5XGQ3CMT.js.map
223
+ //# sourceMappingURL=chunk-OCJN32IL.js.map
@@ -3,14 +3,14 @@ import {
3
3
  calculateSnap,
4
4
  cleanupAttachments,
5
5
  clearSnapGuides
6
- } from "./chunk-KXLNEFN5.js";
6
+ } from "./chunk-2U47AU6Y.js";
7
7
  import {
8
8
  pushCreateAction,
9
9
  pushDeleteAction,
10
10
  pushFrameAttachmentAction,
11
11
  pushOptionsChangeAction,
12
12
  pushTransformAction
13
- } from "./chunk-VZX55VQL.js";
13
+ } from "./chunk-TFCBCWL5.js";
14
14
 
15
15
  // src/tools/circleTool.js
16
16
  function getThemeStroke() {
@@ -92,6 +92,7 @@ var handleMouseDown = (e) => {
92
92
  initialOptions.strokeDasharray = "";
93
93
  }
94
94
  currentShape = new Circle(startX, startY, 0, 0, initialOptions);
95
+ currentShape.isBeingDrawn = true;
95
96
  } else if (isSelectionToolActive) {
96
97
  let clickedOnShape = false;
97
98
  if (currentShape && currentShape.shapeName === "circle" && currentShape.isSelected) {
@@ -185,7 +186,7 @@ var handleMouseMove = (e) => {
185
186
  currentShape.y = (startY + svgMouseY) / 2;
186
187
  currentShape.rx = Math.abs(svgMouseX - startX) / 2;
187
188
  currentShape.ry = Math.abs(svgMouseY - startY) / 2;
188
- currentShape.draw();
189
+ currentShape.scheduleDrawingRender();
189
190
  shapes.forEach((frame) => {
190
191
  if (frame.shapeName === "frame") {
191
192
  if (frame.isShapeInFrame(currentShape)) {
@@ -279,11 +280,13 @@ var handleMouseMove = (e) => {
279
280
  var handleMouseUp = (e) => {
280
281
  if (isDrawingCircle && currentShape) {
281
282
  if (currentShape.rx === 0 && currentShape.ry === 0) {
283
+ currentShape.cancelDrawingRender();
282
284
  if (currentShape.group.parentNode) {
283
285
  currentShape.group.parentNode.removeChild(currentShape.group);
284
286
  }
285
287
  currentShape = null;
286
288
  } else {
289
+ currentShape.finalizeDrawing();
287
290
  shapes.push(currentShape);
288
291
  pushCreateAction(currentShape);
289
292
  const finalFrame = hoveredFrameCircle;
@@ -550,4 +553,4 @@ export {
550
553
  handleMouseMove,
551
554
  handleMouseUp
552
555
  };
553
- //# sourceMappingURL=chunk-7NHZYKYB.js.map
556
+ //# sourceMappingURL=chunk-P7VIYR6R.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/tools/circleTool.js"],
4
+ "sourcesContent": ["/* eslint-disable */\n// Circle tool event handlers - extracted from drawCircle.js\nimport { pushCreateAction, pushDeleteAction, pushOptionsChangeAction, pushTransformAction, pushFrameAttachmentAction } from '../core/UndoRedo.js';\nimport { cleanupAttachments } from './arrowTool.js';\nimport { calculateSnap, clearSnapGuides } from '../core/SnapGuides.js';\n\nfunction getThemeStroke() { if (typeof document === \"undefined\") return \"#fff\"; return document.body && document.body.classList.contains(\"theme-dark\") ? \"#fff\" : \"#000000\"; }\n\nlet isDrawingCircle = false;\nlet isDraggingShapeCircle = false;\nlet isResizingShapeCircle = false;\nlet isRotatingShapeCircle = false;\nlet resizingAnchorIndexCircle = null;\n\nlet startRotationMouseAngleCircle = null;\nlet startShapeRotationCircle = null;\nconst rc = rough.svg(svg);\nlet startX, startY;\n\n\nlet circleStrokecolor = null;\nlet circleBackgroundColor = \"transparent\";\nlet circleFillStyleValue = \"none\";\nlet circleStrokeThicknes = 2;\nlet circleOutlineStyle = \"solid\";\n\nlet dragOldPosCircle = null;\nlet draggedShapeInitialFrameCircle = null;\nlet hoveredFrameCircle = null;\nlet colorOptionsCircle = document.querySelectorAll(\".circleStrokeSpan\");\nlet backgroundColorOptionsCircle = document.querySelectorAll(\".circleBackgroundSpan\");\nlet fillStyleOptionsCircle = document.querySelectorAll(\".circleFillStyleSpan\");\nlet strokeThicknessValueCircle = document.querySelectorAll(\".circleStrokeThickSpan\");\nlet outlineStyleValueCircle = document.querySelectorAll(\".circleOutlineStyle\");\n\n\n\nfunction getSVGCoordsFromMouse(e) {\n const viewBox = svg.viewBox.baseVal;\n const rect = svg.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const svgX = viewBox.x + (mouseX / rect.width) * viewBox.width;\n const svgY = viewBox.y + (mouseY / rect.height) * viewBox.height;\n return { x: svgX, y: svgY };\n}\n\n\nfunction deleteCurrentShape() {\n if (currentShape && currentShape.shapeName === 'circle') {\n const idx = shapes.indexOf(currentShape);\n if (idx !== -1) shapes.splice(idx, 1);\n \n // Clean up any arrow attachments before deleting\n cleanupAttachments(currentShape);\n \n if (currentShape.group.parentNode) {\n currentShape.group.parentNode.removeChild(currentShape.group);\n }\n pushDeleteAction(currentShape);\n currentShape = null;\n disableAllSideBars();\n }\n}\n\ndocument.addEventListener('keydown', (e) => {\n if (e.key === 'Delete' && currentShape && currentShape.shapeName === 'circle') {\n deleteCurrentShape();\n }\n});\n\nconst handleMouseDown = (e) => {\n const {x: svgMouseX, y: svgMouseY} = getSVGCoordsFromMouse(e);\n\n if(isCircleToolActive)\n {\n startX = svgMouseX;\n startY = svgMouseY;\n isDrawingCircle = true;\n\n if(currentShape) \n {\n currentShape.removeSelection();\n currentShape = null;\n disableAllSideBars();\n }\n let initialOptions = {\n stroke: circleStrokecolor ?? getThemeStroke(),\n fill: circleBackgroundColor,\n fillStyle: circleFillStyleValue,\n strokeWidth: circleStrokeThicknes,\n };\n if(circleOutlineStyle === \"dashed\") {\n initialOptions.strokeDasharray = \"5,5\";\n }\n else if(circleOutlineStyle === \"dotted\") {\n initialOptions.strokeDasharray = \"2,8\";\n } else {\n initialOptions.strokeDasharray = \"\";\n }\n\n currentShape = new Circle(startX, startY, 0, 0, initialOptions);\n currentShape.isBeingDrawn = true;\n }\n\n else if(isSelectionToolActive) \n {\n let clickedOnShape = false;\n if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected)\n {\n const anchorInfo = currentShape.isNearAnchor(svgMouseX, svgMouseY);\n if (anchorInfo) {\n dragOldPosCircle = { \n x: currentShape.x, \n y: currentShape.y, \n rx: currentShape.rx, \n ry: currentShape.ry, \n rotation: currentShape.rotation \n };\n if(anchorInfo.type === 'resize') \n {\n isResizingShapeCircle = true;\n resizingAnchorIndexCircle = anchorInfo.index;\n }\n else if(anchorInfo.type === 'rotate') \n {\n isRotatingShapeCircle = true;\n startRotationMouseAngleCircle = Math.atan2(svgMouseY - currentShape.y, svgMouseX - currentShape.x) * (180 / Math.PI);\n startShapeRotationCircle = currentShape.rotation;\n }\n clickedOnShape = true;\n }\n else if (currentShape.contains(svgMouseX, svgMouseY)) \n {\n isDraggingShapeCircle = true;\n dragOldPosCircle = { \n x: currentShape.x, \n y: currentShape.y, \n rx: currentShape.rx, \n ry: currentShape.ry, \n rotation: currentShape.rotation \n };\n \n // Store initial frame state\n draggedShapeInitialFrameCircle = currentShape.parentFrame || null;\n \n // Temporarily remove from frame clipping if dragging\n if (currentShape.parentFrame) {\n currentShape.parentFrame.temporarilyRemoveFromFrame(currentShape);\n }\n \n startX = svgMouseX;\n startY = svgMouseY;\n clickedOnShape = true;\n }\n }\n if (!clickedOnShape) \n {\n let shapeToSelect = null;\n for (let i = shapes.length - 1; i >= 0; i--) {\n const shape = shapes[i];\n if (shape.shapeName === 'circle' && shape.contains(svgMouseX, svgMouseY)) {\n shapeToSelect = shape;\n break; \n }\n }\n if (currentShape && currentShape !== shapeToSelect) {\n currentShape.removeSelection();\n currentShape = null;\n disableAllSideBars();\n }\n if(shapeToSelect)\n {\n currentShape = shapeToSelect;\n currentShape.isSelected = true;\n currentShape.draw();\n isDraggingShapeCircle = true;\n dragOldPosCircle = { \n x: currentShape.x, \n y: currentShape.y, \n rx: currentShape.rx, \n ry: currentShape.ry, \n rotation: currentShape.rotation \n };\n \n // Store initial frame state\n draggedShapeInitialFrameCircle = currentShape.parentFrame || null;\n \n // Temporarily remove from frame clipping if dragging\n if (currentShape.parentFrame) {\n currentShape.parentFrame.temporarilyRemoveFromFrame(currentShape);\n }\n \n startX = svgMouseX;\n startY = svgMouseY;\n clickedOnShape = true;\n }\n }\n if(!clickedOnShape && currentShape) {\n currentShape.removeSelection();\n currentShape = null;\n disableAllSideBars();\n }\n }\n};\n\nconst handleMouseMove = (e) => {\n\n const {x: svgMouseX, y: svgMouseY} = getSVGCoordsFromMouse(e);\n \n // Keep lastMousePos in screen coordinates for other functions\n const svgRect = svg.getBoundingClientRect();\n lastMousePos = {\n x: e.clientX - svgRect.left, \n y: e.clientY - svgRect.top\n };\n\n if(isDrawingCircle && isCircleToolActive && currentShape) \n {\n currentShape.x = (startX + svgMouseX) / 2;\n currentShape.y = (startY + svgMouseY) / 2;\n currentShape.rx = Math.abs(svgMouseX - startX) / 2;\n currentShape.ry = Math.abs(svgMouseY - startY) / 2;\n currentShape.scheduleDrawingRender();\n \n // Check for frame containment while drawing (but don't apply clipping yet)\n shapes.forEach(frame => {\n if (frame.shapeName === 'frame') {\n if (frame.isShapeInFrame(currentShape)) {\n frame.highlightFrame();\n hoveredFrameCircle = frame;\n } else if (hoveredFrameCircle === frame) {\n frame.removeHighlight();\n hoveredFrameCircle = null;\n }\n }\n });\n }\n else if (isDraggingShapeCircle && currentShape && currentShape.isSelected) {\n const dx = svgMouseX - startX;\n const dy = svgMouseY - startY;\n currentShape.move(dx, dy);\n startX = svgMouseX;\n startY = svgMouseY;\n\n // Snap guides\n if (window.__sketchStoreApi && window.__sketchStoreApi.getState().snapToObjects) {\n const snap = calculateSnap(currentShape, e.shiftKey, e.clientX, e.clientY);\n if (snap.dx || snap.dy) {\n currentShape.move(snap.dx, snap.dy);\n }\n } else {\n clearSnapGuides();\n }\n\n // Issue #24 bug #4: track containing frame during drag (see same\n // block in rectangleTool for the rationale).\n let newHover = null;\n for (const f of shapes) {\n if (f.shapeName !== 'frame') continue;\n if (f === currentShape) continue;\n if (typeof f.isShapeInFrame === 'function' && f.isShapeInFrame(currentShape)) {\n newHover = f;\n break;\n }\n }\n if (hoveredFrameCircle && hoveredFrameCircle !== newHover && typeof hoveredFrameCircle.removeHighlight === 'function') {\n hoveredFrameCircle.removeHighlight();\n }\n if (newHover && newHover !== hoveredFrameCircle && typeof newHover.highlightFrame === 'function') {\n newHover.highlightFrame();\n }\n hoveredFrameCircle = newHover;\n }\n \n else if(isResizingShapeCircle && currentShape && currentShape.isSelected)\n {\n currentShape.updatePosition(resizingAnchorIndexCircle, svgMouseX, svgMouseY);\n currentShape._skipAnchors = true;\n currentShape.draw();\n currentShape._skipAnchors = false;\n }\n else if (isRotatingShapeCircle && currentShape && currentShape.isSelected)\n {\n const currentMouseAngle = Math.atan2(svgMouseY - currentShape.y, svgMouseX - currentShape.x) * (180 / Math.PI);\n const angleDiff = currentMouseAngle - startRotationMouseAngleCircle;\n let newRotation = startShapeRotationCircle + angleDiff;\n const snapAngle = 15;\n if (e.shiftKey) {\n newRotation = Math.round(newRotation / snapAngle) * snapAngle;\n }\n currentShape.rotate(newRotation);\n currentShape._skipAnchors = true;\n currentShape.draw();\n currentShape._skipAnchors = false;\n svg.style.cursor = 'grabbing'; \n }\n else if (isSelectionToolActive && !isDrawingCircle && currentShape && currentShape.isSelected) \n {\n const anchorInfo = currentShape.isNearAnchor(svgMouseX, svgMouseY);\n if(anchorInfo)\n {\n if(anchorInfo.type === 'resize') {\n const baseDirection = anchorInfo.index; \n const rotatedCursor = currentShape.getRotatedCursor(baseDirection, currentShape.rotation);\n svg.style.cursor = rotatedCursor + '-resize';\n }\n else if(anchorInfo.type === 'rotate') {\n svg.style.cursor = 'grab';\n }\n }\n else if(currentShape.contains(svgMouseX, svgMouseY)) {\n svg.style.cursor = 'move';\n }\n else \n {\n svg.style.cursor = 'default';\n }\n }\n else if (isSelectionToolActive && !isDrawingCircle && !isDraggingShapeCircle && !isResizingShapeCircle && !isRotatingShapeCircle) \n {\n let hoveredShape = null;\n for (let i = shapes.length - 1; i >= 0; i--) {\n const shape = shapes[i];\n if (shape.shapeName === 'circle' && shape.contains(svgMouseX, svgMouseY)) {\n hoveredShape = shape;\n break; \n }\n }\n if (hoveredShape) {\n svg.style.cursor = 'pointer';\n } else {\n svg.style.cursor = 'default';\n }\n }\n}\n\nconst handleMouseUp = (e) => {\n if (isDrawingCircle && currentShape) {\n if(currentShape.rx === 0 && currentShape.ry === 0) {\n currentShape.cancelDrawingRender();\n if (currentShape.group.parentNode) {\n currentShape.group.parentNode.removeChild(currentShape.group);\n }\n currentShape = null;\n } else {\n currentShape.finalizeDrawing();\n shapes.push(currentShape);\n pushCreateAction(currentShape);\n\n // Check for frame containment and track attachment\n const finalFrame = hoveredFrameCircle;\n if (finalFrame) {\n finalFrame.addShapeToFrame(currentShape);\n // Track the attachment for undo\n pushFrameAttachmentAction(finalFrame, currentShape, 'attach', null);\n }\n\n // Auto-select the drawn shape and switch to selection tool\n const drawnShape = currentShape;\n if (window.__sketchStoreApi) window.__sketchStoreApi.setActiveTool('select', { afterDraw: true });\n currentShape = drawnShape;\n currentShape.isSelected = true;\n if (typeof currentShape.addAnchors === 'function') {\n currentShape.addAnchors();\n }\n }\n \n // Clear frame highlighting\n if (hoveredFrameCircle) {\n hoveredFrameCircle.removeHighlight();\n hoveredFrameCircle = null;\n }\n }\n \n if((isDraggingShapeCircle || isResizingShapeCircle || isRotatingShapeCircle) && dragOldPosCircle && currentShape) {\n // Issue #34 bug #2: see rectangleTool \u2014 record the hovered frame\n // as the destination, not the stale `parentFrame` (containment\n // transfer happens later in this handler).\n const newPos = {\n x: currentShape.x,\n y: currentShape.y,\n rx: currentShape.rx,\n ry: currentShape.ry,\n rotation: currentShape.rotation,\n parentFrame: isDraggingShapeCircle ? (hoveredFrameCircle || null) : currentShape.parentFrame,\n };\n const oldPos = {\n ...dragOldPosCircle,\n parentFrame: draggedShapeInitialFrameCircle\n };\n \n const stateChanged = oldPos.x !== newPos.x || oldPos.y !== newPos.y ||\n oldPos.rx !== newPos.rx || oldPos.ry !== newPos.ry || \n oldPos.rotation !== newPos.rotation;\n\n const frameChanged = oldPos.parentFrame !== newPos.parentFrame;\n\n if (stateChanged || frameChanged) {\n const oldPosForUndo = {\n x: oldPos.x,\n y: oldPos.y,\n rx: oldPos.rx,\n ry: oldPos.ry,\n rotation: oldPos.rotation,\n parentFrame: oldPos.parentFrame\n };\n const newPosForUndo = {\n x: newPos.x,\n y: newPos.y,\n rx: newPos.rx,\n ry: newPos.ry,\n rotation: newPos.rotation,\n parentFrame: newPos.parentFrame\n };\n pushTransformAction(currentShape, oldPosForUndo, newPosForUndo);\n }\n \n // Handle frame containment changes after drag\n if (isDraggingShapeCircle) {\n const finalFrame = hoveredFrameCircle;\n \n // If shape moved to a different frame\n if (draggedShapeInitialFrameCircle !== finalFrame) {\n // Remove from initial frame\n if (draggedShapeInitialFrameCircle) {\n draggedShapeInitialFrameCircle.removeShapeFromFrame(currentShape);\n }\n \n // Add to new frame\n if (finalFrame) {\n finalFrame.addShapeToFrame(currentShape);\n }\n \n // Track the frame change for undo\n if (frameChanged) {\n pushFrameAttachmentAction(finalFrame || draggedShapeInitialFrameCircle, currentShape, \n finalFrame ? 'attach' : 'detach', draggedShapeInitialFrameCircle);\n }\n } else if (draggedShapeInitialFrameCircle) {\n // Shape stayed in same frame, restore clipping\n draggedShapeInitialFrameCircle.restoreToFrame(currentShape);\n }\n }\n \n dragOldPosCircle = null;\n draggedShapeInitialFrameCircle = null;\n }\n \n // Clear frame highlighting\n if (hoveredFrameCircle) {\n hoveredFrameCircle.removeHighlight();\n hoveredFrameCircle = null;\n }\n\n clearSnapGuides();\n isDrawingCircle = false;\n isDraggingShapeCircle = false;\n isResizingShapeCircle = false;\n isRotatingShapeCircle = false;\n resizingAnchorIndexCircle = null;\n startRotationMouseAngleCircle = null;\n startShapeRotationCircle = 0;\n svg.style.cursor = 'default';\n}\n\n\ncolorOptionsCircle.forEach(span => {\n span.addEventListener('click', function(event) {\n event.stopPropagation();\n if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {\n const color = this.getAttribute('data-id');\n const oldOptions = {...currentShape.options};\n currentShape.options.stroke = color;\n currentShape.draw();\n currentShape.updateSidebar();\n pushOptionsChangeAction(currentShape, oldOptions);\n }\n else \n {\n circleStrokecolor = this.getAttribute('data-id');\n }\n colorOptionsCircle.forEach(span => {\n span.classList.remove('selected');\n });\n this.classList.add('selected');\n });\n});\nbackgroundColorOptionsCircle.forEach(span => {\n span.addEventListener('click', function(event) {\n event.stopPropagation();\n if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {\n const color = this.getAttribute('data-id');\n const oldOptions = {...currentShape.options};\n currentShape.options.fill = color;\n currentShape.draw();\n currentShape.updateSidebar();\n pushOptionsChangeAction(currentShape, oldOptions);\n }\n else \n {\n circleBackgroundColor = this.getAttribute('data-id');\n }\n backgroundColorOptionsCircle.forEach(span => {\n span.classList.remove('selected');\n });\n this.classList.add('selected');\n });\n});\nfillStyleOptionsCircle.forEach(span => {\n span.addEventListener('click', function(event) {\n event.stopPropagation();\n if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {\n const style = this.getAttribute('data-id');\n const oldOptions = {...currentShape.options};\n currentShape.options.fillStyle = style;\n currentShape.draw();\n currentShape.updateSidebar();\n pushOptionsChangeAction(currentShape, oldOptions);\n }\n else \n {\n circleFillStyleValue = this.getAttribute('data-id');\n }\n fillStyleOptionsCircle.forEach(span => {\n span.classList.remove('selected');\n });\n this.classList.add('selected');\n });\n});\nstrokeThicknessValueCircle.forEach(span => {\n span.addEventListener('click', function(event) {\n event.stopPropagation();\n if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {\n const thick = parseInt(this.getAttribute('data-id'), 10);\n const oldOptions = {...currentShape.options};\n currentShape.options.strokeWidth = thick;\n currentShape.draw();\n currentShape.updateSidebar();\n pushOptionsChangeAction(currentShape, oldOptions);\n }\n else \n {\n circleStrokeThicknes = parseInt(this.getAttribute('data-id'), 10);\n }\n strokeThicknessValueCircle.forEach(span => {\n span.classList.remove('selected');\n });\n this.classList.add('selected');\n });\n});\noutlineStyleValueCircle.forEach(span => {\n span.addEventListener('click', function(event) {\n event.stopPropagation();\n if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {\n const style = this.getAttribute('data-id');\n const oldOptions = {...currentShape.options};\n if (style === \"dashed\") {\n currentShape.options.strokeDasharray = \"5,5\";\n } else if (style === \"dotted\") {\n currentShape.options.strokeDasharray = \"2,8\";\n } else {\n currentShape.options.strokeDasharray = \"\";\n }\n currentShape.draw();\n currentShape.updateSidebar();\n pushOptionsChangeAction(currentShape, oldOptions);\n }\n else \n {\n circleOutlineStyle = this.getAttribute('data-id');\n }\n outlineStyleValueCircle.forEach(span => {\n span.classList.remove('selected');\n });\n this.classList.add('selected');\n });\n});\n\nwindow.Circle = Circle;\n\n// Bridge circle tool settings to React sidebar\nwindow.circleToolSettings = {\n get strokeColor() { return circleStrokecolor; },\n set strokeColor(v) { circleStrokecolor = v; },\n get bgColor() { return circleBackgroundColor; },\n set bgColor(v) { circleBackgroundColor = v; },\n get fillStyle() { return circleFillStyleValue; },\n set fillStyle(v) { circleFillStyleValue = v; },\n get strokeWidth() { return circleStrokeThicknes; },\n set strokeWidth(v) { circleStrokeThicknes = v; },\n get outlineStyle() { return circleOutlineStyle; },\n set outlineStyle(v) { circleOutlineStyle = v; },\n};\nwindow.updateSelectedCircleStyle = function(changes) {\n if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {\n pushOptionsChangeAction(currentShape, { ...currentShape.options });\n if (changes.stroke !== undefined) { circleStrokecolor = changes.stroke; currentShape.options.stroke = changes.stroke; }\n if (changes.fill !== undefined) { circleBackgroundColor = changes.fill; currentShape.options.fill = changes.fill; }\n if (changes.fillStyle !== undefined) { circleFillStyleValue = changes.fillStyle; currentShape.options.fillStyle = changes.fillStyle; }\n if (changes.strokeWidth !== undefined) { circleStrokeThicknes = changes.strokeWidth; currentShape.options.strokeWidth = changes.strokeWidth; }\n if (changes.outlineStyle !== undefined) {\n circleOutlineStyle = changes.outlineStyle;\n if (changes.outlineStyle === \"dashed\") currentShape.options.strokeDasharray = \"5,5\";\n else if (changes.outlineStyle === \"dotted\") currentShape.options.strokeDasharray = \"2,8\";\n else currentShape.options.strokeDasharray = \"\";\n }\n currentShape.draw();\n } else {\n if (changes.stroke !== undefined) circleStrokecolor = changes.stroke;\n if (changes.fill !== undefined) circleBackgroundColor = changes.fill;\n if (changes.fillStyle !== undefined) circleFillStyleValue = changes.fillStyle;\n if (changes.strokeWidth !== undefined) circleStrokeThicknes = changes.strokeWidth;\n if (changes.outlineStyle !== undefined) circleOutlineStyle = changes.outlineStyle;\n }\n};\n\nexport {\n handleMouseDown as handleMouseDownCircle,\n handleMouseMove as handleMouseMoveCircle,\n handleMouseUp as handleMouseUpCircle,\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["span"]
7
+ }