Use only Figma clipboard format, fix textAutoResize and autoRename serialization

Drop the OpenPencil clipboard format from the editor — Figma's Kiwi
format is the single clipboard path now. Fix the remaining roundtrip
losses:
- textAutoResize: was hardcoded to WIDTH_AND_HEIGHT, now uses actual value
- autoRename: now serialized (was always defaulting to true on import)
This commit is contained in:
Danila Poyarkov 2026-03-12 17:27:10 +03:00
parent f54fcc32f9
commit 1b1a04a596
2 changed files with 5 additions and 83 deletions

View file

@ -300,7 +300,7 @@ function serializeTextProps(
postscript: ''
}
nc.textData = exportTextData(node)
nc.textAutoResize = 'WIDTH_AND_HEIGHT'
if (node.textAutoResize !== 'NONE') nc.textAutoResize = node.textAutoResize
nc.textAlignHorizontal = node.textAlignHorizontal
nc.textUserLayoutVersion = 3
if (fontDigestMap) nc.derivedTextData = buildDerivedTextData(node, fontDigestMap)
@ -468,6 +468,8 @@ export function sceneNodeToKiwi(
}
}
if (!node.autoRename) nc.autoRename = false
serializeLayoutProps(node, nc)
serializeGeometry(node, nc, blobs)
serializeVariableBindings(node, nc, graph)

View file

@ -21,9 +21,7 @@ import {
exportFigFile,
importClipboardNodes,
parseFigmaClipboard,
parseOpenPencilClipboard,
buildFigmaClipboardHTML,
buildOpenPencilClipboardHTML,
prefetchFigmaSchema,
readFigFile,
computeImageHash,
@ -1922,15 +1920,8 @@ export function createEditorStore() {
if (nodes.length === 0) return
const names = nodes.map((n) => n.name).join('\n')
const renderer = _renderer
const textPicBuilder = renderer
? (node: SceneNode) => renderer.buildTextPicture(node)
: undefined
const internalHtml = buildOpenPencilClipboardHTML(nodes, graph, textPicBuilder)
const figmaHtml = buildFigmaClipboardHTML(nodes, graph)
const html = figmaHtml ? internalHtml + figmaHtml : internalHtml
clipboardData.setData('text/html', html)
const html = buildFigmaClipboardHTML(nodes, graph)
if (html) clipboardData.setData('text/html', html)
clipboardData.setData('text/plain', names)
}
@ -1988,13 +1979,6 @@ export function createEditorStore() {
}
function pasteFromHTML(html: string, cursorPos?: Vector) {
const own = parseOpenPencilClipboard(html)
if (own) {
for (const [hash, data] of own.images) graph.images.set(hash, data)
pasteOpenPencilNodes(own.nodes, undefined, cursorPos)
return
}
void parseFigmaClipboard(html).then((figma) => {
if (figma) {
const prevSelection = new Set(state.selectedIds)
@ -2053,70 +2037,6 @@ export function createEditorStore() {
}
}
function pasteOpenPencilNodes(
nodes: Array<SceneNode & { children?: SceneNode[] }>,
parentId?: string,
cursorPos?: Vector
) {
const target = parentId ?? state.currentPageId
const prevSelection = new Set(state.selectedIds)
const newIds: string[] = []
const created: Array<{ id: string; parentId: string; snapshot: SceneNode }> = []
let offsetX = 20
let offsetY = 20
if (cursorPos && nodes.length > 0) {
let minX = Infinity
let minY = Infinity
let maxX = -Infinity
let maxY = -Infinity
for (const n of nodes) {
minX = Math.min(minX, n.x)
minY = Math.min(minY, n.y)
maxX = Math.max(maxX, n.x + n.width)
maxY = Math.max(maxY, n.y + n.height)
}
offsetX = cursorPos.x - (minX + maxX) / 2
offsetY = cursorPos.y - (minY + maxY) / 2
}
function createTree(src: SceneNode & { children?: SceneNode[] }, pid: string, isTop: boolean) {
const { id: _srcId, parentId: _srcParent, childIds: _srcChildren, ...rest } = src
const node = graph.createNode(src.type, pid, {
...rest,
x: src.x + (isTop ? offsetX : 0),
y: src.y + (isTop ? offsetY : 0)
})
created.push({ id: node.id, parentId: pid, snapshot: { ...node } })
if (isTop) newIds.push(node.id)
if (src.children) {
for (const child of src.children) {
createTree(child, node.id, false)
}
}
}
for (const src of nodes) {
createTree(src, target, true)
}
if (newIds.length > 0) {
state.selectedIds = new Set(newIds)
undo.push({
label: 'Paste',
forward: () => {
for (const { snapshot, parentId: pid } of created) {
graph.createNode(snapshot.type, pid, snapshot)
}
state.selectedIds = new Set(newIds)
},
inverse: () => {
for (const { id } of [...created].reverse()) graph.deleteNode(id)
state.selectedIds = prevSelection
}
})
}
}
function deleteSelected() {
const entries: Array<{ id: string; parentId: string; snapshot: SceneNode; index: number }> = []
for (const id of state.selectedIds) {