@elixpo/lixsketch 5.4.7 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react/AIRenderer-M4LMJ66J.js +1105 -0
- package/dist/react/AIRenderer-M4LMJ66J.js.map +7 -0
- package/dist/react/Arrow-BJDAXPMH.js +8 -0
- package/dist/react/Arrow-BJDAXPMH.js.map +7 -0
- package/dist/react/Circle-KPG7TKIX.js +8 -0
- package/dist/react/Circle-KPG7TKIX.js.map +7 -0
- package/dist/react/CodeShape-K4DIZAIV.js +8 -0
- package/dist/react/CodeShape-K4DIZAIV.js.map +7 -0
- package/dist/react/CopyPaste-4CKJRHJ3.js +569 -0
- package/dist/react/CopyPaste-4CKJRHJ3.js.map +7 -0
- package/dist/react/EraserTrail-PA6IQLQN.js +20 -0
- package/dist/react/EraserTrail-PA6IQLQN.js.map +7 -0
- package/dist/react/EventDispatcher-SRFH6LQZ.js +463 -0
- package/dist/react/EventDispatcher-SRFH6LQZ.js.map +7 -0
- package/dist/react/Frame-6UR5XPAX.js +10 -0
- package/dist/react/Frame-6UR5XPAX.js.map +7 -0
- package/dist/react/FreehandStroke-CK24NUT3.js +8 -0
- package/dist/react/FreehandStroke-CK24NUT3.js.map +7 -0
- package/dist/react/GraphEngine-QE5B2PMR.js +340 -0
- package/dist/react/GraphEngine-QE5B2PMR.js.map +7 -0
- package/dist/react/GraphMathParser-2WMTY4IE.js +10 -0
- package/dist/react/GraphMathParser-2WMTY4IE.js.map +7 -0
- package/dist/react/IconShape-KMIA6T2H.js +10 -0
- package/dist/react/IconShape-KMIA6T2H.js.map +7 -0
- package/dist/react/ImageShape-CHHGBXUQ.js +10 -0
- package/dist/react/ImageShape-CHHGBXUQ.js.map +7 -0
- package/dist/react/LayerOrder-XCHF4MSS.js +66 -0
- package/dist/react/LayerOrder-XCHF4MSS.js.map +7 -0
- package/dist/react/Line-2KOQEEGA.js +10 -0
- package/dist/react/Line-2KOQEEGA.js.map +7 -0
- package/dist/react/LixScriptParser-JYWJX375.js +1033 -0
- package/dist/react/LixScriptParser-JYWJX375.js.map +7 -0
- package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js +412 -0
- package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js.map +7 -0
- package/dist/react/MermaidSequenceParser-UKG2NSZY.js +8 -0
- package/dist/react/MermaidSequenceParser-UKG2NSZY.js.map +7 -0
- package/dist/react/MermaidSequenceRenderer-HPLHY5II.js +387 -0
- package/dist/react/MermaidSequenceRenderer-HPLHY5II.js.map +7 -0
- package/dist/react/Rectangle-6FE7RN6W.js +8 -0
- package/dist/react/Rectangle-6FE7RN6W.js.map +7 -0
- package/dist/react/ResizeCode-WAMDTKSW.js +2 -0
- package/dist/react/ResizeCode-WAMDTKSW.js.map +7 -0
- package/dist/react/ResizeShapes-LKEQTITP.js +250 -0
- package/dist/react/ResizeShapes-LKEQTITP.js.map +7 -0
- package/dist/react/SceneSerializer-4U4B24JM.js +739 -0
- package/dist/react/SceneSerializer-4U4B24JM.js.map +7 -0
- package/dist/react/Selection-VVUHY5YJ.js +34 -0
- package/dist/react/Selection-VVUHY5YJ.js.map +7 -0
- package/dist/react/SketchEngine-YA4RG3KX.js +413 -0
- package/dist/react/SketchEngine-YA4RG3KX.js.map +7 -0
- package/dist/react/TextShape-54ZJ66E3.js +8 -0
- package/dist/react/TextShape-54ZJ66E3.js.map +7 -0
- package/dist/react/UndoRedo-M2JZUBKN.js +30 -0
- package/dist/react/UndoRedo-M2JZUBKN.js.map +7 -0
- package/dist/react/ZoomPan-U3TXC5AJ.js +186 -0
- package/dist/react/ZoomPan-U3TXC5AJ.js.map +7 -0
- package/dist/react/arrowTool-CWEMIRXK.js +17 -0
- package/dist/react/arrowTool-CWEMIRXK.js.map +7 -0
- package/dist/react/boxicons-5JNJQPUP.woff +0 -0
- package/dist/react/boxicons-6NVWQSCQ.eot +0 -0
- package/dist/react/boxicons-AQ5N6WP7.woff2 +0 -0
- package/dist/react/boxicons-GDR4JU3X.ttf +0 -0
- package/dist/react/boxicons-NNFHLMOR.svg +1660 -0
- package/dist/react/chunk-2OQXI7QB.js +564 -0
- package/dist/react/chunk-2OQXI7QB.js.map +7 -0
- package/dist/react/chunk-5OUBTHHO.js +187 -0
- package/dist/react/chunk-5OUBTHHO.js.map +7 -0
- package/dist/react/chunk-6PFXZKL2.js +628 -0
- package/dist/react/chunk-6PFXZKL2.js.map +7 -0
- package/dist/react/chunk-6SFNWGGZ.js +453 -0
- package/dist/react/chunk-6SFNWGGZ.js.map +7 -0
- package/dist/react/chunk-7TZSIR6V.js +210 -0
- package/dist/react/chunk-7TZSIR6V.js.map +7 -0
- package/dist/react/chunk-AJAZC37E.js +662 -0
- package/dist/react/chunk-AJAZC37E.js.map +7 -0
- package/dist/react/chunk-BU4D2WYQ.js +1213 -0
- package/dist/react/chunk-BU4D2WYQ.js.map +7 -0
- package/dist/react/chunk-BZE4CEBG.js +747 -0
- package/dist/react/chunk-BZE4CEBG.js.map +7 -0
- package/dist/react/chunk-CB2RANCB.js +212 -0
- package/dist/react/chunk-CB2RANCB.js.map +7 -0
- package/dist/react/chunk-DNAG7ML6.js +128 -0
- package/dist/react/chunk-DNAG7ML6.js.map +7 -0
- package/dist/react/chunk-HZWLPXFN.js +198 -0
- package/dist/react/chunk-HZWLPXFN.js.map +7 -0
- package/dist/react/chunk-I6HCCIXB.js +572 -0
- package/dist/react/chunk-I6HCCIXB.js.map +7 -0
- package/dist/react/chunk-IZ5OGWGW.js +235 -0
- package/dist/react/chunk-IZ5OGWGW.js.map +7 -0
- package/dist/react/chunk-JJCJNLNN.js +1490 -0
- package/dist/react/chunk-JJCJNLNN.js.map +7 -0
- package/dist/react/chunk-JQ3IRFDP.js +222 -0
- package/dist/react/chunk-JQ3IRFDP.js.map +7 -0
- package/dist/react/chunk-L5OARZJ7.js +1134 -0
- package/dist/react/chunk-L5OARZJ7.js.map +7 -0
- package/dist/react/chunk-LHRTXNVE.js +1600 -0
- package/dist/react/chunk-LHRTXNVE.js.map +7 -0
- package/dist/react/chunk-Q2GA4MBZ.js +1653 -0
- package/dist/react/chunk-Q2GA4MBZ.js.map +7 -0
- package/dist/react/chunk-QNSE5BAY.js +519 -0
- package/dist/react/chunk-QNSE5BAY.js.map +7 -0
- package/dist/react/chunk-QXFBG7OM.js +191 -0
- package/dist/react/chunk-QXFBG7OM.js.map +7 -0
- package/dist/react/chunk-T6ZVV5ZO.js +714 -0
- package/dist/react/chunk-T6ZVV5ZO.js.map +7 -0
- package/dist/react/chunk-URB6MY46.js +974 -0
- package/dist/react/chunk-URB6MY46.js.map +7 -0
- package/dist/react/chunk-VN62KLOC.js +931 -0
- package/dist/react/chunk-VN62KLOC.js.map +7 -0
- package/dist/react/chunk-VQVEPJSA.js +158 -0
- package/dist/react/chunk-VQVEPJSA.js.map +7 -0
- package/dist/react/chunk-XISEAGBV.js +1632 -0
- package/dist/react/chunk-XISEAGBV.js.map +7 -0
- package/dist/react/chunk-YKJUBFHE.js +575 -0
- package/dist/react/chunk-YKJUBFHE.js.map +7 -0
- package/dist/react/circleTool-NUATSEI2.js +14 -0
- package/dist/react/circleTool-NUATSEI2.js.map +7 -0
- package/dist/react/codeTool-MHCB2FNB.js +38 -0
- package/dist/react/codeTool-MHCB2FNB.js.map +7 -0
- package/dist/react/eraserTool-2GS2LQCS.js +103 -0
- package/dist/react/eraserTool-2GS2LQCS.js.map +7 -0
- package/dist/react/frameTool-PWVKKXSP.js +14 -0
- package/dist/react/frameTool-PWVKKXSP.js.map +7 -0
- package/dist/react/freehandTool-SLYGASVP.js +14 -0
- package/dist/react/freehandTool-SLYGASVP.js.map +7 -0
- package/dist/react/iconTool-GPZ7O7NH.js +18 -0
- package/dist/react/iconTool-GPZ7O7NH.js.map +7 -0
- package/dist/react/imageTool-D5R4XGEU.js +15 -0
- package/dist/react/imageTool-D5R4XGEU.js.map +7 -0
- package/dist/react/index.js +5342 -0
- package/dist/react/index.js.map +7 -0
- package/dist/react/laserTool-XVMV63AV.js +239 -0
- package/dist/react/laserTool-XVMV63AV.js.map +7 -0
- package/dist/react/lineTool-WNI5EMZ5.js +14 -0
- package/dist/react/lineTool-WNI5EMZ5.js.map +7 -0
- package/dist/react/lixCode-OJMVUXXI.ttf +0 -0
- package/dist/react/lixDefault-JEAPAUJL.ttf +0 -0
- package/dist/react/lixFancy-BPXYM5CQ.ttf +0 -0
- package/dist/react/lixFont-CPKEUDVM.woff2 +0 -0
- package/dist/react/rectangleTool-U7DZ6ZTA.js +14 -0
- package/dist/react/rectangleTool-U7DZ6ZTA.js.map +7 -0
- package/dist/react/styles.css +6627 -0
- package/dist/react/textTool-M7S6F3VC.js +21 -0
- package/dist/react/textTool-M7S6F3VC.js.map +7 -0
- package/package.json +39 -5
- package/src/EngineShortcuts.js +83 -27
- package/src/core/AIRenderer.js +30 -18
- package/src/core/GraphEngine.js +64 -41
- package/src/core/MermaidFlowchartRenderer.js +153 -88
- package/src/core/MermaidSequenceRenderer.js +168 -93
- package/src/core/SceneSerializer.js +86 -2
- package/src/core/Selection.js +119 -19
- package/src/core/UndoRedo.js +82 -15
- package/src/core/ZoomPan.js +15 -5
- package/src/index.js +14 -1
- package/src/react/LixSketchCanvas.jsx +347 -0
- package/src/react/components/AppMenu.jsx +475 -0
- package/src/react/components/Footer.jsx +85 -0
- package/src/react/components/Toolbar.jsx +140 -0
- package/src/react/components/canvas/CanvasLoadingOverlay.jsx +76 -0
- package/src/react/components/canvas/ContextMenu.jsx +466 -0
- package/src/react/components/canvas/FindBar.jsx +177 -0
- package/src/react/components/canvas/ImageSourcePicker.jsx +133 -0
- package/src/react/components/canvas/MultiSelectActions.jsx +120 -0
- package/src/react/components/canvas/SVGCanvas.jsx +145 -0
- package/src/react/components/canvas/SaveStatusIndicator.jsx +29 -0
- package/src/react/components/modals/CanvasPropertiesModal.jsx +358 -0
- package/src/react/components/modals/CommandPalette.jsx +307 -0
- package/src/react/components/modals/ExportImageModal.jsx +287 -0
- package/src/react/components/modals/GraphModal.jsx +174 -0
- package/src/react/components/modals/HelpModal.jsx +208 -0
- package/src/react/components/modals/LixScriptModal.jsx +130 -0
- package/src/react/components/modals/ShortcutsModal.jsx +125 -0
- package/src/react/components/sidebars/ArrowSidebar.jsx +173 -0
- package/src/react/components/sidebars/CircleSidebar.jsx +134 -0
- package/src/react/components/sidebars/FrameSidebar.jsx +263 -0
- package/src/react/components/sidebars/IconSidebar.jsx +279 -0
- package/src/react/components/sidebars/ImageSidebar.jsx +69 -0
- package/src/react/components/sidebars/LineSidebar.jsx +109 -0
- package/src/react/components/sidebars/PaintbrushSidebar.jsx +119 -0
- package/src/react/components/sidebars/RectangleSidebar.jsx +165 -0
- package/src/react/components/sidebars/ShapeSidebar.jsx +130 -0
- package/src/react/components/sidebars/TextSidebar.jsx +174 -0
- package/src/react/hooks/inertStores.js +58 -0
- package/src/react/hooks/useSketchEngine.js +76 -0
- package/src/react/hooks/useTranslation.js +92 -0
- package/src/react/index.js +41 -0
- package/src/react/store/useSketchStore.js +234 -0
- package/src/react/store/useUIStore.js +196 -0
- package/src/react/styles/arrowSidebar.css +263 -0
- package/src/react/styles/canvasStroke.css +47 -0
- package/src/react/styles/canvasTools.css +769 -0
- package/src/react/styles/circleSidebar.css +206 -0
- package/src/react/styles/fonts/fonts.css +29 -0
- package/src/react/styles/fonts/lixCode.ttf +0 -0
- package/src/react/styles/fonts/lixDefault.ttf +0 -0
- package/src/react/styles/fonts/lixDocs.ttf +0 -0
- package/src/react/styles/fonts/lixFancy.ttf +0 -0
- package/src/react/styles/fonts/lixFont.woff2 +0 -0
- package/src/react/styles/lineSidebar.css +207 -0
- package/src/react/styles/paintbrushSidebar.css +247 -0
- package/src/react/styles/squareSidebar.css +206 -0
- package/src/react/styles/writeText.css +149 -0
- package/src/react/styles.css +175 -0
- package/src/react/toolsEnum.js +20 -0
- package/src/react/utils/toast.js +18 -0
- package/src/shapes/Frame.js +7 -1
- package/src/shapes/Line.js +11 -5
- package/src/tools/arrowTool.js +30 -4
- package/src/tools/circleTool.js +33 -9
- package/src/tools/codeTool.js +5 -3
- package/src/tools/frameTool.js +47 -7
- package/src/tools/freehandTool.js +12 -4
- package/src/tools/iconTool.js +7 -1
- package/src/tools/imageTool.js +7 -1
- package/src/tools/lineTool.js +27 -3
- package/src/tools/rectangleTool.js +45 -8
- package/src/tools/textTool.js +23 -6
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/core/SnapGuides.js", "../../src/tools/arrowTool.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * SnapGuides - Shows thin red alignment guides when moving shapes\n * to help users align shapes with each other and the viewport.\n */\n\nconst SNAP_THRESHOLD = 6; // pixels \u2014 how close before snapping\nconst BREAK_THRESHOLD = 12; // pixels \u2014 how far mouse must move to break free\nconst GUIDE_COLOR = '#ff4444';\nconst GUIDE_WIDTH = 1;\n\nlet guideLayer = null;\n\n// Track active snaps so we can implement break-out\nlet activeSnapX = null; // { guideValue, mouseAtSnap }\nlet activeSnapY = null;\n\nfunction ensureGuideLayer() {\n if (guideLayer && guideLayer.parentNode) return guideLayer;\n const svg = window.svg;\n if (!svg) return null;\n\n guideLayer = document.createElementNS('http://www.w3.org/2000/svg', 'g');\n guideLayer.setAttribute('id', 'snap-guides');\n guideLayer.setAttribute('pointer-events', 'none');\n svg.appendChild(guideLayer);\n return guideLayer;\n}\n\nfunction clearGuides() {\n if (guideLayer) {\n while (guideLayer.firstChild) guideLayer.removeChild(guideLayer.firstChild);\n }\n}\n\nfunction drawGuide(x1, y1, x2, y2) {\n const layer = ensureGuideLayer();\n if (!layer) return;\n\n const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n line.setAttribute('x1', x1);\n line.setAttribute('y1', y1);\n line.setAttribute('x2', x2);\n line.setAttribute('y2', y2);\n line.setAttribute('stroke', GUIDE_COLOR);\n line.setAttribute('stroke-width', GUIDE_WIDTH);\n line.setAttribute('stroke-dasharray', '4 2');\n layer.appendChild(line);\n}\n\n/**\n * Get the bounding box of a shape in canvas coordinates\n */\nfunction getShapeBounds(shape) {\n if (!shape) return null;\n\n const name = shape.shapeName;\n if (name === 'rectangle' || name === 'frame') {\n return {\n left: shape.x,\n top: shape.y,\n right: shape.x + shape.width,\n bottom: shape.y + shape.height,\n cx: shape.x + shape.width / 2,\n cy: shape.y + shape.height / 2,\n };\n }\n if (name === 'circle') {\n return {\n left: shape.x - shape.rx,\n top: shape.y - shape.ry,\n right: shape.x + shape.rx,\n bottom: shape.y + shape.ry,\n cx: shape.x,\n cy: shape.y,\n };\n }\n if (name === 'text' || name === 'code' || name === 'image' || name === 'icon') {\n const el = shape.group || shape.element;\n if (!el) return null;\n const bbox = el.getBBox();\n return {\n left: bbox.x,\n top: bbox.y,\n right: bbox.x + bbox.width,\n bottom: bbox.y + bbox.height,\n cx: bbox.x + bbox.width / 2,\n cy: bbox.y + bbox.height / 2,\n };\n }\n if (name === 'line' || name === 'arrow') {\n const sx = shape.startPoint?.x ?? 0;\n const sy = shape.startPoint?.y ?? 0;\n const ex = shape.endPoint?.x ?? 0;\n const ey = shape.endPoint?.y ?? 0;\n return {\n left: Math.min(sx, ex),\n top: Math.min(sy, ey),\n right: Math.max(sx, ex),\n bottom: Math.max(sy, ey),\n cx: (sx + ex) / 2,\n cy: (sy + ey) / 2,\n };\n }\n return null;\n}\n\n/**\n * Get the canvas viewport reference points for global alignment.\n */\nfunction getCanvasGuides() {\n const vb = window.currentViewBox;\n if (!vb) return [];\n\n return [\n { // Viewport center\n left: vb.x + vb.width / 2,\n top: vb.y + vb.height / 2,\n right: vb.x + vb.width / 2,\n bottom: vb.y + vb.height / 2,\n cx: vb.x + vb.width / 2,\n cy: vb.y + vb.height / 2,\n },\n { // Viewport edges\n left: vb.x,\n top: vb.y,\n right: vb.x + vb.width,\n bottom: vb.y + vb.height,\n cx: vb.x + vb.width / 2,\n cy: vb.y + vb.height / 2,\n },\n ];\n}\n\n/**\n * Calculate snap offsets and draw guides.\n * Returns { dx, dy } snap offset to apply.\n *\n * Uses a break-out system: once snapped, the shape stays on the guide\n * until the mouse moves BREAK_THRESHOLD away, then it breaks free.\n */\nexport function calculateSnap(movingShape, shiftKey = false, mouseX, mouseY) {\n clearGuides();\n\n const shapes = window.shapes;\n if (!shapes || !movingShape) return { dx: 0, dy: 0 };\n\n const moving = getShapeBounds(movingShape);\n if (!moving) return { dx: 0, dy: 0 };\n\n // Check if we should break out of an active snap\n if (activeSnapX && mouseX !== undefined) {\n if (Math.abs(mouseX - activeSnapX.mouseAtSnap) > BREAK_THRESHOLD) {\n activeSnapX = null;\n }\n }\n if (activeSnapY && mouseY !== undefined) {\n if (Math.abs(mouseY - activeSnapY.mouseAtSnap) > BREAK_THRESHOLD) {\n activeSnapY = null;\n }\n }\n\n let snapX = null;\n let snapY = null;\n let bestDistX = SNAP_THRESHOLD;\n let bestDistY = SNAP_THRESHOLD;\n\n const movingXs = [moving.left, moving.cx, moving.right];\n const movingYs = [moving.top, moving.cy, moving.bottom];\n\n const vb = window.currentViewBox;\n const extendY1 = vb ? vb.y : 0;\n const extendY2 = vb ? vb.y + vb.height : 10000;\n const extendX1 = vb ? vb.x : 0;\n const extendX2 = vb ? vb.x + vb.width : 10000;\n\n let otherShapeCount = 0;\n\n for (const shape of shapes) {\n if (shape === movingShape) continue;\n if (window.multiSelection && window.multiSelection.selectedShapes?.has(shape)) continue;\n\n const other = getShapeBounds(shape);\n if (!other) continue;\n otherShapeCount++;\n\n const otherXs = [other.left, other.cx, other.right];\n const otherYs = [other.top, other.cy, other.bottom];\n\n for (const mx of movingXs) {\n for (const ox of otherXs) {\n const dist = Math.abs(mx - ox);\n if (dist < bestDistX) {\n bestDistX = dist;\n snapX = { offset: ox - mx, x: ox, extendY1, extendY2 };\n }\n }\n }\n\n for (const my of movingYs) {\n for (const oy of otherYs) {\n const dist = Math.abs(my - oy);\n if (dist < bestDistY) {\n bestDistY = dist;\n snapY = { offset: oy - my, y: oy, extendX1, extendX2 };\n }\n }\n }\n }\n\n // Viewport guides when alone, no snap found, or shift held\n if (shiftKey || otherShapeCount === 0 || (!snapX && !snapY)) {\n const canvasGuides = getCanvasGuides();\n for (const guide of canvasGuides) {\n const guideXs = [guide.left, guide.cx, guide.right];\n const guideYs = [guide.top, guide.cy, guide.bottom];\n\n for (const mx of movingXs) {\n for (const gx of guideXs) {\n const dist = Math.abs(mx - gx);\n if (dist < bestDistX) {\n bestDistX = dist;\n snapX = { offset: gx - mx, x: gx, extendY1, extendY2 };\n }\n }\n }\n for (const my of movingYs) {\n for (const gy of guideYs) {\n const dist = Math.abs(my - gy);\n if (dist < bestDistY) {\n bestDistY = dist;\n snapY = { offset: gy - my, y: gy, extendX1, extendX2 };\n }\n }\n }\n }\n }\n\n let dx = 0;\n let dy = 0;\n\n // Apply X snap only if not broken out of a previous X snap\n if (snapX && !activeSnapX) {\n dx = snapX.offset;\n drawGuide(snapX.x, snapX.extendY1, snapX.x, snapX.extendY2);\n if (mouseX !== undefined) {\n activeSnapX = { guideValue: snapX.x, mouseAtSnap: mouseX };\n }\n } else if (activeSnapX) {\n // Still in an active snap \u2014 hold position by drawing guide but no offset\n drawGuide(activeSnapX.guideValue, extendY1, activeSnapX.guideValue, extendY2);\n }\n\n if (snapY && !activeSnapY) {\n dy = snapY.offset;\n drawGuide(snapY.extendX1, snapY.y, snapY.extendX2, snapY.y);\n if (mouseY !== undefined) {\n activeSnapY = { guideValue: snapY.y, mouseAtSnap: mouseY };\n }\n } else if (activeSnapY) {\n drawGuide(extendX1, activeSnapY.guideValue, extendX2, activeSnapY.guideValue);\n }\n\n return { dx, dy };\n}\n\n/**\n * Clear all snap guides and reset snap state. Call on mouseUp.\n */\nexport function clearSnapGuides() {\n clearGuides();\n activeSnapX = null;\n activeSnapY = null;\n}\n", "/* eslint-disable */\n// Arrow tool event handlers - extracted from drawArrow.js\nimport { pushCreateAction, pushDeleteAction, pushOptionsChangeAction, pushTransformAction, pushFrameAttachmentAction } from '../core/UndoRedo.js';\nimport { calculateSnap, clearSnapGuides } from '../core/SnapGuides.js';\n\n\nfunction getThemeStroke() { if (typeof document === \"undefined\") return \"#fff\"; return document.body && document.body.classList.contains(\"theme-dark\") ? \"#fff\" : \"#1a1a2e\"; }\n\nlet arrowStartX, arrowStartY;\nlet currentArrow = null;\nlet isResizing = false;\nlet isDragging = false;\nlet activeAnchor = null;\nlet isDrawingArrow = false;\nlet arrowStrokeColor = null;\nlet arrowStrokeThickness = 2;\nlet arrowOutlineStyle = \"solid\";\nlet arrowCurved = \"straight\";\nlet arrowCurveAmount = 20;\nlet arrowHeadLength = 10;\nlet arrowHeadAngleDeg = 30;\nlet arrowHeadStyle = \"default\";\nlet startX, startY;\nlet dragOldPosArrow = null;\nlet draggedShapeInitialFrameArrow = null;\nlet hoveredFrameArrow = null;\nlet arrowStrokeColorOptions = document.querySelectorAll(\".arrowStrokeSpan\");\nlet arrowStrokeThicknessValue = document.querySelectorAll(\".arrowStrokeThickSpan\");\nlet arrowOutlineStyleValue = document.querySelectorAll(\".arrowOutlineStyle\");\nlet arrowTypeStyleValue = document.querySelectorAll(\".arrowTypeStyle\");\nlet arrowHeadStyleValue = document.querySelectorAll(\".arrowHeadStyleSpan\");\nlet arrowCurveAmountOptions = document.querySelectorAll(\".arrowCurveSpan\");\n\n\nfunction getSVGCoordsFromMouse(e) {\n const viewBox = svg.viewBox.baseVal;\n const rect = svg.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 deleteCurrentShape() {\n if (currentShape && currentShape.shapeName === 'arrow') {\n const idx = shapes.indexOf(currentShape);\n if (idx !== -1) shapes.splice(idx, 1);\n if (currentShape.group.parentNode) {\n currentShape.group.parentNode.removeChild(currentShape.group);\n }\n pushDeleteAction(currentShape);\n currentShape = null;\n disableAllSideBars();\n }\n}\n\ndocument.addEventListener('keydown', (e) => {\n if (e.key === 'Delete' && currentShape && currentShape.shapeName === 'arrow') {\n deleteCurrentShape();\n }\n});\n\n\nconst handleMouseDown = (e) => {\n if (!isArrowToolActive && !isSelectionToolActive) return;\n\n const { x, y } = getSVGCoordsFromMouse(e);\n\n if (isArrowToolActive) {\n isDrawingArrow = true;\n currentArrow = new Arrow({ x, y }, { x, y }, {\n stroke: arrowStrokeColor ?? getThemeStroke(),\n strokeWidth: arrowStrokeThickness,\n arrowOutlineStyle: arrowOutlineStyle,\n arrowHeadStyle: arrowHeadStyle,\n arrowCurved: arrowCurved,\n arrowCurveAmount: arrowCurveAmount\n });\n shapes.push(currentArrow);\n currentShape = currentArrow;\n } else if (isSelectionToolActive) {\n let clickedOnShape = false;\n let clickedOnAnchor = false;\n\n if (currentShape && currentShape.shapeName === 'arrow' && currentShape.isSelected) {\n const anchorInfo = currentShape.isNearAnchor(x, y);\n if (anchorInfo && anchorInfo.type === 'anchor') {\n clickedOnAnchor = true;\n clickedOnShape = true;\n } \n if (currentShape.contains(x, y)) {\n isDragging = true;\n dragOldPosArrow = {\n startPoint: { x: currentShape.startPoint.x, y: currentShape.startPoint.y },\n endPoint: { x: currentShape.endPoint.x, y: currentShape.endPoint.y },\n controlPoint1: currentShape.controlPoint1 ? { x: currentShape.controlPoint1.x, y: currentShape.controlPoint1.y } : null,\n controlPoint2: currentShape.controlPoint2 ? { x: currentShape.controlPoint2.x, y: currentShape.controlPoint2.y } : null,\n parentFrame: currentShape.parentFrame // Add this line\n };\n \n // Store initial frame state\n draggedShapeInitialFrameArrow = currentShape.parentFrame || null;\n \n // Temporarily remove from frame clipping if dragging\n if (currentShape.parentFrame) {\n currentShape.parentFrame.temporarilyRemoveFromFrame(currentShape);\n }\n \n startX = x;\n startY = y;\n clickedOnShape = true;\n }\n }\n\n if (!clickedOnShape) {\n let shapeToSelect = null;\n\n for (let i = shapes.length - 1; i >= 0; i--) {\n const shape = shapes[i];\n if (shape instanceof Arrow && shape.contains(x, y)) {\n shapeToSelect = shape;\n break;\n }\n }\n\n if (currentShape && currentShape !== shapeToSelect) {\n currentShape.removeSelection();\n currentShape = null;\n }\n\n if (shapeToSelect) {\n currentShape = shapeToSelect;\n currentShape.selectArrow();\n\n const anchorInfo = currentShape.isNearAnchor(x, y);\n if (anchorInfo && anchorInfo.type === 'anchor') {\n clickedOnAnchor = true;\n } else {\n isDragging = true;\n dragOldPosArrow = {\n startPoint: { x: currentShape.startPoint.x, y: currentShape.startPoint.y },\n endPoint: { x: currentShape.endPoint.x, y: currentShape.endPoint.y },\n controlPoint1: currentShape.controlPoint1 ? { x: currentShape.controlPoint1.x, y: currentShape.controlPoint1.y } : null,\n controlPoint2: currentShape.controlPoint2 ? { x: currentShape.controlPoint2.x, y: currentShape.controlPoint2.y } : null\n };\n startX = x;\n startY = y;\n }\n clickedOnShape = true;\n }\n }\n\n if (!clickedOnShape && !clickedOnAnchor && currentShape) {\n currentShape.removeSelection();\n currentShape = null;\n }\n }\n};\n\n// Enhanced mouse move with better cursor feedback\nconst handleMouseMove = (e) => {\n const { x, y } = getSVGCoordsFromMouse(e);\n\n if (isDrawingArrow && currentArrow) {\n let endX = x, endY = y;\n if (e.shiftKey) {\n const dx = x - currentArrow.startPoint.x;\n const dy = y - currentArrow.startPoint.y;\n const angle = Math.atan2(dy, dx);\n const snapAngle = Math.round(angle / (Math.PI / 4)) * (Math.PI / 4);\n const dist = Math.sqrt(dx * dx + dy * dy);\n endX = currentArrow.startPoint.x + dist * Math.cos(snapAngle);\n endY = currentArrow.startPoint.y + dist * Math.sin(snapAngle);\n }\n currentArrow.endPoint = { x: endX, y: endY };\n\n // Check for potential attachment and show preview\n const nearbyShape = Arrow.findNearbyShape({ x: endX, y: endY });\n if (nearbyShape) {\n // Snap to attachment point\n currentArrow.endPoint = nearbyShape.attachment.point;\n svg.style.cursor = 'crosshair';\n\n const existingPreview = svg.querySelector('.attachment-preview');\n if (existingPreview) existingPreview.remove();\n\n const preview = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\");\n preview.setAttribute(\"cx\", nearbyShape.attachment.point.x);\n preview.setAttribute(\"cy\", nearbyShape.attachment.point.y);\n preview.setAttribute(\"r\", 6);\n preview.setAttribute(\"fill\", \"none\");\n preview.setAttribute(\"stroke\", \"#5B57D1\");\n preview.setAttribute(\"stroke-width\", 2);\n preview.setAttribute(\"class\", \"attachment-preview\");\n preview.setAttribute(\"opacity\", \"0.7\");\n svg.appendChild(preview);\n } else {\n // Remove preview if no nearby shape\n const existingPreview = svg.querySelector('.attachment-preview');\n if (existingPreview) existingPreview.remove();\n }\n\n // Check for frame containment while drawing (but don't apply clipping yet)\n shapes.forEach(frame => {\n if (frame.shapeName === 'frame') {\n if (frame.isShapeInFrame(currentArrow)) {\n frame.highlightFrame();\n hoveredFrameArrow = frame;\n } else if (hoveredFrameArrow === frame) {\n frame.removeHighlight();\n hoveredFrameArrow = null;\n }\n }\n });\n\n // Update control points for curved arrows during drawing\n if (currentArrow.arrowCurved) {\n currentArrow.initializeCurveControlPoints();\n }\n currentArrow.draw();\n }\n\n else if (isDragging && currentShape && currentShape.isSelected) {\n const dx = x - startX;\n const dy = y - startY;\n currentShape.move(dx, dy);\n startX = x;\n startY = y;\n\n // Issue #24 bug #4: track containing frame during drag of an\n // existing arrow so mouseUp re-parents correctly. Without this\n // hoveredFrameArrow stays null and the arrow is detached the\n // moment the user nudges it inside its own parent frame.\n let newHover = null;\n for (const f of shapes) {\n if (f.shapeName !== 'frame') continue;\n if (f === currentShape) continue;\n if (typeof f.isShapeInFrame === 'function' && f.isShapeInFrame(currentShape)) {\n newHover = f;\n break;\n }\n }\n if (hoveredFrameArrow && hoveredFrameArrow !== newHover && typeof hoveredFrameArrow.removeHighlight === 'function') {\n hoveredFrameArrow.removeHighlight();\n }\n if (newHover && newHover !== hoveredFrameArrow && typeof newHover.highlightFrame === 'function') {\n newHover.highlightFrame();\n }\n hoveredFrameArrow = newHover;\n\n // Snap guides\n if (window.__sketchStoreApi && window.__sketchStoreApi.getState().snapToObjects) {\n const snap = calculateSnap(currentShape, e.shiftKey, e.clientX, e.clientY);\n if (snap.dx || snap.dy) {\n currentShape.move(snap.dx, snap.dy);\n }\n } else {\n clearSnapGuides();\n }\n\n svg.style.cursor = 'grabbing';\n } else if (isSelectionToolActive && currentShape && currentShape.isSelected) {\n // Provide visual feedback when hovering over anchors or the arrow\n const anchorInfo = currentShape.isNearAnchor(x, y);\n if (anchorInfo) {\n svg.style.cursor = 'grab';\n } else if (currentShape.contains(x, y)) {\n svg.style.cursor = 'move';\n } else {\n svg.style.cursor = 'default';\n }\n } else if (isSelectionToolActive) {\n // Check if hovering over any selectable arrow\n let hoveringOverArrow = false;\n for (let i = shapes.length - 1; i >= 0; i--) {\n const shape = shapes[i];\n if (shape instanceof Arrow && shape.contains(x, y)) {\n hoveringOverArrow = true;\n break;\n }\n }\n svg.style.cursor = hoveringOverArrow ? 'pointer' : 'default';\n }\n};\n\nconst handleMouseUp = (e) => {\nif (isDrawingArrow && currentArrow) {\n // Remove any attachment preview that might still be visible\n const existingPreview = svg.querySelector('.attachment-preview');\n if (existingPreview) existingPreview.remove();\n\n // Check if arrow is too small\n const dx = currentArrow.endPoint.x - currentArrow.startPoint.x;\n const dy = currentArrow.endPoint.y - currentArrow.startPoint.y;\n const lengthSq = dx * dx + dy * dy;\n\n if (lengthSq < (5 / currentZoom) ** 2) {\n shapes.pop();\n if (currentArrow.group.parentNode) {\n currentArrow.group.parentNode.removeChild(currentArrow.group);\n }\n currentArrow = null;\n currentShape = null;\n } else {\n const startAttachment = Arrow.findNearbyShape(currentArrow.startPoint);\n const endAttachment = Arrow.findNearbyShape(currentArrow.endPoint);\n\n if (startAttachment) {\n currentArrow.attachToShape(true, startAttachment.shape, startAttachment.attachment);\n }\n\n if (endAttachment) {\n currentArrow.attachToShape(false, endAttachment.shape, endAttachment.attachment);\n }\n\n // Check for frame containment and track attachment\n const finalFrame = hoveredFrameArrow;\n if (finalFrame) {\n finalFrame.addShapeToFrame(currentArrow);\n // Track the attachment for undo\n pushFrameAttachmentAction(finalFrame, currentArrow, 'attach', null);\n }\n\n // Push create action for undo/redo\n pushCreateAction(currentArrow);\n\n // Auto-select the drawn arrow and switch to selection tool\n const drawnArrow = currentArrow;\n if (window.__sketchStoreApi) window.__sketchStoreApi.setActiveTool('select', { afterDraw: true });\n currentShape = drawnArrow;\n drawnArrow.selectArrow();\n }\n\n // Clear frame highlighting\n if (hoveredFrameArrow) {\n hoveredFrameArrow.removeHighlight();\n hoveredFrameArrow = null;\n }\n\n currentArrow = null;\n}\n\nif (isDragging && dragOldPosArrow && currentShape) {\n // Issue #34 bug #2: containment transfer happens later in this block,\n // so currentShape.parentFrame is still the OLD frame here. hoveredFrameArrow\n // tracks the actual destination during mousemove \u2014 use that as the truth.\n const newPos = {\n startPoint: { x: currentShape.startPoint.x, y: currentShape.startPoint.y },\n endPoint: { x: currentShape.endPoint.x, y: currentShape.endPoint.y },\n parentFrame: hoveredFrameArrow || null,\n };\n const oldPos = {\n ...dragOldPosArrow,\n parentFrame: draggedShapeInitialFrameArrow // Add this line\n };\n \n const stateChanged = dragOldPosArrow.startPoint.x !== newPos.startPoint.x ||\n dragOldPosArrow.startPoint.y !== newPos.startPoint.y ||\n dragOldPosArrow.endPoint.x !== newPos.endPoint.x ||\n dragOldPosArrow.endPoint.y !== newPos.endPoint.y;\n \n const frameChanged = oldPos.parentFrame !== newPos.parentFrame;\n\n if (stateChanged || frameChanged) {\n pushTransformAction(currentShape, oldPos, newPos);\n }\n \n // Handle frame containment changes after drag\n if (isDragging) {\n const finalFrame = hoveredFrameArrow;\n \n // If shape moved to a different frame\n if (draggedShapeInitialFrameArrow !== finalFrame) {\n // Remove from initial frame\n if (draggedShapeInitialFrameArrow) {\n draggedShapeInitialFrameArrow.removeShapeFromFrame(currentShape);\n }\n \n // Add to new frame\n if (finalFrame) {\n finalFrame.addShapeToFrame(currentShape);\n }\n \n // Track the frame change for undo\n if (frameChanged) {\n pushFrameAttachmentAction(finalFrame || draggedShapeInitialFrameArrow, currentShape, \n finalFrame ? 'attach' : 'detach', draggedShapeInitialFrameArrow);\n }\n } else if (draggedShapeInitialFrameArrow) {\n // Shape stayed in same frame, restore clipping\n draggedShapeInitialFrameArrow.restoreToFrame(currentShape);\n }\n }\n \n draggedShapeInitialFrameArrow = null;\n dragOldPosArrow = null;\n}\n\n// Clear frame highlighting\nif (hoveredFrameArrow) {\n hoveredFrameArrow.removeHighlight();\n hoveredFrameArrow = null;\n}\n\nclearSnapGuides();\nisDrawingArrow = false;\nisResizing = false;\nisDragging = false;\nactiveAnchor = null;\nsvg.style.cursor = 'default';\n};\n\n// Remove old event listeners and add new ones\nsvg.removeEventListener('pointerdown', handleMouseDown);\nsvg.removeEventListener('pointermove', handleMouseMove);\nsvg.removeEventListener('pointerup', handleMouseUp);\n\n\n// Updated style handlers with undo/redo support\nconst updateSelectedArrowStyle = (styleChanges) => {\n if (currentShape instanceof Arrow && currentShape.isSelected) {\n const oldOptions = {\n ...currentShape.options,\n arrowOutlineStyle: currentShape.arrowOutlineStyle,\n arrowHeadStyle: currentShape.arrowHeadStyle,\n arrowCurved: currentShape.arrowCurved,\n arrowCurveAmount: currentShape.arrowCurveAmount\n };\n currentShape.updateStyle(styleChanges);\n pushOptionsChangeAction(currentShape, oldOptions);\n } else {\n if (styleChanges.stroke !== undefined) arrowStrokeColor = styleChanges.stroke;\n if (styleChanges.strokeWidth !== undefined) arrowStrokeThickness = styleChanges.strokeWidth;\n if (styleChanges.arrowOutlineStyle !== undefined) arrowOutlineStyle = styleChanges.arrowOutlineStyle;\n if (styleChanges.arrowHeadStyle !== undefined) arrowHeadStyle = styleChanges.arrowHeadStyle;\n if (styleChanges.arrowCurved !== undefined) arrowCurved = styleChanges.arrowCurved;\n if (styleChanges.arrowCurveAmount !== undefined) arrowCurveAmount = styleChanges.arrowCurveAmount;\n }\n};\n\narrowStrokeColorOptions.forEach((span) => {\n span.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n arrowStrokeColorOptions.forEach((el) => el.classList.remove(\"selected\"));\n span.classList.add(\"selected\");\n const newColor = span.getAttribute(\"data-id\");\n updateSelectedArrowStyle({ stroke: newColor });\n });\n});\n\narrowStrokeThicknessValue.forEach((span) => {\n span.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n arrowStrokeThicknessValue.forEach((el) => el.classList.remove(\"selected\"));\n span.classList.add(\"selected\");\n const newThickness = parseInt(span.getAttribute(\"data-id\"));\n updateSelectedArrowStyle({ strokeWidth: newThickness });\n });\n});\n\narrowOutlineStyleValue.forEach((span) => {\n span.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n arrowOutlineStyleValue.forEach((el) => el.classList.remove(\"selected\"));\n span.classList.add(\"selected\");\n const newStyle = span.getAttribute(\"data-id\");\n updateSelectedArrowStyle({ arrowOutlineStyle: newStyle });\n });\n});\n\narrowTypeStyleValue.forEach((span) => {\n span.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n arrowTypeStyleValue.forEach((el) => el.classList.remove(\"selected\"));\n span.classList.add(\"selected\");\n updateSelectedArrowStyle({ arrowCurved: span.getAttribute(\"data-id\") });\n });\n});\n\narrowCurveAmountOptions.forEach((span) => {\n span.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n arrowCurveAmountOptions.forEach((el) => el.classList.remove(\"selected\"));\n span.classList.add(\"selected\");\n updateSelectedArrowStyle({ arrowCurveAmount: parseInt(span.getAttribute(\"data-id\")) });\n });\n});\n\narrowHeadStyleValue.forEach((span) => {\n span.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n arrowHeadStyleValue.forEach((el) => el.classList.remove(\"selected\"));\n span.classList.add(\"selected\");\n const newHeadStyle = span.getAttribute(\"data-id\");\n updateSelectedArrowStyle({ arrowHeadStyle: newHeadStyle });\n });\n});\n\nfunction detachSelectedArrow() {\n if (currentShape instanceof Arrow && currentShape.isSelected) {\n if (currentShape.attachedToStart || currentShape.attachedToEnd) {\n const oldState = {\n attachedToStart: currentShape.attachedToStart,\n attachedToEnd: currentShape.attachedToEnd,\n startPoint: { ...currentShape.startPoint },\n endPoint: { ...currentShape.endPoint }\n };\n\n currentShape.detachFromShape(true);\n currentShape.detachFromShape(false);\n currentShape.draw();\n\n // Add to undo/redo if needed\n }\n }\n}\n\nfunction updateAttachedArrows(shape) {\n if (!shape) return;\n\n // If a DOM element was passed (e.g. from text/code/image move), find the wrapper\n let targetShape = shape;\n if (shape.nodeType) {\n targetShape = shapes.find(s => s.group === shape || s.element === shape) || shape;\n }\n\n shapes.forEach(arrowShape => {\n if (arrowShape instanceof Arrow) {\n let needsUpdate = false;\n if (arrowShape.attachedToStart && arrowShape.attachedToStart.shape === targetShape) {\n needsUpdate = true;\n }\n if (arrowShape.attachedToEnd && arrowShape.attachedToEnd.shape === targetShape) {\n needsUpdate = true;\n }\n\n if (needsUpdate) {\n arrowShape.updateAttachments();\n }\n }\n });\n}\n\nfunction cleanupAttachments(deletedShape) {\n if (!deletedShape) return;\n\n // If a DOM element was passed, find the wrapper\n let targetShape = deletedShape;\n if (deletedShape.nodeType) {\n targetShape = shapes.find(s => s.group === deletedShape || s.element === deletedShape) || deletedShape;\n }\n\n shapes.forEach(shape => {\n if (shape instanceof Arrow) {\n let needsDraw = false;\n if (shape.attachedToStart && shape.attachedToStart.shape === targetShape) {\n shape.detachFromShape(true);\n needsDraw = true;\n }\n if (shape.attachedToEnd && shape.attachedToEnd.shape === targetShape) {\n shape.detachFromShape(false);\n needsDraw = true;\n }\n if (needsDraw) {\n shape.draw();\n }\n }\n });\n}\n\n// Add keyboard shortcut to detach arrows\ndocument.addEventListener('keydown', (e) => {\n if (e.key.toLowerCase() === 'd' && e.ctrlKey) {\n e.preventDefault();\n detachSelectedArrow();\n }\n});\n\n// Expose arrow tool settings on window for React sidebar bridge\nwindow.arrowToolSettings = {\n get strokeColor() { return arrowStrokeColor; },\n set strokeColor(v) { arrowStrokeColor = v; },\n get strokeWidth() { return arrowStrokeThickness; },\n set strokeWidth(v) { arrowStrokeThickness = v; },\n get outlineStyle() { return arrowOutlineStyle; },\n set outlineStyle(v) { arrowOutlineStyle = v; },\n get headStyle() { return arrowHeadStyle; },\n set headStyle(v) { arrowHeadStyle = v; },\n get arrowCurved() { return arrowCurved; },\n set arrowCurved(v) { arrowCurved = v; },\n get curveAmount() { return arrowCurveAmount; },\n set curveAmount(v) { arrowCurveAmount = v; },\n};\nwindow.updateSelectedArrowStyle = updateSelectedArrowStyle;\n\n// Export the cleanup function\n// Expose cleanupAttachments globally for centralized delete\nwindow.cleanupAttachments = cleanupAttachments;\n\nexport {\n handleMouseDown as handleMouseDownArrow,\n handleMouseMove as handleMouseMoveArrow,\n handleMouseUp as handleMouseUpArrow,\n cleanupAttachments,\n updateAttachedArrows\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["svg", "shapes"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
updateAttachedArrows
|
|
4
|
+
} from "./chunk-BZE4CEBG.js";
|
|
5
|
+
|
|
6
|
+
// src/shapes/ImageShape.js
|
|
7
|
+
var isDragging = false;
|
|
8
|
+
var hoveredFrameImage = null;
|
|
9
|
+
function selectImage() {
|
|
10
|
+
}
|
|
11
|
+
var ImageShape = class {
|
|
12
|
+
constructor(element) {
|
|
13
|
+
this.element = element;
|
|
14
|
+
this.shapeName = "image";
|
|
15
|
+
this.shapeID = element.shapeID || `image-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 1e4)}`;
|
|
16
|
+
this.parentFrame = null;
|
|
17
|
+
this.uploadStatus = "pending";
|
|
18
|
+
this.uploadAbortController = null;
|
|
19
|
+
this._uploadIndicator = null;
|
|
20
|
+
this.element.setAttribute("type", "image");
|
|
21
|
+
this.element.shapeID = this.shapeID;
|
|
22
|
+
this.group = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
23
|
+
this.group.setAttribute("id", this.shapeID);
|
|
24
|
+
if (this.element.parentNode) {
|
|
25
|
+
this.element.parentNode.removeChild(this.element);
|
|
26
|
+
}
|
|
27
|
+
this.group.appendChild(this.element);
|
|
28
|
+
svg.appendChild(this.group);
|
|
29
|
+
}
|
|
30
|
+
showUploadIndicator() {
|
|
31
|
+
if (this._uploadIndicator) return;
|
|
32
|
+
const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
33
|
+
g.setAttribute("class", "upload-indicator");
|
|
34
|
+
const x = this.x + 6;
|
|
35
|
+
const y = this.y + 6;
|
|
36
|
+
const bg = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
37
|
+
bg.setAttribute("cx", x + 10);
|
|
38
|
+
bg.setAttribute("cy", y + 10);
|
|
39
|
+
bg.setAttribute("r", 12);
|
|
40
|
+
bg.setAttribute("fill", "rgba(0,0,0,0.7)");
|
|
41
|
+
g.appendChild(bg);
|
|
42
|
+
const icon = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
|
|
43
|
+
icon.setAttribute("points", `${x + 10},${y + 3} ${x + 17},${y + 16} ${x + 3},${y + 16}`);
|
|
44
|
+
icon.setAttribute("fill", "none");
|
|
45
|
+
icon.setAttribute("stroke", "#FBBF24");
|
|
46
|
+
icon.setAttribute("stroke-width", "1.5");
|
|
47
|
+
icon.setAttribute("stroke-linejoin", "round");
|
|
48
|
+
g.appendChild(icon);
|
|
49
|
+
const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
50
|
+
line.setAttribute("x1", x + 10);
|
|
51
|
+
line.setAttribute("y1", y + 8);
|
|
52
|
+
line.setAttribute("x2", x + 10);
|
|
53
|
+
line.setAttribute("y2", y + 12);
|
|
54
|
+
line.setAttribute("stroke", "#FBBF24");
|
|
55
|
+
line.setAttribute("stroke-width", "1.5");
|
|
56
|
+
line.setAttribute("stroke-linecap", "round");
|
|
57
|
+
g.appendChild(line);
|
|
58
|
+
const dot = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
59
|
+
dot.setAttribute("cx", x + 10);
|
|
60
|
+
dot.setAttribute("cy", y + 14.5);
|
|
61
|
+
dot.setAttribute("r", 0.8);
|
|
62
|
+
dot.setAttribute("fill", "#FBBF24");
|
|
63
|
+
g.appendChild(dot);
|
|
64
|
+
const animate = document.createElementNS("http://www.w3.org/2000/svg", "animate");
|
|
65
|
+
animate.setAttribute("attributeName", "opacity");
|
|
66
|
+
animate.setAttribute("values", "1;0.4;1");
|
|
67
|
+
animate.setAttribute("dur", "1.5s");
|
|
68
|
+
animate.setAttribute("repeatCount", "indefinite");
|
|
69
|
+
g.appendChild(animate);
|
|
70
|
+
const transform = this.element.getAttribute("transform");
|
|
71
|
+
if (transform) g.setAttribute("transform", transform);
|
|
72
|
+
g.style.pointerEvents = "none";
|
|
73
|
+
this.group.appendChild(g);
|
|
74
|
+
this._uploadIndicator = g;
|
|
75
|
+
}
|
|
76
|
+
removeUploadIndicator() {
|
|
77
|
+
if (this._uploadIndicator && this._uploadIndicator.parentNode) {
|
|
78
|
+
this._uploadIndicator.parentNode.removeChild(this._uploadIndicator);
|
|
79
|
+
}
|
|
80
|
+
this._uploadIndicator = null;
|
|
81
|
+
}
|
|
82
|
+
updateUploadIndicatorPosition() {
|
|
83
|
+
if (!this._uploadIndicator) return;
|
|
84
|
+
const x = this.x + 6;
|
|
85
|
+
const y = this.y + 6;
|
|
86
|
+
const bg = this._uploadIndicator.querySelector("circle");
|
|
87
|
+
if (bg) {
|
|
88
|
+
bg.setAttribute("cx", x + 10);
|
|
89
|
+
bg.setAttribute("cy", y + 10);
|
|
90
|
+
}
|
|
91
|
+
const icon = this._uploadIndicator.querySelector("polygon");
|
|
92
|
+
if (icon) icon.setAttribute("points", `${x + 10},${y + 3} ${x + 17},${y + 16} ${x + 3},${y + 16}`);
|
|
93
|
+
const line = this._uploadIndicator.querySelector("line");
|
|
94
|
+
if (line) {
|
|
95
|
+
line.setAttribute("x1", x + 10);
|
|
96
|
+
line.setAttribute("y1", y + 8);
|
|
97
|
+
line.setAttribute("x2", x + 10);
|
|
98
|
+
line.setAttribute("y2", y + 12);
|
|
99
|
+
}
|
|
100
|
+
const dots = this._uploadIndicator.querySelectorAll("circle");
|
|
101
|
+
if (dots[1]) {
|
|
102
|
+
dots[1].setAttribute("cx", x + 10);
|
|
103
|
+
dots[1].setAttribute("cy", y + 14.5);
|
|
104
|
+
}
|
|
105
|
+
const transform = this.element.getAttribute("transform");
|
|
106
|
+
if (transform) this._uploadIndicator.setAttribute("transform", transform);
|
|
107
|
+
}
|
|
108
|
+
// Position and dimension properties for frame compatibility
|
|
109
|
+
get x() {
|
|
110
|
+
return parseFloat(this.element.getAttribute("x"));
|
|
111
|
+
}
|
|
112
|
+
set x(value) {
|
|
113
|
+
this.element.setAttribute("x", value);
|
|
114
|
+
this.element.setAttribute("data-shape-x", value);
|
|
115
|
+
}
|
|
116
|
+
get y() {
|
|
117
|
+
return parseFloat(this.element.getAttribute("y"));
|
|
118
|
+
}
|
|
119
|
+
set y(value) {
|
|
120
|
+
this.element.setAttribute("y", value);
|
|
121
|
+
this.element.setAttribute("data-shape-y", value);
|
|
122
|
+
}
|
|
123
|
+
get width() {
|
|
124
|
+
return parseFloat(this.element.getAttribute("width"));
|
|
125
|
+
}
|
|
126
|
+
set width(value) {
|
|
127
|
+
this.element.setAttribute("width", value);
|
|
128
|
+
this.element.setAttribute("data-shape-width", value);
|
|
129
|
+
}
|
|
130
|
+
get height() {
|
|
131
|
+
return parseFloat(this.element.getAttribute("height"));
|
|
132
|
+
}
|
|
133
|
+
set height(value) {
|
|
134
|
+
this.element.setAttribute("height", value);
|
|
135
|
+
this.element.setAttribute("data-shape-height", value);
|
|
136
|
+
}
|
|
137
|
+
get rotation() {
|
|
138
|
+
const transform = this.element.getAttribute("transform");
|
|
139
|
+
if (transform) {
|
|
140
|
+
const rotateMatch = transform.match(/rotate\(([^,]+)/);
|
|
141
|
+
if (rotateMatch) {
|
|
142
|
+
return parseFloat(rotateMatch[1]);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
set rotation(value) {
|
|
148
|
+
const centerX = this.x + this.width / 2;
|
|
149
|
+
const centerY = this.y + this.height / 2;
|
|
150
|
+
this.element.setAttribute("transform", `rotate(${value}, ${centerX}, ${centerY})`);
|
|
151
|
+
this.element.setAttribute("data-shape-rotation", value);
|
|
152
|
+
}
|
|
153
|
+
move(dx, dy) {
|
|
154
|
+
this.x += dx;
|
|
155
|
+
this.y += dy;
|
|
156
|
+
const centerX = this.x + this.width / 2;
|
|
157
|
+
const centerY = this.y + this.height / 2;
|
|
158
|
+
this.element.setAttribute("transform", `rotate(${this.rotation}, ${centerX}, ${centerY})`);
|
|
159
|
+
if (isDragging && !this.isBeingMovedByFrame) {
|
|
160
|
+
this.updateFrameContainment();
|
|
161
|
+
}
|
|
162
|
+
this.updateAttachedArrows();
|
|
163
|
+
}
|
|
164
|
+
updateAttachedArrows() {
|
|
165
|
+
updateAttachedArrows(this);
|
|
166
|
+
}
|
|
167
|
+
updateFrameContainment() {
|
|
168
|
+
if (this.isBeingMovedByFrame) return;
|
|
169
|
+
let targetFrame = null;
|
|
170
|
+
if (typeof shapes !== "undefined" && Array.isArray(shapes)) {
|
|
171
|
+
shapes.forEach((shape) => {
|
|
172
|
+
if (shape.shapeName === "frame" && shape.isShapeInFrame(this)) {
|
|
173
|
+
targetFrame = shape;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (this.parentFrame && isDragging) {
|
|
178
|
+
this.parentFrame.temporarilyRemoveFromFrame(this);
|
|
179
|
+
}
|
|
180
|
+
if (hoveredFrameImage && hoveredFrameImage !== targetFrame) {
|
|
181
|
+
hoveredFrameImage.removeHighlight();
|
|
182
|
+
}
|
|
183
|
+
if (targetFrame && targetFrame !== hoveredFrameImage) {
|
|
184
|
+
targetFrame.highlightFrame();
|
|
185
|
+
}
|
|
186
|
+
hoveredFrameImage = targetFrame;
|
|
187
|
+
}
|
|
188
|
+
contains(x, y) {
|
|
189
|
+
const imgX = this.x;
|
|
190
|
+
const imgY = this.y;
|
|
191
|
+
const imgWidth = this.width;
|
|
192
|
+
const imgHeight = this.height;
|
|
193
|
+
return x >= imgX && x <= imgX + imgWidth && y >= imgY && y <= imgY + imgHeight;
|
|
194
|
+
}
|
|
195
|
+
// Add draw method for consistency with other shapes
|
|
196
|
+
draw() {
|
|
197
|
+
}
|
|
198
|
+
// Add methods for frame compatibility
|
|
199
|
+
removeSelection() {
|
|
200
|
+
svg.querySelectorAll(".selection-outline").forEach((el) => el.remove());
|
|
201
|
+
svg.querySelectorAll(".resize-anchor, .rotation-anchor").forEach((el) => el.remove());
|
|
202
|
+
}
|
|
203
|
+
selectShape() {
|
|
204
|
+
selectImage({ target: this.element, stopPropagation: () => {
|
|
205
|
+
} });
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export {
|
|
210
|
+
ImageShape
|
|
211
|
+
};
|
|
212
|
+
//# sourceMappingURL=chunk-CB2RANCB.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/shapes/ImageShape.js"],
|
|
4
|
+
"sourcesContent": ["/* eslint-disable */\n// ImageShape class - extracted from imageTool.js\n// Depends on globals: svg, shapes, currentShape\n\nimport { updateAttachedArrows as updateArrowsForShape } from \"../tools/arrowTool.js\";\nlet isDragging = false;\nlet hoveredFrameImage = null;\nfunction selectImage() {} // stub - image selection handled by imageTool\n\nclass ImageShape {\n constructor(element) {\n this.element = element;\n this.shapeName = 'image';\n this.shapeID = element.shapeID || `image-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n\n // Frame attachment properties\n this.parentFrame = null;\n\n // Upload pipeline state\n this.uploadStatus = 'pending'; // 'pending' | 'uploading' | 'done' | 'failed'\n this.uploadAbortController = null;\n this._uploadIndicator = null;\n\n // Update element attributes\n this.element.setAttribute('type', 'image');\n this.element.shapeID = this.shapeID;\n\n // Create a group wrapper for the image to work with frames properly\n this.group = document.createElementNS('http://www.w3.org/2000/svg', 'g');\n this.group.setAttribute('id', this.shapeID);\n\n // Move the image element into the group\n if (this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.group.appendChild(this.element);\n svg.appendChild(this.group);\n }\n\n showUploadIndicator() {\n if (this._uploadIndicator) return;\n const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\n g.setAttribute('class', 'upload-indicator');\n\n const x = this.x + 6;\n const y = this.y + 6;\n\n // Background circle\n const bg = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\n bg.setAttribute('cx', x + 10);\n bg.setAttribute('cy', y + 10);\n bg.setAttribute('r', 12);\n bg.setAttribute('fill', 'rgba(0,0,0,0.7)');\n g.appendChild(bg);\n\n // Caution/loading icon (\u26A1 style triangle)\n const icon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');\n icon.setAttribute('points', `${x+10},${y+3} ${x+17},${y+16} ${x+3},${y+16}`);\n icon.setAttribute('fill', 'none');\n icon.setAttribute('stroke', '#FBBF24');\n icon.setAttribute('stroke-width', '1.5');\n icon.setAttribute('stroke-linejoin', 'round');\n g.appendChild(icon);\n\n // Exclamation mark inside\n const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n line.setAttribute('x1', x + 10);\n line.setAttribute('y1', y + 8);\n line.setAttribute('x2', x + 10);\n line.setAttribute('y2', y + 12);\n line.setAttribute('stroke', '#FBBF24');\n line.setAttribute('stroke-width', '1.5');\n line.setAttribute('stroke-linecap', 'round');\n g.appendChild(line);\n\n const dot = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\n dot.setAttribute('cx', x + 10);\n dot.setAttribute('cy', y + 14.5);\n dot.setAttribute('r', 0.8);\n dot.setAttribute('fill', '#FBBF24');\n g.appendChild(dot);\n\n // Pulsing animation\n const animate = document.createElementNS('http://www.w3.org/2000/svg', 'animate');\n animate.setAttribute('attributeName', 'opacity');\n animate.setAttribute('values', '1;0.4;1');\n animate.setAttribute('dur', '1.5s');\n animate.setAttribute('repeatCount', 'indefinite');\n g.appendChild(animate);\n\n // Apply same transform as image (rotation)\n const transform = this.element.getAttribute('transform');\n if (transform) g.setAttribute('transform', transform);\n\n g.style.pointerEvents = 'none';\n this.group.appendChild(g);\n this._uploadIndicator = g;\n }\n\n removeUploadIndicator() {\n if (this._uploadIndicator && this._uploadIndicator.parentNode) {\n this._uploadIndicator.parentNode.removeChild(this._uploadIndicator);\n }\n this._uploadIndicator = null;\n }\n\n updateUploadIndicatorPosition() {\n if (!this._uploadIndicator) return;\n const x = this.x + 6;\n const y = this.y + 6;\n\n const bg = this._uploadIndicator.querySelector('circle');\n if (bg) { bg.setAttribute('cx', x + 10); bg.setAttribute('cy', y + 10); }\n\n const icon = this._uploadIndicator.querySelector('polygon');\n if (icon) icon.setAttribute('points', `${x+10},${y+3} ${x+17},${y+16} ${x+3},${y+16}`);\n\n const line = this._uploadIndicator.querySelector('line');\n if (line) {\n line.setAttribute('x1', x + 10); line.setAttribute('y1', y + 8);\n line.setAttribute('x2', x + 10); line.setAttribute('y2', y + 12);\n }\n\n const dots = this._uploadIndicator.querySelectorAll('circle');\n if (dots[1]) { dots[1].setAttribute('cx', x + 10); dots[1].setAttribute('cy', y + 14.5); }\n\n const transform = this.element.getAttribute('transform');\n if (transform) this._uploadIndicator.setAttribute('transform', transform);\n }\n \n // Position and dimension properties for frame compatibility\n get x() {\n return parseFloat(this.element.getAttribute('x'));\n }\n \n set x(value) {\n this.element.setAttribute('x', value);\n this.element.setAttribute('data-shape-x', value);\n }\n \n get y() {\n return parseFloat(this.element.getAttribute('y'));\n }\n \n set y(value) {\n this.element.setAttribute('y', value);\n this.element.setAttribute('data-shape-y', value);\n }\n \n get width() {\n return parseFloat(this.element.getAttribute('width'));\n }\n \n set width(value) {\n this.element.setAttribute('width', value);\n this.element.setAttribute('data-shape-width', value);\n }\n \n get height() {\n return parseFloat(this.element.getAttribute('height'));\n }\n \n set height(value) {\n this.element.setAttribute('height', value);\n this.element.setAttribute('data-shape-height', value);\n }\n \n get rotation() {\n const transform = this.element.getAttribute('transform');\n if (transform) {\n const rotateMatch = transform.match(/rotate\\(([^,]+)/);\n if (rotateMatch) {\n return parseFloat(rotateMatch[1]);\n }\n }\n return 0;\n }\n \n set rotation(value) {\n const centerX = this.x + this.width / 2;\n const centerY = this.y + this.height / 2;\n this.element.setAttribute('transform', `rotate(${value}, ${centerX}, ${centerY})`);\n this.element.setAttribute('data-shape-rotation', value);\n }\n\n move(dx, dy) {\n this.x += dx;\n this.y += dy;\n\n // Update transform for rotation\n const centerX = this.x + this.width / 2;\n const centerY = this.y + this.height / 2;\n this.element.setAttribute('transform', `rotate(${this.rotation}, ${centerX}, ${centerY})`);\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 updateArrowsForShape(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 (hoveredFrameImage && hoveredFrameImage !== targetFrame) {\n hoveredFrameImage.removeHighlight();\n }\n \n if (targetFrame && targetFrame !== hoveredFrameImage) {\n targetFrame.highlightFrame();\n }\n \n hoveredFrameImage = targetFrame;\n }\n\n contains(x, y) {\n const imgX = this.x;\n const imgY = this.y;\n const imgWidth = this.width;\n const imgHeight = this.height;\n \n // Simple bounding box check (could be enhanced for rotation)\n return x >= imgX && x <= imgX + imgWidth && y >= imgY && y <= imgY + imgHeight;\n }\n\n // Add draw method for consistency with other shapes\n draw() {\n // Images don't need redrawing like other shapes, but we need this method for consistency\n // Update any visual state if needed\n }\n\n // Add methods for frame compatibility\n removeSelection() {\n // Remove selection outlines from SVG\n svg.querySelectorAll(\".selection-outline\").forEach(el => el.remove());\n // Remove resize/rotation anchors if present\n svg.querySelectorAll(\".resize-anchor, .rotation-anchor\").forEach(el => el.remove());\n }\n\n selectShape() {\n // Select the image\n selectImage({ target: this.element, stopPropagation: () => {} });\n }\n}\n\nexport { ImageShape };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/utils/imageCompressor.js
|
|
4
|
+
var MAX_DIMENSION = 1920;
|
|
5
|
+
var TARGET_SIZE_BYTES = 300 * 1024;
|
|
6
|
+
var MIN_QUALITY = 0.4;
|
|
7
|
+
async function compressImage(dataUrl, { maxWidth = MAX_DIMENSION, quality = 0.8 } = {}) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const img = new Image();
|
|
10
|
+
img.onload = () => {
|
|
11
|
+
try {
|
|
12
|
+
const originalSize = Math.ceil(dataUrl.length * 0.75);
|
|
13
|
+
let w = img.width;
|
|
14
|
+
let h = img.height;
|
|
15
|
+
if (w > maxWidth) {
|
|
16
|
+
const ratio = maxWidth / w;
|
|
17
|
+
w = maxWidth;
|
|
18
|
+
h = Math.round(h * ratio);
|
|
19
|
+
}
|
|
20
|
+
const canvas = document.createElement("canvas");
|
|
21
|
+
canvas.width = w;
|
|
22
|
+
canvas.height = h;
|
|
23
|
+
const ctx = canvas.getContext("2d");
|
|
24
|
+
ctx.drawImage(img, 0, 0, w, h);
|
|
25
|
+
const hasAlpha = detectAlpha(ctx, w, h);
|
|
26
|
+
const mimeType = hasAlpha ? "image/png" : "image/jpeg";
|
|
27
|
+
if (mimeType === "image/jpeg") {
|
|
28
|
+
let currentQuality = quality;
|
|
29
|
+
let result = canvas.toDataURL(mimeType, currentQuality);
|
|
30
|
+
let resultSize = Math.ceil(result.length * 0.75);
|
|
31
|
+
while (resultSize > TARGET_SIZE_BYTES && currentQuality > MIN_QUALITY) {
|
|
32
|
+
currentQuality -= 0.1;
|
|
33
|
+
result = canvas.toDataURL(mimeType, currentQuality);
|
|
34
|
+
resultSize = Math.ceil(result.length * 0.75);
|
|
35
|
+
}
|
|
36
|
+
canvas.toBlob((blob) => {
|
|
37
|
+
resolve({
|
|
38
|
+
dataUrl: result,
|
|
39
|
+
blob,
|
|
40
|
+
width: w,
|
|
41
|
+
height: h,
|
|
42
|
+
originalSize,
|
|
43
|
+
compressedSize: blob.size
|
|
44
|
+
});
|
|
45
|
+
}, mimeType, currentQuality);
|
|
46
|
+
} else {
|
|
47
|
+
const result = canvas.toDataURL(mimeType);
|
|
48
|
+
canvas.toBlob((blob) => {
|
|
49
|
+
resolve({
|
|
50
|
+
dataUrl: result,
|
|
51
|
+
blob,
|
|
52
|
+
width: w,
|
|
53
|
+
height: h,
|
|
54
|
+
originalSize,
|
|
55
|
+
compressedSize: blob.size
|
|
56
|
+
});
|
|
57
|
+
}, mimeType);
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
reject(err);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
img.onerror = () => reject(new Error("Failed to load image for compression"));
|
|
64
|
+
img.src = dataUrl;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function detectAlpha(ctx, w, h) {
|
|
68
|
+
const points = [
|
|
69
|
+
[0, 0],
|
|
70
|
+
[w - 1, 0],
|
|
71
|
+
[0, h - 1],
|
|
72
|
+
[w - 1, h - 1],
|
|
73
|
+
[Math.floor(w / 2), Math.floor(h / 2)]
|
|
74
|
+
];
|
|
75
|
+
for (const [x, y] of points) {
|
|
76
|
+
const pixel = ctx.getImageData(x, y, 1, 1).data;
|
|
77
|
+
if (pixel[3] < 255) return true;
|
|
78
|
+
}
|
|
79
|
+
const topRow = ctx.getImageData(0, 0, w, 1).data;
|
|
80
|
+
for (let i = 3; i < topRow.length; i += 16) {
|
|
81
|
+
if (topRow[i] < 255) return true;
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/utils/allowedImageTypes.js
|
|
87
|
+
var ALLOWED_IMAGE_MIME_TYPES = Object.freeze([
|
|
88
|
+
"image/avif",
|
|
89
|
+
"image/jpeg",
|
|
90
|
+
"image/png",
|
|
91
|
+
"image/bmp",
|
|
92
|
+
"image/svg+xml",
|
|
93
|
+
"image/webp"
|
|
94
|
+
]);
|
|
95
|
+
var ALLOWED_IMAGE_EXTENSIONS = Object.freeze([
|
|
96
|
+
".avif",
|
|
97
|
+
".jpeg",
|
|
98
|
+
".jpg",
|
|
99
|
+
".png",
|
|
100
|
+
".bmp",
|
|
101
|
+
".svg",
|
|
102
|
+
".webp"
|
|
103
|
+
]);
|
|
104
|
+
var IMAGE_ACCEPT_ATTR = ALLOWED_IMAGE_MIME_TYPES.join(",");
|
|
105
|
+
function isAllowedImage(file) {
|
|
106
|
+
if (!file) return false;
|
|
107
|
+
const type = (file.type || "").toLowerCase();
|
|
108
|
+
if (type && ALLOWED_IMAGE_MIME_TYPES.includes(type)) return true;
|
|
109
|
+
const name = (file.name || "").toLowerCase();
|
|
110
|
+
if (!name) return false;
|
|
111
|
+
return ALLOWED_IMAGE_EXTENSIONS.some((ext) => name.endsWith(ext));
|
|
112
|
+
}
|
|
113
|
+
function isAllowedImageDataUrl(dataUrl) {
|
|
114
|
+
if (typeof dataUrl !== "string") return false;
|
|
115
|
+
const m = dataUrl.match(/^data:([^;]+);/i);
|
|
116
|
+
if (!m) return false;
|
|
117
|
+
return ALLOWED_IMAGE_MIME_TYPES.includes(m[1].toLowerCase());
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export {
|
|
121
|
+
compressImage,
|
|
122
|
+
ALLOWED_IMAGE_MIME_TYPES,
|
|
123
|
+
ALLOWED_IMAGE_EXTENSIONS,
|
|
124
|
+
IMAGE_ACCEPT_ATTR,
|
|
125
|
+
isAllowedImage,
|
|
126
|
+
isAllowedImageDataUrl
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=chunk-DNAG7ML6.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/imageCompressor.js", "../../src/utils/allowedImageTypes.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * Adaptive image compression utility.\n * Compresses images to reduce size while maintaining quality.\n * Uses JPEG for opaque images, PNG for transparent ones.\n */\n\nconst MAX_DIMENSION = 1920\nconst TARGET_SIZE_BYTES = 300 * 1024 // 300KB target\nconst MIN_QUALITY = 0.4\n\n/**\n * Compress a data URL image adaptively.\n * @param {string} dataUrl - Base64 data URL of the image\n * @param {object} options\n * @param {number} options.maxWidth - Max width (default 1920)\n * @param {number} options.quality - Initial JPEG quality (default 0.8)\n * @returns {Promise<{dataUrl: string, blob: Blob, width: number, height: number, originalSize: number, compressedSize: number}>}\n */\nexport async function compressImage(dataUrl, { maxWidth = MAX_DIMENSION, quality = 0.8 } = {}) {\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.onload = () => {\n try {\n const originalSize = Math.ceil(dataUrl.length * 0.75) // approx bytes from base64\n\n // Calculate scaled dimensions\n let w = img.width\n let h = img.height\n if (w > maxWidth) {\n const ratio = maxWidth / w\n w = maxWidth\n h = Math.round(h * ratio)\n }\n\n const canvas = document.createElement('canvas')\n canvas.width = w\n canvas.height = h\n const ctx = canvas.getContext('2d')\n ctx.drawImage(img, 0, 0, w, h)\n\n // Detect transparency\n const hasAlpha = detectAlpha(ctx, w, h)\n const mimeType = hasAlpha ? 'image/png' : 'image/jpeg'\n\n // For JPEG: adaptive quality to hit target size\n if (mimeType === 'image/jpeg') {\n let currentQuality = quality\n let result = canvas.toDataURL(mimeType, currentQuality)\n let resultSize = Math.ceil(result.length * 0.75)\n\n // Reduce quality iteratively if still too large\n while (resultSize > TARGET_SIZE_BYTES && currentQuality > MIN_QUALITY) {\n currentQuality -= 0.1\n result = canvas.toDataURL(mimeType, currentQuality)\n resultSize = Math.ceil(result.length * 0.75)\n }\n\n canvas.toBlob((blob) => {\n resolve({\n dataUrl: result,\n blob,\n width: w,\n height: h,\n originalSize,\n compressedSize: blob.size,\n })\n }, mimeType, currentQuality)\n } else {\n // PNG \u2014 just use scaled version\n const result = canvas.toDataURL(mimeType)\n canvas.toBlob((blob) => {\n resolve({\n dataUrl: result,\n blob,\n width: w,\n height: h,\n originalSize,\n compressedSize: blob.size,\n })\n }, mimeType)\n }\n } catch (err) {\n reject(err)\n }\n }\n img.onerror = () => reject(new Error('Failed to load image for compression'))\n img.src = dataUrl\n })\n}\n\nfunction detectAlpha(ctx, w, h) {\n // Sample pixels to check for transparency (check corners and center)\n const points = [\n [0, 0], [w - 1, 0], [0, h - 1], [w - 1, h - 1],\n [Math.floor(w / 2), Math.floor(h / 2)],\n ]\n for (const [x, y] of points) {\n const pixel = ctx.getImageData(x, y, 1, 1).data\n if (pixel[3] < 255) return true\n }\n // Also do a quick scan of edges\n const topRow = ctx.getImageData(0, 0, w, 1).data\n for (let i = 3; i < topRow.length; i += 16) { // sample every 4th pixel\n if (topRow[i] < 255) return true\n }\n return false\n}\n", "/**\n * Canonical allowlist for image uploads across LixSketch and any embedding\n * host (e.g. blogs.elixpo). Anything not in this list is rejected at file\n * pick / paste / drop time and again at the server boundary.\n *\n * Static raster + vector formats only. Animated GIF is intentionally excluded\n * (animation isn't supported by the SVG renderer or the blog reader); HEIC,\n * TIFF, video, audio, PDF, and arbitrary files are excluded by omission.\n */\n\nexport const ALLOWED_IMAGE_MIME_TYPES = Object.freeze([\n 'image/avif',\n 'image/jpeg',\n 'image/png',\n 'image/bmp',\n 'image/svg+xml',\n 'image/webp',\n]);\n\nexport const ALLOWED_IMAGE_EXTENSIONS = Object.freeze([\n '.avif',\n '.jpeg',\n '.jpg',\n '.png',\n '.bmp',\n '.svg',\n '.webp',\n]);\n\n/** Comma-joined value suitable for an <input accept=\"\u2026\"> attribute. */\nexport const IMAGE_ACCEPT_ATTR = ALLOWED_IMAGE_MIME_TYPES.join(',');\n\n/**\n * Validate a File / Blob against the allowlist by mime type, falling back\n * to extension matching when the browser doesn't fill in `type` (some\n * drag-drop sources, some SVGs).\n */\nexport function isAllowedImage(file) {\n if (!file) return false;\n const type = (file.type || '').toLowerCase();\n if (type && ALLOWED_IMAGE_MIME_TYPES.includes(type)) return true;\n const name = (file.name || '').toLowerCase();\n if (!name) return false;\n return ALLOWED_IMAGE_EXTENSIONS.some((ext) => name.endsWith(ext));\n}\n\n/** Same check but for a base64 data URL (e.g. from clipboard paste). */\nexport function isAllowedImageDataUrl(dataUrl) {\n if (typeof dataUrl !== 'string') return false;\n const m = dataUrl.match(/^data:([^;]+);/i);\n if (!m) return false;\n return ALLOWED_IMAGE_MIME_TYPES.includes(m[1].toLowerCase());\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|