@seed-design/figma 1.1.13 → 1.1.14
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/lib/codegen/index.cjs +636 -114
- package/lib/codegen/index.d.ts +136 -96
- package/lib/codegen/index.d.ts.map +1 -1
- package/lib/codegen/index.js +636 -114
- package/lib/codegen/targets/react/index.cjs +682 -134
- package/lib/codegen/targets/react/index.d.ts +31 -11
- package/lib/codegen/targets/react/index.d.ts.map +1 -1
- package/lib/codegen/targets/react/index.js +682 -135
- package/lib/index.cjs +1254 -433
- package/lib/index.d.ts +46 -10
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1254 -433
- package/package.json +1 -1
- package/src/codegen/component-properties.ts +5 -5
- package/src/codegen/core/value-resolver.ts +49 -12
- package/src/codegen/targets/figma/frame.ts +1 -0
- package/src/codegen/targets/figma/pipeline.ts +5 -0
- package/src/codegen/targets/figma/props.ts +30 -1
- package/src/codegen/targets/figma/shape.ts +1 -0
- package/src/codegen/targets/figma/value-resolver.ts +20 -0
- package/src/codegen/targets/react/component/handlers/menu-sheet.ts +1 -1
- package/src/codegen/targets/react/component/handlers/page-banner.ts +2 -2
- package/src/codegen/targets/react/component/handlers/{radio-mark.ts → radiomark.ts} +4 -4
- package/src/codegen/targets/react/component/handlers/result-section.ts +1 -1
- package/src/codegen/targets/react/component/handlers/{switch-mark.ts → switchmark.ts} +4 -4
- package/src/codegen/targets/react/component/index.ts +4 -4
- package/src/codegen/targets/react/frame.ts +16 -2
- package/src/codegen/targets/react/pipeline.ts +6 -1
- package/src/codegen/targets/react/props.ts +26 -0
- package/src/codegen/targets/react/shape.ts +5 -1
- package/src/codegen/targets/react/value-resolver.ts +26 -0
- package/src/entities/data/__generated__/component-sets/index.d.ts +84 -89
- package/src/entities/data/__generated__/component-sets/index.mjs +84 -89
- package/src/entities/data/__generated__/components/index.d.ts +2 -2
- package/src/entities/data/__generated__/components/index.mjs +2 -2
- package/src/entities/data/__generated__/icons/index.mjs +14 -0
- package/src/entities/data/__generated__/styles/index.mjs +190 -1
- package/src/entities/data/__generated__/variable-collections/index.mjs +11 -1
- package/src/entities/data/__generated__/variables/index.mjs +280 -0
- package/src/normalizer/from-plugin.ts +427 -258
- package/src/normalizer/from-rest.ts +428 -58
- package/src/normalizer/types.ts +63 -10
- package/src/utils/figma-node.ts +15 -10
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* from-rest could be run outside of the Figma Plugin environment
|
|
3
|
+
* so we cannot use the Plugin API types directly e.g. getNodeByIdAsync
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* NOTE: types of MinimalFillsTrait["styles"] can be found here:
|
|
8
|
+
* https://developers.figma.com/docs/rest-api/component-types/#style-type
|
|
9
|
+
* Record<"text" | "fill" | "stroke" | "effect" | "grid", string>
|
|
10
|
+
*/
|
|
11
|
+
|
|
1
12
|
import type * as FigmaRestSpec from "@figma/rest-api-spec";
|
|
2
13
|
import type {
|
|
3
14
|
NormalizedSceneNode,
|
|
@@ -9,86 +20,285 @@ import type {
|
|
|
9
20
|
NormalizedTextSegment,
|
|
10
21
|
NormalizedVectorNode,
|
|
11
22
|
NormalizedBooleanOperationNode,
|
|
23
|
+
NormalizedShadow,
|
|
24
|
+
NormalizedCornerTrait,
|
|
25
|
+
NormalizedHasFramePropertiesTrait,
|
|
26
|
+
NormalizedPaint,
|
|
27
|
+
NormalizedDefaultShapeTrait,
|
|
28
|
+
NormalizedHasEffectsTrait,
|
|
29
|
+
NormalizedIsLayerTrait,
|
|
12
30
|
} from "./types";
|
|
13
31
|
|
|
14
32
|
export interface RestNormalizerContext {
|
|
33
|
+
/**
|
|
34
|
+
* A map of style **ID** to style data
|
|
35
|
+
*/
|
|
15
36
|
styles: Record<string, FigmaRestSpec.Style>;
|
|
37
|
+
/**
|
|
38
|
+
* A map of component **ID** to component data
|
|
39
|
+
*/
|
|
16
40
|
components: Record<string, FigmaRestSpec.Component>;
|
|
41
|
+
/**
|
|
42
|
+
* A map of component set **ID** to component set data
|
|
43
|
+
*/
|
|
17
44
|
componentSets: Record<string, FigmaRestSpec.ComponentSet>;
|
|
18
45
|
}
|
|
19
46
|
|
|
20
|
-
export function createRestNormalizer(
|
|
47
|
+
export function createRestNormalizer(
|
|
48
|
+
ctx: RestNormalizerContext,
|
|
49
|
+
): (node: FigmaRestSpec.Node) => NormalizedSceneNode {
|
|
21
50
|
function normalizeNodes(nodes: readonly FigmaRestSpec.Node[]): NormalizedSceneNode[] {
|
|
22
51
|
// Figma REST API omits default values for some fields, "visible" is one of them
|
|
23
52
|
return nodes.filter((node) => !("visible" in node) || node.visible).map(normalizeNode);
|
|
24
53
|
}
|
|
25
54
|
|
|
26
55
|
function normalizeNode(node: FigmaRestSpec.Node): NormalizedSceneNode {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
switch (node.type) {
|
|
57
|
+
case "FRAME":
|
|
58
|
+
return normalizeFrameNode(node);
|
|
59
|
+
case "RECTANGLE":
|
|
60
|
+
return normalizeRectangleNode(node);
|
|
61
|
+
case "TEXT":
|
|
62
|
+
return normalizeTextNode(node);
|
|
63
|
+
case "COMPONENT":
|
|
64
|
+
return normalizeComponentNode(node);
|
|
65
|
+
case "INSTANCE":
|
|
66
|
+
return normalizeInstanceNode(node);
|
|
67
|
+
case "VECTOR":
|
|
68
|
+
return normalizeVectorNode(node);
|
|
69
|
+
case "BOOLEAN_OPERATION":
|
|
70
|
+
return normalizeBooleanOperationNode(node);
|
|
71
|
+
case "GROUP":
|
|
72
|
+
return normalizeGroupNodeAsFrameNode(node);
|
|
73
|
+
default:
|
|
74
|
+
return {
|
|
75
|
+
type: "UNHANDLED",
|
|
76
|
+
id: node.id,
|
|
77
|
+
original: node,
|
|
78
|
+
};
|
|
50
79
|
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function normalizeBoundVariables(
|
|
83
|
+
boundVariables: FigmaRestSpec.IsLayerTrait["boundVariables"] | undefined,
|
|
84
|
+
) {
|
|
85
|
+
if (!boundVariables) return undefined;
|
|
51
86
|
|
|
52
87
|
return {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
88
|
+
fills: boundVariables.fills,
|
|
89
|
+
strokes: boundVariables.strokes,
|
|
90
|
+
itemSpacing: boundVariables.itemSpacing,
|
|
91
|
+
counterAxisSpacing: boundVariables.counterAxisSpacing,
|
|
92
|
+
topLeftRadius: boundVariables.topLeftRadius,
|
|
93
|
+
topRightRadius: boundVariables.topRightRadius,
|
|
94
|
+
bottomLeftRadius: boundVariables.bottomLeftRadius,
|
|
95
|
+
bottomRightRadius: boundVariables.bottomRightRadius,
|
|
96
|
+
paddingTop: boundVariables.paddingTop,
|
|
97
|
+
paddingRight: boundVariables.paddingRight,
|
|
98
|
+
paddingBottom: boundVariables.paddingBottom,
|
|
99
|
+
paddingLeft: boundVariables.paddingLeft,
|
|
100
|
+
minWidth: boundVariables.minWidth,
|
|
101
|
+
maxWidth: boundVariables.maxWidth,
|
|
102
|
+
minHeight: boundVariables.minHeight,
|
|
103
|
+
maxHeight: boundVariables.maxHeight,
|
|
104
|
+
fontSize: boundVariables.fontSize,
|
|
105
|
+
fontWeight: boundVariables.fontWeight,
|
|
106
|
+
lineHeight: boundVariables.lineHeight,
|
|
107
|
+
size: boundVariables.size,
|
|
56
108
|
};
|
|
57
109
|
}
|
|
58
110
|
|
|
59
|
-
function
|
|
111
|
+
function normalizePaint(paint: FigmaRestSpec.Paint): NormalizedPaint {
|
|
112
|
+
switch (paint.type) {
|
|
113
|
+
case "SOLID":
|
|
114
|
+
case "IMAGE":
|
|
115
|
+
case "GRADIENT_LINEAR":
|
|
116
|
+
case "GRADIENT_RADIAL":
|
|
117
|
+
case "GRADIENT_ANGULAR":
|
|
118
|
+
case "GRADIENT_DIAMOND":
|
|
119
|
+
return paint;
|
|
120
|
+
default:
|
|
121
|
+
throw new Error(`Unimplemented paint type: ${paint.type}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function normalizePaints(paints: FigmaRestSpec.Paint[] | undefined): NormalizedPaint[] {
|
|
126
|
+
if (!paints) return [];
|
|
127
|
+
|
|
128
|
+
return paints.map(normalizePaint);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function normalizeRadiusProps({
|
|
132
|
+
cornerRadius,
|
|
133
|
+
rectangleCornerRadii,
|
|
134
|
+
}: Pick<
|
|
135
|
+
FigmaRestSpec.RectangleNode,
|
|
136
|
+
"cornerRadius" | "rectangleCornerRadii"
|
|
137
|
+
>): NormalizedCornerTrait {
|
|
138
|
+
return { cornerRadius, rectangleCornerRadii };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function normalizeEffectProps(
|
|
142
|
+
node: Pick<FigmaRestSpec.FrameNode, "effects" | "styles">,
|
|
143
|
+
): NormalizedHasEffectsTrait {
|
|
144
|
+
const effects = (node.effects ?? [])
|
|
145
|
+
.filter(
|
|
146
|
+
(effect): effect is FigmaRestSpec.DropShadowEffect | FigmaRestSpec.InnerShadowEffect =>
|
|
147
|
+
effect.visible !== false &&
|
|
148
|
+
(effect.type === "DROP_SHADOW" || effect.type === "INNER_SHADOW"),
|
|
149
|
+
)
|
|
150
|
+
.map((effect): NormalizedShadow => {
|
|
151
|
+
const { type, color, offset, radius, spread, boundVariables } = effect;
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
type,
|
|
155
|
+
color,
|
|
156
|
+
offset,
|
|
157
|
+
radius,
|
|
158
|
+
spread,
|
|
159
|
+
boundVariables,
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
|
|
60
163
|
return {
|
|
61
|
-
|
|
62
|
-
|
|
164
|
+
effects,
|
|
165
|
+
effectStyleKey: node.styles?.["effect"] ? ctx.styles[node.styles["effect"]]?.key : undefined,
|
|
63
166
|
};
|
|
64
167
|
}
|
|
65
168
|
|
|
66
|
-
function
|
|
169
|
+
function normalizeShapeProps(
|
|
170
|
+
node: Pick<
|
|
171
|
+
FigmaRestSpec.FrameNode,
|
|
172
|
+
| "fills"
|
|
173
|
+
| "strokes"
|
|
174
|
+
| "strokeWeight"
|
|
175
|
+
| "styles"
|
|
176
|
+
| "layoutGrow"
|
|
177
|
+
| "layoutAlign"
|
|
178
|
+
| "layoutSizingHorizontal"
|
|
179
|
+
| "layoutSizingVertical"
|
|
180
|
+
| "absoluteBoundingBox"
|
|
181
|
+
| "relativeTransform"
|
|
182
|
+
| "layoutPositioning"
|
|
183
|
+
| "minHeight"
|
|
184
|
+
| "minWidth"
|
|
185
|
+
| "maxHeight"
|
|
186
|
+
| "maxWidth"
|
|
187
|
+
| "effects"
|
|
188
|
+
>,
|
|
189
|
+
): Omit<NormalizedDefaultShapeTrait, keyof NormalizedIsLayerTrait> {
|
|
67
190
|
return {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
191
|
+
// NormalizedHasLayoutTrait
|
|
192
|
+
layoutGrow: node.layoutGrow,
|
|
193
|
+
layoutAlign: node.layoutAlign,
|
|
194
|
+
layoutSizingHorizontal: node.layoutSizingHorizontal,
|
|
195
|
+
layoutSizingVertical: node.layoutSizingVertical,
|
|
196
|
+
absoluteBoundingBox: node.absoluteBoundingBox,
|
|
197
|
+
relativeTransform: node.relativeTransform,
|
|
198
|
+
layoutPositioning: node.layoutPositioning,
|
|
199
|
+
minHeight: node.minHeight,
|
|
200
|
+
minWidth: node.minWidth,
|
|
201
|
+
maxHeight: node.maxHeight,
|
|
202
|
+
maxWidth: node.maxWidth,
|
|
203
|
+
|
|
204
|
+
// NormalizedHasGeometryTrait
|
|
205
|
+
fills: normalizePaints(node.fills),
|
|
206
|
+
fillStyleKey: node.styles?.["fill"] ? ctx.styles[node.styles["fill"]]?.key : undefined,
|
|
207
|
+
strokes: normalizePaints(node.strokes),
|
|
208
|
+
strokeWeight: node.strokeWeight,
|
|
209
|
+
|
|
210
|
+
// NormalizedHasEffectsTrait
|
|
211
|
+
...normalizeEffectProps(node),
|
|
71
212
|
};
|
|
72
213
|
}
|
|
73
214
|
|
|
74
|
-
function
|
|
75
|
-
|
|
215
|
+
function normalizeAutolayoutProps(
|
|
216
|
+
node: Pick<
|
|
217
|
+
FigmaRestSpec.FrameNode,
|
|
218
|
+
| "layoutMode"
|
|
219
|
+
| "layoutWrap"
|
|
220
|
+
| "paddingLeft"
|
|
221
|
+
| "paddingRight"
|
|
222
|
+
| "paddingTop"
|
|
223
|
+
| "paddingBottom"
|
|
224
|
+
| "primaryAxisAlignItems"
|
|
225
|
+
| "primaryAxisSizingMode"
|
|
226
|
+
| "counterAxisAlignItems"
|
|
227
|
+
| "counterAxisSizingMode"
|
|
228
|
+
| "itemSpacing"
|
|
229
|
+
| "counterAxisSpacing"
|
|
230
|
+
>,
|
|
231
|
+
): NormalizedHasFramePropertiesTrait {
|
|
232
|
+
return {
|
|
233
|
+
layoutMode: node.layoutMode,
|
|
234
|
+
layoutWrap: node.layoutWrap,
|
|
235
|
+
paddingLeft: node.paddingLeft,
|
|
236
|
+
paddingRight: node.paddingRight,
|
|
237
|
+
paddingTop: node.paddingTop,
|
|
238
|
+
paddingBottom: node.paddingBottom,
|
|
239
|
+
primaryAxisAlignItems: node.primaryAxisAlignItems,
|
|
240
|
+
primaryAxisSizingMode: node.primaryAxisSizingMode,
|
|
241
|
+
counterAxisAlignItems: node.counterAxisAlignItems,
|
|
242
|
+
counterAxisSizingMode: node.counterAxisSizingMode,
|
|
243
|
+
itemSpacing: node.itemSpacing,
|
|
244
|
+
counterAxisSpacing: node.counterAxisSpacing,
|
|
245
|
+
};
|
|
76
246
|
}
|
|
77
247
|
|
|
78
|
-
function
|
|
79
|
-
return
|
|
248
|
+
function normalizeFrameNode(node: FigmaRestSpec.FrameNode): NormalizedFrameNode {
|
|
249
|
+
return {
|
|
250
|
+
// NormalizedIsLayerTrait
|
|
251
|
+
type: node.type,
|
|
252
|
+
id: node.id,
|
|
253
|
+
name: node.name,
|
|
254
|
+
boundVariables: normalizeBoundVariables(node.boundVariables),
|
|
255
|
+
|
|
256
|
+
// NormalizedHasLayoutTrait, NormalizedHasGeometryTrait, NormalizedHasEffectsTrait, NormalizedHasFramePropertiesTrait
|
|
257
|
+
...normalizeShapeProps(node),
|
|
258
|
+
|
|
259
|
+
// NormalizedCornerTrait
|
|
260
|
+
...normalizeRadiusProps(node),
|
|
261
|
+
|
|
262
|
+
// NormalizedHasFramePropertiesTrait
|
|
263
|
+
...normalizeAutolayoutProps(node),
|
|
264
|
+
|
|
265
|
+
// NormalizedHasChildrenTrait
|
|
266
|
+
children: normalizeNodes(node.children),
|
|
267
|
+
};
|
|
80
268
|
}
|
|
81
269
|
|
|
82
|
-
function
|
|
83
|
-
node: FigmaRestSpec.BooleanOperationNode,
|
|
84
|
-
): NormalizedBooleanOperationNode {
|
|
270
|
+
function normalizeRectangleNode(node: FigmaRestSpec.RectangleNode): NormalizedRectangleNode {
|
|
85
271
|
return {
|
|
86
|
-
|
|
87
|
-
|
|
272
|
+
// NormalizedIsLayerTrait
|
|
273
|
+
type: node.type,
|
|
274
|
+
id: node.id,
|
|
275
|
+
name: node.name,
|
|
276
|
+
boundVariables: normalizeBoundVariables(node.boundVariables),
|
|
277
|
+
|
|
278
|
+
// NormalizedCornerTrait
|
|
279
|
+
...normalizeRadiusProps(node),
|
|
280
|
+
|
|
281
|
+
// NormalizedHasLayoutTrait, NormalizedHasGeometryTrait, NormalizedHasEffectsTrait
|
|
282
|
+
...normalizeShapeProps(node),
|
|
88
283
|
};
|
|
89
284
|
}
|
|
90
285
|
|
|
91
286
|
function normalizeTextNode(node: FigmaRestSpec.TextNode): NormalizedTextNode {
|
|
287
|
+
// Convert TypeStyle to NormalizedTextSegment.style format
|
|
288
|
+
function normalizeSegmentStyle(
|
|
289
|
+
typeStyle: FigmaRestSpec.TypeStyle,
|
|
290
|
+
): NormalizedTextSegment["style"] {
|
|
291
|
+
return {
|
|
292
|
+
fontFamily: typeStyle.fontFamily,
|
|
293
|
+
fontWeight: typeStyle.fontWeight,
|
|
294
|
+
fontSize: typeStyle.fontSize,
|
|
295
|
+
italic: typeStyle.italic,
|
|
296
|
+
textDecoration: typeStyle.textDecoration,
|
|
297
|
+
letterSpacing: typeStyle.letterSpacing,
|
|
298
|
+
lineHeight: typeStyle.lineHeightPx,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
92
302
|
// Function to segment a text node based on style overrides
|
|
93
303
|
function segmentTextNode(textNode: FigmaRestSpec.TextNode): NormalizedTextSegment[] {
|
|
94
304
|
const segments: NormalizedTextSegment[] = [];
|
|
@@ -103,7 +313,7 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
103
313
|
characters: characters,
|
|
104
314
|
start: 0,
|
|
105
315
|
end: characters.length,
|
|
106
|
-
style: textNode.style
|
|
316
|
+
style: normalizeSegmentStyle(textNode.style),
|
|
107
317
|
},
|
|
108
318
|
];
|
|
109
319
|
}
|
|
@@ -138,7 +348,7 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
138
348
|
characters: "",
|
|
139
349
|
start: i,
|
|
140
350
|
end: 0,
|
|
141
|
-
style: styleId ? styleTable[styleId]
|
|
351
|
+
style: styleId ? normalizeSegmentStyle(styleTable[styleId]) : {},
|
|
142
352
|
};
|
|
143
353
|
}
|
|
144
354
|
}
|
|
@@ -154,15 +364,41 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
154
364
|
}
|
|
155
365
|
|
|
156
366
|
return {
|
|
157
|
-
|
|
367
|
+
// NormalizedIsLayerTrait
|
|
368
|
+
type: node.type,
|
|
369
|
+
id: node.id,
|
|
370
|
+
name: node.name,
|
|
371
|
+
boundVariables: normalizeBoundVariables(node.boundVariables),
|
|
372
|
+
|
|
373
|
+
// NormalizedTypePropertiesTrait
|
|
374
|
+
style: node.style, // this style is the style of the first segment
|
|
375
|
+
characters: node.characters,
|
|
158
376
|
textStyleKey: node.styles?.["text"] ? ctx.styles[node.styles["text"]]?.key : undefined,
|
|
159
377
|
segments: segmentTextNode(node),
|
|
378
|
+
|
|
379
|
+
// NormalizedHasLayoutTrait, NormalizedHasGeometryTrait, NormalizedHasEffectsTrait
|
|
380
|
+
...normalizeShapeProps(node),
|
|
160
381
|
};
|
|
161
382
|
}
|
|
162
383
|
|
|
163
384
|
function normalizeComponentNode(node: FigmaRestSpec.ComponentNode): NormalizedComponentNode {
|
|
164
385
|
return {
|
|
165
|
-
|
|
386
|
+
// NormalizedIsLayerTrait
|
|
387
|
+
type: node.type,
|
|
388
|
+
id: node.id,
|
|
389
|
+
name: node.name,
|
|
390
|
+
boundVariables: normalizeBoundVariables(node.boundVariables),
|
|
391
|
+
|
|
392
|
+
// NormalizedHasLayoutTrait, NormalizedHasGeometryTrait, NormalizedHasEffectsTrait
|
|
393
|
+
...normalizeShapeProps(node),
|
|
394
|
+
|
|
395
|
+
// NormalizedHasCornerTrait
|
|
396
|
+
...normalizeRadiusProps(node),
|
|
397
|
+
|
|
398
|
+
// NormalizedHasFramePropertiesTrait
|
|
399
|
+
...normalizeAutolayoutProps(node),
|
|
400
|
+
|
|
401
|
+
// NormalizedHasChildrenTrait
|
|
166
402
|
children: normalizeNodes(node.children),
|
|
167
403
|
};
|
|
168
404
|
}
|
|
@@ -172,33 +408,167 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
172
408
|
if (!mainComponent) {
|
|
173
409
|
throw new Error(`Component ${node.componentId} not found`);
|
|
174
410
|
}
|
|
411
|
+
|
|
175
412
|
const componentSet = mainComponent.componentSetId
|
|
176
413
|
? ctx.componentSets[mainComponent.componentSetId]
|
|
177
414
|
: undefined;
|
|
415
|
+
|
|
178
416
|
const componentProperties: NormalizedInstanceNode["componentProperties"] = {};
|
|
179
417
|
|
|
180
418
|
for (const [key, value] of Object.entries(node.componentProperties ?? {})) {
|
|
181
419
|
componentProperties[key] = value;
|
|
420
|
+
|
|
182
421
|
if (value.type === "INSTANCE_SWAP") {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
422
|
+
// unless value.type === "BOOLEAN", value.value is string
|
|
423
|
+
const swappedComponent = ctx.components[value.value as string];
|
|
424
|
+
|
|
425
|
+
if (swappedComponent) {
|
|
426
|
+
componentProperties[key].componentKey = swappedComponent.key;
|
|
427
|
+
|
|
428
|
+
const swappedComponentSet = swappedComponent?.componentSetId
|
|
429
|
+
? ctx.componentSets[swappedComponent.componentSetId]
|
|
430
|
+
: undefined;
|
|
431
|
+
|
|
432
|
+
if (swappedComponentSet) {
|
|
433
|
+
componentProperties[key].componentSetKey = swappedComponentSet.key;
|
|
434
|
+
}
|
|
192
435
|
}
|
|
193
436
|
}
|
|
194
437
|
}
|
|
195
438
|
|
|
196
439
|
return {
|
|
197
|
-
|
|
440
|
+
// NormalizedIsLayerTrait
|
|
441
|
+
type: node.type,
|
|
442
|
+
id: node.id,
|
|
443
|
+
name: node.name,
|
|
444
|
+
boundVariables: normalizeBoundVariables(node.boundVariables),
|
|
445
|
+
|
|
446
|
+
// NormalizedHasLayoutTrait, NormalizedHasGeometryTrait, NormalizedHasEffectsTrait
|
|
447
|
+
...normalizeShapeProps(node),
|
|
448
|
+
|
|
449
|
+
// NormalizedCornerTrait
|
|
450
|
+
...normalizeRadiusProps(node),
|
|
451
|
+
|
|
452
|
+
// NormalizedHasFramePropertiesTrait
|
|
453
|
+
...normalizeAutolayoutProps(node),
|
|
454
|
+
|
|
455
|
+
// NormalizedHasChildrenTrait
|
|
198
456
|
children: normalizeNodes(node.children),
|
|
457
|
+
|
|
458
|
+
// NormalizedInstanceNode specific
|
|
459
|
+
componentProperties,
|
|
199
460
|
componentKey: mainComponent.key,
|
|
200
461
|
componentSetKey: componentSet?.key,
|
|
201
|
-
|
|
462
|
+
overrides: node.overrides,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function normalizeVectorNode(node: FigmaRestSpec.VectorNode): NormalizedVectorNode {
|
|
467
|
+
return {
|
|
468
|
+
// NormalizedIsLayerTrait
|
|
469
|
+
type: node.type,
|
|
470
|
+
id: node.id,
|
|
471
|
+
name: node.name,
|
|
472
|
+
boundVariables: normalizeBoundVariables(node.boundVariables),
|
|
473
|
+
|
|
474
|
+
// NormalizedCornerTrait
|
|
475
|
+
...normalizeRadiusProps(node),
|
|
476
|
+
|
|
477
|
+
// NormalizedHasLayoutTrait, NormalizedHasGeometryTrait, NormalizedHasEffectsTrait
|
|
478
|
+
...normalizeShapeProps(node),
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function normalizeBooleanOperationNode(
|
|
483
|
+
node: FigmaRestSpec.BooleanOperationNode,
|
|
484
|
+
): NormalizedBooleanOperationNode {
|
|
485
|
+
return {
|
|
486
|
+
// NormalizedIsLayerTrait
|
|
487
|
+
type: node.type,
|
|
488
|
+
id: node.id,
|
|
489
|
+
name: node.name,
|
|
490
|
+
boundVariables: normalizeBoundVariables(node.boundVariables),
|
|
491
|
+
|
|
492
|
+
// NormalizedHasLayoutTrait
|
|
493
|
+
layoutGrow: node.layoutGrow,
|
|
494
|
+
layoutAlign: node.layoutAlign,
|
|
495
|
+
layoutSizingHorizontal: node.layoutSizingHorizontal,
|
|
496
|
+
layoutSizingVertical: node.layoutSizingVertical,
|
|
497
|
+
absoluteBoundingBox: node.absoluteBoundingBox,
|
|
498
|
+
relativeTransform: node.relativeTransform,
|
|
499
|
+
layoutPositioning: node.layoutPositioning,
|
|
500
|
+
minHeight: node.minHeight,
|
|
501
|
+
minWidth: node.minWidth,
|
|
502
|
+
maxHeight: node.maxHeight,
|
|
503
|
+
maxWidth: node.maxWidth,
|
|
504
|
+
|
|
505
|
+
// NormalizedHasGeometryTrait
|
|
506
|
+
fills: normalizePaints(node.fills),
|
|
507
|
+
fillStyleKey: node.styles?.["fill"] ? ctx.styles[node.styles["fill"]]?.key : undefined,
|
|
508
|
+
strokes: normalizePaints(node.strokes),
|
|
509
|
+
strokeWeight: node.strokeWeight,
|
|
510
|
+
|
|
511
|
+
// NormalizedHasEffectsTrait
|
|
512
|
+
...normalizeEffectProps(node),
|
|
513
|
+
|
|
514
|
+
// NormalizedHasChildrenTrait
|
|
515
|
+
children: normalizeNodes(node.children),
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function normalizeGroupNodeAsFrameNode(node: FigmaRestSpec.GroupNode): NormalizedFrameNode {
|
|
520
|
+
return {
|
|
521
|
+
// NormalizedIsLayerTrait
|
|
522
|
+
type: "FRAME",
|
|
523
|
+
id: node.id,
|
|
524
|
+
name: node.name,
|
|
525
|
+
boundVariables: normalizeBoundVariables(node.boundVariables),
|
|
526
|
+
|
|
527
|
+
// NormalizedHasLayoutTrait
|
|
528
|
+
layoutGrow: node.layoutGrow,
|
|
529
|
+
layoutAlign: node.layoutAlign,
|
|
530
|
+
layoutSizingHorizontal: node.layoutSizingHorizontal,
|
|
531
|
+
layoutSizingVertical: node.layoutSizingVertical,
|
|
532
|
+
absoluteBoundingBox: node.absoluteBoundingBox,
|
|
533
|
+
relativeTransform: node.relativeTransform,
|
|
534
|
+
layoutPositioning: node.layoutPositioning,
|
|
535
|
+
minHeight: node.minHeight,
|
|
536
|
+
minWidth: node.minWidth,
|
|
537
|
+
maxHeight: node.maxHeight,
|
|
538
|
+
maxWidth: node.maxWidth,
|
|
539
|
+
|
|
540
|
+
// NormalizedHasGeometryTrait
|
|
541
|
+
fills: [],
|
|
542
|
+
fillStyleKey: undefined,
|
|
543
|
+
strokes: [],
|
|
544
|
+
strokeWeight: undefined,
|
|
545
|
+
|
|
546
|
+
// NormalizedHasEffectsTrait
|
|
547
|
+
effects: [],
|
|
548
|
+
effectStyleKey: undefined,
|
|
549
|
+
|
|
550
|
+
// NormalizedCornerTrait
|
|
551
|
+
cornerRadius: undefined,
|
|
552
|
+
rectangleCornerRadii: undefined,
|
|
553
|
+
|
|
554
|
+
// NormalizedHasFramePropertiesTrait
|
|
555
|
+
// these are undefined compared to from-plugin normalizer
|
|
556
|
+
// since inferredAutoLayout isn't available in REST API
|
|
557
|
+
layoutMode: undefined,
|
|
558
|
+
layoutWrap: undefined,
|
|
559
|
+
paddingLeft: undefined,
|
|
560
|
+
paddingRight: undefined,
|
|
561
|
+
paddingTop: undefined,
|
|
562
|
+
paddingBottom: undefined,
|
|
563
|
+
primaryAxisAlignItems: undefined,
|
|
564
|
+
primaryAxisSizingMode: undefined,
|
|
565
|
+
counterAxisAlignItems: undefined,
|
|
566
|
+
counterAxisSizingMode: undefined,
|
|
567
|
+
itemSpacing: undefined,
|
|
568
|
+
counterAxisSpacing: undefined,
|
|
569
|
+
|
|
570
|
+
// NormalizedHasChildrenTrait
|
|
571
|
+
children: normalizeNodes(node.children),
|
|
202
572
|
};
|
|
203
573
|
}
|
|
204
574
|
|
package/src/normalizer/types.ts
CHANGED
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
import type * as FigmaRestSpec from "@figma/rest-api-spec";
|
|
2
2
|
|
|
3
|
-
export type NormalizedIsLayerTrait = Pick<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
export type NormalizedIsLayerTrait = Pick<FigmaRestSpec.IsLayerTrait, "type" | "id" | "name"> & {
|
|
4
|
+
boundVariables?: Pick<
|
|
5
|
+
NonNullable<FigmaRestSpec.IsLayerTrait["boundVariables"]>,
|
|
6
|
+
| "fills"
|
|
7
|
+
| "strokes"
|
|
8
|
+
| "itemSpacing"
|
|
9
|
+
| "counterAxisSpacing"
|
|
10
|
+
| "bottomLeftRadius"
|
|
11
|
+
| "bottomRightRadius"
|
|
12
|
+
| "topLeftRadius"
|
|
13
|
+
| "topRightRadius"
|
|
14
|
+
| "paddingBottom"
|
|
15
|
+
| "paddingLeft"
|
|
16
|
+
| "paddingRight"
|
|
17
|
+
| "paddingTop"
|
|
18
|
+
| "maxHeight"
|
|
19
|
+
| "minHeight"
|
|
20
|
+
| "maxWidth"
|
|
21
|
+
| "minWidth"
|
|
22
|
+
| "fontSize"
|
|
23
|
+
| "fontWeight"
|
|
24
|
+
| "lineHeight"
|
|
25
|
+
| "size"
|
|
26
|
+
>;
|
|
27
|
+
};
|
|
7
28
|
|
|
8
29
|
export type NormalizedCornerTrait = Pick<
|
|
9
30
|
FigmaRestSpec.CornerTrait,
|
|
@@ -29,13 +50,39 @@ export type NormalizedHasLayoutTrait = Pick<
|
|
|
29
50
|
| "maxWidth"
|
|
30
51
|
>;
|
|
31
52
|
|
|
32
|
-
export type
|
|
33
|
-
|
|
34
|
-
|
|
53
|
+
export type NormalizedSolidPaint = FigmaRestSpec.SolidPaint;
|
|
54
|
+
|
|
55
|
+
export type NormalizedPaint =
|
|
56
|
+
| NormalizedSolidPaint
|
|
57
|
+
| FigmaRestSpec.GradientPaint
|
|
58
|
+
| FigmaRestSpec.ImagePaint;
|
|
59
|
+
|
|
60
|
+
export type NormalizedHasGeometryTrait = Omit<
|
|
61
|
+
Pick<FigmaRestSpec.HasGeometryTrait, "fills" | "strokes" | "strokeWeight">,
|
|
62
|
+
"fills" | "strokes"
|
|
35
63
|
> & {
|
|
64
|
+
fills: NormalizedPaint[];
|
|
65
|
+
strokes: NormalizedPaint[];
|
|
36
66
|
fillStyleKey?: string;
|
|
37
67
|
};
|
|
38
68
|
|
|
69
|
+
export type NormalizedShadow =
|
|
70
|
+
| (Pick<
|
|
71
|
+
FigmaRestSpec.DropShadowEffect,
|
|
72
|
+
"color" | "offset" | "radius" | "spread" | "boundVariables"
|
|
73
|
+
> &
|
|
74
|
+
Required<Pick<FigmaRestSpec.DropShadowEffect, "type">>)
|
|
75
|
+
| (Pick<
|
|
76
|
+
FigmaRestSpec.InnerShadowEffect,
|
|
77
|
+
"color" | "offset" | "radius" | "spread" | "boundVariables"
|
|
78
|
+
> &
|
|
79
|
+
Required<Pick<FigmaRestSpec.InnerShadowEffect, "type">>);
|
|
80
|
+
|
|
81
|
+
export type NormalizedHasEffectsTrait = Omit<FigmaRestSpec.HasEffectsTrait, "effects"> & {
|
|
82
|
+
effects: NormalizedShadow[];
|
|
83
|
+
effectStyleKey?: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
39
86
|
export type NormalizedHasFramePropertiesTrait = Pick<
|
|
40
87
|
FigmaRestSpec.HasFramePropertiesTrait,
|
|
41
88
|
| "layoutMode"
|
|
@@ -63,7 +110,10 @@ export interface NormalizedTextSegment {
|
|
|
63
110
|
italic?: boolean;
|
|
64
111
|
textDecoration?: string;
|
|
65
112
|
letterSpacing?: number;
|
|
66
|
-
|
|
113
|
+
/**
|
|
114
|
+
* in pixels
|
|
115
|
+
*/
|
|
116
|
+
lineHeight?: number;
|
|
67
117
|
};
|
|
68
118
|
}
|
|
69
119
|
|
|
@@ -78,11 +128,13 @@ export type NormalizedTypePropertiesTrait = Pick<
|
|
|
78
128
|
|
|
79
129
|
export type NormalizedDefaultShapeTrait = NormalizedIsLayerTrait &
|
|
80
130
|
NormalizedHasLayoutTrait &
|
|
81
|
-
NormalizedHasGeometryTrait
|
|
131
|
+
NormalizedHasGeometryTrait &
|
|
132
|
+
NormalizedHasEffectsTrait;
|
|
82
133
|
|
|
83
134
|
export type NormalizedFrameTrait = NormalizedIsLayerTrait &
|
|
84
135
|
NormalizedHasLayoutTrait &
|
|
85
136
|
NormalizedHasGeometryTrait &
|
|
137
|
+
NormalizedHasEffectsTrait &
|
|
86
138
|
NormalizedHasChildrenTrait &
|
|
87
139
|
NormalizedCornerTrait &
|
|
88
140
|
NormalizedHasFramePropertiesTrait;
|
|
@@ -134,7 +186,8 @@ export interface NormalizedBooleanOperationNode
|
|
|
134
186
|
extends NormalizedIsLayerTrait,
|
|
135
187
|
NormalizedHasChildrenTrait,
|
|
136
188
|
NormalizedHasLayoutTrait,
|
|
137
|
-
NormalizedHasGeometryTrait
|
|
189
|
+
NormalizedHasGeometryTrait,
|
|
190
|
+
NormalizedHasEffectsTrait {
|
|
138
191
|
type: FigmaRestSpec.BooleanOperationNode["type"];
|
|
139
192
|
}
|
|
140
193
|
|