From 49ad467aa99022f28cdac263e973102c8e29e449 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Tue, 28 Apr 2026 22:30:43 +0200 Subject: [PATCH] Switch pane resize handle to pointer events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit internal/notesium/web/app/pane.js drove the sidebar/pane resize via mousedown + window-level mousemove/mouseup, which doesn't fire on touch (browsers only emulate mouse for taps, not drags). Replaced with pointer events: - @pointerdown on the handle (covers mouse, touch, pen). - setPointerCapture so we keep receiving pointermove/pointerup events when the pointer drifts off the handle. This eliminates the need for document-level listeners and avoids stuck-drag states when the user releases outside the window. - pointermove + pointerup + pointercancel listeners on the captured target only — when the capture ends they're removed regardless of whether the user is still on top of the handle. - Filter on event.pointerId so a second simultaneous touch (e.g., a multi-finger gesture) cannot hijack the in-progress resize. - event.button !== 0 guard rejects right-click / middle-click. - touch-action: none on the handle so the browser doesn't try to interpret a horizontal drag as a page scroll. CodeMirror's internal mousedown handlers in note.js / preview.js are left alone — those are link-click guards, not drags, and CodeMirror's own pointer support handles touch internally. Closes #20. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/notesium/web/app/pane.js | 35 ++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/internal/notesium/web/app/pane.js b/internal/notesium/web/app/pane.js index 6d47984..fe5e61e 100644 --- a/internal/notesium/web/app/pane.js +++ b/internal/notesium/web/app/pane.js @@ -4,9 +4,10 @@ var t = `
-
+ class="z-50 absolute group inset-y-0 cursor-ew-resize flex items-center" + style="touch-action: none;">
@@ -26,29 +27,49 @@ export default { startResizeClientX: null, startResizePaneWidth: null, resizing: false, + activePointerId: null, } }, methods: { startResize(event) { + // Only respond to primary button / single touch / pen. + // event.button is 0 for primary mouse and is also 0 for + // touch / pen via PointerEvent. + if (event.button !== undefined && event.button !== 0) return; this.startResizeClientX = event.clientX; this.startResizePaneWidth = this.paneWidth; this.maxWidth = this.$el.parentElement.offsetWidth - 50; this.resizing = true; + this.activePointerId = event.pointerId; event.preventDefault(); - document.addEventListener('mousemove', this.doResize); - document.addEventListener('mouseup', this.stopResize); + // Capture the pointer so we keep getting move/up events even + // when the pointer leaves the handle. This replaces the + // window-level mousemove/mouseup listeners and handles touch + // and pen identically. + try { event.target.setPointerCapture(event.pointerId); } catch (_) {} + event.target.addEventListener('pointermove', this.doResize); + event.target.addEventListener('pointerup', this.stopResize); + event.target.addEventListener('pointercancel', this.stopResize); }, doResize(event) { + if (event.pointerId !== this.activePointerId) return; let draggedDistance = event.clientX - this.startResizeClientX; if (this.direction === 'left') draggedDistance = -draggedDistance; const newWidth = this.startResizePaneWidth + draggedDistance; if (newWidth <= this.maxWidth && newWidth >= this.minWidth ) this.paneWidth = newWidth; }, - stopResize() { + stopResize(event) { + if (event && event.pointerId !== this.activePointerId) return; this.resizing = false; this.savePreferredWidth(); - document.removeEventListener('mousemove', this.doResize); - document.removeEventListener('mouseup', this.stopResize); + const target = event && event.target; + if (target) { + try { target.releasePointerCapture(this.activePointerId); } catch (_) {} + target.removeEventListener('pointermove', this.doResize); + target.removeEventListener('pointerup', this.stopResize); + target.removeEventListener('pointercancel', this.stopResize); + } + this.activePointerId = null; }, setDefaultWidth() { this.paneWidth = this.defaultWidth;