@elixpo/lixsketch 5.4.7 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/dist/react/AIRenderer-M4LMJ66J.js +1105 -0
  2. package/dist/react/AIRenderer-M4LMJ66J.js.map +7 -0
  3. package/dist/react/Arrow-BJDAXPMH.js +8 -0
  4. package/dist/react/Arrow-BJDAXPMH.js.map +7 -0
  5. package/dist/react/Circle-KPG7TKIX.js +8 -0
  6. package/dist/react/Circle-KPG7TKIX.js.map +7 -0
  7. package/dist/react/CodeShape-K4DIZAIV.js +8 -0
  8. package/dist/react/CodeShape-K4DIZAIV.js.map +7 -0
  9. package/dist/react/CopyPaste-4CKJRHJ3.js +569 -0
  10. package/dist/react/CopyPaste-4CKJRHJ3.js.map +7 -0
  11. package/dist/react/EraserTrail-PA6IQLQN.js +20 -0
  12. package/dist/react/EraserTrail-PA6IQLQN.js.map +7 -0
  13. package/dist/react/EventDispatcher-SRFH6LQZ.js +463 -0
  14. package/dist/react/EventDispatcher-SRFH6LQZ.js.map +7 -0
  15. package/dist/react/Frame-6UR5XPAX.js +10 -0
  16. package/dist/react/Frame-6UR5XPAX.js.map +7 -0
  17. package/dist/react/FreehandStroke-CK24NUT3.js +8 -0
  18. package/dist/react/FreehandStroke-CK24NUT3.js.map +7 -0
  19. package/dist/react/GraphEngine-QE5B2PMR.js +340 -0
  20. package/dist/react/GraphEngine-QE5B2PMR.js.map +7 -0
  21. package/dist/react/GraphMathParser-2WMTY4IE.js +10 -0
  22. package/dist/react/GraphMathParser-2WMTY4IE.js.map +7 -0
  23. package/dist/react/IconShape-KMIA6T2H.js +10 -0
  24. package/dist/react/IconShape-KMIA6T2H.js.map +7 -0
  25. package/dist/react/ImageShape-CHHGBXUQ.js +10 -0
  26. package/dist/react/ImageShape-CHHGBXUQ.js.map +7 -0
  27. package/dist/react/LayerOrder-XCHF4MSS.js +66 -0
  28. package/dist/react/LayerOrder-XCHF4MSS.js.map +7 -0
  29. package/dist/react/Line-2KOQEEGA.js +10 -0
  30. package/dist/react/Line-2KOQEEGA.js.map +7 -0
  31. package/dist/react/LixScriptParser-JYWJX375.js +1033 -0
  32. package/dist/react/LixScriptParser-JYWJX375.js.map +7 -0
  33. package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js +412 -0
  34. package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js.map +7 -0
  35. package/dist/react/MermaidSequenceParser-UKG2NSZY.js +8 -0
  36. package/dist/react/MermaidSequenceParser-UKG2NSZY.js.map +7 -0
  37. package/dist/react/MermaidSequenceRenderer-HPLHY5II.js +387 -0
  38. package/dist/react/MermaidSequenceRenderer-HPLHY5II.js.map +7 -0
  39. package/dist/react/Rectangle-6FE7RN6W.js +8 -0
  40. package/dist/react/Rectangle-6FE7RN6W.js.map +7 -0
  41. package/dist/react/ResizeCode-WAMDTKSW.js +2 -0
  42. package/dist/react/ResizeCode-WAMDTKSW.js.map +7 -0
  43. package/dist/react/ResizeShapes-LKEQTITP.js +250 -0
  44. package/dist/react/ResizeShapes-LKEQTITP.js.map +7 -0
  45. package/dist/react/SceneSerializer-4U4B24JM.js +739 -0
  46. package/dist/react/SceneSerializer-4U4B24JM.js.map +7 -0
  47. package/dist/react/Selection-VVUHY5YJ.js +34 -0
  48. package/dist/react/Selection-VVUHY5YJ.js.map +7 -0
  49. package/dist/react/SketchEngine-YA4RG3KX.js +413 -0
  50. package/dist/react/SketchEngine-YA4RG3KX.js.map +7 -0
  51. package/dist/react/TextShape-54ZJ66E3.js +8 -0
  52. package/dist/react/TextShape-54ZJ66E3.js.map +7 -0
  53. package/dist/react/UndoRedo-M2JZUBKN.js +30 -0
  54. package/dist/react/UndoRedo-M2JZUBKN.js.map +7 -0
  55. package/dist/react/ZoomPan-U3TXC5AJ.js +186 -0
  56. package/dist/react/ZoomPan-U3TXC5AJ.js.map +7 -0
  57. package/dist/react/arrowTool-CWEMIRXK.js +17 -0
  58. package/dist/react/arrowTool-CWEMIRXK.js.map +7 -0
  59. package/dist/react/boxicons-5JNJQPUP.woff +0 -0
  60. package/dist/react/boxicons-6NVWQSCQ.eot +0 -0
  61. package/dist/react/boxicons-AQ5N6WP7.woff2 +0 -0
  62. package/dist/react/boxicons-GDR4JU3X.ttf +0 -0
  63. package/dist/react/boxicons-NNFHLMOR.svg +1660 -0
  64. package/dist/react/chunk-2OQXI7QB.js +564 -0
  65. package/dist/react/chunk-2OQXI7QB.js.map +7 -0
  66. package/dist/react/chunk-5OUBTHHO.js +187 -0
  67. package/dist/react/chunk-5OUBTHHO.js.map +7 -0
  68. package/dist/react/chunk-6PFXZKL2.js +628 -0
  69. package/dist/react/chunk-6PFXZKL2.js.map +7 -0
  70. package/dist/react/chunk-6SFNWGGZ.js +453 -0
  71. package/dist/react/chunk-6SFNWGGZ.js.map +7 -0
  72. package/dist/react/chunk-7TZSIR6V.js +210 -0
  73. package/dist/react/chunk-7TZSIR6V.js.map +7 -0
  74. package/dist/react/chunk-AJAZC37E.js +662 -0
  75. package/dist/react/chunk-AJAZC37E.js.map +7 -0
  76. package/dist/react/chunk-BU4D2WYQ.js +1213 -0
  77. package/dist/react/chunk-BU4D2WYQ.js.map +7 -0
  78. package/dist/react/chunk-BZE4CEBG.js +747 -0
  79. package/dist/react/chunk-BZE4CEBG.js.map +7 -0
  80. package/dist/react/chunk-CB2RANCB.js +212 -0
  81. package/dist/react/chunk-CB2RANCB.js.map +7 -0
  82. package/dist/react/chunk-DNAG7ML6.js +128 -0
  83. package/dist/react/chunk-DNAG7ML6.js.map +7 -0
  84. package/dist/react/chunk-HZWLPXFN.js +198 -0
  85. package/dist/react/chunk-HZWLPXFN.js.map +7 -0
  86. package/dist/react/chunk-I6HCCIXB.js +572 -0
  87. package/dist/react/chunk-I6HCCIXB.js.map +7 -0
  88. package/dist/react/chunk-IZ5OGWGW.js +235 -0
  89. package/dist/react/chunk-IZ5OGWGW.js.map +7 -0
  90. package/dist/react/chunk-JJCJNLNN.js +1490 -0
  91. package/dist/react/chunk-JJCJNLNN.js.map +7 -0
  92. package/dist/react/chunk-JQ3IRFDP.js +222 -0
  93. package/dist/react/chunk-JQ3IRFDP.js.map +7 -0
  94. package/dist/react/chunk-L5OARZJ7.js +1134 -0
  95. package/dist/react/chunk-L5OARZJ7.js.map +7 -0
  96. package/dist/react/chunk-LHRTXNVE.js +1600 -0
  97. package/dist/react/chunk-LHRTXNVE.js.map +7 -0
  98. package/dist/react/chunk-Q2GA4MBZ.js +1653 -0
  99. package/dist/react/chunk-Q2GA4MBZ.js.map +7 -0
  100. package/dist/react/chunk-QNSE5BAY.js +519 -0
  101. package/dist/react/chunk-QNSE5BAY.js.map +7 -0
  102. package/dist/react/chunk-QXFBG7OM.js +191 -0
  103. package/dist/react/chunk-QXFBG7OM.js.map +7 -0
  104. package/dist/react/chunk-T6ZVV5ZO.js +714 -0
  105. package/dist/react/chunk-T6ZVV5ZO.js.map +7 -0
  106. package/dist/react/chunk-URB6MY46.js +974 -0
  107. package/dist/react/chunk-URB6MY46.js.map +7 -0
  108. package/dist/react/chunk-VN62KLOC.js +931 -0
  109. package/dist/react/chunk-VN62KLOC.js.map +7 -0
  110. package/dist/react/chunk-VQVEPJSA.js +158 -0
  111. package/dist/react/chunk-VQVEPJSA.js.map +7 -0
  112. package/dist/react/chunk-XISEAGBV.js +1632 -0
  113. package/dist/react/chunk-XISEAGBV.js.map +7 -0
  114. package/dist/react/chunk-YKJUBFHE.js +575 -0
  115. package/dist/react/chunk-YKJUBFHE.js.map +7 -0
  116. package/dist/react/circleTool-NUATSEI2.js +14 -0
  117. package/dist/react/circleTool-NUATSEI2.js.map +7 -0
  118. package/dist/react/codeTool-MHCB2FNB.js +38 -0
  119. package/dist/react/codeTool-MHCB2FNB.js.map +7 -0
  120. package/dist/react/eraserTool-2GS2LQCS.js +103 -0
  121. package/dist/react/eraserTool-2GS2LQCS.js.map +7 -0
  122. package/dist/react/frameTool-PWVKKXSP.js +14 -0
  123. package/dist/react/frameTool-PWVKKXSP.js.map +7 -0
  124. package/dist/react/freehandTool-SLYGASVP.js +14 -0
  125. package/dist/react/freehandTool-SLYGASVP.js.map +7 -0
  126. package/dist/react/iconTool-GPZ7O7NH.js +18 -0
  127. package/dist/react/iconTool-GPZ7O7NH.js.map +7 -0
  128. package/dist/react/imageTool-D5R4XGEU.js +15 -0
  129. package/dist/react/imageTool-D5R4XGEU.js.map +7 -0
  130. package/dist/react/index.js +5342 -0
  131. package/dist/react/index.js.map +7 -0
  132. package/dist/react/laserTool-XVMV63AV.js +239 -0
  133. package/dist/react/laserTool-XVMV63AV.js.map +7 -0
  134. package/dist/react/lineTool-WNI5EMZ5.js +14 -0
  135. package/dist/react/lineTool-WNI5EMZ5.js.map +7 -0
  136. package/dist/react/lixCode-OJMVUXXI.ttf +0 -0
  137. package/dist/react/lixDefault-JEAPAUJL.ttf +0 -0
  138. package/dist/react/lixFancy-BPXYM5CQ.ttf +0 -0
  139. package/dist/react/lixFont-CPKEUDVM.woff2 +0 -0
  140. package/dist/react/rectangleTool-U7DZ6ZTA.js +14 -0
  141. package/dist/react/rectangleTool-U7DZ6ZTA.js.map +7 -0
  142. package/dist/react/styles.css +6627 -0
  143. package/dist/react/textTool-M7S6F3VC.js +21 -0
  144. package/dist/react/textTool-M7S6F3VC.js.map +7 -0
  145. package/package.json +39 -5
  146. package/src/EngineShortcuts.js +83 -27
  147. package/src/core/AIRenderer.js +30 -18
  148. package/src/core/GraphEngine.js +64 -41
  149. package/src/core/MermaidFlowchartRenderer.js +153 -88
  150. package/src/core/MermaidSequenceRenderer.js +168 -93
  151. package/src/core/SceneSerializer.js +86 -2
  152. package/src/core/Selection.js +119 -19
  153. package/src/core/UndoRedo.js +82 -15
  154. package/src/core/ZoomPan.js +15 -5
  155. package/src/index.js +14 -1
  156. package/src/react/LixSketchCanvas.jsx +347 -0
  157. package/src/react/components/AppMenu.jsx +475 -0
  158. package/src/react/components/Footer.jsx +85 -0
  159. package/src/react/components/Toolbar.jsx +140 -0
  160. package/src/react/components/canvas/CanvasLoadingOverlay.jsx +76 -0
  161. package/src/react/components/canvas/ContextMenu.jsx +466 -0
  162. package/src/react/components/canvas/FindBar.jsx +177 -0
  163. package/src/react/components/canvas/ImageSourcePicker.jsx +133 -0
  164. package/src/react/components/canvas/MultiSelectActions.jsx +120 -0
  165. package/src/react/components/canvas/SVGCanvas.jsx +145 -0
  166. package/src/react/components/canvas/SaveStatusIndicator.jsx +29 -0
  167. package/src/react/components/modals/CanvasPropertiesModal.jsx +358 -0
  168. package/src/react/components/modals/CommandPalette.jsx +307 -0
  169. package/src/react/components/modals/ExportImageModal.jsx +287 -0
  170. package/src/react/components/modals/GraphModal.jsx +174 -0
  171. package/src/react/components/modals/HelpModal.jsx +208 -0
  172. package/src/react/components/modals/LixScriptModal.jsx +130 -0
  173. package/src/react/components/modals/ShortcutsModal.jsx +125 -0
  174. package/src/react/components/sidebars/ArrowSidebar.jsx +173 -0
  175. package/src/react/components/sidebars/CircleSidebar.jsx +134 -0
  176. package/src/react/components/sidebars/FrameSidebar.jsx +263 -0
  177. package/src/react/components/sidebars/IconSidebar.jsx +279 -0
  178. package/src/react/components/sidebars/ImageSidebar.jsx +69 -0
  179. package/src/react/components/sidebars/LineSidebar.jsx +109 -0
  180. package/src/react/components/sidebars/PaintbrushSidebar.jsx +119 -0
  181. package/src/react/components/sidebars/RectangleSidebar.jsx +165 -0
  182. package/src/react/components/sidebars/ShapeSidebar.jsx +130 -0
  183. package/src/react/components/sidebars/TextSidebar.jsx +174 -0
  184. package/src/react/hooks/inertStores.js +58 -0
  185. package/src/react/hooks/useSketchEngine.js +76 -0
  186. package/src/react/hooks/useTranslation.js +92 -0
  187. package/src/react/index.js +41 -0
  188. package/src/react/store/useSketchStore.js +234 -0
  189. package/src/react/store/useUIStore.js +196 -0
  190. package/src/react/styles/arrowSidebar.css +263 -0
  191. package/src/react/styles/canvasStroke.css +47 -0
  192. package/src/react/styles/canvasTools.css +769 -0
  193. package/src/react/styles/circleSidebar.css +206 -0
  194. package/src/react/styles/fonts/fonts.css +29 -0
  195. package/src/react/styles/fonts/lixCode.ttf +0 -0
  196. package/src/react/styles/fonts/lixDefault.ttf +0 -0
  197. package/src/react/styles/fonts/lixDocs.ttf +0 -0
  198. package/src/react/styles/fonts/lixFancy.ttf +0 -0
  199. package/src/react/styles/fonts/lixFont.woff2 +0 -0
  200. package/src/react/styles/lineSidebar.css +207 -0
  201. package/src/react/styles/paintbrushSidebar.css +247 -0
  202. package/src/react/styles/squareSidebar.css +206 -0
  203. package/src/react/styles/writeText.css +149 -0
  204. package/src/react/styles.css +175 -0
  205. package/src/react/toolsEnum.js +20 -0
  206. package/src/react/utils/toast.js +18 -0
  207. package/src/shapes/Frame.js +7 -1
  208. package/src/shapes/Line.js +11 -5
  209. package/src/tools/arrowTool.js +30 -4
  210. package/src/tools/circleTool.js +33 -9
  211. package/src/tools/codeTool.js +5 -3
  212. package/src/tools/frameTool.js +47 -7
  213. package/src/tools/freehandTool.js +12 -4
  214. package/src/tools/iconTool.js +7 -1
  215. package/src/tools/imageTool.js +7 -1
  216. package/src/tools/lineTool.js +27 -3
  217. package/src/tools/rectangleTool.js +45 -8
  218. package/src/tools/textTool.js +23 -6
@@ -0,0 +1,1490 @@
1
+ "use client";
2
+ import {
3
+ applySyntaxHighlightingToSVG,
4
+ createHighlightedSVGText,
5
+ deselectCodeBlock,
6
+ extractTextFromCodeElement,
7
+ getCodeLanguage,
8
+ getSelectedCodeBlock,
9
+ selectCodeBlock,
10
+ setCodeLanguage,
11
+ updateCodeBackground,
12
+ wrapCodeElement
13
+ } from "./chunk-LHRTXNVE.js";
14
+ import {
15
+ cleanupAttachments,
16
+ updateAttachedArrows
17
+ } from "./chunk-BZE4CEBG.js";
18
+ import {
19
+ pushCreateAction,
20
+ pushDeleteActionWithAttachments,
21
+ pushFrameAttachmentAction,
22
+ pushOptionsChangeAction,
23
+ pushTransformAction,
24
+ setTextReferences,
25
+ updateSelectedElement
26
+ } from "./chunk-L5OARZJ7.js";
27
+
28
+ // src/tools/textTool.js
29
+ function getThemeStroke() {
30
+ if (typeof document === "undefined") return "#fff";
31
+ return document.body && document.body.classList.contains("theme-dark") ? "#fff" : "#1a1a2e";
32
+ }
33
+ var textSize = "30px";
34
+ var textFont = "lixFont";
35
+ var textColor = null;
36
+ var textAlign = "left";
37
+ var textColorOptions = document.querySelectorAll(".textColorSpan");
38
+ var textFontOptions = document.querySelectorAll(".textFontSpan");
39
+ var textSizeOptions = document.querySelectorAll(".textSizeSpan");
40
+ var textAlignOptions = document.querySelectorAll(".textAlignSpan");
41
+ var selectedElement = null;
42
+ var selectionBox = null;
43
+ var resizeHandles = {};
44
+ var dragOffsetX;
45
+ var dragOffsetY;
46
+ var isDragging = false;
47
+ var isResizing = false;
48
+ var currentResizeHandle = null;
49
+ var startBBox = null;
50
+ var startFontSize = null;
51
+ var startPoint = null;
52
+ var isRotating = false;
53
+ var rotationStartAngle = 0;
54
+ var rotationStartTransform = null;
55
+ var initialHandlePosRelGroup = null;
56
+ var initialGroupTx = 0;
57
+ var initialGroupTy = 0;
58
+ var initialInverseScreenCTM = null;
59
+ var draggedShapeInitialFrameText = null;
60
+ var hoveredFrameText = null;
61
+ setTextReferences(selectedElement, updateSelectionFeedback, svg);
62
+ function switchToSelectionTool() {
63
+ if (window.__sketchStoreApi) {
64
+ window.__sketchStoreApi.setActiveTool("select", { afterDraw: true });
65
+ } else {
66
+ window.isSelectionToolActive = true;
67
+ }
68
+ }
69
+ function wrapTextElement(groupElement) {
70
+ const textShape = new TextShape(groupElement);
71
+ return textShape;
72
+ }
73
+ function getSVGCoordinates(event, element = svg) {
74
+ if (!svg || !svg.createSVGPoint) {
75
+ console.error("SVG element or createSVGPoint method not available.");
76
+ return { x: 0, y: 0 };
77
+ }
78
+ let pt = svg.createSVGPoint();
79
+ pt.x = event.clientX;
80
+ pt.y = event.clientY;
81
+ try {
82
+ let screenCTM = element && typeof element.getScreenCTM === "function" && element.getScreenCTM() || svg.getScreenCTM();
83
+ if (!screenCTM) {
84
+ console.error("Could not get Screen CTM.");
85
+ return { x: event.clientX, y: event.clientY };
86
+ }
87
+ let svgPoint = pt.matrixTransform(screenCTM.inverse());
88
+ return {
89
+ x: svgPoint.x,
90
+ y: svgPoint.y
91
+ };
92
+ } catch (error) {
93
+ console.error("Error getting SVG coordinates:", error);
94
+ return { x: event.clientX, y: event.clientY };
95
+ }
96
+ }
97
+ function addText(event) {
98
+ let { x, y } = getSVGCoordinates(event);
99
+ let gElement = document.createElementNS("http://www.w3.org/2000/svg", "g");
100
+ gElement.setAttribute("data-type", "text-group");
101
+ gElement.setAttribute("transform", `translate(${x}, ${y})`);
102
+ let textElement = document.createElementNS(
103
+ "http://www.w3.org/2000/svg",
104
+ "text"
105
+ );
106
+ let textAlignElement = "start";
107
+ if (textAlign === "center") textAlignElement = "middle";
108
+ else if (textAlign === "right") textAlignElement = "end";
109
+ textElement.setAttribute("x", 0);
110
+ textElement.setAttribute("y", 0);
111
+ textElement.setAttribute("fill", textColor ?? getThemeStroke());
112
+ textElement.setAttribute("font-size", textSize);
113
+ textElement.setAttribute("font-family", textFont);
114
+ textElement.setAttribute("text-anchor", textAlignElement);
115
+ textElement.setAttribute("cursor", "default");
116
+ textElement.setAttribute("white-space", "pre");
117
+ textElement.setAttribute("dominant-baseline", "hanging");
118
+ textElement.setAttribute("pointer-events", "bounding-box");
119
+ textElement.textContent = "";
120
+ gElement.setAttribute("data-x", x);
121
+ gElement.setAttribute("data-y", y);
122
+ textElement.setAttribute("data-initial-size", textSize);
123
+ textElement.setAttribute("data-initial-font", textFont);
124
+ textElement.setAttribute("data-initial-color", textColor ?? getThemeStroke());
125
+ textElement.setAttribute("data-initial-align", textAlign);
126
+ textElement.setAttribute("data-type", "text");
127
+ gElement.appendChild(textElement);
128
+ svg.appendChild(gElement);
129
+ const shapeID = `text-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 1e4)}`;
130
+ gElement.setAttribute("id", shapeID);
131
+ textElement.setAttribute("id", `${shapeID}-text`);
132
+ const textShape = wrapTextElement(gElement);
133
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
134
+ shapes.push(textShape);
135
+ }
136
+ pushCreateAction({
137
+ type: "text",
138
+ element: textShape,
139
+ shapeName: "text"
140
+ });
141
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
142
+ shapes.forEach((shape) => {
143
+ if (shape.shapeName === "frame" && shape.isShapeInFrame(textShape)) {
144
+ shape.addShapeToFrame(textShape);
145
+ }
146
+ });
147
+ }
148
+ makeTextEditable(textElement, gElement);
149
+ }
150
+ function makeTextEditable(textElement, groupElement) {
151
+ if (document.querySelector("textarea.svg-text-editor")) {
152
+ return;
153
+ }
154
+ if (selectedElement) {
155
+ deselectElement();
156
+ }
157
+ let input = document.createElement("textarea");
158
+ input.className = "svg-text-editor";
159
+ let textContent = "";
160
+ const tspans = textElement.querySelectorAll("tspan");
161
+ if (tspans.length > 0) {
162
+ tspans.forEach((tspan, index) => {
163
+ textContent += tspan.textContent.replace(/ /g, "\xA0");
164
+ if (index < tspans.length - 1) {
165
+ textContent += "\n";
166
+ }
167
+ });
168
+ } else {
169
+ textContent = textElement.textContent.replace(/ /g, "\xA0");
170
+ }
171
+ input.value = textContent;
172
+ input.style.position = "absolute";
173
+ input.style.outline = "none";
174
+ input.style.padding = "1px";
175
+ input.style.margin = "0";
176
+ input.style.boxSizing = "border-box";
177
+ input.style.overflow = "hidden";
178
+ input.style.resize = "none";
179
+ input.style.whiteSpace = "pre-wrap";
180
+ input.style.minHeight = "1.2em";
181
+ input.style.zIndex = "10000";
182
+ const svgRect = svg.getBoundingClientRect();
183
+ const textBBox = textElement.getBBox();
184
+ let pt = svg.createSVGPoint();
185
+ pt.x = textBBox.x;
186
+ pt.y = textBBox.y;
187
+ const groupCTM = groupElement.getScreenCTM() || svg.getScreenCTM();
188
+ let screenPt = pt.matrixTransform(groupCTM);
189
+ input.style.left = `${screenPt.x}px`;
190
+ input.style.top = `${screenPt.y}px`;
191
+ const svgZoomFactor = svg.getScreenCTM() ? svg.getScreenCTM().a : 1;
192
+ const screenWidth = textBBox.width * svgZoomFactor;
193
+ input.style.width = "auto";
194
+ input.style.height = "auto";
195
+ const currentFontSize = textElement.getAttribute("font-size") || "30px";
196
+ const currentFontFamily = textElement.getAttribute("font-family") || "lixFont";
197
+ const currentFill = textElement.getAttribute("fill") || "#fff";
198
+ const currentAnchor = textElement.getAttribute("text-anchor") || "start";
199
+ const rawSize = parseFloat(currentFontSize) || 30;
200
+ const scaledFontSize = `${rawSize * svgZoomFactor}px`;
201
+ input.style.minWidth = "150px";
202
+ input.style.minHeight = "1.5em";
203
+ input.style.width = "auto";
204
+ input.style.height = "auto";
205
+ input.style.overflow = "visible";
206
+ input.style.whiteSpace = "pre-wrap";
207
+ input.style.wordBreak = "break-word";
208
+ input.style.fontSize = scaledFontSize;
209
+ input.style.fontFamily = currentFontFamily;
210
+ input.style.color = currentFill;
211
+ input.style.lineHeight = "1.2em";
212
+ input.style.textAlign = currentAnchor === "middle" ? "center" : currentAnchor === "end" ? "right" : "left";
213
+ input.style.backgroundColor = "transparent";
214
+ input.style.border = "1px dashed rgba(255,255,255,0.55)";
215
+ input.style.borderRadius = "3px";
216
+ input.style.outline = "none";
217
+ document.body.appendChild(input);
218
+ const adjustHeight = () => {
219
+ input.style.height = "auto";
220
+ input.style.height = input.scrollHeight + "px";
221
+ const maxHeight = svgRect.height - screenPt.y;
222
+ if (input.scrollHeight > maxHeight) {
223
+ input.style.height = maxHeight + "px";
224
+ input.style.overflowY = "auto";
225
+ } else {
226
+ input.style.overflowY = "hidden";
227
+ }
228
+ };
229
+ const adjustWidth = () => {
230
+ input.style.width = "auto";
231
+ const maxWidth = svgRect.width - screenPt.x;
232
+ const contentWidth = Math.max(input.scrollWidth, 150);
233
+ if (contentWidth > maxWidth) {
234
+ input.style.width = maxWidth + "px";
235
+ input.style.overflowX = "auto";
236
+ } else {
237
+ input.style.width = contentWidth + "px";
238
+ input.style.overflowX = "hidden";
239
+ }
240
+ };
241
+ adjustHeight();
242
+ adjustWidth();
243
+ setTimeout(() => {
244
+ input.focus();
245
+ input.select();
246
+ }, 50);
247
+ input.addEventListener("input", adjustHeight);
248
+ input.addEventListener("input", adjustWidth);
249
+ input.addEventListener("keydown", function(e) {
250
+ if (e.key === "Enter" && !e.shiftKey) {
251
+ e.preventDefault();
252
+ renderText(input, textElement, true);
253
+ } else if (e.key === "Escape") {
254
+ e.preventDefault();
255
+ renderText(input, textElement, true);
256
+ }
257
+ });
258
+ input.originalTextElement = textElement;
259
+ input.textGroup = groupElement;
260
+ const handleClickOutside = (event) => {
261
+ if (!input.contains(event.target)) {
262
+ renderText(input, textElement, true);
263
+ document.removeEventListener("pointerdown", handleClickOutside, true);
264
+ }
265
+ };
266
+ document.addEventListener("pointerdown", handleClickOutside, true);
267
+ input.handleClickOutside = handleClickOutside;
268
+ const textEl = groupElement.querySelector("text");
269
+ if (textEl) textEl.setAttribute("cursor", "text");
270
+ groupElement.style.display = "none";
271
+ }
272
+ function renderText(input, textElement, deleteIfEmpty = false) {
273
+ if (!input || !document.body.contains(input)) {
274
+ return;
275
+ }
276
+ const text = input.value || "";
277
+ const gElement = input.textGroup;
278
+ if (input.handleClickOutside) {
279
+ document.removeEventListener("pointerdown", input.handleClickOutside, true);
280
+ }
281
+ document.body.removeChild(input);
282
+ if (textElement) textElement.setAttribute("cursor", "default");
283
+ if (!gElement || !textElement) {
284
+ return;
285
+ }
286
+ if (!gElement.parentNode) {
287
+ if (selectedElement === gElement) {
288
+ deselectElement();
289
+ }
290
+ return;
291
+ }
292
+ if (deleteIfEmpty && text.trim() === "") {
293
+ let textShape = null;
294
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
295
+ textShape = shapes.find((shape) => shape.shapeName === "text" && shape.group === gElement);
296
+ if (textShape) {
297
+ const idx = shapes.indexOf(textShape);
298
+ if (idx !== -1) shapes.splice(idx, 1);
299
+ }
300
+ }
301
+ pushDeleteActionWithAttachments({
302
+ type: "text",
303
+ element: textShape || gElement,
304
+ shapeName: "text"
305
+ });
306
+ if (typeof cleanupAttachments === "function") {
307
+ cleanupAttachments(gElement);
308
+ }
309
+ svg.removeChild(gElement);
310
+ if (selectedElement === gElement) {
311
+ selectedElement = null;
312
+ removeSelectionFeedback();
313
+ }
314
+ } else {
315
+ while (textElement.firstChild) {
316
+ textElement.removeChild(textElement.firstChild);
317
+ }
318
+ const lines = text.split("\n");
319
+ const x = textElement.getAttribute("x") || 0;
320
+ lines.forEach((line, index) => {
321
+ let tspan = document.createElementNS(
322
+ "http://www.w3.org/2000/svg",
323
+ "tspan"
324
+ );
325
+ tspan.setAttribute("x", x);
326
+ tspan.setAttribute("dy", index === 0 ? "0" : "1.2em");
327
+ tspan.textContent = line.replace(/\u00A0/g, " ") || " ";
328
+ textElement.appendChild(tspan);
329
+ });
330
+ gElement.style.display = "block";
331
+ updateAttachedArrows(gElement);
332
+ if (selectedElement === gElement) {
333
+ setTimeout(updateSelectionFeedback, 0);
334
+ }
335
+ }
336
+ if (gElement.parentNode) {
337
+ switchToSelectionTool();
338
+ requestAnimationFrame(() => selectElement(gElement));
339
+ }
340
+ }
341
+ function createSelectionFeedback(groupElement) {
342
+ if (!groupElement) return;
343
+ removeSelectionFeedback();
344
+ const textElement = groupElement.querySelector("text");
345
+ if (!textElement) {
346
+ return;
347
+ }
348
+ const bbox = textElement.getBBox();
349
+ const zoom = window.currentZoom || 1;
350
+ const padding = 8 / zoom;
351
+ const handleSize = 10 / zoom;
352
+ const handleOffset = handleSize / 2;
353
+ const anchorStrokeWidth = 2;
354
+ const selX = bbox.x - padding;
355
+ const selY = bbox.y - padding;
356
+ const selWidth = bbox.width + 2 * padding;
357
+ const selHeight = bbox.height + 2 * padding;
358
+ const outlinePoints = [
359
+ [selX, selY],
360
+ [selX + selWidth, selY],
361
+ [selX + selWidth, selY + selHeight],
362
+ [selX, selY + selHeight],
363
+ [selX, selY]
364
+ ];
365
+ const pointsAttr = outlinePoints.map((p) => p.join(",")).join(" ");
366
+ selectionBox = document.createElementNS("http://www.w3.org/2000/svg", "polyline");
367
+ selectionBox.setAttribute("class", "selection-box");
368
+ selectionBox.setAttribute("points", pointsAttr);
369
+ selectionBox.setAttribute("fill", "none");
370
+ selectionBox.setAttribute("stroke", "#5B57D1");
371
+ selectionBox.setAttribute("stroke-width", "1.5");
372
+ selectionBox.setAttribute("stroke-dasharray", `${4 / zoom} ${2 / zoom}`);
373
+ selectionBox.setAttribute("vector-effect", "non-scaling-stroke");
374
+ selectionBox.setAttribute("pointer-events", "none");
375
+ groupElement.appendChild(selectionBox);
376
+ const handlesData = [
377
+ { name: "nw", x: selX, y: selY, cursor: "nwse-resize" },
378
+ { name: "ne", x: selX + selWidth, y: selY, cursor: "nesw-resize" },
379
+ { name: "sw", x: selX, y: selY + selHeight, cursor: "nesw-resize" },
380
+ { name: "se", x: selX + selWidth, y: selY + selHeight, cursor: "nwse-resize" }
381
+ ];
382
+ resizeHandles = {};
383
+ handlesData.forEach((handle) => {
384
+ const handleRect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
385
+ handleRect.setAttribute("class", `resize-handle resize-handle-${handle.name}`);
386
+ handleRect.setAttribute("x", handle.x - handleOffset);
387
+ handleRect.setAttribute("y", handle.y - handleOffset);
388
+ handleRect.setAttribute("width", handleSize);
389
+ handleRect.setAttribute("height", handleSize);
390
+ handleRect.setAttribute("fill", "#121212");
391
+ handleRect.setAttribute("stroke", "#5B57D1");
392
+ handleRect.setAttribute("stroke-width", anchorStrokeWidth);
393
+ handleRect.setAttribute("vector-effect", "non-scaling-stroke");
394
+ handleRect.style.cursor = handle.cursor;
395
+ handleRect.setAttribute("data-anchor", handle.name);
396
+ groupElement.appendChild(handleRect);
397
+ resizeHandles[handle.name] = handleRect;
398
+ handleRect.addEventListener("pointerdown", (e) => {
399
+ if (window.isSelectionToolActive) {
400
+ e.stopPropagation();
401
+ startResize(e, handle.name);
402
+ }
403
+ });
404
+ });
405
+ const rotationAnchorPos = { x: selX + selWidth / 2, y: selY - 30 };
406
+ const rotationAnchor = document.createElementNS("http://www.w3.org/2000/svg", "circle");
407
+ rotationAnchor.setAttribute("cx", rotationAnchorPos.x);
408
+ rotationAnchor.setAttribute("cy", rotationAnchorPos.y);
409
+ rotationAnchor.setAttribute("r", 8);
410
+ rotationAnchor.setAttribute("class", "rotate-anchor");
411
+ rotationAnchor.setAttribute("fill", "#121212");
412
+ rotationAnchor.setAttribute("stroke", "#5B57D1");
413
+ rotationAnchor.setAttribute("stroke-width", anchorStrokeWidth);
414
+ rotationAnchor.setAttribute("vector-effect", "non-scaling-stroke");
415
+ rotationAnchor.style.cursor = "grab";
416
+ rotationAnchor.setAttribute("pointer-events", "all");
417
+ groupElement.appendChild(rotationAnchor);
418
+ resizeHandles.rotate = rotationAnchor;
419
+ rotationAnchor.addEventListener("pointerdown", (e) => {
420
+ if (window.isSelectionToolActive) {
421
+ e.stopPropagation();
422
+ startRotation(e);
423
+ }
424
+ });
425
+ rotationAnchor.addEventListener("mouseover", function() {
426
+ if (!isResizing && !isDragging) {
427
+ this.style.cursor = "grab";
428
+ }
429
+ });
430
+ rotationAnchor.addEventListener("mouseout", function() {
431
+ if (!isResizing && !isDragging) {
432
+ this.style.cursor = "default";
433
+ }
434
+ });
435
+ }
436
+ function updateSelectionFeedback() {
437
+ if (!selectedElement || !selectionBox) return;
438
+ const textElement = selectedElement.querySelector("text");
439
+ if (!textElement) return;
440
+ const wasHidden = selectedElement.style.display === "none";
441
+ if (wasHidden) selectedElement.style.display = "block";
442
+ const bbox = textElement.getBBox();
443
+ if (wasHidden) selectedElement.style.display = "none";
444
+ if (bbox.width === 0 && bbox.height === 0 && textElement.textContent.trim() !== "") {
445
+ }
446
+ const zoom2 = window.currentZoom || 1;
447
+ const padding = 8 / zoom2;
448
+ const handleSize = 10 / zoom2;
449
+ const handleOffset = handleSize / 2;
450
+ const selX = bbox.x - padding;
451
+ const selY = bbox.y - padding;
452
+ const selWidth = Math.max(bbox.width + 2 * padding, handleSize);
453
+ const selHeight = Math.max(bbox.height + 2 * padding, handleSize);
454
+ const outlinePoints = [
455
+ [selX, selY],
456
+ [selX + selWidth, selY],
457
+ [selX + selWidth, selY + selHeight],
458
+ [selX, selY + selHeight],
459
+ [selX, selY]
460
+ ];
461
+ const pointsAttr = outlinePoints.map((p) => p.join(",")).join(" ");
462
+ selectionBox.setAttribute("points", pointsAttr);
463
+ const handlesData = [
464
+ { name: "nw", x: selX, y: selY },
465
+ { name: "ne", x: selX + selWidth, y: selY },
466
+ { name: "sw", x: selX, y: selY + selHeight },
467
+ { name: "se", x: selX + selWidth, y: selY + selHeight }
468
+ ];
469
+ handlesData.forEach((handle) => {
470
+ const handleRect = resizeHandles[handle.name];
471
+ if (handleRect) {
472
+ handleRect.setAttribute("x", handle.x - handleOffset);
473
+ handleRect.setAttribute("y", handle.y - handleOffset);
474
+ }
475
+ });
476
+ const rotationAnchor = resizeHandles.rotate;
477
+ if (rotationAnchor) {
478
+ const rotationAnchorPos = { x: selX + selWidth / 2, y: selY - 30 };
479
+ rotationAnchor.setAttribute("cx", rotationAnchorPos.x);
480
+ rotationAnchor.setAttribute("cy", rotationAnchorPos.y);
481
+ }
482
+ }
483
+ function startRotation(event) {
484
+ if (!selectedElement || event.button !== 0) return;
485
+ event.preventDefault();
486
+ event.stopPropagation();
487
+ isRotating = true;
488
+ isDragging = false;
489
+ isResizing = false;
490
+ const textElement = selectedElement.querySelector("text");
491
+ if (!textElement) return;
492
+ const bbox = textElement.getBBox();
493
+ const centerX = bbox.x + bbox.width / 2;
494
+ const centerY = bbox.y + bbox.height / 2;
495
+ const mousePos = getSVGCoordinates(event);
496
+ let centerPoint = svg.createSVGPoint();
497
+ centerPoint.x = centerX;
498
+ centerPoint.y = centerY;
499
+ const groupTransform = selectedElement.transform.baseVal.consolidate();
500
+ if (groupTransform) {
501
+ centerPoint = centerPoint.matrixTransform(groupTransform.matrix);
502
+ }
503
+ rotationStartAngle = Math.atan2(mousePos.y - centerPoint.y, mousePos.x - centerPoint.x) * 180 / Math.PI;
504
+ const currentTransform = selectedElement.transform.baseVal.consolidate();
505
+ rotationStartTransform = currentTransform ? currentTransform.matrix : svg.createSVGMatrix();
506
+ svg.style.cursor = "grabbing";
507
+ window.addEventListener("pointermove", handleMouseMove);
508
+ window.addEventListener("pointerup", handleMouseUp);
509
+ }
510
+ function removeSelectionFeedback(element) {
511
+ const target = element || selectedElement;
512
+ if (target) {
513
+ target.querySelectorAll(".selection-box, .resize-handle, .rotate-anchor").forEach((el) => el.remove());
514
+ }
515
+ svg.querySelectorAll('g[data-type="text-group"] .selection-box, g[data-type="text-group"] .resize-handle, g[data-type="text-group"] .rotate-anchor').forEach((el) => el.remove());
516
+ selectionBox = null;
517
+ resizeHandles = {};
518
+ }
519
+ function selectElement(groupElement) {
520
+ if (!groupElement || !groupElement.parentNode) return;
521
+ if (groupElement === selectedElement) return;
522
+ deselectElement();
523
+ selectedElement = groupElement;
524
+ selectedElement.classList.add("selected");
525
+ createSelectionFeedback(selectedElement);
526
+ updateSelectedElement(selectedElement);
527
+ updateCodeToggleForShape("text");
528
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
529
+ const wrapper = shapes.find((s) => s.element === groupElement || s.group === groupElement);
530
+ if (wrapper) {
531
+ currentShape = wrapper;
532
+ }
533
+ }
534
+ if (window.__showSidebarForShape) window.__showSidebarForShape("text");
535
+ }
536
+ function deselectElement() {
537
+ const activeEditor = document.querySelector("textarea.svg-text-editor");
538
+ if (activeEditor) {
539
+ let textElement = activeEditor.originalTextElement;
540
+ if (textElement) {
541
+ renderText(activeEditor, textElement, true);
542
+ } else if (document.body.contains(activeEditor)) {
543
+ document.body.removeChild(activeEditor);
544
+ }
545
+ }
546
+ if (selectedElement) {
547
+ removeSelectionFeedback();
548
+ selectedElement.classList.remove("selected");
549
+ selectedElement = null;
550
+ updateSelectedElement(null);
551
+ if (currentShape && (currentShape.shapeName === "text" || currentShape.shapeName === "code")) {
552
+ currentShape = null;
553
+ }
554
+ if (isSelectionToolActive) {
555
+ textSideBar.classList.add("hidden");
556
+ }
557
+ }
558
+ if (isRotating) {
559
+ isRotating = false;
560
+ rotationStartAngle = 0;
561
+ rotationStartTransform = null;
562
+ svg.style.cursor = "default";
563
+ window.removeEventListener("pointermove", handleMouseMove);
564
+ window.removeEventListener("pointerup", handleMouseUp);
565
+ }
566
+ }
567
+ function startDrag(event) {
568
+ if (!selectedElement || event.button !== 0) return;
569
+ if (event.target.closest(".resize-handle")) {
570
+ return;
571
+ }
572
+ isDragging = true;
573
+ isResizing = false;
574
+ event.preventDefault();
575
+ const currentTransform = selectedElement.transform.baseVal.consolidate();
576
+ const initialTranslateX = currentTransform ? currentTransform.matrix.e : 0;
577
+ const initialTranslateY = currentTransform ? currentTransform.matrix.f : 0;
578
+ startPoint = getSVGCoordinates(event);
579
+ dragOffsetX = startPoint.x - initialTranslateX;
580
+ dragOffsetY = startPoint.y - initialTranslateY;
581
+ let textShape = null;
582
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
583
+ textShape = shapes.find((shape) => shape.shapeName === "text" && shape.group === selectedElement);
584
+ }
585
+ if (textShape) {
586
+ draggedShapeInitialFrameText = textShape.parentFrame || null;
587
+ if (textShape.parentFrame) {
588
+ textShape.parentFrame.temporarilyRemoveFromFrame(textShape);
589
+ }
590
+ }
591
+ svg.style.cursor = "grabbing";
592
+ svg.addEventListener("pointermove", handleMouseMove);
593
+ svg.addEventListener("pointerup", handleMouseUp);
594
+ }
595
+ function startResize(event, anchor) {
596
+ if (!selectedElement || event.button !== 0) return;
597
+ event.preventDefault();
598
+ event.stopPropagation();
599
+ isResizing = true;
600
+ isDragging = false;
601
+ currentResizeHandle = anchor;
602
+ const textElement = selectedElement.querySelector("text");
603
+ if (!textElement) {
604
+ isResizing = false;
605
+ return;
606
+ }
607
+ startBBox = textElement.getBBox();
608
+ startFontSize = parseFloat(textElement.getAttribute("font-size") || 30);
609
+ if (isNaN(startFontSize)) startFontSize = 30;
610
+ startPoint = getSVGCoordinates(event, selectedElement);
611
+ const groupScreenCTM = selectedElement.getScreenCTM();
612
+ initialInverseScreenCTM = groupScreenCTM ? groupScreenCTM.inverse() : null;
613
+ const currentTransform = selectedElement.transform.baseVal.consolidate();
614
+ initialGroupTx = currentTransform ? currentTransform.matrix.e : 0;
615
+ initialGroupTy = currentTransform ? currentTransform.matrix.f : 0;
616
+ const padding = 3;
617
+ const startX = startBBox.x - padding;
618
+ const startY = startBBox.y - padding;
619
+ const startWidth = startBBox.width + 2 * padding;
620
+ const startHeight = startBBox.height + 2 * padding;
621
+ let hx = startX;
622
+ let hy = startY;
623
+ if (anchor.includes("e")) {
624
+ hx = startX + startWidth;
625
+ }
626
+ if (anchor.includes("s")) {
627
+ hy = startY + startHeight;
628
+ }
629
+ initialHandlePosRelGroup = { x: hx, y: hy };
630
+ svg.style.cursor = resizeHandles[anchor]?.style.cursor || "default";
631
+ svg.addEventListener("pointermove", handleMouseMove);
632
+ svg.addEventListener("pointerup", handleMouseUp);
633
+ }
634
+ var handleMouseMove = (event) => {
635
+ if (!selectedElement) return;
636
+ event.preventDefault();
637
+ const svgRect = svg.getBoundingClientRect();
638
+ lastMousePos = {
639
+ x: event.clientX - svgRect.left,
640
+ y: event.clientY - svgRect.top
641
+ };
642
+ if (isDragging) {
643
+ const currentPoint = getSVGCoordinates(event);
644
+ const newTranslateX = currentPoint.x - dragOffsetX;
645
+ const newTranslateY = currentPoint.y - dragOffsetY;
646
+ const currentTransform = selectedElement.transform.baseVal.consolidate();
647
+ if (currentTransform) {
648
+ const matrix = currentTransform.matrix;
649
+ const angle = Math.atan2(matrix.b, matrix.a) * 180 / Math.PI;
650
+ const textElement = selectedElement.querySelector("text");
651
+ if (textElement) {
652
+ const bbox = textElement.getBBox();
653
+ const centerX = bbox.x + bbox.width / 2;
654
+ const centerY = bbox.y + bbox.height / 2;
655
+ selectedElement.setAttribute(
656
+ "transform",
657
+ `translate(${newTranslateX}, ${newTranslateY}) rotate(${angle}, ${centerX}, ${centerY})`
658
+ );
659
+ } else {
660
+ selectedElement.setAttribute("transform", `translate(${newTranslateX}, ${newTranslateY})`);
661
+ }
662
+ } else {
663
+ selectedElement.setAttribute("transform", `translate(${newTranslateX}, ${newTranslateY})`);
664
+ }
665
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
666
+ const textShape = shapes.find((shape) => shape.shapeName === "text" && shape.group === selectedElement);
667
+ if (textShape) {
668
+ textShape.updateFrameContainment();
669
+ }
670
+ }
671
+ updateAttachedArrows(selectedElement);
672
+ } else if (isResizing) {
673
+ const textElement = selectedElement.querySelector("text");
674
+ if (!textElement || !startBBox || startFontSize === null || !startPoint || !initialHandlePosRelGroup) return;
675
+ let currentPoint;
676
+ if (initialInverseScreenCTM) {
677
+ const pt = svg.createSVGPoint();
678
+ pt.x = event.clientX;
679
+ pt.y = event.clientY;
680
+ currentPoint = pt.matrixTransform(initialInverseScreenCTM);
681
+ } else {
682
+ currentPoint = getSVGCoordinates(event, selectedElement);
683
+ }
684
+ const startX = startBBox.x;
685
+ const startY = startBBox.y;
686
+ const startWidth = startBBox.width;
687
+ const startHeight = startBBox.height;
688
+ let anchorX, anchorY;
689
+ switch (currentResizeHandle) {
690
+ case "nw":
691
+ anchorX = startX + startWidth;
692
+ anchorY = startY + startHeight;
693
+ break;
694
+ case "ne":
695
+ anchorX = startX;
696
+ anchorY = startY + startHeight;
697
+ break;
698
+ case "sw":
699
+ anchorX = startX + startWidth;
700
+ anchorY = startY;
701
+ break;
702
+ case "se":
703
+ anchorX = startX;
704
+ anchorY = startY;
705
+ break;
706
+ }
707
+ const newWidth = Math.abs(currentPoint.x - anchorX);
708
+ const newHeight = Math.abs(currentPoint.y - anchorY);
709
+ const chosenScale = newHeight / startHeight;
710
+ const minScale = 0.1;
711
+ const maxScale = 10;
712
+ const clampedScale = Math.max(minScale, Math.min(chosenScale, maxScale));
713
+ const newFontSize = startFontSize * clampedScale;
714
+ const minFontSize = 5;
715
+ const finalFontSize = Math.max(newFontSize, minFontSize);
716
+ textElement.setAttribute("font-size", `${finalFontSize}px`);
717
+ const currentBBox = textElement.getBBox();
718
+ let newAnchorX, newAnchorY;
719
+ switch (currentResizeHandle) {
720
+ case "nw":
721
+ newAnchorX = currentBBox.x + currentBBox.width;
722
+ newAnchorY = currentBBox.y + currentBBox.height;
723
+ break;
724
+ case "ne":
725
+ newAnchorX = currentBBox.x;
726
+ newAnchorY = currentBBox.y + currentBBox.height;
727
+ break;
728
+ case "sw":
729
+ newAnchorX = currentBBox.x + currentBBox.width;
730
+ newAnchorY = currentBBox.y;
731
+ break;
732
+ case "se":
733
+ newAnchorX = currentBBox.x;
734
+ newAnchorY = currentBBox.y;
735
+ break;
736
+ }
737
+ const deltaX = anchorX - newAnchorX;
738
+ const deltaY = anchorY - newAnchorY;
739
+ const currentTransform = selectedElement.transform.baseVal.consolidate();
740
+ if (currentTransform) {
741
+ const matrix = currentTransform.matrix;
742
+ const angle = Math.atan2(matrix.b, matrix.a) * 180 / Math.PI;
743
+ const newGroupTx = initialGroupTx + deltaX;
744
+ const newGroupTy = initialGroupTy + deltaY;
745
+ const centerX = currentBBox.x + currentBBox.width / 2;
746
+ const centerY = currentBBox.y + currentBBox.height / 2;
747
+ selectedElement.setAttribute(
748
+ "transform",
749
+ `translate(${newGroupTx}, ${newGroupTy}) rotate(${angle}, ${centerX}, ${centerY})`
750
+ );
751
+ } else {
752
+ const newGroupTx = initialGroupTx + deltaX;
753
+ const newGroupTy = initialGroupTy + deltaY;
754
+ selectedElement.setAttribute("transform", `translate(${newGroupTx}, ${newGroupTy})`);
755
+ }
756
+ updateAttachedArrows(selectedElement);
757
+ clearTimeout(selectedElement.updateFeedbackTimeout);
758
+ selectedElement.updateFeedbackTimeout = setTimeout(() => {
759
+ updateSelectionFeedback();
760
+ delete selectedElement.updateFeedbackTimeout;
761
+ }, 0);
762
+ } else if (isRotating) {
763
+ const textElement = selectedElement.querySelector("text");
764
+ if (!textElement) return;
765
+ const bbox = textElement.getBBox();
766
+ const centerX = bbox.x + bbox.width / 2;
767
+ const centerY = bbox.y + bbox.height / 2;
768
+ const mousePos = getSVGCoordinates(event);
769
+ let centerPoint = svg.createSVGPoint();
770
+ centerPoint.x = centerX;
771
+ centerPoint.y = centerY;
772
+ const groupTransform = selectedElement.transform.baseVal.consolidate();
773
+ if (groupTransform) {
774
+ centerPoint = centerPoint.matrixTransform(groupTransform.matrix);
775
+ }
776
+ const currentAngle = Math.atan2(mousePos.y - centerPoint.y, mousePos.x - centerPoint.x) * 180 / Math.PI;
777
+ const rotationDiff = currentAngle - rotationStartAngle;
778
+ const newTransform = `translate(${rotationStartTransform.e}, ${rotationStartTransform.f}) rotate(${rotationDiff}, ${centerX}, ${centerY})`;
779
+ selectedElement.setAttribute("transform", newTransform);
780
+ updateAttachedArrows(selectedElement);
781
+ updateSelectionFeedback();
782
+ }
783
+ };
784
+ var handleMouseUp = (event) => {
785
+ if (event.button !== 0) return;
786
+ if (isDragging && selectedElement) {
787
+ const currentTransform = selectedElement.transform.baseVal.consolidate();
788
+ if (currentTransform) {
789
+ const finalTranslateX = currentTransform.matrix.e;
790
+ const finalTranslateY = currentTransform.matrix.f;
791
+ const initialX = parseFloat(selectedElement.getAttribute("data-x")) || 0;
792
+ const initialY = parseFloat(selectedElement.getAttribute("data-y")) || 0;
793
+ let textShape = null;
794
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
795
+ textShape = shapes.find((shape) => shape.shapeName === "text" && shape.group === selectedElement);
796
+ }
797
+ const oldPosWithFrame = {
798
+ x: initialX,
799
+ y: initialY,
800
+ rotation: extractRotationFromTransform(selectedElement) || 0,
801
+ parentFrame: draggedShapeInitialFrameText
802
+ };
803
+ const newPosWithFrame = {
804
+ x: finalTranslateX,
805
+ y: finalTranslateY,
806
+ rotation: extractRotationFromTransform(selectedElement) || 0,
807
+ parentFrame: hoveredFrameText || null
808
+ };
809
+ const stateChanged = initialX !== finalTranslateX || initialY !== finalTranslateY;
810
+ const frameChanged = oldPosWithFrame.parentFrame !== newPosWithFrame.parentFrame;
811
+ if (stateChanged || frameChanged) {
812
+ pushTransformAction(
813
+ {
814
+ type: "text",
815
+ element: selectedElement,
816
+ shapeName: "text"
817
+ },
818
+ oldPosWithFrame,
819
+ newPosWithFrame
820
+ );
821
+ }
822
+ if (textShape) {
823
+ const finalFrame = hoveredFrameText;
824
+ if (draggedShapeInitialFrameText !== finalFrame) {
825
+ if (draggedShapeInitialFrameText) {
826
+ draggedShapeInitialFrameText.removeShapeFromFrame(textShape);
827
+ }
828
+ if (finalFrame) {
829
+ finalFrame.addShapeToFrame(textShape);
830
+ }
831
+ if (frameChanged) {
832
+ pushFrameAttachmentAction(
833
+ finalFrame || draggedShapeInitialFrameText,
834
+ textShape,
835
+ finalFrame ? "attach" : "detach",
836
+ draggedShapeInitialFrameText
837
+ );
838
+ }
839
+ } else if (draggedShapeInitialFrameText) {
840
+ draggedShapeInitialFrameText.restoreToFrame(textShape);
841
+ }
842
+ }
843
+ selectedElement.setAttribute("data-x", finalTranslateX);
844
+ selectedElement.setAttribute("data-y", finalTranslateY);
845
+ }
846
+ draggedShapeInitialFrameText = null;
847
+ } else if (isResizing && selectedElement) {
848
+ const textElement = selectedElement.querySelector("text");
849
+ if (textElement) {
850
+ const finalFontSize = textElement.getAttribute("font-size");
851
+ const initialFontSize = startFontSize;
852
+ const currentTransform = selectedElement.transform.baseVal.consolidate();
853
+ if (currentTransform && initialFontSize !== parseFloat(finalFontSize)) {
854
+ const finalTranslateX = currentTransform.matrix.e;
855
+ const finalTranslateY = currentTransform.matrix.f;
856
+ pushTransformAction(
857
+ {
858
+ type: "text",
859
+ element: selectedElement,
860
+ shapeName: "text"
861
+ },
862
+ {
863
+ x: initialGroupTx,
864
+ y: initialGroupTy,
865
+ fontSize: initialFontSize,
866
+ rotation: extractRotationFromTransform(selectedElement) || 0
867
+ },
868
+ {
869
+ x: finalTranslateX,
870
+ y: finalTranslateY,
871
+ fontSize: parseFloat(finalFontSize),
872
+ rotation: extractRotationFromTransform(selectedElement) || 0
873
+ }
874
+ );
875
+ selectedElement.setAttribute("data-x", finalTranslateX);
876
+ selectedElement.setAttribute("data-y", finalTranslateY);
877
+ }
878
+ clearTimeout(selectedElement.updateFeedbackTimeout);
879
+ updateSelectionFeedback();
880
+ }
881
+ } else if (isRotating && selectedElement) {
882
+ const currentTransform = selectedElement.transform.baseVal.consolidate();
883
+ if (currentTransform && rotationStartTransform) {
884
+ const initialRotation = Math.atan2(rotationStartTransform.b, rotationStartTransform.a) * 180 / Math.PI;
885
+ const finalRotation = extractRotationFromTransform(selectedElement) || 0;
886
+ if (Math.abs(initialRotation - finalRotation) > 1) {
887
+ pushTransformAction(
888
+ {
889
+ type: "text",
890
+ element: selectedElement,
891
+ shapeName: "text"
892
+ },
893
+ {
894
+ x: rotationStartTransform.e,
895
+ y: rotationStartTransform.f,
896
+ rotation: initialRotation
897
+ },
898
+ {
899
+ x: currentTransform.matrix.e,
900
+ y: currentTransform.matrix.f,
901
+ rotation: finalRotation
902
+ }
903
+ );
904
+ }
905
+ }
906
+ updateSelectionFeedback();
907
+ }
908
+ if (hoveredFrameText) {
909
+ hoveredFrameText.removeHighlight();
910
+ hoveredFrameText = null;
911
+ }
912
+ isDragging = false;
913
+ isResizing = false;
914
+ isRotating = false;
915
+ currentResizeHandle = null;
916
+ startPoint = null;
917
+ startBBox = null;
918
+ startFontSize = null;
919
+ dragOffsetX = void 0;
920
+ dragOffsetY = void 0;
921
+ initialHandlePosRelGroup = null;
922
+ initialGroupTx = 0;
923
+ initialGroupTy = 0;
924
+ rotationStartAngle = 0;
925
+ rotationStartTransform = null;
926
+ svg.style.cursor = isSelectionToolActive ? "default" : isTextToolActive ? "text" : "default";
927
+ if (selectedElement) {
928
+ setTimeout(updateSelectionFeedback, 0);
929
+ }
930
+ svg.removeEventListener("pointermove", handleMouseMove);
931
+ svg.removeEventListener("pointerup", handleMouseUp);
932
+ window.removeEventListener("pointermove", handleMouseMove);
933
+ window.removeEventListener("pointerup", handleMouseUp);
934
+ };
935
+ function extractRotationFromTransform(element) {
936
+ const currentTransform = element.transform.baseVal.consolidate();
937
+ if (currentTransform) {
938
+ const matrix = currentTransform.matrix;
939
+ return Math.atan2(matrix.b, matrix.a) * 180 / Math.PI;
940
+ }
941
+ return 0;
942
+ }
943
+ var handleTextMouseDown = function(e) {
944
+ if (!e.target) return;
945
+ const activeEditor = document.querySelector("textarea.svg-text-editor");
946
+ if (activeEditor && activeEditor.contains(e.target)) {
947
+ return;
948
+ }
949
+ if (activeEditor && !activeEditor.contains(e.target)) {
950
+ let textElement = activeEditor.originalTextElement;
951
+ if (textElement) {
952
+ renderText(activeEditor, textElement, true);
953
+ return;
954
+ } else if (document.body.contains(activeEditor)) {
955
+ document.body.removeChild(activeEditor);
956
+ }
957
+ }
958
+ const targetGroup = e.target.closest('g[data-type="text-group"]');
959
+ if (isSelectionToolActive && e.button === 0) {
960
+ if (targetGroup) {
961
+ if (e.target.closest(".resize-handle")) {
962
+ return;
963
+ }
964
+ if (e.detail >= 2 && targetGroup === selectedElement) {
965
+ enterEditMode(targetGroup);
966
+ e.stopPropagation();
967
+ return;
968
+ }
969
+ if (targetGroup === selectedElement) {
970
+ startDrag(e);
971
+ } else {
972
+ selectElement(targetGroup);
973
+ startDrag(e);
974
+ }
975
+ } else {
976
+ deselectElement();
977
+ }
978
+ } else if (isTextToolActive && e.button === 0) {
979
+ if (targetGroup) {
980
+ if (e.detail >= 2) {
981
+ let textEl = targetGroup.querySelector("text");
982
+ if (textEl) {
983
+ makeTextEditable(textEl, targetGroup);
984
+ e.stopPropagation();
985
+ return;
986
+ }
987
+ }
988
+ if (targetGroup === selectedElement) {
989
+ startDrag(e);
990
+ } else {
991
+ selectElement(targetGroup);
992
+ startDrag(e);
993
+ }
994
+ } else {
995
+ deselectElement();
996
+ addText(e);
997
+ }
998
+ }
999
+ };
1000
+ function enterEditMode(groupElement) {
1001
+ const textEl = groupElement.querySelector("text");
1002
+ if (!textEl) return;
1003
+ if (window.__sketchStoreApi) {
1004
+ window.__sketchStoreApi.setActiveTool("text");
1005
+ } else {
1006
+ window.isTextToolActive = true;
1007
+ window.isSelectionToolActive = false;
1008
+ }
1009
+ toolExtraPopup();
1010
+ deselectElement();
1011
+ makeTextEditable(textEl, groupElement);
1012
+ }
1013
+ var handleTextMouseMove = function(e) {
1014
+ const svgRect = svg.getBoundingClientRect();
1015
+ lastMousePos = {
1016
+ x: e.clientX - svgRect.left,
1017
+ y: e.clientY - svgRect.top
1018
+ };
1019
+ if (isTextToolActive) {
1020
+ const targetGroup = e.target?.closest?.('g[data-type="text-group"]');
1021
+ if (targetGroup) {
1022
+ svg.style.cursor = "pointer";
1023
+ } else {
1024
+ svg.style.cursor = "crosshair";
1025
+ }
1026
+ } else if (isSelectionToolActive) {
1027
+ const targetGroup = e.target?.closest?.('g[data-type="text-group"]');
1028
+ if (targetGroup) {
1029
+ svg.style.cursor = "default";
1030
+ }
1031
+ }
1032
+ if (isTextToolActive && !isDragging && !isResizing && !isRotating) {
1033
+ const { x, y } = getSVGCoordinates(e);
1034
+ const tempTextBounds = {
1035
+ x: x - 50,
1036
+ y: y - 20,
1037
+ width: 100,
1038
+ height: 40
1039
+ };
1040
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
1041
+ shapes.forEach((frame) => {
1042
+ if (frame.shapeName === "frame") {
1043
+ if (frame.isShapeInFrame(tempTextBounds)) {
1044
+ frame.highlightFrame();
1045
+ hoveredFrameText = frame;
1046
+ } else if (hoveredFrameText === frame) {
1047
+ frame.removeHighlight();
1048
+ hoveredFrameText = null;
1049
+ }
1050
+ }
1051
+ });
1052
+ }
1053
+ }
1054
+ };
1055
+ var handleTextMouseUp = function(e) {
1056
+ if (hoveredFrameText) {
1057
+ hoveredFrameText.removeHighlight();
1058
+ hoveredFrameText = null;
1059
+ }
1060
+ };
1061
+ textColorOptions.forEach((span) => {
1062
+ span.addEventListener("click", (event) => {
1063
+ event.stopPropagation();
1064
+ textColorOptions.forEach((el) => el.classList.remove("selected"));
1065
+ span.classList.add("selected");
1066
+ const newColor = span.getAttribute("data-id");
1067
+ const oldColor = textColor;
1068
+ textColor = newColor;
1069
+ if (selectedElement) {
1070
+ const textElement = selectedElement.querySelector("text");
1071
+ if (textElement) {
1072
+ const currentColor = textElement.getAttribute("fill");
1073
+ if (currentColor !== newColor) {
1074
+ pushOptionsChangeAction(
1075
+ {
1076
+ type: "text",
1077
+ element: selectedElement,
1078
+ shapeName: "text"
1079
+ },
1080
+ {
1081
+ color: currentColor,
1082
+ font: textElement.getAttribute("font-family"),
1083
+ size: textElement.getAttribute("font-size"),
1084
+ align: textElement.getAttribute("text-anchor")
1085
+ },
1086
+ {
1087
+ color: newColor,
1088
+ font: textElement.getAttribute("font-family"),
1089
+ size: textElement.getAttribute("font-size"),
1090
+ align: textElement.getAttribute("text-anchor")
1091
+ }
1092
+ );
1093
+ }
1094
+ textElement.setAttribute("fill", newColor);
1095
+ }
1096
+ }
1097
+ });
1098
+ });
1099
+ textFontOptions.forEach((span) => {
1100
+ span.addEventListener("click", (event) => {
1101
+ event.stopPropagation();
1102
+ textFontOptions.forEach((el) => el.classList.remove("selected"));
1103
+ span.classList.add("selected");
1104
+ const newFont = span.getAttribute("data-id");
1105
+ const oldFont = textFont;
1106
+ textFont = newFont;
1107
+ if (selectedElement) {
1108
+ const textElement = selectedElement.querySelector("text");
1109
+ if (textElement) {
1110
+ const currentFont = textElement.getAttribute("font-family");
1111
+ if (currentFont !== newFont) {
1112
+ pushOptionsChangeAction(
1113
+ {
1114
+ type: "text",
1115
+ element: selectedElement,
1116
+ shapeName: "text"
1117
+ },
1118
+ {
1119
+ color: textElement.getAttribute("fill"),
1120
+ font: currentFont,
1121
+ size: textElement.getAttribute("font-size"),
1122
+ align: textElement.getAttribute("text-anchor")
1123
+ },
1124
+ {
1125
+ color: textElement.getAttribute("fill"),
1126
+ font: newFont,
1127
+ size: textElement.getAttribute("font-size"),
1128
+ align: textElement.getAttribute("text-anchor")
1129
+ }
1130
+ );
1131
+ }
1132
+ textElement.setAttribute("font-family", newFont);
1133
+ setTimeout(updateSelectionFeedback, 0);
1134
+ }
1135
+ }
1136
+ });
1137
+ });
1138
+ textSizeOptions.forEach((span) => {
1139
+ span.addEventListener("click", (event) => {
1140
+ event.stopPropagation();
1141
+ textSizeOptions.forEach((el) => el.classList.remove("selected"));
1142
+ span.classList.add("selected");
1143
+ const newSize = span.getAttribute("data-id") + "px";
1144
+ const oldSize = textSize;
1145
+ textSize = newSize;
1146
+ if (selectedElement) {
1147
+ const textElement = selectedElement.querySelector("text");
1148
+ if (textElement) {
1149
+ const currentSize = textElement.getAttribute("font-size");
1150
+ if (currentSize !== newSize) {
1151
+ pushOptionsChangeAction(
1152
+ {
1153
+ type: "text",
1154
+ element: selectedElement,
1155
+ shapeName: "text"
1156
+ },
1157
+ {
1158
+ color: textElement.getAttribute("fill"),
1159
+ font: textElement.getAttribute("font-family"),
1160
+ size: currentSize,
1161
+ align: textElement.getAttribute("text-anchor")
1162
+ },
1163
+ {
1164
+ color: textElement.getAttribute("fill"),
1165
+ font: textElement.getAttribute("font-family"),
1166
+ size: newSize,
1167
+ align: textElement.getAttribute("text-anchor")
1168
+ }
1169
+ );
1170
+ }
1171
+ textElement.setAttribute("font-size", newSize);
1172
+ setTimeout(updateSelectionFeedback, 0);
1173
+ }
1174
+ }
1175
+ });
1176
+ });
1177
+ textAlignOptions.forEach((span) => {
1178
+ span.addEventListener("click", (event) => {
1179
+ event.stopPropagation();
1180
+ textAlignOptions.forEach((el) => el.classList.remove("selected"));
1181
+ span.classList.add("selected");
1182
+ const newAlign = span.getAttribute("data-id");
1183
+ const oldAlign = textAlign;
1184
+ textAlign = newAlign;
1185
+ if (selectedElement) {
1186
+ const textElement = selectedElement.querySelector("text");
1187
+ if (textElement) {
1188
+ const currentAnchor = textElement.getAttribute("text-anchor");
1189
+ let newAnchor = "start";
1190
+ if (newAlign === "center") newAnchor = "middle";
1191
+ else if (newAlign === "right") newAnchor = "end";
1192
+ if (currentAnchor !== newAnchor) {
1193
+ pushOptionsChangeAction(
1194
+ {
1195
+ type: "text",
1196
+ element: selectedElement,
1197
+ shapeName: "text"
1198
+ },
1199
+ {
1200
+ color: textElement.getAttribute("fill"),
1201
+ font: textElement.getAttribute("font-family"),
1202
+ size: textElement.getAttribute("font-size"),
1203
+ align: currentAnchor
1204
+ },
1205
+ {
1206
+ color: textElement.getAttribute("fill"),
1207
+ font: textElement.getAttribute("font-family"),
1208
+ size: textElement.getAttribute("font-size"),
1209
+ align: newAnchor
1210
+ }
1211
+ );
1212
+ }
1213
+ textElement.setAttribute("text-anchor", newAnchor);
1214
+ setTimeout(updateSelectionFeedback, 0);
1215
+ }
1216
+ }
1217
+ });
1218
+ });
1219
+ var textCodeOptions = document.querySelectorAll(".textCodeSpan");
1220
+ var languageSelector = document.getElementById("textLanguageSelector");
1221
+ var codeLanguageSelect = document.getElementById("codeLanguageSelect");
1222
+ textCodeOptions.forEach((span) => {
1223
+ span.addEventListener("click", (event) => {
1224
+ event.stopPropagation();
1225
+ textCodeOptions.forEach((el) => el.classList.remove("selected"));
1226
+ span.classList.add("selected");
1227
+ const isCodeMode = span.getAttribute("data-id") === "true";
1228
+ isTextInCodeMode = isCodeMode;
1229
+ if (languageSelector) {
1230
+ languageSelector.classList.toggle("hidden", !isCodeMode);
1231
+ }
1232
+ if (isTextToolActive) {
1233
+ isCodeToolActive = isCodeMode;
1234
+ }
1235
+ if (isCodeMode && selectedElement) {
1236
+ convertTextToCode(selectedElement);
1237
+ } else if (!isCodeMode && getSelectedCodeBlock()) {
1238
+ convertCodeToText(getSelectedCodeBlock());
1239
+ }
1240
+ });
1241
+ });
1242
+ if (codeLanguageSelect) {
1243
+ codeLanguageSelect.addEventListener("change", (event) => {
1244
+ const lang = event.target.value;
1245
+ setCodeLanguage(lang);
1246
+ const selectedCode = getSelectedCodeBlock();
1247
+ if (selectedCode) {
1248
+ const codeElement = selectedCode.querySelector("text");
1249
+ if (codeElement) {
1250
+ codeElement.setAttribute("data-language", lang);
1251
+ const content = extractTextFromCodeElement(codeElement);
1252
+ while (codeElement.firstChild) {
1253
+ codeElement.removeChild(codeElement.firstChild);
1254
+ }
1255
+ const highlighted = applySyntaxHighlightingToSVG(content, lang);
1256
+ createHighlightedSVGText(highlighted, codeElement);
1257
+ updateCodeBackground(selectedCode, codeElement);
1258
+ }
1259
+ }
1260
+ });
1261
+ }
1262
+ function convertTextToCode(textGroupElement) {
1263
+ const textElement = textGroupElement.querySelector("text");
1264
+ if (!textElement) return;
1265
+ let textContent = "";
1266
+ const tspans = textElement.querySelectorAll("tspan");
1267
+ if (tspans.length > 0) {
1268
+ tspans.forEach((tspan, index) => {
1269
+ textContent += tspan.textContent;
1270
+ if (index < tspans.length - 1) textContent += "\n";
1271
+ });
1272
+ } else {
1273
+ textContent = textElement.textContent || "";
1274
+ }
1275
+ const currentTransform = textGroupElement.transform.baseVal.consolidate();
1276
+ const tx = currentTransform ? currentTransform.matrix.e : 0;
1277
+ const ty = currentTransform ? currentTransform.matrix.f : 0;
1278
+ const fontSize = textElement.getAttribute("font-size") || "25px";
1279
+ const color = textElement.getAttribute("fill") || "#fff";
1280
+ let oldTextShape = null;
1281
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
1282
+ oldTextShape = shapes.find((s) => s.shapeName === "text" && s.group === textGroupElement);
1283
+ if (oldTextShape) {
1284
+ const idx = shapes.indexOf(oldTextShape);
1285
+ if (idx !== -1) shapes.splice(idx, 1);
1286
+ }
1287
+ }
1288
+ deselectElement();
1289
+ if (textGroupElement.parentNode) {
1290
+ textGroupElement.parentNode.removeChild(textGroupElement);
1291
+ }
1292
+ const gElement = document.createElementNS("http://www.w3.org/2000/svg", "g");
1293
+ gElement.setAttribute("data-type", "code-group");
1294
+ gElement.setAttribute("transform", `translate(${tx}, ${ty})`);
1295
+ const backgroundRect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
1296
+ backgroundRect.setAttribute("class", "code-background");
1297
+ backgroundRect.setAttribute("x", -10);
1298
+ backgroundRect.setAttribute("y", -10);
1299
+ backgroundRect.setAttribute("width", 300);
1300
+ backgroundRect.setAttribute("height", 60);
1301
+ backgroundRect.setAttribute("fill", "#161b22");
1302
+ backgroundRect.setAttribute("stroke", "#30363d");
1303
+ backgroundRect.setAttribute("stroke-width", "1");
1304
+ backgroundRect.setAttribute("rx", "6");
1305
+ backgroundRect.setAttribute("ry", "6");
1306
+ gElement.appendChild(backgroundRect);
1307
+ const codeElement = document.createElementNS("http://www.w3.org/2000/svg", "text");
1308
+ codeElement.setAttribute("x", 0);
1309
+ codeElement.setAttribute("y", 0);
1310
+ codeElement.setAttribute("fill", color);
1311
+ codeElement.setAttribute("font-size", fontSize);
1312
+ codeElement.setAttribute("font-family", "lixCode");
1313
+ codeElement.setAttribute("text-anchor", "start");
1314
+ codeElement.setAttribute("cursor", "default");
1315
+ codeElement.setAttribute("white-space", "pre");
1316
+ codeElement.setAttribute("dominant-baseline", "hanging");
1317
+ codeElement.setAttribute("data-language", getCodeLanguage());
1318
+ codeElement.setAttribute("data-type", "code");
1319
+ const shapeID = `code-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 1e4)}`;
1320
+ gElement.setAttribute("id", shapeID);
1321
+ gElement.setAttribute("data-x", tx);
1322
+ gElement.setAttribute("data-y", ty);
1323
+ codeElement.setAttribute("id", `${shapeID}-code`);
1324
+ gElement.appendChild(codeElement);
1325
+ svg.appendChild(gElement);
1326
+ if (textContent.trim()) {
1327
+ const lang = getCodeLanguage();
1328
+ const highlighted = applySyntaxHighlightingToSVG(textContent, lang);
1329
+ createHighlightedSVGText(highlighted, codeElement);
1330
+ updateCodeBackground(gElement, codeElement);
1331
+ }
1332
+ const codeShape = wrapCodeElement(gElement);
1333
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
1334
+ shapes.push(codeShape);
1335
+ }
1336
+ pushModeConvertAction(oldTextShape, textGroupElement, "text", codeShape, gElement, "code");
1337
+ selectCodeBlock(gElement);
1338
+ }
1339
+ function convertCodeToText(codeGroupElement) {
1340
+ const codeElement = codeGroupElement.querySelector("text");
1341
+ if (!codeElement) return;
1342
+ const textContent = extractTextFromCodeElement(codeElement);
1343
+ const currentTransform = codeGroupElement.transform.baseVal.consolidate();
1344
+ const tx = currentTransform ? currentTransform.matrix.e : 0;
1345
+ const ty = currentTransform ? currentTransform.matrix.f : 0;
1346
+ const fontSize = codeElement.getAttribute("font-size") || "30px";
1347
+ const color = codeElement.getAttribute("fill") || "#fff";
1348
+ let oldCodeShape = null;
1349
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
1350
+ oldCodeShape = shapes.find((s) => s.shapeName === "code" && s.group === codeGroupElement);
1351
+ if (oldCodeShape) {
1352
+ const idx = shapes.indexOf(oldCodeShape);
1353
+ if (idx !== -1) shapes.splice(idx, 1);
1354
+ }
1355
+ }
1356
+ deselectCodeBlock();
1357
+ if (codeGroupElement.parentNode) {
1358
+ codeGroupElement.parentNode.removeChild(codeGroupElement);
1359
+ }
1360
+ const gElement = document.createElementNS("http://www.w3.org/2000/svg", "g");
1361
+ gElement.setAttribute("data-type", "text-group");
1362
+ gElement.setAttribute("transform", `translate(${tx}, ${ty})`);
1363
+ const textElement = document.createElementNS("http://www.w3.org/2000/svg", "text");
1364
+ textElement.setAttribute("x", 0);
1365
+ textElement.setAttribute("y", 0);
1366
+ textElement.setAttribute("fill", color);
1367
+ textElement.setAttribute("font-size", fontSize);
1368
+ textElement.setAttribute("font-family", textFont);
1369
+ textElement.setAttribute("text-anchor", "start");
1370
+ textElement.setAttribute("cursor", "default");
1371
+ textElement.setAttribute("white-space", "pre");
1372
+ textElement.setAttribute("dominant-baseline", "hanging");
1373
+ textElement.setAttribute("data-type", "text");
1374
+ const shapeID = `text-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 1e4)}`;
1375
+ gElement.setAttribute("id", shapeID);
1376
+ gElement.setAttribute("data-x", tx);
1377
+ gElement.setAttribute("data-y", ty);
1378
+ textElement.setAttribute("id", `${shapeID}-text`);
1379
+ gElement.appendChild(textElement);
1380
+ svg.appendChild(gElement);
1381
+ if (textContent.trim()) {
1382
+ const lines = textContent.split("\n");
1383
+ const x = textElement.getAttribute("x") || 0;
1384
+ lines.forEach((line, index) => {
1385
+ const tspan = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
1386
+ tspan.setAttribute("x", x);
1387
+ tspan.setAttribute("dy", index === 0 ? "0" : "1.2em");
1388
+ tspan.textContent = line || " ";
1389
+ textElement.appendChild(tspan);
1390
+ });
1391
+ }
1392
+ const textShape = wrapTextElement(gElement);
1393
+ if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
1394
+ shapes.push(textShape);
1395
+ }
1396
+ pushModeConvertAction(oldCodeShape, codeGroupElement, "code", textShape, gElement, "text");
1397
+ selectElement(gElement);
1398
+ }
1399
+ function pushModeConvertAction(oldShape, oldElement, oldType, newShape, newElement, newType) {
1400
+ pushCreateAction({
1401
+ type: "modeConvert",
1402
+ oldShape,
1403
+ oldElement,
1404
+ oldType,
1405
+ newShape,
1406
+ newElement,
1407
+ newType,
1408
+ element: newShape,
1409
+ shapeName: newType
1410
+ });
1411
+ }
1412
+ function updateCodeToggleForShape(shapeName) {
1413
+ const isCode = shapeName === "code";
1414
+ textCodeOptions.forEach((el) => el.classList.remove("selected"));
1415
+ textCodeOptions.forEach((el) => {
1416
+ if (el.getAttribute("data-id") === "true" === isCode) {
1417
+ el.classList.add("selected");
1418
+ }
1419
+ });
1420
+ if (languageSelector) {
1421
+ languageSelector.classList.toggle("hidden", !isCode);
1422
+ }
1423
+ if (isCode && codeLanguageSelect) {
1424
+ const selectedCode = getSelectedCodeBlock();
1425
+ if (selectedCode) {
1426
+ const codeEl = selectedCode.querySelector("text");
1427
+ const lang = codeEl?.getAttribute("data-language") || "auto";
1428
+ codeLanguageSelect.value = lang;
1429
+ }
1430
+ }
1431
+ }
1432
+ window.updateSelectedTextStyle = function(changes) {
1433
+ const el = selectedElement || (window.currentShape && window.currentShape.shapeName === "text" ? window.currentShape.group : null);
1434
+ if (!el) return;
1435
+ const textElement = el.querySelector("text");
1436
+ if (!textElement) return;
1437
+ if (changes.color) {
1438
+ textElement.setAttribute("fill", changes.color);
1439
+ textColor = changes.color;
1440
+ }
1441
+ if (changes.font) {
1442
+ textElement.setAttribute("font-family", changes.font);
1443
+ textFont = changes.font;
1444
+ }
1445
+ if (changes.fontSize) {
1446
+ textElement.setAttribute("font-size", changes.fontSize);
1447
+ textSize = changes.fontSize;
1448
+ }
1449
+ };
1450
+ window.__deselectTextElement = deselectElement;
1451
+ window.__selectTextElement = selectElement;
1452
+ window.__convertTextToCode = function() {
1453
+ if (selectedElement && selectedElement.getAttribute("data-type") === "text-group") {
1454
+ convertTextToCode(selectedElement);
1455
+ }
1456
+ };
1457
+ window.__convertCodeToText = function() {
1458
+ let codeBlock = getSelectedCodeBlock();
1459
+ if (!codeBlock && selectedElement && selectedElement.getAttribute("data-type") === "code-group") {
1460
+ codeBlock = selectedElement;
1461
+ }
1462
+ if (codeBlock) {
1463
+ convertCodeToText(codeBlock);
1464
+ }
1465
+ };
1466
+ window.__setCodeLanguage = function(lang) {
1467
+ setCodeLanguage(lang);
1468
+ const selectedCode = getSelectedCodeBlock();
1469
+ if (selectedCode) {
1470
+ const codeElement = selectedCode.querySelector("text");
1471
+ if (codeElement) {
1472
+ codeElement.setAttribute("data-language", lang);
1473
+ const textContent = extractTextFromCodeElement(codeElement);
1474
+ while (codeElement.firstChild) codeElement.removeChild(codeElement.firstChild);
1475
+ const highlighted = applySyntaxHighlightingToSVG(textContent, lang);
1476
+ createHighlightedSVGText(highlighted, codeElement);
1477
+ updateCodeBackground(selectedCode, codeElement);
1478
+ }
1479
+ }
1480
+ };
1481
+
1482
+ export {
1483
+ deselectElement,
1484
+ handleTextMouseDown,
1485
+ enterEditMode,
1486
+ handleTextMouseMove,
1487
+ handleTextMouseUp,
1488
+ updateCodeToggleForShape
1489
+ };
1490
+ //# sourceMappingURL=chunk-JJCJNLNN.js.map