@elixpo/lixsketch 5.5.13 → 5.5.14

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 (47) hide show
  1. package/dist/react/Circle-ZH76FPOR.js +8 -0
  2. package/dist/react/CodeShape-TE74XP5V.js +8 -0
  3. package/dist/react/{CopyPaste-VUM5WRDX.js → CopyPaste-UTU5MPKY.js} +14 -10
  4. package/dist/react/{CopyPaste-VUM5WRDX.js.map → CopyPaste-UTU5MPKY.js.map} +2 -2
  5. package/dist/react/{EventDispatcher-BZQRHROG.js → EventDispatcher-K4CNNBAU.js} +2 -2
  6. package/dist/react/FreehandStroke-BOWDNAVC.js +8 -0
  7. package/dist/react/Rectangle-2F7BAXG4.js +8 -0
  8. package/dist/react/{SceneSerializer-3RWFYSLY.js → SceneSerializer-34VQFJN7.js} +6 -6
  9. package/dist/react/{Selection-VVUHY5YJ.js → Selection-XLRY6VYO.js} +2 -2
  10. package/dist/react/{SketchEngine-WW5LIHNT.js → SketchEngine-P3XNZA56.js} +10 -10
  11. package/dist/react/TextShape-QRDG4P7F.js +8 -0
  12. package/dist/react/{chunk-42O6W7DF.js → chunk-62W6XTCZ.js} +13 -9
  13. package/dist/react/{chunk-42O6W7DF.js.map → chunk-62W6XTCZ.js.map} +2 -2
  14. package/dist/react/{chunk-AJAZC37E.js → chunk-GZ6NPDAB.js} +7 -11
  15. package/dist/react/{chunk-AJAZC37E.js.map → chunk-GZ6NPDAB.js.map} +2 -2
  16. package/dist/react/{chunk-ABZEV54U.js → chunk-HKYUJUD7.js} +12 -1
  17. package/dist/react/chunk-HKYUJUD7.js.map +7 -0
  18. package/dist/react/{chunk-Q2GA4MBZ.js → chunk-IW2NRHNK.js} +11 -2
  19. package/dist/react/{chunk-Q2GA4MBZ.js.map → chunk-IW2NRHNK.js.map} +2 -2
  20. package/dist/react/{chunk-7TZSIR6V.js → chunk-MB7VS6MK.js} +13 -9
  21. package/dist/react/{chunk-7TZSIR6V.js.map → chunk-MB7VS6MK.js.map} +2 -2
  22. package/dist/react/{chunk-T6ZVV5ZO.js → chunk-Z4YVT54E.js} +11 -9
  23. package/dist/react/{chunk-T6ZVV5ZO.js.map → chunk-Z4YVT54E.js.map} +2 -2
  24. package/dist/react/index.js +2 -2
  25. package/package.json +1 -1
  26. package/src/core/CopyPaste.js +11 -5
  27. package/src/core/Selection.js +15 -2
  28. package/src/shapes/Circle.js +8 -12
  29. package/src/shapes/CodeShape.js +17 -12
  30. package/src/shapes/FreehandStroke.js +18 -0
  31. package/src/shapes/Rectangle.js +14 -11
  32. package/src/shapes/TextShape.js +17 -12
  33. package/dist/react/Circle-KPG7TKIX.js +0 -8
  34. package/dist/react/CodeShape-K4DIZAIV.js +0 -8
  35. package/dist/react/FreehandStroke-JKTCTOKU.js +0 -8
  36. package/dist/react/Rectangle-6FE7RN6W.js +0 -8
  37. package/dist/react/TextShape-U6ZZKB35.js +0 -8
  38. package/dist/react/chunk-ABZEV54U.js.map +0 -7
  39. /package/dist/react/{Circle-KPG7TKIX.js.map → Circle-ZH76FPOR.js.map} +0 -0
  40. /package/dist/react/{CodeShape-K4DIZAIV.js.map → CodeShape-TE74XP5V.js.map} +0 -0
  41. /package/dist/react/{EventDispatcher-BZQRHROG.js.map → EventDispatcher-K4CNNBAU.js.map} +0 -0
  42. /package/dist/react/{FreehandStroke-JKTCTOKU.js.map → FreehandStroke-BOWDNAVC.js.map} +0 -0
  43. /package/dist/react/{Rectangle-6FE7RN6W.js.map → Rectangle-2F7BAXG4.js.map} +0 -0
  44. /package/dist/react/{SceneSerializer-3RWFYSLY.js.map → SceneSerializer-34VQFJN7.js.map} +0 -0
  45. /package/dist/react/{Selection-VVUHY5YJ.js.map → Selection-XLRY6VYO.js.map} +0 -0
  46. /package/dist/react/{SketchEngine-WW5LIHNT.js.map → SketchEngine-P3XNZA56.js.map} +0 -0
  47. /package/dist/react/{TextShape-U6ZZKB35.js.map → TextShape-QRDG4P7F.js.map} +0 -0
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import {
3
+ Circle
4
+ } from "./chunk-GZ6NPDAB.js";
5
+ export {
6
+ Circle
7
+ };
8
+ //# sourceMappingURL=Circle-ZH76FPOR.js.map
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import {
3
+ CodeShape
4
+ } from "./chunk-MB7VS6MK.js";
5
+ export {
6
+ CodeShape
7
+ };
8
+ //# sourceMappingURL=CodeShape-TE74XP5V.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  CodeShape
4
- } from "./chunk-7TZSIR6V.js";
4
+ } from "./chunk-MB7VS6MK.js";
5
5
  import {
6
6
  ImageShape
7
7
  } from "./chunk-CB2RANCB.js";
@@ -13,17 +13,17 @@ import {
13
13
  } from "./chunk-BU4D2WYQ.js";
14
14
  import {
15
15
  FreehandStroke
16
- } from "./chunk-ABZEV54U.js";
16
+ } from "./chunk-HKYUJUD7.js";
17
17
  import {
18
18
  compressImage,
19
19
  isAllowedImage
20
20
  } from "./chunk-DNAG7ML6.js";
21
21
  import {
22
22
  Rectangle
23
- } from "./chunk-T6ZVV5ZO.js";
23
+ } from "./chunk-Z4YVT54E.js";
24
24
  import {
25
25
  Circle
26
- } from "./chunk-AJAZC37E.js";
26
+ } from "./chunk-GZ6NPDAB.js";
27
27
  import {
28
28
  Arrow
29
29
  } from "./chunk-XISEAGBV.js";
@@ -36,7 +36,7 @@ import {
36
36
  } from "./chunk-L5OARZJ7.js";
37
37
  import {
38
38
  TextShape
39
- } from "./chunk-42O6W7DF.js";
39
+ } from "./chunk-62W6XTCZ.js";
40
40
 
41
41
  // src/core/CopyPaste.js
42
42
  var clipboard = null;
@@ -352,10 +352,14 @@ function createShapeFromData(data, offsetX, offsetY) {
352
352
  return imageShape;
353
353
  }
354
354
  case "icon": {
355
- const tempDiv = document.createElement("div");
356
- tempDiv.innerHTML = data.elementHTML;
357
- const clonedEl = tempDiv.firstElementChild;
358
- if (!clonedEl) return null;
355
+ const parser = new DOMParser();
356
+ const parsed = parser.parseFromString(
357
+ `<svg xmlns="http://www.w3.org/2000/svg">${data.elementHTML}</svg>`,
358
+ "image/svg+xml"
359
+ );
360
+ const parsedGroup = parsed.querySelector("g");
361
+ if (!parsedGroup || parsed.querySelector("parsererror")) return null;
362
+ const clonedEl = svgEl.ownerDocument.importNode(parsedGroup, true);
359
363
  const newX = data.x + offsetX;
360
364
  const newY = data.y + offsetY;
361
365
  const newID = `icon-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 1e4)}`;
@@ -566,4 +570,4 @@ export {
566
570
  initCopyPaste,
567
571
  pasteClipboard
568
572
  };
569
- //# sourceMappingURL=CopyPaste-VUM5WRDX.js.map
573
+ //# sourceMappingURL=CopyPaste-UTU5MPKY.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/core/CopyPaste.js"],
4
- "sourcesContent": ["/* eslint-disable */\n// Centralized Copy/Paste system for ALL shape types\n// Supports single and multi-selection copy/paste\n// Pastes at mouse pointer position with offset to prevent stacking\n\nimport { pushCreateAction } from './UndoRedo.js';\nimport { Rectangle } from '../shapes/Rectangle.js';\nimport { Circle } from '../shapes/Circle.js';\nimport { Line } from '../shapes/Line.js';\nimport { Arrow } from '../shapes/Arrow.js';\nimport { FreehandStroke } from '../shapes/FreehandStroke.js';\nimport { Frame } from '../shapes/Frame.js';\nimport { TextShape } from '../shapes/TextShape.js';\nimport { CodeShape } from '../shapes/CodeShape.js';\nimport { ImageShape } from '../shapes/ImageShape.js';\nimport { isAllowedImage, isAllowedImageDataUrl } from '../utils/allowedImageTypes.js';\nimport { compressImage } from '../utils/imageCompressor.js';\nimport { IconShape } from '../shapes/IconShape.js';\n\n// Clipboard storage\nlet clipboard = null; // { shapes: [...clonedData], centerX, centerY }\nlet pasteCount = 0; // Increments per paste to offset repeated pastes\n\n// Last known mouse position in SVG coordinates\nlet lastMouseSVG = { x: 0, y: 0 };\n\nfunction getSVGElement() {\n return document.getElementById('freehand-canvas');\n}\n\nfunction getSVGCoordsFromMouse(e) {\n const svgEl = getSVGElement();\n if (!svgEl) return { x: 0, y: 0 };\n const viewBox = svgEl.viewBox.baseVal;\n const rect = svgEl.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const svgX = viewBox.x + (mouseX / rect.width) * viewBox.width;\n const svgY = viewBox.y + (mouseY / rect.height) * viewBox.height;\n return { x: svgX, y: svgY };\n}\n\nfunction cloneOptions(options) {\n return JSON.parse(JSON.stringify(options));\n}\n\n// ============================================================\n// SERIALIZE: Extract copyable data from a shape\n// ============================================================\nfunction serializeShape(shape) {\n switch (shape.shapeName) {\n case 'rectangle':\n return {\n type: 'rectangle',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n options: cloneOptions(shape.options)\n };\n\n case 'circle':\n return {\n type: 'circle',\n x: shape.x,\n y: shape.y,\n rx: shape.rx,\n ry: shape.ry,\n rotation: shape.rotation,\n options: cloneOptions(shape.options)\n };\n\n case 'line':\n return {\n type: 'line',\n startPoint: { x: shape.startPoint.x, y: shape.startPoint.y },\n endPoint: { x: shape.endPoint.x, y: shape.endPoint.y },\n controlPoint: shape.controlPoint ? { x: shape.controlPoint.x, y: shape.controlPoint.y } : null,\n isCurved: shape.isCurved || false,\n options: cloneOptions(shape.options)\n };\n\n case 'arrow':\n return {\n type: 'arrow',\n startPoint: { x: shape.startPoint.x, y: shape.startPoint.y },\n endPoint: { x: shape.endPoint.x, y: shape.endPoint.y },\n controlPoint1: shape.controlPoint1 ? { x: shape.controlPoint1.x, y: shape.controlPoint1.y } : null,\n controlPoint2: shape.controlPoint2 ? { x: shape.controlPoint2.x, y: shape.controlPoint2.y } : null,\n options: cloneOptions(shape.options),\n arrowOutlineStyle: shape.arrowOutlineStyle,\n arrowHeadStyle: shape.arrowHeadStyle,\n arrowCurved: shape.arrowCurved,\n arrowCurveAmount: shape.arrowCurveAmount\n };\n\n case 'freehandStroke':\n return {\n type: 'freehandStroke',\n points: JSON.parse(JSON.stringify(shape.points)),\n rotation: shape.rotation,\n options: cloneOptions(shape.options)\n };\n\n case 'frame':\n return {\n type: 'frame',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n frameName: shape.frameName,\n options: cloneOptions(shape.options)\n };\n\n case 'text': {\n const group = shape.group;\n const textEl = group.querySelector('text');\n return {\n type: 'text',\n x: shape.x,\n y: shape.y,\n rotation: shape.rotation,\n groupHTML: group.cloneNode(true).outerHTML\n };\n }\n\n case 'code': {\n const group = shape.group;\n return {\n type: 'code',\n x: shape.x,\n y: shape.y,\n rotation: shape.rotation,\n groupHTML: group.cloneNode(true).outerHTML\n };\n }\n\n case 'image': {\n const el = shape.element;\n return {\n type: 'image',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n href: el.getAttribute('href') || el.getAttributeNS('http://www.w3.org/1999/xlink', 'href') || ''\n };\n }\n\n case 'icon': {\n const el = shape.element;\n return {\n type: 'icon',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n elementHTML: el.cloneNode(true).outerHTML,\n viewboxWidth: parseFloat(el.getAttribute('data-viewbox-width')) || 24,\n viewboxHeight: parseFloat(el.getAttribute('data-viewbox-height')) || 24\n };\n }\n\n default:\n console.warn('Copy not supported for shape type:', shape.shapeName);\n return null;\n }\n}\n\n// ============================================================\n// Get bounding center of a serialized shape\n// ============================================================\nfunction getShapeCenter(data) {\n switch (data.type) {\n case 'rectangle':\n case 'frame':\n return { x: data.x + data.width / 2, y: data.y + data.height / 2 };\n case 'circle':\n return { x: data.x, y: data.y };\n case 'line':\n return {\n x: (data.startPoint.x + data.endPoint.x) / 2,\n y: (data.startPoint.y + data.endPoint.y) / 2\n };\n case 'arrow':\n return {\n x: (data.startPoint.x + data.endPoint.x) / 2,\n y: (data.startPoint.y + data.endPoint.y) / 2\n };\n case 'freehandStroke': {\n if (!data.points.length) return { x: 0, y: 0 };\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n data.points.forEach(p => {\n if (p[0] < minX) minX = p[0];\n if (p[1] < minY) minY = p[1];\n if (p[0] > maxX) maxX = p[0];\n if (p[1] > maxY) maxY = p[1];\n });\n return { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };\n }\n case 'text':\n case 'code':\n return { x: data.x, y: data.y };\n case 'image':\n case 'icon':\n return { x: data.x + data.width / 2, y: data.y + data.height / 2 };\n default:\n return { x: 0, y: 0 };\n }\n}\n\n// ============================================================\n// DESERIALIZE: Create a new shape from copied data at offset\n// ============================================================\nfunction createShapeFromData(data, offsetX, offsetY) {\n const svgEl = getSVGElement();\n if (!svgEl) return null;\n\n switch (data.type) {\n case 'rectangle': {\n const newRect = new Rectangle(\n data.x + offsetX,\n data.y + offsetY,\n data.width,\n data.height,\n cloneOptions(data.options)\n );\n newRect.rotation = data.rotation;\n newRect.draw();\n return newRect;\n }\n\n case 'circle': {\n const newCircle = new Circle(\n data.x + offsetX,\n data.y + offsetY,\n data.rx,\n data.ry,\n cloneOptions(data.options)\n );\n newCircle.rotation = data.rotation;\n newCircle.draw();\n return newCircle;\n }\n\n case 'line': {\n const newLine = new Line(\n { x: data.startPoint.x + offsetX, y: data.startPoint.y + offsetY },\n { x: data.endPoint.x + offsetX, y: data.endPoint.y + offsetY },\n cloneOptions(data.options)\n );\n if (data.isCurved && data.controlPoint) {\n newLine.isCurved = true;\n newLine.controlPoint = { x: data.controlPoint.x + offsetX, y: data.controlPoint.y + offsetY };\n }\n newLine.draw();\n return newLine;\n }\n\n case 'arrow': {\n const opts = {\n ...cloneOptions(data.options),\n arrowOutlineStyle: data.arrowOutlineStyle,\n arrowHeadStyle: data.arrowHeadStyle,\n arrowCurved: data.arrowCurved,\n arrowCurveAmount: data.arrowCurveAmount,\n controlPoint1: data.controlPoint1 ? { x: data.controlPoint1.x + offsetX, y: data.controlPoint1.y + offsetY } : null,\n controlPoint2: data.controlPoint2 ? { x: data.controlPoint2.x + offsetX, y: data.controlPoint2.y + offsetY } : null\n };\n const newArrow = new Arrow(\n { x: data.startPoint.x + offsetX, y: data.startPoint.y + offsetY },\n { x: data.endPoint.x + offsetX, y: data.endPoint.y + offsetY },\n opts\n );\n return newArrow;\n }\n\n case 'freehandStroke': {\n const offsetPoints = data.points.map(p => [\n p[0] + offsetX,\n p[1] + offsetY,\n p[2] || 0.5\n ]);\n const newStroke = new FreehandStroke(offsetPoints, cloneOptions(data.options));\n newStroke.rotation = data.rotation;\n newStroke.draw();\n return newStroke;\n }\n\n case 'frame': {\n const newFrame = new Frame(\n data.x + offsetX,\n data.y + offsetY,\n data.width,\n data.height,\n { ...cloneOptions(data.options), frameName: data.frameName, rotation: data.rotation }\n );\n newFrame.rotation = data.rotation;\n return newFrame;\n }\n\n case 'text': {\n // Parse the cloned HTML and insert into SVG\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = data.groupHTML;\n const clonedGroup = tempDiv.firstElementChild;\n if (!clonedGroup) return null;\n\n // Generate new unique ID\n const newID = `text-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n clonedGroup.setAttribute('id', newID);\n const textChild = clonedGroup.querySelector('text');\n if (textChild) textChild.setAttribute('id', `${newID}-text`);\n\n // Update position\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n const rotation = data.rotation || 0;\n if (textChild && rotation) {\n try {\n const bbox = { x: 0, y: 0, width: 100, height: 30 }; // approximate until appended\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY}) rotate(${rotation}, ${bbox.width / 2}, ${bbox.height / 2})`);\n } catch (e) {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY})`);\n }\n } else {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY})`);\n }\n clonedGroup.setAttribute('data-x', newX);\n clonedGroup.setAttribute('data-y', newY);\n\n svgEl.appendChild(clonedGroup);\n\n const textShape = new TextShape(clonedGroup);\n return textShape;\n }\n\n case 'code': {\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = data.groupHTML;\n const clonedGroup = tempDiv.firstElementChild;\n if (!clonedGroup) return null;\n\n const newID = `code-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n clonedGroup.setAttribute('id', newID);\n const codeChild = clonedGroup.querySelector('text');\n if (codeChild) codeChild.setAttribute('id', `${newID}-code`);\n\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n const rotation = data.rotation || 0;\n if (rotation) {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY}) rotate(${rotation}, 0, 0)`);\n } else {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY})`);\n }\n clonedGroup.setAttribute('data-x', newX);\n clonedGroup.setAttribute('data-y', newY);\n\n svgEl.appendChild(clonedGroup);\n\n const codeShape = new CodeShape(clonedGroup);\n return codeShape;\n }\n\n case 'image': {\n const imgEl = document.createElementNS('http://www.w3.org/2000/svg', 'image');\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n imgEl.setAttribute('x', newX);\n imgEl.setAttribute('y', newY);\n imgEl.setAttribute('width', data.width);\n imgEl.setAttribute('height', data.height);\n imgEl.setAttribute('href', data.href);\n imgEl.setAttribute('data-shape-x', newX);\n imgEl.setAttribute('data-shape-y', newY);\n imgEl.setAttribute('data-shape-width', data.width);\n imgEl.setAttribute('data-shape-height', data.height);\n imgEl.setAttribute('preserveAspectRatio', 'none');\n imgEl.setAttribute('style', 'cursor: pointer;');\n\n // ImageShape constructor moves element into a group and appends to svg\n svgEl.appendChild(imgEl);\n const imageShape = new ImageShape(imgEl);\n imageShape.rotation = data.rotation;\n return imageShape;\n }\n\n case 'icon': {\n // Parse the cloned icon element HTML\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = data.elementHTML;\n const clonedEl = tempDiv.firstElementChild;\n if (!clonedEl) return null;\n\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n const newID = `icon-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n clonedEl.setAttribute('id', newID);\n clonedEl.setAttribute('x', newX);\n clonedEl.setAttribute('y', newY);\n clonedEl.setAttribute('data-shape-x', newX);\n clonedEl.setAttribute('data-shape-y', newY);\n clonedEl.setAttribute('data-shape-width', data.width);\n clonedEl.setAttribute('data-shape-height', data.height);\n clonedEl.setAttribute('data-shape-rotation', data.rotation);\n clonedEl.setAttribute('data-viewbox-width', data.viewboxWidth);\n clonedEl.setAttribute('data-viewbox-height', data.viewboxHeight);\n\n // Recalculate transform\n const scale = data.width / Math.max(data.viewboxWidth, data.viewboxHeight);\n const localCenterX = data.width / 2 / scale;\n const localCenterY = data.height / 2 / scale;\n clonedEl.setAttribute('transform', `translate(${newX}, ${newY}) scale(${scale}) rotate(${data.rotation}, ${localCenterX}, ${localCenterY})`);\n\n svgEl.appendChild(clonedEl);\n\n const iconShape = new IconShape(clonedEl);\n return iconShape;\n }\n\n default:\n return null;\n }\n}\n\n// ============================================================\n// COPY: Serialize currently selected shapes\n// ============================================================\nfunction copySelected() {\n const shapesToCopy = [];\n\n // Check multi-selection first\n if (window.multiSelection && window.multiSelection.selectedShapes && window.multiSelection.selectedShapes.size > 0) {\n window.multiSelection.selectedShapes.forEach(shape => {\n const data = serializeShape(shape);\n if (data) shapesToCopy.push(data);\n });\n }\n // Fall back to single currentShape\n else if (typeof currentShape !== 'undefined' && currentShape && currentShape.isSelected) {\n const data = serializeShape(currentShape);\n if (data) shapesToCopy.push(data);\n }\n\n if (shapesToCopy.length === 0) return false;\n\n // Calculate center of all copied shapes\n let totalX = 0, totalY = 0;\n shapesToCopy.forEach(d => {\n const c = getShapeCenter(d);\n totalX += c.x;\n totalY += c.y;\n });\n const centerX = totalX / shapesToCopy.length;\n const centerY = totalY / shapesToCopy.length;\n\n clipboard = {\n shapes: shapesToCopy,\n centerX,\n centerY\n };\n pasteCount = 0;\n\n return true;\n}\n\n// ============================================================\n// PASTE: Create new shapes from clipboard at mouse position\n// ============================================================\nfunction pasteClipboard() {\n if (!clipboard || clipboard.shapes.length === 0) return false;\n\n pasteCount++;\n const baseOffset = 20 * pasteCount;\n\n // Calculate paste position: center the group on the mouse pointer\n const targetX = lastMouseSVG.x;\n const targetY = lastMouseSVG.y;\n const groupOffsetX = targetX - clipboard.centerX + baseOffset;\n const groupOffsetY = targetY - clipboard.centerY + baseOffset;\n\n // Deselect all currently selected shapes\n if (typeof shapes !== 'undefined' && Array.isArray(shapes)) {\n shapes.forEach(s => {\n if (s.isSelected && typeof s.removeSelection === 'function') {\n s.removeSelection();\n s.isSelected = false;\n }\n });\n }\n if (window.multiSelection) {\n window.multiSelection.clearSelection();\n }\n if (typeof currentShape !== 'undefined') {\n currentShape = null;\n }\n if (typeof disableAllSideBars === 'function') {\n disableAllSideBars();\n }\n\n const pastedShapes = [];\n\n clipboard.shapes.forEach(data => {\n const newShape = createShapeFromData(data, groupOffsetX, groupOffsetY);\n if (newShape) {\n if (typeof shapes !== 'undefined' && Array.isArray(shapes)) {\n shapes.push(newShape);\n }\n pushCreateAction(newShape);\n pastedShapes.push(newShape);\n }\n });\n\n // Select the pasted shapes\n if (pastedShapes.length === 1) {\n const s = pastedShapes[0];\n s.isSelected = true;\n currentShape = s;\n if (typeof s.addAnchors === 'function') {\n s.addAnchors();\n } else if (typeof s.selectShape === 'function') {\n s.selectShape();\n }\n } else if (pastedShapes.length > 1 && window.multiSelection) {\n pastedShapes.forEach(s => {\n window.multiSelection.addShape(s);\n });\n window.multiSelection.updateControls();\n }\n\n return true;\n}\n\n// ============================================================\n// KEYBOARD HANDLER: Ctrl+C / Ctrl+V\n// ============================================================\nfunction handleCopyPasteKeydown(e) {\n // Don't intercept if user is typing in an input/textarea/contenteditable\n const tag = (e.target.tagName || '').toLowerCase();\n if (tag === 'input' || tag === 'textarea' || e.target.isContentEditable) return;\n\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c') {\n if (copySelected()) {\n e.preventDefault();\n }\n }\n\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v') {\n if (pasteClipboard()) {\n e.preventDefault();\n }\n }\n}\n\n// Track mouse position for paste placement\nfunction handleMouseMoveForPaste(e) {\n const svgEl = getSVGElement();\n if (!svgEl) return;\n const viewBox = svgEl.viewBox.baseVal;\n const rect = svgEl.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n lastMouseSVG.x = viewBox.x + (mouseX / rect.width) * viewBox.width;\n lastMouseSVG.y = viewBox.y + (mouseY / rect.height) * viewBox.height;\n}\n\n// ============================================================\n// PASTE IMAGE FROM CLIPBOARD (external images, screenshots)\n// ============================================================\nfunction handlePasteEvent(e) {\n // Don't intercept if user is typing\n const tag = (e.target.tagName || '').toLowerCase();\n if (tag === 'input' || tag === 'textarea' || e.target.isContentEditable) return;\n\n const items = e.clipboardData?.items;\n if (!items) return;\n\n for (const item of items) {\n if (item.type.startsWith('image/')) {\n e.preventDefault();\n const blob = item.getAsFile();\n if (!blob) return;\n\n // Validate against the canonical allowlist \u2014 clipboard sources\n // can include animated GIFs / HEIC / TIFF / arbitrary mime types.\n if (!isAllowedImage(blob)) {\n console.warn('[CopyPaste] Rejected pasted image type:', blob.type);\n return;\n }\n\n const reader = new FileReader();\n reader.onload = async (ev) => {\n const rawDataUrl = ev.target.result;\n const isSvg = (blob.type || '').toLowerCase() === 'image/svg+xml';\n let placedDataUrl = rawDataUrl;\n if (!isSvg) {\n try {\n const compressed = await compressImage(rawDataUrl);\n if (compressed?.dataUrl) placedDataUrl = compressed.dataUrl;\n } catch (err) {\n console.warn('[CopyPaste] Pre-placement compression failed, using raw:', err);\n }\n }\n placeImageFromDataUrl(placedDataUrl);\n };\n reader.readAsDataURL(blob);\n return; // only handle first image\n }\n }\n}\n\nfunction placeImageFromDataUrl(dataUrl) {\n const svgEl = getSVGElement();\n if (!svgEl || !window.ImageShape) return;\n\n const img = new Image();\n img.onload = () => {\n const aspectRatio = img.height / img.width;\n const displayW = Math.min(400, img.width);\n const displayH = displayW * aspectRatio;\n\n // Place at center of current viewport\n const vb = svgEl.viewBox.baseVal;\n const cx = vb.x + vb.width / 2;\n const cy = vb.y + vb.height / 2;\n\n const imgEl = document.createElementNS('http://www.w3.org/2000/svg', 'image');\n imgEl.setAttribute('href', dataUrl);\n imgEl.setAttribute('x', cx - displayW / 2);\n imgEl.setAttribute('y', cy - displayH / 2);\n imgEl.setAttribute('width', displayW);\n imgEl.setAttribute('height', displayH);\n imgEl.setAttribute('data-shape-x', cx - displayW / 2);\n imgEl.setAttribute('data-shape-y', cy - displayH / 2);\n imgEl.setAttribute('data-shape-width', displayW);\n imgEl.setAttribute('data-shape-height', displayH);\n imgEl.setAttribute('type', 'image');\n imgEl.setAttribute('preserveAspectRatio', 'none');\n\n svgEl.appendChild(imgEl);\n const imageShape = new ImageShape(imgEl);\n if (window.shapes) window.shapes.push(imageShape);\n if (window.pushCreateAction) window.pushCreateAction(imageShape);\n\n // Compress and upload to Cloudinary\n if (window.uploadImageToCloudinary) {\n window.uploadImageToCloudinary(imageShape);\n }\n\n console.log('[CopyPaste] Pasted image from clipboard');\n };\n img.src = dataUrl;\n}\n\n// ============================================================\n// INIT: Set up event listeners\n// ============================================================\nfunction initCopyPaste() {\n document.addEventListener('keydown', handleCopyPasteKeydown);\n document.addEventListener('pointermove', handleMouseMoveForPaste);\n document.addEventListener('paste', handlePasteEvent);\n\n // Expose for context menu\n window.copySelected = copySelected;\n window.pasteClipboard = pasteClipboard;\n}\n\nexport { initCopyPaste, copySelected, pasteClipboard };\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable */\n// Centralized Copy/Paste system for ALL shape types\n// Supports single and multi-selection copy/paste\n// Pastes at mouse pointer position with offset to prevent stacking\n\nimport { pushCreateAction } from './UndoRedo.js';\nimport { Rectangle } from '../shapes/Rectangle.js';\nimport { Circle } from '../shapes/Circle.js';\nimport { Line } from '../shapes/Line.js';\nimport { Arrow } from '../shapes/Arrow.js';\nimport { FreehandStroke } from '../shapes/FreehandStroke.js';\nimport { Frame } from '../shapes/Frame.js';\nimport { TextShape } from '../shapes/TextShape.js';\nimport { CodeShape } from '../shapes/CodeShape.js';\nimport { ImageShape } from '../shapes/ImageShape.js';\nimport { isAllowedImage, isAllowedImageDataUrl } from '../utils/allowedImageTypes.js';\nimport { compressImage } from '../utils/imageCompressor.js';\nimport { IconShape } from '../shapes/IconShape.js';\n\n// Clipboard storage\nlet clipboard = null; // { shapes: [...clonedData], centerX, centerY }\nlet pasteCount = 0; // Increments per paste to offset repeated pastes\n\n// Last known mouse position in SVG coordinates\nlet lastMouseSVG = { x: 0, y: 0 };\n\nfunction getSVGElement() {\n return document.getElementById('freehand-canvas');\n}\n\nfunction getSVGCoordsFromMouse(e) {\n const svgEl = getSVGElement();\n if (!svgEl) return { x: 0, y: 0 };\n const viewBox = svgEl.viewBox.baseVal;\n const rect = svgEl.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const svgX = viewBox.x + (mouseX / rect.width) * viewBox.width;\n const svgY = viewBox.y + (mouseY / rect.height) * viewBox.height;\n return { x: svgX, y: svgY };\n}\n\nfunction cloneOptions(options) {\n return JSON.parse(JSON.stringify(options));\n}\n\n// ============================================================\n// SERIALIZE: Extract copyable data from a shape\n// ============================================================\nfunction serializeShape(shape) {\n switch (shape.shapeName) {\n case 'rectangle':\n return {\n type: 'rectangle',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n options: cloneOptions(shape.options)\n };\n\n case 'circle':\n return {\n type: 'circle',\n x: shape.x,\n y: shape.y,\n rx: shape.rx,\n ry: shape.ry,\n rotation: shape.rotation,\n options: cloneOptions(shape.options)\n };\n\n case 'line':\n return {\n type: 'line',\n startPoint: { x: shape.startPoint.x, y: shape.startPoint.y },\n endPoint: { x: shape.endPoint.x, y: shape.endPoint.y },\n controlPoint: shape.controlPoint ? { x: shape.controlPoint.x, y: shape.controlPoint.y } : null,\n isCurved: shape.isCurved || false,\n options: cloneOptions(shape.options)\n };\n\n case 'arrow':\n return {\n type: 'arrow',\n startPoint: { x: shape.startPoint.x, y: shape.startPoint.y },\n endPoint: { x: shape.endPoint.x, y: shape.endPoint.y },\n controlPoint1: shape.controlPoint1 ? { x: shape.controlPoint1.x, y: shape.controlPoint1.y } : null,\n controlPoint2: shape.controlPoint2 ? { x: shape.controlPoint2.x, y: shape.controlPoint2.y } : null,\n options: cloneOptions(shape.options),\n arrowOutlineStyle: shape.arrowOutlineStyle,\n arrowHeadStyle: shape.arrowHeadStyle,\n arrowCurved: shape.arrowCurved,\n arrowCurveAmount: shape.arrowCurveAmount\n };\n\n case 'freehandStroke':\n return {\n type: 'freehandStroke',\n points: JSON.parse(JSON.stringify(shape.points)),\n rotation: shape.rotation,\n options: cloneOptions(shape.options)\n };\n\n case 'frame':\n return {\n type: 'frame',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n frameName: shape.frameName,\n options: cloneOptions(shape.options)\n };\n\n case 'text': {\n const group = shape.group;\n const textEl = group.querySelector('text');\n return {\n type: 'text',\n x: shape.x,\n y: shape.y,\n rotation: shape.rotation,\n groupHTML: group.cloneNode(true).outerHTML\n };\n }\n\n case 'code': {\n const group = shape.group;\n return {\n type: 'code',\n x: shape.x,\n y: shape.y,\n rotation: shape.rotation,\n groupHTML: group.cloneNode(true).outerHTML\n };\n }\n\n case 'image': {\n const el = shape.element;\n return {\n type: 'image',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n href: el.getAttribute('href') || el.getAttributeNS('http://www.w3.org/1999/xlink', 'href') || ''\n };\n }\n\n case 'icon': {\n const el = shape.element;\n return {\n type: 'icon',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n elementHTML: el.cloneNode(true).outerHTML,\n viewboxWidth: parseFloat(el.getAttribute('data-viewbox-width')) || 24,\n viewboxHeight: parseFloat(el.getAttribute('data-viewbox-height')) || 24\n };\n }\n\n default:\n console.warn('Copy not supported for shape type:', shape.shapeName);\n return null;\n }\n}\n\n// ============================================================\n// Get bounding center of a serialized shape\n// ============================================================\nfunction getShapeCenter(data) {\n switch (data.type) {\n case 'rectangle':\n case 'frame':\n return { x: data.x + data.width / 2, y: data.y + data.height / 2 };\n case 'circle':\n return { x: data.x, y: data.y };\n case 'line':\n return {\n x: (data.startPoint.x + data.endPoint.x) / 2,\n y: (data.startPoint.y + data.endPoint.y) / 2\n };\n case 'arrow':\n return {\n x: (data.startPoint.x + data.endPoint.x) / 2,\n y: (data.startPoint.y + data.endPoint.y) / 2\n };\n case 'freehandStroke': {\n if (!data.points.length) return { x: 0, y: 0 };\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n data.points.forEach(p => {\n if (p[0] < minX) minX = p[0];\n if (p[1] < minY) minY = p[1];\n if (p[0] > maxX) maxX = p[0];\n if (p[1] > maxY) maxY = p[1];\n });\n return { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };\n }\n case 'text':\n case 'code':\n return { x: data.x, y: data.y };\n case 'image':\n case 'icon':\n return { x: data.x + data.width / 2, y: data.y + data.height / 2 };\n default:\n return { x: 0, y: 0 };\n }\n}\n\n// ============================================================\n// DESERIALIZE: Create a new shape from copied data at offset\n// ============================================================\nfunction createShapeFromData(data, offsetX, offsetY) {\n const svgEl = getSVGElement();\n if (!svgEl) return null;\n\n switch (data.type) {\n case 'rectangle': {\n const newRect = new Rectangle(\n data.x + offsetX,\n data.y + offsetY,\n data.width,\n data.height,\n cloneOptions(data.options)\n );\n newRect.rotation = data.rotation;\n newRect.draw();\n return newRect;\n }\n\n case 'circle': {\n const newCircle = new Circle(\n data.x + offsetX,\n data.y + offsetY,\n data.rx,\n data.ry,\n cloneOptions(data.options)\n );\n newCircle.rotation = data.rotation;\n newCircle.draw();\n return newCircle;\n }\n\n case 'line': {\n const newLine = new Line(\n { x: data.startPoint.x + offsetX, y: data.startPoint.y + offsetY },\n { x: data.endPoint.x + offsetX, y: data.endPoint.y + offsetY },\n cloneOptions(data.options)\n );\n if (data.isCurved && data.controlPoint) {\n newLine.isCurved = true;\n newLine.controlPoint = { x: data.controlPoint.x + offsetX, y: data.controlPoint.y + offsetY };\n }\n newLine.draw();\n return newLine;\n }\n\n case 'arrow': {\n const opts = {\n ...cloneOptions(data.options),\n arrowOutlineStyle: data.arrowOutlineStyle,\n arrowHeadStyle: data.arrowHeadStyle,\n arrowCurved: data.arrowCurved,\n arrowCurveAmount: data.arrowCurveAmount,\n controlPoint1: data.controlPoint1 ? { x: data.controlPoint1.x + offsetX, y: data.controlPoint1.y + offsetY } : null,\n controlPoint2: data.controlPoint2 ? { x: data.controlPoint2.x + offsetX, y: data.controlPoint2.y + offsetY } : null\n };\n const newArrow = new Arrow(\n { x: data.startPoint.x + offsetX, y: data.startPoint.y + offsetY },\n { x: data.endPoint.x + offsetX, y: data.endPoint.y + offsetY },\n opts\n );\n return newArrow;\n }\n\n case 'freehandStroke': {\n const offsetPoints = data.points.map(p => [\n p[0] + offsetX,\n p[1] + offsetY,\n p[2] || 0.5\n ]);\n const newStroke = new FreehandStroke(offsetPoints, cloneOptions(data.options));\n newStroke.rotation = data.rotation;\n newStroke.draw();\n return newStroke;\n }\n\n case 'frame': {\n const newFrame = new Frame(\n data.x + offsetX,\n data.y + offsetY,\n data.width,\n data.height,\n { ...cloneOptions(data.options), frameName: data.frameName, rotation: data.rotation }\n );\n newFrame.rotation = data.rotation;\n return newFrame;\n }\n\n case 'text': {\n // Parse the cloned HTML and insert into SVG\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = data.groupHTML;\n const clonedGroup = tempDiv.firstElementChild;\n if (!clonedGroup) return null;\n\n // Generate new unique ID\n const newID = `text-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n clonedGroup.setAttribute('id', newID);\n const textChild = clonedGroup.querySelector('text');\n if (textChild) textChild.setAttribute('id', `${newID}-text`);\n\n // Update position\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n const rotation = data.rotation || 0;\n if (textChild && rotation) {\n try {\n const bbox = { x: 0, y: 0, width: 100, height: 30 }; // approximate until appended\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY}) rotate(${rotation}, ${bbox.width / 2}, ${bbox.height / 2})`);\n } catch (e) {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY})`);\n }\n } else {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY})`);\n }\n clonedGroup.setAttribute('data-x', newX);\n clonedGroup.setAttribute('data-y', newY);\n\n svgEl.appendChild(clonedGroup);\n\n const textShape = new TextShape(clonedGroup);\n return textShape;\n }\n\n case 'code': {\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = data.groupHTML;\n const clonedGroup = tempDiv.firstElementChild;\n if (!clonedGroup) return null;\n\n const newID = `code-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n clonedGroup.setAttribute('id', newID);\n const codeChild = clonedGroup.querySelector('text');\n if (codeChild) codeChild.setAttribute('id', `${newID}-code`);\n\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n const rotation = data.rotation || 0;\n if (rotation) {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY}) rotate(${rotation}, 0, 0)`);\n } else {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY})`);\n }\n clonedGroup.setAttribute('data-x', newX);\n clonedGroup.setAttribute('data-y', newY);\n\n svgEl.appendChild(clonedGroup);\n\n const codeShape = new CodeShape(clonedGroup);\n return codeShape;\n }\n\n case 'image': {\n const imgEl = document.createElementNS('http://www.w3.org/2000/svg', 'image');\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n imgEl.setAttribute('x', newX);\n imgEl.setAttribute('y', newY);\n imgEl.setAttribute('width', data.width);\n imgEl.setAttribute('height', data.height);\n imgEl.setAttribute('href', data.href);\n imgEl.setAttribute('data-shape-x', newX);\n imgEl.setAttribute('data-shape-y', newY);\n imgEl.setAttribute('data-shape-width', data.width);\n imgEl.setAttribute('data-shape-height', data.height);\n imgEl.setAttribute('preserveAspectRatio', 'none');\n imgEl.setAttribute('style', 'cursor: pointer;');\n\n // ImageShape constructor moves element into a group and appends to svg\n svgEl.appendChild(imgEl);\n const imageShape = new ImageShape(imgEl);\n imageShape.rotation = data.rotation;\n return imageShape;\n }\n\n case 'icon': {\n // Parse inside an SVG document. Parsing a copied <g> through an\n // HTML <div> creates it in the HTML namespace, so it can be added\n // to shapes[] but the SVG renderer will not paint it.\n const parser = new DOMParser();\n const parsed = parser.parseFromString(\n `<svg xmlns=\"http://www.w3.org/2000/svg\">${data.elementHTML}</svg>`,\n 'image/svg+xml'\n );\n const parsedGroup = parsed.querySelector('g');\n if (!parsedGroup || parsed.querySelector('parsererror')) return null;\n const clonedEl = svgEl.ownerDocument.importNode(parsedGroup, true);\n\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n const newID = `icon-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n clonedEl.setAttribute('id', newID);\n clonedEl.setAttribute('x', newX);\n clonedEl.setAttribute('y', newY);\n clonedEl.setAttribute('data-shape-x', newX);\n clonedEl.setAttribute('data-shape-y', newY);\n clonedEl.setAttribute('data-shape-width', data.width);\n clonedEl.setAttribute('data-shape-height', data.height);\n clonedEl.setAttribute('data-shape-rotation', data.rotation);\n clonedEl.setAttribute('data-viewbox-width', data.viewboxWidth);\n clonedEl.setAttribute('data-viewbox-height', data.viewboxHeight);\n\n // Recalculate transform\n const scale = data.width / Math.max(data.viewboxWidth, data.viewboxHeight);\n const localCenterX = data.width / 2 / scale;\n const localCenterY = data.height / 2 / scale;\n clonedEl.setAttribute('transform', `translate(${newX}, ${newY}) scale(${scale}) rotate(${data.rotation}, ${localCenterX}, ${localCenterY})`);\n\n svgEl.appendChild(clonedEl);\n\n const iconShape = new IconShape(clonedEl);\n return iconShape;\n }\n\n default:\n return null;\n }\n}\n\n// ============================================================\n// COPY: Serialize currently selected shapes\n// ============================================================\nfunction copySelected() {\n const shapesToCopy = [];\n\n // Check multi-selection first\n if (window.multiSelection && window.multiSelection.selectedShapes && window.multiSelection.selectedShapes.size > 0) {\n window.multiSelection.selectedShapes.forEach(shape => {\n const data = serializeShape(shape);\n if (data) shapesToCopy.push(data);\n });\n }\n // Fall back to single currentShape\n else if (typeof currentShape !== 'undefined' && currentShape && currentShape.isSelected) {\n const data = serializeShape(currentShape);\n if (data) shapesToCopy.push(data);\n }\n\n if (shapesToCopy.length === 0) return false;\n\n // Calculate center of all copied shapes\n let totalX = 0, totalY = 0;\n shapesToCopy.forEach(d => {\n const c = getShapeCenter(d);\n totalX += c.x;\n totalY += c.y;\n });\n const centerX = totalX / shapesToCopy.length;\n const centerY = totalY / shapesToCopy.length;\n\n clipboard = {\n shapes: shapesToCopy,\n centerX,\n centerY\n };\n pasteCount = 0;\n\n return true;\n}\n\n// ============================================================\n// PASTE: Create new shapes from clipboard at mouse position\n// ============================================================\nfunction pasteClipboard() {\n if (!clipboard || clipboard.shapes.length === 0) return false;\n\n pasteCount++;\n const baseOffset = 20 * pasteCount;\n\n // Calculate paste position: center the group on the mouse pointer\n const targetX = lastMouseSVG.x;\n const targetY = lastMouseSVG.y;\n const groupOffsetX = targetX - clipboard.centerX + baseOffset;\n const groupOffsetY = targetY - clipboard.centerY + baseOffset;\n\n // Deselect all currently selected shapes\n if (typeof shapes !== 'undefined' && Array.isArray(shapes)) {\n shapes.forEach(s => {\n if (s.isSelected && typeof s.removeSelection === 'function') {\n s.removeSelection();\n s.isSelected = false;\n }\n });\n }\n if (window.multiSelection) {\n window.multiSelection.clearSelection();\n }\n if (typeof currentShape !== 'undefined') {\n currentShape = null;\n }\n if (typeof disableAllSideBars === 'function') {\n disableAllSideBars();\n }\n\n const pastedShapes = [];\n\n clipboard.shapes.forEach(data => {\n const newShape = createShapeFromData(data, groupOffsetX, groupOffsetY);\n if (newShape) {\n if (typeof shapes !== 'undefined' && Array.isArray(shapes)) {\n shapes.push(newShape);\n }\n pushCreateAction(newShape);\n pastedShapes.push(newShape);\n }\n });\n\n // Select the pasted shapes\n if (pastedShapes.length === 1) {\n const s = pastedShapes[0];\n s.isSelected = true;\n currentShape = s;\n if (typeof s.addAnchors === 'function') {\n s.addAnchors();\n } else if (typeof s.selectShape === 'function') {\n s.selectShape();\n }\n } else if (pastedShapes.length > 1 && window.multiSelection) {\n pastedShapes.forEach(s => {\n window.multiSelection.addShape(s);\n });\n window.multiSelection.updateControls();\n }\n\n return true;\n}\n\n// ============================================================\n// KEYBOARD HANDLER: Ctrl+C / Ctrl+V\n// ============================================================\nfunction handleCopyPasteKeydown(e) {\n // Don't intercept if user is typing in an input/textarea/contenteditable\n const tag = (e.target.tagName || '').toLowerCase();\n if (tag === 'input' || tag === 'textarea' || e.target.isContentEditable) return;\n\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c') {\n if (copySelected()) {\n e.preventDefault();\n }\n }\n\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v') {\n if (pasteClipboard()) {\n e.preventDefault();\n }\n }\n}\n\n// Track mouse position for paste placement\nfunction handleMouseMoveForPaste(e) {\n const svgEl = getSVGElement();\n if (!svgEl) return;\n const viewBox = svgEl.viewBox.baseVal;\n const rect = svgEl.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n lastMouseSVG.x = viewBox.x + (mouseX / rect.width) * viewBox.width;\n lastMouseSVG.y = viewBox.y + (mouseY / rect.height) * viewBox.height;\n}\n\n// ============================================================\n// PASTE IMAGE FROM CLIPBOARD (external images, screenshots)\n// ============================================================\nfunction handlePasteEvent(e) {\n // Don't intercept if user is typing\n const tag = (e.target.tagName || '').toLowerCase();\n if (tag === 'input' || tag === 'textarea' || e.target.isContentEditable) return;\n\n const items = e.clipboardData?.items;\n if (!items) return;\n\n for (const item of items) {\n if (item.type.startsWith('image/')) {\n e.preventDefault();\n const blob = item.getAsFile();\n if (!blob) return;\n\n // Validate against the canonical allowlist \u2014 clipboard sources\n // can include animated GIFs / HEIC / TIFF / arbitrary mime types.\n if (!isAllowedImage(blob)) {\n console.warn('[CopyPaste] Rejected pasted image type:', blob.type);\n return;\n }\n\n const reader = new FileReader();\n reader.onload = async (ev) => {\n const rawDataUrl = ev.target.result;\n const isSvg = (blob.type || '').toLowerCase() === 'image/svg+xml';\n let placedDataUrl = rawDataUrl;\n if (!isSvg) {\n try {\n const compressed = await compressImage(rawDataUrl);\n if (compressed?.dataUrl) placedDataUrl = compressed.dataUrl;\n } catch (err) {\n console.warn('[CopyPaste] Pre-placement compression failed, using raw:', err);\n }\n }\n placeImageFromDataUrl(placedDataUrl);\n };\n reader.readAsDataURL(blob);\n return; // only handle first image\n }\n }\n}\n\nfunction placeImageFromDataUrl(dataUrl) {\n const svgEl = getSVGElement();\n if (!svgEl || !window.ImageShape) return;\n\n const img = new Image();\n img.onload = () => {\n const aspectRatio = img.height / img.width;\n const displayW = Math.min(400, img.width);\n const displayH = displayW * aspectRatio;\n\n // Place at center of current viewport\n const vb = svgEl.viewBox.baseVal;\n const cx = vb.x + vb.width / 2;\n const cy = vb.y + vb.height / 2;\n\n const imgEl = document.createElementNS('http://www.w3.org/2000/svg', 'image');\n imgEl.setAttribute('href', dataUrl);\n imgEl.setAttribute('x', cx - displayW / 2);\n imgEl.setAttribute('y', cy - displayH / 2);\n imgEl.setAttribute('width', displayW);\n imgEl.setAttribute('height', displayH);\n imgEl.setAttribute('data-shape-x', cx - displayW / 2);\n imgEl.setAttribute('data-shape-y', cy - displayH / 2);\n imgEl.setAttribute('data-shape-width', displayW);\n imgEl.setAttribute('data-shape-height', displayH);\n imgEl.setAttribute('type', 'image');\n imgEl.setAttribute('preserveAspectRatio', 'none');\n\n svgEl.appendChild(imgEl);\n const imageShape = new ImageShape(imgEl);\n if (window.shapes) window.shapes.push(imageShape);\n if (window.pushCreateAction) window.pushCreateAction(imageShape);\n\n // Compress and upload to Cloudinary\n if (window.uploadImageToCloudinary) {\n window.uploadImageToCloudinary(imageShape);\n }\n\n console.log('[CopyPaste] Pasted image from clipboard');\n };\n img.src = dataUrl;\n}\n\n// ============================================================\n// INIT: Set up event listeners\n// ============================================================\nfunction initCopyPaste() {\n document.addEventListener('keydown', handleCopyPasteKeydown);\n document.addEventListener('pointermove', handleMouseMoveForPaste);\n document.addEventListener('paste', handlePasteEvent);\n\n // Expose for context menu\n window.copySelected = copySelected;\n window.pasteClipboard = pasteClipboard;\n}\n\nexport { initCopyPaste, copySelected, pasteClipboard };\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -37,7 +37,7 @@ import {
37
37
  isMultiSelecting,
38
38
  multiSelection,
39
39
  removeMultiSelectionRect
40
- } from "./chunk-Q2GA4MBZ.js";
40
+ } from "./chunk-IW2NRHNK.js";
41
41
  import {
42
42
  handleMouseDownRect,
43
43
  handleMouseMoveRect,
@@ -460,4 +460,4 @@ export {
460
460
  handleMainMouseUp,
461
461
  initEventDispatcher
462
462
  };
463
- //# sourceMappingURL=EventDispatcher-BZQRHROG.js.map
463
+ //# sourceMappingURL=EventDispatcher-K4CNNBAU.js.map
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import {
3
+ FreehandStroke
4
+ } from "./chunk-HKYUJUD7.js";
5
+ export {
6
+ FreehandStroke
7
+ };
8
+ //# sourceMappingURL=FreehandStroke-BOWDNAVC.js.map
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import {
3
+ Rectangle
4
+ } from "./chunk-Z4YVT54E.js";
5
+ export {
6
+ Rectangle
7
+ };
8
+ //# sourceMappingURL=Rectangle-2F7BAXG4.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  CodeShape
4
- } from "./chunk-7TZSIR6V.js";
4
+ } from "./chunk-MB7VS6MK.js";
5
5
  import {
6
6
  ImageShape
7
7
  } from "./chunk-CB2RANCB.js";
@@ -13,13 +13,13 @@ import {
13
13
  } from "./chunk-BU4D2WYQ.js";
14
14
  import {
15
15
  FreehandStroke
16
- } from "./chunk-ABZEV54U.js";
16
+ } from "./chunk-HKYUJUD7.js";
17
17
  import {
18
18
  Rectangle
19
- } from "./chunk-T6ZVV5ZO.js";
19
+ } from "./chunk-Z4YVT54E.js";
20
20
  import {
21
21
  Circle
22
- } from "./chunk-AJAZC37E.js";
22
+ } from "./chunk-GZ6NPDAB.js";
23
23
  import {
24
24
  Arrow
25
25
  } from "./chunk-XISEAGBV.js";
@@ -30,7 +30,7 @@ import "./chunk-BZE4CEBG.js";
30
30
  import "./chunk-L5OARZJ7.js";
31
31
  import {
32
32
  TextShape
33
- } from "./chunk-42O6W7DF.js";
33
+ } from "./chunk-62W6XTCZ.js";
34
34
 
35
35
  // src/core/SceneSerializer.js
36
36
  var FORMAT_VERSION = 1;
@@ -736,4 +736,4 @@ export {
736
736
  uploadScene,
737
737
  validateScene
738
738
  };
739
- //# sourceMappingURL=SceneSerializer-3RWFYSLY.js.map
739
+ //# sourceMappingURL=SceneSerializer-34VQFJN7.js.map
@@ -13,7 +13,7 @@ import {
13
13
  removeMultiSelectionControls,
14
14
  removeMultiSelectionRect,
15
15
  selectShapesInRect
16
- } from "./chunk-Q2GA4MBZ.js";
16
+ } from "./chunk-IW2NRHNK.js";
17
17
  import "./chunk-BZE4CEBG.js";
18
18
  import "./chunk-L5OARZJ7.js";
19
19
  export {
@@ -31,4 +31,4 @@ export {
31
31
  removeMultiSelectionRect,
32
32
  selectShapesInRect
33
33
  };
34
- //# sourceMappingURL=Selection-VVUHY5YJ.js.map
34
+ //# sourceMappingURL=Selection-XLRY6VYO.js.map
@@ -161,16 +161,16 @@ var SketchEngine = class {
161
161
  { Frame },
162
162
  { FreehandStroke }
163
163
  ] = await Promise.all([
164
- import("./Rectangle-6FE7RN6W.js"),
165
- import("./Circle-KPG7TKIX.js"),
164
+ import("./Rectangle-2F7BAXG4.js"),
165
+ import("./Circle-ZH76FPOR.js"),
166
166
  import("./Arrow-BJDAXPMH.js"),
167
167
  import("./Line-2KOQEEGA.js"),
168
- import("./TextShape-U6ZZKB35.js"),
169
- import("./CodeShape-K4DIZAIV.js"),
168
+ import("./TextShape-QRDG4P7F.js"),
169
+ import("./CodeShape-TE74XP5V.js"),
170
170
  import("./ImageShape-CHHGBXUQ.js"),
171
171
  import("./IconShape-KMIA6T2H.js"),
172
172
  import("./Frame-6UR5XPAX.js"),
173
- import("./FreehandStroke-JKTCTOKU.js")
173
+ import("./FreehandStroke-BOWDNAVC.js")
174
174
  ]);
175
175
  window.Rectangle = Rectangle;
176
176
  window.Circle = Circle;
@@ -239,11 +239,11 @@ var SketchEngine = class {
239
239
  resizeShapes,
240
240
  resizeCode
241
241
  ] = await Promise.all([
242
- import("./EventDispatcher-BZQRHROG.js"),
242
+ import("./EventDispatcher-K4CNNBAU.js"),
243
243
  import("./UndoRedo-M2JZUBKN.js"),
244
- import("./Selection-VVUHY5YJ.js"),
244
+ import("./Selection-XLRY6VYO.js"),
245
245
  import("./ZoomPan-NYPDJBD5.js"),
246
- import("./CopyPaste-VUM5WRDX.js"),
246
+ import("./CopyPaste-UTU5MPKY.js"),
247
247
  import("./EraserTrail-PA6IQLQN.js"),
248
248
  import("./ResizeShapes-LKEQTITP.js"),
249
249
  import("./ResizeCode-WAMDTKSW.js")
@@ -262,7 +262,7 @@ var SketchEngine = class {
262
262
  eventDispatcher.initEventDispatcher(this.svg);
263
263
  }
264
264
  window.__sketchInteractionReady = true;
265
- const sceneSerializer = await import("./SceneSerializer-3RWFYSLY.js");
265
+ const sceneSerializer = await import("./SceneSerializer-34VQFJN7.js");
266
266
  if (sceneSerializer.initSceneSerializer) sceneSerializer.initSceneSerializer();
267
267
  await Promise.all([
268
268
  import("./eraserTool-2GS2LQCS.js"),
@@ -414,4 +414,4 @@ export {
414
414
  SketchEngine,
415
415
  SketchEngine_default as default
416
416
  };
417
- //# sourceMappingURL=SketchEngine-WW5LIHNT.js.map
417
+ //# sourceMappingURL=SketchEngine-P3XNZA56.js.map
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import {
3
+ TextShape
4
+ } from "./chunk-62W6XTCZ.js";
5
+ export {
6
+ TextShape
7
+ };
8
+ //# sourceMappingURL=TextShape-QRDG4P7F.js.map
@@ -172,14 +172,18 @@ var TextShape = class {
172
172
  return false;
173
173
  }
174
174
  const padding = 8;
175
- const CTM = this.group.getCTM();
176
- if (!CTM) return false;
177
- const inverseCTM = CTM.inverse();
178
- const svgPoint = svg.createSVGPoint();
179
- svgPoint.x = x;
180
- svgPoint.y = y;
181
- const transformedPoint = svgPoint.matrixTransform(inverseCTM);
182
- return transformedPoint.x >= bbox.x - padding && transformedPoint.x <= bbox.x + bbox.width + padding && transformedPoint.y >= bbox.y - padding && transformedPoint.y <= bbox.y + bbox.height + padding;
175
+ const transform = this.group.getAttribute("transform") || "";
176
+ const translate = transform.match(/translate\(\s*([^,\s)]+)[,\s]+([^\s)]+)/);
177
+ const tx = Number.isFinite(parseFloat(this.group.getAttribute("data-x"))) ? parseFloat(this.group.getAttribute("data-x")) : parseFloat(translate?.[1]) || 0;
178
+ const ty = Number.isFinite(parseFloat(this.group.getAttribute("data-y"))) ? parseFloat(this.group.getAttribute("data-y")) : parseFloat(translate?.[2]) || 0;
179
+ const centerX = bbox.x + bbox.width / 2;
180
+ const centerY = bbox.y + bbox.height / 2;
181
+ const angle = -extractRotationFromTransform(this.group) * Math.PI / 180;
182
+ const dx = x - tx - centerX;
183
+ const dy = y - ty - centerY;
184
+ const localX = dx * Math.cos(angle) - dy * Math.sin(angle) + centerX;
185
+ const localY = dx * Math.sin(angle) + dy * Math.cos(angle) + centerY;
186
+ return localX >= bbox.x - padding && localX <= bbox.x + bbox.width + padding && localY >= bbox.y - padding && localY <= bbox.y + bbox.height + padding;
183
187
  }
184
188
  // Add draw method for consistency with other shapes
185
189
  draw() {
@@ -205,4 +209,4 @@ var TextShape = class {
205
209
  export {
206
210
  TextShape
207
211
  };
208
- //# sourceMappingURL=chunk-42O6W7DF.js.map
212
+ //# sourceMappingURL=chunk-62W6XTCZ.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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\nfunction removeLegacySoftWrap(groupElement) {\n const textElement = groupElement.querySelector('text');\n if (!textElement || !textElement.hasAttribute('data-wrap-width')) return;\n const source = textElement.getAttribute('data-wrap-source');\n if (source === null) return;\n\n while (textElement.firstChild) textElement.removeChild(textElement.firstChild);\n const x = textElement.getAttribute('x') || 0;\n source.split('\\n').forEach((line, index) => {\n const tspan = textElement.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'tspan');\n tspan.setAttribute('x', x);\n tspan.setAttribute('dy', index === 0 ? '0' : '1.2em');\n tspan.textContent = line || ' ';\n textElement.appendChild(tspan);\n });\n textElement.removeAttribute('data-wrap-width');\n}\n\nclass TextShape {\n constructor(groupElement) {\n this.group = groupElement;\n removeLegacySoftWrap(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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",
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\nfunction removeLegacySoftWrap(groupElement) {\n const textElement = groupElement.querySelector('text');\n if (!textElement || !textElement.hasAttribute('data-wrap-width')) return;\n const source = textElement.getAttribute('data-wrap-source');\n if (source === null) return;\n\n while (textElement.firstChild) textElement.removeChild(textElement.firstChild);\n const x = textElement.getAttribute('x') || 0;\n source.split('\\n').forEach((line, index) => {\n const tspan = textElement.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'tspan');\n tspan.setAttribute('x', x);\n tspan.setAttribute('dy', index === 0 ? '0' : '1.2em');\n tspan.textContent = line || ' ';\n textElement.appendChild(tspan);\n });\n textElement.removeAttribute('data-wrap-width');\n}\n\nclass TextShape {\n constructor(groupElement) {\n this.group = groupElement;\n removeLegacySoftWrap(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 transform = this.group.getAttribute('transform') || '';\n const translate = transform.match(/translate\\(\\s*([^,\\s)]+)[,\\s]+([^\\s)]+)/);\n const tx = Number.isFinite(parseFloat(this.group.getAttribute('data-x')))\n ? parseFloat(this.group.getAttribute('data-x')) : parseFloat(translate?.[1]) || 0;\n const ty = Number.isFinite(parseFloat(this.group.getAttribute('data-y')))\n ? parseFloat(this.group.getAttribute('data-y')) : parseFloat(translate?.[2]) || 0;\n const centerX = bbox.x + bbox.width / 2;\n const centerY = bbox.y + bbox.height / 2;\n const angle = -extractRotationFromTransform(this.group) * Math.PI / 180;\n const dx = x - tx - centerX;\n const dy = y - ty - centerY;\n const localX = dx * Math.cos(angle) - dy * Math.sin(angle) + centerX;\n const localY = dx * Math.sin(angle) + dy * Math.cos(angle) + centerY;\n \n return localX >= bbox.x - padding &&\n localX <= bbox.x + bbox.width + padding &&\n localY >= bbox.y - padding &&\n localY <= 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
6
  "names": []
7
7
  }
@@ -358,16 +358,12 @@ var Circle = class {
358
358
  this.isSelected = false;
359
359
  }
360
360
  contains(x, y) {
361
- if (!this.element) return false;
362
- const CTM = this.group.getCTM();
363
- if (!CTM) return false;
364
- const inverseCTM = CTM.inverse();
365
- const svgPoint = svg.createSVGPoint();
366
- svgPoint.x = x;
367
- svgPoint.y = y;
368
- const transformedPoint = svgPoint.matrixTransform(inverseCTM);
369
- const dx = transformedPoint.x - 0;
370
- const dy = transformedPoint.y - 0;
361
+ if (!this.element || !this.rx || !this.ry) return false;
362
+ const angle = -(this.rotation || 0) * Math.PI / 180;
363
+ const translatedX = x - this.x;
364
+ const translatedY = y - this.y;
365
+ const dx = translatedX * Math.cos(angle) - translatedY * Math.sin(angle);
366
+ const dy = translatedX * Math.sin(angle) + translatedY * Math.cos(angle);
371
367
  const rx = this.rx;
372
368
  const ry = this.ry;
373
369
  return dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1.05;
@@ -659,4 +655,4 @@ var Circle = class {
659
655
  export {
660
656
  Circle
661
657
  };
662
- //# sourceMappingURL=chunk-AJAZC37E.js.map
658
+ //# sourceMappingURL=chunk-GZ6NPDAB.js.map