diff --git a/css/styles.css b/css/styles.css index 7f9a60e..44b65be 100644 --- a/css/styles.css +++ b/css/styles.css @@ -435,6 +435,7 @@ body { position: absolute; cursor: move; user-select: none; + touch-action: none; /* Allow custom touch handling for dragging */ } .element.selected { @@ -616,6 +617,7 @@ body { font-size: 13px; color: #333; font-family: inherit; + touch-action: auto; /* Allow normal touch interactions for inputs */ } .property-group textarea { diff --git a/js/modules/Canvas.js b/js/modules/Canvas.js index 2c19e2d..34da1a2 100644 --- a/js/modules/Canvas.js +++ b/js/modules/Canvas.js @@ -233,6 +233,31 @@ class Canvas { }); } + // Helper method to get DOM node for an element + getElementDomNode(elementId) { + return this.content.querySelector(`[data-id="${elementId}"]`); + } + + // Helper method to update element position in DOM + updateElementPosition(elementId, x, y) { + const domElement = this.getElementDomNode(elementId); + if (domElement) { + domElement.style.left = x + 'px'; + domElement.style.top = y + 'px'; + } + } + + // Helper method to update element styles in DOM + updateElementStyles(elementId, updates) { + const domElement = this.getElementDomNode(elementId); + if (domElement) { + if (updates.x !== undefined) domElement.style.left = updates.x + 'px'; + if (updates.y !== undefined) domElement.style.top = updates.y + 'px'; + if (updates.width !== undefined) domElement.style.width = updates.width + 'px'; + if (updates.height !== undefined) domElement.style.height = updates.height + 'px'; + } + } + handleElementMouseDown(e, elementId) { if (e.button !== 0) return; e.stopPropagation(); @@ -268,7 +293,10 @@ class Canvas { if (this.isDragging && this.state.selectedElementId && this.dragStart) { const newX = (e.clientX - this.dragStart.x) / this.state.zoom; const newY = (e.clientY - this.dragStart.y) / this.state.zoom; - this.state.updateElement(this.state.selectedElementId, { x: newX, y: newY }); + this.state.updateElementSilent(this.state.selectedElementId, { x: newX, y: newY }); + + // Manually update DOM element position for smooth dragging + this.updateElementPosition(this.state.selectedElementId, newX, newY); } else if (this.isResizing && this.state.selectedElementId && this.resizeStart) { const dx = e.clientX - this.resizeStart.x; @@ -293,7 +321,10 @@ class Canvas { updates.y = this.resizeStart.elementY + (this.resizeStart.elementHeight - newHeight); } - this.state.updateElement(this.state.selectedElementId, updates); + this.state.updateElementSilent(this.state.selectedElementId, updates); + + // Manually update DOM element for smooth resizing + this.updateElementStyles(this.state.selectedElementId, updates); } // Update cursor @@ -305,6 +336,7 @@ class Canvas { handleMouseUp() { if (this.isDragging || this.isResizing) { this.state.saveHistory(); + this.state.notify(); // Trigger re-render with final positions this.isDragging = false; this.isResizing = false; this.dragStart = null; @@ -376,7 +408,10 @@ class Canvas { const touch = e.touches[0]; const newX = (touch.clientX - this.dragStart.x) / this.state.zoom; const newY = (touch.clientY - this.dragStart.y) / this.state.zoom; - this.state.updateElement(this.state.selectedElementId, { x: newX, y: newY }); + this.state.updateElementSilent(this.state.selectedElementId, { x: newX, y: newY }); + + // Manually update DOM element position for smooth dragging + this.updateElementPosition(this.state.selectedElementId, newX, newY); } else if (this.isResizing && this.state.selectedElementId && this.resizeStart) { e.preventDefault(); @@ -403,7 +438,10 @@ class Canvas { updates.y = this.resizeStart.elementY + (this.resizeStart.elementHeight - newHeight); } - this.state.updateElement(this.state.selectedElementId, updates); + this.state.updateElementSilent(this.state.selectedElementId, updates); + + // Manually update DOM element for smooth resizing + this.updateElementStyles(this.state.selectedElementId, updates); } // Update cursor @@ -415,6 +453,7 @@ class Canvas { handleTouchEnd() { if (this.isDragging || this.isResizing) { this.state.saveHistory(); + this.state.notify(); // Trigger re-render with final positions this.isDragging = false; this.isResizing = false; this.dragStart = null; diff --git a/js/modules/StateManager.js b/js/modules/StateManager.js index 2787d41..f580383 100644 --- a/js/modules/StateManager.js +++ b/js/modules/StateManager.js @@ -159,6 +159,17 @@ class StateManager { } } + // Update element without triggering notification (for dragging/resizing) + updateElementSilent(id, updates) { + const page = this.getCurrentPage(); + if (!page) return; + + const element = page.elements.find(el => el.id === id); + if (element) { + Object.assign(element, updates); + } + } + // Delete element deleteElement(id) { const page = this.getCurrentPage(); @@ -174,8 +185,10 @@ class StateManager { // Select element selectElement(id) { - this.selectedElementId = id; - this.notify(); + if (this.selectedElementId !== id) { + this.selectedElementId = id; + this.notify(); + } } // Deselect element