@seed-design/figma 0.0.6 → 0.0.15

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.
Files changed (195) hide show
  1. package/lib/index.cjs +5548 -4901
  2. package/lib/index.d.ts +489 -189
  3. package/lib/index.js +5535 -4888
  4. package/package.json +3 -2
  5. package/src/codegen/core/codegen.ts +65 -0
  6. package/src/codegen/core/component.ts +15 -27
  7. package/src/codegen/core/component.types.ts +29 -0
  8. package/src/codegen/core/element.ts +13 -0
  9. package/src/codegen/core/index.ts +13 -8
  10. package/src/codegen/core/infer-layout.test.ts +285 -0
  11. package/src/codegen/core/infer-layout.ts +416 -0
  12. package/src/codegen/core/jsx.ts +12 -0
  13. package/src/codegen/core/props.ts +81 -0
  14. package/src/codegen/core/value.ts +289 -0
  15. package/src/codegen/index.ts +39 -6
  16. package/src/codegen/targets/figma/context.ts +139 -0
  17. package/src/codegen/targets/figma/frame.ts +37 -0
  18. package/src/codegen/targets/figma/index.ts +6 -0
  19. package/src/codegen/targets/figma/instance.ts +16 -0
  20. package/src/codegen/targets/figma/props.ts +244 -0
  21. package/src/codegen/targets/figma/shape.ts +62 -0
  22. package/src/codegen/targets/figma/text.ts +33 -0
  23. package/src/codegen/targets/index.ts +2 -0
  24. package/src/codegen/{domain/seed-component → targets/react/component}/deps.interface.ts +2 -2
  25. package/src/codegen/{domain/seed-component → targets/react/component}/index.ts +36 -34
  26. package/src/codegen/{domain/seed-component → targets/react/component}/properties.type.ts +2 -2
  27. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/action-button.ts +4 -5
  28. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/action-chip.ts +3 -4
  29. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/action-sheet.ts +4 -5
  30. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/app-bar.ts +5 -6
  31. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/avatar-stack.ts +4 -5
  32. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/avatar.ts +4 -5
  33. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/badge.ts +4 -5
  34. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/callout.ts +4 -5
  35. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/checkbox.ts +4 -5
  36. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/chip-tabs.ts +4 -5
  37. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/control-chip.ts +4 -5
  38. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/error-state.ts +4 -5
  39. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/extended-action-sheet.ts +4 -5
  40. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/extended-fab.ts +4 -5
  41. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/fab.ts +2 -2
  42. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/help-bubble.ts +2 -2
  43. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/identity-placeholder.ts +2 -2
  44. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/inline-banner.ts +5 -6
  45. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/manner-temp-badge.ts +3 -4
  46. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/multiline-text-field.ts +4 -5
  47. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/progress-circle.ts +3 -4
  48. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/reaction-button.ts +4 -5
  49. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/segmented-control.ts +4 -5
  50. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/select-box.ts +4 -5
  51. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/skeleton.ts +3 -4
  52. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/snackbar.ts +3 -4
  53. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/switch.ts +4 -5
  54. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/tabs.ts +5 -6
  55. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/text-button.ts +6 -7
  56. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/text-field.ts +4 -5
  57. package/src/codegen/{domain/seed-component → targets/react/component}/transformers/toggle-button.ts +4 -5
  58. package/src/codegen/targets/react/context.ts +170 -0
  59. package/src/codegen/targets/react/frame.ts +75 -0
  60. package/src/codegen/targets/react/index.ts +7 -0
  61. package/src/codegen/{domain/instance.service.ts → targets/react/instance.ts} +20 -33
  62. package/src/codegen/targets/react/props.ts +361 -0
  63. package/src/codegen/targets/react/shape.ts +36 -0
  64. package/src/codegen/targets/react/text.ts +33 -0
  65. package/src/{codegen → entities}/data/icons.ts +1 -1
  66. package/src/{codegen → entities}/data/styles.ts +1 -1
  67. package/src/{codegen → entities}/data/variable-collections.ts +1 -1
  68. package/src/{codegen → entities}/data/variables.ts +1 -1
  69. package/src/entities/index.ts +41 -0
  70. package/src/{codegen/domain → entities}/style.repository.ts +6 -2
  71. package/src/{codegen/domain → entities}/style.service.ts +1 -1
  72. package/src/{codegen/domain → entities}/variable.repository.ts +17 -4
  73. package/src/{codegen/domain → entities}/variable.service.ts +47 -9
  74. package/src/index.ts +1 -0
  75. package/src/normalizer/from-plugin.ts +3 -0
  76. package/src/normalizer/types.ts +28 -24
  77. package/src/utils/common.ts +4 -0
  78. package/src/utils/css.ts +10 -4
  79. package/src/utils/figma-node.ts +42 -2
  80. package/src/codegen/context.ts +0 -148
  81. package/src/codegen/core/transformer.ts +0 -40
  82. package/src/codegen/domain/codegen.service.ts +0 -69
  83. package/src/codegen/domain/figma-component.service.ts +0 -21
  84. package/src/codegen/domain/frame.service.ts +0 -108
  85. package/src/codegen/domain/index.ts +0 -22
  86. package/src/codegen/domain/props/container-layout-props.service.ts +0 -248
  87. package/src/codegen/domain/props/fill-props.service.ts +0 -75
  88. package/src/codegen/domain/props/radius-props.service.ts +0 -105
  89. package/src/codegen/domain/props/self-layout-props.service.ts +0 -127
  90. package/src/codegen/domain/props/stroke-props.service.ts +0 -45
  91. package/src/codegen/domain/props/type-style-props.service.ts +0 -31
  92. package/src/codegen/domain/rectangle.service.ts +0 -31
  93. package/src/codegen/domain/text.service.ts +0 -62
  94. /package/src/codegen/{domain/seed-component → targets/react/component}/size.ts +0 -0
  95. /package/src/{codegen → entities}/data/__generated__/component-sets/action-button.d.ts +0 -0
  96. /package/src/{codegen → entities}/data/__generated__/component-sets/action-button.mjs +0 -0
  97. /package/src/{codegen → entities}/data/__generated__/component-sets/action-chip.d.ts +0 -0
  98. /package/src/{codegen → entities}/data/__generated__/component-sets/action-chip.mjs +0 -0
  99. /package/src/{codegen → entities}/data/__generated__/component-sets/action-sheet.d.ts +0 -0
  100. /package/src/{codegen → entities}/data/__generated__/component-sets/action-sheet.mjs +0 -0
  101. /package/src/{codegen → entities}/data/__generated__/component-sets/avatar-stack.d.ts +0 -0
  102. /package/src/{codegen → entities}/data/__generated__/component-sets/avatar-stack.mjs +0 -0
  103. /package/src/{codegen → entities}/data/__generated__/component-sets/avatar.d.ts +0 -0
  104. /package/src/{codegen → entities}/data/__generated__/component-sets/avatar.mjs +0 -0
  105. /package/src/{codegen → entities}/data/__generated__/component-sets/badge.d.ts +0 -0
  106. /package/src/{codegen → entities}/data/__generated__/component-sets/badge.mjs +0 -0
  107. /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-navigation-global.d.ts +0 -0
  108. /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-navigation-global.mjs +0 -0
  109. /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-navigation-kr.d.ts +0 -0
  110. /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-navigation-kr.mjs +0 -0
  111. /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-sheet.d.ts +0 -0
  112. /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-sheet.mjs +0 -0
  113. /package/src/{codegen → entities}/data/__generated__/component-sets/callout.d.ts +0 -0
  114. /package/src/{codegen → entities}/data/__generated__/component-sets/callout.mjs +0 -0
  115. /package/src/{codegen → entities}/data/__generated__/component-sets/checkbox.d.ts +0 -0
  116. /package/src/{codegen → entities}/data/__generated__/component-sets/checkbox.mjs +0 -0
  117. /package/src/{codegen → entities}/data/__generated__/component-sets/chip-tablist.d.ts +0 -0
  118. /package/src/{codegen → entities}/data/__generated__/component-sets/chip-tablist.mjs +0 -0
  119. /package/src/{codegen → entities}/data/__generated__/component-sets/control-chip.d.ts +0 -0
  120. /package/src/{codegen → entities}/data/__generated__/component-sets/control-chip.mjs +0 -0
  121. /package/src/{codegen → entities}/data/__generated__/component-sets/divider.d.ts +0 -0
  122. /package/src/{codegen → entities}/data/__generated__/component-sets/divider.mjs +0 -0
  123. /package/src/{codegen → entities}/data/__generated__/component-sets/error-state.d.ts +0 -0
  124. /package/src/{codegen → entities}/data/__generated__/component-sets/error-state.mjs +0 -0
  125. /package/src/{codegen → entities}/data/__generated__/component-sets/extended-action-sheet.d.ts +0 -0
  126. /package/src/{codegen → entities}/data/__generated__/component-sets/extended-action-sheet.mjs +0 -0
  127. /package/src/{codegen → entities}/data/__generated__/component-sets/extended-floating-action-button.d.ts +0 -0
  128. /package/src/{codegen → entities}/data/__generated__/component-sets/extended-floating-action-button.mjs +0 -0
  129. /package/src/{codegen → entities}/data/__generated__/component-sets/floating-action-button.d.ts +0 -0
  130. /package/src/{codegen → entities}/data/__generated__/component-sets/floating-action-button.mjs +0 -0
  131. /package/src/{codegen → entities}/data/__generated__/component-sets/help-bubble.d.ts +0 -0
  132. /package/src/{codegen → entities}/data/__generated__/component-sets/help-bubble.mjs +0 -0
  133. /package/src/{codegen → entities}/data/__generated__/component-sets/identity-placeholder.d.ts +0 -0
  134. /package/src/{codegen → entities}/data/__generated__/component-sets/identity-placeholder.mjs +0 -0
  135. /package/src/{codegen → entities}/data/__generated__/component-sets/index.d.ts +0 -0
  136. /package/src/{codegen → entities}/data/__generated__/component-sets/index.mjs +0 -0
  137. /package/src/{codegen → entities}/data/__generated__/component-sets/inline-banner.d.ts +0 -0
  138. /package/src/{codegen → entities}/data/__generated__/component-sets/inline-banner.mjs +0 -0
  139. /package/src/{codegen → entities}/data/__generated__/component-sets/main-tab-navigation-global.d.ts +0 -0
  140. /package/src/{codegen → entities}/data/__generated__/component-sets/main-tab-navigation-global.mjs +0 -0
  141. /package/src/{codegen → entities}/data/__generated__/component-sets/main-tab-navigation-kr.d.ts +0 -0
  142. /package/src/{codegen → entities}/data/__generated__/component-sets/main-tab-navigation-kr.mjs +0 -0
  143. /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp-badge.d.ts +0 -0
  144. /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp-badge.mjs +0 -0
  145. /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp-bar.d.ts +0 -0
  146. /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp-bar.mjs +0 -0
  147. /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp.d.ts +0 -0
  148. /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp.mjs +0 -0
  149. /package/src/{codegen → entities}/data/__generated__/component-sets/multiline-text-field.d.ts +0 -0
  150. /package/src/{codegen → entities}/data/__generated__/component-sets/multiline-text-field.mjs +0 -0
  151. /package/src/{codegen → entities}/data/__generated__/component-sets/progress-circle.d.ts +0 -0
  152. /package/src/{codegen → entities}/data/__generated__/component-sets/progress-circle.mjs +0 -0
  153. /package/src/{codegen → entities}/data/__generated__/component-sets/radio.d.ts +0 -0
  154. /package/src/{codegen → entities}/data/__generated__/component-sets/radio.mjs +0 -0
  155. /package/src/{codegen → entities}/data/__generated__/component-sets/range-slider.d.ts +0 -0
  156. /package/src/{codegen → entities}/data/__generated__/component-sets/range-slider.mjs +0 -0
  157. /package/src/{codegen → entities}/data/__generated__/component-sets/reaction-button.d.ts +0 -0
  158. /package/src/{codegen → entities}/data/__generated__/component-sets/reaction-button.mjs +0 -0
  159. /package/src/{codegen → entities}/data/__generated__/component-sets/segmented-control.d.ts +0 -0
  160. /package/src/{codegen → entities}/data/__generated__/component-sets/segmented-control.mjs +0 -0
  161. /package/src/{codegen → entities}/data/__generated__/component-sets/select-box.d.ts +0 -0
  162. /package/src/{codegen → entities}/data/__generated__/component-sets/select-box.mjs +0 -0
  163. /package/src/{codegen → entities}/data/__generated__/component-sets/skeleton.d.ts +0 -0
  164. /package/src/{codegen → entities}/data/__generated__/component-sets/skeleton.mjs +0 -0
  165. /package/src/{codegen → entities}/data/__generated__/component-sets/slider.d.ts +0 -0
  166. /package/src/{codegen → entities}/data/__generated__/component-sets/slider.mjs +0 -0
  167. /package/src/{codegen → entities}/data/__generated__/component-sets/snackbar.d.ts +0 -0
  168. /package/src/{codegen → entities}/data/__generated__/component-sets/snackbar.mjs +0 -0
  169. /package/src/{codegen → entities}/data/__generated__/component-sets/standard-navigation.d.ts +0 -0
  170. /package/src/{codegen → entities}/data/__generated__/component-sets/standard-navigation.mjs +0 -0
  171. /package/src/{codegen → entities}/data/__generated__/component-sets/switch.d.ts +0 -0
  172. /package/src/{codegen → entities}/data/__generated__/component-sets/switch.mjs +0 -0
  173. /package/src/{codegen → entities}/data/__generated__/component-sets/tablist.d.ts +0 -0
  174. /package/src/{codegen → entities}/data/__generated__/component-sets/tablist.mjs +0 -0
  175. /package/src/{codegen → entities}/data/__generated__/component-sets/template-bottom-fixed-bar.d.ts +0 -0
  176. /package/src/{codegen → entities}/data/__generated__/component-sets/template-bottom-fixed-bar.mjs +0 -0
  177. /package/src/{codegen → entities}/data/__generated__/component-sets/template-button-group.d.ts +0 -0
  178. /package/src/{codegen → entities}/data/__generated__/component-sets/template-button-group.mjs +0 -0
  179. /package/src/{codegen → entities}/data/__generated__/component-sets/template-chip-group.d.ts +0 -0
  180. /package/src/{codegen → entities}/data/__generated__/component-sets/template-chip-group.mjs +0 -0
  181. /package/src/{codegen → entities}/data/__generated__/component-sets/template-select-box-group.d.ts +0 -0
  182. /package/src/{codegen → entities}/data/__generated__/component-sets/template-select-box-group.mjs +0 -0
  183. /package/src/{codegen → entities}/data/__generated__/component-sets/template-top-navigation.d.ts +0 -0
  184. /package/src/{codegen → entities}/data/__generated__/component-sets/template-top-navigation.mjs +0 -0
  185. /package/src/{codegen → entities}/data/__generated__/component-sets/text-button.d.ts +0 -0
  186. /package/src/{codegen → entities}/data/__generated__/component-sets/text-button.mjs +0 -0
  187. /package/src/{codegen → entities}/data/__generated__/component-sets/text-field.d.ts +0 -0
  188. /package/src/{codegen → entities}/data/__generated__/component-sets/text-field.mjs +0 -0
  189. /package/src/{codegen → entities}/data/__generated__/component-sets/toggle-button.d.ts +0 -0
  190. /package/src/{codegen → entities}/data/__generated__/component-sets/toggle-button.mjs +0 -0
  191. /package/src/{codegen/domain → entities}/icon.interface.ts +0 -0
  192. /package/src/{codegen/domain → entities}/icon.repository.ts +0 -0
  193. /package/src/{codegen/domain → entities}/icon.service.ts +0 -0
  194. /package/src/{codegen/domain → entities}/style.interface.ts +0 -0
  195. /package/src/{codegen/domain → entities}/variable.interface.ts +0 -0
@@ -73,6 +73,7 @@ export function createPluginNormalizer() {
73
73
  layoutSizingHorizontal: node.layoutSizingHorizontal,
74
74
  layoutSizingVertical: node.layoutSizingVertical,
75
75
  absoluteBoundingBox: node.absoluteBoundingBox,
76
+ relativeTransform: node.relativeTransform,
76
77
  layoutMode: node.inferredAutoLayout?.layoutMode,
77
78
  layoutWrap: node.inferredAutoLayout?.layoutWrap,
78
79
  paddingLeft: node.inferredAutoLayout?.paddingLeft,
@@ -296,6 +297,7 @@ export function createPluginNormalizer() {
296
297
  | "layoutSizingHorizontal"
297
298
  | "layoutSizingVertical"
298
299
  | "absoluteBoundingBox"
300
+ | "relativeTransform"
299
301
  | "minHeight"
300
302
  | "minWidth"
301
303
  | "maxHeight"
@@ -309,6 +311,7 @@ export function createPluginNormalizer() {
309
311
  layoutSizingHorizontal: node.layoutSizingHorizontal,
310
312
  layoutSizingVertical: node.layoutSizingVertical,
311
313
  absoluteBoundingBox: node.absoluteBoundingBox,
314
+ relativeTransform: node.relativeTransform,
312
315
  fills: normalizePaints(node.fills),
313
316
  strokes: normalizePaints(node.strokes),
314
317
  strokeWeight: node.strokeWeight === figma.mixed ? undefined : node.strokeWeight,
@@ -19,6 +19,7 @@ export type NormalizedHasLayoutTrait = Pick<
19
19
  | "layoutAlign"
20
20
  | "layoutGrow"
21
21
  | "absoluteBoundingBox"
22
+ | "relativeTransform"
22
23
  | "layoutPositioning"
23
24
  | "layoutSizingHorizontal"
24
25
  | "layoutSizingVertical"
@@ -49,6 +50,30 @@ export type NormalizedHasFramePropertiesTrait = Pick<
49
50
  | "counterAxisSpacing"
50
51
  >;
51
52
 
53
+ export interface NormalizedTextSegment {
54
+ characters: string;
55
+ start: number;
56
+ end: number;
57
+ style: {
58
+ fontFamily?: string;
59
+ fontWeight?: number;
60
+ fontSize?: number;
61
+ italic?: boolean;
62
+ textDecoration?: string;
63
+ letterSpacing?: number;
64
+ lineHeight?: number | { unit: string; value: number };
65
+ };
66
+ }
67
+
68
+ export type NormalizedTypePropertiesTrait = Pick<
69
+ FigmaRestSpec.TypePropertiesTrait,
70
+ "style" | "characters"
71
+ > & {
72
+ segments: NormalizedTextSegment[];
73
+
74
+ textStyleKey?: string;
75
+ };
76
+
52
77
  export type NormalizedDefaultShapeTrait = NormalizedIsLayerTrait &
53
78
  NormalizedHasLayoutTrait &
54
79
  NormalizedHasGeometryTrait;
@@ -70,31 +95,10 @@ export interface NormalizedRectangleNode
70
95
  type: FigmaRestSpec.RectangleNode["type"];
71
96
  }
72
97
 
73
- export interface NormalizedTextNode extends NormalizedDefaultShapeTrait {
98
+ export interface NormalizedTextNode
99
+ extends NormalizedDefaultShapeTrait,
100
+ NormalizedTypePropertiesTrait {
74
101
  type: FigmaRestSpec.TextNode["type"];
75
-
76
- style: FigmaRestSpec.TextNode["style"];
77
-
78
- characters: FigmaRestSpec.TextNode["characters"];
79
-
80
- segments: NormalizedTextSegment[];
81
-
82
- textStyleKey?: string;
83
- }
84
-
85
- export interface NormalizedTextSegment {
86
- characters: string;
87
- start: number;
88
- end: number;
89
- style: {
90
- fontFamily?: string;
91
- fontWeight?: number;
92
- fontSize?: number;
93
- italic?: boolean;
94
- textDecoration?: string;
95
- letterSpacing?: number;
96
- lineHeight?: number | { unit: string; value: number };
97
- };
98
102
  }
99
103
 
100
104
  export interface NormalizedComponentNode extends NormalizedFrameTrait {
@@ -20,6 +20,10 @@ export function objectEntries<T extends Record<string, unknown>>(obj: T) {
20
20
  return Object.entries(obj) as [keyof T, T[keyof T]][];
21
21
  }
22
22
 
23
+ export function identity<T>(value: T) {
24
+ return value;
25
+ }
26
+
23
27
  /**
24
28
  * camelCase but preserve underscore between numbers.
25
29
  * temporary workaround to avoid x1_5 -> x15
package/src/utils/css.ts CHANGED
@@ -1,13 +1,19 @@
1
1
  import type { RGBA } from "@figma/rest-api-spec";
2
2
 
3
- export function toCssPixel(value: number) {
3
+ export function toCssPixel(value: number): `${number}px` {
4
4
  return `${value}px`;
5
5
  }
6
6
 
7
- export function toCssRgba(color: RGBA) {
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})` {
8
14
  if (color.a === 1) {
9
- return `rgb(${color.r * 255}, ${color.g * 255}, ${color.b * 255})`;
15
+ return `rgb(${Math.round(color.r * 255)}, ${Math.round(color.g * 255)}, ${Math.round(color.b * 255)})`;
10
16
  }
11
17
 
12
- return `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${color.a})`;
18
+ return `rgba(${Math.round(color.r * 255)}, ${Math.round(color.g * 255)}, ${Math.round(color.b * 255)}, ${color.a})`;
13
19
  }
@@ -1,5 +1,10 @@
1
- import type { NormalizedInstanceNode, NormalizedSceneNode } from "../normalizer";
2
-
1
+ import type { SolidPaint } from "@figma/rest-api-spec";
2
+ import type {
3
+ NormalizedHasGeometryTrait,
4
+ NormalizedInstanceNode,
5
+ NormalizedIsLayerTrait,
6
+ NormalizedSceneNode,
7
+ } from "../normalizer";
3
8
  export function traverseNode(
4
9
  node: NormalizedSceneNode,
5
10
  callback: (node: NormalizedSceneNode) => void,
@@ -47,3 +52,38 @@ export function findAllInstances<T>({ node, key }: { node: NormalizedSceneNode;
47
52
  (n) => n.type === "INSTANCE" && (n.componentKey === key || n.componentSetKey === key),
48
53
  ) as (NormalizedInstanceNode & { componentProperties: T })[];
49
54
  }
55
+
56
+ export function getFirstSolidFill(node: NormalizedHasGeometryTrait) {
57
+ const fills = node.fills.filter(
58
+ (fill): fill is SolidPaint =>
59
+ fill.type === "SOLID" && (!("visible" in fill) || fill.visible === true),
60
+ );
61
+
62
+ if (fills.length === 0) {
63
+ return undefined;
64
+ }
65
+
66
+ return fills[0];
67
+ }
68
+
69
+ export function getFirstFillVariable(node: NormalizedIsLayerTrait) {
70
+ return node.boundVariables?.fills?.[0];
71
+ }
72
+
73
+ export function getFirstStroke(node: NormalizedHasGeometryTrait) {
74
+ const strokes =
75
+ node.strokes?.filter(
76
+ (stroke): stroke is SolidPaint =>
77
+ stroke.type === "SOLID" && (!("visible" in stroke) || stroke.visible === true),
78
+ ) ?? [];
79
+
80
+ if (strokes.length === 0) {
81
+ return undefined;
82
+ }
83
+
84
+ return strokes[0];
85
+ }
86
+
87
+ export function getFirstStrokeVariable(node: NormalizedIsLayerTrait) {
88
+ return node.boundVariables?.strokes?.[0];
89
+ }
@@ -1,148 +0,0 @@
1
- import { camelCasePreserveUnderscoreBetweenNumbers } from "@/utils/common";
2
- import { camelCase } from "change-case";
3
- import { FIGMA_ICONS } from "./data/icons";
4
- import { FIGMA_TEXT_STYLES } from "./data/styles";
5
- import { FIGMA_VARIABLE_COLLECTIONS } from "./data/variable-collections";
6
- import { FIGMA_VARIABLES } from "./data/variables";
7
- import {
8
- createCodegenService,
9
- createContainerLayoutPropsService,
10
- createFigmaComponentService,
11
- createFrameFillPropsService,
12
- createFrameStrokePropsService,
13
- createFrameTypeStylePropsService,
14
- createIconService,
15
- createRadiusPropsService,
16
- createSeedComponentTransformers,
17
- createSeedFrameService,
18
- createSeedInstanceService,
19
- createSeedRectangleService,
20
- createSeedTextService,
21
- createSelfLayoutPropsService,
22
- createShapeFillPropsService,
23
- createStaticIconRepository,
24
- createStaticStyleRepository,
25
- createStaticVariableRepository,
26
- createStyleService,
27
- createVariableService,
28
- } from "./domain";
29
-
30
- const IGNORED_COMPONENT_KEYS = new Set<string>([
31
- "1acdc7247c83a73a0504d6fad86d08783938cb1a",
32
- "b38b719b61cdf1a24458d7a7888bee74b7649084",
33
- ]);
34
-
35
- export interface CodegenContextOptions {
36
- ignoredComponentKeys?: Set<string>;
37
- shouldInferVariableName: boolean;
38
- shouldPrintSource: boolean;
39
- }
40
-
41
- export function createCodegenContext(options: CodegenContextOptions) {
42
- const {
43
- ignoredComponentKeys = IGNORED_COMPONENT_KEYS,
44
- shouldInferVariableName,
45
- shouldPrintSource,
46
- } = options;
47
-
48
- const styleRepository = createStaticStyleRepository(FIGMA_TEXT_STYLES);
49
- const variableRepository = createStaticVariableRepository({
50
- variables: FIGMA_VARIABLES,
51
- variableCollections: FIGMA_VARIABLE_COLLECTIONS,
52
- });
53
- const iconRepository = createStaticIconRepository(FIGMA_ICONS);
54
-
55
- const styleService = createStyleService({
56
- styleRepository,
57
- styleNameTransformer: ({ slug }) =>
58
- camelCase(slug[slug.length - 1]!, { mergeAmbiguousCharacters: true }),
59
- });
60
- const variableService = createVariableService({
61
- variableRepository,
62
- variableNameTransformer: ({ slug }) =>
63
- slug
64
- .filter((s) => s !== "dimension")
65
- .map((s) => s.replaceAll(",", "_"))
66
- .map(camelCasePreserveUnderscoreBetweenNumbers)
67
- .join("."),
68
- });
69
- const iconService = createIconService({
70
- iconRepository,
71
- });
72
-
73
- const containerLayoutPropsService = createContainerLayoutPropsService({
74
- variableService,
75
- shouldInferVariableName,
76
- });
77
- const selfLayoutPropsService = createSelfLayoutPropsService({
78
- variableService,
79
- shouldInferVariableName,
80
- });
81
- const frameFillPropsService = createFrameFillPropsService({
82
- variableService,
83
- });
84
- const shapeFillPropsService = createShapeFillPropsService({
85
- variableService,
86
- });
87
- const radiusPropsService = createRadiusPropsService({
88
- variableService,
89
- shouldInferVariableName,
90
- });
91
- const strokePropsService = createFrameStrokePropsService({
92
- variableService,
93
- });
94
- const typeStylePropsService = createFrameTypeStylePropsService({
95
- variableService,
96
- });
97
-
98
- const figmaComponentService = createFigmaComponentService({
99
- transformers: createSeedComponentTransformers({
100
- iconService,
101
- variableService,
102
- }),
103
- });
104
-
105
- const frameService = createSeedFrameService({
106
- containerLayoutPropsService,
107
- selfLayoutPropsService,
108
- radiusPropsService,
109
- fillPropsService: frameFillPropsService,
110
- strokePropsService,
111
- });
112
- const instanceService = createSeedInstanceService({
113
- figmaComponentService,
114
- fillPropsService: shapeFillPropsService,
115
- selfLayoutPropsService,
116
- iconService,
117
- frameService,
118
- ignoredComponentKeys,
119
- });
120
- const textService = createSeedTextService({
121
- styleService,
122
- fillPropsService: shapeFillPropsService,
123
- typeStylePropsService,
124
- });
125
- const rectangleService = createSeedRectangleService({
126
- selfLayoutPropsService,
127
- });
128
-
129
- const codegenService = createCodegenService({
130
- frameService,
131
- textService,
132
- rectangleService,
133
- instanceService,
134
- shouldPrintSource,
135
- });
136
-
137
- return codegenService;
138
- }
139
-
140
- export const codegenService = createCodegenContext({
141
- shouldInferVariableName: true,
142
- shouldPrintSource: false,
143
- });
144
-
145
- export const devCodegenService = createCodegenContext({
146
- shouldInferVariableName: false,
147
- shouldPrintSource: true,
148
- });
@@ -1,40 +0,0 @@
1
- import type { ElementNode } from "./jsx";
2
- import type { NormalizedInstanceNode, NormalizedSceneNode } from "@/normalizer";
3
-
4
- export type ElementTransformer<T extends NormalizedSceneNode> = (
5
- node: T,
6
- traverse: (node: NormalizedSceneNode) => ElementNode | undefined,
7
- ) => ElementNode | undefined;
8
-
9
- export type PropsTransformer<
10
- T extends Record<string, any> = Record<string, any>,
11
- R extends Record<string, any> = Record<string, any>,
12
- > = (node: T, traverse: (node: NormalizedSceneNode) => ElementNode | undefined) => R;
13
-
14
- export interface ComponentTransformer<
15
- T extends
16
- NormalizedInstanceNode["componentProperties"] = NormalizedInstanceNode["componentProperties"],
17
- > {
18
- key: string;
19
- transform: (node: NormalizedInstanceNode & { componentProperties: T }) => ElementNode;
20
- }
21
-
22
- export function defineElementTransformer<T extends NormalizedSceneNode>(
23
- transformer: ElementTransformer<T>,
24
- ) {
25
- return transformer;
26
- }
27
-
28
- export function definePropsTransformer<
29
- T extends Record<string, any>,
30
- R extends Record<string, any>,
31
- >(transformer: PropsTransformer<T, R>) {
32
- return transformer;
33
- }
34
-
35
- export function defineComponentTransformer<T extends NormalizedInstanceNode["componentProperties"]>(
36
- key: string,
37
- transform: (node: NormalizedInstanceNode & { componentProperties: T }) => ElementNode,
38
- ): ComponentTransformer<T> {
39
- return { key, transform };
40
- }
@@ -1,69 +0,0 @@
1
- import type { NormalizedSceneNode } from "@/normalizer";
2
- import type { ElementNode } from "../core";
3
- import { appendSource, createElement, stringifyElement } from "../core/jsx";
4
- import type { FrameService } from "./frame.service";
5
- import type { InstanceService } from "./instance.service";
6
- import type { RectangleService } from "./rectangle.service";
7
- import type { TextService } from "./text.service";
8
- import { match } from "ts-pattern";
9
-
10
- export interface CodegenService {
11
- transform: (node: NormalizedSceneNode) => ElementNode | undefined;
12
- transformToString: (node: NormalizedSceneNode) => string | undefined;
13
- }
14
-
15
- export interface SeedCodegenServiceDeps {
16
- frameService: FrameService;
17
- textService: TextService;
18
- rectangleService: RectangleService;
19
- instanceService: InstanceService;
20
- shouldPrintSource: boolean;
21
- }
22
-
23
- export function createCodegenService({
24
- frameService,
25
- textService,
26
- rectangleService,
27
- instanceService,
28
- shouldPrintSource,
29
- }: SeedCodegenServiceDeps): CodegenService {
30
- function traverse(node: NormalizedSceneNode): ElementNode | undefined {
31
- if ("visible" in node && !node.visible) {
32
- return;
33
- }
34
-
35
- const result = match(node)
36
- .with({ type: "FRAME" }, (node) => frameService.transform(node, traverse))
37
- .with({ type: "TEXT" }, (node) => textService.transform(node, traverse))
38
- .with({ type: "RECTANGLE" }, (node) => rectangleService.transform(node, traverse))
39
- .with({ type: "COMPONENT" }, (node) => frameService.transform(node, traverse)) // NOTE: Treat component node as Frame for now
40
- .with({ type: "INSTANCE" }, (node) => instanceService.transform(node, traverse))
41
- .with({ type: "VECTOR" }, () => createElement("svg", {}, "Vector Node Placeholder"))
42
- .with({ type: "BOOLEAN_OPERATION" }, () =>
43
- createElement("svg", {}, "Boolean Operation Node Placeholder"),
44
- )
45
- .with({ type: "UNHANDLED" }, () => createElement("UnhandledFigmaNode"))
46
- .exhaustive();
47
-
48
- if (result) {
49
- return appendSource(result, node.id);
50
- }
51
-
52
- return;
53
- }
54
-
55
- function transform(node: NormalizedSceneNode): ElementNode | undefined {
56
- return traverse(node);
57
- }
58
-
59
- function transformToString(node: NormalizedSceneNode): string | undefined {
60
- const result = transform(node);
61
- if (!result) return undefined;
62
-
63
- return stringifyElement(result, {
64
- printSource: shouldPrintSource,
65
- });
66
- }
67
-
68
- return { transform, transformToString };
69
- }
@@ -1,21 +0,0 @@
1
- import type { ComponentTransformer } from "@/codegen/core";
2
-
3
- export interface FigmaComponentService {
4
- getTransformer: (key: string) => ComponentTransformer | undefined;
5
- }
6
-
7
- export function createFigmaComponentService({
8
- transformers,
9
- }: {
10
- transformers: ComponentTransformer[];
11
- }): FigmaComponentService {
12
- const transformerServiceMap = new Map(
13
- transformers.map((transformer) => [transformer.key, transformer]),
14
- );
15
-
16
- return {
17
- getTransformer: (key: string) => {
18
- return transformerServiceMap.get(key);
19
- },
20
- };
21
- }
@@ -1,108 +0,0 @@
1
- import type {
2
- NormalizedComponentNode,
3
- NormalizedFrameNode,
4
- NormalizedInstanceNode,
5
- } from "@/normalizer";
6
- import { createElement, defineElementTransformer, type ElementTransformer } from "../core";
7
- import type {
8
- ContainerLayoutPropsService,
9
- SeedContainerLayoutProps,
10
- } from "./props/container-layout-props.service";
11
- import type { FillPropsService, FrameFillProps } from "./props/fill-props.service";
12
- import type { RadiusPropsService, SeedRadiusProps } from "./props/radius-props.service";
13
- import type {
14
- SeedSelfLayoutProps,
15
- SelfLayoutPropsService,
16
- } from "./props/self-layout-props.service";
17
- import type { SeedFrameStrokeProps, StrokePropsService } from "./props/stroke-props.service";
18
-
19
- export interface FrameService {
20
- transform: ElementTransformer<
21
- NormalizedFrameNode | NormalizedInstanceNode | NormalizedComponentNode
22
- >;
23
- }
24
-
25
- export interface SeedFrameServiceDeps {
26
- containerLayoutPropsService: ContainerLayoutPropsService<SeedContainerLayoutProps>;
27
- selfLayoutPropsService: SelfLayoutPropsService<SeedSelfLayoutProps>;
28
- radiusPropsService: RadiusPropsService<SeedRadiusProps>;
29
- fillPropsService: FillPropsService<FrameFillProps>;
30
- strokePropsService: StrokePropsService<SeedFrameStrokeProps>;
31
- }
32
-
33
- export function createSeedFrameService({
34
- containerLayoutPropsService,
35
- selfLayoutPropsService,
36
- radiusPropsService,
37
- fillPropsService,
38
- strokePropsService,
39
- }: SeedFrameServiceDeps): FrameService {
40
- function inferLayoutComponent(props: SeedContainerLayoutProps) {
41
- if (
42
- props.flexDirection === "row" &&
43
- props.alignItems === "flexStart" &&
44
- props.justifyContent === "flexStart" &&
45
- props.flexWrap === "wrap"
46
- ) {
47
- return "Inline";
48
- }
49
-
50
- if (
51
- props.flexDirection === "row" &&
52
- props.justifyContent === "flexStart" &&
53
- props.flexWrap === "nowrap"
54
- ) {
55
- return "Columns";
56
- }
57
-
58
- if (props.flexDirection === "column") {
59
- return "Stack";
60
- }
61
-
62
- return "Flex";
63
- }
64
-
65
- const transform = defineElementTransformer(
66
- (node: NormalizedFrameNode | NormalizedInstanceNode | NormalizedComponentNode, traverse) => {
67
- const children = node.children;
68
-
69
- const props = {
70
- ...radiusPropsService.transform(node, traverse),
71
- ...containerLayoutPropsService.transform(node, traverse),
72
- ...selfLayoutPropsService.transform(node, traverse),
73
- ...fillPropsService.transform(node, traverse),
74
- ...strokePropsService.transform(node, traverse),
75
- };
76
-
77
- const layoutComponent = inferLayoutComponent(props);
78
-
79
- if (layoutComponent === "Stack") {
80
- const { flexDirection, ...rest } = props;
81
-
82
- return createElement("Stack", rest, children.map(traverse));
83
- }
84
-
85
- if (layoutComponent === "Inline") {
86
- const { flexDirection, flexWrap, alignItems, justifyContent, ...rest } = props;
87
-
88
- return createElement("Inline", rest, children.map(traverse));
89
- }
90
-
91
- if (layoutComponent === "Columns") {
92
- const { flexDirection, flexWrap, justifyContent, ...rest } = props;
93
-
94
- const childrenResult = children.map(traverse);
95
-
96
- return createElement(
97
- "Columns",
98
- rest,
99
- childrenResult.map((child) => createElement("Column", {}, child)),
100
- );
101
- }
102
- },
103
- );
104
-
105
- return {
106
- transform,
107
- };
108
- }
@@ -1,22 +0,0 @@
1
- export * from "./codegen.service";
2
- export * from "./figma-component.service";
3
- export * from "./frame.service";
4
- export * from "./icon.interface";
5
- export * from "./icon.repository";
6
- export * from "./icon.service";
7
- export * from "./instance.service";
8
- export * from "./props/container-layout-props.service";
9
- export * from "./props/fill-props.service";
10
- export * from "./props/radius-props.service";
11
- export * from "./props/self-layout-props.service";
12
- export * from "./props/stroke-props.service";
13
- export * from "./props/type-style-props.service";
14
- export * from "./rectangle.service";
15
- export * from "./seed-component";
16
- export * from "./style.interface";
17
- export * from "./style.repository";
18
- export * from "./style.service";
19
- export * from "./text.service";
20
- export * from "./variable.interface";
21
- export * from "./variable.repository";
22
- export * from "./variable.service";