@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,38 @@
1
+ import type {
2
+ AvatarProperties,
3
+ AvatarStackProperties,
4
+ } from "@/codegen/component-properties";
5
+ import { defineComponentHandler } from "@/codegen/core";
6
+ import * as metadata from "@/entities/data/__generated__/component-sets";
7
+ import { findAllInstances } from "@/utils/figma-node";
8
+ import { createLocalSnippetHelper } from "../../element-factories";
9
+ import type { ComponentHandlerDeps } from "../deps.interface";
10
+ import { createAvatarHandler } from "./avatar";
11
+
12
+ const { createLocalSnippetElement } = createLocalSnippetHelper("avatar");
13
+
14
+ export const createAvatarStackHandler = (ctx: ComponentHandlerDeps) => {
15
+ const avatarHandler = createAvatarHandler(ctx);
16
+
17
+ return defineComponentHandler<AvatarStackProperties>(
18
+ metadata.componentAvatarStack.key,
19
+ (node, traverse) => {
20
+ const avatarNodes = findAllInstances<AvatarProperties>({
21
+ node,
22
+ key: avatarHandler.key,
23
+ });
24
+
25
+ const { componentProperties: props } = node;
26
+
27
+ const commonProps = {
28
+ size: props.Size.value,
29
+ };
30
+
31
+ const avatarStackChildren = avatarNodes.map((avatarNode) =>
32
+ avatarHandler.transform(avatarNode, traverse),
33
+ );
34
+
35
+ return createLocalSnippetElement("AvatarStack", commonProps, avatarStackChildren);
36
+ },
37
+ );
38
+ };
@@ -0,0 +1,58 @@
1
+ import type {
2
+ AvatarProperties,
3
+ IdentityPlaceholderProperties,
4
+ } from "@/codegen/component-properties";
5
+ import { createElement, defineComponentHandler } from "@/codegen/core";
6
+ import * as metadata from "@/entities/data/__generated__/component-sets";
7
+ import { findAllInstances } from "@/utils/figma-node";
8
+ import { createLocalSnippetHelper } from "../../element-factories";
9
+ import type { ComponentHandlerDeps } from "../deps.interface";
10
+ import { createIdentityPlaceholderHandler } from "./identity-placeholder";
11
+ import { camelCase } from "change-case";
12
+
13
+ const { createLocalSnippetElement } = createLocalSnippetHelper("avatar");
14
+
15
+ export const createAvatarHandler = (ctx: ComponentHandlerDeps) => {
16
+ const identityPlaceholderHandler = createIdentityPlaceholderHandler(ctx);
17
+
18
+ return defineComponentHandler<AvatarProperties>(
19
+ metadata.componentAvatar.key,
20
+ (node, traverse) => {
21
+ const [placeholder] = findAllInstances<IdentityPlaceholderProperties>({
22
+ node,
23
+ key: identityPlaceholderHandler.key,
24
+ });
25
+ const { componentProperties: props } = node;
26
+
27
+ const avatarHasSrc = props["Has Image Contents#33407:0"].value;
28
+
29
+ const commonProps = {
30
+ ...(avatarHasSrc && {
31
+ // Placeholder
32
+ src: `https://placehold.co/${props.Size.value}x${props.Size.value}`,
33
+ }),
34
+ ...(placeholder && {
35
+ fallback: identityPlaceholderHandler.transform(placeholder, traverse),
36
+ }),
37
+ ...(props["Badge"].value !== "None" && {
38
+ badgeMask: camelCase(props["Badge"].value),
39
+ }),
40
+ size: props.Size.value,
41
+ };
42
+
43
+ return createLocalSnippetElement(
44
+ "Avatar",
45
+ commonProps,
46
+ props["Badge"].value === "None"
47
+ ? undefined
48
+ : createLocalSnippetElement(
49
+ "AvatarBadge",
50
+ { asChild: true },
51
+ createElement("img", { src: "https://placehold.co/20x20" }),
52
+ { comment: "뱃지를 설명하는 alt 텍스트를 제공해야 합니다." },
53
+ ),
54
+ { comment: avatarHasSrc ? "alt 텍스트를 제공해야 합니다." : undefined },
55
+ );
56
+ },
57
+ );
58
+ };
@@ -0,0 +1,18 @@
1
+ import type { BadgeProperties } 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 { createSeedReactElement } from "../../element-factories";
6
+ import type { ComponentHandlerDeps } from "../deps.interface";
7
+ import { handleSizeProp } from "../size";
8
+
9
+ export const createBadgeHandler = (_ctx: ComponentHandlerDeps) =>
10
+ defineComponentHandler<BadgeProperties>(metadata.componentBadge.key, ({ componentProperties: props }) => {
11
+ const commonProps = {
12
+ size: handleSizeProp(props.Size.value),
13
+ tone: camelCase(props.Tone.value),
14
+ variant: camelCase(props.Variant.value),
15
+ };
16
+
17
+ return createSeedReactElement("Badge", commonProps, props["Label#1584:0"].value);
18
+ });
@@ -0,0 +1,74 @@
1
+ import type { BottomSheetProperties } from "@/codegen/component-properties";
2
+ import { createElement, defineComponentHandler } from "@/codegen/core";
3
+ import * as metadata from "@/entities/data/__generated__/component-sets";
4
+ import { match } from "ts-pattern";
5
+ import { createLocalSnippetHelper } from "../../element-factories";
6
+ import type { ComponentHandlerDeps } from "../deps.interface";
7
+ import { findAllInstances } from "@/utils/figma-node";
8
+
9
+ const { createLocalSnippetElement } = createLocalSnippetHelper("bottom-sheet");
10
+ const { createLocalSnippetElement: createLocalSnippetElementTrigger } =
11
+ createLocalSnippetHelper("action-button");
12
+
13
+ export const createBottomSheetHandler = (_ctx: ComponentHandlerDeps) =>
14
+ defineComponentHandler<BottomSheetProperties>(
15
+ metadata.componentBottomSheet.key,
16
+ (node, traverse) => {
17
+ const props = node.componentProperties;
18
+ const headerAlign = match(props["Header Layout"].value)
19
+ .with("Bottom Left", "Top Left", () => "left")
20
+ .with("Bottom Center", "Top Center", () => "center")
21
+ .with("None", () => undefined)
22
+ .exhaustive();
23
+
24
+ const contentProps = {
25
+ title: props["Title#19787:3"].value,
26
+ ...(props["Show Description#25192:0"].value === true && {
27
+ description: props["Description#19787:7"].value,
28
+ }),
29
+ showHandle: props["Show Handle#49774:6"].value,
30
+ showCloseButton: props["Show Close Button#19787:11"].value,
31
+ };
32
+
33
+ const bodyNodes = findAllInstances({
34
+ node,
35
+ key: props["Contents#25320:0"].componentKey,
36
+ });
37
+
38
+ const bottomSheetBody =
39
+ bodyNodes.length === 1
40
+ ? createLocalSnippetElement("BottomSheetBody", {}, bodyNodes[0].children.map(traverse))
41
+ : createLocalSnippetElement(
42
+ "BottomSheetBody",
43
+ {},
44
+ createElement("div", undefined, "No content available"),
45
+ );
46
+
47
+ const footerNodes = findAllInstances({
48
+ node,
49
+ // TODO: Bottom Action Bar (WIP) handler의 키. 해당 컴포넌트(템플릿) 핸들러 작성 시 handler.transform()으로 대체
50
+ key: metadata.componentBottomActionBarFigmaOnly.key,
51
+ });
52
+
53
+ const bottomSheetFooter =
54
+ props["Show Footer#25162:14"].value && footerNodes.length === 1
55
+ ? createLocalSnippetElement(
56
+ "BottomSheetFooter",
57
+ {},
58
+ footerNodes[0].children.map(traverse),
59
+ )
60
+ : undefined;
61
+
62
+ return createLocalSnippetElement("BottomSheetRoot", { defaultOpen: true, headerAlign }, [
63
+ createLocalSnippetElement(
64
+ "BottomSheetTrigger",
65
+ { asChild: true },
66
+ createLocalSnippetElementTrigger("ActionButton", {}, "BottomSheet 열기"),
67
+ ),
68
+ createLocalSnippetElement("BottomSheetContent", contentProps, [
69
+ bottomSheetBody,
70
+ bottomSheetFooter,
71
+ ]),
72
+ ]);
73
+ },
74
+ );
@@ -0,0 +1,88 @@
1
+ import type { CalloutProperties } from "@/codegen/component-properties";
2
+ import { defineComponentHandler } from "@/codegen/core";
3
+ import * as metadata from "@/entities/data/__generated__/component-sets";
4
+ import type { NormalizedTextNode } from "@/normalizer";
5
+ import { camelCase } from "change-case";
6
+ import { createLocalSnippetHelper } from "../../element-factories";
7
+ import type { ComponentHandlerDeps } from "../deps.interface";
8
+ import { match } from "ts-pattern";
9
+
10
+ const { createLocalSnippetElement } = createLocalSnippetHelper("callout");
11
+
12
+ export const createCalloutHandler = (ctx: ComponentHandlerDeps) =>
13
+ defineComponentHandler<CalloutProperties>(
14
+ metadata.componentCallout.key,
15
+ ({ componentProperties: props, children }) => {
16
+ const tag = match(props.Interaction.value)
17
+ .with("Display", () => "Callout")
18
+ .with("Actionable", () => "ActionableCallout")
19
+ .with("Dismissible", () => "DismissibleCallout")
20
+ .exhaustive();
21
+
22
+ const textNode = children.find((child) => child.type === "TEXT") as NormalizedTextNode | null;
23
+
24
+ if (!textNode) {
25
+ return createLocalSnippetElement(tag, undefined, undefined, {
26
+ comment: "내용을 제공해주세요.",
27
+ });
28
+ }
29
+
30
+ const slices = textNode.segments;
31
+
32
+ let title: string | undefined;
33
+ let description: string | undefined;
34
+ let linkLabel: string | undefined;
35
+
36
+ switch (slices.length) {
37
+ case 1: {
38
+ description = slices[0]?.characters.trim();
39
+
40
+ break;
41
+ }
42
+ case 2: {
43
+ const firstSlice = slices[0];
44
+ const secondSlice = slices[1];
45
+
46
+ if (firstSlice?.style.fontWeight === 700) {
47
+ title = firstSlice?.characters.trim();
48
+ description = secondSlice?.characters.trim();
49
+ break;
50
+ }
51
+
52
+ description = firstSlice?.characters.trim();
53
+
54
+ if (tag !== "ActionableCallout") {
55
+ linkLabel = secondSlice?.characters.trim();
56
+ }
57
+
58
+ break;
59
+ }
60
+ case 3: {
61
+ title = slices[0]?.characters.trim();
62
+ description = slices[1]?.characters.trim();
63
+
64
+ if (tag !== "ActionableCallout") {
65
+ linkLabel = slices[2]?.characters.trim();
66
+ }
67
+
68
+ break;
69
+ }
70
+ }
71
+
72
+ const commonProps = {
73
+ tone: camelCase(props.Tone.value),
74
+ title,
75
+ description,
76
+ ...(linkLabel && {
77
+ linkProps: {
78
+ children: linkLabel,
79
+ },
80
+ }),
81
+ ...(props["Show Prefix Icon#35087:1"].value && {
82
+ prefixIcon: ctx.iconHandler.transform(props["Prefix Icon#35087:0"]),
83
+ }),
84
+ };
85
+
86
+ return createLocalSnippetElement(tag, commonProps);
87
+ },
88
+ );
@@ -0,0 +1,129 @@
1
+ import type {
2
+ CheckboxGroupFieldProperties,
3
+ CheckboxProperties,
4
+ FieldFooterProperties,
5
+ FieldHeaderProperties,
6
+ } from "@/codegen/component-properties";
7
+ import { defineComponentHandler } from "@/codegen/core";
8
+ import * as metadata from "@/entities/data/__generated__/component-sets";
9
+ import { camelCase } from "change-case";
10
+ import { createLocalSnippetHelper } from "../../element-factories";
11
+ import type { ComponentHandlerDeps } from "../deps.interface";
12
+ import { handleSizeProp } from "../size";
13
+ import { match } from "ts-pattern";
14
+ import {
15
+ createFieldFooterHandler,
16
+ createFieldHeaderHandler,
17
+ type FieldFooterProps,
18
+ type FieldHeaderProps,
19
+ } from "@/codegen/targets/react/component/handlers/field";
20
+ import { findAllInstances } from "@/utils/figma-node";
21
+
22
+ const { createLocalSnippetElement } = createLocalSnippetHelper("checkbox");
23
+
24
+ export const createCheckboxHandler = (_ctx: ComponentHandlerDeps) =>
25
+ defineComponentHandler<CheckboxProperties>(
26
+ metadata.componentCheckbox.key,
27
+ ({ componentProperties: props }) => {
28
+ const tone = match(props.Tone.value)
29
+ .with("Neutral", () => "neutral")
30
+ .with("🚫[Deprecated]Brand", () => "brand")
31
+ .exhaustive();
32
+
33
+ const commonProps = {
34
+ label: props["Label#49990:0"].value,
35
+ weight: camelCase(props.Weight.value),
36
+ tone,
37
+ variant: camelCase(props.Shape.value),
38
+ size: handleSizeProp(props.Size.value),
39
+ ...(props.Selected.value === "True" && {
40
+ defaultChecked: true,
41
+ }),
42
+ ...(props.Selected.value === "Indeterminate" && {
43
+ defaultChecked: true,
44
+ indeterminate: true,
45
+ }),
46
+ ...(props.State.value === "Disabled" && {
47
+ disabled: true,
48
+ }),
49
+ };
50
+
51
+ return createLocalSnippetElement("Checkbox", commonProps, undefined, {
52
+ comment: "CheckboxGroup으로 묶어서 사용하는 것을 권장합니다.",
53
+ });
54
+ },
55
+ );
56
+
57
+ export const createCheckboxGroupFieldHandler = (ctx: ComponentHandlerDeps) => {
58
+ const checkboxHandler = createCheckboxHandler(ctx);
59
+ const fieldHeaderHandler = createFieldHeaderHandler(ctx);
60
+ const fieldFooterHandler = createFieldFooterHandler(ctx);
61
+
62
+ return defineComponentHandler<CheckboxGroupFieldProperties>(
63
+ metadata.templateCheckboxField.key,
64
+ (node, traverse) => {
65
+ const { componentProperties: props } = node;
66
+
67
+ const items = findAllInstances<CheckboxProperties>({
68
+ node,
69
+ key: checkboxHandler.key,
70
+ });
71
+ const [fieldHeader] = findAllInstances<FieldHeaderProperties>({
72
+ node,
73
+ key: fieldHeaderHandler.key,
74
+ });
75
+ const [fieldFooter] = findAllInstances<FieldFooterProperties>({
76
+ node,
77
+ key: fieldFooterHandler.key,
78
+ });
79
+
80
+ // maxGraphemeCount / required / invalid can't be props of CheckboxGroup
81
+ const { required: _required, ...headerProps } =
82
+ props["Show Header#40606:8"].value && fieldHeader
83
+ ? (fieldHeaderHandler.transform(fieldHeader, traverse).props as FieldHeaderProps)
84
+ : {};
85
+ const {
86
+ maxGraphemeCount: _maxGraphemeCount,
87
+ invalid: _invalid,
88
+ ...footerProps
89
+ } = props["Show Footer#40606:9"].value && fieldFooter
90
+ ? (fieldFooterHandler.transform(fieldFooter, traverse).props as FieldFooterProps)
91
+ : {};
92
+
93
+ const commonProps = {
94
+ ...headerProps,
95
+ ...footerProps,
96
+ };
97
+
98
+ return createLocalSnippetElement(
99
+ "CheckboxGroup",
100
+ commonProps,
101
+ items.map((item) => {
102
+ const result = checkboxHandler.transform(item, traverse);
103
+
104
+ return {
105
+ ...result,
106
+ meta: {
107
+ ...result.meta,
108
+
109
+ // remove comment from individual Checkbox items
110
+ comment: undefined,
111
+ },
112
+ };
113
+ }),
114
+ {
115
+ comment: [
116
+ headerProps.label
117
+ ? undefined
118
+ : "label을 제공하지 않는 경우 aria-label이나 aria-labelledby 중 하나를 제공해야 합니다.",
119
+ footerProps.errorMessage
120
+ ? "errorMessage를 표시하는 경우, 접근성을 위해 개별 Checkbox 중 무효한 항목에 invalid를 설정해주세요."
121
+ : undefined,
122
+ ]
123
+ .filter(Boolean)
124
+ .join(" "),
125
+ },
126
+ );
127
+ },
128
+ );
129
+ };
@@ -0,0 +1,29 @@
1
+ import type { CheckmarkProperties } 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 } from "../../element-factories";
6
+ import type { ComponentHandlerDeps } from "../deps.interface";
7
+ import { handleSizeProp } from "../size";
8
+ import { match } from "ts-pattern";
9
+
10
+ const { createLocalSnippetElement } = createLocalSnippetHelper("checkbox");
11
+
12
+ export const createCheckmarkHandler = (_ctx: ComponentHandlerDeps) =>
13
+ defineComponentHandler<CheckmarkProperties>(
14
+ metadata.componentCheckmark.key,
15
+ ({ componentProperties: props }) => {
16
+ const tone = match(props.Tone.value)
17
+ .with("Neutral", () => "neutral")
18
+ .with("🚫[Deprecated]Brand", () => "brand")
19
+ .exhaustive();
20
+
21
+ const commonProps = {
22
+ tone,
23
+ variant: camelCase(props.Shape.value),
24
+ size: handleSizeProp(props.Size.value),
25
+ };
26
+
27
+ return createLocalSnippetElement("Checkmark", commonProps);
28
+ },
29
+ );
@@ -0,0 +1,93 @@
1
+ import type {
2
+ AvatarProperties,
3
+ ChipIconSuffixProperties,
4
+ ChipProperties,
5
+ } from "@/codegen/component-properties";
6
+ import { defineComponentHandler } from "@/codegen/core";
7
+ import * as metadata from "@/entities/data/__generated__/component-sets";
8
+ import * as components from "@/entities/data/__generated__/components";
9
+ import { match } from "ts-pattern";
10
+ import { createLocalSnippetHelper, createSeedReactElement } from "../../element-factories";
11
+ import type { ComponentHandlerDeps } from "../deps.interface";
12
+ import { handleSizeProp } from "../size";
13
+ import { camelCase } from "change-case";
14
+ import { findAllInstances } from "@/utils/figma-node";
15
+ import { createAvatarHandler } from "@/codegen/targets/react/component/handlers/avatar";
16
+
17
+ const { createLocalSnippetElement } = createLocalSnippetHelper("chip");
18
+
19
+ const createChipIconSuffixHandler = (ctx: ComponentHandlerDeps) => {
20
+ return defineComponentHandler<ChipIconSuffixProperties>(
21
+ components.componentChipSuffixIcon.key,
22
+ ({ componentProperties }) => {
23
+ return createLocalSnippetElement(
24
+ "Chip.SuffixIcon",
25
+ undefined,
26
+ createSeedReactElement("Icon", {
27
+ svg: ctx.iconHandler.transform(componentProperties["Icon#33203:0"]),
28
+ }),
29
+ );
30
+ },
31
+ );
32
+ };
33
+
34
+ export const createChipHandler = (ctx: ComponentHandlerDeps) => {
35
+ const avatarHandler = createAvatarHandler(ctx);
36
+ const iconSuffixHandler = createChipIconSuffixHandler(ctx);
37
+
38
+ return defineComponentHandler<ChipProperties>(metadata.componentChip.key, (node, traverse) => {
39
+ const props = node.componentProperties;
40
+
41
+ const prefix = match(props["Prefix Type"].value)
42
+ .with("None", "Image", () => undefined)
43
+ .with("Icon", () =>
44
+ createLocalSnippetElement(
45
+ "Chip.PrefixIcon",
46
+ undefined,
47
+ createSeedReactElement("Icon", {
48
+ svg: ctx.iconHandler.transform(props["Prefix Icon#8722:0"]),
49
+ }),
50
+ ),
51
+ )
52
+ .with("Avatar", () => {
53
+ const [avatar] = findAllInstances<AvatarProperties>({
54
+ node,
55
+ key: avatarHandler.key,
56
+ });
57
+ if (!avatar) return undefined;
58
+
59
+ return createLocalSnippetElement(
60
+ "Chip.PrefixAvatar",
61
+ undefined,
62
+ avatarHandler.transform(avatar, traverse),
63
+ );
64
+ })
65
+ .exhaustive();
66
+
67
+ const label = createLocalSnippetElement("Chip.Label", undefined, props["Label#7185:0"].value);
68
+
69
+ const [suffixIcon] = findAllInstances<ChipIconSuffixProperties>({
70
+ node,
71
+ key: components.componentChipSuffixIcon.key,
72
+ });
73
+
74
+ const commonProps = {
75
+ variant: camelCase(props.Variant.value),
76
+ size: handleSizeProp(props.Size.value),
77
+ layout: props["Label#7185:0"].value ? "withText" : "iconOnly",
78
+ ...(props.Selected.value === "True" && {
79
+ defaultChecked: true,
80
+ }),
81
+ ...(props.State.value === "Disabled" && {
82
+ disabled: true,
83
+ }),
84
+ };
85
+
86
+ return createLocalSnippetElement(
87
+ "Chip.Toggle",
88
+ commonProps,
89
+ [prefix, label, suffixIcon ? iconSuffixHandler.transform(suffixIcon, traverse) : undefined],
90
+ { comment: "목적에 따라 Chip.Button, Chip.RadioItem 등으로 바꿔 사용하세요." },
91
+ );
92
+ });
93
+ };
@@ -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 { ContentPlaceholderProperties } from "@/codegen/component-properties";
6
+ import * as metadata from "@/entities/data/__generated__/component-sets";
7
+
8
+ const { createLocalSnippetElement } = createLocalSnippetHelper("content-placeholder");
9
+
10
+ export const createContentPlaceholderHandler = (_ctx: ComponentHandlerDeps) =>
11
+ defineComponentHandler<ContentPlaceholderProperties>(
12
+ metadata.privateComponentContentPlaceholder.key,
13
+ ({ componentProperties: props }) => {
14
+ const commonProps = {
15
+ type: camelCase(props.Type.value),
16
+ };
17
+
18
+ return createLocalSnippetElement("ContentPlaceholder", commonProps);
19
+ },
20
+ );
@@ -0,0 +1,52 @@
1
+ import type { ContextualFloatingButtonProperties } from "@/codegen/component-properties";
2
+ import { defineComponentHandler } from "@/codegen/core";
3
+ import * as metadata from "@/entities/data/__generated__/component-sets";
4
+ import { match } from "ts-pattern";
5
+ import { createLocalSnippetHelper, createSeedReactElement } from "../../element-factories";
6
+ import type { ComponentHandlerDeps } from "../deps.interface";
7
+
8
+ const { createLocalSnippetElement } = createLocalSnippetHelper("contextual-floating-button");
9
+
10
+ export const createContextualFloatingButtonHandler = (ctx: ComponentHandlerDeps) =>
11
+ defineComponentHandler<ContextualFloatingButtonProperties>(
12
+ metadata.componentContextualFloatingButton.key,
13
+ ({ componentProperties: props }) => {
14
+ const states = props.State.value.split("-");
15
+
16
+ const { layout, children } = match(props.Layout.value)
17
+ .with("Icon Only", () => ({
18
+ layout: "iconOnly",
19
+ children: [
20
+ createSeedReactElement("Icon", {
21
+ svg: ctx.iconHandler.transform(props["Icon#28796:0"]),
22
+ }),
23
+ ],
24
+ }))
25
+ .with("Icon First", () => ({
26
+ layout: "withText",
27
+ children: [
28
+ createSeedReactElement("PrefixIcon", {
29
+ svg: ctx.iconHandler.transform(props["Icon#28796:0"]),
30
+ }),
31
+ props["Label#28936:0"].value,
32
+ ],
33
+ }))
34
+ .exhaustive();
35
+
36
+ const commonProps = {
37
+ ...(states.includes("Disabled") && {
38
+ disabled: true,
39
+ }),
40
+ ...(states.includes("Loading") && {
41
+ loading: true,
42
+ }),
43
+ variant: match(props.Variant.value)
44
+ .with("Solid", () => "solid")
45
+ .with("Layer", () => "layer")
46
+ .exhaustive(),
47
+ layout,
48
+ };
49
+
50
+ return createLocalSnippetElement("ContextualFloatingButton", commonProps, children);
51
+ },
52
+ );
@@ -0,0 +1,25 @@
1
+ import type { DividerProperties } from "@/codegen/component-properties";
2
+ import { defineComponentHandler } from "@/codegen/core";
3
+ import * as metadata from "@/entities/data/__generated__/component-sets";
4
+ import { match } from "ts-pattern";
5
+ import { createSeedReactElement } from "../../element-factories";
6
+ import type { ComponentHandlerDeps } from "../deps.interface";
7
+ import { camelCase } from "change-case";
8
+
9
+ export const createDividerHandler = (_ctx: ComponentHandlerDeps) =>
10
+ defineComponentHandler<DividerProperties>(
11
+ metadata.componentDivider.key,
12
+ ({ componentProperties: props }) => {
13
+ const { color } = match(props.Tone.value)
14
+ .with("Neutral Muted", () => ({ color: "stroke.neutralMuted" }))
15
+ .with("Neutral Subtle", () => ({ color: "stroke.neutralSubtle" }))
16
+ .exhaustive();
17
+
18
+ const commonProps = {
19
+ color,
20
+ orientation: camelCase(props.Orientation.value),
21
+ };
22
+
23
+ return createSeedReactElement("Divider", commonProps, undefined);
24
+ },
25
+ );