fix: allow tldraw context menus in tauri

This commit is contained in:
lucaronin
2026-05-08 10:06:25 +02:00
parent 5e978e315e
commit cef3e6a805
2 changed files with 62 additions and 1 deletions

View File

@@ -22,6 +22,7 @@ import { shouldUseLinuxWindowChrome } from './utils/platform'
import { reloadFrontendOnceIfStartupFailed } from './utils/frontendReady'
const EDITOR_DROP_SELECTOR = '.editor__blocknote-container'
const TLDRAW_CONTEXT_MENU_SELECTOR = '.tldraw-whiteboard'
function dataTransferHasFiles(dataTransfer: DataTransfer | null): boolean {
if (!dataTransfer) return false
@@ -42,6 +43,16 @@ function preventFileDropNavigation(event: DragEvent): void {
event.preventDefault()
}
function isTldrawContextMenuTarget(target: EventTarget | null): boolean {
return target instanceof Element && target.closest(TLDRAW_CONTEXT_MENU_SELECTOR) !== null
}
function preventNativeContextMenu(event: MouseEvent): void {
if (isTldrawContextMenuTarget(event.target)) return
event.preventDefault()
}
document.addEventListener('dragover', preventFileDropNavigation, true)
document.addEventListener('drop', preventFileDropNavigation, true)
@@ -50,7 +61,7 @@ document.addEventListener('drop', preventFileDropNavigation, true)
// Capture phase fires first → prevents native menu; React bubble phase still fires
// → our custom context menus (e.g. sidebar right-click) work correctly.
if ('__TAURI__' in window || '__TAURI_INTERNALS__' in window) {
document.addEventListener('contextmenu', (e) => e.preventDefault(), true)
document.addEventListener('contextmenu', preventNativeContextMenu, true)
}
if (shouldUseLinuxWindowChrome()) {

View File

@@ -6,6 +6,14 @@ import { executeCommand, openCommandPalette } from './helpers'
let tempVaultDir: string
type TauriHarnessWindow = Window & typeof globalThis & {
isTauri?: boolean
__TAURI__?: unknown
__TAURI_INTERNALS__?: {
invoke?: () => Promise<never>
}
}
const WHITEBOARD_NOTE = [
'# Whiteboard Embed',
'',
@@ -18,11 +26,15 @@ const WHITEBOARD_NOTE = [
'Context after the board.',
'',
].join('\n')
const TAURI_CONTEXT_MENU_TEST = 'embedded tldraw context menu opens from a native right-click path'
test.beforeEach(async ({ page }, testInfo) => {
testInfo.setTimeout(90_000)
tempVaultDir = createFixtureVaultCopy()
fs.writeFileSync(path.join(tempVaultDir, 'note', 'whiteboard-embed.md'), WHITEBOARD_NOTE)
if (testInfo.title === TAURI_CONTEXT_MENU_TEST) {
await installTauriContextMenuHarness(page)
}
await openFixtureVault(page, tempVaultDir)
})
@@ -35,6 +47,20 @@ async function openNote(page: Page, title: string): Promise<void> {
await expect(page.locator('.bn-editor')).toBeVisible({ timeout: 5_000 })
}
async function installTauriContextMenuHarness(page: Page): Promise<void> {
await page.addInitScript(() => {
const harnessWindow = window as TauriHarnessWindow
harnessWindow.isTauri = false
harnessWindow.__TAURI__ = harnessWindow.__TAURI__ ?? {}
harnessWindow.__TAURI_INTERNALS__ = {
...harnessWindow.__TAURI_INTERNALS__,
invoke: async () => {
throw new Error('No native bridge in context menu harness')
},
}
})
}
async function toggleRawMode(page: Page, visibleSelector: '.bn-editor' | '.cm-content'): Promise<void> {
await openCommandPalette(page)
await executeCommand(page, 'Toggle Raw')
@@ -180,6 +206,30 @@ test('embedded tldraw dialogs appear and release focus when closed', async ({ pa
await expectNoEditorNodeSelection(page)
})
test(TAURI_CONTEXT_MENU_TEST, async ({ page }) => {
await openNote(page, 'Whiteboard Embed')
const whiteboard = page.locator('.tldraw-whiteboard')
await expect(whiteboard).toBeVisible({ timeout: 20_000 })
const boardBox = await whiteboard.boundingBox()
expect(boardBox).not.toBeNull()
const canvas = page.getByTestId('canvas')
await canvas.click({ position: { x: 160, y: 160 } })
await canvas.click({ button: 'right', position: { x: 160, y: 160 } })
const contextMenu = page.getByTestId('context-menu')
await expect(contextMenu).toBeVisible({ timeout: 5_000 })
const menuBox = await contextMenu.boundingBox()
expect(menuBox).not.toBeNull()
expect(menuBox!.x).toBeGreaterThanOrEqual(boardBox!.x - 1)
expect(menuBox!.x + menuBox!.width).toBeLessThanOrEqual(boardBox!.x + boardBox!.width + 1)
await expectNoEditorNodeSelection(page)
await page.keyboard.press('Escape')
await expect(contextMenu).toHaveCount(0)
})
test('embedded tldraw drawing uses the clicked coordinates while zoomed', async ({ page }) => {
await openNote(page, 'Whiteboard Embed')
await applyZoom(page, 110)