@seed-design/figma 0.0.2 → 0.0.5
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/index.cjs +10622 -12209
- package/lib/index.d.ts +1734 -18
- package/lib/index.js +10598 -12210
- package/package.json +2 -2
- package/src/codegen/context.ts +148 -0
- package/src/{component/type-helper.ts → codegen/core/component.ts} +1 -1
- package/src/codegen/core/index.ts +14 -0
- package/src/{jsx.ts → codegen/core/jsx.ts} +13 -3
- package/src/codegen/core/transformer.ts +40 -0
- package/src/{data → codegen/data}/icons.ts +2 -6
- package/src/{data → codegen/data}/styles.ts +87 -29
- package/src/codegen/data/variable-collections.ts +310 -0
- package/src/{data → codegen/data}/variables.ts +2821 -5887
- package/src/codegen/domain/codegen.service.ts +69 -0
- package/src/codegen/domain/figma-component.service.ts +21 -0
- package/src/codegen/domain/frame.service.ts +108 -0
- package/src/codegen/domain/icon.interface.ts +5 -0
- package/src/codegen/domain/icon.repository.ts +11 -0
- package/src/codegen/domain/icon.service.ts +35 -0
- package/src/codegen/domain/index.ts +22 -0
- package/src/codegen/domain/instance.service.ts +91 -0
- package/src/codegen/domain/props/container-layout-props.service.ts +248 -0
- package/src/codegen/domain/props/fill-props.service.ts +75 -0
- package/src/codegen/domain/props/radius-props.service.ts +105 -0
- package/src/codegen/domain/props/self-layout-props.service.ts +127 -0
- package/src/codegen/domain/props/stroke-props.service.ts +45 -0
- package/src/codegen/domain/props/type-style-props.service.ts +31 -0
- package/src/codegen/domain/rectangle.service.ts +31 -0
- package/src/codegen/domain/seed-component/deps.interface.ts +6 -0
- package/src/codegen/domain/seed-component/index.ts +75 -0
- package/src/{component/type.ts → codegen/domain/seed-component/properties.type.ts} +2 -2
- package/src/{component/properties.ts → codegen/domain/seed-component/size.ts} +4 -2
- package/src/codegen/domain/seed-component/transformers/action-button.ts +69 -0
- package/src/codegen/domain/seed-component/transformers/action-chip.ts +82 -0
- package/src/codegen/domain/seed-component/transformers/action-sheet.ts +78 -0
- package/src/codegen/domain/seed-component/transformers/app-bar.ts +186 -0
- package/src/codegen/domain/seed-component/transformers/avatar-stack.ts +30 -0
- package/src/codegen/domain/seed-component/transformers/avatar.ts +39 -0
- package/src/codegen/domain/seed-component/transformers/badge.ts +22 -0
- package/src/codegen/domain/seed-component/transformers/callout.ts +90 -0
- package/src/codegen/domain/seed-component/transformers/checkbox.ts +34 -0
- package/src/codegen/domain/seed-component/transformers/chip-tabs.ts +55 -0
- package/src/codegen/domain/seed-component/transformers/control-chip.ts +86 -0
- package/src/codegen/domain/seed-component/transformers/error-state.ts +39 -0
- package/src/codegen/domain/seed-component/transformers/extended-action-sheet.ts +99 -0
- package/src/codegen/domain/seed-component/transformers/extended-fab.ts +25 -0
- package/src/codegen/domain/seed-component/transformers/fab.ts +18 -0
- package/src/codegen/domain/seed-component/transformers/help-bubble.ts +68 -0
- package/src/codegen/domain/seed-component/transformers/identity-placeholder.ts +18 -0
- package/src/codegen/domain/seed-component/transformers/inline-banner.ts +81 -0
- package/src/codegen/domain/seed-component/transformers/manner-temp-badge.ts +19 -0
- package/src/codegen/domain/seed-component/transformers/multiline-text-field.ts +82 -0
- package/src/codegen/domain/seed-component/transformers/progress-circle.ts +51 -0
- package/src/codegen/domain/seed-component/transformers/reaction-button.ts +37 -0
- package/src/codegen/domain/seed-component/transformers/segmented-control.ts +59 -0
- package/src/codegen/domain/seed-component/transformers/select-box.ts +82 -0
- package/src/codegen/domain/seed-component/transformers/skeleton.ts +52 -0
- package/src/codegen/domain/seed-component/transformers/snackbar.ts +23 -0
- package/src/codegen/domain/seed-component/transformers/switch.ts +31 -0
- package/src/codegen/domain/seed-component/transformers/tabs.ts +129 -0
- package/src/codegen/domain/seed-component/transformers/text-button.ts +55 -0
- package/src/codegen/domain/seed-component/transformers/text-field.ts +109 -0
- package/src/codegen/domain/seed-component/transformers/toggle-button.ts +47 -0
- package/src/codegen/domain/style.interface.ts +5 -0
- package/src/codegen/domain/style.repository.ts +23 -0
- package/src/codegen/domain/style.service.ts +38 -0
- package/src/codegen/domain/text.service.ts +62 -0
- package/src/codegen/domain/variable.interface.ts +18 -0
- package/src/codegen/domain/variable.repository.ts +44 -0
- package/src/codegen/domain/variable.service.ts +95 -0
- package/src/codegen/index.ts +13 -0
- package/src/index.ts +2 -3
- package/src/normalizer/from-plugin.ts +52 -31
- package/src/normalizer/from-rest.ts +27 -5
- package/src/normalizer/index.ts +3 -0
- package/src/normalizer/types.ts +81 -31
- package/src/utils/common.ts +34 -0
- package/src/utils/css.ts +13 -0
- package/src/{node-util.ts → utils/figma-node.ts} +1 -1
- package/src/utils/figma-variable.ts +13 -0
- package/src/color.ts +0 -78
- package/src/component/index.ts +0 -1688
- package/src/generate-code.ts +0 -213
- package/src/icon.ts +0 -46
- package/src/layout.ts +0 -289
- package/src/sizing.ts +0 -58
- package/src/text.ts +0 -20
- package/src/util.ts +0 -17
- package/src/variable.ts +0 -66
- /package/src/{data → codegen/data}/__generated__/component-sets/action-button.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/action-button.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/action-chip.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/action-chip.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/action-sheet.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/action-sheet.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/avatar-stack.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/avatar-stack.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/avatar.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/avatar.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/badge.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/badge.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/bottom-navigation-global.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/bottom-navigation-global.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/bottom-navigation-kr.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/bottom-navigation-kr.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/bottom-sheet.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/bottom-sheet.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/callout.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/callout.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/checkbox.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/checkbox.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/chip-tablist.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/chip-tablist.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/control-chip.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/control-chip.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/divider.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/divider.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/error-state.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/error-state.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/extended-action-sheet.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/extended-action-sheet.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/extended-floating-action-button.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/extended-floating-action-button.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/floating-action-button.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/floating-action-button.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/help-bubble.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/help-bubble.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/identity-placeholder.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/identity-placeholder.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/index.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/index.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/inline-banner.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/inline-banner.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/main-tab-navigation-global.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/main-tab-navigation-global.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/main-tab-navigation-kr.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/main-tab-navigation-kr.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/manner-temp-badge.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/manner-temp-badge.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/manner-temp-bar.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/manner-temp-bar.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/manner-temp.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/manner-temp.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/multiline-text-field.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/multiline-text-field.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/progress-circle.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/progress-circle.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/radio.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/radio.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/range-slider.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/range-slider.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/reaction-button.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/reaction-button.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/segmented-control.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/segmented-control.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/select-box.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/select-box.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/skeleton.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/skeleton.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/slider.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/slider.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/snackbar.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/snackbar.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/standard-navigation.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/standard-navigation.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/switch.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/switch.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/tablist.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/tablist.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-bottom-fixed-bar.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-bottom-fixed-bar.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-button-group.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-button-group.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-chip-group.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-chip-group.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-select-box-group.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-select-box-group.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-top-navigation.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/template-top-navigation.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/text-button.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/text-button.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/text-field.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/text-field.mjs +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/toggle-button.d.ts +0 -0
- /package/src/{data → codegen/data}/__generated__/component-sets/toggle-button.mjs +0 -0
|
@@ -7,9 +7,14 @@ import type {
|
|
|
7
7
|
NormalizedComponentNode,
|
|
8
8
|
NormalizedInstanceNode,
|
|
9
9
|
NormalizedVectorNode,
|
|
10
|
+
NormalizedBooleanOperationNode,
|
|
10
11
|
} from "./types";
|
|
11
12
|
|
|
12
13
|
export function createPluginNormalizer() {
|
|
14
|
+
async function normalizeNodes(nodes: readonly SceneNode[]): Promise<NormalizedSceneNode[]> {
|
|
15
|
+
return Promise.all(nodes.filter((node) => node.visible).map(normalizeNode));
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
async function normalizeNode(node: SceneNode): Promise<NormalizedSceneNode> {
|
|
14
19
|
if (node.type === "FRAME") {
|
|
15
20
|
return normalizeFrameNode(node);
|
|
@@ -23,6 +28,9 @@ export function createPluginNormalizer() {
|
|
|
23
28
|
if (node.type === "VECTOR") {
|
|
24
29
|
return normalizeVectorNode(node);
|
|
25
30
|
}
|
|
31
|
+
if (node.type === "BOOLEAN_OPERATION") {
|
|
32
|
+
return normalizeBooleanOperationNode(node);
|
|
33
|
+
}
|
|
26
34
|
if (node.type === "TEXT") {
|
|
27
35
|
return normalizeTextNode(node);
|
|
28
36
|
}
|
|
@@ -33,7 +41,11 @@ export function createPluginNormalizer() {
|
|
|
33
41
|
return normalizeInstanceNode(node);
|
|
34
42
|
}
|
|
35
43
|
|
|
36
|
-
|
|
44
|
+
return {
|
|
45
|
+
type: "UNHANDLED",
|
|
46
|
+
id: node.id,
|
|
47
|
+
original: node,
|
|
48
|
+
};
|
|
37
49
|
}
|
|
38
50
|
|
|
39
51
|
async function normalizeFrameNode(node: FrameNode): Promise<NormalizedFrameNode> {
|
|
@@ -44,7 +56,7 @@ export function createPluginNormalizer() {
|
|
|
44
56
|
boundVariables: await normalizeBoundVariables(node),
|
|
45
57
|
...normalizeRadiusProps(node),
|
|
46
58
|
...normalizeAutolayoutProps(node),
|
|
47
|
-
children: await
|
|
59
|
+
children: await normalizeNodes(node.children),
|
|
48
60
|
};
|
|
49
61
|
}
|
|
50
62
|
|
|
@@ -75,7 +87,7 @@ export function createPluginNormalizer() {
|
|
|
75
87
|
counterAxisSpacing: node.inferredAutoLayout?.counterAxisSpacing ?? undefined,
|
|
76
88
|
fills: [],
|
|
77
89
|
strokes: [],
|
|
78
|
-
children: await
|
|
90
|
+
children: await normalizeNodes(node.children),
|
|
79
91
|
};
|
|
80
92
|
}
|
|
81
93
|
|
|
@@ -100,6 +112,18 @@ export function createPluginNormalizer() {
|
|
|
100
112
|
};
|
|
101
113
|
}
|
|
102
114
|
|
|
115
|
+
async function normalizeBooleanOperationNode(
|
|
116
|
+
node: BooleanOperationNode,
|
|
117
|
+
): Promise<NormalizedBooleanOperationNode> {
|
|
118
|
+
return {
|
|
119
|
+
type: node.type,
|
|
120
|
+
id: node.id,
|
|
121
|
+
name: node.name,
|
|
122
|
+
boundVariables: await normalizeBoundVariables(node),
|
|
123
|
+
children: await normalizeNodes(node.children),
|
|
124
|
+
...normalizeShapeProps(node),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
103
127
|
async function normalizeTextNode(node: TextNode): Promise<NormalizedTextNode> {
|
|
104
128
|
const segments = node.getStyledTextSegments([
|
|
105
129
|
"fontSize",
|
|
@@ -112,7 +136,7 @@ export function createPluginNormalizer() {
|
|
|
112
136
|
"fills",
|
|
113
137
|
"boundVariables",
|
|
114
138
|
]);
|
|
115
|
-
const first = segments[0]!;
|
|
139
|
+
const first = segments[0]!;
|
|
116
140
|
|
|
117
141
|
const textStyleKey =
|
|
118
142
|
typeof node.textStyleId === "string"
|
|
@@ -124,8 +148,6 @@ export function createPluginNormalizer() {
|
|
|
124
148
|
id: node.id,
|
|
125
149
|
name: node.name,
|
|
126
150
|
boundVariables: await normalizeBoundVariables(node),
|
|
127
|
-
layoutGrow: node.layoutGrow as 0 | 1 | undefined,
|
|
128
|
-
layoutAlign: node.layoutAlign,
|
|
129
151
|
style: {
|
|
130
152
|
fontSize: first.fontSize,
|
|
131
153
|
fontWeight: first.fontWeight,
|
|
@@ -139,29 +161,20 @@ export function createPluginNormalizer() {
|
|
|
139
161
|
},
|
|
140
162
|
...(textStyleKey ? { textStyleKey } : {}),
|
|
141
163
|
characters: node.characters,
|
|
142
|
-
segments:
|
|
143
|
-
.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
fontWeight: segment.fontWeight,
|
|
157
|
-
fontFamily: segment.fontName.family,
|
|
158
|
-
letterSpacing:
|
|
159
|
-
segment.letterSpacing.unit === "PIXELS" ? segment.letterSpacing.value : undefined,
|
|
160
|
-
lineHeightPx:
|
|
161
|
-
segment.lineHeight.unit === "PIXELS" ? segment.lineHeight.value : undefined,
|
|
162
|
-
},
|
|
163
|
-
})),
|
|
164
|
-
fills: normalizePaints(node.fills),
|
|
164
|
+
segments: segments.map((segment) => ({
|
|
165
|
+
characters: segment.characters,
|
|
166
|
+
start: segment.start,
|
|
167
|
+
end: segment.end,
|
|
168
|
+
style: {
|
|
169
|
+
fontSize: segment.fontSize,
|
|
170
|
+
fontWeight: segment.fontWeight,
|
|
171
|
+
fontFamily: segment.fontName.family,
|
|
172
|
+
letterSpacing:
|
|
173
|
+
segment.letterSpacing.unit === "PIXELS" ? segment.letterSpacing.value : undefined,
|
|
174
|
+
lineHeightPx: segment.lineHeight.unit === "PIXELS" ? segment.lineHeight.value : undefined,
|
|
175
|
+
},
|
|
176
|
+
})),
|
|
177
|
+
...normalizeShapeProps(node),
|
|
165
178
|
};
|
|
166
179
|
}
|
|
167
180
|
|
|
@@ -173,7 +186,7 @@ export function createPluginNormalizer() {
|
|
|
173
186
|
boundVariables: await normalizeBoundVariables(node),
|
|
174
187
|
...normalizeRadiusProps(node),
|
|
175
188
|
...normalizeAutolayoutProps(node),
|
|
176
|
-
children: await
|
|
189
|
+
children: await normalizeNodes(node.children),
|
|
177
190
|
};
|
|
178
191
|
}
|
|
179
192
|
|
|
@@ -203,7 +216,7 @@ export function createPluginNormalizer() {
|
|
|
203
216
|
boundVariables: await normalizeBoundVariables(node),
|
|
204
217
|
...normalizeRadiusProps(node),
|
|
205
218
|
...normalizeAutolayoutProps(node),
|
|
206
|
-
children: await
|
|
219
|
+
children: await normalizeNodes(node.children),
|
|
207
220
|
componentKey: mainComponent.key,
|
|
208
221
|
componentSetKey:
|
|
209
222
|
mainComponent.parent?.type === "COMPONENT_SET" ? mainComponent.parent.key : undefined,
|
|
@@ -283,6 +296,10 @@ export function createPluginNormalizer() {
|
|
|
283
296
|
| "layoutSizingHorizontal"
|
|
284
297
|
| "layoutSizingVertical"
|
|
285
298
|
| "absoluteBoundingBox"
|
|
299
|
+
| "minHeight"
|
|
300
|
+
| "minWidth"
|
|
301
|
+
| "maxHeight"
|
|
302
|
+
| "maxWidth"
|
|
286
303
|
> &
|
|
287
304
|
Partial<Pick<FrameNode, "inferredAutoLayout">>,
|
|
288
305
|
) {
|
|
@@ -295,6 +312,10 @@ export function createPluginNormalizer() {
|
|
|
295
312
|
fills: normalizePaints(node.fills),
|
|
296
313
|
strokes: normalizePaints(node.strokes),
|
|
297
314
|
strokeWeight: node.strokeWeight === figma.mixed ? undefined : node.strokeWeight,
|
|
315
|
+
minHeight: node.minHeight ?? undefined,
|
|
316
|
+
minWidth: node.minWidth ?? undefined,
|
|
317
|
+
maxHeight: node.maxHeight ?? undefined,
|
|
318
|
+
maxWidth: node.maxWidth ?? undefined,
|
|
298
319
|
};
|
|
299
320
|
}
|
|
300
321
|
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
NormalizedInstanceNode,
|
|
9
9
|
NormalizedTextSegment,
|
|
10
10
|
NormalizedVectorNode,
|
|
11
|
+
NormalizedBooleanOperationNode,
|
|
11
12
|
} from "./types";
|
|
12
13
|
|
|
13
14
|
export interface RestNormalizerContext {
|
|
@@ -17,6 +18,11 @@ export interface RestNormalizerContext {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
21
|
+
function normalizeNodes(nodes: readonly FigmaRestSpec.Node[]): NormalizedSceneNode[] {
|
|
22
|
+
// Figma REST API omits default values for some fields, "visible" is one of them
|
|
23
|
+
return nodes.filter((node) => !("visible" in node) || node.visible).map(normalizeNode);
|
|
24
|
+
}
|
|
25
|
+
|
|
20
26
|
function normalizeNode(node: FigmaRestSpec.Node): NormalizedSceneNode {
|
|
21
27
|
if (node.type === "FRAME") {
|
|
22
28
|
return normalizeFrameNode(node);
|
|
@@ -30,6 +36,9 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
30
36
|
if (node.type === "VECTOR") {
|
|
31
37
|
return normalizeVectorNode(node);
|
|
32
38
|
}
|
|
39
|
+
if (node.type === "BOOLEAN_OPERATION") {
|
|
40
|
+
return normalizeBooleanOperationNode(node);
|
|
41
|
+
}
|
|
33
42
|
if (node.type === "TEXT") {
|
|
34
43
|
return normalizeTextNode(node);
|
|
35
44
|
}
|
|
@@ -40,13 +49,17 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
40
49
|
return normalizeInstanceNode(node);
|
|
41
50
|
}
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
return {
|
|
53
|
+
type: "UNHANDLED",
|
|
54
|
+
id: node.id,
|
|
55
|
+
original: node,
|
|
56
|
+
};
|
|
44
57
|
}
|
|
45
58
|
|
|
46
59
|
function normalizeFrameNode(node: FigmaRestSpec.FrameNode): NormalizedFrameNode {
|
|
47
60
|
return {
|
|
48
61
|
...node,
|
|
49
|
-
children: node.children
|
|
62
|
+
children: normalizeNodes(node.children),
|
|
50
63
|
};
|
|
51
64
|
}
|
|
52
65
|
|
|
@@ -54,7 +67,7 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
54
67
|
return {
|
|
55
68
|
...node,
|
|
56
69
|
type: "FRAME",
|
|
57
|
-
children: node.children
|
|
70
|
+
children: normalizeNodes(node.children),
|
|
58
71
|
};
|
|
59
72
|
}
|
|
60
73
|
|
|
@@ -66,6 +79,15 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
66
79
|
return node;
|
|
67
80
|
}
|
|
68
81
|
|
|
82
|
+
function normalizeBooleanOperationNode(
|
|
83
|
+
node: FigmaRestSpec.BooleanOperationNode,
|
|
84
|
+
): NormalizedBooleanOperationNode {
|
|
85
|
+
return {
|
|
86
|
+
...node,
|
|
87
|
+
children: normalizeNodes(node.children),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
69
91
|
function normalizeTextNode(node: FigmaRestSpec.TextNode): NormalizedTextNode {
|
|
70
92
|
// Function to segment a text node based on style overrides
|
|
71
93
|
function segmentTextNode(textNode: FigmaRestSpec.TextNode): NormalizedTextSegment[] {
|
|
@@ -141,7 +163,7 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
141
163
|
function normalizeComponentNode(node: FigmaRestSpec.ComponentNode): NormalizedComponentNode {
|
|
142
164
|
return {
|
|
143
165
|
...node,
|
|
144
|
-
children: node.children
|
|
166
|
+
children: normalizeNodes(node.children),
|
|
145
167
|
};
|
|
146
168
|
}
|
|
147
169
|
|
|
@@ -167,7 +189,7 @@ export function createRestNormalizer(ctx: RestNormalizerContext) {
|
|
|
167
189
|
|
|
168
190
|
return {
|
|
169
191
|
...node,
|
|
170
|
-
children: node.children
|
|
192
|
+
children: normalizeNodes(node.children),
|
|
171
193
|
componentKey: mainComponent.key,
|
|
172
194
|
componentSetKey: componentSet?.key,
|
|
173
195
|
componentProperties,
|
package/src/normalizer/types.ts
CHANGED
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
import type * as FigmaRestSpec from "@figma/rest-api-spec";
|
|
2
2
|
|
|
3
|
-
export type
|
|
3
|
+
export type NormalizedIsLayerTrait = Pick<
|
|
4
|
+
FigmaRestSpec.IsLayerTrait,
|
|
5
|
+
"type" | "id" | "name" | "boundVariables"
|
|
6
|
+
>;
|
|
4
7
|
|
|
5
|
-
export type
|
|
8
|
+
export type NormalizedCornerTrait = Pick<
|
|
9
|
+
FigmaRestSpec.CornerTrait,
|
|
10
|
+
"cornerRadius" | "rectangleCornerRadii"
|
|
11
|
+
>;
|
|
6
12
|
|
|
7
|
-
export type
|
|
8
|
-
|
|
13
|
+
export type NormalizedHasChildrenTrait = {
|
|
14
|
+
children: NormalizedSceneNode[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type NormalizedHasLayoutTrait = Pick<
|
|
18
|
+
FigmaRestSpec.HasLayoutTrait,
|
|
9
19
|
| "layoutAlign"
|
|
20
|
+
| "layoutGrow"
|
|
21
|
+
| "absoluteBoundingBox"
|
|
22
|
+
| "layoutPositioning"
|
|
10
23
|
| "layoutSizingHorizontal"
|
|
11
24
|
| "layoutSizingVertical"
|
|
12
|
-
| "
|
|
13
|
-
| "
|
|
14
|
-
| "
|
|
15
|
-
| "
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
| "minHeight"
|
|
26
|
+
| "minWidth"
|
|
27
|
+
| "maxHeight"
|
|
28
|
+
| "maxWidth"
|
|
29
|
+
>;
|
|
30
|
+
|
|
31
|
+
export type NormalizedHasGeometryTrait = Pick<
|
|
32
|
+
FigmaRestSpec.HasGeometryTrait,
|
|
33
|
+
"fills" | "strokes" | "strokeWeight" | "styles"
|
|
34
|
+
>;
|
|
35
|
+
|
|
36
|
+
export type NormalizedHasFramePropertiesTrait = Pick<
|
|
37
|
+
FigmaRestSpec.HasFramePropertiesTrait,
|
|
18
38
|
| "layoutMode"
|
|
19
39
|
| "layoutWrap"
|
|
20
40
|
| "paddingLeft"
|
|
@@ -22,26 +42,43 @@ export type LayoutProps =
|
|
|
22
42
|
| "paddingTop"
|
|
23
43
|
| "paddingBottom"
|
|
24
44
|
| "primaryAxisAlignItems"
|
|
25
|
-
| "counterAxisAlignItems"
|
|
26
45
|
| "primaryAxisSizingMode"
|
|
46
|
+
| "counterAxisAlignItems"
|
|
27
47
|
| "counterAxisSizingMode"
|
|
28
48
|
| "itemSpacing"
|
|
29
|
-
| "counterAxisSpacing"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
| "counterAxisSpacing"
|
|
50
|
+
>;
|
|
51
|
+
|
|
52
|
+
export type NormalizedDefaultShapeTrait = NormalizedIsLayerTrait &
|
|
53
|
+
NormalizedHasLayoutTrait &
|
|
54
|
+
NormalizedHasGeometryTrait;
|
|
55
|
+
|
|
56
|
+
export type NormalizedFrameTrait = NormalizedIsLayerTrait &
|
|
57
|
+
NormalizedHasLayoutTrait &
|
|
58
|
+
NormalizedHasGeometryTrait &
|
|
59
|
+
NormalizedHasChildrenTrait &
|
|
60
|
+
NormalizedCornerTrait &
|
|
61
|
+
NormalizedHasFramePropertiesTrait;
|
|
62
|
+
|
|
63
|
+
export interface NormalizedFrameNode extends NormalizedFrameTrait {
|
|
64
|
+
type: FigmaRestSpec.FrameNode["type"];
|
|
34
65
|
}
|
|
35
66
|
|
|
36
67
|
export interface NormalizedRectangleNode
|
|
37
|
-
extends
|
|
68
|
+
extends NormalizedDefaultShapeTrait,
|
|
69
|
+
NormalizedCornerTrait {
|
|
70
|
+
type: FigmaRestSpec.RectangleNode["type"];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface NormalizedTextNode extends NormalizedDefaultShapeTrait {
|
|
74
|
+
type: FigmaRestSpec.TextNode["type"];
|
|
75
|
+
|
|
76
|
+
style: FigmaRestSpec.TextNode["style"];
|
|
77
|
+
|
|
78
|
+
characters: FigmaRestSpec.TextNode["characters"];
|
|
38
79
|
|
|
39
|
-
export interface NormalizedTextNode
|
|
40
|
-
extends Pick<
|
|
41
|
-
FigmaRestSpec.TextNode,
|
|
42
|
-
CommonProps | "layoutGrow" | "layoutAlign" | "style" | "characters" | "fills"
|
|
43
|
-
> {
|
|
44
80
|
segments: NormalizedTextSegment[];
|
|
81
|
+
|
|
45
82
|
textStyleKey?: string;
|
|
46
83
|
}
|
|
47
84
|
|
|
@@ -60,13 +97,13 @@ export interface NormalizedTextSegment {
|
|
|
60
97
|
};
|
|
61
98
|
}
|
|
62
99
|
|
|
63
|
-
export interface NormalizedComponentNode
|
|
64
|
-
|
|
65
|
-
children: NormalizedSceneNode[];
|
|
100
|
+
export interface NormalizedComponentNode extends NormalizedFrameTrait {
|
|
101
|
+
type: FigmaRestSpec.ComponentNode["type"];
|
|
66
102
|
}
|
|
67
103
|
|
|
68
|
-
export interface NormalizedInstanceNode
|
|
69
|
-
|
|
104
|
+
export interface NormalizedInstanceNode extends NormalizedFrameTrait {
|
|
105
|
+
type: FigmaRestSpec.InstanceNode["type"];
|
|
106
|
+
|
|
70
107
|
componentProperties: {
|
|
71
108
|
[key: string]: FigmaRestSpec.ComponentProperty & { componentKey?: string };
|
|
72
109
|
};
|
|
@@ -78,11 +115,23 @@ export interface NormalizedInstanceNode
|
|
|
78
115
|
children: NormalizedSceneNode[];
|
|
79
116
|
}
|
|
80
117
|
|
|
81
|
-
export interface NormalizedVectorNode
|
|
82
|
-
|
|
118
|
+
export interface NormalizedVectorNode extends NormalizedDefaultShapeTrait, NormalizedCornerTrait {
|
|
119
|
+
type: FigmaRestSpec.VectorNode["type"];
|
|
120
|
+
}
|
|
83
121
|
|
|
84
122
|
export interface NormalizedBooleanOperationNode
|
|
85
|
-
extends
|
|
123
|
+
extends NormalizedIsLayerTrait,
|
|
124
|
+
NormalizedHasChildrenTrait,
|
|
125
|
+
NormalizedHasLayoutTrait,
|
|
126
|
+
NormalizedHasGeometryTrait {
|
|
127
|
+
type: FigmaRestSpec.BooleanOperationNode["type"];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface NormalizedUnhandledNode {
|
|
131
|
+
type: "UNHANDLED";
|
|
132
|
+
id: string;
|
|
133
|
+
original: FigmaRestSpec.Node | SceneNode;
|
|
134
|
+
}
|
|
86
135
|
|
|
87
136
|
export type NormalizedSceneNode =
|
|
88
137
|
| NormalizedFrameNode
|
|
@@ -91,4 +140,5 @@ export type NormalizedSceneNode =
|
|
|
91
140
|
| NormalizedComponentNode
|
|
92
141
|
| NormalizedInstanceNode
|
|
93
142
|
| NormalizedVectorNode
|
|
94
|
-
| NormalizedBooleanOperationNode
|
|
143
|
+
| NormalizedBooleanOperationNode
|
|
144
|
+
| NormalizedUnhandledNode;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { camelCase } from "change-case";
|
|
2
|
+
|
|
3
|
+
export function ensureArray<T>(maybeArray: T | T[]): T[] {
|
|
4
|
+
if (Array.isArray(maybeArray)) {
|
|
5
|
+
return maybeArray;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return [maybeArray];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function exists<T>(value: T | null | undefined): value is T {
|
|
12
|
+
return value != null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function compactObject<T extends Record<string, unknown>>(obj: T): T {
|
|
16
|
+
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value != null)) as T;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function objectEntries<T extends Record<string, unknown>>(obj: T) {
|
|
20
|
+
return Object.entries(obj) as [keyof T, T[keyof T]][];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* camelCase but preserve underscore between numbers.
|
|
25
|
+
* temporary workaround to avoid x1_5 -> x15
|
|
26
|
+
* @example "color-1_5" -> "color1_5"
|
|
27
|
+
*/
|
|
28
|
+
export function camelCasePreserveUnderscoreBetweenNumbers(input: string) {
|
|
29
|
+
return camelCase(input, {
|
|
30
|
+
mergeAmbiguousCharacters: false,
|
|
31
|
+
})
|
|
32
|
+
.replaceAll(/(\D)_(\d)/g, "$1$2")
|
|
33
|
+
.replaceAll(/(\d)_(\D)/g, "$1$2");
|
|
34
|
+
}
|
package/src/utils/css.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RGBA } from "@figma/rest-api-spec";
|
|
2
|
+
|
|
3
|
+
export function toCssPixel(value: number) {
|
|
4
|
+
return `${value}px`;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function toCssRgba(color: RGBA) {
|
|
8
|
+
if (color.a === 1) {
|
|
9
|
+
return `rgb(${color.r * 255}, ${color.g * 255}, ${color.b * 255})`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${color.a})`;
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function isVariableAlias(value: unknown): value is VariableAlias {
|
|
2
|
+
return (
|
|
3
|
+
typeof value === "object" &&
|
|
4
|
+
value !== null &&
|
|
5
|
+
"type" in value &&
|
|
6
|
+
value.type === "VARIABLE_ALIAS"
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// boundVariable.id is formatted as "VariableID:{key}/{localId}", we have to extract the key
|
|
11
|
+
export function sanitizeVariableId(id: string) {
|
|
12
|
+
return id.replace("VariableID:", "").split("/")[0]!;
|
|
13
|
+
}
|
package/src/color.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import type { NormalizedFrameNode, NormalizedTextNode } from "./normalizer/types";
|
|
2
|
-
import { getColorVariableName } from "./variable";
|
|
3
|
-
|
|
4
|
-
export function createBackgroundProps(
|
|
5
|
-
node: Pick<NormalizedFrameNode, "fills" | "boundVariables">,
|
|
6
|
-
): Partial<Record<"background", string | undefined>> {
|
|
7
|
-
const fills = node.fills;
|
|
8
|
-
if (fills.length === 0) {
|
|
9
|
-
return {};
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const fill = fills[0];
|
|
13
|
-
if (!fill || ("visible" in fill && !fill.visible) || fill.type !== "SOLID") {
|
|
14
|
-
return {};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (node.boundVariables?.fills?.length === 1) {
|
|
18
|
-
return {
|
|
19
|
-
background: getColorVariableName(node.boundVariables.fills[0]!.id),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const color = fill.color;
|
|
24
|
-
return {
|
|
25
|
-
background: `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${fill.opacity})`,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function createColorProps(
|
|
30
|
-
node: Pick<NormalizedTextNode, "fills" | "boundVariables">,
|
|
31
|
-
): Partial<Record<"color", string | undefined>> {
|
|
32
|
-
const fills = node.fills;
|
|
33
|
-
if (fills.length === 0) {
|
|
34
|
-
return {};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const fill = fills[0];
|
|
38
|
-
if (!fill || ("visible" in fill && !fill.visible) || fill.type !== "SOLID") {
|
|
39
|
-
return {};
|
|
40
|
-
}
|
|
41
|
-
if (node.boundVariables?.fills?.length === 1) {
|
|
42
|
-
return {
|
|
43
|
-
color: getColorVariableName(node.boundVariables.fills[0]!.id),
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const color = fill.color;
|
|
48
|
-
return {
|
|
49
|
-
color: `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${fill.opacity})`,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function createBorderProps(
|
|
54
|
-
node: Pick<NormalizedFrameNode, "strokeWeight" | "strokes" | "boundVariables">,
|
|
55
|
-
): Partial<Record<"borderWidth" | "borderColor", string | number | undefined>> {
|
|
56
|
-
const strokes = node.strokes;
|
|
57
|
-
if (strokes === undefined || strokes.length === 0) {
|
|
58
|
-
return {};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const stroke = strokes[0];
|
|
62
|
-
if (!stroke || ("visible" in stroke && !stroke.visible) || stroke.type !== "SOLID") {
|
|
63
|
-
return {};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (node.boundVariables?.strokes?.length === 1) {
|
|
67
|
-
return {
|
|
68
|
-
borderWidth: node.strokeWeight as number,
|
|
69
|
-
borderColor: getColorVariableName(node.boundVariables.strokes[0]!.id),
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const color = stroke.color;
|
|
74
|
-
return {
|
|
75
|
-
borderWidth: node.strokeWeight as number,
|
|
76
|
-
borderColor: `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${stroke.opacity})`,
|
|
77
|
-
};
|
|
78
|
-
}
|