diff --git a/scripts/menuModalGuards.test.ts b/scripts/menuModalGuards.test.ts new file mode 100644 index 0000000..b6dbb38 --- /dev/null +++ b/scripts/menuModalGuards.test.ts @@ -0,0 +1,23 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const viewer = readFileSync(new URL('../src/lib/MarkdownViewer.svelte', import.meta.url), 'utf8'); +const titleBar = readFileSync(new URL('../src/lib/components/TitleBar.svelte', import.meta.url), 'utf8'); +const modal = readFileSync(new URL('../src/lib/components/Modal.svelte', import.meta.url), 'utf8'); + +test('document context menus do not open while a modal is active', () => { + assert.match( + viewer, + /function handleContextMenu\(e: MouseEvent\) \{\n\t\tif \(modalState\.show\) return;/, + ); +}); + +test('titlebar menus close before a document context menu opens', () => { + assert.match(titleBar, /window\.addEventListener\('contextmenu', handleGlobalDismiss\)/); + assert.match(titleBar, /window\.addEventListener\('blur', handleGlobalDismiss\)/); +}); + +test('modal backdrop consumes context-menu events', () => { + assert.match(modal, /oncontextmenu=\{\(e\) => \{ e\.preventDefault\(\); e\.stopPropagation\(\); \}\}/); +}); diff --git a/src/lib/MarkdownViewer.svelte b/src/lib/MarkdownViewer.svelte index df723ec..103f5e2 100644 --- a/src/lib/MarkdownViewer.svelte +++ b/src/lib/MarkdownViewer.svelte @@ -2093,6 +2093,7 @@ import { t } from './utils/i18n.js'; } function handleContextMenu(e: MouseEvent) { + if (modalState.show) return; if (mode !== 'app') return; e.preventDefault(); diff --git a/src/lib/components/Modal.svelte b/src/lib/components/Modal.svelte index a4c45ce..279d2fc 100644 --- a/src/lib/components/Modal.svelte +++ b/src/lib/components/Modal.svelte @@ -97,7 +97,12 @@ {#if show} -