@seed-design/figma 0.0.0-alpha-20260324091316
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 +23543 -0
- package/lib/codegen/index.d.ts +2957 -0
- package/lib/codegen/index.d.ts.map +1 -0
- package/lib/codegen/index.js +23514 -0
- package/lib/codegen/targets/react/index.cjs +31980 -0
- package/lib/codegen/targets/react/index.d.ts +308 -0
- package/lib/codegen/targets/react/index.d.ts.map +1 -0
- package/lib/codegen/targets/react/index.js +31961 -0
- package/lib/index.cjs +26905 -0
- package/lib/index.d.ts +221 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +26884 -0
- package/package.json +56 -0
- package/src/codegen/component-properties.archive.ts +1019 -0
- package/src/codegen/component-properties.ts +369 -0
- package/src/codegen/core/codegen.ts +112 -0
- package/src/codegen/core/component-handler.ts +23 -0
- package/src/codegen/core/component-type-helper.ts +35 -0
- package/src/codegen/core/element-transformer.ts +13 -0
- package/src/codegen/core/index.ts +19 -0
- package/src/codegen/core/infer-layout.test.ts +286 -0
- package/src/codegen/core/infer-layout.ts +416 -0
- package/src/codegen/core/jsx.ts +174 -0
- package/src/codegen/core/props-converter.ts +78 -0
- package/src/codegen/core/value-resolver.ts +381 -0
- package/src/codegen/default-services.ts +44 -0
- package/src/codegen/index.ts +3 -0
- package/src/codegen/skip-components.ts +7 -0
- package/src/codegen/targets/figma/frame.ts +38 -0
- package/src/codegen/targets/figma/index.ts +6 -0
- package/src/codegen/targets/figma/instance.ts +36 -0
- package/src/codegen/targets/figma/pipeline.ts +106 -0
- package/src/codegen/targets/figma/props.ts +262 -0
- package/src/codegen/targets/figma/shape.ts +65 -0
- package/src/codegen/targets/figma/text.ts +30 -0
- package/src/codegen/targets/figma/value-resolver.ts +75 -0
- package/src/codegen/targets/index.ts +2 -0
- package/src/codegen/targets/react/component/deps.interface.ts +7 -0
- package/src/codegen/targets/react/component/handlers/action-button.ts +149 -0
- package/src/codegen/targets/react/component/handlers/alert-dialog.ts +120 -0
- package/src/codegen/targets/react/component/handlers/app-bar.ts +169 -0
- package/src/codegen/targets/react/component/handlers/archive/action-button.ts +144 -0
- package/src/codegen/targets/react/component/handlers/archive/alert-dialog.ts +122 -0
- package/src/codegen/targets/react/component/handlers/archive/app-bar.ts +149 -0
- package/src/codegen/targets/react/component/handlers/archive/avatar-stack.ts +35 -0
- package/src/codegen/targets/react/component/handlers/archive/avatar.ts +55 -0
- package/src/codegen/targets/react/component/handlers/archive/badge.ts +18 -0
- package/src/codegen/targets/react/component/handlers/archive/bottom-sheet.ts +70 -0
- package/src/codegen/targets/react/component/handlers/archive/callout.ts +88 -0
- package/src/codegen/targets/react/component/handlers/archive/checkbox.ts +43 -0
- package/src/codegen/targets/react/component/handlers/archive/checkmark.ts +29 -0
- package/src/codegen/targets/react/component/handlers/archive/chip.ts +90 -0
- package/src/codegen/targets/react/component/handlers/archive/contextual-floating-button.ts +52 -0
- package/src/codegen/targets/react/component/handlers/archive/divider.ts +25 -0
- package/src/codegen/targets/react/component/handlers/archive/field-button.ts +197 -0
- package/src/codegen/targets/react/component/handlers/archive/field.ts +167 -0
- package/src/codegen/targets/react/component/handlers/archive/floating-action-button.ts +48 -0
- package/src/codegen/targets/react/component/handlers/archive/help-bubble.ts +73 -0
- package/src/codegen/targets/react/component/handlers/archive/identity-placeholder.ts +21 -0
- package/src/codegen/targets/react/component/handlers/archive/index.ts +40 -0
- package/src/codegen/targets/react/component/handlers/archive/legacy-select-box.ts +89 -0
- package/src/codegen/targets/react/component/handlers/archive/legacy-text-field.ts +198 -0
- package/src/codegen/targets/react/component/handlers/archive/list-header.ts +20 -0
- package/src/codegen/targets/react/component/handlers/archive/list-item.ts +162 -0
- package/src/codegen/targets/react/component/handlers/archive/manner-temp-badge.ts +21 -0
- package/src/codegen/targets/react/component/handlers/archive/manner-temp.ts +18 -0
- package/src/codegen/targets/react/component/handlers/archive/menu-sheet.ts +108 -0
- package/src/codegen/targets/react/component/handlers/archive/page-banner.ts +101 -0
- package/src/codegen/targets/react/component/handlers/archive/progress-circle.ts +55 -0
- package/src/codegen/targets/react/component/handlers/archive/radio-group.ts +31 -0
- package/src/codegen/targets/react/component/handlers/archive/radiomark.ts +27 -0
- package/src/codegen/targets/react/component/handlers/archive/reaction-button.ts +37 -0
- package/src/codegen/targets/react/component/handlers/archive/result-section.ts +67 -0
- package/src/codegen/targets/react/component/handlers/archive/segmented-control.ts +64 -0
- package/src/codegen/targets/react/component/handlers/archive/skeleton.ts +26 -0
- package/src/codegen/targets/react/component/handlers/archive/slider.ts +114 -0
- package/src/codegen/targets/react/component/handlers/archive/snackbar.ts +25 -0
- package/src/codegen/targets/react/component/handlers/archive/switch.ts +39 -0
- package/src/codegen/targets/react/component/handlers/archive/switchmark.ts +26 -0
- package/src/codegen/targets/react/component/handlers/archive/tabs.ts +297 -0
- package/src/codegen/targets/react/component/handlers/archive/tag-group.ts +86 -0
- package/src/codegen/targets/react/component/handlers/archive/text-field.ts +264 -0
- package/src/codegen/targets/react/component/handlers/archive/toggle-button.ts +43 -0
- package/src/codegen/targets/react/component/handlers/avatar-stack.ts +38 -0
- package/src/codegen/targets/react/component/handlers/avatar.ts +58 -0
- package/src/codegen/targets/react/component/handlers/badge.ts +18 -0
- package/src/codegen/targets/react/component/handlers/bottom-sheet.ts +74 -0
- package/src/codegen/targets/react/component/handlers/callout.ts +88 -0
- package/src/codegen/targets/react/component/handlers/checkbox.ts +129 -0
- package/src/codegen/targets/react/component/handlers/checkmark.ts +29 -0
- package/src/codegen/targets/react/component/handlers/chip.ts +93 -0
- package/src/codegen/targets/react/component/handlers/content-placeholder.ts +20 -0
- package/src/codegen/targets/react/component/handlers/contextual-floating-button.ts +52 -0
- package/src/codegen/targets/react/component/handlers/divider.ts +25 -0
- package/src/codegen/targets/react/component/handlers/field-button.ts +192 -0
- package/src/codegen/targets/react/component/handlers/field.ts +164 -0
- package/src/codegen/targets/react/component/handlers/floating-action-button.ts +45 -0
- package/src/codegen/targets/react/component/handlers/help-bubble.ts +73 -0
- package/src/codegen/targets/react/component/handlers/identity-placeholder.ts +20 -0
- package/src/codegen/targets/react/component/handlers/image-frame.ts +147 -0
- package/src/codegen/targets/react/component/handlers/index.ts +43 -0
- package/src/codegen/targets/react/component/handlers/legacy-select-box.ts +87 -0
- package/src/codegen/targets/react/component/handlers/legacy-text-field.ts +196 -0
- package/src/codegen/targets/react/component/handlers/list-header.ts +20 -0
- package/src/codegen/targets/react/component/handlers/list-item.ts +163 -0
- package/src/codegen/targets/react/component/handlers/manner-temp-badge.ts +21 -0
- package/src/codegen/targets/react/component/handlers/manner-temp.ts +18 -0
- package/src/codegen/targets/react/component/handlers/menu-sheet.ts +111 -0
- package/src/codegen/targets/react/component/handlers/page-banner.ts +106 -0
- package/src/codegen/targets/react/component/handlers/progress-circle.ts +55 -0
- package/src/codegen/targets/react/component/handlers/radio-group.ts +109 -0
- package/src/codegen/targets/react/component/handlers/radiomark.ts +27 -0
- package/src/codegen/targets/react/component/handlers/reaction-button.ts +37 -0
- package/src/codegen/targets/react/component/handlers/result-section.ts +67 -0
- package/src/codegen/targets/react/component/handlers/segmented-control.ts +63 -0
- package/src/codegen/targets/react/component/handlers/select-box.ts +333 -0
- package/src/codegen/targets/react/component/handlers/skeleton.ts +26 -0
- package/src/codegen/targets/react/component/handlers/slider.ts +117 -0
- package/src/codegen/targets/react/component/handlers/snackbar.ts +25 -0
- package/src/codegen/targets/react/component/handlers/switch.ts +35 -0
- package/src/codegen/targets/react/component/handlers/switchmark.ts +26 -0
- package/src/codegen/targets/react/component/handlers/tabs.ts +298 -0
- package/src/codegen/targets/react/component/handlers/tag-group.ts +90 -0
- package/src/codegen/targets/react/component/handlers/text-field.ts +253 -0
- package/src/codegen/targets/react/component/handlers/toggle-button.ts +43 -0
- package/src/codegen/targets/react/component/index.ts +24 -0
- package/src/codegen/targets/react/component/size.ts +22 -0
- package/src/codegen/targets/react/element-factories.ts +59 -0
- package/src/codegen/targets/react/frame.ts +96 -0
- package/src/codegen/targets/react/icon.ts +55 -0
- package/src/codegen/targets/react/index.ts +7 -0
- package/src/codegen/targets/react/instance.ts +82 -0
- package/src/codegen/targets/react/pipeline.ts +133 -0
- package/src/codegen/targets/react/props.ts +417 -0
- package/src/codegen/targets/react/shape.ts +47 -0
- package/src/codegen/targets/react/text.ts +31 -0
- package/src/codegen/targets/react/value-resolver.ts +93 -0
- package/src/entities/component.interface.ts +7 -0
- package/src/entities/component.repository.ts +16 -0
- package/src/entities/data/__generated__/archive/component-sets/index.d.ts +2074 -0
- package/src/entities/data/__generated__/archive/component-sets/index.mjs +2074 -0
- package/src/entities/data/__generated__/archive/components/index.d.ts +116 -0
- package/src/entities/data/__generated__/archive/components/index.mjs +116 -0
- package/src/entities/data/__generated__/archive/styles/index.d.ts +3 -0
- package/src/entities/data/__generated__/archive/styles/index.mjs +429 -0
- package/src/entities/data/__generated__/archive/variable-collections/index.d.ts +3 -0
- package/src/entities/data/__generated__/archive/variable-collections/index.mjs +501 -0
- package/src/entities/data/__generated__/archive/variables/index.d.ts +3 -0
- package/src/entities/data/__generated__/archive/variables/index.mjs +7019 -0
- package/src/entities/data/__generated__/component-sets/index.d.ts +4325 -0
- package/src/entities/data/__generated__/component-sets/index.mjs +4325 -0
- package/src/entities/data/__generated__/components/index.d.ts +378 -0
- package/src/entities/data/__generated__/components/index.mjs +378 -0
- package/src/entities/data/__generated__/icons/index.d.ts +3 -0
- package/src/entities/data/__generated__/icons/index.mjs +3476 -0
- package/src/entities/data/__generated__/styles/index.d.ts +3 -0
- package/src/entities/data/__generated__/styles/index.mjs +436 -0
- package/src/entities/data/__generated__/variable-collections/index.d.ts +3 -0
- package/src/entities/data/__generated__/variable-collections/index.mjs +479 -0
- package/src/entities/data/__generated__/variables/index.d.ts +3 -0
- package/src/entities/data/__generated__/variables/index.mjs +6969 -0
- package/src/entities/icon.interface.ts +5 -0
- package/src/entities/icon.repository.ts +11 -0
- package/src/entities/icon.service.ts +26 -0
- package/src/entities/index.ts +60 -0
- package/src/entities/style.interface.ts +5 -0
- package/src/entities/style.repository.ts +27 -0
- package/src/entities/style.service.ts +36 -0
- package/src/entities/variable.interface.ts +18 -0
- package/src/entities/variable.repository.ts +57 -0
- package/src/entities/variable.service.ts +101 -0
- package/src/index.ts +3 -0
- package/src/normalizer/from-plugin.ts +602 -0
- package/src/normalizer/from-rest.ts +577 -0
- package/src/normalizer/index.ts +3 -0
- package/src/normalizer/types.ts +208 -0
- package/src/utils/common.ts +38 -0
- package/src/utils/css.ts +19 -0
- package/src/utils/figma-gradient.ts +72 -0
- package/src/utils/figma-node.ts +95 -0
- package/src/utils/figma-variable.ts +49 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import type * as FigmaRestSpec from "@figma/rest-api-spec";
|
|
2
|
+
|
|
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
|
+
};
|
|
28
|
+
|
|
29
|
+
export type NormalizedCornerTrait = Pick<
|
|
30
|
+
FigmaRestSpec.CornerTrait,
|
|
31
|
+
"cornerRadius" | "rectangleCornerRadii"
|
|
32
|
+
>;
|
|
33
|
+
|
|
34
|
+
export type NormalizedHasChildrenTrait = {
|
|
35
|
+
children: NormalizedSceneNode[];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type NormalizedHasLayoutTrait = Pick<
|
|
39
|
+
FigmaRestSpec.HasLayoutTrait,
|
|
40
|
+
| "layoutAlign"
|
|
41
|
+
| "layoutGrow"
|
|
42
|
+
| "absoluteBoundingBox"
|
|
43
|
+
| "relativeTransform"
|
|
44
|
+
| "layoutPositioning"
|
|
45
|
+
| "layoutSizingHorizontal"
|
|
46
|
+
| "layoutSizingVertical"
|
|
47
|
+
| "minHeight"
|
|
48
|
+
| "minWidth"
|
|
49
|
+
| "maxHeight"
|
|
50
|
+
| "maxWidth"
|
|
51
|
+
>;
|
|
52
|
+
|
|
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"
|
|
63
|
+
> & {
|
|
64
|
+
fills: NormalizedPaint[];
|
|
65
|
+
strokes: NormalizedPaint[];
|
|
66
|
+
fillStyleKey?: string;
|
|
67
|
+
};
|
|
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
|
+
|
|
86
|
+
export type NormalizedHasFramePropertiesTrait = Pick<
|
|
87
|
+
FigmaRestSpec.HasFramePropertiesTrait,
|
|
88
|
+
| "layoutMode"
|
|
89
|
+
| "layoutWrap"
|
|
90
|
+
| "paddingLeft"
|
|
91
|
+
| "paddingRight"
|
|
92
|
+
| "paddingTop"
|
|
93
|
+
| "paddingBottom"
|
|
94
|
+
| "primaryAxisAlignItems"
|
|
95
|
+
| "primaryAxisSizingMode"
|
|
96
|
+
| "counterAxisAlignItems"
|
|
97
|
+
| "counterAxisSizingMode"
|
|
98
|
+
| "itemSpacing"
|
|
99
|
+
| "counterAxisSpacing"
|
|
100
|
+
>;
|
|
101
|
+
|
|
102
|
+
export interface NormalizedTextSegment {
|
|
103
|
+
characters: string;
|
|
104
|
+
start: number;
|
|
105
|
+
end: number;
|
|
106
|
+
style: {
|
|
107
|
+
fontFamily?: string;
|
|
108
|
+
fontWeight?: number;
|
|
109
|
+
fontSize?: number;
|
|
110
|
+
italic?: boolean;
|
|
111
|
+
textDecoration?: string;
|
|
112
|
+
letterSpacing?: number;
|
|
113
|
+
/**
|
|
114
|
+
* in pixels
|
|
115
|
+
*/
|
|
116
|
+
lineHeight?: number;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export type NormalizedTypePropertiesTrait = Pick<
|
|
121
|
+
FigmaRestSpec.TypePropertiesTrait,
|
|
122
|
+
"style" | "characters"
|
|
123
|
+
> & {
|
|
124
|
+
segments: NormalizedTextSegment[];
|
|
125
|
+
|
|
126
|
+
textStyleKey?: string;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export type NormalizedDefaultShapeTrait = NormalizedIsLayerTrait &
|
|
130
|
+
NormalizedHasLayoutTrait &
|
|
131
|
+
NormalizedHasGeometryTrait &
|
|
132
|
+
NormalizedHasEffectsTrait;
|
|
133
|
+
|
|
134
|
+
export type NormalizedFrameTrait = NormalizedIsLayerTrait &
|
|
135
|
+
NormalizedHasLayoutTrait &
|
|
136
|
+
NormalizedHasGeometryTrait &
|
|
137
|
+
NormalizedHasEffectsTrait &
|
|
138
|
+
NormalizedHasChildrenTrait &
|
|
139
|
+
NormalizedCornerTrait &
|
|
140
|
+
NormalizedHasFramePropertiesTrait;
|
|
141
|
+
|
|
142
|
+
export interface NormalizedFrameNode extends NormalizedFrameTrait {
|
|
143
|
+
type: FigmaRestSpec.FrameNode["type"];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface NormalizedRectangleNode
|
|
147
|
+
extends NormalizedDefaultShapeTrait,
|
|
148
|
+
NormalizedCornerTrait {
|
|
149
|
+
type: FigmaRestSpec.RectangleNode["type"];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface NormalizedTextNode
|
|
153
|
+
extends NormalizedDefaultShapeTrait,
|
|
154
|
+
NormalizedTypePropertiesTrait {
|
|
155
|
+
type: FigmaRestSpec.TextNode["type"];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface NormalizedComponentNode extends NormalizedFrameTrait {
|
|
159
|
+
type: FigmaRestSpec.ComponentNode["type"];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface NormalizedInstanceNode extends NormalizedFrameTrait {
|
|
163
|
+
type: FigmaRestSpec.InstanceNode["type"];
|
|
164
|
+
|
|
165
|
+
componentProperties: {
|
|
166
|
+
[key: string]: FigmaRestSpec.ComponentProperty & {
|
|
167
|
+
componentKey?: string;
|
|
168
|
+
componentSetKey?: string;
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
componentKey: string;
|
|
173
|
+
|
|
174
|
+
componentSetKey?: string;
|
|
175
|
+
|
|
176
|
+
overrides?: FigmaRestSpec.InstanceNode["overrides"];
|
|
177
|
+
|
|
178
|
+
children: NormalizedSceneNode[];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface NormalizedVectorNode extends NormalizedDefaultShapeTrait, NormalizedCornerTrait {
|
|
182
|
+
type: FigmaRestSpec.VectorNode["type"];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface NormalizedBooleanOperationNode
|
|
186
|
+
extends NormalizedIsLayerTrait,
|
|
187
|
+
NormalizedHasChildrenTrait,
|
|
188
|
+
NormalizedHasLayoutTrait,
|
|
189
|
+
NormalizedHasGeometryTrait,
|
|
190
|
+
NormalizedHasEffectsTrait {
|
|
191
|
+
type: FigmaRestSpec.BooleanOperationNode["type"];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export interface NormalizedUnhandledNode {
|
|
195
|
+
type: "UNHANDLED";
|
|
196
|
+
id: string;
|
|
197
|
+
original: FigmaRestSpec.Node | SceneNode;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export type NormalizedSceneNode =
|
|
201
|
+
| NormalizedFrameNode
|
|
202
|
+
| NormalizedRectangleNode
|
|
203
|
+
| NormalizedTextNode
|
|
204
|
+
| NormalizedComponentNode
|
|
205
|
+
| NormalizedInstanceNode
|
|
206
|
+
| NormalizedVectorNode
|
|
207
|
+
| NormalizedBooleanOperationNode
|
|
208
|
+
| NormalizedUnhandledNode;
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
export function identity<T>(value: T) {
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* camelCase but preserve underscore between numbers.
|
|
29
|
+
* temporary workaround to avoid x1_5 -> x15
|
|
30
|
+
* @example "color-1_5" -> "color1_5"
|
|
31
|
+
*/
|
|
32
|
+
export function camelCasePreserveUnderscoreBetweenNumbers(input: string) {
|
|
33
|
+
return camelCase(input, {
|
|
34
|
+
mergeAmbiguousCharacters: false,
|
|
35
|
+
})
|
|
36
|
+
.replaceAll(/(\D)_(\d)/g, "$1$2")
|
|
37
|
+
.replaceAll(/(\d)_(\D)/g, "$1$2");
|
|
38
|
+
}
|
package/src/utils/css.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RGBA } from "@figma/rest-api-spec";
|
|
2
|
+
|
|
3
|
+
export function toCssPixel(value: number): `${number}px` {
|
|
4
|
+
return `${value}px`;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function toCssRem(value: number): `${number}rem` {
|
|
8
|
+
return `${value / 16}rem`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function toCssRgba(
|
|
12
|
+
color: RGBA,
|
|
13
|
+
): `rgba(${number}, ${number}, ${number}, ${number})` | `rgb(${number}, ${number}, ${number})` {
|
|
14
|
+
if (color.a === 1) {
|
|
15
|
+
return `rgb(${Math.round(color.r * 255)}, ${Math.round(color.g * 255)}, ${Math.round(color.b * 255)})`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return `rgba(${Math.round(color.r * 255)}, ${Math.round(color.g * 255)}, ${Math.round(color.b * 255)}, ${color.a})`;
|
|
19
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @see https://gist.github.com/yagudaev/0c2b89674c6aee8b38cd379752ef58d0
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const identityMatrixHandlePositions = [
|
|
6
|
+
[0, 1, 0],
|
|
7
|
+
[0.5, 0.5, 1],
|
|
8
|
+
[1, 1, 1],
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Inverts a 2x3 affine transformation matrix
|
|
13
|
+
* For a 2x3 matrix [[a, b, c], [d, e, f]], we treat it as a 3x3 matrix with [0, 0, 1] as the third row
|
|
14
|
+
*/
|
|
15
|
+
function inv(matrix: number[][]): number[][] {
|
|
16
|
+
const [[a, b, c], [d, e, f]] = matrix;
|
|
17
|
+
|
|
18
|
+
// Calculate determinant of the 2x2 linear part
|
|
19
|
+
const det = a * e - b * d;
|
|
20
|
+
|
|
21
|
+
if (Math.abs(det) < 1e-10) {
|
|
22
|
+
throw new Error("Matrix is not invertible");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Invert the 2x2 linear part
|
|
26
|
+
const invDet = 1 / det;
|
|
27
|
+
const a_inv = e * invDet;
|
|
28
|
+
const b_inv = -b * invDet;
|
|
29
|
+
const d_inv = -d * invDet;
|
|
30
|
+
const e_inv = a * invDet;
|
|
31
|
+
|
|
32
|
+
// Calculate the inverted translation
|
|
33
|
+
const c_inv = -(a_inv * c + b_inv * f);
|
|
34
|
+
const f_inv = -(d_inv * c + e_inv * f);
|
|
35
|
+
|
|
36
|
+
return [
|
|
37
|
+
[a_inv, b_inv, c_inv],
|
|
38
|
+
[d_inv, e_inv, f_inv],
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Multiplies a 2x3 matrix with a 3x3 matrix
|
|
44
|
+
* Result is a 2x3 matrix
|
|
45
|
+
*/
|
|
46
|
+
function multiply(matrix1: number[][], matrix2: number[][]): number[][] {
|
|
47
|
+
const [[a, b, c], [d, e, f]] = matrix1;
|
|
48
|
+
const result: number[][] = [[], []];
|
|
49
|
+
|
|
50
|
+
// For each column in matrix2
|
|
51
|
+
for (let col = 0; col < matrix2[0].length; col++) {
|
|
52
|
+
// First row of result
|
|
53
|
+
result[0][col] = a * matrix2[0][col] + b * matrix2[1][col] + c * matrix2[2][col];
|
|
54
|
+
// Second row of result
|
|
55
|
+
result[1][col] = d * matrix2[0][col] + e * matrix2[1][col] + f * matrix2[2][col];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function convertTransformToGradientHandles(transform: number[][]) {
|
|
62
|
+
const inverseTransform = inv(transform);
|
|
63
|
+
|
|
64
|
+
// point matrix
|
|
65
|
+
const mp = multiply(inverseTransform, identityMatrixHandlePositions);
|
|
66
|
+
|
|
67
|
+
return [
|
|
68
|
+
{ x: mp[0][0], y: mp[1][0] },
|
|
69
|
+
{ x: mp[0][1], y: mp[1][1] },
|
|
70
|
+
{ x: mp[0][2], y: mp[1][2] },
|
|
71
|
+
];
|
|
72
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NormalizedHasGeometryTrait,
|
|
3
|
+
NormalizedInstanceNode,
|
|
4
|
+
NormalizedSceneNode,
|
|
5
|
+
NormalizedSolidPaint,
|
|
6
|
+
} from "../normalizer";
|
|
7
|
+
|
|
8
|
+
export function traverseNode(
|
|
9
|
+
node: NormalizedSceneNode,
|
|
10
|
+
callback: (node: NormalizedSceneNode) => void,
|
|
11
|
+
) {
|
|
12
|
+
callback(node);
|
|
13
|
+
|
|
14
|
+
if (!("children" in node)) return;
|
|
15
|
+
|
|
16
|
+
for (const child of node.children) {
|
|
17
|
+
traverseNode(child, callback);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function findOne(
|
|
22
|
+
node: NormalizedSceneNode,
|
|
23
|
+
callback: (node: NormalizedSceneNode) => boolean,
|
|
24
|
+
) {
|
|
25
|
+
let result: NormalizedSceneNode | undefined;
|
|
26
|
+
|
|
27
|
+
traverseNode(node, (n) => {
|
|
28
|
+
if (callback(n)) {
|
|
29
|
+
result = n;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function findAll(
|
|
37
|
+
node: NormalizedSceneNode,
|
|
38
|
+
callback: (node: NormalizedSceneNode) => boolean,
|
|
39
|
+
) {
|
|
40
|
+
const result: NormalizedSceneNode[] = [];
|
|
41
|
+
|
|
42
|
+
traverseNode(node, (n) => {
|
|
43
|
+
if (callback(n)) {
|
|
44
|
+
result.push(n);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function findAllInstances<T>({ node, key }: { node: NormalizedSceneNode; key: string }) {
|
|
52
|
+
return findAll(
|
|
53
|
+
node,
|
|
54
|
+
(n) => n.type === "INSTANCE" && (n.componentKey === key || n.componentSetKey === key),
|
|
55
|
+
) as (Omit<NormalizedInstanceNode, "componentProperties"> & { componentProperties: T })[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function getFirstSolidFill(node: NormalizedHasGeometryTrait) {
|
|
59
|
+
const fills = node.fills.filter(
|
|
60
|
+
(fill): fill is NormalizedSolidPaint =>
|
|
61
|
+
fill.type === "SOLID" && (!("visible" in fill) || fill.visible === true),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (fills.length === 0) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return fills[0];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function getFirstFillVariable(node: NormalizedHasGeometryTrait) {
|
|
72
|
+
const fill = getFirstSolidFill(node);
|
|
73
|
+
|
|
74
|
+
return fill?.boundVariables?.color;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function getFirstStroke(node: NormalizedHasGeometryTrait) {
|
|
78
|
+
const strokes =
|
|
79
|
+
node.strokes?.filter(
|
|
80
|
+
(stroke): stroke is NormalizedSolidPaint =>
|
|
81
|
+
stroke.type === "SOLID" && (!("visible" in stroke) || stroke.visible === true),
|
|
82
|
+
) ?? [];
|
|
83
|
+
|
|
84
|
+
if (strokes.length === 0) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return strokes[0];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getFirstStrokeVariable(node: NormalizedHasGeometryTrait) {
|
|
92
|
+
const stroke = getFirstStroke(node);
|
|
93
|
+
|
|
94
|
+
return stroke?.boundVariables?.color;
|
|
95
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { VariableScope } from "@figma/rest-api-spec";
|
|
2
|
+
|
|
3
|
+
// boundVariable.id is formatted as "VariableID:{key}/{localId}", we have to extract the key
|
|
4
|
+
export function sanitizeVariableId(id: string) {
|
|
5
|
+
return id.replace("VariableID:", "").split("/")[0]!;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function isVariableAlias(value: unknown): value is VariableAlias {
|
|
9
|
+
return (
|
|
10
|
+
typeof value === "object" &&
|
|
11
|
+
value !== null &&
|
|
12
|
+
"type" in value &&
|
|
13
|
+
value.type === "VARIABLE_ALIAS"
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isIdenticalVariableValue(
|
|
18
|
+
value1: string | number | boolean | RGBA,
|
|
19
|
+
value2: string | number | boolean | RGBA,
|
|
20
|
+
) {
|
|
21
|
+
if (typeof value1 !== typeof value2) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (typeof value1 === "string" || typeof value1 === "number" || typeof value1 === "boolean") {
|
|
26
|
+
return value1 === value2;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
value1.r === (value2 as RGBA).r &&
|
|
31
|
+
value1.g === (value2 as RGBA).g &&
|
|
32
|
+
value1.b === (value2 as RGBA).b &&
|
|
33
|
+
value1.a === (value2 as RGBA).a
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isInsideScope(variable: { scopes: VariableScope[] }, scope: VariableScope) {
|
|
38
|
+
if (variable.scopes.includes("ALL_SCOPES")) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (variable.scopes.includes("ALL_FILLS")) {
|
|
43
|
+
if (scope === "FRAME_FILL" || scope === "SHAPE_FILL" || scope === "TEXT_FILL") {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return variable.scopes.includes(scope);
|
|
49
|
+
}
|