diff --git a/frontend/src/lib/actions/clickOutside.svelte.spec.ts b/frontend/src/lib/actions/clickOutside.svelte.spec.ts index 81917cb0..1616b463 100644 --- a/frontend/src/lib/actions/clickOutside.svelte.spec.ts +++ b/frontend/src/lib/actions/clickOutside.svelte.spec.ts @@ -51,6 +51,18 @@ describe('clickOutside action', () => { expect(fired).toBe(false); }); + it('does not dispatch clickoutside when event.defaultPrevented is true', () => { + const node = makeNode(); + const outside = makeNode(); + let fired = false; + node.addEventListener('clickoutside', () => (fired = true)); + clickOutside(node); + const event = new MouseEvent('click', { bubbles: true, cancelable: true }); + event.preventDefault(); + outside.dispatchEvent(event); + expect(fired).toBe(false); + }); + it('removes the listener on destroy', () => { const node = makeNode(); const outside = makeNode(); diff --git a/frontend/src/lib/actions/clickOutside.ts b/frontend/src/lib/actions/clickOutside.ts index ef7fc3a2..018b4736 100644 --- a/frontend/src/lib/actions/clickOutside.ts +++ b/frontend/src/lib/actions/clickOutside.ts @@ -5,6 +5,7 @@ export function clickOutside(node: HTMLElement): { destroy: () => void } { } } + // Capture phase (true) ensures this fires before any child stopPropagation() calls. document.addEventListener('click', handleClick, true); return {