refactor(fig): share style ref resolution

This commit is contained in:
Danila Poyarkov 2026-05-17 23:52:41 +03:00
parent a441e1778b
commit 4080c25f6b
3 changed files with 65 additions and 38 deletions

View file

@ -9,6 +9,7 @@ import {
setVariableColorResolver,
VARIABLE_BINDING_FIELDS_INVERSE
} from '#core/kiwi/node-change/convert'
import { applyStyleRefsToFields } from '#core/kiwi/node-change/style-refs'
import { SceneGraph } from '#core/scene-graph'
import type { VariableType, VariableValue } from '#core/scene-graph'
@ -350,35 +351,7 @@ function parseDocumentColorSpace(nodeChanges: NodeChange[]): 'srgb' | 'display-p
}
function applyStyleRefs(changeMap: Map<string, NodeChange>): void {
const textStyleFields = [
'fontSize',
'fontName',
'lineHeight',
'letterSpacing',
'textDecoration',
'textCase'
] as const
for (const nc of changeMap.values()) {
const fillStyleGuid = nc.styleIdForFill?.guid
if (fillStyleGuid) {
const style = changeMap.get(guidToString(fillStyleGuid))
if (style?.styleType === 'FILL' && style.fillPaints) nc.fillPaints = style.fillPaints
}
if (nc.type !== 'TEXT') continue
const textStyleGuid = nc.styleIdForText?.guid
if (!textStyleGuid) continue
const style = changeMap.get(guidToString(textStyleGuid))
if (style?.type !== 'TEXT' || style.styleType !== 'TEXT') continue
for (const field of textStyleFields) {
if (field === 'textDecoration') {
nc.textDecoration = style.textDecoration
} else if (style[field] !== undefined) {
nc[field] = style[field] as never
}
}
}
for (const nc of changeMap.values()) applyStyleRefsToFields(changeMap, nc)
}
export interface FigImportOptions {

View file

@ -1,7 +1,7 @@
import { resolveOverrideTarget, repopulateInstance } from '#core/kiwi/instance-overrides/resolve'
import type { OverrideContext } from '#core/kiwi/instance-overrides/types'
import type { GUID } from '#core/kiwi/binary/codec'
import { guidToString } from '#core/kiwi/node-change/convert'
import { applyStyleRefsToFields } from '#core/kiwi/node-change/style-refs'
import type { SceneNode } from '#core/scene-graph'
import { convertOverrideToProps } from './props'
@ -10,13 +10,6 @@ function isActiveInstance(ctx: OverrideContext, nodeId: string | undefined): nod
return nodeId !== undefined && (!ctx.activeNodeIds || ctx.activeNodeIds.has(nodeId))
}
function resolveStrokeFillStyle(ctx: OverrideContext, fields: Record<string, unknown>): void {
const guid = (fields.styleIdForStrokeFill as { guid?: GUID } | undefined)?.guid
if (!guid || fields.strokePaints !== undefined) return
const style = ctx.changeMap.get(guidToString(guid))
if (style?.styleType === 'FILL' && style.fillPaints) fields.strokePaints = style.fillPaints
}
function preserveStrokeShapeProps(target: SceneNode, updates: Partial<SceneNode>): void {
if (!updates.strokes) return
updates.strokes = updates.strokes.map((stroke, index) => {
@ -80,7 +73,7 @@ export function applySymbolOverrides(ctx: OverrideContext): Set<string> {
const { guidPath: _, overriddenSymbolID: _s, componentPropAssignments: _c, ...fields } = ov
if (Object.keys(fields).length === 0) continue
resolveStrokeFillStyle(ctx, fields)
applyStyleRefsToFields(ctx.changeMap, fields)
const updates = convertOverrideToProps(fields as Record<string, unknown>)
if (Object.keys(updates).length > 0) {
const target = ctx.graph.getNode(targetId)

View file

@ -0,0 +1,61 @@
import type { GUID, NodeChange } from '#core/kiwi/binary/codec'
import { guidToString } from '#core/kiwi/node-change/guid'
const TEXT_STYLE_FIELDS = [
'fontSize',
'fontName',
'lineHeight',
'letterSpacing',
'textDecoration',
'textCase'
] as const
type StyleRefFields = Record<string, unknown> & {
styleIdForFill?: { guid?: GUID }
styleIdForStrokeFill?: { guid?: GUID }
styleIdForText?: { guid?: GUID }
}
type StyleSource = Pick<
NodeChange,
| 'type'
| 'styleType'
| 'fillPaints'
| 'fontSize'
| 'fontName'
| 'lineHeight'
| 'letterSpacing'
| 'textDecoration'
| 'textCase'
>
export function applyStyleRefsToFields(
changeMap: ReadonlyMap<string, Partial<StyleSource>>,
fields: StyleRefFields
): void {
const fillStyleGuid = fields.styleIdForFill?.guid
if (fillStyleGuid) {
const style = changeMap.get(guidToString(fillStyleGuid))
if (style?.styleType === 'FILL' && style.fillPaints) fields.fillPaints = style.fillPaints
}
const strokeFillStyleGuid = fields.styleIdForStrokeFill?.guid
if (strokeFillStyleGuid && fields.strokePaints === undefined) {
const style = changeMap.get(guidToString(strokeFillStyleGuid))
if (style?.styleType === 'FILL' && style.fillPaints) fields.strokePaints = style.fillPaints
}
const textStyleGuid = fields.styleIdForText?.guid
if (!textStyleGuid) return
const style = changeMap.get(guidToString(textStyleGuid))
if (style?.type !== 'TEXT' || style.styleType !== 'TEXT') return
for (const field of TEXT_STYLE_FIELDS) {
if (field === 'textDecoration') {
fields.textDecoration = style.textDecoration
} else if (style[field] !== undefined) {
fields[field] = style[field]
}
}
}