fix: stabilize tldraw whiteboard assets

This commit is contained in:
lucaronin
2026-05-04 18:34:07 +02:00
parent 38ea51627d
commit e46613b82b
6 changed files with 42 additions and 3 deletions

View File

@@ -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",

View File

@@ -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;

View File

@@ -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<string, string>) {
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())
})
})

View File

@@ -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

View File

@@ -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<string, string>
expect(csp['connect-src']).toContain('data:')
})
})

View File

@@ -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 }) => {