@seed-design/figma 0.0.2 → 0.0.4

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 (53) hide show
  1. package/lib/index.cjs +556 -471
  2. package/lib/index.d.ts +29 -4
  3. package/lib/index.js +556 -471
  4. package/package.json +2 -2
  5. package/src/component/handlers/action-button.ts +66 -0
  6. package/src/component/handlers/action-chip.ts +71 -0
  7. package/src/component/handlers/action-sheet.ts +74 -0
  8. package/src/component/handlers/app-bar.ts +183 -0
  9. package/src/component/handlers/avatar-stack.ts +35 -0
  10. package/src/component/handlers/avatar.ts +37 -0
  11. package/src/component/handlers/badge.ts +20 -0
  12. package/src/component/handlers/callout.ts +87 -0
  13. package/src/component/handlers/checkbox.ts +32 -0
  14. package/src/component/handlers/chip-tabs.ts +51 -0
  15. package/src/component/handlers/control-chip.ts +75 -0
  16. package/src/component/handlers/error-state.ts +37 -0
  17. package/src/component/handlers/extended-action-sheet.ts +86 -0
  18. package/src/component/handlers/extended-fab.ts +24 -0
  19. package/src/component/handlers/fab.ts +17 -0
  20. package/src/component/handlers/help-bubble.ts +66 -0
  21. package/src/component/handlers/identity-placeholder.ts +16 -0
  22. package/src/component/handlers/inline-banner.ts +83 -0
  23. package/src/component/handlers/manner-temp-badge.ts +17 -0
  24. package/src/component/handlers/multiline-text-field.ts +80 -0
  25. package/src/component/handlers/progress-circle.ts +49 -0
  26. package/src/component/handlers/reaction-button.ts +36 -0
  27. package/src/component/handlers/segmented-control.ts +51 -0
  28. package/src/component/handlers/select-box.ts +76 -0
  29. package/src/component/handlers/skeleton.ts +51 -0
  30. package/src/component/handlers/snackbar.ts +21 -0
  31. package/src/component/handlers/switch.ts +29 -0
  32. package/src/component/handlers/tabs.ts +107 -0
  33. package/src/component/handlers/text-button.ts +57 -0
  34. package/src/component/handlers/text-field.ts +108 -0
  35. package/src/component/handlers/toggle-button.ts +44 -0
  36. package/src/component/index.ts +32 -1644
  37. package/src/component/type-helper.ts +11 -0
  38. package/src/generate-code.ts +183 -145
  39. package/src/icon.ts +2 -2
  40. package/src/index.ts +1 -2
  41. package/src/jsx.ts +1 -1
  42. package/src/layout.ts +23 -281
  43. package/src/normalizer/from-plugin.ts +24 -4
  44. package/src/normalizer/from-rest.ts +22 -4
  45. package/src/normalizer/index.ts +3 -0
  46. package/src/normalizer/types.ts +3 -1
  47. package/src/{color.ts → props/color.ts} +1 -1
  48. package/src/props/layout.ts +292 -0
  49. package/src/{sizing.ts → props/sizing.ts} +17 -17
  50. package/src/{text.ts → props/text.ts} +2 -1
  51. package/src/{variable.ts → props/variable.ts} +1 -1
  52. package/src/{util.ts → utils/common.ts} +0 -2
  53. package/src/{node-util.ts → utils/figma-node.ts} +1 -1
@@ -0,0 +1,75 @@
1
+ import { match } from "ts-pattern";
2
+ import * as metadata from "../../data/__generated__/component-sets";
3
+ import { createIconTagNameFromKey } from "../../icon";
4
+ import { createElement } from "../../jsx";
5
+ import { handleSize } from "../properties";
6
+ import type { ControlChipProperties } from "../type";
7
+ import type { ComponentHandler } from "../type-helper";
8
+
9
+ export const controlChipHandler: ComponentHandler<ControlChipProperties> = {
10
+ key: metadata.controlChip.key,
11
+ codegen: async ({ componentProperties: props }) => {
12
+ const states = props.State.value.split("-");
13
+
14
+ const { layout, children } = await match(props.Layout.value)
15
+ .with("Icon Only", async () => ({
16
+ layout: "iconOnly",
17
+ children: [
18
+ createElement("Icon", {
19
+ svg: createElement(createIconTagNameFromKey(props["Icon#8722:41"].componentKey)),
20
+ }),
21
+ ],
22
+ }))
23
+ .with("Icon First", async () => ({
24
+ layout: "withText",
25
+ children: [
26
+ createElement("PrefixIcon", {
27
+ svg: createElement(createIconTagNameFromKey(props["Prefix Icon#8722:0"].componentKey)),
28
+ }),
29
+ props["Label#7185:0"].value,
30
+ ],
31
+ }))
32
+ .with("Icon Last", async () => ({
33
+ layout: "withText",
34
+ children: [
35
+ props["Label#7185:0"].value,
36
+ createElement("SuffixIcon", {
37
+ svg: createElement(createIconTagNameFromKey(props["Suffix Icon#8722:82"].componentKey)),
38
+ }),
39
+ ],
40
+ }))
41
+ .with("Icon Both", async () => ({
42
+ layout: "withText",
43
+ children: [
44
+ createElement("PrefixIcon", {
45
+ svg: createElement(createIconTagNameFromKey(props["Prefix Icon#8722:0"].componentKey)),
46
+ }),
47
+ props["Label#7185:0"].value,
48
+ createElement("SuffixIcon", {
49
+ svg: createElement(createIconTagNameFromKey(props["Suffix Icon#8722:82"].componentKey)),
50
+ }),
51
+ ],
52
+ }))
53
+ .with("Text Only", () => ({
54
+ layout: "withText",
55
+ children: props["Label#7185:0"].value,
56
+ }))
57
+ .exhaustive();
58
+
59
+ const commonProps = {
60
+ size: handleSize(props.Size.value),
61
+ layout,
62
+ ...(states.includes("Selected") && {
63
+ defaultChecked: true,
64
+ }),
65
+ ...(states.includes("Disabled") && {
66
+ disabled: true,
67
+ }),
68
+ ...(props["Show Count#7185:42"].value && {
69
+ count: Number(props["Count#7185:21"].value),
70
+ }),
71
+ };
72
+
73
+ return createElement("ControlChip.Toggle", commonProps, children);
74
+ },
75
+ };
@@ -0,0 +1,37 @@
1
+ import { camelCase } from "change-case";
2
+ import * as metadata from "../../data/__generated__/component-sets";
3
+ import { createElement } from "../../jsx";
4
+ import { findAllInstances } from "../../utils/figma-node";
5
+ import type { ActionButtonProperties, ErrorStateProperties } from "../type";
6
+ import type { ComponentHandler } from "../type-helper";
7
+ import { actionButtonHandler } from "./action-button";
8
+
9
+ export const errorStateHandler: ComponentHandler<ErrorStateProperties> = {
10
+ key: metadata.errorState.key,
11
+ codegen: async (node) => {
12
+ const props = node.componentProperties;
13
+
14
+ const [actionButtonNode] = await findAllInstances<ActionButtonProperties>({
15
+ node,
16
+ key: actionButtonHandler.key,
17
+ });
18
+
19
+ const commonProps = {
20
+ variant: camelCase(props.Variant.value),
21
+ ...(props.Layout.value === "With Title" && {
22
+ title: props["Title#16237:0"].value,
23
+ }),
24
+ description: props["Description#16237:5"].value,
25
+ ...(actionButtonNode && {
26
+ primaryActionProps: {
27
+ children: (await actionButtonHandler.codegen(actionButtonNode)).children[0],
28
+ },
29
+ secondaryActionProps: {
30
+ children: props["Secondary Action Label#17042:0"].value,
31
+ },
32
+ }),
33
+ };
34
+
35
+ return createElement("ErrorState", commonProps);
36
+ },
37
+ };
@@ -0,0 +1,86 @@
1
+ import { camelCase } from "change-case";
2
+ import * as metadata from "../../data/__generated__/component-sets";
3
+ import { createIconTagNameFromKey } from "../../icon";
4
+ import { createElement } from "../../jsx";
5
+ import { findAllInstances } from "../../utils/figma-node";
6
+ import type {
7
+ ExtendedActionSheetGroupProperties,
8
+ ExtendedActionSheetItemProperties,
9
+ ExtendedActionSheetProperties,
10
+ } from "../type";
11
+ import type { ComponentHandler } from "../type-helper";
12
+
13
+ export const extendedActionSheetHandler: ComponentHandler<ExtendedActionSheetProperties> = {
14
+ key: metadata.extendedActionSheet.key,
15
+ codegen: async (node) => {
16
+ const { componentProperties: props } = node;
17
+
18
+ const groups = findAllInstances<ExtendedActionSheetGroupProperties>({
19
+ node,
20
+ key: extendedActionSheetGroupHandler.key,
21
+ });
22
+
23
+ const contentChildren = await Promise.all(groups.map(extendedActionSheetGroupHandler.codegen));
24
+
25
+ const title = props["Show Title#17043:12"].value ? props["Title#14599:0"].value : undefined;
26
+
27
+ const content = createElement(
28
+ "ExtendedActionSheetContent",
29
+ { title },
30
+ contentChildren,
31
+ title
32
+ ? undefined
33
+ : "title을 제공하지 않는 경우 aria-label이나 aria-labelledby 중 하나를 제공해야 합니다.",
34
+ );
35
+
36
+ const trigger = createElement(
37
+ "ExtendedActionSheetTrigger",
38
+ { asChild: true },
39
+ createElement(
40
+ "ActionButton",
41
+ undefined,
42
+ "열기",
43
+ "ExtendedActionSheet을 여는 요소를 제공해주세요.",
44
+ ),
45
+ );
46
+
47
+ return createElement("ExtendedActionSheet", undefined, [trigger, content]);
48
+ },
49
+ };
50
+
51
+ const extendedActionSheetGroupHandler: ComponentHandler<ExtendedActionSheetGroupProperties> = {
52
+ key: "2a504a1c6b7810d5e652862dcba2cb7048f9eb16",
53
+ codegen: async (node) => {
54
+ const items = findAllInstances<ExtendedActionSheetItemProperties>({
55
+ node,
56
+ key: extendedActionSheetItemHandler.key,
57
+ });
58
+
59
+ const contentChildren = await Promise.all(items.map(extendedActionSheetItemHandler.codegen));
60
+
61
+ return createElement("ExtendedActionSheetGroup", undefined, contentChildren);
62
+ },
63
+ };
64
+
65
+ const extendedActionSheetItemHandler: ComponentHandler<ExtendedActionSheetItemProperties> = {
66
+ key: "057083e95466da59051119eec0b41d4ad5a07f8f",
67
+ codegen: async ({ componentProperties: props }) => {
68
+ const states = props.State.value.split("-");
69
+
70
+ const commonProps = {
71
+ tone: camelCase(props.Tone.value),
72
+ ...(states.includes("Disabled") && {
73
+ disabled: true,
74
+ }),
75
+ };
76
+
77
+ return createElement("ExtendedActionSheetItem", commonProps, [
78
+ props["Show Prefix Icon#17043:5"].value
79
+ ? createElement("PrefixIcon", {
80
+ svg: createElement(createIconTagNameFromKey(props["Prefix Icon#55948:0"].componentKey)),
81
+ })
82
+ : undefined,
83
+ props["Label#55905:8"].value,
84
+ ]);
85
+ },
86
+ };
@@ -0,0 +1,24 @@
1
+ import { camelCase } from "change-case";
2
+ import * as metadata from "../../data/__generated__/component-sets";
3
+ import { createIconTagNameFromKey } from "../../icon";
4
+ import { createElement } from "../../jsx";
5
+ import { handleSize } from "../properties";
6
+ import type { ExtendedFabProperties } from "../type";
7
+ import type { ComponentHandler } from "../type-helper";
8
+
9
+ export const extendedFabHandler: ComponentHandler<ExtendedFabProperties> = {
10
+ key: metadata.extendedFloatingActionButton.key,
11
+ codegen: async ({ componentProperties: props }) => {
12
+ const commonProps = {
13
+ size: handleSize(props.Size.value),
14
+ variant: camelCase(props.Variant.value),
15
+ };
16
+
17
+ return createElement("ExtendedFab", commonProps, [
18
+ createElement("PrefixIcon", {
19
+ svg: createElement(createIconTagNameFromKey(props["Icon#28796:0"].componentKey)),
20
+ }),
21
+ props["Label#28936:0"].value,
22
+ ]);
23
+ },
24
+ };
@@ -0,0 +1,17 @@
1
+ import * as metadata from "../../data/__generated__/component-sets";
2
+ import { createIconTagNameFromKey } from "../../icon";
3
+ import { createElement } from "../../jsx";
4
+ import type { ComponentHandler } from "../type-helper";
5
+ import type { FabProperties } from "../type";
6
+
7
+ export const fabHandler: ComponentHandler<FabProperties> = {
8
+ key: metadata.floatingActionButton.key,
9
+ codegen: async ({ componentProperties: props }) => {
10
+ return createElement(
11
+ "Fab",
12
+ undefined,
13
+ createElement(createIconTagNameFromKey(props["Icon#28796:0"].componentKey)),
14
+ "aria-label이나 aria-labelledby 중 하나를 제공해야 합니다.",
15
+ );
16
+ },
17
+ };
@@ -0,0 +1,66 @@
1
+ import * as metadata from "../../data/__generated__/component-sets";
2
+ import { createElement } from "../../jsx";
3
+ import type { ComponentHandler } from "../type-helper";
4
+ import type { HelpBubbleProperties } from "../type";
5
+
6
+ export const helpBubbleHandler: ComponentHandler<HelpBubbleProperties> = {
7
+ key: metadata.helpBubble.key,
8
+ codegen: async ({ componentProperties: props }) => {
9
+ const placement:
10
+ | "top"
11
+ | "right"
12
+ | "bottom"
13
+ | "left"
14
+ | "top-end"
15
+ | "top-start"
16
+ | "right-end"
17
+ | "right-start"
18
+ | "bottom-end"
19
+ | "bottom-start"
20
+ | "left-end"
21
+ | "left-start" = (() => {
22
+ switch (props.Placement.value) {
23
+ case "Bottom-Left":
24
+ return "top-start";
25
+ case "Bottom-Center":
26
+ return "top";
27
+ case "Bottom-Right":
28
+ return "top-end";
29
+ case "Left-Top":
30
+ return "right-start";
31
+ case "Left-Center":
32
+ return "right";
33
+ case "Left-Bottom":
34
+ return "right-end";
35
+ case "Top-Left":
36
+ return "bottom-start";
37
+ case "Top-Center":
38
+ return "bottom";
39
+ case "Top-Right":
40
+ return "bottom-end";
41
+ case "Right-Top":
42
+ return "left-start";
43
+ case "Right-Center":
44
+ return "left";
45
+ case "Right-Bottom":
46
+ return "left-end";
47
+ }
48
+ })();
49
+
50
+ const commonProps = {
51
+ title: props["Title#62535:0"].value,
52
+ ...(props["Show Description#62499:0"].value && {
53
+ description: props["Description#62535:98"].value,
54
+ }),
55
+ showCloseButton: props["Show Close Button"].value === "True",
56
+ defaultOpen: true,
57
+ placement,
58
+ };
59
+
60
+ return createElement(
61
+ "HelpBubbleTrigger",
62
+ commonProps,
63
+ createElement("ActionButton", undefined, "열기", "HelpBubble을 여는 요소를 제공해주세요."),
64
+ );
65
+ },
66
+ };
@@ -0,0 +1,16 @@
1
+ import { camelCase } from "change-case";
2
+ import * as metadata from "../../data/__generated__/component-sets";
3
+ import { createElement } from "../../jsx";
4
+ import type { ComponentHandler } from "../type-helper";
5
+ import type { IdentityPlaceholderProperties } from "../type";
6
+
7
+ export const identityPlaceholderHandler: ComponentHandler<IdentityPlaceholderProperties> = {
8
+ key: metadata.identityPlaceholder.key,
9
+ codegen: async ({ componentProperties: props }) => {
10
+ const commonProps = {
11
+ identity: camelCase(props.Identity.value),
12
+ };
13
+
14
+ return createElement("IdentityPlaceholder", commonProps);
15
+ },
16
+ };
@@ -0,0 +1,83 @@
1
+ import { camelCase } from "change-case";
2
+ import * as metadata from "../../data/__generated__/component-sets";
3
+ import { createIconTagNameFromKey } from "../../icon";
4
+ import { createElement } from "../../jsx";
5
+ import { findOne } from "../../utils/figma-node";
6
+ import type { NormalizedInstanceNode, NormalizedTextNode } from "../../normalizer";
7
+ import type { InlineBannerProperties } from "../type";
8
+ import type { ComponentHandler } from "../type-helper";
9
+
10
+ export const inlineBannerHandler: ComponentHandler<InlineBannerProperties> = {
11
+ key: metadata.inlineBanner.key,
12
+ codegen: async (node) => {
13
+ const { componentProperties: props } = node;
14
+
15
+ const tag = (() => {
16
+ switch (props.Interaction.value) {
17
+ case "Default":
18
+ return "InlineBanner";
19
+ case "Actionable":
20
+ return "ActionableInlineBanner";
21
+ case "Dismissible":
22
+ return "DismissibleInlineBanner";
23
+ case "Link":
24
+ return "InlineBanner";
25
+ default:
26
+ return "InlineBanner";
27
+ }
28
+ })();
29
+
30
+ const textNode = findOne(
31
+ node,
32
+ (child) => child.type === "TEXT" && child.name === "Label",
33
+ ) as NormalizedTextNode | null;
34
+
35
+ if (!textNode) {
36
+ return createElement(tag, undefined, undefined, "내용을 제공해주세요.");
37
+ }
38
+
39
+ const slices = textNode.segments;
40
+
41
+ let title: string | undefined;
42
+ let description: string | undefined;
43
+
44
+ switch (slices.length) {
45
+ case 1: {
46
+ description = slices[0]?.characters.trim();
47
+
48
+ break;
49
+ }
50
+ case 2: {
51
+ title = slices[0]?.characters.trim();
52
+ description = slices[1]?.characters.trim();
53
+
54
+ break;
55
+ }
56
+ }
57
+
58
+ const iconNode = findOne(
59
+ node,
60
+ (child) => child.type === "INSTANCE" && child.name === "icon",
61
+ ) as NormalizedInstanceNode | null;
62
+
63
+ const iconComponentKey =
64
+ props["Show Icon#11840:27"] && iconNode ? iconNode.componentKey : undefined;
65
+ const prefixIcon = iconComponentKey
66
+ ? createElement(createIconTagNameFromKey(iconComponentKey))
67
+ : undefined;
68
+
69
+ const commonProps = {
70
+ variant: camelCase(props.Variant.value),
71
+ title,
72
+ description,
73
+ ...(props.Interaction.value === "Link" && {
74
+ linkProps: {
75
+ children: props["Link Label#1547:81"].value,
76
+ },
77
+ }),
78
+ prefixIcon,
79
+ };
80
+
81
+ return createElement(tag, commonProps);
82
+ },
83
+ };
@@ -0,0 +1,17 @@
1
+ import * as metadata from "../../data/__generated__/component-sets";
2
+ import { createElement } from "../../jsx";
3
+ import type { MannerTempBadgeProperties } from "../type";
4
+ import type { ComponentHandler } from "../type-helper";
5
+
6
+ export const mannerTempBadgeHandler: ComponentHandler<MannerTempBadgeProperties> = {
7
+ key: metadata.mannerTempBadge.key,
8
+ codegen: async ({ children }) => {
9
+ const textNode = children.find((child) => child.type === "TEXT");
10
+
11
+ const commonProps = {
12
+ temperature: Number(textNode?.characters.replace(/[^\d.-]/g, "") ?? "-1"),
13
+ };
14
+
15
+ return createElement("MannerTempBadge", commonProps);
16
+ },
17
+ };
@@ -0,0 +1,80 @@
1
+ import * as metadata from "../../data/__generated__/component-sets";
2
+ import { createElement } from "../../jsx";
3
+ import { handleSize } from "../properties";
4
+ import type { MultilineTextFieldProperties } from "../type";
5
+ import type { ComponentHandler } from "../type-helper";
6
+
7
+ export const multilineTextFieldHandler: ComponentHandler<MultilineTextFieldProperties> = {
8
+ key: metadata.multilineTextField.key,
9
+ codegen: async ({ componentProperties: props }) => {
10
+ const {
11
+ Size: { value: size },
12
+ State: { value: state },
13
+ Filled: { value: filled },
14
+ "Show Header#870:0": { value: showHeader },
15
+ "Label#15327:323": { value: label },
16
+ "Show Indicator#1259:0": { value: showIndicator },
17
+ "Indicator#15327:286": { value: indicator },
18
+ "Placeholder#958:0": { value: placeholder },
19
+ "Filled Text#1304:0": { value: defaultValue },
20
+ "Show Footer#958:25": { value: showFooter },
21
+ "Show Description#958:50": { value: showDescription },
22
+ "Description#15327:212": { value: description },
23
+ "Show Character count#958:75": { value: showCharacterCount },
24
+ "Character Count#15327:360": { value: _characterCount },
25
+ "Max Character Count#15327:175": { value: maxCharacterCount },
26
+ } = props;
27
+
28
+ const states = state.split("-");
29
+
30
+ const commonProps = {
31
+ size: handleSize(size),
32
+ // header
33
+ ...(showHeader && {
34
+ label,
35
+ }),
36
+ ...(showHeader &&
37
+ showIndicator && {
38
+ indicator,
39
+ }),
40
+ // input
41
+ ...(filled === "True" && {
42
+ defaultValue,
43
+ }),
44
+ ...(states.includes("Invalid") && {
45
+ invalid: true,
46
+ }),
47
+ ...(states.includes("Disabled") && {
48
+ disabled: true,
49
+ }),
50
+ ...(states.includes("Read Only") && {
51
+ readOnly: true,
52
+ }),
53
+ // footer
54
+ ...(showFooter &&
55
+ showDescription &&
56
+ states.includes("Invalid") && {
57
+ // invalid인 경우 description을 error로 사용
58
+ errorMessage: description,
59
+ }),
60
+ ...(showFooter &&
61
+ showDescription &&
62
+ !states.includes("Invalid") && {
63
+ // invalid가 아닌 경우 description을 description으로 사용
64
+ description,
65
+ }),
66
+ ...(showFooter &&
67
+ showCharacterCount && {
68
+ maxGraphemeCount: Number(maxCharacterCount),
69
+ }),
70
+ };
71
+
72
+ const inputProps = {
73
+ placeholder,
74
+ };
75
+
76
+ const TextFieldChildren = createElement("TextFieldTextarea", inputProps);
77
+
78
+ return createElement("TextField", commonProps, TextFieldChildren);
79
+ },
80
+ };
@@ -0,0 +1,49 @@
1
+ import { camelCase } from "change-case";
2
+ import { match } from "ts-pattern";
3
+ import * as metadata from "../../data/__generated__/component-sets";
4
+ import { createElement } from "../../jsx";
5
+ import type { ProgressCircleProperties } from "../type";
6
+ import type { ComponentHandler } from "../type-helper";
7
+
8
+ export const progressCircleHandler: ComponentHandler<ProgressCircleProperties> = {
9
+ key: metadata.progressCircle.key,
10
+ codegen: async ({ componentProperties: props }) => {
11
+ const { value, minValue, maxValue } = match(props.Value.value)
12
+ .with("Indeterminate", () => ({
13
+ value: undefined,
14
+ minValue: undefined,
15
+ maxValue: undefined,
16
+ }))
17
+ .with("0%", () => ({
18
+ value: 0,
19
+ minValue: 0,
20
+ maxValue: 100,
21
+ }))
22
+ .with("25%", () => ({
23
+ value: 25,
24
+ minValue: 0,
25
+ maxValue: 100,
26
+ }))
27
+ .with("75%", () => ({
28
+ value: 75,
29
+ minValue: 0,
30
+ maxValue: 100,
31
+ }))
32
+ .with("100%", () => ({
33
+ value: 100,
34
+ minValue: 0,
35
+ maxValue: 100,
36
+ }))
37
+ .exhaustive();
38
+
39
+ const commonProps = {
40
+ value,
41
+ minValue,
42
+ maxValue,
43
+ size: props.Size.value,
44
+ tone: camelCase(props.Tone.value),
45
+ };
46
+
47
+ return createElement("ProgressCircle", commonProps);
48
+ },
49
+ };
@@ -0,0 +1,36 @@
1
+ import * as metadata from "../../data/__generated__/component-sets";
2
+ import { createIconTagNameFromKey } from "../../icon";
3
+ import { createElement } from "../../jsx";
4
+ import { handleSize } from "../properties";
5
+ import type { ReactionButtonProperties } from "../type";
6
+ import type { ComponentHandler } from "../type-helper";
7
+
8
+ export const reactionButtonHandler: ComponentHandler<ReactionButtonProperties> = {
9
+ key: metadata.reactionButton.key,
10
+ codegen: async ({ componentProperties: props }) => {
11
+ const states = props.State.value.split("-");
12
+
13
+ const commonProps = {
14
+ size: handleSize(props.Size.value),
15
+ ...(states.includes("Loading") && {
16
+ loading: true,
17
+ }),
18
+ ...(states.includes("Disabled") && {
19
+ disabled: true,
20
+ }),
21
+ ...(states.includes("Selected") && {
22
+ defaultPressed: true,
23
+ }),
24
+ };
25
+
26
+ return createElement("ReactionButton", commonProps, [
27
+ createElement("PrefixIcon", {
28
+ svg: createElement(createIconTagNameFromKey(props["Icon#12379:0"].componentKey)),
29
+ }),
30
+ props["Label#6397:0"].value,
31
+ props["Show Count#6397:33"].value
32
+ ? createElement("Count", {}, props["Count#15816:0"].value)
33
+ : undefined,
34
+ ]);
35
+ },
36
+ };
@@ -0,0 +1,51 @@
1
+ import * as metadata from "../../data/__generated__/component-sets";
2
+ import { createElement } from "../../jsx";
3
+ import { findAllInstances } from "../../utils/figma-node";
4
+ import type { ComponentHandler } from "../type-helper";
5
+ import type { SegmentedControlItemProperties, SegmentedControlProperties } from "../type";
6
+
7
+ export const segmentedControlHandler: ComponentHandler<SegmentedControlProperties> = {
8
+ key: metadata.segmentedControl.key,
9
+ codegen: async (node) => {
10
+ const segments = await findAllInstances<SegmentedControlItemProperties>({
11
+ node,
12
+ key: segmentedControlItemHandler.key,
13
+ });
14
+
15
+ const selectedSegment = segments.find((segment) =>
16
+ segment.componentProperties.State.value.split("-").includes("Selected"),
17
+ );
18
+
19
+ const segmentedControlChildren = await Promise.all(
20
+ segments.map(segmentedControlItemHandler.codegen),
21
+ );
22
+
23
+ const commonProps = {
24
+ ...(selectedSegment && {
25
+ defaultValue: selectedSegment.componentProperties["Label#11366:15"].value,
26
+ }),
27
+ };
28
+
29
+ return createElement(
30
+ "SegmentedControl",
31
+ commonProps,
32
+ segmentedControlChildren,
33
+ "aria-label이나 aria-labelledby 중 하나를 제공해야 합니다.",
34
+ );
35
+ },
36
+ };
37
+
38
+ const segmentedControlItemHandler: ComponentHandler<SegmentedControlItemProperties> = {
39
+ key: "9a7ba0d4c041ddbce84ee48881788434fd6bccc8",
40
+ codegen: async ({ componentProperties: props }) => {
41
+ const states = props.State.value.split("-");
42
+ const commonProps = {
43
+ value: props["Label#11366:15"].value,
44
+ ...(states.includes("Disabled") && {
45
+ disabled: true,
46
+ }),
47
+ };
48
+
49
+ return createElement("SegmentedControlItem", commonProps, props["Label#11366:15"].value);
50
+ },
51
+ };