fix(fig): preserve imported text and paint fallbacks
This commit is contained in:
parent
b784882e88
commit
2ef237f5e1
|
|
@ -8,6 +8,7 @@ import { populateAllLazyFigImportRoots } from '#core/kiwi/fig/lazy-import'
|
|||
import { initCodec, getCompiledSchema, getSchemaBytes } from '#core/kiwi/fig/codec'
|
||||
import type { NodeChange } from '#core/kiwi/fig/codec'
|
||||
import { stringToGuid } from '#core/kiwi/fig/node-change/convert'
|
||||
import { buildFigmaPaintVariableColorMap } from '#core/kiwi/fig/node-change/export-node'
|
||||
import {
|
||||
sceneNodeToKiwi,
|
||||
fractionalPosition,
|
||||
|
|
@ -244,6 +245,7 @@ export async function exportFigFile(
|
|||
const modeIdToGuid = new Map<string, GUID>()
|
||||
const fontDigestMap = await buildFontDigestMap(graph)
|
||||
const glyphBlobMap = new Map<string, number>()
|
||||
const paintVariableColorMap = buildFigmaPaintVariableColorMap(graph)
|
||||
|
||||
assignVariableGuids(graph, localIdCounter, varIdToGuid, modeIdToGuid)
|
||||
|
||||
|
|
@ -275,7 +277,8 @@ export async function exportFigFile(
|
|||
nodeIdToGuid,
|
||||
fontDigestMap,
|
||||
varIdToGuid,
|
||||
glyphBlobMap
|
||||
glyphBlobMap,
|
||||
paintVariableColorMap
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -721,6 +721,18 @@ const FIGMA_RAW_NODE_FIELD_KEYS = [
|
|||
'miterLimit',
|
||||
'strokeWeight',
|
||||
'strokeJoin',
|
||||
'textAutoResize',
|
||||
'textData',
|
||||
'lineHeight',
|
||||
'fontName',
|
||||
'fontSize',
|
||||
'letterSpacing',
|
||||
'textTracking',
|
||||
'fontVersion',
|
||||
'textUserLayoutVersion',
|
||||
'textExplicitLayoutVersion',
|
||||
'fontVariations',
|
||||
'derivedTextData',
|
||||
'fillPaints',
|
||||
'strokePaints',
|
||||
'effects',
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ interface SceneNodeToKiwiContext {
|
|||
fontDigestMap?: Map<string, Uint8Array>
|
||||
glyphBlobMap?: Map<string, number>
|
||||
varIdToGuid?: Map<string, GUID>
|
||||
paintVariableColorMap?: Map<string, Color>
|
||||
fractionalPosition: (index: number) => string
|
||||
mapToFigmaType: (type: SceneNode['type']) => string
|
||||
fillToKiwiPaint: (fill: SceneNode['fills'][number]) => Paint
|
||||
|
|
@ -115,10 +116,23 @@ function materializeSafeVariableMap(value: unknown, blobs: Uint8Array[]): unknow
|
|||
return { entries: entries.map((entry) => materializeFigmaPayload(entry, blobs)) }
|
||||
}
|
||||
|
||||
function paintVariableKey(value: unknown): string | null {
|
||||
if (!value || typeof value !== 'object') return null
|
||||
const assetRef = (value as { value?: { alias?: { assetRef?: { key?: unknown; version?: unknown } } } })
|
||||
.value?.alias?.assetRef
|
||||
return typeof assetRef?.key === 'string'
|
||||
? `${assetRef.key}:${typeof assetRef.version === 'string' ? assetRef.version : ''}`
|
||||
: null
|
||||
}
|
||||
|
||||
function materializeFigmaPayload(
|
||||
value: unknown,
|
||||
blobs: Uint8Array[],
|
||||
options: { includeVariableMaps?: boolean } = {}
|
||||
options: {
|
||||
includePaintVariables?: boolean
|
||||
includeVariableMaps?: boolean
|
||||
paintVariableColorMap?: Map<string, Color>
|
||||
} = {}
|
||||
): unknown {
|
||||
if (value instanceof Uint8Array) return value
|
||||
if (Array.isArray(value)) return value.map((item) => materializeFigmaPayload(item, blobs, options))
|
||||
|
|
@ -133,8 +147,11 @@ function materializeFigmaPayload(
|
|||
}
|
||||
|
||||
const materialized: Record<string, unknown> = {}
|
||||
const paintVariableColor = options.paintVariableColorMap?.get(
|
||||
paintVariableKey((value as { colorVar?: unknown }).colorVar) ?? ''
|
||||
)
|
||||
for (const [key, child] of Object.entries(value)) {
|
||||
if (FIGMA_PAYLOAD_PAINT_VARIABLE_FIELDS.has(key)) continue
|
||||
if (FIGMA_PAYLOAD_PAINT_VARIABLE_FIELDS.has(key) && !options.includePaintVariables) continue
|
||||
if (!options.includeVariableMaps && FIGMA_PAYLOAD_VARIABLE_MAP_FIELDS.has(key)) {
|
||||
const variableMap = materializeSafeVariableMap(child, blobs)
|
||||
if (variableMap !== undefined) materialized[key] = variableMap
|
||||
|
|
@ -142,9 +159,52 @@ function materializeFigmaPayload(
|
|||
}
|
||||
materialized[key] = materializeFigmaPayload(child, blobs, options)
|
||||
}
|
||||
if (paintVariableColor) materialized.color = paintVariableColor
|
||||
return materialized
|
||||
}
|
||||
|
||||
function collectPaintVariableColorCounts(
|
||||
value: unknown,
|
||||
counts: Map<string, Map<string, { color: Color; count: number }>>
|
||||
): void {
|
||||
if (!value || typeof value !== 'object') return
|
||||
if (Array.isArray(value)) {
|
||||
for (const item of value) collectPaintVariableColorCounts(item, counts)
|
||||
return
|
||||
}
|
||||
|
||||
const paint = value as { color?: Color; colorVar?: unknown }
|
||||
const key = paintVariableKey(paint.colorVar)
|
||||
if (key && paint.color) {
|
||||
const colorKey = [paint.color.r, paint.color.g, paint.color.b, paint.color.a]
|
||||
.map((component) => Math.round(component * 255))
|
||||
.join(',')
|
||||
const colorCounts = counts.get(key) ?? new Map<string, { color: Color; count: number }>()
|
||||
const current = colorCounts.get(colorKey)
|
||||
colorCounts.set(colorKey, { color: paint.color, count: (current?.count ?? 0) + 1 })
|
||||
counts.set(key, colorCounts)
|
||||
}
|
||||
|
||||
for (const child of Object.values(value)) collectPaintVariableColorCounts(child, counts)
|
||||
}
|
||||
|
||||
export function buildFigmaPaintVariableColorMap(graph: SceneGraph): Map<string, Color> {
|
||||
const counts = new Map<string, Map<string, { color: Color; count: number }>>()
|
||||
for (const node of graph.nodes.values()) {
|
||||
collectPaintVariableColorCounts(node.figmaRawNodeFields, counts)
|
||||
collectPaintVariableColorCounts(node.figmaSymbolOverrides, counts)
|
||||
collectPaintVariableColorCounts(node.figmaComponentPropAssignments, counts)
|
||||
collectPaintVariableColorCounts(node.figmaDerivedSymbolData, counts)
|
||||
}
|
||||
|
||||
const colors = new Map<string, Color>()
|
||||
for (const [key, colorCounts] of counts) {
|
||||
const [mostCommon] = [...colorCounts.values()].sort((a, b) => b.count - a.count)
|
||||
colors.set(key, mostCommon.color)
|
||||
}
|
||||
return colors
|
||||
}
|
||||
|
||||
function resolveInstanceComponentId(context: SceneNodeToKiwiContext, componentId: string): string {
|
||||
const seen = new Set<string>()
|
||||
let currentId = componentId
|
||||
|
|
@ -196,7 +256,8 @@ function applyInstancePayload(
|
|||
const symbolData: Record<string, unknown> = { symbolID }
|
||||
if (node.figmaSymbolOverrides.length > 0) {
|
||||
symbolData.symbolOverrides = materializeFigmaPayload(node.figmaSymbolOverrides, context.blobs, {
|
||||
includeVariableMaps: true
|
||||
includeVariableMaps: true,
|
||||
paintVariableColorMap: context.paintVariableColorMap
|
||||
})
|
||||
}
|
||||
if (node.figmaUniformScaleFactor != null) {
|
||||
|
|
@ -208,12 +269,13 @@ function applyInstancePayload(
|
|||
nc.componentPropAssignments = materializeFigmaPayload(
|
||||
node.figmaComponentPropAssignments,
|
||||
context.blobs,
|
||||
{ includeVariableMaps: true }
|
||||
{ includeVariableMaps: true, paintVariableColorMap: context.paintVariableColorMap }
|
||||
)
|
||||
}
|
||||
if (node.figmaDerivedSymbolData.length > 0) {
|
||||
nc.derivedSymbolData = materializeFigmaPayload(node.figmaDerivedSymbolData, context.blobs, {
|
||||
includeVariableMaps: true
|
||||
includeVariableMaps: true,
|
||||
paintVariableColorMap: context.paintVariableColorMap
|
||||
})
|
||||
}
|
||||
if (node.figmaDerivedSymbolDataLayoutVersion != null) {
|
||||
|
|
|
|||
|
|
@ -496,7 +496,8 @@ export function sceneNodeToKiwi(
|
|||
nodeIdToGuid?: Map<string, GUID>,
|
||||
fontDigestMap?: Map<string, Uint8Array>,
|
||||
varIdToGuid?: Map<string, GUID>,
|
||||
glyphBlobMap = new Map<string, number>()
|
||||
glyphBlobMap = new Map<string, number>(),
|
||||
paintVariableColorMap?: Map<string, Color>
|
||||
): KiwiNodeChange[] {
|
||||
return sceneNodeToKiwiWithContext(node, parentGuid, childIndex, localIdCounter, {
|
||||
graph,
|
||||
|
|
@ -505,6 +506,7 @@ export function sceneNodeToKiwi(
|
|||
fontDigestMap,
|
||||
glyphBlobMap,
|
||||
varIdToGuid,
|
||||
paintVariableColorMap,
|
||||
fractionalPosition,
|
||||
mapToFigmaType,
|
||||
fillToKiwiPaint,
|
||||
|
|
|
|||
Loading…
Reference in a new issue