@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,192 @@
1
+ import { defineComponentHandler } from "@/codegen/core";
2
+ import * as sets from "@/entities/data/__generated__/component-sets";
3
+ import * as components from "@/entities/data/__generated__/components";
4
+ import { createLocalSnippetHelper } from "../../element-factories";
5
+ import type { ComponentHandlerDeps } from "../deps.interface";
6
+ import {
7
+ createFieldFooterHandler,
8
+ createFieldHeaderHandler,
9
+ type FieldFooterProps,
10
+ type FieldHeaderProps,
11
+ } from "@/codegen/targets/react/component/handlers/field";
12
+ import type {
13
+ FieldHeaderProperties,
14
+ FieldFooterProperties,
15
+ FieldButtonProperties,
16
+ InputButtonProperties,
17
+ InputButtonPrefixProperties,
18
+ InputButtonSuffixProperties,
19
+ ActionButtonGhostProperties,
20
+ GenericFieldButtonProps,
21
+ } from "@/codegen/component-properties";
22
+ import { findAllInstances, findOne } from "@/utils/figma-node";
23
+ import type { NormalizedTextNode } from "@/normalizer";
24
+
25
+ const { createLocalSnippetElement } = createLocalSnippetHelper("field-button");
26
+
27
+ export const createFieldButtonHandler = (ctx: ComponentHandlerDeps) => {
28
+ const fieldHeaderHandler = createFieldHeaderHandler(ctx);
29
+ const fieldFooterHandler = createFieldFooterHandler(ctx);
30
+
31
+ return defineComponentHandler<FieldButtonProperties>(
32
+ sets.templateFieldButton.key,
33
+ (node, traverse) => {
34
+ const props = node.componentProperties;
35
+
36
+ const [inputButton] = findAllInstances<InputButtonProperties>({
37
+ node,
38
+ key: sets.componentInputButton.key,
39
+ });
40
+
41
+ const [clearButton] = findAllInstances<ActionButtonGhostProperties>({
42
+ node,
43
+ key: sets.componentActionButtonGhostButton.key,
44
+ });
45
+
46
+ const [fieldHeader] = findAllInstances<FieldHeaderProperties>({
47
+ node,
48
+ key: sets.componentFieldHeader.key,
49
+ });
50
+ const [fieldFooter] = findAllInstances<FieldFooterProperties>({
51
+ node,
52
+ key: sets.componentFieldFooter.key,
53
+ });
54
+
55
+ // maxGraphemeCount and required can't be props of FieldButton
56
+ const { required: _required, ...headerProps } =
57
+ props["Show Header#40606:8"].value && fieldHeader
58
+ ? (fieldHeaderHandler.transform(fieldHeader, traverse).props as FieldHeaderProps)
59
+ : {};
60
+ const { maxGraphemeCount: _maxGraphemeCount, ...footerProps } =
61
+ props["Show Footer#40606:9"].value && fieldFooter
62
+ ? (fieldFooterHandler.transform(fieldFooter, traverse).props as FieldFooterProps)
63
+ : {};
64
+
65
+ const [prefix] = findAllInstances<InputButtonPrefixProperties>({
66
+ node: inputButton,
67
+ key: sets.privateComponentInputButtonPrefix.key,
68
+ });
69
+
70
+ const [suffix] = findAllInstances<InputButtonSuffixProperties>({
71
+ node: inputButton,
72
+ key: sets.privateComponentInputButtonSuffix.key,
73
+ });
74
+
75
+ const commonProps = {
76
+ ...(inputButton.componentProperties.State.value === "Disabled" && {
77
+ disabled: true,
78
+ }),
79
+ ...((inputButton.componentProperties.State.value === "Error" ||
80
+ inputButton.componentProperties.State.value === "Error Pressed") && {
81
+ invalid: true,
82
+ }),
83
+ ...(clearButton && {
84
+ showClearButton: true,
85
+ }),
86
+ ...(inputButton.componentProperties["Has Prefix#32514:10"].value === true &&
87
+ prefix &&
88
+ prefix.componentProperties.Type.value === "Icon" && {
89
+ prefixIcon: ctx.iconHandler.transform(prefix.componentProperties["Icon#34021:2"]),
90
+ }),
91
+ ...(inputButton.componentProperties["Has Suffix#32865:68"].value === true &&
92
+ suffix &&
93
+ suffix.componentProperties["Type (Figma Only)"].value === "Icon" && {
94
+ suffixIcon: ctx.iconHandler.transform(suffix.componentProperties["Icon#37963:0"]),
95
+ }),
96
+ ...(inputButton.componentProperties["Has Suffix#32865:68"].value === true &&
97
+ suffix &&
98
+ suffix.componentProperties["Type (Figma Only)"].value === "Text" && {
99
+ suffix: suffix.componentProperties["Suffix Text#34021:4"].value,
100
+ }),
101
+ };
102
+
103
+ // these can be fragile but better than having 9 different handlers
104
+ const placeholder = findOne(
105
+ node,
106
+ (node) => node.type === "TEXT" && node.name.toLowerCase().includes("placeholder"),
107
+ ) as NormalizedTextNode;
108
+
109
+ const value = findOne(
110
+ node,
111
+ (node) => node.type === "TEXT" && node.name.toLowerCase().includes("value"),
112
+ ) as NormalizedTextNode;
113
+
114
+ return createLocalSnippetElement(
115
+ "FieldButton",
116
+ { ...headerProps, ...footerProps, ...commonProps },
117
+ props["Has Value"].value === "True" && value
118
+ ? createLocalSnippetElement("FieldButtonValue", undefined, value.characters)
119
+ : placeholder
120
+ ? createLocalSnippetElement("FieldButtonPlaceholder", undefined, placeholder.characters)
121
+ : undefined,
122
+ { comment: "buttonProps를 통해 aria-label을 제공하세요." },
123
+ );
124
+ },
125
+ );
126
+ };
127
+
128
+ // TODO: those 4 are basically the same
129
+
130
+ export const createSelectFieldHandler = (ctx: ComponentHandlerDeps) => {
131
+ const fieldButtonHandler = createFieldButtonHandler(ctx);
132
+
133
+ return defineComponentHandler<GenericFieldButtonProps>(
134
+ components.privateTemplateSelectField.key,
135
+ (node, traverse) => {
136
+ const [fieldButton] = findAllInstances<FieldButtonProperties>({
137
+ node,
138
+ key: fieldButtonHandler.key,
139
+ });
140
+
141
+ return fieldButtonHandler.transform(fieldButton, traverse);
142
+ },
143
+ );
144
+ };
145
+
146
+ export const createDatePickerFieldHandler = (ctx: ComponentHandlerDeps) => {
147
+ const fieldButtonHandler = createFieldButtonHandler(ctx);
148
+
149
+ return defineComponentHandler<GenericFieldButtonProps>(
150
+ components.privateTemplateDatePickerField.key,
151
+ (node, traverse) => {
152
+ const [fieldButton] = findAllInstances<FieldButtonProperties>({
153
+ node,
154
+ key: fieldButtonHandler.key,
155
+ });
156
+
157
+ return fieldButtonHandler.transform(fieldButton, traverse);
158
+ },
159
+ );
160
+ };
161
+
162
+ export const createTimePickerFieldHandler = (ctx: ComponentHandlerDeps) => {
163
+ const fieldButtonHandler = createFieldButtonHandler(ctx);
164
+
165
+ return defineComponentHandler<GenericFieldButtonProps>(
166
+ components.privateTemplateTimePickerField.key,
167
+ (node, traverse) => {
168
+ const [fieldButton] = findAllInstances<FieldButtonProperties>({
169
+ node,
170
+ key: fieldButtonHandler.key,
171
+ });
172
+
173
+ return fieldButtonHandler.transform(fieldButton, traverse);
174
+ },
175
+ );
176
+ };
177
+
178
+ export const createAddressFieldHandler = (ctx: ComponentHandlerDeps) => {
179
+ const fieldButtonHandler = createFieldButtonHandler(ctx);
180
+
181
+ return defineComponentHandler<GenericFieldButtonProps>(
182
+ components.privateTemplateAddressPickerField.key,
183
+ (node, traverse) => {
184
+ const [fieldButton] = findAllInstances<FieldButtonProperties>({
185
+ node,
186
+ key: fieldButtonHandler.key,
187
+ });
188
+
189
+ return fieldButtonHandler.transform(fieldButton, traverse);
190
+ },
191
+ );
192
+ };
@@ -0,0 +1,164 @@
1
+ import type {
2
+ FieldCharacterCountProperties,
3
+ FieldFooterProperties,
4
+ FieldHeaderProperties,
5
+ FieldIndicatorProperties,
6
+ } from "@/codegen/component-properties";
7
+ import { defineComponentHandler } from "@/codegen/core";
8
+ import * as metadata from "@/entities/data/__generated__/component-sets";
9
+ import { createSeedReactElement } from "../../element-factories";
10
+ import type { ComponentHandlerDeps } from "../deps.interface";
11
+ import { match } from "ts-pattern";
12
+ import { findAllInstances } from "@/utils/figma-node";
13
+ import { camelCase } from "change-case";
14
+
15
+ export type FieldHeaderProps = FieldIndicatorProps & {
16
+ label?: string;
17
+ labelWeight?: string;
18
+ };
19
+
20
+ /**
21
+ * NOTE: only gives useful 'props' for field-related components but doesn't give fully functional code.
22
+ */
23
+ export const createFieldHeaderHandler = (ctx: ComponentHandlerDeps) => {
24
+ const indicatorHandler = createFieldIndicatorHandler(ctx);
25
+
26
+ return defineComponentHandler<FieldHeaderProperties>(
27
+ metadata.componentFieldHeader.key,
28
+ (node, traverse) => {
29
+ const { componentProperties: props } = node;
30
+
31
+ const [indicator] = findAllInstances<FieldIndicatorProperties>({
32
+ node,
33
+ key: indicatorHandler.key,
34
+ });
35
+
36
+ // only returns some nice common props for Slider, TextField and more
37
+ return createSeedReactElement("__FieldHeader__", {
38
+ label: props["Label#34796:0"].value,
39
+ labelWeight: camelCase(props.Weight.value),
40
+ ...(indicator &&
41
+ (indicatorHandler.transform(indicator, traverse).props as FieldIndicatorProps)),
42
+ } satisfies FieldHeaderProps);
43
+ },
44
+ );
45
+ };
46
+
47
+ type FieldIndicatorProps = {
48
+ required?: boolean;
49
+ showRequiredIndicator?: boolean;
50
+ indicator?: string;
51
+ };
52
+
53
+ /**
54
+ * NOTE: only gives useful 'props' for field-related components but doesn't give fully functional code.
55
+ */
56
+ const createFieldIndicatorHandler = (_ctx: ComponentHandlerDeps) => {
57
+ return defineComponentHandler<FieldIndicatorProperties>(
58
+ metadata.privateComponentFieldHeaderIndicator.key,
59
+ ({ componentProperties: props }) => {
60
+ const { required, showRequiredIndicator, indicator } = match(props.Type.value)
61
+ .with("Required Mark", () => ({
62
+ required: true,
63
+ showRequiredIndicator: true,
64
+ indicator: undefined,
65
+ }))
66
+ .with("Text", () => ({
67
+ required: undefined,
68
+ showRequiredIndicator: undefined,
69
+ indicator: props["Required Label#40606:3"].value,
70
+ }))
71
+ .exhaustive();
72
+
73
+ // only returns some nice common props for Slider, TextField and more
74
+ return createSeedReactElement("__FieldIndicator__", {
75
+ required,
76
+ showRequiredIndicator,
77
+ indicator,
78
+ } satisfies FieldIndicatorProps);
79
+ },
80
+ );
81
+ };
82
+
83
+ export type FieldFooterProps = FieldCharacterCountProps & {
84
+ description?: string;
85
+ maxGraphemeCount?: number;
86
+ invalid?: boolean;
87
+ errorMessage?: string;
88
+ };
89
+
90
+ /**
91
+ * NOTE: only gives useful 'props' for field-related components but doesn't give fully functional code.
92
+ */
93
+ export const createFieldFooterHandler = (ctx: ComponentHandlerDeps) => {
94
+ const characterCountHandler = createFieldCharacterCountHandler(ctx);
95
+
96
+ return defineComponentHandler<FieldFooterProperties>(
97
+ metadata.componentFieldFooter.key,
98
+ (node, traverse) => {
99
+ const { componentProperties: props } = node;
100
+
101
+ const { description, maxGraphemeCount } = match(props.Type.value)
102
+ .with("Description", () => ({
103
+ description: props["Text#2770:0"].value,
104
+ maxGraphemeCount: undefined,
105
+ }))
106
+ .with("Description With Character Count", () => ({
107
+ description: props["Text#2770:0"].value,
108
+ maxGraphemeCount: undefined,
109
+ }))
110
+ .with("Character Count", () => {
111
+ const [characterCount] = findAllInstances<FieldCharacterCountProperties>({
112
+ node,
113
+ key: characterCountHandler.key,
114
+ });
115
+
116
+ return {
117
+ description: undefined,
118
+ ...(characterCount &&
119
+ (characterCountHandler.transform(characterCount, traverse)
120
+ .props as FieldCharacterCountProps)),
121
+ };
122
+ })
123
+ .exhaustive();
124
+
125
+ const { errorMessage, invalid } = match(props.Error.value === "true")
126
+ .with(true, () => ({
127
+ invalid: true,
128
+ errorMessage: props["Error Text#32821:0"].value,
129
+ }))
130
+ .with(false, () => ({
131
+ invalid: undefined,
132
+ errorMessage: undefined,
133
+ }))
134
+ .exhaustive();
135
+
136
+ // only returns some nice common props for Slider, TextField and more
137
+ return createSeedReactElement("__FieldFooter__", {
138
+ description,
139
+ maxGraphemeCount,
140
+ invalid,
141
+ errorMessage,
142
+ } satisfies FieldFooterProps);
143
+ },
144
+ );
145
+ };
146
+
147
+ type FieldCharacterCountProps = {
148
+ maxGraphemeCount?: number;
149
+ };
150
+
151
+ /**
152
+ * NOTE: only gives useful 'props' for field-related components but doesn't give fully functional code.
153
+ */
154
+ const createFieldCharacterCountHandler = (_ctx: ComponentHandlerDeps) => {
155
+ return defineComponentHandler<FieldCharacterCountProperties>(
156
+ metadata.privateComponentFieldFooterCharacterCount.key,
157
+ ({ componentProperties: props }) => {
158
+ // only returns some nice common props for Slider, TextField and more
159
+ return createSeedReactElement("__FieldCharacterCount__", {
160
+ maxGraphemeCount: Number(props["Max Count#40960:4"].value),
161
+ } satisfies FieldCharacterCountProps);
162
+ },
163
+ );
164
+ };
@@ -0,0 +1,45 @@
1
+ import type {
2
+ FloatingActionButtonButtonItemProperties,
3
+ FloatingActionButtonMenuItemProperties,
4
+ FloatingActionButtonProperties,
5
+ } from "@/codegen/component-properties";
6
+ import { defineComponentHandler } from "@/codegen/core";
7
+ import * as metadata from "@/entities/data/__generated__/component-sets";
8
+ import { createLocalSnippetHelper } from "../../element-factories";
9
+ import type { ComponentHandlerDeps } from "../deps.interface";
10
+ import { findAllInstances } from "@/utils/figma-node";
11
+
12
+ const { createLocalSnippetElement } = createLocalSnippetHelper("floating-action-button");
13
+
14
+ export const createFloatingActionButtonHandler = (ctx: ComponentHandlerDeps) =>
15
+ defineComponentHandler<FloatingActionButtonProperties>(
16
+ metadata.componentFloatingActionButton.key,
17
+ (node) => {
18
+ const [button] = findAllInstances<FloatingActionButtonButtonItemProperties>({
19
+ node,
20
+ key: metadata.privateComponentItemButtonType.key,
21
+ });
22
+ const [menu] = findAllInstances<FloatingActionButtonMenuItemProperties>({
23
+ node,
24
+ key: metadata.privateComponentItemMenuType.key,
25
+ });
26
+
27
+ const commonProps = (() => {
28
+ if (button)
29
+ return {
30
+ icon: ctx.iconHandler.transform(button.componentProperties["Icon#29766:18"]),
31
+ extended: button.componentProperties.Extended.value === "True",
32
+ label: button.componentProperties["Label#29808:0"].value,
33
+ };
34
+
35
+ if (menu)
36
+ return {
37
+ icon: ctx.iconHandler.transform(menu.componentProperties["Icon#29766:0"]),
38
+ extended: menu.componentProperties.Extended.value === "True",
39
+ label: menu.componentProperties["Label#29766:9"].value,
40
+ };
41
+ })();
42
+
43
+ return createLocalSnippetElement("FloatingActionButton", commonProps);
44
+ },
45
+ );
@@ -0,0 +1,73 @@
1
+ import type { HelpBubbleProperties } from "@/codegen/component-properties";
2
+ import { defineComponentHandler } 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
+
7
+ const { createLocalSnippetElement } = createLocalSnippetHelper("help-bubble");
8
+ const { createLocalSnippetElement: createLocalSnippetElementTrigger } =
9
+ createLocalSnippetHelper("action-button");
10
+
11
+ export const createHelpBubbleHandler = (_ctx: ComponentHandlerDeps) =>
12
+ defineComponentHandler<HelpBubbleProperties>(
13
+ metadata.componentHelpBubble.key,
14
+ ({ componentProperties: props }) => {
15
+ const placement:
16
+ | "top"
17
+ | "right"
18
+ | "bottom"
19
+ | "left"
20
+ | "top-end"
21
+ | "top-start"
22
+ | "right-end"
23
+ | "right-start"
24
+ | "bottom-end"
25
+ | "bottom-start"
26
+ | "left-end"
27
+ | "left-start" = (() => {
28
+ switch (props.Placement.value) {
29
+ case "Bottom-Left":
30
+ return "top-start";
31
+ case "Bottom-Center":
32
+ return "top";
33
+ case "Bottom-Right":
34
+ return "top-end";
35
+ case "Left-Top":
36
+ return "right-start";
37
+ case "Left-Center":
38
+ return "right";
39
+ case "Left-Bottom":
40
+ return "right-end";
41
+ case "Top-Left":
42
+ return "bottom-start";
43
+ case "Top-Center":
44
+ return "bottom";
45
+ case "Top-Right":
46
+ return "bottom-end";
47
+ case "Right-Top":
48
+ return "left-start";
49
+ case "Right-Center":
50
+ return "left";
51
+ case "Right-Bottom":
52
+ return "left-end";
53
+ }
54
+ })();
55
+
56
+ const commonProps = {
57
+ title: props["Title#62535:0"].value,
58
+ ...(props["Show Description#62499:0"].value && {
59
+ description: props["Description#62535:98"].value,
60
+ }),
61
+ defaultOpen: true,
62
+ showCloseButton: props["Show Close Button#40538:0"].value,
63
+ placement,
64
+ };
65
+
66
+ return createLocalSnippetElement(
67
+ "HelpBubbleTrigger",
68
+ commonProps,
69
+ createLocalSnippetElementTrigger("ActionButton", {}, "HelpBubble 열기"),
70
+ { comment: "필요에 따라 HelpBubbleAnchor로 변경하여 사용하세요." },
71
+ );
72
+ },
73
+ );
@@ -0,0 +1,20 @@
1
+ import { defineComponentHandler } from "@/codegen/core";
2
+ import { camelCase } from "change-case";
3
+ import { createLocalSnippetHelper } from "../../element-factories";
4
+ import type { ComponentHandlerDeps } from "../deps.interface";
5
+ import type { IdentityPlaceholderProperties } from "@/codegen/component-properties";
6
+ import * as metadata from "@/entities/data/__generated__/component-sets";
7
+
8
+ const { createLocalSnippetElement } = createLocalSnippetHelper("identity-placeholder");
9
+
10
+ export const createIdentityPlaceholderHandler = (_ctx: ComponentHandlerDeps) =>
11
+ defineComponentHandler<IdentityPlaceholderProperties>(
12
+ metadata.privateComponentIdentityPlaceholder.key,
13
+ ({ componentProperties: props }) => {
14
+ const commonProps = {
15
+ identity: camelCase(props.Identity.value),
16
+ };
17
+
18
+ return createLocalSnippetElement("IdentityPlaceholder", commonProps);
19
+ },
20
+ );
@@ -0,0 +1,147 @@
1
+ import type {
2
+ BadgeProperties,
3
+ ContentPlaceholderProperties,
4
+ ImageFrameIconProperties,
5
+ ImageFrameOverlayIndicatorProperties,
6
+ ImageFrameProperties,
7
+ ImageFrameReactionButtonProperties,
8
+ } from "@/codegen/component-properties";
9
+ import { defineComponentHandler } from "@/codegen/core";
10
+ import * as metadata from "@/entities/data/__generated__/component-sets";
11
+ import * as components from "@/entities/data/__generated__/components";
12
+ import { findAll, findAllInstances, findOne } from "@/utils/figma-node";
13
+ import { createSeedReactElement } from "../../element-factories";
14
+ import type { ComponentHandlerDeps } from "../deps.interface";
15
+ import { createBadgeHandler } from "@/codegen/targets/react/component/handlers/badge";
16
+ import { createContentPlaceholderHandler } from "@/codegen/targets/react/component/handlers/content-placeholder";
17
+
18
+ const CORNER_CONFIGS = [
19
+ {
20
+ showKey: "ㄴ Left Top#58686:165",
21
+ placement: "top-start",
22
+ },
23
+ {
24
+ showKey: "ㄴ Right Top#58686:198",
25
+ placement: "top-end",
26
+ },
27
+ {
28
+ showKey: "ㄴ Left Bottom#58686:231",
29
+ placement: "bottom-start",
30
+ },
31
+ {
32
+ showKey: "ㄴ Right Bottom#58686:264",
33
+ placement: "bottom-end",
34
+ },
35
+ ] as const satisfies ReadonlyArray<{
36
+ showKey: keyof ImageFrameProperties;
37
+ placement: string;
38
+ }>;
39
+
40
+ function formatRatio(ratioStr: `${number}:${number}`): string {
41
+ const [w, h] = ratioStr.split(":");
42
+
43
+ return `${w} / ${h}`;
44
+ }
45
+
46
+ export const createImageFrameBadgeHandler = (ctx: ComponentHandlerDeps) => {
47
+ const badgeHandler = createBadgeHandler(ctx);
48
+
49
+ return defineComponentHandler<{}>(components.componentImageFrameBadge.key, (node, traverse) => {
50
+ const [badge] = findAllInstances<BadgeProperties>({
51
+ node,
52
+ key: badgeHandler.key,
53
+ });
54
+
55
+ if (!badge) throw new Error("Badge component not found within ImageFrameBadge");
56
+
57
+ return { ...badgeHandler.transform(badge, traverse), tag: "ImageFrameBadge" };
58
+ });
59
+ };
60
+
61
+ export const createImageFrameReactionButtonHandler = (_ctx: ComponentHandlerDeps) => {
62
+ return defineComponentHandler<ImageFrameReactionButtonProperties>(
63
+ metadata.componentImageFrameReactionButton.key,
64
+ ({ componentProperties: props }) => {
65
+ return createSeedReactElement("ImageFrameReactionButton", {
66
+ ...(props.Selected.value === "True" && { defaultPressed: true }),
67
+ });
68
+ },
69
+ );
70
+ };
71
+
72
+ export const createImageFrameOverlayIndicatorHandler = (_ctx: ComponentHandlerDeps) => {
73
+ return defineComponentHandler<ImageFrameOverlayIndicatorProperties>(
74
+ components.componentImageFrameOverlayIndicator.key,
75
+ ({ componentProperties: props }) => {
76
+ return createSeedReactElement("ImageFrameIndicator", undefined, props["Text#58708:0"].value);
77
+ },
78
+ );
79
+ };
80
+
81
+ export const createImageFrameIconHandler = (ctx: ComponentHandlerDeps) => {
82
+ return defineComponentHandler<ImageFrameIconProperties>(
83
+ components.componentImageFrameIcon.key,
84
+ ({ componentProperties: props }) => {
85
+ return createSeedReactElement("ImageFrameIcon", {
86
+ svg: ctx.iconHandler.transform(props["Icon#58686:297"]),
87
+ });
88
+ },
89
+ );
90
+ };
91
+
92
+ export const createImageFrameHandler = (ctx: ComponentHandlerDeps) => {
93
+ const contentPlaceholderHandler = createContentPlaceholderHandler(ctx);
94
+
95
+ return defineComponentHandler<ImageFrameProperties>(
96
+ metadata.componentImageFrame.key,
97
+ (node, traverse) => {
98
+ const props = node.componentProperties;
99
+
100
+ const [placeholder] = findAllInstances<ContentPlaceholderProperties>({
101
+ node,
102
+ key: contentPlaceholderHandler.key,
103
+ });
104
+
105
+ const floaters = [];
106
+ for (const { showKey, placement } of CORNER_CONFIGS) {
107
+ if (!props[showKey].value) continue;
108
+
109
+ const slotName = showKey.split("#")[0];
110
+ const slotNode = findOne(node, (n) => "name" in n && n.name === slotName);
111
+ if (!slotNode) continue;
112
+
113
+ const child = traverse(slotNode);
114
+ if (!child) continue;
115
+
116
+ floaters.push(createSeedReactElement("ImageFrameFloater", { placement }, child));
117
+ }
118
+
119
+ const commonProps = {
120
+ src: `https://placehold.co/${node.absoluteBoundingBox?.width ?? 100}x${node.absoluteBoundingBox?.height ?? 100}`,
121
+ alt: "",
122
+ ratio: formatRatio(props.Ratio.value),
123
+
124
+ ...(props.Rounded.value === "True" && {
125
+ borderRadius: ctx.valueResolver.getFormattedValue.topLeftRadius(node),
126
+ }),
127
+
128
+ ...(placeholder && {
129
+ fallback: contentPlaceholderHandler.transform(placeholder, traverse),
130
+ }),
131
+
132
+ ...(node.layoutGrow === 1
133
+ ? { flexGrow: true }
134
+ : node.layoutAlign === "STRETCH"
135
+ ? { alignSelf: "stretch" }
136
+ : { width: ctx.valueResolver.getFormattedValue.width(node) }),
137
+ };
138
+
139
+ return createSeedReactElement(
140
+ "ImageFrame",
141
+ commonProps,
142
+ props["Show Overlay#58686:33"].value && floaters.length > 0 ? floaters : undefined,
143
+ { comment: "alt 텍스트를 제공해야 합니다." },
144
+ );
145
+ },
146
+ );
147
+ };
@@ -0,0 +1,43 @@
1
+ export * from "./action-button";
2
+ export * from "./alert-dialog";
3
+ export * from "./app-bar";
4
+ export * from "./avatar";
5
+ export * from "./avatar-stack";
6
+ export * from "./badge";
7
+ export * from "./bottom-sheet";
8
+ export * from "./callout";
9
+ export * from "./checkbox";
10
+ export * from "./checkmark";
11
+ export * from "./chip";
12
+ export * from "./content-placeholder";
13
+ export * from "./contextual-floating-button";
14
+ export * from "./divider";
15
+ export * from "./field-button";
16
+ export * from "./floating-action-button";
17
+ export * from "./help-bubble";
18
+ export * from "./identity-placeholder";
19
+ export * from "./image-frame";
20
+ export * from "./legacy-select-box";
21
+ export * from "./legacy-text-field";
22
+ export * from "./list-header";
23
+ export * from "./list-item";
24
+ export * from "./manner-temp";
25
+ export * from "./manner-temp-badge";
26
+ export * from "./menu-sheet";
27
+ export * from "./page-banner";
28
+ export * from "./progress-circle";
29
+ export * from "./radio-group";
30
+ export * from "./radiomark";
31
+ export * from "./reaction-button";
32
+ export * from "./result-section";
33
+ export * from "./segmented-control";
34
+ export * from "./select-box";
35
+ export * from "./skeleton";
36
+ export * from "./slider";
37
+ export * from "./snackbar";
38
+ export * from "./switch";
39
+ export * from "./switchmark";
40
+ export * from "./tabs";
41
+ export * from "./tag-group";
42
+ export * from "./text-field";
43
+ export * from "./toggle-button";