diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index caa8a2f5..af372662 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -34,7 +34,7 @@ "csp": { "default-src": "'self' ipc: http://ipc.localhost", "script-src": "'self' https://us.i.posthog.com https://eu.i.posthog.com https://us-assets.i.posthog.com https://eu-assets.i.posthog.com", - "connect-src": "'self' ipc: http://ipc.localhost ws://localhost:9710 ws://127.0.0.1:9710 ws://localhost:9711 ws://127.0.0.1:9711 https:", + "connect-src": "'self' ipc: http://ipc.localhost data: ws://localhost:9710 ws://127.0.0.1:9710 ws://localhost:9711 ws://127.0.0.1:9711 https:", "img-src": "'self' asset: http://asset.localhost data: blob: https:", "style-src": "'self' 'unsafe-inline' https://fonts.googleapis.com", "style-src-elem": "'self' 'nonce-tolaria-runtime-style' https://fonts.googleapis.com", diff --git a/src/components/EditorTheme.css b/src/components/EditorTheme.css index f27ffe9e..434d2b54 100644 --- a/src/components/EditorTheme.css +++ b/src/components/EditorTheme.css @@ -416,6 +416,7 @@ .editor__blocknote-container .tldraw-whiteboard .tl-container { --color-background: var(--card); + --tl-layer-menu-click-capture: 25; --tl-layer-panels: 30; --tl-layer-menus: 40; --tl-layer-toasts: 50; diff --git a/src/components/TldrawWhiteboard.test.tsx b/src/components/TldrawWhiteboard.test.tsx index fdce6e3a..92dca9c0 100644 --- a/src/components/TldrawWhiteboard.test.tsx +++ b/src/components/TldrawWhiteboard.test.tsx @@ -17,6 +17,23 @@ const tldrawMock = vi.hoisted(() => ({ Tldraw: vi.fn(), })) +const assetImportMock = vi.hoisted(() => ({ + getAssetUrlsByImport: vi.fn((formatAssetUrl: (assetUrl?: string) => string) => ({ + embedIcons: {}, + fonts: { + tldraw_draw: formatAssetUrl('/assets/Shantell_Sans-Informal_Regular.woff2'), + }, + icons: { + 'tool-pencil': `${formatAssetUrl('/assets/0_merged.svg')}#tool-pencil`, + }, + translations: { + en: formatAssetUrl(undefined), + }, + })), +})) + +vi.mock('@tldraw/assets/imports.vite', () => assetImportMock) + vi.mock('tldraw', async () => { const { createElement } = await import('react') @@ -65,7 +82,7 @@ function expectNoCdnUrls(urls: Record) { function expectBundledTldrawAssetUrls(assetUrls: MockAssetUrls) { expect(assetUrls.fonts.tldraw_draw).toContain('Shantell_Sans-Informal_Regular.woff2') expect(assetUrls.icons['tool-pencil']).toContain('0_merged.svg#tool-pencil') - expect(assetUrls.translations.en).toContain('en.json') + expect(assetUrls.translations.en).toBe('data:application/json;base64,e30K') expectNoCdnUrls(assetUrls.fonts) expectNoCdnUrls(assetUrls.icons) expectNoCdnUrls(assetUrls.translations) @@ -85,6 +102,7 @@ describe('TldrawWhiteboard', () => { ) expect(screen.getByTestId('mock-tldraw')).toHaveAttribute('data-draw-font-url') + expect(assetImportMock.getAssetUrlsByImport).toHaveBeenCalledWith(expect.any(Function)) expectBundledTldrawAssetUrls(renderedTldrawAssetUrls()) }) }) diff --git a/src/components/TldrawWhiteboard.tsx b/src/components/TldrawWhiteboard.tsx index 5cd6ccce..b962b51b 100644 --- a/src/components/TldrawWhiteboard.tsx +++ b/src/components/TldrawWhiteboard.tsx @@ -12,7 +12,13 @@ import { } from 'tldraw' import 'tldraw/tldraw.css' -const tldrawAssetUrls = getAssetUrlsByImport() +const EMPTY_TLDRAW_TRANSLATION_URL = 'data:application/json;base64,e30K' + +function resolveTldrawAssetUrl(assetUrl: string | undefined): string { + return assetUrl ?? EMPTY_TLDRAW_TRANSLATION_URL +} + +const tldrawAssetUrls = getAssetUrlsByImport(resolveTldrawAssetUrl) interface TldrawWhiteboardProps { boardId: string diff --git a/src/utils/tauriCsp.test.ts b/src/utils/tauriCsp.test.ts index 308084b6..ea91ac53 100644 --- a/src/utils/tauriCsp.test.ts +++ b/src/utils/tauriCsp.test.ts @@ -19,4 +19,11 @@ describe('Tauri Content Security Policy', () => { expect(csp['object-src']).toContain('asset:') expect(csp['object-src']).toContain('http://asset.localhost') }) + + it('allows bundled tldraw translation JSON fetched from inlined data URLs', () => { + const config = JSON.parse(readFileSync(`${process.cwd()}/src-tauri/tauri.conf.json`, 'utf8')) + const csp = config.app.security.csp as Record + + expect(csp['connect-src']).toContain('data:') + }) }) diff --git a/tests/smoke/tldraw-whiteboard-notes.spec.ts b/tests/smoke/tldraw-whiteboard-notes.spec.ts index 2a9abaa8..35b82f69 100644 --- a/tests/smoke/tldraw-whiteboard-notes.spec.ts +++ b/tests/smoke/tldraw-whiteboard-notes.spec.ts @@ -143,6 +143,13 @@ test('embedded tldraw interactions stay inside the whiteboard', async ({ page }) expect(menuBox!.x).toBeGreaterThanOrEqual(boardBox!.x - 1) expect(menuBox!.x).toBeLessThanOrEqual(buttonBox!.x + 1) await expectNoEditorNodeSelection(page) + + await page.getByTestId('tools.more-button').click() + const ellipseTool = page.getByTestId('tools.more.ellipse') + await expect(ellipseTool).toBeVisible({ timeout: 5_000 }) + await ellipseTool.click() + await expect(page.getByTestId('tools.ellipse')).toHaveAttribute('aria-pressed', 'true') + await expectNoEditorNodeSelection(page) }) test('embedded tldraw drawing uses the clicked coordinates while zoomed', async ({ page }) => {