diff --git a/lib/folk-shape.ts b/lib/folk-shape.ts index d183868..4bbda8e 100644 --- a/lib/folk-shape.ts +++ b/lib/folk-shape.ts @@ -576,10 +576,14 @@ export class FolkShape extends FolkElement { const isDragHandle = target?.closest?.(".header, [data-drag]") !== null; if (event instanceof PointerEvent) { + // For pointerdown on non-drag targets (content areas, inputs, etc.), + // stop immediate propagation so canvas selection/snap listeners don't fire. + if (event.type === "pointerdown" && target !== this && !handle && !isDragHandle) { + event.stopImmediatePropagation(); + return; + } event.stopPropagation(); if (event.type === "pointerdown") { - // Allow drag from: the host itself, a handle, or a drag handle element - if (target !== this && !handle && !isDragHandle) return; // If clicking on the shape body (not a handle), check if a text input // is under the pointer — if so, enter edit mode immediately instead of dragging. diff --git a/website/canvas.html b/website/canvas.html index 9d265a5..f3dc736 100644 --- a/website/canvas.html +++ b/website/canvas.html @@ -3777,8 +3777,15 @@ Use real coordinates, YYYY-MM-DD dates, ISO currency codes. Ask clarifying quest const shapeLastPos = new Map(); function setupShapeEventListeners(shape) { - // Track position for group dragging - shape.addEventListener("pointerdown", () => { + // Track position for group dragging — only for actual drag targets + // (host element, resize/rotation handles, or drag handles like .header) + shape.addEventListener("pointerdown", (e) => { + const target = e.composedPath()[0]; + const isHost = target === shape; + const isHandle = target?.getAttribute?.("part")?.startsWith?.("resize") || + target?.getAttribute?.("part")?.startsWith?.("rotation"); + const isDragHandle = target?.closest?.(".header, [data-drag]") !== null; + if (!isHost && !isHandle && !isDragHandle) return; shapeLastPos.set(shape.id, { x: shape.x, y: shape.y }); onShapeMoveStart(shape); }, { capture: true });