(
node: SceneNode,
config: CodegenConfig,
assetRegistry: Map<string, AssetDescriptor>,
options: ExportOptions = {}
)
| 27 | } |
| 28 | |
| 29 | export async function exportSvgEntry( |
| 30 | node: SceneNode, |
| 31 | config: CodegenConfig, |
| 32 | assetRegistry: Map<string, AssetDescriptor>, |
| 33 | options: ExportOptions = {} |
| 34 | ): Promise<SvgEntry | null> { |
| 35 | const { colorModel = { kind: 'fixed' }, vectorMode = 'smart' } = options |
| 36 | const themeable = colorModel.kind === 'single-channel' |
| 37 | const presentationStyle = themeable ? { color: colorModel.color } : undefined |
| 38 | |
| 39 | try { |
| 40 | const svgUint8 = await node.exportAsync({ format: 'SVG' }) |
| 41 | const svgString = decodeSvgBytes(svgUint8) |
| 42 | const sized = ensureSvgRootSize(svgString, config, node.width, node.height) |
| 43 | const baseProps = sized?.props ?? buildFallbackProps(node, config) |
| 44 | try { |
| 45 | const width = Math.round(toDecimalPlace(node.width)) |
| 46 | const height = Math.round(toDecimalPlace(node.height)) |
| 47 | const asset = await ensureAssetUploaded(svgUint8, 'image/svg+xml', { |
| 48 | ...(width > 0 ? { width } : {}), |
| 49 | ...(height > 0 ? { height } : {}), |
| 50 | ...(themeable ? { themeable: true } : {}) |
| 51 | }) |
| 52 | assetRegistry.set(asset.hash, asset) |
| 53 | return { |
| 54 | props: { |
| 55 | ...baseProps, |
| 56 | 'data-src': asset.url |
| 57 | }, |
| 58 | ...(presentationStyle ? { presentationStyle } : {}) |
| 59 | } |
| 60 | } catch (uploadError) { |
| 61 | logger.warn( |
| 62 | 'Failed to upload vector asset; inlining SVG fallback to preserve source of truth.', |
| 63 | uploadError |
| 64 | ) |
| 65 | const themeableFallback = |
| 66 | themeable && vectorMode !== 'snapshot' |
| 67 | ? normalizeThemeableSvg(svgString, config, { |
| 68 | width: node.width, |
| 69 | height: node.height, |
| 70 | idPrefix: node.id |
| 71 | }) |
| 72 | : null |
| 73 | return { |
| 74 | props: baseProps, |
| 75 | ...(themeableFallback |
| 76 | ? { |
| 77 | raw: themeableFallback.content, |
| 78 | presentationStyle |
| 79 | } |
| 80 | : { |
| 81 | raw: sized?.content ?? svgString |
| 82 | }) |
| 83 | } |
| 84 | } |
| 85 | } catch (error) { |
| 86 | logger.warn('Failed to export vector node:', error) |
no test coverage detected