fix(fig): preserve imported geometry and prop values
- Keep raw Figma size and transform values for imported nodes during export - Add current Kiwi schema fields for component prop varValue and symbol id variable values - Preserve component source geometry used by Figma to reconstruct instances
This commit is contained in:
parent
1c0122b485
commit
f4ad80d789
|
|
@ -227,6 +227,7 @@ export interface VariableAnyValue {
|
|||
floatValue?: number
|
||||
colorValue?: Color
|
||||
alias?: { guid?: GUID; assetRef?: { key: string; version?: string } }
|
||||
symbolIdValue?: { guid?: GUID }
|
||||
}
|
||||
|
||||
export interface VariableDataEntry {
|
||||
|
|
|
|||
|
|
@ -1580,6 +1580,7 @@ enum ComponentPropNodeField {
|
|||
message ComponentPropAssignment {
|
||||
GUID defID = 1;
|
||||
ComponentPropValue value = 2;
|
||||
VariableData varValue = 3;
|
||||
}
|
||||
|
||||
message ComponentPropDef {
|
||||
|
|
@ -2044,6 +2045,8 @@ enum VariableDataType {
|
|||
STRING = 2;
|
||||
ALIAS = 3;
|
||||
COLOR = 4;
|
||||
SYMBOL_ID = 7;
|
||||
TEXT_DATA = 9;
|
||||
}
|
||||
|
||||
enum VariableResolvedDataType {
|
||||
|
|
@ -2051,12 +2054,18 @@ enum VariableResolvedDataType {
|
|||
FLOAT = 1;
|
||||
STRING = 2;
|
||||
COLOR = 4;
|
||||
SYMBOL_ID = 6;
|
||||
TEXT_DATA = 8;
|
||||
}
|
||||
|
||||
message VariableID {
|
||||
GUID guid = 1;
|
||||
}
|
||||
|
||||
message SymbolId {
|
||||
GUID guid = 1;
|
||||
}
|
||||
|
||||
message VariableSetID {
|
||||
GUID guid = 1;
|
||||
}
|
||||
|
|
@ -2067,6 +2076,7 @@ message VariableAnyValue {
|
|||
float floatValue = 3;
|
||||
VariableID alias = 4;
|
||||
Color colorValue = 5;
|
||||
SymbolId symbolIdValue = 8;
|
||||
}
|
||||
|
||||
message VariableData {
|
||||
|
|
|
|||
|
|
@ -483,6 +483,7 @@ export function nodeChangeToProps(
|
|||
nodeType,
|
||||
name: nc.name ?? nodeType,
|
||||
figmaGuid: nc.guid ? guidToString(nc.guid) : null,
|
||||
...extractFigmaRawGeometry(nc),
|
||||
...extractFigmaSymbolMetadata(nc, blobs),
|
||||
...convertTransformProps(nc),
|
||||
opacity: nc.opacity ?? 1,
|
||||
|
|
@ -698,6 +699,15 @@ function preserveFigmaPayloadBlobs(value: unknown, blobs: Uint8Array[]): unknown
|
|||
return result
|
||||
}
|
||||
|
||||
function extractFigmaRawGeometry(
|
||||
nc: NodeChange
|
||||
): Pick<SceneNode, 'figmaRawSize' | 'figmaRawTransform'> {
|
||||
return {
|
||||
figmaRawSize: nc.size ? { ...nc.size } : null,
|
||||
figmaRawTransform: nc.transform ? { ...nc.transform } : null
|
||||
}
|
||||
}
|
||||
|
||||
function extractFigmaSymbolMetadata(
|
||||
nc: NodeChange,
|
||||
blobs: Uint8Array[]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { NodeChange, Paint } from '#core/kiwi/binary/codec'
|
||||
import type { SceneGraph, SceneNode } from '#core/scene-graph'
|
||||
import type { Color, GUID, Matrix } from '#core/types'
|
||||
import type { Color, GUID, Matrix, Vector } from '#core/types'
|
||||
|
||||
import { stringToGuid } from './guid'
|
||||
import {
|
||||
|
|
@ -148,6 +148,36 @@ function getOrCreateNodeGuid(
|
|||
return guid
|
||||
}
|
||||
|
||||
function applyInstancePayload(
|
||||
context: SceneNodeToKiwiContext,
|
||||
node: SceneNode,
|
||||
nc: KiwiNodeChange,
|
||||
localIdCounter: { value: number }
|
||||
): void {
|
||||
if (node.type !== 'INSTANCE' || !node.componentId) return
|
||||
const symbolID = getOrCreateNodeGuid(
|
||||
context,
|
||||
resolveInstanceComponentId(context, node.componentId),
|
||||
localIdCounter
|
||||
)
|
||||
if (symbolID) {
|
||||
const symbolData: Record<string, unknown> = { symbolID }
|
||||
if (node.figmaSymbolOverrides.length > 0) {
|
||||
symbolData.symbolOverrides = materializeFigmaPayload(node.figmaSymbolOverrides, context.blobs)
|
||||
}
|
||||
if (node.figmaUniformScaleFactor != null) {
|
||||
symbolData.uniformScaleFactor = node.figmaUniformScaleFactor
|
||||
}
|
||||
nc.symbolData = symbolData as KiwiNodeChange['symbolData']
|
||||
}
|
||||
if (node.figmaDerivedSymbolData.length > 0) {
|
||||
nc.derivedSymbolData = materializeFigmaPayload(node.figmaDerivedSymbolData, context.blobs)
|
||||
}
|
||||
if (node.figmaDerivedSymbolDataLayoutVersion != null) {
|
||||
nc.derivedSymbolDataLayoutVersion = node.figmaDerivedSymbolDataLayoutVersion
|
||||
}
|
||||
}
|
||||
|
||||
function applyComponentMetadata(node: SceneNode, nc: KiwiNodeChange): void {
|
||||
if (node.componentKey) nc.componentKey = node.componentKey
|
||||
if (node.sourceLibraryKey) nc.sourceLibraryKey = node.sourceLibraryKey
|
||||
|
|
@ -185,6 +215,14 @@ function applyComponentMetadata(node: SceneNode, nc: KiwiNodeChange): void {
|
|||
if (variantPropSpecs.length > 0) nc.variantPropSpecs = variantPropSpecs
|
||||
}
|
||||
|
||||
function exportNodeSize(node: SceneNode): Vector {
|
||||
return node.figmaRawSize ? { ...node.figmaRawSize } : { x: node.width, y: node.height }
|
||||
}
|
||||
|
||||
function exportNodeTransform(context: SceneNodeToKiwiContext, node: SceneNode): Matrix {
|
||||
return node.figmaRawTransform ? { ...node.figmaRawTransform } : context.computeExportTransform(node)
|
||||
}
|
||||
|
||||
function applyNodeVisualProps(
|
||||
context: SceneNodeToKiwiContext,
|
||||
node: SceneNode,
|
||||
|
|
@ -273,37 +311,15 @@ export function sceneNodeToKiwiWithContext(
|
|||
visible: node.visible,
|
||||
opacity: node.opacity,
|
||||
phase: 'CREATED',
|
||||
size: { x: node.width, y: node.height },
|
||||
transform: context.computeExportTransform(node),
|
||||
size: exportNodeSize(node),
|
||||
transform: exportNodeTransform(context, node),
|
||||
strokeWeight: node.strokes[0]?.weight ?? DEFAULT_STROKE_WEIGHT,
|
||||
strokeAlign: node.strokes[0]?.align ?? 'INSIDE'
|
||||
}
|
||||
|
||||
applyNodeVisualProps(context, node, nc)
|
||||
applyComponentMetadata(node, nc)
|
||||
if (node.type === 'INSTANCE' && node.componentId) {
|
||||
const symbolID = getOrCreateNodeGuid(
|
||||
context,
|
||||
resolveInstanceComponentId(context, node.componentId),
|
||||
localIdCounter
|
||||
)
|
||||
if (symbolID) {
|
||||
const symbolData: Record<string, unknown> = { symbolID }
|
||||
if (node.figmaSymbolOverrides.length > 0) {
|
||||
symbolData.symbolOverrides = materializeFigmaPayload(node.figmaSymbolOverrides, context.blobs)
|
||||
}
|
||||
if (node.figmaUniformScaleFactor != null) {
|
||||
symbolData.uniformScaleFactor = node.figmaUniformScaleFactor
|
||||
}
|
||||
nc.symbolData = symbolData as KiwiNodeChange['symbolData']
|
||||
}
|
||||
if (node.figmaDerivedSymbolData.length > 0) {
|
||||
nc.derivedSymbolData = materializeFigmaPayload(node.figmaDerivedSymbolData, context.blobs)
|
||||
}
|
||||
if (node.figmaDerivedSymbolDataLayoutVersion != null) {
|
||||
nc.derivedSymbolDataLayoutVersion = node.figmaDerivedSymbolDataLayoutVersion
|
||||
}
|
||||
}
|
||||
applyInstancePayload(context, node, nc, localIdCounter)
|
||||
if (node.type === 'COMPONENT_SET') upsertPluginData(node, NODE_TYPE_PLUGIN_KEY, node.type)
|
||||
if (strokePaints.length > 0) nc.strokePaints = strokePaints
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ export function createDefaultNode(
|
|||
width: 100,
|
||||
height: 100,
|
||||
rotation: 0,
|
||||
figmaRawSize: null,
|
||||
figmaRawTransform: null,
|
||||
figmaDerivedLayout: null,
|
||||
fills:
|
||||
type === 'TEXT'
|
||||
|
|
|
|||
|
|
@ -269,6 +269,8 @@ export interface SceneNode {
|
|||
width: number
|
||||
height: number
|
||||
rotation: number
|
||||
figmaRawSize: Vector | null
|
||||
figmaRawTransform: Matrix | null
|
||||
figmaDerivedLayout: Partial<Rect> | null
|
||||
|
||||
fills: Fill[]
|
||||
|
|
|
|||
Loading…
Reference in a new issue