@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.
Files changed (181) hide show
  1. package/lib/codegen/index.cjs +23543 -0
  2. package/lib/codegen/index.d.ts +2957 -0
  3. package/lib/codegen/index.d.ts.map +1 -0
  4. package/lib/codegen/index.js +23514 -0
  5. package/lib/codegen/targets/react/index.cjs +31980 -0
  6. package/lib/codegen/targets/react/index.d.ts +308 -0
  7. package/lib/codegen/targets/react/index.d.ts.map +1 -0
  8. package/lib/codegen/targets/react/index.js +31961 -0
  9. package/lib/index.cjs +26905 -0
  10. package/lib/index.d.ts +221 -0
  11. package/lib/index.d.ts.map +1 -0
  12. package/lib/index.js +26884 -0
  13. package/package.json +56 -0
  14. package/src/codegen/component-properties.archive.ts +1019 -0
  15. package/src/codegen/component-properties.ts +369 -0
  16. package/src/codegen/core/codegen.ts +112 -0
  17. package/src/codegen/core/component-handler.ts +23 -0
  18. package/src/codegen/core/component-type-helper.ts +35 -0
  19. package/src/codegen/core/element-transformer.ts +13 -0
  20. package/src/codegen/core/index.ts +19 -0
  21. package/src/codegen/core/infer-layout.test.ts +286 -0
  22. package/src/codegen/core/infer-layout.ts +416 -0
  23. package/src/codegen/core/jsx.ts +174 -0
  24. package/src/codegen/core/props-converter.ts +78 -0
  25. package/src/codegen/core/value-resolver.ts +381 -0
  26. package/src/codegen/default-services.ts +44 -0
  27. package/src/codegen/index.ts +3 -0
  28. package/src/codegen/skip-components.ts +7 -0
  29. package/src/codegen/targets/figma/frame.ts +38 -0
  30. package/src/codegen/targets/figma/index.ts +6 -0
  31. package/src/codegen/targets/figma/instance.ts +36 -0
  32. package/src/codegen/targets/figma/pipeline.ts +106 -0
  33. package/src/codegen/targets/figma/props.ts +262 -0
  34. package/src/codegen/targets/figma/shape.ts +65 -0
  35. package/src/codegen/targets/figma/text.ts +30 -0
  36. package/src/codegen/targets/figma/value-resolver.ts +75 -0
  37. package/src/codegen/targets/index.ts +2 -0
  38. package/src/codegen/targets/react/component/deps.interface.ts +7 -0
  39. package/src/codegen/targets/react/component/handlers/action-button.ts +149 -0
  40. package/src/codegen/targets/react/component/handlers/alert-dialog.ts +120 -0
  41. package/src/codegen/targets/react/component/handlers/app-bar.ts +169 -0
  42. package/src/codegen/targets/react/component/handlers/archive/action-button.ts +144 -0
  43. package/src/codegen/targets/react/component/handlers/archive/alert-dialog.ts +122 -0
  44. package/src/codegen/targets/react/component/handlers/archive/app-bar.ts +149 -0
  45. package/src/codegen/targets/react/component/handlers/archive/avatar-stack.ts +35 -0
  46. package/src/codegen/targets/react/component/handlers/archive/avatar.ts +55 -0
  47. package/src/codegen/targets/react/component/handlers/archive/badge.ts +18 -0
  48. package/src/codegen/targets/react/component/handlers/archive/bottom-sheet.ts +70 -0
  49. package/src/codegen/targets/react/component/handlers/archive/callout.ts +88 -0
  50. package/src/codegen/targets/react/component/handlers/archive/checkbox.ts +43 -0
  51. package/src/codegen/targets/react/component/handlers/archive/checkmark.ts +29 -0
  52. package/src/codegen/targets/react/component/handlers/archive/chip.ts +90 -0
  53. package/src/codegen/targets/react/component/handlers/archive/contextual-floating-button.ts +52 -0
  54. package/src/codegen/targets/react/component/handlers/archive/divider.ts +25 -0
  55. package/src/codegen/targets/react/component/handlers/archive/field-button.ts +197 -0
  56. package/src/codegen/targets/react/component/handlers/archive/field.ts +167 -0
  57. package/src/codegen/targets/react/component/handlers/archive/floating-action-button.ts +48 -0
  58. package/src/codegen/targets/react/component/handlers/archive/help-bubble.ts +73 -0
  59. package/src/codegen/targets/react/component/handlers/archive/identity-placeholder.ts +21 -0
  60. package/src/codegen/targets/react/component/handlers/archive/index.ts +40 -0
  61. package/src/codegen/targets/react/component/handlers/archive/legacy-select-box.ts +89 -0
  62. package/src/codegen/targets/react/component/handlers/archive/legacy-text-field.ts +198 -0
  63. package/src/codegen/targets/react/component/handlers/archive/list-header.ts +20 -0
  64. package/src/codegen/targets/react/component/handlers/archive/list-item.ts +162 -0
  65. package/src/codegen/targets/react/component/handlers/archive/manner-temp-badge.ts +21 -0
  66. package/src/codegen/targets/react/component/handlers/archive/manner-temp.ts +18 -0
  67. package/src/codegen/targets/react/component/handlers/archive/menu-sheet.ts +108 -0
  68. package/src/codegen/targets/react/component/handlers/archive/page-banner.ts +101 -0
  69. package/src/codegen/targets/react/component/handlers/archive/progress-circle.ts +55 -0
  70. package/src/codegen/targets/react/component/handlers/archive/radio-group.ts +31 -0
  71. package/src/codegen/targets/react/component/handlers/archive/radiomark.ts +27 -0
  72. package/src/codegen/targets/react/component/handlers/archive/reaction-button.ts +37 -0
  73. package/src/codegen/targets/react/component/handlers/archive/result-section.ts +67 -0
  74. package/src/codegen/targets/react/component/handlers/archive/segmented-control.ts +64 -0
  75. package/src/codegen/targets/react/component/handlers/archive/skeleton.ts +26 -0
  76. package/src/codegen/targets/react/component/handlers/archive/slider.ts +114 -0
  77. package/src/codegen/targets/react/component/handlers/archive/snackbar.ts +25 -0
  78. package/src/codegen/targets/react/component/handlers/archive/switch.ts +39 -0
  79. package/src/codegen/targets/react/component/handlers/archive/switchmark.ts +26 -0
  80. package/src/codegen/targets/react/component/handlers/archive/tabs.ts +297 -0
  81. package/src/codegen/targets/react/component/handlers/archive/tag-group.ts +86 -0
  82. package/src/codegen/targets/react/component/handlers/archive/text-field.ts +264 -0
  83. package/src/codegen/targets/react/component/handlers/archive/toggle-button.ts +43 -0
  84. package/src/codegen/targets/react/component/handlers/avatar-stack.ts +38 -0
  85. package/src/codegen/targets/react/component/handlers/avatar.ts +58 -0
  86. package/src/codegen/targets/react/component/handlers/badge.ts +18 -0
  87. package/src/codegen/targets/react/component/handlers/bottom-sheet.ts +74 -0
  88. package/src/codegen/targets/react/component/handlers/callout.ts +88 -0
  89. package/src/codegen/targets/react/component/handlers/checkbox.ts +129 -0
  90. package/src/codegen/targets/react/component/handlers/checkmark.ts +29 -0
  91. package/src/codegen/targets/react/component/handlers/chip.ts +93 -0
  92. package/src/codegen/targets/react/component/handlers/content-placeholder.ts +20 -0
  93. package/src/codegen/targets/react/component/handlers/contextual-floating-button.ts +52 -0
  94. package/src/codegen/targets/react/component/handlers/divider.ts +25 -0
  95. package/src/codegen/targets/react/component/handlers/field-button.ts +192 -0
  96. package/src/codegen/targets/react/component/handlers/field.ts +164 -0
  97. package/src/codegen/targets/react/component/handlers/floating-action-button.ts +45 -0
  98. package/src/codegen/targets/react/component/handlers/help-bubble.ts +73 -0
  99. package/src/codegen/targets/react/component/handlers/identity-placeholder.ts +20 -0
  100. package/src/codegen/targets/react/component/handlers/image-frame.ts +147 -0
  101. package/src/codegen/targets/react/component/handlers/index.ts +43 -0
  102. package/src/codegen/targets/react/component/handlers/legacy-select-box.ts +87 -0
  103. package/src/codegen/targets/react/component/handlers/legacy-text-field.ts +196 -0
  104. package/src/codegen/targets/react/component/handlers/list-header.ts +20 -0
  105. package/src/codegen/targets/react/component/handlers/list-item.ts +163 -0
  106. package/src/codegen/targets/react/component/handlers/manner-temp-badge.ts +21 -0
  107. package/src/codegen/targets/react/component/handlers/manner-temp.ts +18 -0
  108. package/src/codegen/targets/react/component/handlers/menu-sheet.ts +111 -0
  109. package/src/codegen/targets/react/component/handlers/page-banner.ts +106 -0
  110. package/src/codegen/targets/react/component/handlers/progress-circle.ts +55 -0
  111. package/src/codegen/targets/react/component/handlers/radio-group.ts +109 -0
  112. package/src/codegen/targets/react/component/handlers/radiomark.ts +27 -0
  113. package/src/codegen/targets/react/component/handlers/reaction-button.ts +37 -0
  114. package/src/codegen/targets/react/component/handlers/result-section.ts +67 -0
  115. package/src/codegen/targets/react/component/handlers/segmented-control.ts +63 -0
  116. package/src/codegen/targets/react/component/handlers/select-box.ts +333 -0
  117. package/src/codegen/targets/react/component/handlers/skeleton.ts +26 -0
  118. package/src/codegen/targets/react/component/handlers/slider.ts +117 -0
  119. package/src/codegen/targets/react/component/handlers/snackbar.ts +25 -0
  120. package/src/codegen/targets/react/component/handlers/switch.ts +35 -0
  121. package/src/codegen/targets/react/component/handlers/switchmark.ts +26 -0
  122. package/src/codegen/targets/react/component/handlers/tabs.ts +298 -0
  123. package/src/codegen/targets/react/component/handlers/tag-group.ts +90 -0
  124. package/src/codegen/targets/react/component/handlers/text-field.ts +253 -0
  125. package/src/codegen/targets/react/component/handlers/toggle-button.ts +43 -0
  126. package/src/codegen/targets/react/component/index.ts +24 -0
  127. package/src/codegen/targets/react/component/size.ts +22 -0
  128. package/src/codegen/targets/react/element-factories.ts +59 -0
  129. package/src/codegen/targets/react/frame.ts +96 -0
  130. package/src/codegen/targets/react/icon.ts +55 -0
  131. package/src/codegen/targets/react/index.ts +7 -0
  132. package/src/codegen/targets/react/instance.ts +82 -0
  133. package/src/codegen/targets/react/pipeline.ts +133 -0
  134. package/src/codegen/targets/react/props.ts +417 -0
  135. package/src/codegen/targets/react/shape.ts +47 -0
  136. package/src/codegen/targets/react/text.ts +31 -0
  137. package/src/codegen/targets/react/value-resolver.ts +93 -0
  138. package/src/entities/component.interface.ts +7 -0
  139. package/src/entities/component.repository.ts +16 -0
  140. package/src/entities/data/__generated__/archive/component-sets/index.d.ts +2074 -0
  141. package/src/entities/data/__generated__/archive/component-sets/index.mjs +2074 -0
  142. package/src/entities/data/__generated__/archive/components/index.d.ts +116 -0
  143. package/src/entities/data/__generated__/archive/components/index.mjs +116 -0
  144. package/src/entities/data/__generated__/archive/styles/index.d.ts +3 -0
  145. package/src/entities/data/__generated__/archive/styles/index.mjs +429 -0
  146. package/src/entities/data/__generated__/archive/variable-collections/index.d.ts +3 -0
  147. package/src/entities/data/__generated__/archive/variable-collections/index.mjs +501 -0
  148. package/src/entities/data/__generated__/archive/variables/index.d.ts +3 -0
  149. package/src/entities/data/__generated__/archive/variables/index.mjs +7019 -0
  150. package/src/entities/data/__generated__/component-sets/index.d.ts +4325 -0
  151. package/src/entities/data/__generated__/component-sets/index.mjs +4325 -0
  152. package/src/entities/data/__generated__/components/index.d.ts +378 -0
  153. package/src/entities/data/__generated__/components/index.mjs +378 -0
  154. package/src/entities/data/__generated__/icons/index.d.ts +3 -0
  155. package/src/entities/data/__generated__/icons/index.mjs +3476 -0
  156. package/src/entities/data/__generated__/styles/index.d.ts +3 -0
  157. package/src/entities/data/__generated__/styles/index.mjs +436 -0
  158. package/src/entities/data/__generated__/variable-collections/index.d.ts +3 -0
  159. package/src/entities/data/__generated__/variable-collections/index.mjs +479 -0
  160. package/src/entities/data/__generated__/variables/index.d.ts +3 -0
  161. package/src/entities/data/__generated__/variables/index.mjs +6969 -0
  162. package/src/entities/icon.interface.ts +5 -0
  163. package/src/entities/icon.repository.ts +11 -0
  164. package/src/entities/icon.service.ts +26 -0
  165. package/src/entities/index.ts +60 -0
  166. package/src/entities/style.interface.ts +5 -0
  167. package/src/entities/style.repository.ts +27 -0
  168. package/src/entities/style.service.ts +36 -0
  169. package/src/entities/variable.interface.ts +18 -0
  170. package/src/entities/variable.repository.ts +57 -0
  171. package/src/entities/variable.service.ts +101 -0
  172. package/src/index.ts +3 -0
  173. package/src/normalizer/from-plugin.ts +602 -0
  174. package/src/normalizer/from-rest.ts +577 -0
  175. package/src/normalizer/index.ts +3 -0
  176. package/src/normalizer/types.ts +208 -0
  177. package/src/utils/common.ts +38 -0
  178. package/src/utils/css.ts +19 -0
  179. package/src/utils/figma-gradient.ts +72 -0
  180. package/src/utils/figma-node.ts +95 -0
  181. package/src/utils/figma-variable.ts +49 -0
@@ -0,0 +1,298 @@
1
+ import { createLocalSnippetHelper } from "../../element-factories";
2
+ import type {
3
+ ChipProperties,
4
+ ChipTabsTriggerProperties,
5
+ TabsChipWrapperProperties,
6
+ TabsLineTriggerFillProperties,
7
+ TabsLineTriggerHugProperties,
8
+ TabsLineWrapperProperties,
9
+ TabsProperties,
10
+ } from "@/codegen/component-properties";
11
+ import { defineComponentHandler } from "@/codegen/core";
12
+ import * as metadata from "@/entities/data/__generated__/component-sets";
13
+ import { camelCase } from "change-case";
14
+ import type { ComponentHandlerDeps } from "../deps.interface";
15
+ import { handleSizeProp } from "../size";
16
+ import { match } from "ts-pattern";
17
+ import { findAllInstances } from "@/utils/figma-node";
18
+
19
+ const { createLocalSnippetElement: createTabsLocalSnippetElement } =
20
+ createLocalSnippetHelper("tabs");
21
+
22
+ const { createLocalSnippetElement: createChipTabsLocalSnippetElement } =
23
+ createLocalSnippetHelper("chip-tabs");
24
+
25
+ export const createTabsHandler = (_ctx: ComponentHandlerDeps) => {
26
+ const lineHandler = createLineTabsHandler(_ctx);
27
+ const chipHandler = createChipTabsHandler(_ctx);
28
+
29
+ return defineComponentHandler<TabsProperties>(metadata.componentTabs.key, (node, traverse) => {
30
+ const props = node.componentProperties;
31
+
32
+ const elementNode = match(props.Variant.value)
33
+ .with("Line", () => {
34
+ const [wrapper] = findAllInstances<TabsLineWrapperProperties>({
35
+ node,
36
+ key: lineHandler.key,
37
+ });
38
+
39
+ if (!wrapper) throw new Error("Line Tab wrapper not found");
40
+
41
+ return lineHandler.transform(wrapper, traverse);
42
+ })
43
+ .with("Chip", () => {
44
+ const [wrapper] = findAllInstances<TabsChipWrapperProperties>({
45
+ node,
46
+ key: chipHandler.key,
47
+ });
48
+
49
+ if (!wrapper) throw new Error("Chip Tab wrapper not found");
50
+
51
+ return chipHandler.transform(wrapper, traverse);
52
+ })
53
+ .exhaustive();
54
+
55
+ return elementNode;
56
+ });
57
+ };
58
+
59
+ /*
60
+ <TabsRoot defaultValue="2" triggerLayout="fill">
61
+ <TabsList>
62
+ <TabsTrigger value="1">라벨1</TabsTrigger>
63
+ <TabsTrigger value="2">라벨2</TabsTrigger>
64
+ <TabsTrigger value="3">라벨3</TabsTrigger>
65
+ </TabsList>
66
+ <TabsCarousel>
67
+ <TabsContent value="1">
68
+ <Content>Content 1</Content>
69
+ </TabsContent>
70
+ <TabsContent value="2">
71
+ <Content>Content 2</Content>
72
+ </TabsContent>
73
+ <TabsContent value="3">
74
+ <Content>Content 3</Content>
75
+ </TabsContent>
76
+ </TabsCarousel>
77
+ </TabsRoot>
78
+ */
79
+
80
+ const createLineTabsHandler = (_ctx: ComponentHandlerDeps) => {
81
+ const hugHandler = createLineTriggerHugHandler(_ctx);
82
+ const fillHandler = createLineTriggerFillHandler(_ctx);
83
+
84
+ return defineComponentHandler<TabsLineWrapperProperties>(
85
+ metadata.privateComponentTabsLine.key,
86
+ (node, traverse) => {
87
+ const props = node.componentProperties;
88
+
89
+ const { triggers, defaultValue } = match(props.Layout.value)
90
+ .with("Hug", () => {
91
+ const nodes = findAllInstances<TabsLineTriggerHugProperties>({
92
+ node,
93
+ key: hugHandler.key,
94
+ });
95
+
96
+ return {
97
+ triggers: nodes.map((node) => ({
98
+ elementNode: hugHandler.transform(node, traverse),
99
+ value: node.componentProperties["Label#4478:2"].value,
100
+ })),
101
+ defaultValue: nodes.find((node) => node.componentProperties.State.value === "Selected")
102
+ ?.componentProperties["Label#4478:2"].value,
103
+ };
104
+ })
105
+ .with("Fill", () => {
106
+ const nodes = findAllInstances<TabsLineTriggerFillProperties>({
107
+ node,
108
+ key: fillHandler.key,
109
+ });
110
+
111
+ return {
112
+ triggers: nodes.map((node) => ({
113
+ elementNode: fillHandler.transform(node, traverse),
114
+ value: node.componentProperties["Label#4478:2"].value,
115
+ })),
116
+ defaultValue: nodes.find((node) => node.componentProperties.State.value === "Selected")
117
+ ?.componentProperties["Label#4478:2"].value,
118
+ };
119
+ })
120
+ .exhaustive();
121
+
122
+ const rootProps = {
123
+ triggerLayout: camelCase(props.Layout.value),
124
+ size: handleSizeProp(props.Size.value),
125
+ defaultValue,
126
+ };
127
+
128
+ const tabsCarousel = createTabsLocalSnippetElement(
129
+ "TabsCarousel",
130
+ undefined,
131
+ triggers.map(({ value }) => createTabsLocalSnippetElement("TabsContent", { value }, value)),
132
+ );
133
+
134
+ const tabsList = createTabsLocalSnippetElement(
135
+ "TabsList",
136
+ undefined,
137
+ triggers.map(({ elementNode }) => elementNode),
138
+ );
139
+
140
+ return createTabsLocalSnippetElement("TabsRoot", rootProps, [tabsList, tabsCarousel]);
141
+ },
142
+ );
143
+ };
144
+
145
+ const createLineTriggerHugHandler = (_ctx: ComponentHandlerDeps) =>
146
+ defineComponentHandler<TabsLineTriggerHugProperties>(
147
+ metadata.privateComponentTabItemLineHug.key,
148
+ ({ componentProperties: props }) => {
149
+ const commonProps = {
150
+ value: props["Label#4478:2"].value,
151
+ ...(props.State.value === "Disabled" && {
152
+ disabled: true,
153
+ }),
154
+ ...(props["Has Notification#32892:0"].value && {
155
+ notification: true,
156
+ }),
157
+ };
158
+
159
+ return createTabsLocalSnippetElement("TabsTrigger", commonProps, props["Label#4478:2"].value);
160
+ },
161
+ );
162
+
163
+ const createLineTriggerFillHandler = (_ctx: ComponentHandlerDeps) =>
164
+ defineComponentHandler<TabsLineTriggerFillProperties>(
165
+ metadata.privateComponentTabItemLineFill.key,
166
+ ({ componentProperties: props }) => {
167
+ const commonProps = {
168
+ value: props["Label#4478:2"].value,
169
+ ...(props.State.value === "Disabled" && {
170
+ disabled: true,
171
+ }),
172
+ ...(props["Has Notification#32904:13"].value && {
173
+ notification: true,
174
+ }),
175
+ };
176
+
177
+ return createTabsLocalSnippetElement("TabsTrigger", commonProps, props["Label#4478:2"].value);
178
+ },
179
+ );
180
+
181
+ /*
182
+ <ChipTabsRoot
183
+ variant="neutralOutline"
184
+ defaultValue="1"
185
+ >
186
+ <ChipTabsList>
187
+ <ChipTabsTrigger value="1">라벨1</ChipTabsTrigger>
188
+ <ChipTabsTrigger value="2">라벨2</ChipTabsTrigger>
189
+ <ChipTabsTrigger value="3">라벨3</ChipTabsTrigger>
190
+ </ChipTabsList>
191
+ <ChipTabsCarousel>
192
+ <ChipTabsContent value="1">
193
+ <Content>Content 1</Content>
194
+ </ChipTabsContent>
195
+ <ChipTabsContent value="2">
196
+ <Content>Content 2</Content>
197
+ </ChipTabsContent>
198
+ <ChipTabsContent value="3">
199
+ <Content>Content 3</Content>
200
+ </ChipTabsContent>
201
+ </ChipTabsCarousel>
202
+ </ChipTabsRoot>
203
+ */
204
+
205
+ const createChipTabsHandler = (_ctx: ComponentHandlerDeps) => {
206
+ const triggerHandler = createChipTabsTriggerHandler(_ctx);
207
+
208
+ return defineComponentHandler<TabsChipWrapperProperties>(
209
+ metadata.privateComponentTabsChip.key,
210
+ (node, traverse) => {
211
+ const props = node.componentProperties;
212
+
213
+ const nodes = findAllInstances<ChipTabsTriggerProperties>({
214
+ node,
215
+ key: triggerHandler.key,
216
+ });
217
+
218
+ const triggers = nodes.map((node) => {
219
+ // this is redundant; can this be better?
220
+ const [chip] = findAllInstances<ChipProperties>({ node, key: metadata.componentChip.key });
221
+ if (!chip) throw new Error("Chip not found in ChipTabsTrigger");
222
+
223
+ return {
224
+ elementNode: triggerHandler.transform(node, traverse),
225
+ value: chip.componentProperties["Label#7185:0"].value,
226
+ };
227
+ });
228
+
229
+ const selectedTrigger = nodes.find(
230
+ (node) => node.componentProperties.State.value === "Selected",
231
+ );
232
+ const [selectedChip] = selectedTrigger
233
+ ? findAllInstances<ChipProperties>({
234
+ node: selectedTrigger,
235
+ key: metadata.componentChip.key,
236
+ })
237
+ : [undefined];
238
+ if (!selectedChip) throw new Error("Chip not found in ChipTabsTrigger");
239
+
240
+ const defaultValue = selectedChip.componentProperties["Label#7185:0"].value;
241
+
242
+ const variant = match(props.Variant.value)
243
+ .with("Outline", () => "neutralOutline")
244
+ .with("Solid", () => "neutralSolid")
245
+ .exhaustive();
246
+
247
+ const rootProps = {
248
+ size: handleSizeProp(props.Size.value),
249
+ variant,
250
+ defaultValue,
251
+ };
252
+
253
+ const tabsCarousel = createChipTabsLocalSnippetElement(
254
+ "ChipTabsCarousel",
255
+ { swipeable: false },
256
+ triggers.map(({ value }) =>
257
+ createChipTabsLocalSnippetElement("ChipTabsContent", { value }, value),
258
+ ),
259
+ );
260
+
261
+ const tabsList = createChipTabsLocalSnippetElement(
262
+ "ChipTabsList",
263
+ undefined,
264
+ triggers.map(({ elementNode }) => elementNode),
265
+ );
266
+
267
+ return createChipTabsLocalSnippetElement("ChipTabsRoot", rootProps, [tabsList, tabsCarousel]);
268
+ },
269
+ );
270
+ };
271
+
272
+ const createChipTabsTriggerHandler = (_ctx: ComponentHandlerDeps) =>
273
+ defineComponentHandler<ChipTabsTriggerProperties>(
274
+ metadata.privateComponentTabItemChip.key,
275
+ (node) => {
276
+ const [chip] = findAllInstances<ChipProperties>({ node, key: metadata.componentChip.key });
277
+ if (!chip) throw new Error("Chip not found in ChipTabsTrigger");
278
+
279
+ const props = node.componentProperties;
280
+ const chipProps = chip.componentProperties;
281
+
282
+ const commonProps = {
283
+ value: chipProps["Label#7185:0"].value,
284
+ ...(chipProps.State.value === "Disabled" && {
285
+ disabled: true,
286
+ }),
287
+ ...(props["Has Notification"].value === "True" && {
288
+ notification: true,
289
+ }),
290
+ };
291
+
292
+ return createChipTabsLocalSnippetElement(
293
+ "ChipTabsTrigger",
294
+ commonProps,
295
+ chipProps["Label#7185:0"].value,
296
+ );
297
+ },
298
+ );
@@ -0,0 +1,90 @@
1
+ import type { TagGroupItemProperties, TagGroupProperties } from "@/codegen/component-properties";
2
+ import { defineComponentHandler, type ElementNode } from "@/codegen/core";
3
+ import * as metadata from "@/entities/data/__generated__/component-sets";
4
+ import { createLocalSnippetHelper } from "../../element-factories";
5
+ import type { ComponentHandlerDeps } from "../deps.interface";
6
+ import { camelCase } from "change-case";
7
+ import { match } from "ts-pattern";
8
+ import { findAllInstances } from "@/utils/figma-node";
9
+
10
+ const { createLocalSnippetElement } = createLocalSnippetHelper("tag-group");
11
+
12
+ export const createTagGroupHandler = (ctx: ComponentHandlerDeps) => {
13
+ const itemHandler = createTagGroupItemHandler(ctx);
14
+
15
+ return defineComponentHandler<TagGroupProperties>(
16
+ metadata.componentTagGroup.key,
17
+ (node, traverse) => {
18
+ const itemNodes = findAllInstances<TagGroupItemProperties>({
19
+ node,
20
+ key: itemHandler.key,
21
+ });
22
+
23
+ const items = itemNodes.map((itemNode) =>
24
+ itemHandler.transform(itemNode, traverse),
25
+ ) as (ElementNode & {
26
+ props: { size?: string; weight?: string; tone?: string };
27
+ })[];
28
+
29
+ if (items.length === 0) {
30
+ return createLocalSnippetElement("TagGroupRoot");
31
+ }
32
+
33
+ // if size/weight/tone are all the same among item[n].props, lift them up to TagGroupRoot
34
+
35
+ const consistent = {
36
+ size: items.map((item) => item.props.size).every((size) => size === items[0].props.size),
37
+ weight: items
38
+ .map((item) => item.props.weight)
39
+ .every((weight) => weight === items[0].props.weight),
40
+ tone: items.map((item) => item.props.tone).every((tone) => tone === items[0].props.tone),
41
+ };
42
+
43
+ return createLocalSnippetElement(
44
+ "TagGroupRoot",
45
+ {
46
+ // lift up consistent props
47
+ ...(consistent.size && { size: items[0].props.size }),
48
+ ...(consistent.weight && { weight: items[0].props.weight }),
49
+ ...(consistent.tone && { tone: items[0].props.tone }),
50
+ },
51
+ items.map((item) => ({
52
+ ...item,
53
+ props: {
54
+ // remove lifted props
55
+ ...item.props,
56
+ size: consistent.size ? undefined : item.props.size,
57
+ weight: consistent.weight ? undefined : item.props.weight,
58
+ tone: consistent.tone ? undefined : item.props.tone,
59
+ },
60
+ })),
61
+ { comment: "`truncate` prop을 통해 한 줄로 표시되도록 할 수 있습니다." },
62
+ );
63
+ },
64
+ );
65
+ };
66
+
67
+ const createTagGroupItemHandler = (ctx: ComponentHandlerDeps) =>
68
+ defineComponentHandler<TagGroupItemProperties>(
69
+ metadata.privateComponentItemTag.key,
70
+ ({ componentProperties: props }) => {
71
+ const size = match(props.Size.value)
72
+ .with("t2(12pt)", () => "t2")
73
+ .with("t3(13pt)", () => "t3")
74
+ .with("t4(14pt)", () => "t4")
75
+ .exhaustive();
76
+
77
+ return createLocalSnippetElement("TagGroupItem", {
78
+ size,
79
+ weight: camelCase(props["Weight"].value),
80
+ tone: camelCase(props["Tone"].value),
81
+ label: props["Label#5409:0"].value,
82
+ ...(props.Layout.value === "Icon First" && {
83
+ prefixIcon: ctx.iconHandler.transform(props["Prefix Icon#47948:0"]),
84
+ }),
85
+ ...(props.Layout.value === "Icon Last" && {
86
+ suffixIcon: ctx.iconHandler.transform(props["Suffix Icon#47948:55"]),
87
+ }),
88
+ });
89
+ },
90
+ );
@@ -0,0 +1,253 @@
1
+ import { defineComponentHandler } from "@/codegen/core";
2
+ import * as metadata from "@/entities/data/__generated__/component-sets";
3
+ import { createLocalSnippetHelper } from "../../element-factories";
4
+ import type { ComponentHandlerDeps } from "../deps.interface";
5
+ import {
6
+ createFieldFooterHandler,
7
+ createFieldHeaderHandler,
8
+ type FieldFooterProps,
9
+ type FieldHeaderProps,
10
+ } from "@/codegen/targets/react/component/handlers/field";
11
+ import type {
12
+ FieldHeaderProperties,
13
+ FieldFooterProperties,
14
+ TextareaProperties,
15
+ TextInputFieldProperties,
16
+ TextInputOutlineProperties,
17
+ TextInputUnderlineProperties,
18
+ TextInputOutlinePrefixProperties,
19
+ TextInputOutlineSuffixProperties,
20
+ TextInputUnderlinePrefixProperties,
21
+ TextInputUnderlineSuffixProperties,
22
+ TextareaFieldProperties,
23
+ } from "@/codegen/component-properties";
24
+ import { findAllInstances, findOne } from "@/utils/figma-node";
25
+ import type { NormalizedTextNode } from "@/normalizer";
26
+
27
+ const { createLocalSnippetElement } = createLocalSnippetHelper("text-field");
28
+
29
+ export const createTextInputFieldHandler = (ctx: ComponentHandlerDeps) => {
30
+ const fieldHeaderHandler = createFieldHeaderHandler(ctx);
31
+ const fieldFooterHandler = createFieldFooterHandler(ctx);
32
+
33
+ return defineComponentHandler<TextInputFieldProperties>(
34
+ metadata.templateTextField.key,
35
+ (node, traverse) => {
36
+ const props = node.componentProperties;
37
+
38
+ const [textInputOutline] = findAllInstances<TextInputOutlineProperties>({
39
+ node,
40
+ key: metadata.componentTextInput.key,
41
+ });
42
+ const [textInputUnderline] = findAllInstances<TextInputUnderlineProperties>({
43
+ node,
44
+ key: metadata.componentUnderlineTextInput.key,
45
+ });
46
+
47
+ const [fieldHeader] = findAllInstances<FieldHeaderProperties>({
48
+ node,
49
+ key: fieldHeaderHandler.key,
50
+ });
51
+ const [fieldFooter] = findAllInstances<FieldFooterProperties>({
52
+ node,
53
+ key: fieldFooterHandler.key,
54
+ });
55
+
56
+ const fieldProps = {
57
+ ...(props["Show Header#40606:8"].value && fieldHeader
58
+ ? (fieldHeaderHandler.transform(fieldHeader, traverse).props as FieldHeaderProps)
59
+ : {}),
60
+ ...(props["Show Footer#40606:9"].value && fieldFooter
61
+ ? (fieldFooterHandler.transform(fieldFooter, traverse).props as FieldFooterProps)
62
+ : {}),
63
+ };
64
+
65
+ const commonProps = (() => {
66
+ if (textInputOutline) {
67
+ const [prefix] = findAllInstances<TextInputOutlinePrefixProperties>({
68
+ node: textInputOutline,
69
+ key: metadata.privateComponentTextInputPrefix.key,
70
+ });
71
+
72
+ const [suffix] = findAllInstances<TextInputOutlineSuffixProperties>({
73
+ node: textInputOutline,
74
+ key: metadata.privateComponentTextInputSuffix.key,
75
+ });
76
+
77
+ return {
78
+ variant: "outline",
79
+ ...(textInputOutline.componentProperties.State.value === "Disabled" && {
80
+ disabled: true,
81
+ }),
82
+ ...(textInputOutline.componentProperties.State.value === "Read Only" && {
83
+ readOnly: true,
84
+ }),
85
+ ...(textInputOutline.componentProperties.State.value === "Error" && {
86
+ invalid: true,
87
+ }),
88
+ ...(textInputOutline.componentProperties.State.value === "Error Focused" && {
89
+ invalid: true,
90
+ }),
91
+ ...(textInputOutline.componentProperties["Has Prefix#32514:10"].value === true &&
92
+ prefix &&
93
+ prefix.componentProperties.Type.value === "Icon" && {
94
+ prefixIcon: ctx.iconHandler.transform(prefix.componentProperties["Icon#34021:2"]),
95
+ }),
96
+ ...(textInputOutline.componentProperties["Has Suffix#32865:68"].value === true &&
97
+ suffix &&
98
+ suffix.componentProperties["Type (Figma Only)"].value === "Icon" && {
99
+ suffixIcon: ctx.iconHandler.transform(suffix.componentProperties["Icon#45391:0"]),
100
+ }),
101
+ ...(textInputOutline.componentProperties["Has Suffix#32865:68"].value === true &&
102
+ suffix &&
103
+ suffix.componentProperties["Type (Figma Only)"].value === "Text" && {
104
+ suffix: suffix.componentProperties["Suffix Text#34021:4"].value,
105
+ }),
106
+ };
107
+ }
108
+
109
+ if (textInputUnderline) {
110
+ const [prefix] = findAllInstances<TextInputUnderlinePrefixProperties>({
111
+ node: textInputUnderline,
112
+ key: metadata.privateComponentUnderlineTextInputPrefix.key,
113
+ });
114
+
115
+ const [suffix] = findAllInstances<TextInputUnderlineSuffixProperties>({
116
+ node: textInputUnderline,
117
+ key: metadata.privateComponentUnderlineTextInputSuffix.key,
118
+ });
119
+
120
+ return {
121
+ variant: "underline",
122
+ ...(textInputUnderline.componentProperties.State.value === "Disabled" && {
123
+ disabled: true,
124
+ }),
125
+ ...(textInputUnderline.componentProperties.State.value === "Read Only" && {
126
+ readOnly: true,
127
+ }),
128
+ ...(textInputUnderline.componentProperties.State.value === "Error" && {
129
+ invalid: true,
130
+ }),
131
+ ...(textInputUnderline.componentProperties.State.value === "Error Focused" && {
132
+ invalid: true,
133
+ }),
134
+ ...(textInputUnderline.componentProperties["Has Prefix#34125:0"].value === true &&
135
+ prefix &&
136
+ prefix.componentProperties.Type.value === "Icon" && {
137
+ prefixIcon: ctx.iconHandler.transform(prefix.componentProperties["Icon#34021:2"]),
138
+ }),
139
+ ...(textInputUnderline.componentProperties["Has Suffix#34125:8"].value === true &&
140
+ suffix &&
141
+ suffix.componentProperties["Type (Figma Only)"].value === "Icon" && {
142
+ suffixIcon: ctx.iconHandler.transform(suffix.componentProperties["Icon#45391:5"]),
143
+ }),
144
+ ...(textInputUnderline.componentProperties["Has Suffix#34125:8"].value === true &&
145
+ suffix &&
146
+ suffix.componentProperties["Type (Figma Only)"].value === "Text" && {
147
+ suffix: suffix.componentProperties["Suffix Text#34021:4"].value,
148
+ }),
149
+ };
150
+ }
151
+
152
+ return {};
153
+ })();
154
+
155
+ // these can be fragile but better than having 9 different handlers
156
+ const placeholder = findOne(
157
+ node,
158
+ (node) => node.type === "TEXT" && node.name.toLowerCase().includes("placeholder"),
159
+ ) as NormalizedTextNode;
160
+
161
+ const value = findOne(
162
+ node,
163
+ (node) => node.type === "TEXT" && node.name.toLowerCase().includes("value"),
164
+ ) as NormalizedTextNode;
165
+
166
+ const inputProps = {
167
+ ...(placeholder && {
168
+ placeholder: placeholder.characters,
169
+ }),
170
+ };
171
+
172
+ return createLocalSnippetElement(
173
+ "TextField",
174
+ {
175
+ ...fieldProps,
176
+ ...commonProps,
177
+ ...(value && {
178
+ defaultValue: value.characters,
179
+ }),
180
+ },
181
+ createLocalSnippetElement("TextFieldInput", inputProps),
182
+ );
183
+ },
184
+ );
185
+ };
186
+
187
+ export const createTextareaFieldHandler = (ctx: ComponentHandlerDeps) => {
188
+ const fieldHeaderHandler = createFieldHeaderHandler(ctx);
189
+ const fieldFooterHandler = createFieldFooterHandler(ctx);
190
+
191
+ return defineComponentHandler<TextareaFieldProperties>(
192
+ metadata.templateTextareaField.key,
193
+ (node, traverse) => {
194
+ const [textarea] = findAllInstances<TextareaProperties>({
195
+ node,
196
+ key: metadata.componentTextarea.key,
197
+ });
198
+ const [fieldHeader] = findAllInstances<FieldHeaderProperties>({
199
+ node,
200
+ key: fieldHeaderHandler.key,
201
+ });
202
+ const [fieldFooter] = findAllInstances<FieldFooterProperties>({
203
+ node,
204
+ key: fieldFooterHandler.key,
205
+ });
206
+
207
+ const fieldProps = {
208
+ ...(fieldHeader
209
+ ? (fieldHeaderHandler.transform(fieldHeader, traverse).props as FieldHeaderProps)
210
+ : {}),
211
+ ...(fieldFooter
212
+ ? (fieldFooterHandler.transform(fieldFooter, traverse).props as FieldFooterProps)
213
+ : {}),
214
+ };
215
+
216
+ // these can be fragile but better than having 9 different handlers
217
+ const placeholder = findOne(
218
+ node,
219
+ (node) => node.type === "TEXT" && node.name.toLowerCase().includes("placeholder"),
220
+ ) as NormalizedTextNode;
221
+
222
+ const value = findOne(
223
+ node,
224
+ (node) => node.type === "TEXT" && node.name.toLowerCase().includes("value"),
225
+ ) as NormalizedTextNode;
226
+
227
+ const inputProps = {
228
+ autoresize: textarea.componentProperties["Auto Size (Figma Only)"].value === "true",
229
+ ...(placeholder && {
230
+ placeholder: placeholder.characters,
231
+ }),
232
+ };
233
+
234
+ const commonProps = {
235
+ ...(textarea.componentProperties.State.value === "Disabled" && {
236
+ disabled: true,
237
+ }),
238
+ ...(textarea.componentProperties.State.value === "Read Only" && {
239
+ readOnly: true,
240
+ }),
241
+ ...(value && {
242
+ defaultValue: value.characters,
243
+ }),
244
+ };
245
+
246
+ return createLocalSnippetElement(
247
+ "TextField",
248
+ { ...fieldProps, ...commonProps },
249
+ createLocalSnippetElement("TextFieldTextarea", inputProps),
250
+ );
251
+ },
252
+ );
253
+ };
@@ -0,0 +1,43 @@
1
+ import type { ToggleButtonProperties } from "@/codegen/component-properties";
2
+ import { defineComponentHandler } from "@/codegen/core";
3
+ import * as metadata from "@/entities/data/__generated__/component-sets";
4
+ import { camelCase } from "change-case";
5
+ import { createLocalSnippetHelper, createSeedReactElement } from "../../element-factories";
6
+ import type { ComponentHandlerDeps } from "../deps.interface";
7
+ import { handleSizeProp } from "../size";
8
+
9
+ const { createLocalSnippetElement } = createLocalSnippetHelper("toggle-button");
10
+
11
+ export const createToggleButtonHandler = (ctx: ComponentHandlerDeps) =>
12
+ defineComponentHandler<ToggleButtonProperties>(
13
+ metadata.componentToggleButton.key,
14
+ ({ componentProperties: props }) => {
15
+ const commonProps = {
16
+ variant: camelCase(props.Variant.value),
17
+ size: handleSizeProp(props.Size.value),
18
+ ...(props.Selected.value === "True" && {
19
+ defaultPressed: true,
20
+ }),
21
+ ...(props.State.value === "Disabled" && {
22
+ disabled: true,
23
+ }),
24
+ ...(props.State.value === "Loading" && {
25
+ loading: true,
26
+ }),
27
+ };
28
+
29
+ return createLocalSnippetElement("ToggleButton", commonProps, [
30
+ props["Show Prefix Icon#6122:392"].value
31
+ ? createSeedReactElement("PrefixIcon", {
32
+ svg: ctx.iconHandler.transform(props["Prefix Icon#6122:98"]),
33
+ })
34
+ : undefined,
35
+ props["Label#6122:49"].value,
36
+ props["Show Suffix Icon#6122:147"].value
37
+ ? createSeedReactElement("SuffixIcon", {
38
+ svg: ctx.iconHandler.transform(props["Suffix Icon#6122:343"]),
39
+ })
40
+ : undefined,
41
+ ]);
42
+ },
43
+ );