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