@elixpo/lixsketch 4.5.8

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 (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/fonts/fonts.css +29 -0
  4. package/fonts/lixCode.ttf +0 -0
  5. package/fonts/lixDefault.ttf +0 -0
  6. package/fonts/lixDocs.ttf +0 -0
  7. package/fonts/lixFancy.ttf +0 -0
  8. package/fonts/lixFont.woff2 +0 -0
  9. package/package.json +49 -0
  10. package/src/SketchEngine.js +473 -0
  11. package/src/core/AIRenderer.js +1390 -0
  12. package/src/core/CopyPaste.js +655 -0
  13. package/src/core/EraserTrail.js +234 -0
  14. package/src/core/EventDispatcher.js +371 -0
  15. package/src/core/GraphEngine.js +150 -0
  16. package/src/core/GraphMathParser.js +231 -0
  17. package/src/core/GraphRenderer.js +255 -0
  18. package/src/core/LayerOrder.js +91 -0
  19. package/src/core/LixScriptParser.js +1299 -0
  20. package/src/core/MermaidFlowchartRenderer.js +475 -0
  21. package/src/core/MermaidSequenceParser.js +197 -0
  22. package/src/core/MermaidSequenceRenderer.js +479 -0
  23. package/src/core/ResizeCode.js +175 -0
  24. package/src/core/ResizeShapes.js +318 -0
  25. package/src/core/SceneSerializer.js +778 -0
  26. package/src/core/Selection.js +1861 -0
  27. package/src/core/SnapGuides.js +273 -0
  28. package/src/core/UndoRedo.js +1358 -0
  29. package/src/core/ZoomPan.js +258 -0
  30. package/src/core/ai-system-prompt.js +663 -0
  31. package/src/index.js +69 -0
  32. package/src/shapes/Arrow.js +1979 -0
  33. package/src/shapes/Circle.js +751 -0
  34. package/src/shapes/CodeShape.js +244 -0
  35. package/src/shapes/Frame.js +1460 -0
  36. package/src/shapes/FreehandStroke.js +724 -0
  37. package/src/shapes/IconShape.js +265 -0
  38. package/src/shapes/ImageShape.js +270 -0
  39. package/src/shapes/Line.js +738 -0
  40. package/src/shapes/Rectangle.js +794 -0
  41. package/src/shapes/TextShape.js +225 -0
  42. package/src/tools/arrowTool.js +581 -0
  43. package/src/tools/circleTool.js +619 -0
  44. package/src/tools/codeTool.js +2103 -0
  45. package/src/tools/eraserTool.js +131 -0
  46. package/src/tools/frameTool.js +241 -0
  47. package/src/tools/freehandTool.js +620 -0
  48. package/src/tools/iconTool.js +1344 -0
  49. package/src/tools/imageTool.js +1323 -0
  50. package/src/tools/laserTool.js +317 -0
  51. package/src/tools/lineTool.js +502 -0
  52. package/src/tools/rectangleTool.js +544 -0
  53. package/src/tools/textTool.js +1823 -0
  54. package/src/utils/imageCompressor.js +107 -0
@@ -0,0 +1,225 @@
1
+ /* eslint-disable */
2
+ // TextShape class - extracted from writeText.js
3
+ // Depends on globals: svg, shapes, currentShape
4
+
5
+ function extractRotationFromTransform(el) {
6
+ const t = el.getAttribute("transform") || "";
7
+ const m = t.match(/rotate\(([^,)]+)/);
8
+ return m ? parseFloat(m[1]) : 0;
9
+ }
10
+ function updateAttachedArrows(wrapper) {
11
+ if (!wrapper || typeof shapes === "undefined") return;
12
+ shapes.forEach(s => {
13
+ if (s && s.shapeName === "arrow" && typeof s.updateAttachments === "function") {
14
+ if ((s.attachedToStart && s.attachedToStart.shape === wrapper) ||
15
+ (s.attachedToEnd && s.attachedToEnd.shape === wrapper)) {
16
+ s.updateAttachments();
17
+ }
18
+ }
19
+ });
20
+ }
21
+ let isDragging = false;
22
+ let hoveredFrameText = null;
23
+ let selectedElement = null;
24
+ function updateSelectionFeedback() {}
25
+ function deselectElement() { selectedElement = null; }
26
+ function selectElement(el) { selectedElement = el; }
27
+
28
+ class TextShape {
29
+ constructor(groupElement) {
30
+ this.group = groupElement;
31
+ this.shapeName = 'text';
32
+ this.shapeID = groupElement.getAttribute('id') || `text-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;
33
+
34
+ // Frame attachment properties
35
+ this.parentFrame = null;
36
+
37
+ // Update group attributes — ensure data-type is set for textTool interaction
38
+ this.group.setAttribute('type', 'text');
39
+ this.group.setAttribute('data-type', 'text-group');
40
+ this.group.shapeName = 'text';
41
+ this.group.shapeID = this.shapeID;
42
+ }
43
+
44
+ // Position and dimension properties for frame compatibility
45
+ get x() {
46
+ const transform = this.group.transform.baseVal.consolidate();
47
+ return transform ? transform.matrix.e : parseFloat(this.group.getAttribute('data-x')) || 0;
48
+ }
49
+
50
+ set x(value) {
51
+ const transform = this.group.transform.baseVal.consolidate();
52
+ const currentY = transform ? transform.matrix.f : parseFloat(this.group.getAttribute('data-y')) || 0;
53
+ const rotation = extractRotationFromTransform(this.group) || 0;
54
+ const textElement = this.group.querySelector('text');
55
+ if (textElement) {
56
+ const bbox = textElement.getBBox();
57
+ const centerX = bbox.x + bbox.width / 2;
58
+ const centerY = bbox.y + bbox.height / 2;
59
+ this.group.setAttribute('transform', `translate(${value}, ${currentY}) rotate(${rotation}, ${centerX}, ${centerY})`);
60
+ } else {
61
+ this.group.setAttribute('transform', `translate(${value}, ${currentY})`);
62
+ }
63
+ this.group.setAttribute('data-x', value);
64
+ }
65
+
66
+ get y() {
67
+ const transform = this.group.transform.baseVal.consolidate();
68
+ return transform ? transform.matrix.f : parseFloat(this.group.getAttribute('data-y')) || 0;
69
+ }
70
+
71
+ set y(value) {
72
+ const transform = this.group.transform.baseVal.consolidate();
73
+ const currentX = transform ? transform.matrix.e : parseFloat(this.group.getAttribute('data-x')) || 0;
74
+ const rotation = extractRotationFromTransform(this.group) || 0;
75
+ const textElement = this.group.querySelector('text');
76
+ if (textElement) {
77
+ const bbox = textElement.getBBox();
78
+ const centerX = bbox.x + bbox.width / 2;
79
+ const centerY = bbox.y + bbox.height / 2;
80
+ this.group.setAttribute('transform', `translate(${currentX}, ${value}) rotate(${rotation}, ${centerX}, ${centerY})`);
81
+ } else {
82
+ this.group.setAttribute('transform', `translate(${currentX}, ${value})`);
83
+ }
84
+ this.group.setAttribute('data-y', value);
85
+ }
86
+
87
+ get width() {
88
+ const textElement = this.group.querySelector('text');
89
+ if (textElement) {
90
+ return textElement.getBBox().width;
91
+ }
92
+ return 0;
93
+ }
94
+
95
+ set width(value) {
96
+ // Text width is determined by content and font size, not directly settable
97
+ // This is here for frame compatibility but doesn't change the text
98
+ }
99
+
100
+ get height() {
101
+ const textElement = this.group.querySelector('text');
102
+ if (textElement) {
103
+ return textElement.getBBox().height;
104
+ }
105
+ return 0;
106
+ }
107
+
108
+ set height(value) {
109
+ // Text height is determined by content and font size, not directly settable
110
+ // This is here for frame compatibility but doesn't change the text
111
+ }
112
+
113
+ get rotation() {
114
+ return extractRotationFromTransform(this.group) || 0;
115
+ }
116
+
117
+ set rotation(value) {
118
+ const currentTransform = this.group.transform.baseVal.consolidate();
119
+ const currentX = currentTransform ? currentTransform.matrix.e : 0;
120
+ const currentY = currentTransform ? currentTransform.matrix.f : 0;
121
+ const textElement = this.group.querySelector('text');
122
+ if (textElement) {
123
+ const bbox = textElement.getBBox();
124
+ const centerX = bbox.x + bbox.width / 2;
125
+ const centerY = bbox.y + bbox.height / 2;
126
+ this.group.setAttribute('transform', `translate(${currentX}, ${currentY}) rotate(${value}, ${centerX}, ${centerY})`);
127
+ }
128
+ }
129
+
130
+ move(dx, dy) {
131
+ const currentTransform = this.group.transform.baseVal.consolidate();
132
+ const currentX = currentTransform ? currentTransform.matrix.e : 0;
133
+ const currentY = currentTransform ? currentTransform.matrix.f : 0;
134
+
135
+ this.x = currentX + dx;
136
+ this.y = currentY + dy;
137
+
138
+ // Only update frame containment if we're actively dragging the shape itself
139
+ // and not being moved by a parent frame
140
+ if (isDragging && !this.isBeingMovedByFrame) {
141
+ this.updateFrameContainment();
142
+ }
143
+
144
+ this.updateAttachedArrows();
145
+ }
146
+
147
+ updateAttachedArrows() {
148
+ updateAttachedArrows(this);
149
+ }
150
+
151
+ updateFrameContainment() {
152
+ // Don't update if we're being moved by a frame
153
+ if (this.isBeingMovedByFrame) return;
154
+
155
+ let targetFrame = null;
156
+
157
+ // Find which frame this shape is over
158
+ if (typeof shapes !== 'undefined' && Array.isArray(shapes)) {
159
+ shapes.forEach(shape => {
160
+ if (shape.shapeName === 'frame' && shape.isShapeInFrame(this)) {
161
+ targetFrame = shape;
162
+ }
163
+ });
164
+ }
165
+
166
+ // If we have a parent frame and we're being dragged, temporarily remove clipping
167
+ if (this.parentFrame && isDragging) {
168
+ this.parentFrame.temporarilyRemoveFromFrame(this);
169
+ }
170
+
171
+ // Update frame highlighting
172
+ if (hoveredFrameText && hoveredFrameText !== targetFrame) {
173
+ hoveredFrameText.removeHighlight();
174
+ }
175
+
176
+ if (targetFrame && targetFrame !== hoveredFrameText) {
177
+ targetFrame.highlightFrame();
178
+ }
179
+
180
+ hoveredFrameText = targetFrame;
181
+ }
182
+
183
+ contains(x, y) {
184
+ const textElement = this.group.querySelector('text');
185
+ if (!textElement) return false;
186
+
187
+ const bbox = textElement.getBBox();
188
+ const padding = 8; // Selection padding
189
+
190
+ const CTM = this.group.getCTM();
191
+ if (!CTM) return false;
192
+
193
+ const inverseCTM = CTM.inverse();
194
+ const svgPoint = svg.createSVGPoint();
195
+ svgPoint.x = x;
196
+ svgPoint.y = y;
197
+ const transformedPoint = svgPoint.matrixTransform(inverseCTM);
198
+
199
+ return transformedPoint.x >= bbox.x - padding &&
200
+ transformedPoint.x <= bbox.x + bbox.width + padding &&
201
+ transformedPoint.y >= bbox.y - padding &&
202
+ transformedPoint.y <= bbox.y + bbox.height + padding;
203
+ }
204
+
205
+ // Add draw method for consistency with other shapes
206
+ draw() {
207
+ // Text doesn't need redrawing like other shapes, but we need this method for consistency
208
+ if (selectedElement === this.group) {
209
+ updateSelectionFeedback();
210
+ }
211
+ }
212
+
213
+ // Add methods for frame compatibility
214
+ removeSelection() {
215
+ if (selectedElement === this.group) {
216
+ deselectElement();
217
+ }
218
+ }
219
+
220
+ selectShape() {
221
+ selectElement(this.group);
222
+ }
223
+ }
224
+
225
+ export { TextShape };