@seed-design/figma 0.0.20 → 0.0.22

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 (87) hide show
  1. package/lib/codegen/index.cjs +8019 -0
  2. package/lib/codegen/index.d.ts +1827 -0
  3. package/lib/codegen/index.js +7989 -0
  4. package/lib/codegen/targets/react/index.cjs +12205 -0
  5. package/lib/codegen/targets/react/index.d.ts +270 -0
  6. package/lib/codegen/targets/react/index.js +12187 -0
  7. package/lib/index.cjs +86 -2741
  8. package/lib/index.d.ts +18 -1933
  9. package/lib/index.js +68 -2715
  10. package/package.json +18 -9
  11. package/src/codegen/{targets/react/component/properties.type.ts → component-properties.ts} +43 -43
  12. package/src/codegen/core/codegen.ts +24 -9
  13. package/src/codegen/core/{component.ts → component-handler.ts} +3 -3
  14. package/src/codegen/core/component-type-helper.ts +35 -0
  15. package/src/codegen/core/context.ts +20 -0
  16. package/src/codegen/core/index.ts +16 -14
  17. package/src/codegen/core/infer-layout.test.ts +17 -16
  18. package/src/codegen/core/infer-layout.ts +1 -1
  19. package/src/codegen/core/{props.ts → props-converter.ts} +10 -13
  20. package/src/codegen/core/{value.ts → value-resolver.ts} +90 -52
  21. package/src/codegen/default-services.ts +44 -0
  22. package/src/codegen/index.ts +1 -44
  23. package/src/codegen/targets/figma/frame.ts +8 -8
  24. package/src/codegen/targets/figma/index.ts +1 -1
  25. package/src/codegen/targets/figma/pipeline.ts +71 -0
  26. package/src/codegen/targets/figma/props.ts +59 -70
  27. package/src/codegen/targets/figma/shape.ts +18 -18
  28. package/src/codegen/targets/figma/text.ts +6 -6
  29. package/src/codegen/targets/figma/value-resolver.ts +22 -0
  30. package/src/codegen/targets/react/component/deps.interface.ts +5 -4
  31. package/src/codegen/targets/react/component/{transformers → handlers}/action-button.ts +8 -14
  32. package/src/codegen/targets/react/component/{transformers → handlers}/action-chip.ts +10 -20
  33. package/src/codegen/targets/react/component/{transformers → handlers}/action-sheet.ts +13 -10
  34. package/src/codegen/targets/react/component/{transformers → handlers}/app-bar.ts +28 -36
  35. package/src/codegen/targets/react/component/handlers/avatar-stack.ts +29 -0
  36. package/src/codegen/targets/react/component/{transformers → handlers}/avatar.ts +12 -9
  37. package/src/codegen/targets/react/component/handlers/badge.ts +18 -0
  38. package/src/codegen/targets/react/component/{transformers → handlers}/callout.ts +6 -8
  39. package/src/codegen/targets/react/component/{transformers → handlers}/checkbox.ts +5 -5
  40. package/src/codegen/targets/react/component/{transformers → handlers}/chip-tabs.ts +10 -10
  41. package/src/codegen/targets/react/component/{transformers → handlers}/control-chip.ts +10 -20
  42. package/src/codegen/targets/react/component/{transformers → handlers}/error-state.ts +9 -9
  43. package/src/codegen/targets/react/component/{transformers → handlers}/extended-action-sheet.ts +16 -18
  44. package/src/codegen/targets/react/component/{transformers → handlers}/extended-fab.ts +6 -6
  45. package/src/codegen/targets/react/component/handlers/fab.ts +18 -0
  46. package/src/codegen/targets/react/component/{transformers → handlers}/help-bubble.ts +5 -5
  47. package/src/codegen/targets/react/component/{transformers → handlers}/identity-placeholder.ts +5 -5
  48. package/src/codegen/targets/react/component/{transformers → handlers}/inline-banner.ts +7 -10
  49. package/src/codegen/targets/react/component/{transformers → handlers}/manner-temp-badge.ts +5 -5
  50. package/src/codegen/targets/react/component/{transformers → handlers}/multiline-text-field.ts +5 -5
  51. package/src/codegen/targets/react/component/{transformers → handlers}/progress-circle.ts +5 -5
  52. package/src/codegen/targets/react/component/{transformers → handlers}/reaction-button.ts +6 -6
  53. package/src/codegen/targets/react/component/{transformers → handlers}/segmented-control.ts +10 -10
  54. package/src/codegen/targets/react/component/{transformers → handlers}/select-box.ts +10 -10
  55. package/src/codegen/targets/react/component/handlers/skeleton.ts +25 -0
  56. package/src/codegen/targets/react/component/{transformers → handlers}/snackbar.ts +5 -5
  57. package/src/codegen/targets/react/component/{transformers → handlers}/switch.ts +5 -5
  58. package/src/codegen/targets/react/component/{transformers → handlers}/tabs.ts +15 -15
  59. package/src/codegen/targets/react/component/{transformers → handlers}/text-button.ts +7 -13
  60. package/src/codegen/targets/react/component/{transformers → handlers}/text-field.ts +9 -9
  61. package/src/codegen/targets/react/component/{transformers → handlers}/toggle-button.ts +7 -11
  62. package/src/codegen/targets/react/component/index.ts +79 -75
  63. package/src/codegen/targets/react/frame.ts +8 -8
  64. package/src/codegen/targets/react/icon.ts +50 -0
  65. package/src/codegen/targets/react/index.ts +1 -1
  66. package/src/codegen/targets/react/instance.ts +19 -50
  67. package/src/codegen/targets/react/pipeline.ts +108 -0
  68. package/src/codegen/targets/react/props.ts +95 -73
  69. package/src/codegen/targets/react/shape.ts +5 -5
  70. package/src/codegen/targets/react/text.ts +6 -6
  71. package/src/codegen/targets/react/value-resolver.ts +35 -0
  72. package/src/entities/icon.repository.ts +2 -2
  73. package/src/entities/icon.service.ts +9 -20
  74. package/src/entities/style.service.ts +5 -17
  75. package/src/entities/variable.service.ts +36 -68
  76. package/src/normalizer/from-plugin.ts +3 -0
  77. package/src/normalizer/from-rest.ts +6 -0
  78. package/src/normalizer/types.ts +4 -1
  79. package/src/utils/figma-variable.ts +39 -3
  80. package/src/codegen/core/component.types.ts +0 -29
  81. package/src/codegen/targets/figma/context.ts +0 -139
  82. package/src/codegen/targets/react/component/transformers/avatar-stack.ts +0 -29
  83. package/src/codegen/targets/react/component/transformers/badge.ts +0 -21
  84. package/src/codegen/targets/react/component/transformers/fab.ts +0 -18
  85. package/src/codegen/targets/react/component/transformers/skeleton.ts +0 -51
  86. package/src/codegen/targets/react/context.ts +0 -176
  87. /package/src/codegen/core/{element.ts → element-transformer.ts} +0 -0
@@ -9,14 +9,14 @@ import {
9
9
  defineElementTransformer,
10
10
  type ElementTransformer,
11
11
  } from "../../core";
12
- import type { ContainerLayoutProps, PropsTransformers } from "./props";
12
+ import type { ContainerLayoutProps, PropsConverters } from "./props";
13
13
 
14
14
  export interface FrameTransformerDeps {
15
- propsTransformers: PropsTransformers;
15
+ propsConverters: PropsConverters;
16
16
  }
17
17
 
18
18
  export function createFrameTransformer({
19
- propsTransformers,
19
+ propsConverters,
20
20
  }: FrameTransformerDeps): ElementTransformer<
21
21
  NormalizedFrameNode | NormalizedInstanceNode | NormalizedComponentNode
22
22
  > {
@@ -39,11 +39,11 @@ export function createFrameTransformer({
39
39
  const isFlex = node.layoutMode === "HORIZONTAL" || node.layoutMode === "VERTICAL";
40
40
 
41
41
  const props = {
42
- ...propsTransformers.radius(node, traverse),
43
- ...(isFlex ? propsTransformers.containerLayout(node, traverse) : {}),
44
- ...propsTransformers.selfLayout(node, traverse),
45
- ...propsTransformers.frameFill(node, traverse),
46
- ...propsTransformers.stroke(node, traverse),
42
+ ...propsConverters.radius(node),
43
+ ...(isFlex ? propsConverters.containerLayout(node) : {}),
44
+ ...propsConverters.selfLayout(node),
45
+ ...propsConverters.frameFill(node),
46
+ ...propsConverters.stroke(node),
47
47
  };
48
48
 
49
49
  const isStretch = props.align === undefined || props.align === "stretch";
@@ -0,0 +1,50 @@
1
+ import type { IconService } from "@/entities";
2
+ import { pascalCase } from "change-case";
3
+ import { type ElementNode, createElement } from "../../core";
4
+
5
+ export interface IconHandler {
6
+ isIconInstance: (node: { componentKey: string }) => boolean;
7
+ transform: (node: { componentKey: string }) => ElementNode;
8
+ }
9
+
10
+ export interface IconHandlerDeps {
11
+ iconService: IconService;
12
+ iconNameFormatter?: (props: { name: string; weight?: string }) => string;
13
+ }
14
+
15
+ const defaultIconNameFormatter = ({ name, weight }: { name: string; weight?: string }) =>
16
+ pascalCase(`${name}${weight ? weight : ""}`);
17
+
18
+ export function createIconHandler({
19
+ iconService,
20
+ iconNameFormatter = defaultIconNameFormatter,
21
+ }: IconHandlerDeps): IconHandler {
22
+ function isIconInstance(node: { componentKey: string }): boolean {
23
+ const key = node.componentKey;
24
+
25
+ if (!key) {
26
+ return false;
27
+ }
28
+
29
+ return iconService.isAvailable(key);
30
+ }
31
+
32
+ function transform(node: { componentKey: string }): ElementNode {
33
+ const key = node.componentKey;
34
+ const iconData = iconService.getOne(key);
35
+ if (!iconData) {
36
+ return createElement("UnknownIcon");
37
+ }
38
+
39
+ const { name, weight } = iconData;
40
+
41
+ const tagName = iconNameFormatter({ name, weight });
42
+
43
+ return createElement(tagName);
44
+ }
45
+
46
+ return {
47
+ isIconInstance,
48
+ transform,
49
+ };
50
+ }
@@ -4,4 +4,4 @@ export * from "./frame";
4
4
  export * from "./instance";
5
5
  export * from "./text";
6
6
  export * from "./component";
7
- export * from "./context";
7
+ export * from "./pipeline";
@@ -1,74 +1,43 @@
1
- import type { IconService } from "@/entities";
2
- import type { NormalizedFrameTrait, NormalizedInstanceNode } from "@/normalizer";
1
+ import type { NormalizedInstanceNode } from "@/normalizer";
3
2
  import {
4
3
  createElement,
5
4
  defineElementTransformer,
6
- definePropsTransformer,
7
- type ComponentTransformer,
5
+ type ComponentHandler,
8
6
  type ElementTransformer,
9
7
  } from "../../core";
10
- import type { PropsTransformers } from "./props";
8
+ import type { IconHandler } from "./icon";
9
+ import type { PropsConverters } from "./props";
11
10
 
12
11
  export interface InstanceTransformerDeps {
13
- iconService?: IconService;
14
- ignoredComponentKeys?: Set<string>;
15
- propsTransformers: PropsTransformers;
16
- componentTransformers: Record<string, ComponentTransformer>;
12
+ iconHandler?: IconHandler;
13
+ propsConverters: PropsConverters;
14
+ componentHandlers: Record<string, ComponentHandler>;
17
15
  frameTransformer: ElementTransformer<NormalizedInstanceNode>;
18
16
  }
19
17
 
20
18
  export function createInstanceTransformer({
21
- iconService,
22
- ignoredComponentKeys,
23
- propsTransformers,
24
- componentTransformers,
19
+ iconHandler,
20
+ propsConverters,
21
+ componentHandlers,
25
22
  frameTransformer,
26
23
  }: InstanceTransformerDeps): ElementTransformer<NormalizedInstanceNode> {
27
- const transformIconColorProps = definePropsTransformer((node: NormalizedFrameTrait, traverse) => {
28
- if (node.children.length === 0) {
29
- throw new Error("Node has no children");
30
- }
31
-
32
- const vectors = node.children.filter(
33
- (child) => child.type === "VECTOR" || child.type === "BOOLEAN_OPERATION",
34
- );
35
-
36
- const colorProps = vectors.map((vector) => propsTransformers.shapeFill(vector, traverse));
37
-
38
- const fills = new Set(
39
- colorProps.map((props) => props.color).filter((color) => color !== undefined),
40
- );
41
-
42
- // If there are more than 1 color, colors are likely pre-defined in the icon component; we should ignore the color prop.
43
- if (fills.size > 1) {
44
- return {};
45
- }
46
-
47
- return { color: fills.values().next().value };
48
- });
49
-
50
24
  const transform = defineElementTransformer((node: NormalizedInstanceNode, traverse) => {
51
25
  const { componentKey, componentSetKey } = node;
52
26
 
53
- if (ignoredComponentKeys?.has(componentKey)) {
54
- return undefined;
55
- }
56
-
57
- if (iconService?.isIconComponent(componentKey)) {
58
- const tagName = iconService.createIconTagName(componentKey);
27
+ if (iconHandler?.isIconInstance(node)) {
59
28
  const props = {
60
- ...propsTransformers.iconSelfLayout(node, traverse),
61
- ...transformIconColorProps(node, traverse),
29
+ ...propsConverters.iconSelfLayout(node),
30
+ ...propsConverters.vectorChildrenFill(node),
62
31
  };
63
- return createElement("Icon", { svg: createElement(tagName), ...props });
32
+ return createElement("Icon", { svg: iconHandler.transform(node), ...props });
64
33
  }
65
34
 
66
- const componentTransformer = componentSetKey
67
- ? componentTransformers[componentSetKey]
68
- : componentTransformers[componentKey];
35
+ const componentHandler = componentSetKey
36
+ ? componentHandlers[componentSetKey]
37
+ : componentHandlers[componentKey];
69
38
 
70
- if (componentTransformer) {
71
- return componentTransformer.transform(node);
39
+ if (componentHandler) {
40
+ return componentHandler.transform(node);
72
41
  }
73
42
 
74
43
  return frameTransformer(node, traverse);
@@ -0,0 +1,108 @@
1
+ import { createCodeGenerator } from "@/codegen/core";
2
+ import { iconService } from "@/codegen/default-services";
3
+ import {
4
+ type UnboundComponentHandler,
5
+ bindComponentHandler,
6
+ unboundSeedComponentHandlers,
7
+ } from "./component";
8
+ import { createFrameTransformer } from "./frame";
9
+ import { createIconHandler } from "./icon";
10
+ import { createInstanceTransformer } from "./instance";
11
+ import {
12
+ createContainerLayoutPropsConverter,
13
+ createFrameFillPropsConverter,
14
+ createIconSelfLayoutPropsConverter,
15
+ createRadiusPropsConverter,
16
+ createSelfLayoutPropsConverter,
17
+ createShapeFillPropsConverter,
18
+ createStrokePropsConverter,
19
+ createTextFillPropsConverter,
20
+ createTypeStylePropsConverter,
21
+ createVectorChildrenFillPropsConverter,
22
+ } from "./props";
23
+ import {
24
+ createBooleanOperationTransformer,
25
+ createRectangleTransformer,
26
+ createVectorTransformer,
27
+ } from "./shape";
28
+ import { createTextTransformer } from "./text";
29
+ import { valueResolver } from "./value-resolver";
30
+
31
+ export interface CreatePipelineConfig {
32
+ extend?: {
33
+ componentHandlers?: Array<UnboundComponentHandler<any>>;
34
+ };
35
+ }
36
+
37
+ const iconHandler = createIconHandler({
38
+ iconService,
39
+ });
40
+
41
+ export function createPipeline(options: CreatePipelineConfig = {}) {
42
+ const { extend = {} } = options;
43
+
44
+ const containerLayoutPropsConverter = createContainerLayoutPropsConverter(valueResolver);
45
+ const selfLayoutPropsConverter = createSelfLayoutPropsConverter(valueResolver);
46
+ const iconSelfLayoutPropsConverter = createIconSelfLayoutPropsConverter(valueResolver);
47
+ const frameFillPropsConverter = createFrameFillPropsConverter(valueResolver);
48
+ const shapeFillPropsConverter = createShapeFillPropsConverter(valueResolver);
49
+ const textFillPropsConverter = createTextFillPropsConverter(valueResolver);
50
+ const vectorChildrenFillPropsConverter = createVectorChildrenFillPropsConverter(valueResolver);
51
+ const radiusPropsConverter = createRadiusPropsConverter(valueResolver);
52
+ const strokePropsConverter = createStrokePropsConverter(valueResolver);
53
+ const typeStylePropsConverter = createTypeStylePropsConverter({
54
+ valueResolver,
55
+ });
56
+ const propsConverters = {
57
+ containerLayout: containerLayoutPropsConverter,
58
+ selfLayout: selfLayoutPropsConverter,
59
+ iconSelfLayout: iconSelfLayoutPropsConverter,
60
+ frameFill: frameFillPropsConverter,
61
+ shapeFill: shapeFillPropsConverter,
62
+ textFill: textFillPropsConverter,
63
+ vectorChildrenFill: vectorChildrenFillPropsConverter,
64
+ radius: radiusPropsConverter,
65
+ stroke: strokePropsConverter,
66
+ typeStyle: typeStylePropsConverter,
67
+ };
68
+
69
+ const componentHandlers = Object.fromEntries(
70
+ [...unboundSeedComponentHandlers, ...(extend.componentHandlers ?? [])]
71
+ .map((h) =>
72
+ bindComponentHandler(h, {
73
+ valueResolver,
74
+ iconHandler,
75
+ }),
76
+ )
77
+ .map((t) => [t.key, t]),
78
+ );
79
+
80
+ const frameTransformer = createFrameTransformer({
81
+ propsConverters,
82
+ });
83
+ const instanceTransformer = createInstanceTransformer({
84
+ iconHandler,
85
+ propsConverters,
86
+ componentHandlers,
87
+ frameTransformer,
88
+ });
89
+ const textTransformer = createTextTransformer({
90
+ propsConverters,
91
+ });
92
+ const rectangleTransformer = createRectangleTransformer({
93
+ propsConverters,
94
+ });
95
+ const vectorTransformer = createVectorTransformer();
96
+ const booleanOperationTransformer = createBooleanOperationTransformer();
97
+
98
+ const codeGenerator = createCodeGenerator({
99
+ frameTransformer,
100
+ textTransformer,
101
+ rectangleTransformer,
102
+ instanceTransformer,
103
+ vectorTransformer,
104
+ booleanOperationTransformer,
105
+ });
106
+
107
+ return codeGenerator;
108
+ }
@@ -1,10 +1,4 @@
1
- import {
2
- createPropsTransformer,
3
- definePropsTransformer,
4
- type PropsTransformer,
5
- type ValueTransformer,
6
- } from "@/codegen/core";
7
- import type { StyleService } from "@/entities";
1
+ import { createPropsConverter, definePropsConverter, type PropsConverter } from "@/codegen/core";
8
2
  import type {
9
3
  NormalizedCornerTrait,
10
4
  NormalizedHasChildrenTrait,
@@ -15,17 +9,19 @@ import type {
15
9
  NormalizedTypePropertiesTrait,
16
10
  } from "@/normalizer";
17
11
  import { match } from "ts-pattern";
18
-
19
- export interface PropsTransformers {
20
- containerLayout: PropsTransformer<ContainerLayoutTrait, ContainerLayoutProps>;
21
- selfLayout: PropsTransformer<SelfLayoutTrait, SelfLayoutProps>;
22
- iconSelfLayout: PropsTransformer<SelfLayoutTrait, IconSelfLayoutProps>;
23
- radius: PropsTransformer<RadiusTrait, RadiusProps>;
24
- frameFill: PropsTransformer<FillTrait, FrameFillProps>;
25
- shapeFill: PropsTransformer<FillTrait, ShapeFillProps>;
26
- textFill: PropsTransformer<FillTrait, TextFillProps>;
27
- stroke: PropsTransformer<StrokeTrait, StrokeProps>;
28
- typeStyle: PropsTransformer<TypeStyleTrait, TypeStyleProps>;
12
+ import type { ReactValueResolver } from "./value-resolver";
13
+
14
+ export interface PropsConverters {
15
+ containerLayout: PropsConverter<ContainerLayoutTrait, ContainerLayoutProps>;
16
+ selfLayout: PropsConverter<SelfLayoutTrait, SelfLayoutProps>;
17
+ iconSelfLayout: PropsConverter<SelfLayoutTrait, IconSelfLayoutProps>;
18
+ radius: PropsConverter<RadiusTrait, RadiusProps>;
19
+ frameFill: PropsConverter<FillTrait, FrameFillProps>;
20
+ shapeFill: PropsConverter<FillTrait, ShapeFillProps>;
21
+ textFill: PropsConverter<FillTrait, TextFillProps>;
22
+ vectorChildrenFill: PropsConverter<ContainerLayoutTrait, VectorChildrenFillProps>;
23
+ stroke: PropsConverter<StrokeTrait, StrokeProps>;
24
+ typeStyle: PropsConverter<TypeStyleTrait, TypeStyleProps>;
29
25
  }
30
26
 
31
27
  export type ContainerLayoutTrait = NormalizedHasFramePropertiesTrait &
@@ -58,12 +54,10 @@ export interface ContainerLayoutProps {
58
54
  p?: string | 0;
59
55
  }
60
56
 
61
- type ReactValueTransformer = ValueTransformer<string, string, string, number>;
62
-
63
- export function createContainerLayoutPropsTransformer(
64
- valueTransformer: ReactValueTransformer,
65
- ): PropsTransformer<ContainerLayoutTrait, ContainerLayoutProps> {
66
- return createPropsTransformer({
57
+ export function createContainerLayoutPropsConverter(
58
+ valueResolver: ReactValueResolver,
59
+ ): PropsConverter<ContainerLayoutTrait, ContainerLayoutProps> {
60
+ return createPropsConverter({
67
61
  _types: {
68
62
  trait: {} as ContainerLayoutTrait,
69
63
  props: {} as ContainerLayoutProps,
@@ -120,12 +114,12 @@ export function createContainerLayoutPropsTransformer(
120
114
  return undefined;
121
115
  }
122
116
 
123
- return valueTransformer.getFormattedValue.itemSpacing(node);
117
+ return valueResolver.getFormattedValue.itemSpacing(node);
124
118
  },
125
- pt: (node) => valueTransformer.getFormattedValue.paddingTop(node),
126
- pb: (node) => valueTransformer.getFormattedValue.paddingBottom(node),
127
- pl: (node) => valueTransformer.getFormattedValue.paddingLeft(node),
128
- pr: (node) => valueTransformer.getFormattedValue.paddingRight(node),
119
+ pt: (node) => valueResolver.getFormattedValue.paddingTop(node),
120
+ pb: (node) => valueResolver.getFormattedValue.paddingBottom(node),
121
+ pl: (node) => valueResolver.getFormattedValue.paddingLeft(node),
122
+ pr: (node) => valueResolver.getFormattedValue.paddingRight(node),
129
123
  },
130
124
  shorthands: {
131
125
  p: ["pt", "pb", "pl", "pr"],
@@ -159,10 +153,10 @@ export interface SelfLayoutProps {
159
153
  maxHeight?: string | number;
160
154
  }
161
155
 
162
- export function createSelfLayoutPropsTransformer(
163
- valueTransformer: ReactValueTransformer,
164
- ): PropsTransformer<SelfLayoutTrait, SelfLayoutProps> {
165
- return createPropsTransformer({
156
+ export function createSelfLayoutPropsConverter(
157
+ valueResolver: ReactValueResolver,
158
+ ): PropsConverter<SelfLayoutTrait, SelfLayoutProps> {
159
+ return createPropsConverter({
166
160
  _types: {
167
161
  trait: {} as SelfLayoutTrait,
168
162
  props: {} as SelfLayoutProps,
@@ -180,27 +174,27 @@ export function createSelfLayoutPropsTransformer(
180
174
  .exhaustive(),
181
175
  height: (node) =>
182
176
  node.layoutSizingVertical === "FIXED"
183
- ? valueTransformer.getFormattedValue.height(node)
177
+ ? valueResolver.getFormattedValue.height(node)
184
178
  : undefined,
185
179
  width: (node) =>
186
180
  node.layoutSizingHorizontal === "FIXED"
187
- ? valueTransformer.getFormattedValue.width(node)
181
+ ? valueResolver.getFormattedValue.width(node)
188
182
  : undefined,
189
183
  minHeight: (node) =>
190
184
  node.layoutSizingVertical === "HUG"
191
- ? valueTransformer.getFormattedValue.minHeight(node)
185
+ ? valueResolver.getFormattedValue.minHeight(node)
192
186
  : undefined,
193
187
  maxHeight: (node) =>
194
188
  node.layoutSizingVertical === "HUG"
195
- ? valueTransformer.getFormattedValue.maxHeight(node)
189
+ ? valueResolver.getFormattedValue.maxHeight(node)
196
190
  : undefined,
197
191
  minWidth: (node) =>
198
192
  node.layoutSizingHorizontal === "HUG"
199
- ? valueTransformer.getFormattedValue.minWidth(node)
193
+ ? valueResolver.getFormattedValue.minWidth(node)
200
194
  : undefined,
201
195
  maxWidth: (node) =>
202
196
  node.layoutSizingHorizontal === "HUG"
203
- ? valueTransformer.getFormattedValue.maxWidth(node)
197
+ ? valueResolver.getFormattedValue.maxWidth(node)
204
198
  : undefined,
205
199
  },
206
200
  defaults: {
@@ -213,14 +207,14 @@ export interface IconSelfLayoutProps {
213
207
  size?: string | number;
214
208
  }
215
209
 
216
- export function createIconSelfLayoutPropsTransformer(valueTransformer: ReactValueTransformer) {
217
- return createPropsTransformer({
210
+ export function createIconSelfLayoutPropsConverter(valueResolver: ReactValueResolver) {
211
+ return createPropsConverter({
218
212
  _types: {
219
213
  trait: {} as SelfLayoutTrait,
220
214
  props: {} as IconSelfLayoutProps,
221
215
  },
222
216
  handlers: {
223
- size: (node) => valueTransformer.getFormattedValue.width(node),
217
+ size: (node) => valueResolver.getFormattedValue.width(node),
224
218
  },
225
219
  });
226
220
  }
@@ -233,17 +227,17 @@ export interface RadiusProps {
233
227
  borderBottomRightRadius?: string | 0;
234
228
  }
235
229
 
236
- export function createRadiusPropsTransformer(valueTransformer: ReactValueTransformer) {
237
- return createPropsTransformer({
230
+ export function createRadiusPropsConverter(valueResolver: ReactValueResolver) {
231
+ return createPropsConverter({
238
232
  _types: {
239
233
  trait: {} as RadiusTrait,
240
234
  props: {} as RadiusProps,
241
235
  },
242
236
  handlers: {
243
- borderTopLeftRadius: (node) => valueTransformer.getFormattedValue.topLeftRadius(node),
244
- borderTopRightRadius: (node) => valueTransformer.getFormattedValue.topRightRadius(node),
245
- borderBottomLeftRadius: (node) => valueTransformer.getFormattedValue.bottomLeftRadius(node),
246
- borderBottomRightRadius: (node) => valueTransformer.getFormattedValue.bottomRightRadius(node),
237
+ borderTopLeftRadius: (node) => valueResolver.getFormattedValue.topLeftRadius(node),
238
+ borderTopRightRadius: (node) => valueResolver.getFormattedValue.topRightRadius(node),
239
+ borderBottomLeftRadius: (node) => valueResolver.getFormattedValue.bottomLeftRadius(node),
240
+ borderBottomRightRadius: (node) => valueResolver.getFormattedValue.bottomRightRadius(node),
247
241
  },
248
242
  shorthands: {
249
243
  borderRadius: [
@@ -271,15 +265,13 @@ export interface TypeStyleProps {
271
265
  maxLines?: number;
272
266
  }
273
267
 
274
- export function createTypeStylePropsTransformer({
275
- valueTransformer,
276
- styleService,
268
+ export function createTypeStylePropsConverter({
269
+ valueResolver,
277
270
  }: {
278
- valueTransformer: ReactValueTransformer;
279
- styleService: StyleService;
280
- }): PropsTransformer<TypeStyleTrait, TypeStyleProps> {
281
- return definePropsTransformer((node) => {
282
- const styleName = node.textStyleKey ? styleService.getStyleName(node.textStyleKey) : undefined;
271
+ valueResolver: ReactValueResolver;
272
+ }): PropsConverter<TypeStyleTrait, TypeStyleProps> {
273
+ return definePropsConverter((node) => {
274
+ const styleName = valueResolver.getTextStyleValue(node);
283
275
  const maxLines =
284
276
  node.style.textTruncation === "ENDING" ? (node.style.maxLines ?? undefined) : undefined;
285
277
 
@@ -291,9 +283,9 @@ export function createTypeStylePropsTransformer({
291
283
  }
292
284
 
293
285
  return {
294
- fontSize: valueTransformer.getFormattedValue.fontSize(node),
295
- fontWeight: valueTransformer.getFormattedValue.fontWeight(node),
296
- lineHeight: valueTransformer.getFormattedValue.lineHeight(node),
286
+ fontSize: valueResolver.getFormattedValue.fontSize(node),
287
+ fontWeight: valueResolver.getFormattedValue.fontWeight(node),
288
+ lineHeight: valueResolver.getFormattedValue.lineHeight(node),
297
289
  maxLines,
298
290
  };
299
291
  });
@@ -303,9 +295,9 @@ export interface FrameFillProps {
303
295
  bg?: string;
304
296
  }
305
297
 
306
- export function createFrameFillPropsTransformer(valueTransformer: ReactValueTransformer) {
307
- return definePropsTransformer<FillTrait, FrameFillProps>((node) => {
308
- const bg = valueTransformer.getFormattedValue.frameFill(node);
298
+ export function createFrameFillPropsConverter(valueResolver: ReactValueResolver) {
299
+ return definePropsConverter<FillTrait, FrameFillProps>((node) => {
300
+ const bg = valueResolver.getFormattedValue.frameFill(node);
309
301
 
310
302
  return {
311
303
  bg,
@@ -317,9 +309,9 @@ export interface ShapeFillProps {
317
309
  color?: string;
318
310
  }
319
311
 
320
- export function createShapeFillPropsTransformer(valueTransformer: ReactValueTransformer) {
321
- return definePropsTransformer<FillTrait, ShapeFillProps>((node) => {
322
- const color = valueTransformer.getFormattedValue.shapeFill(node);
312
+ export function createShapeFillPropsConverter(valueResolver: ReactValueResolver) {
313
+ return definePropsConverter<FillTrait, ShapeFillProps>((node) => {
314
+ const color = valueResolver.getFormattedValue.shapeFill(node);
323
315
 
324
316
  return {
325
317
  color,
@@ -331,9 +323,9 @@ export interface TextFillProps {
331
323
  color?: string;
332
324
  }
333
325
 
334
- export function createTextFillPropsTransformer(valueTransformer: ReactValueTransformer) {
335
- return definePropsTransformer<FillTrait, TextFillProps>((node) => {
336
- const color = valueTransformer.getFormattedValue.textFill(node);
326
+ export function createTextFillPropsConverter(valueResolver: ReactValueResolver) {
327
+ return definePropsConverter<FillTrait, TextFillProps>((node) => {
328
+ const color = valueResolver.getFormattedValue.textFill(node);
337
329
 
338
330
  return {
339
331
  color,
@@ -341,16 +333,46 @@ export function createTextFillPropsTransformer(valueTransformer: ReactValueTrans
341
333
  });
342
334
  }
343
335
 
336
+ export interface VectorChildrenFillProps {
337
+ color?: string;
338
+ }
339
+
340
+ export function createVectorChildrenFillPropsConverter(valueResolver: ReactValueResolver) {
341
+ return definePropsConverter<ContainerLayoutTrait, VectorChildrenFillProps>((node) => {
342
+ if (node.children.length === 0) {
343
+ console.warn(
344
+ `createVectorChildrenFillPropsConverter: Node has no children. Name:${node.name}, ID:${node.id}`,
345
+ );
346
+ return {};
347
+ }
348
+
349
+ const vectors = node.children.filter(
350
+ (child) => child.type === "VECTOR" || child.type === "BOOLEAN_OPERATION",
351
+ );
352
+
353
+ const colors = vectors.map((vector) => valueResolver.getFormattedValue.shapeFill(vector));
354
+
355
+ const fills = new Set(colors.filter((color) => color !== undefined));
356
+
357
+ // If there are more than 1 color, colors are likely pre-defined in the icon component; we should ignore the color prop.
358
+ if (fills.size > 1) {
359
+ return {};
360
+ }
361
+
362
+ return { color: fills.values().next().value };
363
+ });
364
+ }
365
+
344
366
  export interface StrokeProps {
345
367
  borderWidth?: number;
346
368
  borderColor?: string;
347
369
  }
348
370
 
349
- export function createStrokePropsTransformer(
350
- valueTransformer: ReactValueTransformer,
351
- ): PropsTransformer<StrokeTrait, StrokeProps> {
352
- return definePropsTransformer((node) => {
353
- const borderColor = valueTransformer.getFormattedValue.stroke(node);
371
+ export function createStrokePropsConverter(
372
+ valueResolver: ReactValueResolver,
373
+ ): PropsConverter<StrokeTrait, StrokeProps> {
374
+ return definePropsConverter((node) => {
375
+ const borderColor = valueResolver.getFormattedValue.stroke(node);
354
376
  const borderWidth = borderColor ? node.strokeWeight : undefined;
355
377
 
356
378
  return {
@@ -4,19 +4,19 @@ import type {
4
4
  NormalizedVectorNode,
5
5
  } from "@/normalizer";
6
6
  import { createElement, defineElementTransformer, type ElementTransformer } from "../../core";
7
- import type { PropsTransformers } from "./props";
7
+ import type { PropsConverters } from "./props";
8
8
 
9
9
  export interface RectangleTransformerDeps {
10
- propsTransformers: PropsTransformers;
10
+ propsConverters: PropsConverters;
11
11
  }
12
12
 
13
13
  export function createRectangleTransformer({
14
- propsTransformers,
14
+ propsConverters,
15
15
  }: RectangleTransformerDeps): ElementTransformer<NormalizedRectangleNode> {
16
- return defineElementTransformer((node: NormalizedRectangleNode, traverse) => {
16
+ return defineElementTransformer((node: NormalizedRectangleNode) => {
17
17
  return createElement(
18
18
  "Box",
19
- { ...propsTransformers.selfLayout(node, traverse), background: "palette.gray200" },
19
+ { ...propsConverters.selfLayout(node), background: "palette.gray200" },
20
20
  undefined,
21
21
  "Rectangle Node Placeholder",
22
22
  );
@@ -1,20 +1,20 @@
1
1
  import type { NormalizedTextNode } from "@/normalizer";
2
2
  import { compactObject } from "@/utils/common";
3
3
  import { createElement, defineElementTransformer, type ElementTransformer } from "../../core";
4
- import type { PropsTransformers } from "./props";
4
+ import type { PropsConverters } from "./props";
5
5
 
6
6
  export interface TextTransformerDeps {
7
- propsTransformers: PropsTransformers;
7
+ propsConverters: PropsConverters;
8
8
  }
9
9
 
10
10
  export function createTextTransformer({
11
- propsTransformers,
11
+ propsConverters,
12
12
  }: TextTransformerDeps): ElementTransformer<NormalizedTextNode> {
13
- return defineElementTransformer((node: NormalizedTextNode, traverse) => {
13
+ return defineElementTransformer((node: NormalizedTextNode) => {
14
14
  const hasMultipleFills = node.fills.length > 1;
15
15
 
16
- const fillProps = propsTransformers.textFill(node, traverse);
17
- const typeStyleProps = propsTransformers.typeStyle(node, traverse);
16
+ const fillProps = propsConverters.textFill(node);
17
+ const typeStyleProps = propsConverters.typeStyle(node);
18
18
 
19
19
  const props = compactObject({
20
20
  ...typeStyleProps,