@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,473 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
/**
|
|
3
|
+
* SketchEngine - Main engine entry point
|
|
4
|
+
*
|
|
5
|
+
* Initializes the SVG canvas, sets up global state (including RoughJS from npm),
|
|
6
|
+
* then dynamically imports all tool and shape modules.
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT: All globals must be set BEFORE importing modules, because many
|
|
9
|
+
* modules run code at the top level (e.g. `const rc = rough.svg(svg)`) that
|
|
10
|
+
* depends on these globals existing.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import rough from 'roughjs';
|
|
14
|
+
|
|
15
|
+
class SketchEngine {
|
|
16
|
+
constructor(svgElement, options = {}) {
|
|
17
|
+
if (!svgElement || svgElement.tagName !== 'svg') {
|
|
18
|
+
throw new Error('SketchEngine requires an SVG element');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.svg = svgElement;
|
|
22
|
+
this.options = {
|
|
23
|
+
initialZoom: 1,
|
|
24
|
+
minZoom: 0.4,
|
|
25
|
+
maxZoom: 30,
|
|
26
|
+
...options
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Event callback for framework consumers (React, Vue, vanilla, VS Code, etc.)
|
|
30
|
+
this.onEvent = options.onEvent || (() => {});
|
|
31
|
+
|
|
32
|
+
// Public API surfaces (populated after init)
|
|
33
|
+
this.scene = null;
|
|
34
|
+
this.shapes = null;
|
|
35
|
+
|
|
36
|
+
this._modules = {};
|
|
37
|
+
this._initialized = false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Emit an event to the consumer callback.
|
|
42
|
+
* @param {string} type - Event type (e.g. 'sidebar:select', 'zoom:change')
|
|
43
|
+
* @param {*} data - Event payload
|
|
44
|
+
*/
|
|
45
|
+
emit(type, data) {
|
|
46
|
+
try { this.onEvent(type, data); } catch (e) { console.warn('[SketchEngine] onEvent error:', e); }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Set up all the global variables that the tool/shape modules depend on.
|
|
51
|
+
* Must be called BEFORE any module imports.
|
|
52
|
+
*/
|
|
53
|
+
_initGlobals() {
|
|
54
|
+
// Core SVG reference
|
|
55
|
+
window.svg = this.svg;
|
|
56
|
+
window.freehandCanvas = this.svg;
|
|
57
|
+
|
|
58
|
+
// RoughJS from npm
|
|
59
|
+
window.rough = rough;
|
|
60
|
+
window.roughCanvas = rough.svg(this.svg);
|
|
61
|
+
window.roughGenerator = window.roughCanvas.generator;
|
|
62
|
+
|
|
63
|
+
// Shape storage
|
|
64
|
+
window.shapes = window.shapes || [];
|
|
65
|
+
window.currentShape = window.currentShape || null;
|
|
66
|
+
window.lastMousePos = window.lastMousePos || null;
|
|
67
|
+
|
|
68
|
+
// Zoom state
|
|
69
|
+
window.currentZoom = this.options.initialZoom;
|
|
70
|
+
window.minScale = this.options.minZoom;
|
|
71
|
+
window.maxScale = this.options.maxZoom;
|
|
72
|
+
window.minZoom = this.options.minZoom;
|
|
73
|
+
window.maxZoom = this.options.maxZoom;
|
|
74
|
+
|
|
75
|
+
// ViewBox state
|
|
76
|
+
window.currentViewBox = window.currentViewBox || {
|
|
77
|
+
x: 0, y: 0,
|
|
78
|
+
width: window.innerWidth,
|
|
79
|
+
height: window.innerHeight
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Tool activation flags
|
|
83
|
+
window.isPaintToolActive = false;
|
|
84
|
+
window.isTextToolActive = false;
|
|
85
|
+
window.isCircleToolActive = false;
|
|
86
|
+
window.isSquareToolActive = false;
|
|
87
|
+
window.isLaserToolActive = false;
|
|
88
|
+
window.isEraserToolActive = false;
|
|
89
|
+
window.isImageToolActive = false;
|
|
90
|
+
window.isArrowToolActive = false;
|
|
91
|
+
window.isLineToolActive = false;
|
|
92
|
+
window.isSelectionToolActive = true;
|
|
93
|
+
window.isPanningToolActive = false;
|
|
94
|
+
window.isFrameToolActive = false;
|
|
95
|
+
window.isIconToolActive = false;
|
|
96
|
+
window.isCodeToolActive = false;
|
|
97
|
+
window.isTextInCodeMode = false;
|
|
98
|
+
|
|
99
|
+
// Pan state
|
|
100
|
+
window.isPanning = false;
|
|
101
|
+
window.panStart = null;
|
|
102
|
+
window.startCanvasX = 0;
|
|
103
|
+
window.startCanvasY = 0;
|
|
104
|
+
|
|
105
|
+
// Transform state
|
|
106
|
+
window.currentMatrix = new DOMMatrix();
|
|
107
|
+
window.currentTranslation = { x: 0, y: 0 };
|
|
108
|
+
|
|
109
|
+
// Action type constants
|
|
110
|
+
window.ACTION_CREATE = 'create';
|
|
111
|
+
window.ACTION_DELETE = 'delete';
|
|
112
|
+
window.ACTION_MODIFY = 'modify';
|
|
113
|
+
window.ACTION_PASTE = 'paste';
|
|
114
|
+
|
|
115
|
+
// History stacks
|
|
116
|
+
window.historyStack = window.historyStack || [];
|
|
117
|
+
window.redoStack = window.redoStack || [];
|
|
118
|
+
|
|
119
|
+
// Sidebar element stubs — React sidebars handle UI, but legacy code
|
|
120
|
+
// queries these at top level. Provide dummy elements so it doesn't crash.
|
|
121
|
+
const dummyEl = document.createElement('div');
|
|
122
|
+
dummyEl.classList.add('hidden');
|
|
123
|
+
window.paintBrushSideBar = document.getElementById('paintBrushToolBar') || dummyEl;
|
|
124
|
+
window.lineSideBar = document.getElementById('lineSideBar') || dummyEl;
|
|
125
|
+
window.squareSideBar = document.getElementById('squareSideBar') || dummyEl;
|
|
126
|
+
window.circleSideBar = document.getElementById('circleSideBar') || dummyEl;
|
|
127
|
+
window.arrowSideBar = document.getElementById('arrowSideBar') || dummyEl;
|
|
128
|
+
window.textSideBar = document.getElementById('textToolBar') || dummyEl;
|
|
129
|
+
window.frameSideBar = document.getElementById('frameSideBar') || dummyEl;
|
|
130
|
+
|
|
131
|
+
// Zoom control element refs
|
|
132
|
+
window.zoomInBtn = document.getElementById('zoomIn') || dummyEl;
|
|
133
|
+
window.zoomOutBtn = document.getElementById('zoomOut') || dummyEl;
|
|
134
|
+
window.zoomPercentSpan = document.getElementById('zoomPercent') || dummyEl;
|
|
135
|
+
|
|
136
|
+
// Container
|
|
137
|
+
window.container = document.querySelector('.container') || document.body;
|
|
138
|
+
|
|
139
|
+
// Sidebar control — bridge legacy code to consumer UI
|
|
140
|
+
const engine = this;
|
|
141
|
+
window.disableAllSideBars = function() {
|
|
142
|
+
// Hide all legacy sidebar elements
|
|
143
|
+
[window.paintBrushSideBar, window.lineSideBar, window.squareSideBar,
|
|
144
|
+
window.circleSideBar, window.arrowSideBar, window.textSideBar, window.frameSideBar
|
|
145
|
+
].forEach(el => { if (el) el.classList.add('hidden'); });
|
|
146
|
+
// Notify consumer via onEvent + legacy bridge
|
|
147
|
+
engine.emit('sidebar:clear');
|
|
148
|
+
if (window.__sketchStoreApi) {
|
|
149
|
+
window.__sketchStoreApi.clearSelectedShapeSidebar();
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// toolExtraPopup — legacy UI function, no-op in React
|
|
154
|
+
window.toolExtraPopup = window.toolExtraPopup || function() {};
|
|
155
|
+
|
|
156
|
+
// updateUndoRedoButtons — legacy UI function, no-op in React
|
|
157
|
+
window.updateUndoRedoButtons = window.updateUndoRedoButtons || function() {};
|
|
158
|
+
|
|
159
|
+
// Bridge for shape selection -> consumer UI
|
|
160
|
+
// Maps shape.shapeName to the sidebar key
|
|
161
|
+
window.__showSidebarForShape = function(shapeName) {
|
|
162
|
+
const sidebarMap = {
|
|
163
|
+
'rectangle': 'rectangle',
|
|
164
|
+
'circle': 'circle',
|
|
165
|
+
'arrow': 'arrow',
|
|
166
|
+
'line': 'line',
|
|
167
|
+
'freehandStroke': 'paintbrush',
|
|
168
|
+
'text': 'text',
|
|
169
|
+
'code': 'text',
|
|
170
|
+
'frame': 'frame',
|
|
171
|
+
'image': 'image',
|
|
172
|
+
};
|
|
173
|
+
const sidebar = sidebarMap[shapeName];
|
|
174
|
+
// Emit to consumer callback
|
|
175
|
+
engine.emit('sidebar:select', { sidebar, shapeName });
|
|
176
|
+
// Legacy bridge for React
|
|
177
|
+
if (sidebar && window.__sketchStoreApi) {
|
|
178
|
+
window.__sketchStoreApi.setSelectedShapeSidebar(sidebar);
|
|
179
|
+
}
|
|
180
|
+
window.__selectedShapeIsCode = (shapeName === 'code');
|
|
181
|
+
if (window.__onCodeModeChanged) window.__onCodeModeChanged(shapeName === 'code');
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Initialize engine: set globals first, then import modules.
|
|
187
|
+
*/
|
|
188
|
+
async init() {
|
|
189
|
+
if (this._initialized) return;
|
|
190
|
+
|
|
191
|
+
// CRITICAL: Set up ALL globals BEFORE importing modules
|
|
192
|
+
this._initGlobals();
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
// Import shape classes first
|
|
196
|
+
const [
|
|
197
|
+
{ Rectangle },
|
|
198
|
+
{ Circle },
|
|
199
|
+
{ Arrow },
|
|
200
|
+
{ Line },
|
|
201
|
+
{ TextShape },
|
|
202
|
+
{ CodeShape },
|
|
203
|
+
{ ImageShape },
|
|
204
|
+
{ IconShape },
|
|
205
|
+
{ Frame },
|
|
206
|
+
{ FreehandStroke }
|
|
207
|
+
] = await Promise.all([
|
|
208
|
+
import('./shapes/Rectangle.js'),
|
|
209
|
+
import('./shapes/Circle.js'),
|
|
210
|
+
import('./shapes/Arrow.js'),
|
|
211
|
+
import('./shapes/Line.js'),
|
|
212
|
+
import('./shapes/TextShape.js'),
|
|
213
|
+
import('./shapes/CodeShape.js'),
|
|
214
|
+
import('./shapes/ImageShape.js'),
|
|
215
|
+
import('./shapes/IconShape.js'),
|
|
216
|
+
import('./shapes/Frame.js'),
|
|
217
|
+
import('./shapes/FreehandStroke.js')
|
|
218
|
+
]);
|
|
219
|
+
|
|
220
|
+
// Expose shape classes globally
|
|
221
|
+
window.Rectangle = Rectangle;
|
|
222
|
+
window.Circle = Circle;
|
|
223
|
+
window.Arrow = Arrow;
|
|
224
|
+
window.Line = Line;
|
|
225
|
+
window.TextShape = TextShape;
|
|
226
|
+
window.CodeShape = CodeShape;
|
|
227
|
+
window.ImageShape = ImageShape;
|
|
228
|
+
window.IconShape = IconShape;
|
|
229
|
+
window.Frame = Frame;
|
|
230
|
+
window.FreehandStroke = FreehandStroke;
|
|
231
|
+
|
|
232
|
+
this._modules.shapes = {
|
|
233
|
+
Rectangle, Circle, Arrow, Line,
|
|
234
|
+
TextShape, CodeShape, ImageShape, IconShape,
|
|
235
|
+
Frame, FreehandStroke
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// Import tool handlers (they run top-level code that reads globals)
|
|
239
|
+
const [
|
|
240
|
+
rectangleTool, circleTool, arrowTool, lineTool,
|
|
241
|
+
textTool, codeTool, imageTool, iconTool,
|
|
242
|
+
frameTool, freehandTool
|
|
243
|
+
] = await Promise.all([
|
|
244
|
+
import('./tools/rectangleTool.js'),
|
|
245
|
+
import('./tools/circleTool.js'),
|
|
246
|
+
import('./tools/arrowTool.js'),
|
|
247
|
+
import('./tools/lineTool.js'),
|
|
248
|
+
import('./tools/textTool.js'),
|
|
249
|
+
import('./tools/codeTool.js'),
|
|
250
|
+
import('./tools/imageTool.js'),
|
|
251
|
+
import('./tools/iconTool.js'),
|
|
252
|
+
import('./tools/frameTool.js'),
|
|
253
|
+
import('./tools/freehandTool.js')
|
|
254
|
+
]);
|
|
255
|
+
|
|
256
|
+
this._modules.tools = {
|
|
257
|
+
rectangleTool, circleTool, arrowTool, lineTool,
|
|
258
|
+
textTool, codeTool, imageTool, iconTool,
|
|
259
|
+
frameTool, freehandTool
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// Import core modules (EventDispatcher attaches SVG listeners at top level)
|
|
263
|
+
const [
|
|
264
|
+
eventDispatcher, undoRedo, selection,
|
|
265
|
+
zoomPan, copyPaste, eraserTrail,
|
|
266
|
+
resizeShapes, resizeCode
|
|
267
|
+
] = await Promise.all([
|
|
268
|
+
import('./core/EventDispatcher.js'),
|
|
269
|
+
import('./core/UndoRedo.js'),
|
|
270
|
+
import('./core/Selection.js'),
|
|
271
|
+
import('./core/ZoomPan.js'),
|
|
272
|
+
import('./core/CopyPaste.js'),
|
|
273
|
+
import('./core/EraserTrail.js'),
|
|
274
|
+
import('./core/ResizeShapes.js'),
|
|
275
|
+
import('./core/ResizeCode.js')
|
|
276
|
+
]);
|
|
277
|
+
|
|
278
|
+
this._modules.core = {
|
|
279
|
+
eventDispatcher, undoRedo, selection,
|
|
280
|
+
zoomPan, copyPaste, eraserTrail,
|
|
281
|
+
resizeShapes, resizeCode
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
// Re-bind event listeners to the current SVG element
|
|
285
|
+
if (eventDispatcher.initEventDispatcher) {
|
|
286
|
+
eventDispatcher.initEventDispatcher(this.svg);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Import standalone tools
|
|
290
|
+
await Promise.all([
|
|
291
|
+
import('./tools/eraserTool.js'),
|
|
292
|
+
import('./tools/laserTool.js')
|
|
293
|
+
]);
|
|
294
|
+
|
|
295
|
+
// Expose key functions globally
|
|
296
|
+
if (undoRedo.undo) window.undo = undoRedo.undo;
|
|
297
|
+
if (undoRedo.redo) window.redo = undoRedo.redo;
|
|
298
|
+
if (undoRedo.pushCreateAction) window.pushCreateAction = undoRedo.pushCreateAction;
|
|
299
|
+
if (undoRedo.pushDeleteAction) window.pushDeleteAction = undoRedo.pushDeleteAction;
|
|
300
|
+
if (selection.multiSelection) window.multiSelection = selection.multiSelection;
|
|
301
|
+
if (selection.clearAllSelections) window.clearAllSelections = selection.clearAllSelections;
|
|
302
|
+
|
|
303
|
+
// Initialize centralized copy/paste system
|
|
304
|
+
if (copyPaste.initCopyPaste) copyPaste.initCopyPaste();
|
|
305
|
+
|
|
306
|
+
// Initialize AI renderer bridge
|
|
307
|
+
const aiRenderer = await import('./core/AIRenderer.js');
|
|
308
|
+
if (aiRenderer.initAIRenderer) aiRenderer.initAIRenderer();
|
|
309
|
+
|
|
310
|
+
// Initialize graph engine bridge
|
|
311
|
+
const graphEngine = await import('./core/GraphEngine.js');
|
|
312
|
+
if (graphEngine.initGraphEngine) graphEngine.initGraphEngine();
|
|
313
|
+
|
|
314
|
+
// Initialize scene serializer bridge
|
|
315
|
+
const sceneSerializer = await import('./core/SceneSerializer.js');
|
|
316
|
+
if (sceneSerializer.initSceneSerializer) sceneSerializer.initSceneSerializer();
|
|
317
|
+
|
|
318
|
+
// Initialize layer ordering
|
|
319
|
+
const layerOrder = await import('./core/LayerOrder.js');
|
|
320
|
+
if (layerOrder.initLayerOrder) layerOrder.initLayerOrder();
|
|
321
|
+
|
|
322
|
+
// Initialize LixScript programmatic diagram engine
|
|
323
|
+
const lixScript = await import('./core/LixScriptParser.js');
|
|
324
|
+
if (lixScript.initLixScriptBridge) lixScript.initLixScriptBridge();
|
|
325
|
+
|
|
326
|
+
// ── Public API surfaces ──
|
|
327
|
+
|
|
328
|
+
// Scene operations (save, load, export, etc.)
|
|
329
|
+
this.scene = window.__sceneSerializer || {
|
|
330
|
+
save: sceneSerializer.saveScene,
|
|
331
|
+
load: sceneSerializer.loadScene,
|
|
332
|
+
download: sceneSerializer.downloadScene,
|
|
333
|
+
upload: sceneSerializer.uploadScene,
|
|
334
|
+
exportPNG: sceneSerializer.exportAsPNG,
|
|
335
|
+
exportPDF: sceneSerializer.exportAsPDF,
|
|
336
|
+
copyAsPNG: sceneSerializer.copyAsPNG,
|
|
337
|
+
copyAsSVG: sceneSerializer.copyAsSVG,
|
|
338
|
+
reset: sceneSerializer.resetCanvas,
|
|
339
|
+
findText: sceneSerializer.findTextOnCanvas,
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// Shape array reference
|
|
343
|
+
this.shapes = window.shapes;
|
|
344
|
+
|
|
345
|
+
// Undo/redo
|
|
346
|
+
this.undo = undoRedo.undo || (() => {});
|
|
347
|
+
this.redo = undoRedo.redo || (() => {});
|
|
348
|
+
|
|
349
|
+
// LixScript execution
|
|
350
|
+
this.lixscript = {
|
|
351
|
+
parse: lixScript.parseLixScript || (() => null),
|
|
352
|
+
execute: lixScript.executeLixScript || (lixScript.parseLixScript ? (code) => {
|
|
353
|
+
const parsed = lixScript.parseLixScript(code);
|
|
354
|
+
if (parsed && lixScript.resolveShapeRefs) lixScript.resolveShapeRefs(parsed);
|
|
355
|
+
return parsed;
|
|
356
|
+
} : (() => null)),
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// Store module refs for advanced consumers
|
|
360
|
+
this._modules.sceneSerializer = sceneSerializer;
|
|
361
|
+
this._modules.lixScript = lixScript;
|
|
362
|
+
|
|
363
|
+
this._initialized = true;
|
|
364
|
+
console.log('[SketchEngine] Initialized successfully');
|
|
365
|
+
} catch (err) {
|
|
366
|
+
console.error('[SketchEngine] Initialization failed:', err);
|
|
367
|
+
throw err;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Sync tool flags from Zustand activeTool value.
|
|
373
|
+
*/
|
|
374
|
+
setActiveTool(toolName) {
|
|
375
|
+
// Deselect current shape when switching tools
|
|
376
|
+
if (window.currentShape && typeof window.currentShape.removeSelection === 'function') {
|
|
377
|
+
window.currentShape.removeSelection();
|
|
378
|
+
window.currentShape = null;
|
|
379
|
+
}
|
|
380
|
+
if (typeof window.clearAllSelections === 'function') {
|
|
381
|
+
window.clearAllSelections();
|
|
382
|
+
}
|
|
383
|
+
if (typeof window.disableAllSideBars === 'function') {
|
|
384
|
+
window.disableAllSideBars();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Force cleanup eraser trail when switching tools
|
|
388
|
+
if (typeof window.forceCleanupEraserTrail === 'function') {
|
|
389
|
+
window.forceCleanupEraserTrail();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
window.isPaintToolActive = false;
|
|
393
|
+
window.isSquareToolActive = false;
|
|
394
|
+
window.isCircleToolActive = false;
|
|
395
|
+
window.isArrowToolActive = false;
|
|
396
|
+
window.isTextToolActive = false;
|
|
397
|
+
window.isLaserToolActive = false;
|
|
398
|
+
window.isLineToolActive = false;
|
|
399
|
+
window.isEraserToolActive = false;
|
|
400
|
+
window.isSelectionToolActive = false;
|
|
401
|
+
window.isImageToolActive = false;
|
|
402
|
+
window.isPanningToolActive = false;
|
|
403
|
+
window.isFrameToolActive = false;
|
|
404
|
+
window.isIconToolActive = false;
|
|
405
|
+
window.isCodeToolActive = false;
|
|
406
|
+
|
|
407
|
+
const flagMap = {
|
|
408
|
+
select: 'isSelectionToolActive',
|
|
409
|
+
pan: 'isPanningToolActive',
|
|
410
|
+
rectangle: 'isSquareToolActive',
|
|
411
|
+
circle: 'isCircleToolActive',
|
|
412
|
+
line: 'isLineToolActive',
|
|
413
|
+
arrow: 'isArrowToolActive',
|
|
414
|
+
freehand: 'isPaintToolActive',
|
|
415
|
+
text: 'isTextToolActive',
|
|
416
|
+
code: 'isCodeToolActive',
|
|
417
|
+
eraser: 'isEraserToolActive',
|
|
418
|
+
laser: 'isLaserToolActive',
|
|
419
|
+
image: 'isImageToolActive',
|
|
420
|
+
frame: 'isFrameToolActive',
|
|
421
|
+
icon: 'isIconToolActive',
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const flag = flagMap[toolName];
|
|
425
|
+
if (flag) window[flag] = true;
|
|
426
|
+
|
|
427
|
+
if (toolName === 'text' && window.isTextInCodeMode) {
|
|
428
|
+
window.isCodeToolActive = true;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Show image source picker when image tool is activated
|
|
432
|
+
if (toolName === 'image' && window.__showImageSourcePicker) {
|
|
433
|
+
window.__showImageSourcePicker();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Set appropriate cursor for the active tool
|
|
437
|
+
const cursorMap = {
|
|
438
|
+
select: 'default',
|
|
439
|
+
pan: 'grab',
|
|
440
|
+
rectangle: 'crosshair',
|
|
441
|
+
circle: 'crosshair',
|
|
442
|
+
line: 'crosshair',
|
|
443
|
+
arrow: 'crosshair',
|
|
444
|
+
freehand: 'crosshair',
|
|
445
|
+
text: 'crosshair',
|
|
446
|
+
code: 'crosshair',
|
|
447
|
+
eraser: 'crosshair',
|
|
448
|
+
laser: 'crosshair',
|
|
449
|
+
image: 'crosshair',
|
|
450
|
+
frame: 'crosshair',
|
|
451
|
+
icon: 'crosshair',
|
|
452
|
+
};
|
|
453
|
+
if (this.svg) {
|
|
454
|
+
this.svg.style.cursor = cursorMap[toolName] || 'default';
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
cleanup() {
|
|
459
|
+
// Remove event listeners from the SVG element
|
|
460
|
+
if (this._modules.core?.eventDispatcher?.cleanupEventDispatcher) {
|
|
461
|
+
this._modules.core.eventDispatcher.cleanupEventDispatcher();
|
|
462
|
+
}
|
|
463
|
+
window.shapes = [];
|
|
464
|
+
window.currentShape = null;
|
|
465
|
+
window.lastMousePos = null;
|
|
466
|
+
this._modules = {};
|
|
467
|
+
this._initialized = false;
|
|
468
|
+
console.log('[SketchEngine] Cleaned up');
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
export { SketchEngine };
|
|
473
|
+
export default SketchEngine;
|