@dannote/figma-use 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/SKILL.md +88 -209
- package/dist/cli/index.js +38 -5
- package/dist/proxy/index.js +21 -32
- package/package.json +7 -1
- package/packages/cli/src/render/component-set.tsx +138 -0
- package/packages/cli/src/render/components.tsx +155 -0
- package/packages/cli/src/render/index.ts +47 -0
- package/packages/cli/src/render/reconciler.ts +845 -0
- package/packages/cli/src/render/vars.ts +185 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Figma Variable Bindings (StyleX-inspired API)
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```tsx
|
|
6
|
+
* // tokens.figma.ts - with explicit values (recommended)
|
|
7
|
+
* export const colors = defineVars({
|
|
8
|
+
* primary: { name: 'Colors/Gray/50', value: '#F8FAFC' },
|
|
9
|
+
* accent: { name: 'Colors/Blue/500', value: '#3B82F6' },
|
|
10
|
+
* })
|
|
11
|
+
*
|
|
12
|
+
* // tokens.figma.ts - name only (value loaded from Figma)
|
|
13
|
+
* export const colors = defineVars({
|
|
14
|
+
* primary: 'Colors/Gray/50',
|
|
15
|
+
* accent: 'Colors/Blue/500',
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* // Card.figma.tsx
|
|
19
|
+
* <Frame style={{ backgroundColor: colors.primary }}>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { parseColor } from '../color.ts'
|
|
24
|
+
|
|
25
|
+
const VAR_SYMBOL = Symbol.for('figma.variable')
|
|
26
|
+
|
|
27
|
+
/** Variable definition - either string name or object with name and value */
|
|
28
|
+
export type VarDef = string | { name: string; value: string }
|
|
29
|
+
|
|
30
|
+
export interface FigmaVariable {
|
|
31
|
+
[VAR_SYMBOL]: true
|
|
32
|
+
name: string // Variable name like "Colors/Gray/50"
|
|
33
|
+
value?: string // Fallback color value like "#F8FAFC"
|
|
34
|
+
_resolved?: { // Filled in at render time
|
|
35
|
+
id: string
|
|
36
|
+
sessionID: number
|
|
37
|
+
localID: number
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ResolvedVariable {
|
|
42
|
+
id: string
|
|
43
|
+
sessionID: number
|
|
44
|
+
localID: number
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if value is a Figma variable reference
|
|
49
|
+
*/
|
|
50
|
+
export function isVariable(value: unknown): value is FigmaVariable {
|
|
51
|
+
return typeof value === 'object' && value !== null && VAR_SYMBOL in value
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Variable registry - maps names to IDs
|
|
56
|
+
* Populated by loadVariables() before render
|
|
57
|
+
*/
|
|
58
|
+
const variableRegistry = new Map<string, ResolvedVariable>()
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Load variables from Figma into registry
|
|
62
|
+
*/
|
|
63
|
+
export function loadVariablesIntoRegistry(variables: Array<{ id: string; name: string }>) {
|
|
64
|
+
variableRegistry.clear()
|
|
65
|
+
for (const v of variables) {
|
|
66
|
+
const match = v.id.match(/VariableID:(\d+):(\d+)/)
|
|
67
|
+
if (match) {
|
|
68
|
+
variableRegistry.set(v.name, {
|
|
69
|
+
id: v.id,
|
|
70
|
+
sessionID: parseInt(match[1], 10),
|
|
71
|
+
localID: parseInt(match[2], 10),
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a variable name to its ID
|
|
79
|
+
* @throws if variable not found in registry
|
|
80
|
+
*/
|
|
81
|
+
export function resolveVariable(variable: FigmaVariable): ResolvedVariable {
|
|
82
|
+
// Already resolved?
|
|
83
|
+
if (variable._resolved) {
|
|
84
|
+
return variable._resolved
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Check if it's an ID format (legacy support)
|
|
88
|
+
const idMatch = variable.name.match(/^(?:VariableID:)?(\d+):(\d+)$/)
|
|
89
|
+
if (idMatch) {
|
|
90
|
+
const resolved = {
|
|
91
|
+
id: `VariableID:${idMatch[1]}:${idMatch[2]}`,
|
|
92
|
+
sessionID: parseInt(idMatch[1], 10),
|
|
93
|
+
localID: parseInt(idMatch[2], 10),
|
|
94
|
+
}
|
|
95
|
+
variable._resolved = resolved
|
|
96
|
+
return resolved
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Lookup by name
|
|
100
|
+
const resolved = variableRegistry.get(variable.name)
|
|
101
|
+
if (!resolved) {
|
|
102
|
+
const available = Array.from(variableRegistry.keys()).slice(0, 5).join(', ')
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Variable "${variable.name}" not found. ` +
|
|
105
|
+
`Available: ${available}${variableRegistry.size > 5 ? '...' : ''}. ` +
|
|
106
|
+
`Make sure variables are loaded before render.`
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
variable._resolved = resolved
|
|
111
|
+
return resolved
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check if variable registry is populated
|
|
116
|
+
*/
|
|
117
|
+
export function isRegistryLoaded(): boolean {
|
|
118
|
+
return variableRegistry.size > 0
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get registry size (for debugging)
|
|
123
|
+
*/
|
|
124
|
+
export function getRegistrySize(): number {
|
|
125
|
+
return variableRegistry.size
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Define Figma variables for use in styles
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* // With explicit fallback values (recommended)
|
|
134
|
+
* export const colors = defineVars({
|
|
135
|
+
* primary: { name: 'Colors/Gray/50', value: '#F8FAFC' },
|
|
136
|
+
* accent: { name: 'Colors/Blue/500', value: '#3B82F6' },
|
|
137
|
+
* })
|
|
138
|
+
*
|
|
139
|
+
* // Name only (value loaded from Figma registry)
|
|
140
|
+
* export const colors = defineVars({
|
|
141
|
+
* primary: 'Colors/Gray/50',
|
|
142
|
+
* })
|
|
143
|
+
*
|
|
144
|
+
* // Use in components:
|
|
145
|
+
* <Frame style={{ backgroundColor: colors.primary }} />
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export function defineVars<T extends Record<string, VarDef>>(
|
|
149
|
+
vars: T
|
|
150
|
+
): { [K in keyof T]: FigmaVariable } {
|
|
151
|
+
const result = {} as { [K in keyof T]: FigmaVariable }
|
|
152
|
+
|
|
153
|
+
for (const [key, def] of Object.entries(vars)) {
|
|
154
|
+
if (typeof def === 'string') {
|
|
155
|
+
result[key as keyof T] = {
|
|
156
|
+
[VAR_SYMBOL]: true,
|
|
157
|
+
name: def,
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
result[key as keyof T] = {
|
|
161
|
+
[VAR_SYMBOL]: true,
|
|
162
|
+
name: def.name,
|
|
163
|
+
value: def.value,
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return result
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Shorthand for single variable
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```ts
|
|
176
|
+
* const primaryColor = figmaVar('Colors/Gray/50', '#F8FAFC')
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
export function figmaVar(name: string, value?: string): FigmaVariable {
|
|
180
|
+
return {
|
|
181
|
+
[VAR_SYMBOL]: true,
|
|
182
|
+
name,
|
|
183
|
+
value,
|
|
184
|
+
}
|
|
185
|
+
}
|