Fix copy: build fig-kiwi binary synchronously in copy event handler

navigator.clipboard.write() inside .then() loses user gesture context
and gets blocked by the browser. The schema is prefetched on app init
and cached, so encoding is done synchronously in clipboardData.setData
within the native copy event.
This commit is contained in:
Danila Poyarkov 2026-02-27 23:32:56 +03:00
parent 155f7b3af1
commit 49e7514dcf
2 changed files with 17 additions and 16 deletions

View file

@ -55,10 +55,17 @@ let cachedSchema: CompiledSchema | null = null
let cachedSchemaDeflated: Uint8Array | null = null
export function prefetchFigmaSchema(): void {
getFigmaSchema()
getFigmaSchemaAsync()
}
async function getFigmaSchema(): Promise<{ compiled: CompiledSchema; deflated: Uint8Array }> {
function getFigmaSchemaSync(): { compiled: CompiledSchema; deflated: Uint8Array } | null {
if (cachedSchema && cachedSchemaDeflated) {
return { compiled: cachedSchema, deflated: cachedSchemaDeflated }
}
return null
}
async function getFigmaSchemaAsync(): Promise<{ compiled: CompiledSchema; deflated: Uint8Array }> {
if (cachedSchema && cachedSchemaDeflated) {
return { compiled: cachedSchema, deflated: cachedSchemaDeflated }
}
@ -474,11 +481,13 @@ function sceneNodeToKiwi(
return result
}
export async function buildFigmaClipboardHTML(
export function buildFigmaClipboardHTML(
nodes: SceneNode[],
graph: SceneGraph
): Promise<string> {
const { compiled, deflated: schemaDeflated } = await getFigmaSchema()
): string | null {
const schema = getFigmaSchemaSync()
if (!schema) return null
const { compiled, deflated: schemaDeflated } = schema
const docGuid = { sessionID: 0, localID: 0 }
const canvasGuid = { sessionID: 0, localID: 1 }

View file

@ -239,19 +239,11 @@ export function createEditorStore() {
const names = nodes.map((n) => n.name).join('\n')
const internalHtml = buildOpenPencilClipboardHTML(nodes, graph)
const figmaHtml = buildFigmaClipboardHTML(nodes, graph)
const html = figmaHtml ? figmaHtml + internalHtml : internalHtml
clipboardData.setData('text/html', html)
clipboardData.setData('text/plain', names)
clipboardData.setData('text/html', internalHtml)
buildFigmaClipboardHTML(nodes, graph).then((figmaHtml) => {
const combined = figmaHtml + internalHtml
navigator.clipboard.write([
new ClipboardItem({
'text/html': new Blob([combined], { type: 'text/html' }),
'text/plain': new Blob([names], { type: 'text/plain' })
})
])
})
}
function pasteFromHTML(html: string) {