From 15f7e759d15fb9c3c8f82a7b74a194944b152b42 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Sat, 21 Mar 2026 20:44:28 -0700 Subject: [PATCH] fix(canvas): map shape interaction + reminder widget dismissal Map viewer: disable MapLibre interactions when inside a folk-shape until editing mode (double-click). Prevents map panning when trying to select/move the shape on canvas. Reminder widget: dismiss on Escape key and when clicking elsewhere on canvas (deselecting shapes). Clean up schedule icon when shape is deleted. Co-Authored-By: Claude Opus 4.6 --- modules/rmaps/components/folk-map-viewer.ts | 55 +++++++++++++++++++++ website/canvas.html | 10 ++++ 2 files changed, 65 insertions(+) diff --git a/modules/rmaps/components/folk-map-viewer.ts b/modules/rmaps/components/folk-map-viewer.ts index f39c5b3..2197d5b 100644 --- a/modules/rmaps/components/folk-map-viewer.ts +++ b/modules/rmaps/components/folk-map-viewer.ts @@ -158,6 +158,18 @@ class FolkMapViewer extends HTMLElement { if (!localStorage.getItem("rmaps_tour_done")) { setTimeout(() => this._tour.start(), 1200); } + + // When inside a folk-shape, block map interactions until editing mode + const parentShape = this.closest("folk-shape"); + if (parentShape) { + this._parentShape = parentShape; + this._onEditEnter = () => this.setMapInteractive(true); + this._onEditExit = () => this.setMapInteractive(false); + parentShape.addEventListener("edit-enter", this._onEditEnter); + parentShape.addEventListener("edit-exit", this._onEditExit); + // Start with interactions disabled + this.setMapInteractive(false); + } } disconnectedCallback() { @@ -167,6 +179,44 @@ class FolkMapViewer extends HTMLElement { this._themeObserver = null; } if (this.stalenessTimer) { clearInterval(this.stalenessTimer); this.stalenessTimer = null; } + if (this._parentShape) { + this._parentShape.removeEventListener("edit-enter", this._onEditEnter!); + this._parentShape.removeEventListener("edit-exit", this._onEditExit!); + this._parentShape = null; + } + } + + private _parentShape: Element | null = null; + private _onEditEnter: (() => void) | null = null; + private _onEditExit: (() => void) | null = null; + private _mapInteractive = true; + + private setMapInteractive(interactive: boolean) { + this._mapInteractive = interactive; + if (this.map) { + if (interactive) { + this.map.scrollZoom?.enable(); + this.map.boxZoom?.enable(); + this.map.dragRotate?.enable(); + this.map.dragPan?.enable(); + this.map.keyboard?.enable(); + this.map.doubleClickZoom?.enable(); + this.map.touchZoomRotate?.enable(); + } else { + this.map.scrollZoom?.disable(); + this.map.boxZoom?.disable(); + this.map.dragRotate?.disable(); + this.map.dragPan?.disable(); + this.map.keyboard?.disable(); + this.map.doubleClickZoom?.disable(); + this.map.touchZoomRotate?.disable(); + } + } + // Also toggle pointer-events on the map container + const container = this.shadow.getElementById("map-container"); + if (container) { + container.style.pointerEvents = interactive ? "" : "none"; + } } // ─── User profile ──────────────────────────────────────────── @@ -1083,6 +1133,11 @@ class FolkMapViewer extends HTMLElement { this.map.addControl(new (window as any).maplibregl.NavigationControl(), "top-right"); + // If inside a folk-shape and not in editing mode, disable map interactions + if (this._parentShape && !this._mapInteractive) { + this.setMapInteractive(false); + } + // Apply dark mode inversion filter to OSM tiles this.applyDarkFilter(); diff --git a/website/canvas.html b/website/canvas.html index c579acc..54d4d9e 100644 --- a/website/canvas.html +++ b/website/canvas.html @@ -3192,6 +3192,7 @@ } } if (scheduleIconEl) scheduleIconEl.classList.remove("visible"); + if (rwWidget) rwWidget.classList.remove("visible"); } function rectsOverlapScreen(sel, r) { @@ -3552,6 +3553,9 @@ // Also remove wb-svg elements from the overlay const wbEl = wbOverlay?.querySelector(`[data-wb-id="${shapeId}"]`); if (wbEl) wbEl.remove(); + // Hide schedule icon and reminder widget if deleted shape was selected + selectedShapeIds.delete(shapeId); + updateSelectionVisuals(); }); // Three-state: update shape visual when state changes @@ -3887,6 +3891,12 @@ if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA" || e.target.isContentEditable) return; if (e.key === "Escape") { + // Dismiss reminder widget if open + if (rwWidget?.classList.contains("visible")) { + rwWidget.classList.remove("visible"); + if (scheduleIconEl) scheduleIconEl.classList.add("visible"); + return; + } if (wbTool) setWbTool(null); if (pendingTool) clearPendingTool(); if (connectMode) {