fix(kiwi): resolve variable radius overrides
- Resolve numeric variable aliases in symbol override radius fields - Preserve imported 999 corner sentinels through G0 to G1 roundtrips - Remove the resolved corner-radius roundtrip TODO
This commit is contained in:
parent
ae2ba1455b
commit
b4dfd90da0
|
|
@ -1,10 +1,92 @@
|
|||
import type { GUID } from '#core/kiwi/fig/codec'
|
||||
import type { OverridePatch } from '#core/kiwi/fig/instance-overrides/patches'
|
||||
import type { OverrideContext, SymbolOverride } from '#core/kiwi/fig/instance-overrides/types'
|
||||
import { guidToString } from '#core/kiwi/fig/node-change/convert'
|
||||
import { guidToString, VARIABLE_BINDING_FIELDS_INVERSE } from '#core/kiwi/fig/node-change/convert'
|
||||
import { applyStyleRefsToFields } from '#core/kiwi/fig/node-change/style-refs'
|
||||
|
||||
import { convertOverrideToProps } from './props'
|
||||
|
||||
interface AliasRef {
|
||||
guid?: GUID
|
||||
assetRef?: { key: string; version?: string }
|
||||
}
|
||||
|
||||
const VARIABLE_RADIUS_FIELDS = new Set([
|
||||
'RECTANGLE_TOP_LEFT_CORNER_RADIUS',
|
||||
'RECTANGLE_TOP_RIGHT_CORNER_RADIUS',
|
||||
'RECTANGLE_BOTTOM_LEFT_CORNER_RADIUS',
|
||||
'RECTANGLE_BOTTOM_RIGHT_CORNER_RADIUS'
|
||||
])
|
||||
|
||||
function assetRefKey(assetRef: { key: string; version?: string }): string {
|
||||
return assetRef.version ? `${assetRef.key}@${assetRef.version}` : assetRef.key
|
||||
}
|
||||
|
||||
function buildAssetRefMap(ctx: OverrideContext): Map<string, string> {
|
||||
const refs = new Map<string, string>()
|
||||
for (const [id, nc] of ctx.changeMap) {
|
||||
const key = typeof nc.key === 'string' ? nc.key : undefined
|
||||
if (!key) continue
|
||||
refs.set(key, id)
|
||||
const version = typeof nc.version === 'string' ? nc.version : undefined
|
||||
if (version) refs.set(assetRefKey({ key, version }), id)
|
||||
}
|
||||
return refs
|
||||
}
|
||||
|
||||
function resolveAliasId(alias: AliasRef, assetRefs: Map<string, string>): string | undefined {
|
||||
if (alias.guid) return guidToString(alias.guid)
|
||||
const assetRef = alias.assetRef
|
||||
if (!assetRef?.key) return undefined
|
||||
return assetRefs.get(assetRefKey(assetRef)) ?? assetRefs.get(assetRef.key)
|
||||
}
|
||||
|
||||
function resolveFloatVariable(
|
||||
ctx: OverrideContext,
|
||||
id: string,
|
||||
assetRefs: Map<string, string>,
|
||||
depth = 0
|
||||
): number | undefined {
|
||||
if (depth > 10) return undefined
|
||||
const nc = ctx.changeMap.get(id)
|
||||
const entry = nc?.variableDataValues?.entries?.[0]
|
||||
if (!entry) return undefined
|
||||
const value = entry.variableData.value
|
||||
if (!value) return undefined
|
||||
if (typeof value.floatValue === 'number') return value.floatValue
|
||||
const alias = value.alias as AliasRef | undefined
|
||||
const aliasId = alias ? resolveAliasId(alias, assetRefs) : undefined
|
||||
return aliasId ? resolveFloatVariable(ctx, aliasId, assetRefs, depth + 1) : undefined
|
||||
}
|
||||
|
||||
function applyVariableRadiusOverrides(
|
||||
ctx: OverrideContext,
|
||||
fields: Record<string, unknown>,
|
||||
props: ReturnType<typeof convertOverrideToProps>
|
||||
): void {
|
||||
const entries = (fields.variableConsumptionMap as { entries?: unknown[] } | undefined)?.entries
|
||||
if (!entries?.length) return
|
||||
const assetRefs = buildAssetRefMap(ctx)
|
||||
for (const entry of entries) {
|
||||
if (!entry || typeof entry !== 'object') continue
|
||||
const variableEntry = entry as {
|
||||
variableField?: string
|
||||
variableData?: { value?: { alias?: AliasRef } }
|
||||
}
|
||||
const variableField = variableEntry.variableField
|
||||
if (!variableField || !VARIABLE_RADIUS_FIELDS.has(variableField)) continue
|
||||
const alias = variableEntry.variableData?.value?.alias
|
||||
const id = alias ? resolveAliasId(alias, assetRefs) : undefined
|
||||
const value = id ? resolveFloatVariable(ctx, id, assetRefs) : undefined
|
||||
if (typeof value !== 'number') continue
|
||||
const field = VARIABLE_BINDING_FIELDS_INVERSE[variableField]
|
||||
if (field === 'topLeftRadius') props.topLeftRadius = value
|
||||
else if (field === 'topRightRadius') props.topRightRadius = value
|
||||
else if (field === 'bottomRightRadius') props.bottomRightRadius = value
|
||||
else if (field === 'bottomLeftRadius') props.bottomLeftRadius = value
|
||||
}
|
||||
}
|
||||
|
||||
export function patchFromSymbolOverride(
|
||||
ctx: OverrideContext,
|
||||
targetId: string,
|
||||
|
|
@ -20,6 +102,7 @@ export function patchFromSymbolOverride(
|
|||
if (Object.keys(fields).length > 0) {
|
||||
applyStyleRefsToFields(ctx.changeMap, fields)
|
||||
const props = convertOverrideToProps(fields as Record<string, unknown>)
|
||||
applyVariableRadiusOverrides(ctx, fields as Record<string, unknown>, props)
|
||||
if (Object.keys(props).length > 0) patch.props = props
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,10 @@ export interface InstanceNodeChange {
|
|||
strokeGeometry?: Array<{ windingRule?: string; commandsBlob?: number }>
|
||||
strokeWeight?: number
|
||||
derivedSymbolData?: DerivedSymbolOverride[]
|
||||
key?: string
|
||||
version?: string
|
||||
userFacingVersion?: string
|
||||
variableDataValues?: NodeChange['variableDataValues']
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ const SPECS: FixtureSpec[] = [
|
|||
thumbnailHeight: 239,
|
||||
imageCount: 3,
|
||||
figKiwiVersion: 101,
|
||||
g1ExportSize: 594522,
|
||||
g2ExportSize: 594522
|
||||
g1ExportSize: 594517,
|
||||
g2ExportSize: 594517
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -584,10 +584,6 @@ function verifyFixture(spec: FixtureSpec): void {
|
|||
await ensureG2()
|
||||
compareRawNodeFields(spec, g1Graph, g2Graph, g1, g2, 'G1->G2')
|
||||
})
|
||||
|
||||
test.todo(
|
||||
'BUG: corner radius 999 sentinel lost for non-pill nodes on scene import (40 nodes, raw data preserved)'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,11 +92,7 @@ export const SCENE_VERIFIERS = new Map<string, Verifier>([
|
|||
if (!ctx.key.includes('componentPropertyDefinitions')) return false
|
||||
return ctx.a === 'VARIANT' && ctx.b === 'TEXT'
|
||||
}
|
||||
],
|
||||
['topLeftRadius', (ctx) => !isIdempotent(ctx) && ctx.a === 999 && ctx.b === 0],
|
||||
['topRightRadius', (ctx) => !isIdempotent(ctx) && ctx.a === 999 && ctx.b === 0],
|
||||
['bottomRightRadius', (ctx) => !isIdempotent(ctx) && ctx.a === 999 && ctx.b === 0],
|
||||
['bottomLeftRadius', (ctx) => !isIdempotent(ctx) && ctx.a === 999 && ctx.b === 0]
|
||||
]
|
||||
])
|
||||
|
||||
function verifyAEntries(
|
||||
|
|
|
|||
Loading…
Reference in a new issue