@elixpo/lixsketch 5.5.23 → 5.6.2

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 (130) hide show
  1. package/README.md +85 -6
  2. package/dist/mcp/index.js +585 -0
  3. package/dist/mcp/index.js.map +7 -0
  4. package/dist/mcp/node.js +184 -0
  5. package/dist/mcp/node.js.map +7 -0
  6. package/dist/mcp/stdio.js +723 -0
  7. package/dist/mcp/stdio.js.map +7 -0
  8. package/dist/react/{CopyPaste-5OWPTCQ5.js → CopyPaste-YUDZ6DHY.js} +7 -7
  9. package/dist/react/EventDispatcher-7LAK7GQ7.js +1097 -0
  10. package/dist/react/EventDispatcher-7LAK7GQ7.js.map +7 -0
  11. package/dist/react/Frame-7D2MXCFF.js +11 -0
  12. package/dist/react/IconShape-ZADX7Y33.js +10 -0
  13. package/dist/react/ImageShape-UJQN2HI7.js +10 -0
  14. package/dist/react/Line-APEULMHE.js +10 -0
  15. package/dist/react/{SceneSerializer-RDISX4X7.js → SceneSerializer-SG6SJN5X.js} +17 -7
  16. package/dist/react/SceneSerializer-SG6SJN5X.js.map +7 -0
  17. package/dist/react/{Selection-ZL3G6IAO.js → Selection-2TSH3J6P.js} +6 -4
  18. package/dist/react/{SketchEngine-OB6ZW3B6.js → SketchEngine-UD2XV2KT.js} +50 -23
  19. package/dist/react/{SketchEngine-OB6ZW3B6.js.map → SketchEngine-UD2XV2KT.js.map} +2 -2
  20. package/dist/react/{UndoRedo-NL7KLR5B.js → UndoRedo-IN4SXDG6.js} +2 -2
  21. package/dist/react/{ZoomPan-FAWA5OPS.js → ZoomPan-RR7KUYZT.js} +34 -1
  22. package/dist/react/{ZoomPan-FAWA5OPS.js.map → ZoomPan-RR7KUYZT.js.map} +2 -2
  23. package/dist/react/{arrowTool-CNVGM6RX.js → arrowTool-OYDWJGQK.js} +3 -3
  24. package/dist/react/{chunk-U3TB4KRS.js → chunk-6GPEWDRB.js} +19 -12
  25. package/dist/react/chunk-6GPEWDRB.js.map +7 -0
  26. package/dist/react/{chunk-4BLMNGTR.js → chunk-7CM5XQDN.js} +3 -3
  27. package/dist/react/{chunk-XFQECTTF.js → chunk-APTOPAOY.js} +3 -3
  28. package/dist/react/{chunk-EDSKEM6E.js → chunk-ASBC5G35.js} +47 -8
  29. package/dist/react/chunk-ASBC5G35.js.map +7 -0
  30. package/dist/react/{chunk-4TAS67SL.js → chunk-EOURRJ55.js} +2 -2
  31. package/dist/react/{chunk-ETAAQUUV.js → chunk-GQUZPON4.js} +4 -4
  32. package/dist/react/{chunk-KVAQPCUH.js → chunk-K5BG5MHY.js} +49 -5
  33. package/dist/react/chunk-K5BG5MHY.js.map +7 -0
  34. package/dist/react/{chunk-AH4PWNEB.js → chunk-K5RY4EV7.js} +23 -3
  35. package/dist/react/chunk-K5RY4EV7.js.map +7 -0
  36. package/dist/react/{chunk-GC3KTQDA.js → chunk-LJR7EVW2.js} +3 -3
  37. package/dist/react/{chunk-SZD7DKYJ.js → chunk-LSHZYN77.js} +2 -2
  38. package/dist/react/{chunk-HFQZYCHJ.js → chunk-M6TMN76K.js} +3 -3
  39. package/dist/react/{chunk-V2QTYSBK.js → chunk-OP56XPWF.js} +2 -2
  40. package/dist/react/chunk-QZI4UIE5.js +48 -0
  41. package/dist/react/chunk-QZI4UIE5.js.map +7 -0
  42. package/dist/react/{chunk-ILGAFR56.js → chunk-RGMDWLRJ.js} +3 -3
  43. package/dist/react/{chunk-OFGJJKPH.js → chunk-XFL4R5ZF.js} +3 -3
  44. package/dist/react/{chunk-GPIYXREE.js → chunk-XOWNCYE4.js} +3 -3
  45. package/dist/react/{chunk-YF3TK7SC.js → chunk-XYUFEIZR.js} +2 -2
  46. package/dist/react/{circleTool-KICNRQCI.js → circleTool-LDKGZALF.js} +4 -4
  47. package/dist/react/{codeTool-NCQ73R6M.js → codeTool-4YZO5W7J.js} +4 -4
  48. package/dist/react/{frameTool-Y6KB67DO.js → frameTool-MXNJEXQQ.js} +4 -4
  49. package/dist/react/{freehandTool-MMULHCQ7.js → freehandTool-26D3FOOX.js} +4 -4
  50. package/dist/react/{iconTool-LSW2DYGB.js → iconTool-46O5VEUX.js} +4 -4
  51. package/dist/react/{imageTool-2DSR32RX.js → imageTool-P2RWZRHO.js} +4 -4
  52. package/dist/react/index.js +848 -614
  53. package/dist/react/index.js.map +4 -4
  54. package/dist/react/{lineTool-N5I7IGT7.js → lineTool-ZMR27U5L.js} +4 -4
  55. package/dist/react/{rectangleTool-YUT7ZK2E.js → rectangleTool-EJKK6UTX.js} +4 -4
  56. package/dist/react/{textTool-JMTX7OVT.js → textTool-S4XXZHZH.js} +5 -5
  57. package/package.json +7 -1
  58. package/src/EngineShortcuts.js +22 -0
  59. package/src/SketchEngine.js +27 -0
  60. package/src/core/EventDispatcher.js +35 -4
  61. package/src/core/SceneSerializer.js +5 -0
  62. package/src/core/Selection.js +26 -0
  63. package/src/core/UndoRedo.js +20 -16
  64. package/src/core/WebEmbedPolicy.js +41 -0
  65. package/src/core/ZoomPan.js +36 -0
  66. package/src/index.js +4 -0
  67. package/src/mcp/fileStore.js +70 -0
  68. package/src/mcp/index.js +5 -0
  69. package/src/mcp/node.js +2 -0
  70. package/src/mcp/preview.js +39 -0
  71. package/src/mcp/scene.js +275 -0
  72. package/src/mcp/server.js +195 -0
  73. package/src/mcp/stdio.js +41 -0
  74. package/src/mcp/stdioTransport.js +46 -0
  75. package/src/mcp/store.js +23 -0
  76. package/src/mcp/templates.js +51 -0
  77. package/src/react/LixSketchCanvas.jsx +4 -0
  78. package/src/react/components/Toolbar.jsx +84 -7
  79. package/src/react/components/modals/CommandPalette.jsx +8 -0
  80. package/src/react/components/modals/WebEmbedModal.jsx +40 -0
  81. package/src/react/components/sidebars/PaintBucketSidebar.jsx +49 -0
  82. package/src/react/components/sidebars/PaintbrushSidebar.jsx +1 -1
  83. package/src/react/store/useSketchStore.js +13 -0
  84. package/src/react/toolsEnum.js +4 -0
  85. package/src/shapes/Frame.js +47 -4
  86. package/src/shapes/ImageShape.js +49 -6
  87. package/src/tools/lassoTool.js +84 -0
  88. package/src/tools/paintBucketTool.js +50 -0
  89. package/src/tools/shapeRecognitionTool.js +431 -0
  90. package/src/tools/webEmbedTool.js +61 -0
  91. package/dist/react/EventDispatcher-GKNO2KSL.js +0 -464
  92. package/dist/react/EventDispatcher-GKNO2KSL.js.map +0 -7
  93. package/dist/react/Frame-RLSMJJSK.js +0 -11
  94. package/dist/react/IconShape-7OPXAKLK.js +0 -10
  95. package/dist/react/ImageShape-T7UEHP4A.js +0 -10
  96. package/dist/react/Line-WWQFBNX5.js +0 -10
  97. package/dist/react/SceneSerializer-RDISX4X7.js.map +0 -7
  98. package/dist/react/chunk-AH4PWNEB.js.map +0 -7
  99. package/dist/react/chunk-EDSKEM6E.js.map +0 -7
  100. package/dist/react/chunk-KVAQPCUH.js.map +0 -7
  101. package/dist/react/chunk-U3TB4KRS.js.map +0 -7
  102. /package/dist/react/{CopyPaste-5OWPTCQ5.js.map → CopyPaste-YUDZ6DHY.js.map} +0 -0
  103. /package/dist/react/{Frame-RLSMJJSK.js.map → Frame-7D2MXCFF.js.map} +0 -0
  104. /package/dist/react/{IconShape-7OPXAKLK.js.map → IconShape-ZADX7Y33.js.map} +0 -0
  105. /package/dist/react/{ImageShape-T7UEHP4A.js.map → ImageShape-UJQN2HI7.js.map} +0 -0
  106. /package/dist/react/{Line-WWQFBNX5.js.map → Line-APEULMHE.js.map} +0 -0
  107. /package/dist/react/{Selection-ZL3G6IAO.js.map → Selection-2TSH3J6P.js.map} +0 -0
  108. /package/dist/react/{UndoRedo-NL7KLR5B.js.map → UndoRedo-IN4SXDG6.js.map} +0 -0
  109. /package/dist/react/{arrowTool-CNVGM6RX.js.map → arrowTool-OYDWJGQK.js.map} +0 -0
  110. /package/dist/react/{chunk-4BLMNGTR.js.map → chunk-7CM5XQDN.js.map} +0 -0
  111. /package/dist/react/{chunk-XFQECTTF.js.map → chunk-APTOPAOY.js.map} +0 -0
  112. /package/dist/react/{chunk-4TAS67SL.js.map → chunk-EOURRJ55.js.map} +0 -0
  113. /package/dist/react/{chunk-ETAAQUUV.js.map → chunk-GQUZPON4.js.map} +0 -0
  114. /package/dist/react/{chunk-GC3KTQDA.js.map → chunk-LJR7EVW2.js.map} +0 -0
  115. /package/dist/react/{chunk-SZD7DKYJ.js.map → chunk-LSHZYN77.js.map} +0 -0
  116. /package/dist/react/{chunk-HFQZYCHJ.js.map → chunk-M6TMN76K.js.map} +0 -0
  117. /package/dist/react/{chunk-V2QTYSBK.js.map → chunk-OP56XPWF.js.map} +0 -0
  118. /package/dist/react/{chunk-ILGAFR56.js.map → chunk-RGMDWLRJ.js.map} +0 -0
  119. /package/dist/react/{chunk-OFGJJKPH.js.map → chunk-XFL4R5ZF.js.map} +0 -0
  120. /package/dist/react/{chunk-GPIYXREE.js.map → chunk-XOWNCYE4.js.map} +0 -0
  121. /package/dist/react/{chunk-YF3TK7SC.js.map → chunk-XYUFEIZR.js.map} +0 -0
  122. /package/dist/react/{circleTool-KICNRQCI.js.map → circleTool-LDKGZALF.js.map} +0 -0
  123. /package/dist/react/{codeTool-NCQ73R6M.js.map → codeTool-4YZO5W7J.js.map} +0 -0
  124. /package/dist/react/{frameTool-Y6KB67DO.js.map → frameTool-MXNJEXQQ.js.map} +0 -0
  125. /package/dist/react/{freehandTool-MMULHCQ7.js.map → freehandTool-26D3FOOX.js.map} +0 -0
  126. /package/dist/react/{iconTool-LSW2DYGB.js.map → iconTool-46O5VEUX.js.map} +0 -0
  127. /package/dist/react/{imageTool-2DSR32RX.js.map → imageTool-P2RWZRHO.js.map} +0 -0
  128. /package/dist/react/{lineTool-N5I7IGT7.js.map → lineTool-ZMR27U5L.js.map} +0 -0
  129. /package/dist/react/{rectangleTool-YUT7ZK2E.js.map → rectangleTool-EJKK6UTX.js.map} +0 -0
  130. /package/dist/react/{textTool-JMTX7OVT.js.map → textTool-S4XXZHZH.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/SketchEngine.js"],
4
- "sourcesContent": ["/* eslint-disable */\n/**\n * SketchEngine - Main engine entry point\n *\n * Initializes the SVG canvas, sets up global state (including RoughJS from npm),\n * then dynamically imports all tool and shape modules.\n *\n * IMPORTANT: All globals must be set BEFORE importing modules, because many\n * modules run code at the top level (e.g. `const rc = rough.svg(svg)`) that\n * depends on these globals existing.\n */\n\nimport rough from 'roughjs';\n\nclass SketchEngine {\n constructor(svgElement, options = {}) {\n if (!svgElement || svgElement.tagName !== 'svg') {\n throw new Error('SketchEngine requires an SVG element');\n }\n\n this.svg = svgElement;\n // Prevent default touch scrolling/gestures on the canvas to allow for custom pointer events\n this.svg.style.touchAction = 'none';\n\n this.options = {\n initialZoom: 1,\n minZoom: 0.4,\n maxZoom: 30,\n ...options\n };\n\n // Event callback for framework consumers (React, Vue, vanilla, VS Code, etc.)\n this.onEvent = options.onEvent || (() => {});\n\n // Public API surfaces (populated after init)\n this.scene = null;\n this.shapes = null;\n\n this._modules = {};\n this._initialized = false;\n }\n\n /**\n * Emit an event to the consumer callback.\n * @param {string} type - Event type (e.g. 'sidebar:select', 'zoom:change')\n * @param {*} data - Event payload\n */\n emit(type, data) {\n try { this.onEvent(type, data); } catch (e) { console.warn('[SketchEngine] onEvent error:', e); }\n }\n\n /**\n * Set up all the global variables that the tool/shape modules depend on.\n * Must be called BEFORE any module imports.\n */\n _initGlobals() {\n // Core SVG reference\n window.svg = this.svg;\n window.freehandCanvas = this.svg;\n window.__sketchInteractionReady = false;\n\n // RoughJS from npm\n window.rough = rough;\n window.roughCanvas = rough.svg(this.svg);\n window.roughGenerator = window.roughCanvas.generator;\n\n // Shape storage\n window.shapes = window.shapes || [];\n window.currentShape = window.currentShape || null;\n window.lastMousePos = window.lastMousePos || null;\n\n // Zoom state\n window.currentZoom = this.options.initialZoom;\n window.minScale = this.options.minZoom;\n window.maxScale = this.options.maxZoom;\n window.minZoom = this.options.minZoom;\n window.maxZoom = this.options.maxZoom;\n\n // ViewBox state\n window.currentViewBox = window.currentViewBox || {\n x: 0, y: 0,\n width: window.innerWidth,\n height: window.innerHeight\n };\n\n // Tool activation flags\n window.isPaintToolActive = false;\n window.isTextToolActive = false;\n window.isCircleToolActive = false;\n window.isSquareToolActive = false;\n window.isLaserToolActive = false;\n window.isEraserToolActive = false;\n window.isImageToolActive = false;\n window.isArrowToolActive = false;\n window.isLineToolActive = false;\n window.isSelectionToolActive = true;\n window.isPanningToolActive = false;\n window.isFrameToolActive = false;\n window.isIconToolActive = false;\n window.isCodeToolActive = false;\n window.isTextInCodeMode = false;\n\n // Pan state\n window.isPanning = false;\n window.panStart = null;\n window.startCanvasX = 0;\n window.startCanvasY = 0;\n\n // Transform state\n window.currentMatrix = new DOMMatrix();\n window.currentTranslation = { x: 0, y: 0 };\n\n // Action type constants\n window.ACTION_CREATE = 'create';\n window.ACTION_DELETE = 'delete';\n window.ACTION_MODIFY = 'modify';\n window.ACTION_PASTE = 'paste';\n\n // History stacks\n window.historyStack = window.historyStack || [];\n window.redoStack = window.redoStack || [];\n\n // Sidebar element stubs \u2014 React sidebars handle UI, but legacy code\n // queries these at top level. Provide dummy elements so it doesn't crash.\n const dummyEl = document.createElement('div');\n dummyEl.classList.add('hidden');\n window.paintBrushSideBar = document.getElementById('paintBrushToolBar') || dummyEl;\n window.lineSideBar = document.getElementById('lineSideBar') || dummyEl;\n window.squareSideBar = document.getElementById('squareSideBar') || dummyEl;\n window.circleSideBar = document.getElementById('circleSideBar') || dummyEl;\n window.arrowSideBar = document.getElementById('arrowSideBar') || dummyEl;\n window.textSideBar = document.getElementById('textToolBar') || dummyEl;\n window.frameSideBar = document.getElementById('frameSideBar') || dummyEl;\n\n // Zoom control element refs\n window.zoomInBtn = document.getElementById('zoomIn') || dummyEl;\n window.zoomOutBtn = document.getElementById('zoomOut') || dummyEl;\n window.zoomPercentSpan = document.getElementById('zoomPercent') || dummyEl;\n\n // Container\n window.container = document.querySelector('.container') || document.body;\n\n // Sidebar control \u2014 bridge legacy code to consumer UI\n const engine = this;\n window.disableAllSideBars = function() {\n // Hide all legacy sidebar elements\n [window.paintBrushSideBar, window.lineSideBar, window.squareSideBar,\n window.circleSideBar, window.arrowSideBar, window.textSideBar, window.frameSideBar\n ].forEach(el => { if (el) el.classList.add('hidden'); });\n // Notify consumer via onEvent + legacy bridge\n engine.emit('sidebar:clear');\n if (window.__sketchStoreApi) {\n window.__sketchStoreApi.clearSelectedShapeSidebar();\n }\n };\n\n // toolExtraPopup \u2014 legacy UI function, no-op in React\n window.toolExtraPopup = window.toolExtraPopup || function() {};\n\n // updateUndoRedoButtons \u2014 legacy UI function, no-op in React\n window.updateUndoRedoButtons = window.updateUndoRedoButtons || function() {};\n\n // Bridge for shape selection -> consumer UI\n // Maps shape.shapeName to the sidebar key\n window.__showSidebarForShape = function(shapeName) {\n const sidebarMap = {\n 'rectangle': 'rectangle',\n 'circle': 'circle',\n 'arrow': 'arrow',\n 'line': 'line',\n 'freehandStroke': 'paintbrush',\n 'text': 'text',\n 'code': 'text',\n 'frame': 'frame',\n 'image': 'image',\n };\n const sidebar = sidebarMap[shapeName];\n // Emit to consumer callback\n engine.emit('sidebar:select', { sidebar, shapeName });\n // Legacy bridge for React\n if (sidebar && window.__sketchStoreApi) {\n window.__sketchStoreApi.setSelectedShapeSidebar(sidebar);\n }\n window.__selectedShapeIsCode = (shapeName === 'code');\n if (window.__onCodeModeChanged) window.__onCodeModeChanged(shapeName === 'code');\n };\n }\n\n /**\n * Initialize engine: set globals first, then import modules.\n */\n async init() {\n if (this._initialized) return;\n\n // CRITICAL: Set up ALL globals BEFORE importing modules\n this._initGlobals();\n\n try {\n // Import shape classes first\n const [\n { Rectangle },\n { Circle },\n { Arrow },\n { Line },\n { TextShape },\n { CodeShape },\n { ImageShape },\n { IconShape },\n { Frame },\n { FreehandStroke }\n ] = await Promise.all([\n import('./shapes/Rectangle.js'),\n import('./shapes/Circle.js'),\n import('./shapes/Arrow.js'),\n import('./shapes/Line.js'),\n import('./shapes/TextShape.js'),\n import('./shapes/CodeShape.js'),\n import('./shapes/ImageShape.js'),\n import('./shapes/IconShape.js'),\n import('./shapes/Frame.js'),\n import('./shapes/FreehandStroke.js')\n ]);\n\n // Expose shape classes globally\n window.Rectangle = Rectangle;\n window.Circle = Circle;\n window.Arrow = Arrow;\n window.Line = Line;\n window.TextShape = TextShape;\n window.CodeShape = CodeShape;\n window.ImageShape = ImageShape;\n window.IconShape = IconShape;\n window.Frame = Frame;\n window.FreehandStroke = FreehandStroke;\n\n this._modules.shapes = {\n Rectangle, Circle, Arrow, Line,\n TextShape, CodeShape, ImageShape, IconShape,\n Frame, FreehandStroke\n };\n\n // Import tool handlers (they run top-level code that reads globals)\n const [\n rectangleTool, circleTool, arrowTool, lineTool,\n textTool, codeTool, imageTool, iconTool,\n frameTool, freehandTool\n ] = await Promise.all([\n import('./tools/rectangleTool.js'),\n import('./tools/circleTool.js'),\n import('./tools/arrowTool.js'),\n import('./tools/lineTool.js'),\n import('./tools/textTool.js'),\n import('./tools/codeTool.js'),\n import('./tools/imageTool.js'),\n import('./tools/iconTool.js'),\n import('./tools/frameTool.js'),\n import('./tools/freehandTool.js')\n ]);\n\n this._modules.tools = {\n rectangleTool, circleTool, arrowTool, lineTool,\n textTool, codeTool, imageTool, iconTool,\n frameTool, freehandTool\n };\n\n // Import core modules (EventDispatcher attaches SVG listeners at top level)\n const [\n eventDispatcher, undoRedo, selection,\n zoomPan, copyPaste, eraserTrail,\n resizeShapes, resizeCode\n ] = await Promise.all([\n import('./core/EventDispatcher.js'),\n import('./core/UndoRedo.js'),\n import('./core/Selection.js'),\n import('./core/ZoomPan.js'),\n import('./core/CopyPaste.js'),\n import('./core/EraserTrail.js'),\n import('./core/ResizeShapes.js'),\n import('./core/ResizeCode.js')\n ]);\n\n this._modules.core = {\n eventDispatcher, undoRedo, selection,\n zoomPan, copyPaste, eraserTrail,\n resizeShapes, resizeCode\n };\n\n // Re-bind event listeners to the current SVG element\n if (eventDispatcher.initEventDispatcher) {\n eventDispatcher.initEventDispatcher(this.svg);\n }\n window.__sketchInteractionReady = true;\n\n // Restore only after pointer handlers are bound. This still keeps\n // first canvas paint ahead of optional AI/graph/LixScript chunks,\n // while guaranteeing every visible restored shape is immediately\n // selectable and draggable.\n const sceneSerializer = await import('./core/SceneSerializer.js');\n if (sceneSerializer.initSceneSerializer) sceneSerializer.initSceneSerializer();\n\n // Import standalone tools\n await Promise.all([\n import('./tools/eraserTool.js'),\n import('./tools/laserTool.js')\n ]);\n\n // Expose key functions globally\n if (undoRedo.undo) window.undo = undoRedo.undo;\n if (undoRedo.redo) window.redo = undoRedo.redo;\n if (undoRedo.pushCreateAction) window.pushCreateAction = undoRedo.pushCreateAction;\n if (undoRedo.pushDeleteAction) window.pushDeleteAction = undoRedo.pushDeleteAction;\n if (selection.multiSelection) window.multiSelection = selection.multiSelection;\n if (selection.clearAllSelections) window.clearAllSelections = selection.clearAllSelections;\n\n // Initialize centralized copy/paste system\n if (copyPaste.initCopyPaste) copyPaste.initCopyPaste();\n\n // Initialize AI renderer bridge\n const aiRenderer = await import('./core/AIRenderer.js');\n if (aiRenderer.initAIRenderer) aiRenderer.initAIRenderer();\n\n // Initialize graph engine bridge\n const graphEngine = await import('./core/GraphEngine.js');\n if (graphEngine.initGraphEngine) graphEngine.initGraphEngine();\n\n // Initialize layer ordering\n const layerOrder = await import('./core/LayerOrder.js');\n if (layerOrder.initLayerOrder) layerOrder.initLayerOrder();\n\n // Initialize LixScript programmatic diagram engine\n const lixScript = await import('./core/LixScriptParser.js');\n if (lixScript.initLixScriptBridge) lixScript.initLixScriptBridge();\n\n // \u2500\u2500 Public API surfaces \u2500\u2500\n\n // Scene operations (save, load, export, etc.)\n this.scene = window.__sceneSerializer || {\n save: sceneSerializer.saveScene,\n load: sceneSerializer.loadScene,\n download: sceneSerializer.downloadScene,\n upload: sceneSerializer.uploadScene,\n exportPNG: sceneSerializer.exportAsPNG,\n exportPDF: sceneSerializer.exportAsPDF,\n copyAsPNG: sceneSerializer.copyAsPNG,\n copyAsSVG: sceneSerializer.copyAsSVG,\n reset: sceneSerializer.resetCanvas,\n findText: sceneSerializer.findTextOnCanvas,\n };\n\n // Shape array reference\n this.shapes = window.shapes;\n\n // Undo/redo\n this.undo = undoRedo.undo || (() => {});\n this.redo = undoRedo.redo || (() => {});\n\n // LixScript execution\n this.lixscript = {\n parse: lixScript.parseLixScript || (() => null),\n execute: lixScript.executeLixScript || (lixScript.parseLixScript ? (code) => {\n const parsed = lixScript.parseLixScript(code);\n if (parsed && lixScript.resolveShapeRefs) lixScript.resolveShapeRefs(parsed);\n return parsed;\n } : (() => null)),\n };\n\n // Store module refs for advanced consumers\n this._modules.sceneSerializer = sceneSerializer;\n this._modules.lixScript = lixScript;\n\n this._initialized = true;\n console.log('[SketchEngine] Initialized successfully');\n } catch (err) {\n console.error('[SketchEngine] Initialization failed:', err);\n throw err;\n }\n }\n\n /**\n * Sync tool flags from Zustand activeTool value.\n */\n setActiveTool(toolName) {\n // Deselect current shape when switching tools\n if (window.currentShape && typeof window.currentShape.removeSelection === 'function') {\n window.currentShape.removeSelection();\n window.currentShape = null;\n }\n if (typeof window.clearAllSelections === 'function') {\n window.clearAllSelections();\n }\n if (typeof window.disableAllSideBars === 'function') {\n window.disableAllSideBars();\n }\n\n // Force cleanup eraser trail when switching tools\n if (typeof window.forceCleanupEraserTrail === 'function') {\n window.forceCleanupEraserTrail();\n }\n // Clean up any lingering icon miniature/drag state\n if (typeof window.__cleanupIconTool === 'function') {\n window.__cleanupIconTool();\n }\n\n window.isPaintToolActive = false;\n window.isSquareToolActive = false;\n window.isCircleToolActive = false;\n window.isArrowToolActive = false;\n window.isTextToolActive = false;\n window.isLaserToolActive = false;\n window.isLineToolActive = false;\n window.isEraserToolActive = false;\n window.isSelectionToolActive = false;\n window.isImageToolActive = false;\n window.isPanningToolActive = false;\n window.isFrameToolActive = false;\n window.isIconToolActive = false;\n window.isCodeToolActive = false;\n\n const flagMap = {\n select: 'isSelectionToolActive',\n pan: 'isPanningToolActive',\n rectangle: 'isSquareToolActive',\n circle: 'isCircleToolActive',\n line: 'isLineToolActive',\n arrow: 'isArrowToolActive',\n freehand: 'isPaintToolActive',\n text: 'isTextToolActive',\n code: 'isCodeToolActive',\n eraser: 'isEraserToolActive',\n laser: 'isLaserToolActive',\n image: 'isImageToolActive',\n frame: 'isFrameToolActive',\n icon: 'isIconToolActive',\n };\n\n const flag = flagMap[toolName];\n if (flag) window[flag] = true;\n\n if (toolName === 'text' && window.isTextInCodeMode) {\n window.isCodeToolActive = true;\n }\n\n // Show image source picker when image tool is activated\n if (toolName === 'image' && window.__showImageSourcePicker) {\n window.__showImageSourcePicker();\n }\n\n // Set appropriate cursor for the active tool\n const cursorMap = {\n select: 'default',\n pan: 'grab',\n rectangle: 'crosshair',\n circle: 'crosshair',\n line: 'crosshair',\n arrow: 'crosshair',\n freehand: 'crosshair',\n text: 'crosshair',\n code: 'crosshair',\n eraser: 'crosshair',\n laser: 'crosshair',\n image: 'crosshair',\n frame: 'crosshair',\n icon: 'crosshair',\n };\n if (this.svg) {\n this.svg.style.cursor = cursorMap[toolName] || 'default';\n }\n }\n\n cleanup() {\n // Remove event listeners from the SVG element\n if (this._modules.core?.eventDispatcher?.cleanupEventDispatcher) {\n this._modules.core.eventDispatcher.cleanupEventDispatcher();\n }\n window.shapes = [];\n window.currentShape = null;\n window.lastMousePos = null;\n window.__sketchInteractionReady = false;\n delete window.__sceneSerializer;\n this._modules = {};\n this._initialized = false;\n console.log('[SketchEngine] Cleaned up');\n }\n}\n\nexport { SketchEngine };\nexport default SketchEngine;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable */\n/**\n * SketchEngine - Main engine entry point\n *\n * Initializes the SVG canvas, sets up global state (including RoughJS from npm),\n * then dynamically imports all tool and shape modules.\n *\n * IMPORTANT: All globals must be set BEFORE importing modules, because many\n * modules run code at the top level (e.g. `const rc = rough.svg(svg)`) that\n * depends on these globals existing.\n */\n\nimport rough from 'roughjs';\n\nclass SketchEngine {\n constructor(svgElement, options = {}) {\n if (!svgElement || svgElement.tagName !== 'svg') {\n throw new Error('SketchEngine requires an SVG element');\n }\n\n this.svg = svgElement;\n // Prevent default touch scrolling/gestures on the canvas to allow for custom pointer events\n this.svg.style.touchAction = 'none';\n\n this.options = {\n initialZoom: 1,\n minZoom: 0.4,\n maxZoom: 30,\n ...options\n };\n\n // Event callback for framework consumers (React, Vue, vanilla, VS Code, etc.)\n this.onEvent = options.onEvent || (() => {});\n\n // Public API surfaces (populated after init)\n this.scene = null;\n this.shapes = null;\n\n this._modules = {};\n this._initialized = false;\n }\n\n /**\n * Emit an event to the consumer callback.\n * @param {string} type - Event type (e.g. 'sidebar:select', 'zoom:change')\n * @param {*} data - Event payload\n */\n emit(type, data) {\n try { this.onEvent(type, data); } catch (e) { console.warn('[SketchEngine] onEvent error:', e); }\n }\n\n /**\n * Set up all the global variables that the tool/shape modules depend on.\n * Must be called BEFORE any module imports.\n */\n _initGlobals() {\n // Core SVG reference\n window.svg = this.svg;\n window.freehandCanvas = this.svg;\n window.__sketchInteractionReady = false;\n\n // RoughJS from npm\n window.rough = rough;\n window.roughCanvas = rough.svg(this.svg);\n window.roughGenerator = window.roughCanvas.generator;\n\n // Shape storage\n window.shapes = window.shapes || [];\n window.currentShape = window.currentShape || null;\n window.lastMousePos = window.lastMousePos || null;\n\n // Zoom state\n window.currentZoom = this.options.initialZoom;\n window.minScale = this.options.minZoom;\n window.maxScale = this.options.maxZoom;\n window.minZoom = this.options.minZoom;\n window.maxZoom = this.options.maxZoom;\n\n // ViewBox state\n window.currentViewBox = window.currentViewBox || {\n x: 0, y: 0,\n width: window.innerWidth,\n height: window.innerHeight\n };\n\n // Tool activation flags\n window.isPaintToolActive = false;\n window.isTextToolActive = false;\n window.isCircleToolActive = false;\n window.isSquareToolActive = false;\n window.isLaserToolActive = false;\n window.isEraserToolActive = false;\n window.isImageToolActive = false;\n window.isArrowToolActive = false;\n window.isLineToolActive = false;\n window.isSelectionToolActive = true;\n window.isPanningToolActive = false;\n window.isFrameToolActive = false;\n window.isIconToolActive = false;\n window.isCodeToolActive = false;\n window.isShapeRecognitionToolActive = false;\n window.isPaintBucketToolActive = false;\n window.isLassoToolActive = false;\n window.isWebEmbedToolActive = false;\n window.isTextInCodeMode = false;\n\n // Pan state\n window.isPanning = false;\n window.panStart = null;\n window.startCanvasX = 0;\n window.startCanvasY = 0;\n\n // Transform state\n window.currentMatrix = new DOMMatrix();\n window.currentTranslation = { x: 0, y: 0 };\n\n // Action type constants\n window.ACTION_CREATE = 'create';\n window.ACTION_DELETE = 'delete';\n window.ACTION_MODIFY = 'modify';\n window.ACTION_PASTE = 'paste';\n\n // History stacks\n window.historyStack = window.historyStack || [];\n window.redoStack = window.redoStack || [];\n\n // Sidebar element stubs \u2014 React sidebars handle UI, but legacy code\n // queries these at top level. Provide dummy elements so it doesn't crash.\n const dummyEl = document.createElement('div');\n dummyEl.classList.add('hidden');\n window.paintBrushSideBar = document.getElementById('paintBrushToolBar') || dummyEl;\n window.lineSideBar = document.getElementById('lineSideBar') || dummyEl;\n window.squareSideBar = document.getElementById('squareSideBar') || dummyEl;\n window.circleSideBar = document.getElementById('circleSideBar') || dummyEl;\n window.arrowSideBar = document.getElementById('arrowSideBar') || dummyEl;\n window.textSideBar = document.getElementById('textToolBar') || dummyEl;\n window.frameSideBar = document.getElementById('frameSideBar') || dummyEl;\n\n // Zoom control element refs\n window.zoomInBtn = document.getElementById('zoomIn') || dummyEl;\n window.zoomOutBtn = document.getElementById('zoomOut') || dummyEl;\n window.zoomPercentSpan = document.getElementById('zoomPercent') || dummyEl;\n\n // Container\n window.container = document.querySelector('.container') || document.body;\n\n // Sidebar control \u2014 bridge legacy code to consumer UI\n const engine = this;\n window.disableAllSideBars = function() {\n // Hide all legacy sidebar elements\n [window.paintBrushSideBar, window.lineSideBar, window.squareSideBar,\n window.circleSideBar, window.arrowSideBar, window.textSideBar, window.frameSideBar\n ].forEach(el => { if (el) el.classList.add('hidden'); });\n // Notify consumer via onEvent + legacy bridge\n engine.emit('sidebar:clear');\n if (window.__sketchStoreApi) {\n window.__sketchStoreApi.clearSelectedShapeSidebar();\n }\n };\n\n // toolExtraPopup \u2014 legacy UI function, no-op in React\n window.toolExtraPopup = window.toolExtraPopup || function() {};\n\n // updateUndoRedoButtons \u2014 legacy UI function, no-op in React\n window.updateUndoRedoButtons = window.updateUndoRedoButtons || function() {};\n\n // Bridge for shape selection -> consumer UI\n // Maps shape.shapeName to the sidebar key\n window.__showSidebarForShape = function(shapeName) {\n const sidebarMap = {\n 'rectangle': 'rectangle',\n 'circle': 'circle',\n 'arrow': 'arrow',\n 'line': 'line',\n 'freehandStroke': 'paintbrush',\n 'text': 'text',\n 'code': 'text',\n 'frame': 'frame',\n 'image': 'image',\n };\n const sidebar = sidebarMap[shapeName];\n // Emit to consumer callback\n engine.emit('sidebar:select', { sidebar, shapeName });\n // Legacy bridge for React\n if (sidebar && window.__sketchStoreApi) {\n window.__sketchStoreApi.setSelectedShapeSidebar(sidebar);\n }\n window.__selectedShapeIsCode = (shapeName === 'code');\n if (window.__onCodeModeChanged) window.__onCodeModeChanged(shapeName === 'code');\n };\n }\n\n /**\n * Initialize engine: set globals first, then import modules.\n */\n async init() {\n if (this._initialized) return;\n\n // CRITICAL: Set up ALL globals BEFORE importing modules\n this._initGlobals();\n\n try {\n // Import shape classes first\n const [\n { Rectangle },\n { Circle },\n { Arrow },\n { Line },\n { TextShape },\n { CodeShape },\n { ImageShape },\n { IconShape },\n { Frame },\n { FreehandStroke }\n ] = await Promise.all([\n import('./shapes/Rectangle.js'),\n import('./shapes/Circle.js'),\n import('./shapes/Arrow.js'),\n import('./shapes/Line.js'),\n import('./shapes/TextShape.js'),\n import('./shapes/CodeShape.js'),\n import('./shapes/ImageShape.js'),\n import('./shapes/IconShape.js'),\n import('./shapes/Frame.js'),\n import('./shapes/FreehandStroke.js')\n ]);\n\n // Expose shape classes globally\n window.Rectangle = Rectangle;\n window.Circle = Circle;\n window.Arrow = Arrow;\n window.Line = Line;\n window.TextShape = TextShape;\n window.CodeShape = CodeShape;\n window.ImageShape = ImageShape;\n window.IconShape = IconShape;\n window.Frame = Frame;\n window.FreehandStroke = FreehandStroke;\n\n this._modules.shapes = {\n Rectangle, Circle, Arrow, Line,\n TextShape, CodeShape, ImageShape, IconShape,\n Frame, FreehandStroke\n };\n\n // Import tool handlers (they run top-level code that reads globals)\n const [\n rectangleTool, circleTool, arrowTool, lineTool,\n textTool, codeTool, imageTool, iconTool,\n frameTool, freehandTool\n ] = await Promise.all([\n import('./tools/rectangleTool.js'),\n import('./tools/circleTool.js'),\n import('./tools/arrowTool.js'),\n import('./tools/lineTool.js'),\n import('./tools/textTool.js'),\n import('./tools/codeTool.js'),\n import('./tools/imageTool.js'),\n import('./tools/iconTool.js'),\n import('./tools/frameTool.js'),\n import('./tools/freehandTool.js')\n ]);\n\n this._modules.tools = {\n rectangleTool, circleTool, arrowTool, lineTool,\n textTool, codeTool, imageTool, iconTool,\n frameTool, freehandTool\n };\n\n // Import core modules (EventDispatcher attaches SVG listeners at top level)\n const [\n eventDispatcher, undoRedo, selection,\n zoomPan, copyPaste, eraserTrail,\n resizeShapes, resizeCode\n ] = await Promise.all([\n import('./core/EventDispatcher.js'),\n import('./core/UndoRedo.js'),\n import('./core/Selection.js'),\n import('./core/ZoomPan.js'),\n import('./core/CopyPaste.js'),\n import('./core/EraserTrail.js'),\n import('./core/ResizeShapes.js'),\n import('./core/ResizeCode.js')\n ]);\n\n this._modules.core = {\n eventDispatcher, undoRedo, selection,\n zoomPan, copyPaste, eraserTrail,\n resizeShapes, resizeCode\n };\n\n // Re-bind event listeners to the current SVG element\n if (eventDispatcher.initEventDispatcher) {\n eventDispatcher.initEventDispatcher(this.svg);\n }\n window.__sketchInteractionReady = true;\n\n // Restore only after pointer handlers are bound. This still keeps\n // first canvas paint ahead of optional AI/graph/LixScript chunks,\n // while guaranteeing every visible restored shape is immediately\n // selectable and draggable.\n const sceneSerializer = await import('./core/SceneSerializer.js');\n if (sceneSerializer.initSceneSerializer) sceneSerializer.initSceneSerializer();\n\n // Import standalone tools\n await Promise.all([\n import('./tools/eraserTool.js'),\n import('./tools/laserTool.js')\n ]);\n\n // Expose key functions globally\n if (undoRedo.undo) window.undo = undoRedo.undo;\n if (undoRedo.redo) window.redo = undoRedo.redo;\n if (undoRedo.pushCreateAction) window.pushCreateAction = undoRedo.pushCreateAction;\n if (undoRedo.pushDeleteAction) window.pushDeleteAction = undoRedo.pushDeleteAction;\n if (selection.multiSelection) window.multiSelection = selection.multiSelection;\n if (selection.clearAllSelections) window.clearAllSelections = selection.clearAllSelections;\n\n // Initialize centralized copy/paste system\n if (copyPaste.initCopyPaste) copyPaste.initCopyPaste();\n\n // Initialize AI renderer bridge\n const aiRenderer = await import('./core/AIRenderer.js');\n if (aiRenderer.initAIRenderer) aiRenderer.initAIRenderer();\n\n // Initialize graph engine bridge\n const graphEngine = await import('./core/GraphEngine.js');\n if (graphEngine.initGraphEngine) graphEngine.initGraphEngine();\n\n // Initialize layer ordering\n const layerOrder = await import('./core/LayerOrder.js');\n if (layerOrder.initLayerOrder) layerOrder.initLayerOrder();\n\n // Initialize LixScript programmatic diagram engine\n const lixScript = await import('./core/LixScriptParser.js');\n if (lixScript.initLixScriptBridge) lixScript.initLixScriptBridge();\n\n // \u2500\u2500 Public API surfaces \u2500\u2500\n\n // Scene operations (save, load, export, etc.)\n this.scene = window.__sceneSerializer || {\n save: sceneSerializer.saveScene,\n load: sceneSerializer.loadScene,\n download: sceneSerializer.downloadScene,\n upload: sceneSerializer.uploadScene,\n exportPNG: sceneSerializer.exportAsPNG,\n exportPDF: sceneSerializer.exportAsPDF,\n copyAsPNG: sceneSerializer.copyAsPNG,\n copyAsSVG: sceneSerializer.copyAsSVG,\n reset: sceneSerializer.resetCanvas,\n findText: sceneSerializer.findTextOnCanvas,\n };\n\n // Shape array reference\n this.shapes = window.shapes;\n\n // Undo/redo\n this.undo = undoRedo.undo || (() => {});\n this.redo = undoRedo.redo || (() => {});\n\n // LixScript execution\n this.lixscript = {\n parse: lixScript.parseLixScript || (() => null),\n execute: lixScript.executeLixScript || (lixScript.parseLixScript ? (code) => {\n const parsed = lixScript.parseLixScript(code);\n if (parsed && lixScript.resolveShapeRefs) lixScript.resolveShapeRefs(parsed);\n return parsed;\n } : (() => null)),\n };\n\n // Store module refs for advanced consumers\n this._modules.sceneSerializer = sceneSerializer;\n this._modules.lixScript = lixScript;\n\n this._initialized = true;\n console.log('[SketchEngine] Initialized successfully');\n } catch (err) {\n console.error('[SketchEngine] Initialization failed:', err);\n throw err;\n }\n }\n\n /**\n * Sync tool flags from Zustand activeTool value.\n */\n setActiveTool(toolName) {\n // Deselect current shape when switching tools\n if (window.currentShape && typeof window.currentShape.removeSelection === 'function') {\n window.currentShape.removeSelection();\n window.currentShape = null;\n }\n if (typeof window.clearAllSelections === 'function') {\n window.clearAllSelections();\n }\n if (typeof window.disableAllSideBars === 'function') {\n window.disableAllSideBars();\n }\n\n // Force cleanup eraser trail when switching tools\n if (typeof window.forceCleanupEraserTrail === 'function') {\n window.forceCleanupEraserTrail();\n }\n // Clean up any lingering icon miniature/drag state\n if (typeof window.__cleanupIconTool === 'function') {\n window.__cleanupIconTool();\n }\n if (typeof window.__cancelShapeRecognition === 'function') {\n window.__cancelShapeRecognition();\n }\n if (typeof window.__cancelLasso === 'function') window.__cancelLasso();\n\n window.isPaintToolActive = false;\n window.isSquareToolActive = false;\n window.isCircleToolActive = false;\n window.isArrowToolActive = false;\n window.isTextToolActive = false;\n window.isLaserToolActive = false;\n window.isLineToolActive = false;\n window.isEraserToolActive = false;\n window.isSelectionToolActive = false;\n window.isImageToolActive = false;\n window.isPanningToolActive = false;\n window.isFrameToolActive = false;\n window.isIconToolActive = false;\n window.isCodeToolActive = false;\n window.isShapeRecognitionToolActive = false;\n window.isPaintBucketToolActive = false;\n window.isLassoToolActive = false;\n window.isWebEmbedToolActive = false;\n\n const flagMap = {\n select: 'isSelectionToolActive',\n pan: 'isPanningToolActive',\n rectangle: 'isSquareToolActive',\n circle: 'isCircleToolActive',\n line: 'isLineToolActive',\n arrow: 'isArrowToolActive',\n freehand: 'isPaintToolActive',\n text: 'isTextToolActive',\n code: 'isCodeToolActive',\n eraser: 'isEraserToolActive',\n laser: 'isLaserToolActive',\n image: 'isImageToolActive',\n frame: 'isFrameToolActive',\n icon: 'isIconToolActive',\n 'draw-shape': 'isShapeRecognitionToolActive',\n 'paint-bucket': 'isPaintBucketToolActive',\n lasso: 'isLassoToolActive',\n 'web-embed': 'isWebEmbedToolActive',\n };\n\n const flag = flagMap[toolName];\n if (flag) window[flag] = true;\n\n if (toolName === 'text' && window.isTextInCodeMode) {\n window.isCodeToolActive = true;\n }\n\n // Show image source picker when image tool is activated\n if (toolName === 'image' && window.__showImageSourcePicker) {\n window.__showImageSourcePicker();\n }\n if (toolName === 'web-embed') {\n window.__showWebEmbedModal?.();\n window.dispatchEvent(new CustomEvent('lixsketch:open-web-embed'));\n }\n\n // Set appropriate cursor for the active tool\n const cursorMap = {\n select: 'default',\n pan: 'grab',\n rectangle: 'crosshair',\n circle: 'crosshair',\n line: 'crosshair',\n arrow: 'crosshair',\n freehand: 'crosshair',\n text: 'crosshair',\n code: 'crosshair',\n eraser: 'crosshair',\n laser: 'crosshair',\n image: 'crosshair',\n frame: 'crosshair',\n icon: 'crosshair',\n 'draw-shape': 'crosshair',\n 'paint-bucket': 'cell',\n lasso: 'crosshair',\n 'web-embed': 'crosshair',\n };\n if (this.svg) {\n this.svg.style.cursor = cursorMap[toolName] || 'default';\n }\n }\n\n cleanup() {\n if (typeof window.__cancelShapeRecognition === 'function') {\n window.__cancelShapeRecognition();\n }\n // Remove event listeners from the SVG element\n if (this._modules.core?.eventDispatcher?.cleanupEventDispatcher) {\n this._modules.core.eventDispatcher.cleanupEventDispatcher();\n }\n window.shapes = [];\n window.currentShape = null;\n window.lastMousePos = null;\n window.__sketchInteractionReady = false;\n delete window.__sceneSerializer;\n this._modules = {};\n this._initialized = false;\n console.log('[SketchEngine] Cleaned up');\n }\n}\n\nexport { SketchEngine };\nexport default SketchEngine;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -12,7 +12,7 @@ import {
12
12
  setTextReferences,
13
13
  undo,
14
14
  updateSelectedElement
15
- } from "./chunk-U3TB4KRS.js";
15
+ } from "./chunk-6GPEWDRB.js";
16
16
  export {
17
17
  getCurrentSelectedElement,
18
18
  pushCreateAction,
@@ -27,4 +27,4 @@ export {
27
27
  undo,
28
28
  updateSelectedElement
29
29
  };
30
- //# sourceMappingURL=UndoRedo-NL7KLR5B.js.map
30
+ //# sourceMappingURL=UndoRedo-IN4SXDG6.js.map
@@ -190,7 +190,19 @@ freehandCanvas.addEventListener("wheel", function(e) {
190
190
  }
191
191
  });
192
192
  var isMiddleMousePanning = false;
193
+ var isSpaceMousePanning = false;
193
194
  freehandCanvas.addEventListener("mousedown", function(e) {
195
+ if (e.button === 0 && window.__spacePanActive) {
196
+ e.preventDefault();
197
+ isSpaceMousePanning = true;
198
+ window.__spacePanPointerActive = true;
199
+ isPanning = true;
200
+ startCanvasX = e.clientX;
201
+ startCanvasY = e.clientY;
202
+ panStart = { x: e.clientX, y: e.clientY };
203
+ freehandCanvas.style.cursor = "grabbing";
204
+ return;
205
+ }
194
206
  if (e.button === 1) {
195
207
  e.preventDefault();
196
208
  isMiddleMousePanning = true;
@@ -224,6 +236,13 @@ freehandCanvas.addEventListener("mousemove", (e) => {
224
236
  panStart = { x: e.clientX, y: e.clientY };
225
237
  });
226
238
  freehandCanvas.addEventListener("mouseup", (e) => {
239
+ if (isSpaceMousePanning) {
240
+ isSpaceMousePanning = false;
241
+ window.__spacePanPointerActive = false;
242
+ isPanning = false;
243
+ freehandCanvas.style.cursor = window.__spacePanActive ? "grab" : "";
244
+ return;
245
+ }
227
246
  if (isMiddleMousePanning) {
228
247
  isMiddleMousePanning = false;
229
248
  isPanning = false;
@@ -236,6 +255,13 @@ freehandCanvas.addEventListener("mouseup", (e) => {
236
255
  }
237
256
  });
238
257
  freehandCanvas.addEventListener("mouseleave", () => {
258
+ if (isSpaceMousePanning) {
259
+ isSpaceMousePanning = false;
260
+ window.__spacePanPointerActive = false;
261
+ isPanning = false;
262
+ freehandCanvas.style.cursor = window.__spacePanActive ? "grab" : "";
263
+ return;
264
+ }
239
265
  if (isMiddleMousePanning) {
240
266
  isMiddleMousePanning = false;
241
267
  isPanning = false;
@@ -247,6 +273,13 @@ freehandCanvas.addEventListener("mouseleave", () => {
247
273
  freehandCanvas.style.cursor = "grab";
248
274
  }
249
275
  });
276
+ window.addEventListener("blur", () => {
277
+ if (!isSpaceMousePanning) return;
278
+ isSpaceMousePanning = false;
279
+ window.__spacePanPointerActive = false;
280
+ isPanning = false;
281
+ freehandCanvas.style.cursor = "";
282
+ });
250
283
  freehandCanvas.addEventListener("auxclick", (e) => {
251
284
  if (e.button === 1) e.preventDefault();
252
285
  });
@@ -263,4 +296,4 @@ svg.addEventListener("wheel", (e) => {
263
296
  `${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`
264
297
  );
265
298
  });
266
- //# sourceMappingURL=ZoomPan-FAWA5OPS.js.map
299
+ //# sourceMappingURL=ZoomPan-RR7KUYZT.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/core/ZoomPan.js"],
4
- "sourcesContent": ["/* eslint-disable */\nimport { installScreenSpaceControlSync } from './ScreenSpaceControls.js';\n// Zoom and Pan controls - combined from zoomFunction.js + panCanvas.js\n// Depends on globals: svg, freehandCanvas, currentZoom, currentViewBox, isPanningToolActive, isPanning\n// Depends on globals: minScale, maxScale, zoomInBtn, zoomOutBtn, zoomPercentSpan, panStart, startCanvasX, startCanvasY\n\ninstallScreenSpaceControlSync(freehandCanvas);\n\n// === Zoom Functions ===\nlet currentY = 0;\nconst scrollRate = 50;\n\nfunction updateZoomDisplay() {\n zoomPercentSpan.innerText = Math.round(currentZoom * 100) + \"%\";\n}\n\nfunction updateViewBox(anchorX = null, anchorY = null) {\n const width = window.innerWidth;\n const height = window.innerHeight;\n const scaledWidth = width / currentZoom;\n const scaledHeight = height / currentZoom;\n\n let centerX, centerY;\n\n if (anchorX === null || anchorY === null) {\n centerX = currentViewBox.x + (currentViewBox.width / 2);\n centerY = currentViewBox.y + (currentViewBox.height / 2);\n } else {\n\n centerX = anchorX;\n centerY = anchorY;\n }\n\n const viewBoxX = centerX - (scaledWidth / 2);\n const viewBoxY = centerY - (scaledHeight / 2);\n\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${viewBoxX} ${viewBoxY} ${scaledWidth} ${scaledHeight}`\n );\n\n currentViewBox.x = viewBoxX;\n currentViewBox.y = viewBoxY;\n currentViewBox.width = scaledWidth;\n currentViewBox.height = scaledHeight;\n}\n\nzoomInBtn.addEventListener(\"click\", function() {\n currentZoom *= 1.1;\n if (currentZoom > maxScale) currentZoom = maxScale;\n updateViewBox();\n updateZoomDisplay();\n});\n\nzoomOutBtn.addEventListener(\"click\", function() {\n currentZoom /= 1.1;\n if (currentZoom < minScale) currentZoom = minScale;\n updateViewBox();\n updateZoomDisplay();\n});\n\n// Exposed for React Footer buttons \u2014 zoom from center of canvas\nwindow.zoomFromCenter = function(direction) {\n if (direction > 0) {\n currentZoom *= 1.1;\n if (currentZoom > maxScale) currentZoom = maxScale;\n } else {\n currentZoom /= 1.1;\n if (currentZoom < minScale) currentZoom = minScale;\n }\n updateViewBox(); // null anchors = zoom from center\n updateZoomDisplay();\n // Sync React zoom state\n if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {\n window.__sketchStoreApi.setZoom(currentZoom);\n }\n};\n\nwindow.zoomReset = function() {\n // Issue #24 bug #5: reset zoom in place around the current viewport\n // centre \u2014 do NOT recenter to (0, 0). Recentering used to make whatever\n // the user had on screen vanish until they panned back to it.\n const cx = currentViewBox.x + currentViewBox.width / 2;\n const cy = currentViewBox.y + currentViewBox.height / 2;\n\n currentZoom = 1;\n const rect = freehandCanvas.getBoundingClientRect();\n const vbW = rect.width || window.innerWidth;\n const vbH = rect.height || window.innerHeight;\n\n currentViewBox.x = cx - vbW / 2;\n currentViewBox.y = cy - vbH / 2;\n currentViewBox.width = vbW;\n currentViewBox.height = vbH;\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${currentViewBox.x} ${currentViewBox.y} ${vbW} ${vbH}`\n );\n updateZoomDisplay();\n if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {\n window.__sketchStoreApi.setZoom(1);\n }\n};\n\nfunction getShapeBoundsForFit(shape) {\n if (!shape) return null;\n\n const selection = window.multiSelection;\n if (selection && typeof selection.getShapeBounds === \"function\") {\n try {\n const bounds = selection.getShapeBounds(shape);\n if (bounds && [bounds.x, bounds.y, bounds.width, bounds.height].every(Number.isFinite)) {\n return bounds;\n }\n } catch {}\n }\n\n // Fall back to the common shape interface when selection is unavailable.\n // Accessing x/y instead of boundingBox preserves freehand move offsets.\n const bounds = {\n x: Number(shape.x),\n y: Number(shape.y),\n width: Number(shape.width),\n height: Number(shape.height),\n };\n return Object.values(bounds).every(Number.isFinite) ? bounds : null;\n}\n\nwindow.zoomFit = function() {\n if (!window.shapes || window.shapes.length === 0) {\n if (window.zoomReset) window.zoomReset();\n return;\n }\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n window.shapes.forEach(shape => {\n const bounds = getShapeBoundsForFit(shape);\n if (!bounds) return;\n \n // Normalize coordinates just in case width/height is negative\n const x1 = Math.min(bounds.x, bounds.x + bounds.width);\n const x2 = Math.max(bounds.x, bounds.x + bounds.width);\n const y1 = Math.min(bounds.y, bounds.y + bounds.height);\n const y2 = Math.max(bounds.y, bounds.y + bounds.height);\n\n minX = Math.min(minX, x1);\n minY = Math.min(minY, y1);\n maxX = Math.max(maxX, x2);\n maxY = Math.max(maxY, y2);\n });\n\n if (minX === Infinity) {\n if (window.zoomReset) window.zoomReset();\n return;\n }\n\n const rect = freehandCanvas.getBoundingClientRect();\n const screenW = rect.width || window.innerWidth;\n const screenH = rect.height || window.innerHeight;\n\n const contentW = maxX - minX;\n const contentH = maxY - minY;\n \n // Add 10% padding\n const paddingX = Math.max(50, contentW * 0.1);\n const paddingY = Math.max(50, contentH * 0.1);\n\n const paddedW = contentW + paddingX * 2;\n const paddedH = contentH + paddingY * 2;\n\n // Calculate required zoom to fit the padded content in the screen\n const zoomX = screenW / paddedW;\n const zoomY = screenH / paddedH;\n \n let newZoom = Math.min(zoomX, zoomY);\n newZoom = Math.max(minScale, Math.min(newZoom, maxScale));\n\n // Center coordinate of the content\n const cx = minX + contentW / 2;\n const cy = minY + contentH / 2;\n\n // Set the new viewBox and zoom\n currentZoom = newZoom;\n const vbW = screenW / currentZoom;\n const vbH = screenH / currentZoom;\n\n currentViewBox.x = cx - vbW / 2;\n currentViewBox.y = cy - vbH / 2;\n currentViewBox.width = vbW;\n currentViewBox.height = vbH;\n\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${currentViewBox.x} ${currentViewBox.y} ${vbW} ${vbH}`\n );\n \n updateZoomDisplay();\n if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {\n window.__sketchStoreApi.setZoom(currentZoom);\n }\n};\n\nfreehandCanvas.addEventListener(\"wheel\", function(e) {\n if (!e.ctrlKey) return;\n e.preventDefault();\n\n // Determine the zoom delta\n const delta = e.deltaY > 0 ? -0.1 : 0.1;\n let newZoom = currentZoom + delta;\n if (newZoom < minScale) newZoom = minScale;\n if (newZoom > maxScale) newZoom = maxScale;\n\n // Get canvas bounding rect \u2014 this MUST be the SVG element's actual\n // size, not the window's. In split mode the canvas pane is narrower\n // than the viewport; using window.innerWidth here would produce a\n // viewBox aspect that doesn't match the element, and (with\n // preserveAspectRatio=\"none\" on the host) the content gets stretched\n // / squeezed on every zoom step.\n const rect = freehandCanvas.getBoundingClientRect();\n\n // Calculate mouse position relative to the canvas in pixels\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n\n // Determine what fraction of the canvas the mouse is at\n const mouseFracX = mouseX / rect.width;\n const mouseFracY = mouseY / rect.height;\n\n // Compute the current viewBox coordinate under the mouse.\n // currentViewBox.width and .height represent the current viewBox dimensions.\n const anchorViewBoxX = currentViewBox.x + mouseFracX * currentViewBox.width;\n const anchorViewBoxY = currentViewBox.y + mouseFracY * currentViewBox.height;\n\n // New viewBox dimensions sized to the *element*, scaled by the new\n // zoom. This keeps the viewBox aspect ratio matching the element so\n // shapes stay undistorted.\n const newViewBoxWidth = rect.width / newZoom;\n const newViewBoxHeight = rect.height / newZoom;\n \n // Compute the new viewBox's x and y so that the anchor remains at the same screen fraction.\n // That means:\n // newViewBox.x + mouseFracX * newViewBoxWidth === anchorViewBoxX\n // Solve for newViewBox.x:\n const newViewBoxX = anchorViewBoxX - mouseFracX * newViewBoxWidth;\n const newViewBoxY = anchorViewBoxY - mouseFracY * newViewBoxHeight;\n \n // Update the viewBox attribute with the new values.\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${newViewBoxX} ${newViewBoxY} ${newViewBoxWidth} ${newViewBoxHeight}`\n );\n \n // Update our state\n currentZoom = newZoom;\n currentViewBox = {\n x: newViewBoxX,\n y: newViewBoxY,\n width: newViewBoxWidth,\n height: newViewBoxHeight\n };\n\n updateZoomDisplay();\n // Sync React zoom state\n if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {\n window.__sketchStoreApi.setZoom(currentZoom);\n }\n});\n\n// Function to resize the canvas to fill the screen (initial setup)\nfunction resizeCanvas() {\n const width = window.innerWidth;\n const height = window.innerHeight;\n\n freehandCanvas.style.width = `${width}px`;\n freehandCanvas.style.height = `${height}px`;\n\n // Set initial viewBox based on initial zoom\n updateViewBox(); // Initial center anchor\n}\n\n\n\nlet isMiddleMousePanning = false;\n\nfreehandCanvas.addEventListener(\"mousedown\", function (e) {\n // Middle mouse button panning\n if (e.button === 1) {\n e.preventDefault();\n isMiddleMousePanning = true;\n isPanning = true;\n startCanvasX = e.clientX;\n startCanvasY = e.clientY;\n panStart = { x: e.clientX, y: e.clientY };\n freehandCanvas.style.cursor = 'grabbing';\n return;\n }\n if (isPanningToolActive) {\n isPanning = true;\n startCanvasX = e.clientX;\n startCanvasY = e.clientY;\n panStart = { x: e.clientX, y: e.clientY };\n freehandCanvas.style.cursor = 'grabbing';\n }\n});\n\nfreehandCanvas.addEventListener(\"mousemove\", (e) => {\n if (!isPanning) return;\n\n const dx = e.clientX - panStart.x;\n const dy = e.clientY - panStart.y;\n const dxViewBox = dx / currentZoom;\n const dyViewBox = dy / currentZoom;\n\n currentViewBox.x -= dxViewBox;\n currentViewBox.y -= dyViewBox;\n\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`\n );\n\n panStart = { x: e.clientX, y: e.clientY };\n});\n\nfreehandCanvas.addEventListener(\"mouseup\", (e) => {\n if (isMiddleMousePanning) {\n isMiddleMousePanning = false;\n isPanning = false;\n freehandCanvas.style.cursor = '';\n return;\n }\n if(isPanningToolActive)\n {\n isPanning = false;\n freehandCanvas.style.cursor = 'grab';\n }\n});\n\nfreehandCanvas.addEventListener(\"mouseleave\", () => {\n if (isMiddleMousePanning) {\n isMiddleMousePanning = false;\n isPanning = false;\n freehandCanvas.style.cursor = '';\n return;\n }\n if(isPanningToolActive)\n {\n isPanning = false;\n freehandCanvas.style.cursor = 'grab';\n }\n});\n\n// Prevent default middle-click auto-scroll behavior\nfreehandCanvas.addEventListener(\"auxclick\", (e) => {\n if (e.button === 1) e.preventDefault();\n});\n\n\nsvg.addEventListener(\"wheel\", (e) => {\n e.preventDefault();\n if (e.ctrlKey) return; // Ignore zoom gestures\n\n if (e.shiftKey) {\n // Pan sideways when Shift is held\n currentViewBox.x += e.deltaY > 0 ? scrollRate : -scrollRate;\n } else {\n // Pan vertically\n currentViewBox.y += e.deltaY > 0 ? scrollRate : -scrollRate;\n }\n\n svg.setAttribute(\n \"viewBox\",\n `${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`\n );\n});\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable */\nimport { installScreenSpaceControlSync } from './ScreenSpaceControls.js';\n// Zoom and Pan controls - combined from zoomFunction.js + panCanvas.js\n// Depends on globals: svg, freehandCanvas, currentZoom, currentViewBox, isPanningToolActive, isPanning\n// Depends on globals: minScale, maxScale, zoomInBtn, zoomOutBtn, zoomPercentSpan, panStart, startCanvasX, startCanvasY\n\ninstallScreenSpaceControlSync(freehandCanvas);\n\n// === Zoom Functions ===\nlet currentY = 0;\nconst scrollRate = 50;\n\nfunction updateZoomDisplay() {\n zoomPercentSpan.innerText = Math.round(currentZoom * 100) + \"%\";\n}\n\nfunction updateViewBox(anchorX = null, anchorY = null) {\n const width = window.innerWidth;\n const height = window.innerHeight;\n const scaledWidth = width / currentZoom;\n const scaledHeight = height / currentZoom;\n\n let centerX, centerY;\n\n if (anchorX === null || anchorY === null) {\n centerX = currentViewBox.x + (currentViewBox.width / 2);\n centerY = currentViewBox.y + (currentViewBox.height / 2);\n } else {\n\n centerX = anchorX;\n centerY = anchorY;\n }\n\n const viewBoxX = centerX - (scaledWidth / 2);\n const viewBoxY = centerY - (scaledHeight / 2);\n\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${viewBoxX} ${viewBoxY} ${scaledWidth} ${scaledHeight}`\n );\n\n currentViewBox.x = viewBoxX;\n currentViewBox.y = viewBoxY;\n currentViewBox.width = scaledWidth;\n currentViewBox.height = scaledHeight;\n}\n\nzoomInBtn.addEventListener(\"click\", function() {\n currentZoom *= 1.1;\n if (currentZoom > maxScale) currentZoom = maxScale;\n updateViewBox();\n updateZoomDisplay();\n});\n\nzoomOutBtn.addEventListener(\"click\", function() {\n currentZoom /= 1.1;\n if (currentZoom < minScale) currentZoom = minScale;\n updateViewBox();\n updateZoomDisplay();\n});\n\n// Exposed for React Footer buttons \u2014 zoom from center of canvas\nwindow.zoomFromCenter = function(direction) {\n if (direction > 0) {\n currentZoom *= 1.1;\n if (currentZoom > maxScale) currentZoom = maxScale;\n } else {\n currentZoom /= 1.1;\n if (currentZoom < minScale) currentZoom = minScale;\n }\n updateViewBox(); // null anchors = zoom from center\n updateZoomDisplay();\n // Sync React zoom state\n if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {\n window.__sketchStoreApi.setZoom(currentZoom);\n }\n};\n\nwindow.zoomReset = function() {\n // Issue #24 bug #5: reset zoom in place around the current viewport\n // centre \u2014 do NOT recenter to (0, 0). Recentering used to make whatever\n // the user had on screen vanish until they panned back to it.\n const cx = currentViewBox.x + currentViewBox.width / 2;\n const cy = currentViewBox.y + currentViewBox.height / 2;\n\n currentZoom = 1;\n const rect = freehandCanvas.getBoundingClientRect();\n const vbW = rect.width || window.innerWidth;\n const vbH = rect.height || window.innerHeight;\n\n currentViewBox.x = cx - vbW / 2;\n currentViewBox.y = cy - vbH / 2;\n currentViewBox.width = vbW;\n currentViewBox.height = vbH;\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${currentViewBox.x} ${currentViewBox.y} ${vbW} ${vbH}`\n );\n updateZoomDisplay();\n if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {\n window.__sketchStoreApi.setZoom(1);\n }\n};\n\nfunction getShapeBoundsForFit(shape) {\n if (!shape) return null;\n\n const selection = window.multiSelection;\n if (selection && typeof selection.getShapeBounds === \"function\") {\n try {\n const bounds = selection.getShapeBounds(shape);\n if (bounds && [bounds.x, bounds.y, bounds.width, bounds.height].every(Number.isFinite)) {\n return bounds;\n }\n } catch {}\n }\n\n // Fall back to the common shape interface when selection is unavailable.\n // Accessing x/y instead of boundingBox preserves freehand move offsets.\n const bounds = {\n x: Number(shape.x),\n y: Number(shape.y),\n width: Number(shape.width),\n height: Number(shape.height),\n };\n return Object.values(bounds).every(Number.isFinite) ? bounds : null;\n}\n\nwindow.zoomFit = function() {\n if (!window.shapes || window.shapes.length === 0) {\n if (window.zoomReset) window.zoomReset();\n return;\n }\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n window.shapes.forEach(shape => {\n const bounds = getShapeBoundsForFit(shape);\n if (!bounds) return;\n \n // Normalize coordinates just in case width/height is negative\n const x1 = Math.min(bounds.x, bounds.x + bounds.width);\n const x2 = Math.max(bounds.x, bounds.x + bounds.width);\n const y1 = Math.min(bounds.y, bounds.y + bounds.height);\n const y2 = Math.max(bounds.y, bounds.y + bounds.height);\n\n minX = Math.min(minX, x1);\n minY = Math.min(minY, y1);\n maxX = Math.max(maxX, x2);\n maxY = Math.max(maxY, y2);\n });\n\n if (minX === Infinity) {\n if (window.zoomReset) window.zoomReset();\n return;\n }\n\n const rect = freehandCanvas.getBoundingClientRect();\n const screenW = rect.width || window.innerWidth;\n const screenH = rect.height || window.innerHeight;\n\n const contentW = maxX - minX;\n const contentH = maxY - minY;\n \n // Add 10% padding\n const paddingX = Math.max(50, contentW * 0.1);\n const paddingY = Math.max(50, contentH * 0.1);\n\n const paddedW = contentW + paddingX * 2;\n const paddedH = contentH + paddingY * 2;\n\n // Calculate required zoom to fit the padded content in the screen\n const zoomX = screenW / paddedW;\n const zoomY = screenH / paddedH;\n \n let newZoom = Math.min(zoomX, zoomY);\n newZoom = Math.max(minScale, Math.min(newZoom, maxScale));\n\n // Center coordinate of the content\n const cx = minX + contentW / 2;\n const cy = minY + contentH / 2;\n\n // Set the new viewBox and zoom\n currentZoom = newZoom;\n const vbW = screenW / currentZoom;\n const vbH = screenH / currentZoom;\n\n currentViewBox.x = cx - vbW / 2;\n currentViewBox.y = cy - vbH / 2;\n currentViewBox.width = vbW;\n currentViewBox.height = vbH;\n\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${currentViewBox.x} ${currentViewBox.y} ${vbW} ${vbH}`\n );\n \n updateZoomDisplay();\n if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {\n window.__sketchStoreApi.setZoom(currentZoom);\n }\n};\n\nfreehandCanvas.addEventListener(\"wheel\", function(e) {\n if (!e.ctrlKey) return;\n e.preventDefault();\n\n // Determine the zoom delta\n const delta = e.deltaY > 0 ? -0.1 : 0.1;\n let newZoom = currentZoom + delta;\n if (newZoom < minScale) newZoom = minScale;\n if (newZoom > maxScale) newZoom = maxScale;\n\n // Get canvas bounding rect \u2014 this MUST be the SVG element's actual\n // size, not the window's. In split mode the canvas pane is narrower\n // than the viewport; using window.innerWidth here would produce a\n // viewBox aspect that doesn't match the element, and (with\n // preserveAspectRatio=\"none\" on the host) the content gets stretched\n // / squeezed on every zoom step.\n const rect = freehandCanvas.getBoundingClientRect();\n\n // Calculate mouse position relative to the canvas in pixels\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n\n // Determine what fraction of the canvas the mouse is at\n const mouseFracX = mouseX / rect.width;\n const mouseFracY = mouseY / rect.height;\n\n // Compute the current viewBox coordinate under the mouse.\n // currentViewBox.width and .height represent the current viewBox dimensions.\n const anchorViewBoxX = currentViewBox.x + mouseFracX * currentViewBox.width;\n const anchorViewBoxY = currentViewBox.y + mouseFracY * currentViewBox.height;\n\n // New viewBox dimensions sized to the *element*, scaled by the new\n // zoom. This keeps the viewBox aspect ratio matching the element so\n // shapes stay undistorted.\n const newViewBoxWidth = rect.width / newZoom;\n const newViewBoxHeight = rect.height / newZoom;\n \n // Compute the new viewBox's x and y so that the anchor remains at the same screen fraction.\n // That means:\n // newViewBox.x + mouseFracX * newViewBoxWidth === anchorViewBoxX\n // Solve for newViewBox.x:\n const newViewBoxX = anchorViewBoxX - mouseFracX * newViewBoxWidth;\n const newViewBoxY = anchorViewBoxY - mouseFracY * newViewBoxHeight;\n \n // Update the viewBox attribute with the new values.\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${newViewBoxX} ${newViewBoxY} ${newViewBoxWidth} ${newViewBoxHeight}`\n );\n \n // Update our state\n currentZoom = newZoom;\n currentViewBox = {\n x: newViewBoxX,\n y: newViewBoxY,\n width: newViewBoxWidth,\n height: newViewBoxHeight\n };\n\n updateZoomDisplay();\n // Sync React zoom state\n if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {\n window.__sketchStoreApi.setZoom(currentZoom);\n }\n});\n\n// Function to resize the canvas to fill the screen (initial setup)\nfunction resizeCanvas() {\n const width = window.innerWidth;\n const height = window.innerHeight;\n\n freehandCanvas.style.width = `${width}px`;\n freehandCanvas.style.height = `${height}px`;\n\n // Set initial viewBox based on initial zoom\n updateViewBox(); // Initial center anchor\n}\n\n\n\nlet isMiddleMousePanning = false;\nlet isSpaceMousePanning = false;\n\nfreehandCanvas.addEventListener(\"mousedown\", function (e) {\n // Space + primary button temporarily owns the pointer, regardless of the\n // active drawing tool. EventDispatcher yields while this flag is active.\n if (e.button === 0 && window.__spacePanActive) {\n e.preventDefault();\n isSpaceMousePanning = true;\n window.__spacePanPointerActive = true;\n isPanning = true;\n startCanvasX = e.clientX;\n startCanvasY = e.clientY;\n panStart = { x: e.clientX, y: e.clientY };\n freehandCanvas.style.cursor = 'grabbing';\n return;\n }\n // Middle mouse button panning\n if (e.button === 1) {\n e.preventDefault();\n isMiddleMousePanning = true;\n isPanning = true;\n startCanvasX = e.clientX;\n startCanvasY = e.clientY;\n panStart = { x: e.clientX, y: e.clientY };\n freehandCanvas.style.cursor = 'grabbing';\n return;\n }\n if (isPanningToolActive) {\n isPanning = true;\n startCanvasX = e.clientX;\n startCanvasY = e.clientY;\n panStart = { x: e.clientX, y: e.clientY };\n freehandCanvas.style.cursor = 'grabbing';\n }\n});\n\nfreehandCanvas.addEventListener(\"mousemove\", (e) => {\n if (!isPanning) return;\n\n const dx = e.clientX - panStart.x;\n const dy = e.clientY - panStart.y;\n const dxViewBox = dx / currentZoom;\n const dyViewBox = dy / currentZoom;\n\n currentViewBox.x -= dxViewBox;\n currentViewBox.y -= dyViewBox;\n\n freehandCanvas.setAttribute(\n \"viewBox\",\n `${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`\n );\n\n panStart = { x: e.clientX, y: e.clientY };\n});\n\nfreehandCanvas.addEventListener(\"mouseup\", (e) => {\n if (isSpaceMousePanning) {\n isSpaceMousePanning = false;\n window.__spacePanPointerActive = false;\n isPanning = false;\n freehandCanvas.style.cursor = window.__spacePanActive ? 'grab' : '';\n return;\n }\n if (isMiddleMousePanning) {\n isMiddleMousePanning = false;\n isPanning = false;\n freehandCanvas.style.cursor = '';\n return;\n }\n if(isPanningToolActive)\n {\n isPanning = false;\n freehandCanvas.style.cursor = 'grab';\n }\n});\n\nfreehandCanvas.addEventListener(\"mouseleave\", () => {\n if (isSpaceMousePanning) {\n isSpaceMousePanning = false;\n window.__spacePanPointerActive = false;\n isPanning = false;\n freehandCanvas.style.cursor = window.__spacePanActive ? 'grab' : '';\n return;\n }\n if (isMiddleMousePanning) {\n isMiddleMousePanning = false;\n isPanning = false;\n freehandCanvas.style.cursor = '';\n return;\n }\n if(isPanningToolActive)\n {\n isPanning = false;\n freehandCanvas.style.cursor = 'grab';\n }\n});\n\nwindow.addEventListener(\"blur\", () => {\n if (!isSpaceMousePanning) return;\n isSpaceMousePanning = false;\n window.__spacePanPointerActive = false;\n isPanning = false;\n freehandCanvas.style.cursor = '';\n});\n\n// Prevent default middle-click auto-scroll behavior\nfreehandCanvas.addEventListener(\"auxclick\", (e) => {\n if (e.button === 1) e.preventDefault();\n});\n\n\nsvg.addEventListener(\"wheel\", (e) => {\n e.preventDefault();\n if (e.ctrlKey) return; // Ignore zoom gestures\n\n if (e.shiftKey) {\n // Pan sideways when Shift is held\n currentViewBox.x += e.deltaY > 0 ? scrollRate : -scrollRate;\n } else {\n // Pan vertically\n currentViewBox.y += e.deltaY > 0 ? scrollRate : -scrollRate;\n }\n\n svg.setAttribute(\n \"viewBox\",\n `${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`\n );\n});\n"],
5
+ "mappings": "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",
6
6
  "names": ["bounds"]
7
7
  }
@@ -5,8 +5,8 @@ import {
5
5
  handleMouseMove,
6
6
  handleMouseUp,
7
7
  updateAttachedArrows
8
- } from "./chunk-YF3TK7SC.js";
9
- import "./chunk-U3TB4KRS.js";
8
+ } from "./chunk-XYUFEIZR.js";
9
+ import "./chunk-6GPEWDRB.js";
10
10
  export {
11
11
  cleanupAttachments,
12
12
  handleMouseDown as handleMouseDownArrow,
@@ -14,4 +14,4 @@ export {
14
14
  handleMouseUp as handleMouseUpArrow,
15
15
  updateAttachedArrows
16
16
  };
17
- //# sourceMappingURL=arrowTool-CNVGM6RX.js.map
17
+ //# sourceMappingURL=arrowTool-OYDWJGQK.js.map
@@ -361,11 +361,12 @@ function pushTransformAction(shape, oldPos, newPos) {
361
361
  redoStack.length = 0;
362
362
  notifyCollaboration();
363
363
  }
364
- function pushOptionsChangeAction(shape, oldOptions) {
364
+ function pushOptionsChangeAction(shape, oldOptions, newOptions = null) {
365
365
  undoStack.push({
366
366
  type: "optionsChange",
367
367
  shape,
368
- oldOptions
368
+ oldOptions,
369
+ newOptions
369
370
  });
370
371
  redoStack.length = 0;
371
372
  notifyCollaboration();
@@ -731,6 +732,15 @@ function undo() {
731
732
  return;
732
733
  }
733
734
  if (action.type === "optionsChange") {
735
+ if (!action.newOptions && action.shape?.options) {
736
+ action.newOptions = action.shape.shapeName === "arrow" ? {
737
+ ...action.shape.options,
738
+ arrowOutlineStyle: action.shape.arrowOutlineStyle,
739
+ arrowHeadStyle: action.shape.arrowHeadStyle,
740
+ arrowCurved: action.shape.arrowCurved,
741
+ arrowCurveAmount: action.shape.arrowCurveAmount
742
+ } : { ...action.shape.options };
743
+ }
734
744
  if (action.shape.type === "text") {
735
745
  const textElement = (action.shape.element || action.shape).querySelector("text");
736
746
  if (textElement) {
@@ -1128,17 +1138,14 @@ function redo() {
1128
1138
  }
1129
1139
  }
1130
1140
  } else if (action.shape.shapeName === "arrow") {
1131
- const currentOptions = {
1132
- ...action.shape.options,
1133
- arrowOutlineStyle: action.shape.arrowOutlineStyle,
1134
- arrowHeadStyle: action.shape.arrowHeadStyle,
1135
- arrowCurved: action.shape.arrowCurved,
1136
- arrowCurveAmount: action.shape.arrowCurveAmount
1137
- };
1138
- action.newOptions = currentOptions;
1141
+ action.shape.options = { ...action.newOptions };
1142
+ action.shape.arrowOutlineStyle = action.newOptions.arrowOutlineStyle;
1143
+ action.shape.arrowHeadStyle = action.newOptions.arrowHeadStyle;
1144
+ action.shape.arrowCurved = action.newOptions.arrowCurved;
1145
+ action.shape.arrowCurveAmount = action.newOptions.arrowCurveAmount;
1139
1146
  action.shape.draw();
1140
1147
  } else {
1141
- action.newOptions = action.shape.options;
1148
+ action.shape.options = { ...action.newOptions };
1142
1149
  action.shape.draw();
1143
1150
  }
1144
1151
  undoStack.push(action);
@@ -1184,4 +1191,4 @@ export {
1184
1191
  undo,
1185
1192
  redo
1186
1193
  };
1187
- //# sourceMappingURL=chunk-U3TB4KRS.js.map
1194
+ //# sourceMappingURL=chunk-6GPEWDRB.js.map