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 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-21 20:44:28 -07:00
parent d5e822ec7c
commit 15f7e759d1
2 changed files with 65 additions and 0 deletions

View File

@ -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();

View File

@ -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) {