@elixpo/lixsketch 5.5.8 → 5.5.10

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 (27) hide show
  1. package/dist/react/{CopyPaste-4CKJRHJ3.js → CopyPaste-SA72NDFN.js} +2 -2
  2. package/dist/react/{EventDispatcher-FP2RHJGG.js → EventDispatcher-BZQRHROG.js} +7 -7
  3. package/dist/react/{SceneSerializer-4U4B24JM.js → SceneSerializer-ZPHV6IUP.js} +2 -2
  4. package/dist/react/{SketchEngine-WYUPJWK4.js → SketchEngine-BCRJ62CV.js} +11 -7
  5. package/dist/react/SketchEngine-BCRJ62CV.js.map +7 -0
  6. package/dist/react/TextShape-U6ZZKB35.js +8 -0
  7. package/dist/react/{chunk-QXFBG7OM.js → chunk-42O6W7DF.js} +18 -1
  8. package/dist/react/chunk-42O6W7DF.js.map +7 -0
  9. package/dist/react/{chunk-TUMWA4YF.js → chunk-5QIT2WBE.js} +21 -113
  10. package/dist/react/chunk-5QIT2WBE.js.map +7 -0
  11. package/dist/react/index.js +3 -3
  12. package/dist/react/index.js.map +1 -1
  13. package/dist/react/{textTool-QVKV45VD.js → textTool-HY5NMM7H.js} +2 -2
  14. package/package.json +1 -1
  15. package/src/SketchEngine.js +11 -7
  16. package/src/react/components/sidebars/TextSidebar.jsx +1 -1
  17. package/src/shapes/TextShape.js +19 -0
  18. package/src/tools/textTool.js +25 -155
  19. package/dist/react/SketchEngine-WYUPJWK4.js.map +0 -7
  20. package/dist/react/TextShape-54ZJ66E3.js +0 -8
  21. package/dist/react/chunk-QXFBG7OM.js.map +0 -7
  22. package/dist/react/chunk-TUMWA4YF.js.map +0 -7
  23. /package/dist/react/{CopyPaste-4CKJRHJ3.js.map → CopyPaste-SA72NDFN.js.map} +0 -0
  24. /package/dist/react/{EventDispatcher-FP2RHJGG.js.map → EventDispatcher-BZQRHROG.js.map} +0 -0
  25. /package/dist/react/{SceneSerializer-4U4B24JM.js.map → SceneSerializer-ZPHV6IUP.js.map} +0 -0
  26. /package/dist/react/{TextShape-54ZJ66E3.js.map → TextShape-U6ZZKB35.js.map} +0 -0
  27. /package/dist/react/{textTool-QVKV45VD.js.map → textTool-HY5NMM7H.js.map} +0 -0
@@ -6,7 +6,7 @@ import {
6
6
  handleTextMouseMove,
7
7
  handleTextMouseUp,
8
8
  updateCodeToggleForShape
9
- } from "./chunk-TUMWA4YF.js";
9
+ } from "./chunk-5QIT2WBE.js";
10
10
  import "./chunk-LHRTXNVE.js";
11
11
  import "./chunk-BZE4CEBG.js";
12
12
  import "./chunk-L5OARZJ7.js";
@@ -18,4 +18,4 @@ export {
18
18
  handleTextMouseUp,
19
19
  updateCodeToggleForShape
20
20
  };
21
- //# sourceMappingURL=textTool-QVKV45VD.js.map
21
+ //# sourceMappingURL=textTool-HY5NMM7H.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elixpo/lixsketch",
3
- "version": "5.5.8",
3
+ "version": "5.5.10",
4
4
  "description": "Open-source SVG whiteboard engine + React canvas component with hand-drawn aesthetics — the core of LixSketch",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -57,6 +57,7 @@ class SketchEngine {
57
57
  // Core SVG reference
58
58
  window.svg = this.svg;
59
59
  window.freehandCanvas = this.svg;
60
+ window.__sketchInteractionReady = false;
60
61
 
61
62
  // RoughJS from npm
62
63
  window.rough = rough;
@@ -238,13 +239,6 @@ class SketchEngine {
238
239
  Frame, FreehandStroke
239
240
  };
240
241
 
241
- // Expose restore as soon as the shape constructors are ready.
242
- // Tool handlers, AI/graph renderers, and LixScript are not needed
243
- // to deserialize a cached scene, so keeping the serializer behind
244
- // those chunks unnecessarily delayed first canvas paint.
245
- const sceneSerializer = await import('./core/SceneSerializer.js');
246
- if (sceneSerializer.initSceneSerializer) sceneSerializer.initSceneSerializer();
247
-
248
242
  // Import tool handlers (they run top-level code that reads globals)
249
243
  const [
250
244
  rectangleTool, circleTool, arrowTool, lineTool,
@@ -295,6 +289,14 @@ class SketchEngine {
295
289
  if (eventDispatcher.initEventDispatcher) {
296
290
  eventDispatcher.initEventDispatcher(this.svg);
297
291
  }
292
+ window.__sketchInteractionReady = true;
293
+
294
+ // Restore only after pointer handlers are bound. This still keeps
295
+ // first canvas paint ahead of optional AI/graph/LixScript chunks,
296
+ // while guaranteeing every visible restored shape is immediately
297
+ // selectable and draggable.
298
+ const sceneSerializer = await import('./core/SceneSerializer.js');
299
+ if (sceneSerializer.initSceneSerializer) sceneSerializer.initSceneSerializer();
298
300
 
299
301
  // Import standalone tools
300
302
  await Promise.all([
@@ -473,6 +475,8 @@ class SketchEngine {
473
475
  window.shapes = [];
474
476
  window.currentShape = null;
475
477
  window.lastMousePos = null;
478
+ window.__sketchInteractionReady = false;
479
+ delete window.__sceneSerializer;
476
480
  this._modules = {};
477
481
  this._initialized = false;
478
482
  console.log('[SketchEngine] Cleaned up');
@@ -27,7 +27,7 @@ export default function TextSidebar() {
27
27
  const activeTool = useSketchStore((s) => s.activeTool)
28
28
  const selectedShapeSidebar = useSketchStore((s) => s.selectedShapeSidebar)
29
29
  const [textColor, setTextColor] = useState('#fff')
30
- const [fontSize, setFontSize] = useState('M')
30
+ const [fontSize, setFontSize] = useState('S')
31
31
  const [font, setFont] = useState('lixFont')
32
32
  const [codeMode, setCodeMode] = useState(false)
33
33
  const [language, setLanguage] = useState('javascript')
@@ -25,9 +25,28 @@ function updateSelectionFeedback() {}
25
25
  function deselectElement() { selectedElement = null; }
26
26
  function selectElement(el) { selectedElement = el; }
27
27
 
28
+ function removeLegacySoftWrap(groupElement) {
29
+ const textElement = groupElement.querySelector('text');
30
+ if (!textElement || !textElement.hasAttribute('data-wrap-width')) return;
31
+ const source = textElement.getAttribute('data-wrap-source');
32
+ if (source === null) return;
33
+
34
+ while (textElement.firstChild) textElement.removeChild(textElement.firstChild);
35
+ const x = textElement.getAttribute('x') || 0;
36
+ source.split('\n').forEach((line, index) => {
37
+ const tspan = textElement.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'tspan');
38
+ tspan.setAttribute('x', x);
39
+ tspan.setAttribute('dy', index === 0 ? '0' : '1.2em');
40
+ tspan.textContent = line || ' ';
41
+ textElement.appendChild(tspan);
42
+ });
43
+ textElement.removeAttribute('data-wrap-width');
44
+ }
45
+
28
46
  class TextShape {
29
47
  constructor(groupElement) {
30
48
  this.group = groupElement;
49
+ removeLegacySoftWrap(groupElement);
31
50
  this.shapeName = 'text';
32
51
  this.shapeID = groupElement.getAttribute('id') || `text-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;
33
52
 
@@ -27,7 +27,7 @@ import {
27
27
  getSelectedCodeBlock
28
28
  } from './codeTool.js';
29
29
 
30
- let textSize = "30px";
30
+ let textSize = "20px";
31
31
  let textFont = "lixFont";
32
32
  let textColor = null;
33
33
  let textAlign = "left";
@@ -193,11 +193,11 @@ function makeTextEditable(textElement, groupElement) {
193
193
 
194
194
  let input = document.createElement("textarea");
195
195
  input.className = "svg-text-editor";
196
+ input.setAttribute("aria-label", "Edit canvas text");
197
+ input.setAttribute("data-editing", "true");
196
198
 
197
- // Issue #48 phase D follow-up: prefer the persisted `data-wrap-
198
- // source` when present so re-opening the editor shows the user's
199
- // original line breaks instead of the auto-wrap output. Falls back
200
- // to tspan-concatenation for legacy text shapes.
199
+ // Prefer the persisted source so re-opening the editor preserves only
200
+ // the line breaks the user explicitly inserted with Shift+Enter.
201
201
  let textContent = '';
202
202
  const storedSource = textElement.getAttribute('data-wrap-source');
203
203
  if (storedSource !== null && storedSource !== '') {
@@ -222,12 +222,10 @@ function makeTextEditable(textElement, groupElement) {
222
222
  input.style.boxSizing = "border-box";
223
223
  input.style.overflow = "hidden";
224
224
  input.style.resize = "none";
225
- input.style.whiteSpace = "pre-wrap";
225
+ input.style.whiteSpace = "pre";
226
226
  input.style.minHeight = "1.2em";
227
227
  input.style.zIndex = "10000";
228
228
 
229
- const svgRect = svg.getBoundingClientRect();
230
-
231
229
  // Use the group element's own screenCTM which includes group transform + SVG viewBox transform
232
230
  const textBBox = textElement.getBBox();
233
231
  let pt = svg.createSVGPoint();
@@ -241,17 +239,15 @@ function makeTextEditable(textElement, groupElement) {
241
239
  input.style.top = `${screenPt.y}px`;
242
240
 
243
241
  const svgZoomFactor = svg.getScreenCTM() ? svg.getScreenCTM().a : 1;
244
- const screenWidth = textBBox.width * svgZoomFactor;
245
-
246
242
  input.style.width = "auto";
247
243
  input.style.height = "auto";
248
244
 
249
- const currentFontSize = textElement.getAttribute("font-size") || "30px";
245
+ const currentFontSize = textElement.getAttribute("font-size") || "20px";
250
246
  const currentFontFamily = textElement.getAttribute("font-family") || "lixFont";
251
247
  const currentFill = textElement.getAttribute("fill") || "#fff";
252
248
  const currentAnchor = textElement.getAttribute("text-anchor") || "start";
253
249
  // Scale font-size by zoom so the textarea matches what the user sees on canvas
254
- const rawSize = parseFloat(currentFontSize) || 30;
250
+ const rawSize = parseFloat(currentFontSize) || 20;
255
251
  const scaledFontSize = `${rawSize * svgZoomFactor}px`;
256
252
 
257
253
  input.style.minWidth = "150px";
@@ -259,51 +255,31 @@ function makeTextEditable(textElement, groupElement) {
259
255
  input.style.width = "auto";
260
256
  input.style.height = "auto";
261
257
  input.style.overflow = "visible";
262
- input.style.whiteSpace = "pre-wrap";
263
- input.style.wordBreak = "break-word";
258
+ input.style.whiteSpace = "pre";
259
+ input.style.wordBreak = "normal";
260
+ input.style.overflowWrap = "normal";
264
261
  input.style.fontSize = scaledFontSize;
265
262
  input.style.fontFamily = currentFontFamily;
266
263
  input.style.color = currentFill;
267
264
  input.style.lineHeight = "1.2em";
268
265
  input.style.textAlign = currentAnchor === "middle" ? "center" : currentAnchor === "end" ? "right" : "left";
269
266
  input.style.backgroundColor = "transparent";
270
- // Issue #34 bug #5a + #48 bug #2: dashed creation outline that grows
271
- // with the text. Originally `rgba(255,255,255,0.55)` invisible on
272
- // the new light canvas. Read the active theme so the dashes stay
273
- // visible in both modes.
274
- const _isDark = typeof document !== 'undefined'
275
- && document.body
276
- && document.body.classList.contains('theme-dark');
277
- input.style.border = _isDark
278
- ? "1px dashed rgba(255,255,255,0.55)"
279
- : "1px dashed rgba(40,40,60,0.45)";
280
- input.style.borderRadius = "3px";
267
+ input.style.border = "none";
268
+ input.style.boxShadow = "none";
281
269
  input.style.outline = "none";
282
270
  document.body.appendChild(input);
283
271
 
284
272
  const adjustHeight = () => {
285
273
  input.style.height = 'auto';
286
274
  input.style.height = input.scrollHeight + 'px';
287
- const maxHeight = svgRect.height - (screenPt.y);
288
- if (input.scrollHeight > maxHeight) {
289
- input.style.height = maxHeight + 'px';
290
- input.style.overflowY = 'auto';
291
- } else {
292
- input.style.overflowY = 'hidden';
293
- }
275
+ input.style.overflowY = 'hidden';
294
276
  };
295
277
 
296
278
  const adjustWidth = () => {
297
279
  input.style.width = 'auto';
298
- const maxWidth = svgRect.width - (screenPt.x);
299
280
  const contentWidth = Math.max(input.scrollWidth, 150);
300
- if (contentWidth > maxWidth) {
301
- input.style.width = maxWidth + 'px';
302
- input.style.overflowX = 'auto';
303
- } else {
304
- input.style.width = contentWidth + 'px';
305
- input.style.overflowX = 'hidden';
306
- }
281
+ input.style.width = contentWidth + 'px';
282
+ input.style.overflowX = 'hidden';
307
283
  };
308
284
  adjustHeight();
309
285
  adjustWidth();
@@ -345,58 +321,12 @@ function makeTextEditable(textElement, groupElement) {
345
321
  groupElement.style.display = "none";
346
322
  }
347
323
 
348
- /**
349
- * Issue #48 phase D follow-up: true text wrapping driven by E/W width.
350
- *
351
- * `paint(textElement, source, wrapWidth)` renders the user-typed `source`
352
- * string into tspans, soft-wrapping any line that exceeds `wrapWidth`
353
- * pixels (in SVG units). `wrapWidth = null | 0` falls back to the old
354
- * "explicit newlines only" behaviour so existing text shapes that have
355
- * never been width-resized look identical.
356
- *
357
- * The raw `source` is persisted on the element as `data-wrap-source`
358
- * so subsequent edits (textarea re-open) and serialisation can rebuild
359
- * the original content even after auto-wrap inserted line breaks.
360
- */
361
- function measureSegment(text, refTextElement) {
362
- if (!text) return 0;
363
- const NS = 'http://www.w3.org/2000/svg';
364
- const probe = document.createElementNS(NS, 'tspan');
365
- probe.textContent = text;
366
- refTextElement.appendChild(probe);
367
- let width = 0;
368
- try { width = probe.getComputedTextLength(); } catch {}
369
- refTextElement.removeChild(probe);
370
- return width;
371
- }
372
-
373
- function paintTextContent(textElement, source, wrapWidth) {
324
+ /** Render only explicit editor line breaks; text never soft-wraps. */
325
+ function paintTextContent(textElement, source) {
374
326
  while (textElement.firstChild) textElement.removeChild(textElement.firstChild);
375
327
  const x = textElement.getAttribute('x') || 0;
376
328
  const NS = 'http://www.w3.org/2000/svg';
377
- const paragraphs = (source || '').split('\n');
378
- const finalLines = [];
379
-
380
- for (const paragraph of paragraphs) {
381
- const para = paragraph.replace(/ /g, ' ');
382
- if (!wrapWidth || wrapWidth <= 0) {
383
- finalLines.push(para || ' ');
384
- continue;
385
- }
386
- // Word-wrap the paragraph against wrapWidth.
387
- const words = para.split(/(\s+)/); // keep separators so spacing survives
388
- let cur = '';
389
- for (const token of words) {
390
- const candidate = cur + token;
391
- if (measureSegment(candidate, textElement) > wrapWidth && cur.trim().length > 0) {
392
- finalLines.push(cur);
393
- cur = token.replace(/^\s+/, ''); // drop the leading break-space
394
- } else {
395
- cur = candidate;
396
- }
397
- }
398
- finalLines.push(cur.length ? cur : ' ');
399
- }
329
+ const finalLines = (source || '').split('\n').map((line) => line.replace(/ /g, ' '));
400
330
 
401
331
  finalLines.forEach((line, i) => {
402
332
  const tspan = document.createElementNS(NS, 'tspan');
@@ -407,21 +337,6 @@ function paintTextContent(textElement, source, wrapWidth) {
407
337
  });
408
338
  }
409
339
 
410
- function getWrapSource(textElement) {
411
- const stored = textElement.getAttribute('data-wrap-source');
412
- if (stored !== null && stored !== '') return stored;
413
- // Fallback: rebuild from existing tspans (legacy text shapes without
414
- // the attribute). Join each tspan as a paragraph.
415
- const tspans = textElement.querySelectorAll('tspan');
416
- if (tspans.length === 0) return textElement.textContent || '';
417
- return Array.from(tspans).map((t) => (t.textContent || '').replace(/ /g, ' ')).join('\n');
418
- }
419
-
420
- function getWrapWidth(textElement) {
421
- const v = parseFloat(textElement.getAttribute('data-wrap-width') || '');
422
- return Number.isFinite(v) && v > 0 ? v : 0;
423
- }
424
-
425
340
  function renderText(input, textElement, deleteIfEmpty = false) {
426
341
  if (!input || !document.body.contains(input)) {
427
342
  return;
@@ -479,13 +394,12 @@ function renderText(input, textElement, deleteIfEmpty = false) {
479
394
  removeSelectionFeedback();
480
395
  }
481
396
  } else {
482
- // Persist the raw editor content so future E/W resizes can re-wrap
483
- // from the user's original line breaks instead of the auto-inserted
484
- // ones. Then call the shared paint helper \u2014 it falls back to the
485
- // legacy "explicit newlines only" path when no wrap-width is set.
397
+ // Persist and render only the user's explicit Shift+Enter line
398
+ // breaks. Long lines remain long on the infinite canvas.
486
399
  const cleanSource = text.replace(/\u00A0/g, ' ');
487
400
  textElement.setAttribute('data-wrap-source', cleanSource);
488
- paintTextContent(textElement, cleanSource, getWrapWidth(textElement));
401
+ textElement.removeAttribute('data-wrap-width');
402
+ paintTextContent(textElement, cleanSource);
489
403
 
490
404
  gElement.style.display = 'block';
491
405
 
@@ -547,18 +461,13 @@ function createSelectionFeedback(groupElement) {
547
461
  selectionBox.setAttribute("pointer-events", "none");
548
462
  groupElement.appendChild(selectionBox);
549
463
 
550
- // Issue #48 bug #5 + phase D follow-up: E/W midpoint anchors drive
551
- // TRUE word-wrap. Dragging E/W sets `data-wrap-width` on the text
552
- // element; the paint helper re-flows tspans so the text wraps into
553
- // multiple lines. Corner anchors keep their font-size scaling
554
- // behaviour.
464
+ // Corner anchors scale font size. Width handles are intentionally
465
+ // omitted because text width is content-driven and never soft-wraps.
555
466
  const handlesData = [
556
467
  { name: 'nw', x: selX, y: selY, cursor: 'nwse-resize' },
557
468
  { name: 'ne', x: selX + selWidth, y: selY, cursor: 'nesw-resize' },
558
469
  { name: 'sw', x: selX, y: selY + selHeight, cursor: 'nesw-resize' },
559
470
  { name: 'se', x: selX + selWidth, y: selY + selHeight, cursor: 'nwse-resize' },
560
- { name: 'e', x: selX + selWidth, y: selY + selHeight / 2, cursor: 'ew-resize' },
561
- { name: 'w', x: selX, y: selY + selHeight / 2, cursor: 'ew-resize' },
562
471
  ];
563
472
 
564
473
  resizeHandles = {};
@@ -664,10 +573,6 @@ function updateSelectionFeedback() {
664
573
  { name: 'ne', x: selX + selWidth, y: selY },
665
574
  { name: 'sw', x: selX, y: selY + selHeight },
666
575
  { name: 'se', x: selX + selWidth, y: selY + selHeight },
667
- // Issue #48 bug #5: keep E/W midpoint handles aligned with the
668
- // resize so they follow the box as it scales.
669
- { name: 'e', x: selX + selWidth, y: selY + selHeight / 2 },
670
- { name: 'w', x: selX, y: selY + selHeight / 2 },
671
576
  ];
672
577
 
673
578
  handlesData.forEach(handle => {
@@ -959,7 +864,6 @@ const handleMouseMove = (event) => {
959
864
  const startHeight = startBBox.height;
960
865
 
961
866
  let anchorX, anchorY;
962
- const isEdgeWidth = currentResizeHandle === 'e' || currentResizeHandle === 'w';
963
867
 
964
868
  switch (currentResizeHandle) {
965
869
  case 'nw':
@@ -978,34 +882,8 @@ const handleMouseMove = (event) => {
978
882
  anchorX = startX;
979
883
  anchorY = startY;
980
884
  break;
981
- case 'e':
982
- anchorX = startX;
983
- anchorY = startY + startHeight / 2;
984
- break;
985
- case 'w':
986
- anchorX = startX + startWidth;
987
- anchorY = startY + startHeight / 2;
988
- break;
989
- }
990
-
991
- // Issue #48 phase D follow-up: E/W now drives TRUE word-wrap.
992
- // The drag distance becomes the wrap-width target; we re-paint
993
- // the text with the new width and short-circuit the font-size
994
- // scaling path that the corners use.
995
- if (isEdgeWidth) {
996
- const newWrap = Math.abs(currentPoint.x - anchorX);
997
- const minWrap = startFontSize * 2; // at least ~one short word wide
998
- const clampedWrap = Math.max(minWrap, newWrap);
999
- textElement.setAttribute('data-wrap-width', String(clampedWrap));
1000
- const source = getWrapSource(textElement);
1001
- paintTextContent(textElement, source, clampedWrap);
1002
- if (typeof updateSelectionFeedback === 'function') {
1003
- setTimeout(updateSelectionFeedback, 0);
1004
- }
1005
- return;
1006
885
  }
1007
886
 
1008
- const newWidth = Math.abs(currentPoint.x - anchorX);
1009
887
  const newHeight = Math.abs(currentPoint.y - anchorY);
1010
888
  const chosenScale = newHeight / startHeight;
1011
889
 
@@ -1040,14 +918,6 @@ const handleMouseMove = (event) => {
1040
918
  newAnchorX = currentBBox.x;
1041
919
  newAnchorY = currentBBox.y;
1042
920
  break;
1043
- case 'e':
1044
- newAnchorX = currentBBox.x;
1045
- newAnchorY = currentBBox.y + currentBBox.height / 2;
1046
- break;
1047
- case 'w':
1048
- newAnchorX = currentBBox.x + currentBBox.width;
1049
- newAnchorY = currentBBox.y + currentBBox.height / 2;
1050
- break;
1051
921
  }
1052
922
 
1053
923
  const deltaX = anchorX - newAnchorX;
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/SketchEngine.js"],
4
- "sourcesContent": ["/* eslint-disable */\n/**\n * SketchEngine - Main engine entry point\n *\n * Initializes the SVG canvas, sets up global state (including RoughJS from npm),\n * then dynamically imports all tool and shape modules.\n *\n * IMPORTANT: All globals must be set BEFORE importing modules, because many\n * modules run code at the top level (e.g. `const rc = rough.svg(svg)`) that\n * depends on these globals existing.\n */\n\nimport rough from 'roughjs';\n\nclass SketchEngine {\n constructor(svgElement, options = {}) {\n if (!svgElement || svgElement.tagName !== 'svg') {\n throw new Error('SketchEngine requires an SVG element');\n }\n\n this.svg = svgElement;\n // Prevent default touch scrolling/gestures on the canvas to allow for custom pointer events\n this.svg.style.touchAction = 'none';\n\n this.options = {\n initialZoom: 1,\n minZoom: 0.4,\n maxZoom: 30,\n ...options\n };\n\n // Event callback for framework consumers (React, Vue, vanilla, VS Code, etc.)\n this.onEvent = options.onEvent || (() => {});\n\n // Public API surfaces (populated after init)\n this.scene = null;\n this.shapes = null;\n\n this._modules = {};\n this._initialized = false;\n }\n\n /**\n * Emit an event to the consumer callback.\n * @param {string} type - Event type (e.g. 'sidebar:select', 'zoom:change')\n * @param {*} data - Event payload\n */\n emit(type, data) {\n try { this.onEvent(type, data); } catch (e) { console.warn('[SketchEngine] onEvent error:', e); }\n }\n\n /**\n * Set up all the global variables that the tool/shape modules depend on.\n * Must be called BEFORE any module imports.\n */\n _initGlobals() {\n // Core SVG reference\n window.svg = this.svg;\n window.freehandCanvas = this.svg;\n\n // RoughJS from npm\n window.rough = rough;\n window.roughCanvas = rough.svg(this.svg);\n window.roughGenerator = window.roughCanvas.generator;\n\n // Shape storage\n window.shapes = window.shapes || [];\n window.currentShape = window.currentShape || null;\n window.lastMousePos = window.lastMousePos || null;\n\n // Zoom state\n window.currentZoom = this.options.initialZoom;\n window.minScale = this.options.minZoom;\n window.maxScale = this.options.maxZoom;\n window.minZoom = this.options.minZoom;\n window.maxZoom = this.options.maxZoom;\n\n // ViewBox state\n window.currentViewBox = window.currentViewBox || {\n x: 0, y: 0,\n width: window.innerWidth,\n height: window.innerHeight\n };\n\n // Tool activation flags\n window.isPaintToolActive = false;\n window.isTextToolActive = false;\n window.isCircleToolActive = false;\n window.isSquareToolActive = false;\n window.isLaserToolActive = false;\n window.isEraserToolActive = false;\n window.isImageToolActive = false;\n window.isArrowToolActive = false;\n window.isLineToolActive = false;\n window.isSelectionToolActive = true;\n window.isPanningToolActive = false;\n window.isFrameToolActive = false;\n window.isIconToolActive = false;\n window.isCodeToolActive = false;\n window.isTextInCodeMode = false;\n\n // Pan state\n window.isPanning = false;\n window.panStart = null;\n window.startCanvasX = 0;\n window.startCanvasY = 0;\n\n // Transform state\n window.currentMatrix = new DOMMatrix();\n window.currentTranslation = { x: 0, y: 0 };\n\n // Action type constants\n window.ACTION_CREATE = 'create';\n window.ACTION_DELETE = 'delete';\n window.ACTION_MODIFY = 'modify';\n window.ACTION_PASTE = 'paste';\n\n // History stacks\n window.historyStack = window.historyStack || [];\n window.redoStack = window.redoStack || [];\n\n // Sidebar element stubs \u2014 React sidebars handle UI, but legacy code\n // queries these at top level. Provide dummy elements so it doesn't crash.\n const dummyEl = document.createElement('div');\n dummyEl.classList.add('hidden');\n window.paintBrushSideBar = document.getElementById('paintBrushToolBar') || dummyEl;\n window.lineSideBar = document.getElementById('lineSideBar') || dummyEl;\n window.squareSideBar = document.getElementById('squareSideBar') || dummyEl;\n window.circleSideBar = document.getElementById('circleSideBar') || dummyEl;\n window.arrowSideBar = document.getElementById('arrowSideBar') || dummyEl;\n window.textSideBar = document.getElementById('textToolBar') || dummyEl;\n window.frameSideBar = document.getElementById('frameSideBar') || dummyEl;\n\n // Zoom control element refs\n window.zoomInBtn = document.getElementById('zoomIn') || dummyEl;\n window.zoomOutBtn = document.getElementById('zoomOut') || dummyEl;\n window.zoomPercentSpan = document.getElementById('zoomPercent') || dummyEl;\n\n // Container\n window.container = document.querySelector('.container') || document.body;\n\n // Sidebar control \u2014 bridge legacy code to consumer UI\n const engine = this;\n window.disableAllSideBars = function() {\n // Hide all legacy sidebar elements\n [window.paintBrushSideBar, window.lineSideBar, window.squareSideBar,\n window.circleSideBar, window.arrowSideBar, window.textSideBar, window.frameSideBar\n ].forEach(el => { if (el) el.classList.add('hidden'); });\n // Notify consumer via onEvent + legacy bridge\n engine.emit('sidebar:clear');\n if (window.__sketchStoreApi) {\n window.__sketchStoreApi.clearSelectedShapeSidebar();\n }\n };\n\n // toolExtraPopup \u2014 legacy UI function, no-op in React\n window.toolExtraPopup = window.toolExtraPopup || function() {};\n\n // updateUndoRedoButtons \u2014 legacy UI function, no-op in React\n window.updateUndoRedoButtons = window.updateUndoRedoButtons || function() {};\n\n // Bridge for shape selection -> consumer UI\n // Maps shape.shapeName to the sidebar key\n window.__showSidebarForShape = function(shapeName) {\n const sidebarMap = {\n 'rectangle': 'rectangle',\n 'circle': 'circle',\n 'arrow': 'arrow',\n 'line': 'line',\n 'freehandStroke': 'paintbrush',\n 'text': 'text',\n 'code': 'text',\n 'frame': 'frame',\n 'image': 'image',\n };\n const sidebar = sidebarMap[shapeName];\n // Emit to consumer callback\n engine.emit('sidebar:select', { sidebar, shapeName });\n // Legacy bridge for React\n if (sidebar && window.__sketchStoreApi) {\n window.__sketchStoreApi.setSelectedShapeSidebar(sidebar);\n }\n window.__selectedShapeIsCode = (shapeName === 'code');\n if (window.__onCodeModeChanged) window.__onCodeModeChanged(shapeName === 'code');\n };\n }\n\n /**\n * Initialize engine: set globals first, then import modules.\n */\n async init() {\n if (this._initialized) return;\n\n // CRITICAL: Set up ALL globals BEFORE importing modules\n this._initGlobals();\n\n try {\n // Import shape classes first\n const [\n { Rectangle },\n { Circle },\n { Arrow },\n { Line },\n { TextShape },\n { CodeShape },\n { ImageShape },\n { IconShape },\n { Frame },\n { FreehandStroke }\n ] = await Promise.all([\n import('./shapes/Rectangle.js'),\n import('./shapes/Circle.js'),\n import('./shapes/Arrow.js'),\n import('./shapes/Line.js'),\n import('./shapes/TextShape.js'),\n import('./shapes/CodeShape.js'),\n import('./shapes/ImageShape.js'),\n import('./shapes/IconShape.js'),\n import('./shapes/Frame.js'),\n import('./shapes/FreehandStroke.js')\n ]);\n\n // Expose shape classes globally\n window.Rectangle = Rectangle;\n window.Circle = Circle;\n window.Arrow = Arrow;\n window.Line = Line;\n window.TextShape = TextShape;\n window.CodeShape = CodeShape;\n window.ImageShape = ImageShape;\n window.IconShape = IconShape;\n window.Frame = Frame;\n window.FreehandStroke = FreehandStroke;\n\n this._modules.shapes = {\n Rectangle, Circle, Arrow, Line,\n TextShape, CodeShape, ImageShape, IconShape,\n Frame, FreehandStroke\n };\n\n // Expose restore as soon as the shape constructors are ready.\n // Tool handlers, AI/graph renderers, and LixScript are not needed\n // to deserialize a cached scene, so keeping the serializer behind\n // those chunks unnecessarily delayed first canvas paint.\n const sceneSerializer = await import('./core/SceneSerializer.js');\n if (sceneSerializer.initSceneSerializer) sceneSerializer.initSceneSerializer();\n\n // Import tool handlers (they run top-level code that reads globals)\n const [\n rectangleTool, circleTool, arrowTool, lineTool,\n textTool, codeTool, imageTool, iconTool,\n frameTool, freehandTool\n ] = await Promise.all([\n import('./tools/rectangleTool.js'),\n import('./tools/circleTool.js'),\n import('./tools/arrowTool.js'),\n import('./tools/lineTool.js'),\n import('./tools/textTool.js'),\n import('./tools/codeTool.js'),\n import('./tools/imageTool.js'),\n import('./tools/iconTool.js'),\n import('./tools/frameTool.js'),\n import('./tools/freehandTool.js')\n ]);\n\n this._modules.tools = {\n rectangleTool, circleTool, arrowTool, lineTool,\n textTool, codeTool, imageTool, iconTool,\n frameTool, freehandTool\n };\n\n // Import core modules (EventDispatcher attaches SVG listeners at top level)\n const [\n eventDispatcher, undoRedo, selection,\n zoomPan, copyPaste, eraserTrail,\n resizeShapes, resizeCode\n ] = await Promise.all([\n import('./core/EventDispatcher.js'),\n import('./core/UndoRedo.js'),\n import('./core/Selection.js'),\n import('./core/ZoomPan.js'),\n import('./core/CopyPaste.js'),\n import('./core/EraserTrail.js'),\n import('./core/ResizeShapes.js'),\n import('./core/ResizeCode.js')\n ]);\n\n this._modules.core = {\n eventDispatcher, undoRedo, selection,\n zoomPan, copyPaste, eraserTrail,\n resizeShapes, resizeCode\n };\n\n // Re-bind event listeners to the current SVG element\n if (eventDispatcher.initEventDispatcher) {\n eventDispatcher.initEventDispatcher(this.svg);\n }\n\n // Import standalone tools\n await Promise.all([\n import('./tools/eraserTool.js'),\n import('./tools/laserTool.js')\n ]);\n\n // Expose key functions globally\n if (undoRedo.undo) window.undo = undoRedo.undo;\n if (undoRedo.redo) window.redo = undoRedo.redo;\n if (undoRedo.pushCreateAction) window.pushCreateAction = undoRedo.pushCreateAction;\n if (undoRedo.pushDeleteAction) window.pushDeleteAction = undoRedo.pushDeleteAction;\n if (selection.multiSelection) window.multiSelection = selection.multiSelection;\n if (selection.clearAllSelections) window.clearAllSelections = selection.clearAllSelections;\n\n // Initialize centralized copy/paste system\n if (copyPaste.initCopyPaste) copyPaste.initCopyPaste();\n\n // Initialize AI renderer bridge\n const aiRenderer = await import('./core/AIRenderer.js');\n if (aiRenderer.initAIRenderer) aiRenderer.initAIRenderer();\n\n // Initialize graph engine bridge\n const graphEngine = await import('./core/GraphEngine.js');\n if (graphEngine.initGraphEngine) graphEngine.initGraphEngine();\n\n // Initialize layer ordering\n const layerOrder = await import('./core/LayerOrder.js');\n if (layerOrder.initLayerOrder) layerOrder.initLayerOrder();\n\n // Initialize LixScript programmatic diagram engine\n const lixScript = await import('./core/LixScriptParser.js');\n if (lixScript.initLixScriptBridge) lixScript.initLixScriptBridge();\n\n // \u2500\u2500 Public API surfaces \u2500\u2500\n\n // Scene operations (save, load, export, etc.)\n this.scene = window.__sceneSerializer || {\n save: sceneSerializer.saveScene,\n load: sceneSerializer.loadScene,\n download: sceneSerializer.downloadScene,\n upload: sceneSerializer.uploadScene,\n exportPNG: sceneSerializer.exportAsPNG,\n exportPDF: sceneSerializer.exportAsPDF,\n copyAsPNG: sceneSerializer.copyAsPNG,\n copyAsSVG: sceneSerializer.copyAsSVG,\n reset: sceneSerializer.resetCanvas,\n findText: sceneSerializer.findTextOnCanvas,\n };\n\n // Shape array reference\n this.shapes = window.shapes;\n\n // Undo/redo\n this.undo = undoRedo.undo || (() => {});\n this.redo = undoRedo.redo || (() => {});\n\n // LixScript execution\n this.lixscript = {\n parse: lixScript.parseLixScript || (() => null),\n execute: lixScript.executeLixScript || (lixScript.parseLixScript ? (code) => {\n const parsed = lixScript.parseLixScript(code);\n if (parsed && lixScript.resolveShapeRefs) lixScript.resolveShapeRefs(parsed);\n return parsed;\n } : (() => null)),\n };\n\n // Store module refs for advanced consumers\n this._modules.sceneSerializer = sceneSerializer;\n this._modules.lixScript = lixScript;\n\n this._initialized = true;\n console.log('[SketchEngine] Initialized successfully');\n } catch (err) {\n console.error('[SketchEngine] Initialization failed:', err);\n throw err;\n }\n }\n\n /**\n * Sync tool flags from Zustand activeTool value.\n */\n setActiveTool(toolName) {\n // Deselect current shape when switching tools\n if (window.currentShape && typeof window.currentShape.removeSelection === 'function') {\n window.currentShape.removeSelection();\n window.currentShape = null;\n }\n if (typeof window.clearAllSelections === 'function') {\n window.clearAllSelections();\n }\n if (typeof window.disableAllSideBars === 'function') {\n window.disableAllSideBars();\n }\n\n // Force cleanup eraser trail when switching tools\n if (typeof window.forceCleanupEraserTrail === 'function') {\n window.forceCleanupEraserTrail();\n }\n // Clean up any lingering icon miniature/drag state\n if (typeof window.__cleanupIconTool === 'function') {\n window.__cleanupIconTool();\n }\n\n window.isPaintToolActive = false;\n window.isSquareToolActive = false;\n window.isCircleToolActive = false;\n window.isArrowToolActive = false;\n window.isTextToolActive = false;\n window.isLaserToolActive = false;\n window.isLineToolActive = false;\n window.isEraserToolActive = false;\n window.isSelectionToolActive = false;\n window.isImageToolActive = false;\n window.isPanningToolActive = false;\n window.isFrameToolActive = false;\n window.isIconToolActive = false;\n window.isCodeToolActive = false;\n\n const flagMap = {\n select: 'isSelectionToolActive',\n pan: 'isPanningToolActive',\n rectangle: 'isSquareToolActive',\n circle: 'isCircleToolActive',\n line: 'isLineToolActive',\n arrow: 'isArrowToolActive',\n freehand: 'isPaintToolActive',\n text: 'isTextToolActive',\n code: 'isCodeToolActive',\n eraser: 'isEraserToolActive',\n laser: 'isLaserToolActive',\n image: 'isImageToolActive',\n frame: 'isFrameToolActive',\n icon: 'isIconToolActive',\n };\n\n const flag = flagMap[toolName];\n if (flag) window[flag] = true;\n\n if (toolName === 'text' && window.isTextInCodeMode) {\n window.isCodeToolActive = true;\n }\n\n // Show image source picker when image tool is activated\n if (toolName === 'image' && window.__showImageSourcePicker) {\n window.__showImageSourcePicker();\n }\n\n // Set appropriate cursor for the active tool\n const cursorMap = {\n select: 'default',\n pan: 'grab',\n rectangle: 'crosshair',\n circle: 'crosshair',\n line: 'crosshair',\n arrow: 'crosshair',\n freehand: 'crosshair',\n text: 'crosshair',\n code: 'crosshair',\n eraser: 'crosshair',\n laser: 'crosshair',\n image: 'crosshair',\n frame: 'crosshair',\n icon: 'crosshair',\n };\n if (this.svg) {\n this.svg.style.cursor = cursorMap[toolName] || 'default';\n }\n }\n\n cleanup() {\n // Remove event listeners from the SVG element\n if (this._modules.core?.eventDispatcher?.cleanupEventDispatcher) {\n this._modules.core.eventDispatcher.cleanupEventDispatcher();\n }\n window.shapes = [];\n window.currentShape = null;\n window.lastMousePos = null;\n this._modules = {};\n this._initialized = false;\n console.log('[SketchEngine] Cleaned up');\n }\n}\n\nexport { SketchEngine };\nexport default SketchEngine;\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,8 +0,0 @@
1
- "use client";
2
- import {
3
- TextShape
4
- } from "./chunk-QXFBG7OM.js";
5
- export {
6
- TextShape
7
- };
8
- //# sourceMappingURL=TextShape-54ZJ66E3.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/shapes/TextShape.js"],
4
- "sourcesContent": ["/* eslint-disable */\n// TextShape class - extracted from writeText.js\n// Depends on globals: svg, shapes, currentShape\n\nfunction extractRotationFromTransform(el) {\n const t = el.getAttribute(\"transform\") || \"\";\n const m = t.match(/rotate\\(([^,)]+)/);\n return m ? parseFloat(m[1]) : 0;\n}\nfunction updateAttachedArrows(wrapper) {\n if (!wrapper || typeof shapes === \"undefined\") return;\n shapes.forEach(s => {\n if (s && s.shapeName === \"arrow\" && typeof s.updateAttachments === \"function\") {\n if ((s.attachedToStart && s.attachedToStart.shape === wrapper) ||\n (s.attachedToEnd && s.attachedToEnd.shape === wrapper)) {\n s.updateAttachments();\n }\n }\n });\n}\nlet isDragging = false;\nlet hoveredFrameText = null;\nlet selectedElement = null;\nfunction updateSelectionFeedback() {}\nfunction deselectElement() { selectedElement = null; }\nfunction selectElement(el) { selectedElement = el; }\n\nclass TextShape {\n constructor(groupElement) {\n this.group = groupElement;\n this.shapeName = 'text';\n this.shapeID = groupElement.getAttribute('id') || `text-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n \n // Frame attachment properties\n this.parentFrame = null;\n \n // Update group attributes \u2014 ensure data-type is set for textTool interaction\n this.group.setAttribute('type', 'text');\n this.group.setAttribute('data-type', 'text-group');\n this.group.shapeName = 'text';\n this.group.shapeID = this.shapeID;\n }\n \n // Position and dimension properties for frame compatibility\n get x() {\n const transform = this.group.transform.baseVal.consolidate();\n return transform ? transform.matrix.e : parseFloat(this.group.getAttribute('data-x')) || 0;\n }\n \n set x(value) {\n const transform = this.group.transform.baseVal.consolidate();\n const currentY = transform ? transform.matrix.f : parseFloat(this.group.getAttribute('data-y')) || 0;\n const rotation = extractRotationFromTransform(this.group) || 0;\n const textElement = this.group.querySelector('text');\n if (textElement) {\n const bbox = textElement.getBBox();\n const centerX = bbox.x + bbox.width / 2;\n const centerY = bbox.y + bbox.height / 2;\n this.group.setAttribute('transform', `translate(${value}, ${currentY}) rotate(${rotation}, ${centerX}, ${centerY})`);\n } else {\n this.group.setAttribute('transform', `translate(${value}, ${currentY})`);\n }\n this.group.setAttribute('data-x', value);\n }\n \n get y() {\n const transform = this.group.transform.baseVal.consolidate();\n return transform ? transform.matrix.f : parseFloat(this.group.getAttribute('data-y')) || 0;\n }\n \n set y(value) {\n const transform = this.group.transform.baseVal.consolidate();\n const currentX = transform ? transform.matrix.e : parseFloat(this.group.getAttribute('data-x')) || 0;\n const rotation = extractRotationFromTransform(this.group) || 0;\n const textElement = this.group.querySelector('text');\n if (textElement) {\n const bbox = textElement.getBBox();\n const centerX = bbox.x + bbox.width / 2;\n const centerY = bbox.y + bbox.height / 2;\n this.group.setAttribute('transform', `translate(${currentX}, ${value}) rotate(${rotation}, ${centerX}, ${centerY})`);\n } else {\n this.group.setAttribute('transform', `translate(${currentX}, ${value})`);\n }\n this.group.setAttribute('data-y', value);\n }\n \n get width() {\n const textElement = this.group.querySelector('text');\n if (textElement) {\n return textElement.getBBox().width;\n }\n return 0;\n }\n \n set width(value) {\n // Text width is determined by content and font size, not directly settable\n // This is here for frame compatibility but doesn't change the text\n }\n \n get height() {\n const textElement = this.group.querySelector('text');\n if (textElement) {\n return textElement.getBBox().height;\n }\n return 0;\n }\n \n set height(value) {\n // Text height is determined by content and font size, not directly settable\n // This is here for frame compatibility but doesn't change the text\n }\n \n get rotation() {\n return extractRotationFromTransform(this.group) || 0;\n }\n \n set rotation(value) {\n const currentTransform = this.group.transform.baseVal.consolidate();\n const currentX = currentTransform ? currentTransform.matrix.e : 0;\n const currentY = currentTransform ? currentTransform.matrix.f : 0;\n const textElement = this.group.querySelector('text');\n if (textElement) {\n const bbox = textElement.getBBox();\n const centerX = bbox.x + bbox.width / 2;\n const centerY = bbox.y + bbox.height / 2;\n this.group.setAttribute('transform', `translate(${currentX}, ${currentY}) rotate(${value}, ${centerX}, ${centerY})`);\n }\n }\n\n move(dx, dy) {\n const currentTransform = this.group.transform.baseVal.consolidate();\n const currentX = currentTransform ? currentTransform.matrix.e : 0;\n const currentY = currentTransform ? currentTransform.matrix.f : 0;\n\n this.x = currentX + dx;\n this.y = currentY + dy;\n\n // Only update frame containment if we're actively dragging the shape itself\n // and not being moved by a parent frame\n if (isDragging && !this.isBeingMovedByFrame) {\n this.updateFrameContainment();\n }\n\n this.updateAttachedArrows();\n }\n\n updateAttachedArrows() {\n updateAttachedArrows(this);\n }\n\n updateFrameContainment() {\n // Don't update if we're being moved by a frame\n if (this.isBeingMovedByFrame) return;\n \n let targetFrame = null;\n \n // Find which frame this shape is over\n if (typeof shapes !== 'undefined' && Array.isArray(shapes)) {\n shapes.forEach(shape => {\n if (shape.shapeName === 'frame' && shape.isShapeInFrame(this)) {\n targetFrame = shape;\n }\n });\n }\n \n // If we have a parent frame and we're being dragged, temporarily remove clipping\n if (this.parentFrame && isDragging) {\n this.parentFrame.temporarilyRemoveFromFrame(this);\n }\n \n // Update frame highlighting\n if (hoveredFrameText && hoveredFrameText !== targetFrame) {\n hoveredFrameText.removeHighlight();\n }\n \n if (targetFrame && targetFrame !== hoveredFrameText) {\n targetFrame.highlightFrame();\n }\n \n hoveredFrameText = targetFrame;\n }\n\n contains(x, y) {\n const textElement = this.group.querySelector('text');\n if (!textElement || typeof textElement.getBBox !== 'function') return false;\n\n let bbox;\n try { bbox = textElement.getBBox(); } catch { return false; }\n const padding = 8; // Selection padding\n\n const CTM = this.group.getCTM();\n if (!CTM) return false;\n \n const inverseCTM = CTM.inverse();\n const svgPoint = svg.createSVGPoint();\n svgPoint.x = x;\n svgPoint.y = y;\n const transformedPoint = svgPoint.matrixTransform(inverseCTM);\n \n return transformedPoint.x >= bbox.x - padding && \n transformedPoint.x <= bbox.x + bbox.width + padding &&\n transformedPoint.y >= bbox.y - padding && \n transformedPoint.y <= bbox.y + bbox.height + padding;\n }\n\n // Add draw method for consistency with other shapes\n draw() {\n // Text doesn't need redrawing like other shapes, but we need this method for consistency\n if (selectedElement === this.group) {\n updateSelectionFeedback();\n }\n }\n\n // Add methods for frame compatibility\n removeSelection() {\n if (selectedElement === this.group) {\n deselectElement();\n }\n }\n\n selectShape() {\n // Use the real textTool selectElement (with selection feedback) if available\n if (typeof window !== 'undefined' && window.__selectTextElement) {\n window.__selectTextElement(this.group);\n } else {\n selectElement(this.group);\n }\n }\n}\n\nexport { TextShape };\n"],
5
- "mappings": "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",
6
- "names": []
7
- }