@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
@@ -1,1647 +1,35 @@
1
- import { camelCase } from "change-case";
2
- import { match } from "ts-pattern";
3
- import * as metadata from "../data/__generated__/component-sets";
4
- import { createIconTagNameFromKey } from "../icon";
5
- import { type ElementNode, createElement } from "../jsx";
6
- import { findAll, findAllInstances, findOne } from "../node-util";
7
- import type { NormalizedInstanceNode, NormalizedTextNode } from "../normalizer/types";
8
- import { getLayoutVariableName } from "../variable";
9
- import { handleSize } from "./properties";
10
- import type {
11
- ActionButtonProperties,
12
- ActionChipProperties,
13
- ActionSheetItemProperties,
14
- ActionSheetProperties,
15
- AppBarLeftProperties,
16
- AppBarMainProperties,
17
- AppBarProperties,
18
- AppBarRightProperties,
19
- AvatarProperties,
20
- AvatarStackProperties,
21
- BadgeProperties,
22
- CalloutProperties,
23
- CheckboxProperties,
24
- ChipTabsItemProperties,
25
- ChipTabsProperties,
26
- ControlChipProperties,
27
- ErrorStateProperties,
28
- ExtendedActionSheetGroupProperties,
29
- ExtendedActionSheetItemProperties,
30
- ExtendedActionSheetProperties,
31
- ExtendedFabProperties,
32
- FabProperties,
33
- HelpBubbleProperties,
34
- IdentityPlaceholderProperties,
35
- InlineBannerProperties,
36
- MannerTempBadgeProperties,
37
- MultilineTextFieldProperties,
38
- ProgressCircleProperties,
39
- ReactionButtonProperties,
40
- SegmentedControlItemProperties,
41
- SegmentedControlProperties,
42
- SelectBoxGroupProperties,
43
- SelectBoxProperties,
44
- SkeletonProperties,
45
- SnackbarProperties,
46
- SwitchProperties,
47
- TabsFillItemProperties,
48
- TabsHugItemProperties,
49
- TabsProperties,
50
- TextButtonProperties,
51
- TextFieldProperties,
52
- ToggleButtonProperties,
53
- } from "./type";
54
-
55
- export interface ComponentHandler<
56
- T extends
57
- NormalizedInstanceNode["componentProperties"] = NormalizedInstanceNode["componentProperties"],
58
- > {
59
- key: string;
60
- codegen: (node: NormalizedInstanceNode & { componentProperties: T }) => Promise<ElementNode>;
61
- }
62
-
63
- const actionButtonHandler: ComponentHandler<ActionButtonProperties> = {
64
- key: metadata.actionButton.key,
65
- codegen: async ({ componentProperties: props }) => {
66
- const states = props.State.value.split("-");
67
-
68
- const { layout, children } = await match(props.Layout.value)
69
- .with("Icon Only", async () => ({
70
- layout: "iconOnly",
71
- children: [
72
- createElement("Icon", {
73
- svg: createElement(createIconTagNameFromKey(props["Icon#7574:0"].componentKey)),
74
- }),
75
- ],
76
- }))
77
- .with("Icon First", async () => ({
78
- layout: "withText",
79
- children: [
80
- createElement("PrefixIcon", {
81
- svg: createElement(
82
- createIconTagNameFromKey(props["Prefix Icon#5987:305"].componentKey),
83
- ),
84
- }),
85
- props["Label#5987:61"].value,
86
- ],
87
- }))
88
- .with("Icon Last", async () => ({
89
- layout: "withText",
90
- children: [
91
- props["Label#5987:61"].value,
92
- createElement("SuffixIcon", {
93
- svg: createElement(
94
- createIconTagNameFromKey(props["Suffix Icon#5987:244"].componentKey),
95
- ),
96
- }),
97
- ],
98
- }))
99
- .with("Text Only", () => ({
100
- layout: "withText",
101
- children: props["Label#5987:61"].value,
102
- }))
103
- .exhaustive();
104
-
105
- const commonProps = {
106
- ...(states.includes("Disabled") && {
107
- disabled: true,
108
- }),
109
- ...(states.includes("Loading") && {
110
- loading: true,
111
- }),
112
- size: handleSize(props.Size.value),
113
- variant: camelCase(props.Variant.value),
114
- layout,
115
- };
116
-
117
- return createElement("ActionButton", commonProps, children);
118
- },
119
- };
120
-
121
- const actionChipHandler: ComponentHandler<ActionChipProperties> = {
122
- key: metadata.actionChip.key,
123
- codegen: async ({ componentProperties: props }) => {
124
- const states = props.State.value.split("-");
125
-
126
- const { layout, children } = await match(props.Layout.value)
127
- .with("Icon Only", async () => ({
128
- layout: "iconOnly",
129
- children: [
130
- createElement("Icon", {
131
- svg: createElement(createIconTagNameFromKey(props["Icon#8714:0"].componentKey)),
132
- }),
133
- ],
134
- }))
135
- .with("Icon First", async () => ({
136
- layout: "withText",
137
- children: [
138
- createElement("PrefixIcon", {
139
- svg: createElement(createIconTagNameFromKey(props["Prefix Icon#8711:0"].componentKey)),
140
- }),
141
- props["Label#7185:0"].value,
142
- ],
143
- }))
144
- .with("Icon Last", async () => ({
145
- layout: "withText",
146
- children: [
147
- props["Label#7185:0"].value,
148
- createElement("SuffixIcon", {
149
- svg: createElement(createIconTagNameFromKey(props["Suffix Icon#8711:3"].componentKey)),
150
- }),
151
- ],
152
- }))
153
- .with("Icon Both", async () => ({
154
- layout: "withText",
155
- children: [
156
- createElement("PrefixIcon", {
157
- svg: createElement(createIconTagNameFromKey(props["Prefix Icon#8711:0"].componentKey)),
158
- }),
159
- props["Label#7185:0"].value,
160
- createElement("SuffixIcon", {
161
- svg: createElement(createIconTagNameFromKey(props["Suffix Icon#8711:3"].componentKey)),
162
- }),
163
- ],
164
- }))
165
- .with("Text Only", () => ({
166
- layout: "withText",
167
- children: props["Label#7185:0"].value,
168
- }))
169
- .exhaustive();
170
-
171
- const commonProps = {
172
- size: handleSize(props.Size.value),
173
- layout,
174
- ...(states.includes("Disabled") && {
175
- disabled: true,
176
- }),
177
- ...(props["Show Count#7185:42"].value && {
178
- count: Number(props["Count#7185:21"].value),
179
- }),
180
- };
181
- return createElement("ActionChip", commonProps, children);
182
- },
183
- };
184
-
185
- const actionSheetHandler: ComponentHandler<ActionSheetProperties> = {
186
- key: metadata.actionSheet.key,
187
- codegen: async (node) => {
188
- const { componentProperties: props } = node;
189
-
190
- const contentProps = match(props.Header.value)
191
- .with("None", () => ({
192
- title: undefined,
193
- description: undefined,
194
- }))
195
- .with("Title Only", () => ({
196
- title: props["Title#15641:37"].value,
197
- description: undefined,
198
- }))
199
- .with("Description Only", () => ({
200
- title: undefined,
201
- description: props["Description#15641:70"].value,
202
- }))
203
- .with("Title With Description", () => ({
204
- title: props["Title#15641:37"].value,
205
- description: props["Description#15641:70"].value,
206
- }))
207
- .exhaustive();
208
-
209
- const items = await findAllInstances<ActionSheetItemProperties>({
210
- node,
211
- key: actionSheetItemHandler.key,
212
- });
213
-
214
- const contentChildren = await Promise.all(items.map(actionSheetItemHandler.codegen));
215
-
216
- const content = createElement(
217
- "ActionSheetContent",
218
- contentProps,
219
- contentChildren,
220
- contentProps.title
221
- ? ""
222
- : "title을 제공하지 않는 경우 aria-label이나 aria-labelledby 중 하나를 제공해야 합니다.",
223
- );
224
-
225
- const trigger = createElement(
226
- "ActionSheetTrigger",
227
- { asChild: true },
228
- createElement("ActionButton", undefined, "열기", "ActionSheet을 여는 요소를 제공해주세요."),
229
- );
230
-
231
- return createElement("ActionSheet", undefined, [trigger, content]);
232
- },
233
- };
234
-
235
- const actionSheetItemHandler: ComponentHandler<ActionSheetItemProperties> = {
236
- key: "c3cafd3a3fdcd45fecb6971019d88eaf39a2e381",
237
- codegen: async ({ componentProperties: props }) => {
238
- const states = props.State.value.split("-");
239
-
240
- const commonProps = {
241
- label: props["Label#15420:4"].value,
242
- tone: camelCase(props.Tone.value),
243
- ...(states.includes("Disabled") && {
244
- disabled: true,
245
- }),
246
- };
247
-
248
- return createElement("ActionSheetItem", commonProps);
249
- },
250
- };
251
-
252
- const appBarHandler: ComponentHandler<AppBarProperties> = {
253
- key: metadata.standardNavigation.key,
254
- codegen: async (node) => {
255
- const props = node.componentProperties;
256
-
257
- const theme = (() => {
258
- switch (props.OS.value) {
259
- case "Android":
260
- return "android";
261
- case "iOS":
262
- return "cupertino";
263
- }
264
- })();
265
-
266
- const tone = (() => {
267
- switch (props.Variant.value) {
268
- case "Layer Default":
269
- return "layer";
270
- case "Transparent":
271
- return "transparent";
272
- }
273
- })();
274
-
275
- const mainNode = await findAllInstances<AppBarMainProperties>({
276
- key: appBarMainHandler.key,
277
- node,
278
- });
279
- const onlyMainNode = mainNode.length === 1 ? mainNode[0] : undefined;
280
- const main = onlyMainNode ? await appBarMainHandler.codegen(onlyMainNode) : undefined;
281
-
282
- const leftNode = await findAllInstances<AppBarLeftProperties>({
283
- key: appBarLeftHandler.key,
284
- node,
285
- });
286
- const onlyLeftNode = leftNode.length === 1 ? leftNode[0] : undefined;
287
- const left = onlyLeftNode ? await appBarLeftHandler.codegen(onlyLeftNode) : undefined;
288
-
289
- const rightNode = await findAllInstances<AppBarRightProperties>({
290
- key: appBarRightHandler.key,
291
- node,
292
- });
293
- const onlyRightNode = rightNode.length === 1 ? rightNode[0] : undefined;
294
- const right = onlyRightNode ? await appBarRightHandler.codegen(onlyRightNode) : undefined;
295
-
296
- return createElement(
297
- "AppBar",
298
- { theme, tone },
299
- [left, main, right].filter(Boolean),
300
- tone === "transparent"
301
- ? `<AppScreen layerOffsetTop="none">으로 상단 패딩을 제거할 수 있습니다.`
302
- : undefined,
303
- );
304
- },
305
- };
306
-
307
- const appBarMainHandler: ComponentHandler<AppBarMainProperties> = {
308
- key: "336b49b26c3933485d87cc460b06c390976ea58e",
309
- codegen: async ({ componentProperties: props }) => {
310
- const { title, subtitle, layout } = match(props.Type.value)
311
- .with("Title", () => ({
312
- title: props["Title#16944:0"].value,
313
- subtitle: undefined,
314
- layout: undefined,
315
- }))
316
- .with("Title-Subtitle", () => ({
317
- title: props["Title#16944:0"].value,
318
- subtitle: props["Subtitle#16958:9"].value,
319
- layout: "withSubtitle",
320
- }))
321
- .otherwise(() => ({
322
- title: undefined,
323
- subtitle: undefined,
324
- layout: undefined,
325
- }));
326
-
327
- const commonProps = {
328
- title,
329
- subtitle,
330
- layout,
331
- };
332
-
333
- return createElement(
334
- "AppBarMain",
335
- commonProps,
336
- undefined,
337
- title === undefined ? "Title을 제공해주세요." : undefined,
338
- );
339
- },
340
- };
341
-
342
- const appBarLeftHandler: ComponentHandler<AppBarLeftProperties> = {
343
- key: "e5d2e47052a22395db79f195a0991a570dc1b6c9",
344
- codegen: async (node) => {
345
- const props = node.componentProperties;
346
-
347
- const children = await (async () => {
348
- switch (props.Action.value) {
349
- case "Back":
350
- return createElement("AppBarBackButton", undefined);
351
- case "Close":
352
- return createElement("AppBarCloseButton", undefined);
353
- case "Other": {
354
- const iconNode = findOne(
355
- node,
356
- (child) => child.type === "INSTANCE" && child.name === "Icon",
357
- ) as NormalizedInstanceNode | null;
358
-
359
- const iconComponentKey = iconNode?.componentKey ?? undefined;
360
-
361
- return createElement(
362
- "AppBarIconButton",
363
- undefined,
364
- iconComponentKey
365
- ? createElement(createIconTagNameFromKey(iconComponentKey))
366
- : undefined,
367
- iconComponentKey === undefined
368
- ? "아이콘과, aria-label 또는 aria-labelledby를 제공해주세요."
369
- : "aria-label 또는 aria-labelledby를 제공해주세요.",
370
- );
371
- }
372
- }
373
- })();
374
-
375
- return createElement("AppBarLeft", undefined, children);
376
- },
377
- };
378
-
379
- const appBarRightHandler: ComponentHandler<AppBarRightProperties> = {
380
- key: "9e157fc2d1f89ffee938a5bc62f4a58064fec44e",
381
- codegen: async (node) => {
382
- const props = node.componentProperties;
383
-
384
- const children = await (async () => {
385
- switch (props.Type.value) {
386
- case "1 Text": {
387
- const textNode = findOne(
388
- node,
389
- (child) => child.type === "TEXT",
390
- ) as NormalizedTextNode | null;
391
-
392
- return textNode?.characters;
393
- }
394
- default: {
395
- const iconNodes = findAll(
396
- node,
397
- (child) => child.type === "INSTANCE" && child.name === "Icon",
398
- ) as NormalizedInstanceNode[];
399
-
400
- const iconComponentKeys = iconNodes.map((iconNode) => iconNode.componentKey);
401
-
402
- return iconComponentKeys.map((iconComponentKey) =>
403
- createElement(
404
- "AppBarIconButton",
405
- undefined,
406
- iconComponentKey
407
- ? createElement(createIconTagNameFromKey(iconComponentKey))
408
- : undefined,
409
- iconComponentKey === undefined
410
- ? "아이콘과, aria-label 또는 aria-labelledby를 제공해주세요."
411
- : "aria-label 또는 aria-labelledby를 제공해주세요.",
412
- ),
413
- );
414
- }
415
- }
416
- })();
417
-
418
- return createElement("AppBarRight", undefined, children);
419
- },
420
- };
421
-
422
- const avatarHandler: ComponentHandler<AvatarProperties> = {
423
- key: metadata.avatar.key,
424
- codegen: async (node) => {
425
- const [placeholder] = await findAllInstances<IdentityPlaceholderProperties>({
426
- node,
427
- key: identityPlaceholderHandler.key,
428
- });
429
- const { componentProperties: props } = node;
430
-
431
- const avatarHasSrc = props["Show Image#71850:57"].value;
432
-
433
- const commonProps = {
434
- ...(avatarHasSrc && {
435
- // Placeholder
436
- src: `https://placehold.co/${props.Size.value}x${props.Size.value}`,
437
- }),
438
- ...(placeholder && {
439
- fallback: await identityPlaceholderHandler.codegen(placeholder),
440
- }),
441
- size: props.Size.value,
442
- };
443
-
444
- return createElement(
445
- "Avatar",
446
- commonProps,
447
- props["Show Badge#1398:26"].value ? createElement("AvatarBadge", {}) : undefined,
448
- avatarHasSrc ? "alt 텍스트를 제공해야 합니다." : undefined,
449
- );
450
- },
451
- };
452
-
453
- const avatarStackHandler: ComponentHandler<AvatarStackProperties> = {
454
- key: metadata.avatarStack.key,
455
- codegen: async (node) => {
456
- const avatarNodes = await findAllInstances<AvatarProperties>({
457
- node,
458
- key: avatarHandler.key,
459
- });
460
-
461
- const { componentProperties: props } = node;
462
-
463
- const commonProps = {
464
- size: props.Size.value,
465
- // TODO: 구현될 예정
466
- // topItem: camelCase(props["Top Item"].value),
467
- };
468
-
469
- const avatarStackChildren = (await Promise.all(avatarNodes.map(avatarHandler.codegen))).map(
470
- (avatar) => {
471
- return {
472
- ...avatar,
473
- props: { ...avatar.props, size: undefined },
474
- };
475
- },
476
- );
477
-
478
- return createElement("AvatarStack", commonProps, avatarStackChildren);
479
- },
480
- };
481
-
482
- const badgeHandler: ComponentHandler<BadgeProperties> = {
483
- key: metadata.badge.key,
484
- codegen: async ({ componentProperties: props }) => {
485
- const commonProps = {
486
- size: handleSize(props.Size.value),
487
- tone: camelCase(props.Tone.value),
488
- variant: camelCase(props.Variant.value),
489
- shape: camelCase(props.Shape.value),
490
- };
491
-
492
- return createElement("Badge", commonProps, props["Label#1584:0"].value);
493
- },
494
- };
495
-
496
- const calloutHandler: ComponentHandler<CalloutProperties> = {
497
- key: metadata.callout.key,
498
- codegen: async ({ componentProperties: props, children }) => {
499
- const tag = (() => {
500
- switch (props.Interaction.value) {
501
- case "Default":
502
- return "Callout";
503
- case "Actionable":
504
- return "ActionableCallout";
505
- case "Dismissible":
506
- return "DismissibleCallout";
507
- default:
508
- return "Callout";
509
- }
510
- })();
511
-
512
- const textNode = children.find((child) => child.type === "TEXT") as NormalizedTextNode | null;
513
-
514
- if (!textNode) {
515
- return createElement(tag, undefined, undefined, "내용을 제공해주세요.");
516
- }
517
-
518
- const slices = textNode.segments;
519
-
520
- let title: string | undefined;
521
- let description: string | undefined;
522
- let linkLabel: string | undefined;
523
-
524
- switch (slices.length) {
525
- case 1: {
526
- description = slices[0]?.characters.trim();
527
-
528
- break;
529
- }
530
- case 2: {
531
- const firstSlice = slices[0];
532
- const secondSlice = slices[1];
533
-
534
- if (firstSlice?.style.fontWeight === 700) {
535
- title = firstSlice?.characters.trim();
536
- description = secondSlice?.characters.trim();
537
- break;
538
- }
539
-
540
- description = firstSlice?.characters.trim();
541
-
542
- if (tag !== "ActionableCallout") {
543
- linkLabel = secondSlice?.characters.trim();
544
- }
545
-
546
- break;
547
- }
548
- case 3: {
549
- title = slices[0]?.characters.trim();
550
- description = slices[1]?.characters.trim();
551
-
552
- if (tag !== "ActionableCallout") {
553
- linkLabel = slices[2]?.characters.trim();
554
- }
555
-
556
- break;
557
- }
558
- }
559
-
560
- const commonProps = {
561
- tone: camelCase(props.Tone.value),
562
- title,
563
- description,
564
- linkProps: {
565
- children: linkLabel,
566
- },
567
- ...(props["Icon#12598:210"].value && {
568
- prefixIcon: createElement(createIconTagNameFromKey(props["Icon#12598:210"].componentKey)),
569
- }),
570
- };
571
-
572
- return createElement(tag, commonProps);
573
- },
574
- };
575
-
576
- const checkboxHandler: ComponentHandler<CheckboxProperties> = {
577
- key: metadata.checkbox.key,
578
- codegen: async ({ componentProperties: props }) => {
579
- const states = props.State.value.split("-");
580
-
581
- const commonProps = {
582
- label: props["Label#49990:0"].value,
583
- weight: camelCase(props.Weight.value),
584
- variant: camelCase(props.Shape.value),
585
- size: handleSize(props.Size.value),
586
- ...(states.includes("Selected") && {
587
- defaultChecked: true,
588
- }),
589
- ...(states.includes("Indeterminate") && {
590
- defaultChecked: true,
591
- indeterminate: true,
592
- }),
593
- ...(states.includes("Disabled") && {
594
- disabled: true,
595
- }),
596
- };
597
-
598
- return createElement("Checkbox", commonProps);
599
- },
600
- };
601
-
602
- const chipTabsHandler: ComponentHandler<ChipTabsProperties> = {
603
- key: metadata.chipTablist.key,
604
- codegen: async (node) => {
605
- const chipTabsItems = await findAllInstances<ChipTabsItemProperties>({
606
- node,
607
- key: chipTabsItemHandler.key,
608
- });
609
-
610
- const selectedChipTabsItem = chipTabsItems.find((chipTabsItem) =>
611
- chipTabsItem.componentProperties.State.value.split("-").includes("Selected"),
612
- );
613
-
614
- const chipTabsList = createElement(
615
- "ChipTabsList",
616
- undefined,
617
- await Promise.all(chipTabsItems.map(chipTabsItemHandler.codegen)),
618
- );
619
-
620
- const commonProps = {
621
- variant: camelCase(node.componentProperties.Variant.value),
622
- ...(selectedChipTabsItem && {
623
- defaultValue: selectedChipTabsItem.componentProperties["Label#8876:0"].value,
624
- }),
625
- };
626
-
627
- return createElement("ChipTabs", commonProps, chipTabsList);
628
- },
629
- };
630
-
631
- const chipTabsItemHandler: ComponentHandler<ChipTabsItemProperties> = {
632
- key: "fa80168b02051fbb0ba032238bd76d840dbe2e15",
633
- codegen: async ({ componentProperties: props }) => {
634
- const states = props.State.value.split("-");
635
-
636
- const commonProps = {
637
- value: props["Label#8876:0"].value,
638
- ...(states.includes("Disabled") && {
639
- disabled: true,
640
- }),
641
- };
642
-
643
- return createElement("ChipTabsTrigger", commonProps, props["Label#8876:0"].value);
644
- },
645
- };
646
-
647
- const controlChipHandler: ComponentHandler<ControlChipProperties> = {
648
- key: metadata.controlChip.key,
649
- codegen: async ({ componentProperties: props }) => {
650
- const states = props.State.value.split("-");
651
-
652
- const { layout, children } = await match(props.Layout.value)
653
- .with("Icon Only", async () => ({
654
- layout: "iconOnly",
655
- children: [
656
- createElement("Icon", {
657
- svg: createElement(createIconTagNameFromKey(props["Icon#8722:41"].componentKey)),
658
- }),
659
- ],
660
- }))
661
- .with("Icon First", async () => ({
662
- layout: "withText",
663
- children: [
664
- createElement("PrefixIcon", {
665
- svg: createElement(createIconTagNameFromKey(props["Prefix Icon#8722:0"].componentKey)),
666
- }),
667
- props["Label#7185:0"].value,
668
- ],
669
- }))
670
- .with("Icon Last", async () => ({
671
- layout: "withText",
672
- children: [
673
- props["Label#7185:0"].value,
674
- createElement("SuffixIcon", {
675
- svg: createElement(createIconTagNameFromKey(props["Suffix Icon#8722:82"].componentKey)),
676
- }),
677
- ],
678
- }))
679
- .with("Icon Both", async () => ({
680
- layout: "withText",
681
- children: [
682
- createElement("PrefixIcon", {
683
- svg: createElement(createIconTagNameFromKey(props["Prefix Icon#8722:0"].componentKey)),
684
- }),
685
- props["Label#7185:0"].value,
686
- createElement("SuffixIcon", {
687
- svg: createElement(createIconTagNameFromKey(props["Suffix Icon#8722:82"].componentKey)),
688
- }),
689
- ],
690
- }))
691
- .with("Text Only", () => ({
692
- layout: "withText",
693
- children: props["Label#7185:0"].value,
694
- }))
695
- .exhaustive();
696
-
697
- const commonProps = {
698
- size: handleSize(props.Size.value),
699
- layout,
700
- ...(states.includes("Selected") && {
701
- defaultChecked: true,
702
- }),
703
- ...(states.includes("Disabled") && {
704
- disabled: true,
705
- }),
706
- ...(props["Show Count#7185:42"].value && {
707
- count: Number(props["Count#7185:21"].value),
708
- }),
709
- };
710
-
711
- return createElement("ControlChip.Toggle", commonProps, children);
712
- },
713
- };
714
-
715
- const errorStateHandler: ComponentHandler<ErrorStateProperties> = {
716
- key: metadata.errorState.key,
717
- codegen: async (node) => {
718
- const props = node.componentProperties;
719
-
720
- const [actionButtonNode] = await findAllInstances<ActionButtonProperties>({
721
- node,
722
- key: actionButtonHandler.key,
723
- });
724
-
725
- const commonProps = {
726
- variant: camelCase(props.Variant.value),
727
- ...(props.Layout.value === "With Title" && {
728
- title: props["Title#16237:0"].value,
729
- }),
730
- description: props["Description#16237:5"].value,
731
- ...(actionButtonNode && {
732
- primaryActionProps: {
733
- children: (await actionButtonHandler.codegen(actionButtonNode)).children[0],
734
- },
735
- secondaryActionProps: {
736
- children: props["Secondary Action Label#17042:0"].value,
737
- },
738
- }),
739
- };
740
-
741
- return createElement("ErrorState", commonProps);
742
- },
743
- };
744
-
745
- const extendedActionSheetHandler: ComponentHandler<ExtendedActionSheetProperties> = {
746
- key: metadata.extendedActionSheet.key,
747
- codegen: async (node) => {
748
- const { componentProperties: props } = node;
749
-
750
- const groups = findAllInstances<ExtendedActionSheetGroupProperties>({
751
- node,
752
- key: extendedActionSheetGroupHandler.key,
753
- });
754
-
755
- const contentChildren = await Promise.all(groups.map(extendedActionSheetGroupHandler.codegen));
756
-
757
- const title = props["Show Title#17043:12"].value ? props["Title#14599:0"].value : undefined;
758
-
759
- const content = createElement(
760
- "ExtendedActionSheetContent",
761
- { title },
762
- contentChildren,
763
- title
764
- ? undefined
765
- : "title을 제공하지 않는 경우 aria-label이나 aria-labelledby 중 하나를 제공해야 합니다.",
766
- );
767
-
768
- const trigger = createElement(
769
- "ExtendedActionSheetTrigger",
770
- { asChild: true },
771
- createElement(
772
- "ActionButton",
773
- undefined,
774
- "열기",
775
- "ExtendedActionSheet을 여는 요소를 제공해주세요.",
776
- ),
777
- );
778
-
779
- return createElement("ExtendedActionSheet", undefined, [trigger, content]);
780
- },
781
- };
782
-
783
- const extendedActionSheetGroupHandler: ComponentHandler<ExtendedActionSheetGroupProperties> = {
784
- key: "2a504a1c6b7810d5e652862dcba2cb7048f9eb16",
785
- codegen: async (node) => {
786
- const items = findAllInstances<ExtendedActionSheetItemProperties>({
787
- node,
788
- key: extendedActionSheetItemHandler.key,
789
- });
790
-
791
- const contentChildren = await Promise.all(items.map(extendedActionSheetItemHandler.codegen));
792
-
793
- return createElement("ExtendedActionSheetGroup", undefined, contentChildren);
794
- },
795
- };
796
-
797
- const extendedActionSheetItemHandler: ComponentHandler<ExtendedActionSheetItemProperties> = {
798
- key: "057083e95466da59051119eec0b41d4ad5a07f8f",
799
- codegen: async ({ componentProperties: props }) => {
800
- const states = props.State.value.split("-");
801
-
802
- const commonProps = {
803
- tone: camelCase(props.Tone.value),
804
- ...(states.includes("Disabled") && {
805
- disabled: true,
806
- }),
807
- };
808
-
809
- return createElement("ExtendedActionSheetItem", commonProps, [
810
- props["Show Prefix Icon#17043:5"].value
811
- ? createElement("PrefixIcon", {
812
- svg: createElement(createIconTagNameFromKey(props["Prefix Icon#55948:0"].componentKey)),
813
- })
814
- : undefined,
815
- props["Label#55905:8"].value,
816
- ]);
817
- },
818
- };
819
-
820
- const extendedFabHandler: ComponentHandler<ExtendedFabProperties> = {
821
- key: metadata.extendedFloatingActionButton.key,
822
- codegen: async ({ componentProperties: props }) => {
823
- const commonProps = {
824
- size: handleSize(props.Size.value),
825
- variant: camelCase(props.Variant.value),
826
- };
827
-
828
- return createElement("ExtendedFab", commonProps, [
829
- createElement("PrefixIcon", {
830
- svg: createElement(createIconTagNameFromKey(props["Icon#28796:0"].componentKey)),
831
- }),
832
- props["Label#28936:0"].value,
833
- ]);
834
- },
835
- };
836
-
837
- const fabHandler: ComponentHandler<FabProperties> = {
838
- key: metadata.floatingActionButton.key,
839
- codegen: async ({ componentProperties: props }) => {
840
- return createElement(
841
- "Fab",
842
- undefined,
843
- createElement(createIconTagNameFromKey(props["Icon#28796:0"].componentKey)),
844
- "aria-label이나 aria-labelledby 중 하나를 제공해야 합니다.",
845
- );
846
- },
847
- };
848
-
849
- const helpBubbleHandler: ComponentHandler<HelpBubbleProperties> = {
850
- key: metadata.helpBubble.key,
851
- codegen: async ({ componentProperties: props }) => {
852
- const placement:
853
- | "top"
854
- | "right"
855
- | "bottom"
856
- | "left"
857
- | "top-end"
858
- | "top-start"
859
- | "right-end"
860
- | "right-start"
861
- | "bottom-end"
862
- | "bottom-start"
863
- | "left-end"
864
- | "left-start" = (() => {
865
- switch (props.Placement.value) {
866
- case "Bottom-Left":
867
- return "top-start";
868
- case "Bottom-Center":
869
- return "top";
870
- case "Bottom-Right":
871
- return "top-end";
872
- case "Left-Top":
873
- return "right-start";
874
- case "Left-Center":
875
- return "right";
876
- case "Left-Bottom":
877
- return "right-end";
878
- case "Top-Left":
879
- return "bottom-start";
880
- case "Top-Center":
881
- return "bottom";
882
- case "Top-Right":
883
- return "bottom-end";
884
- case "Right-Top":
885
- return "left-start";
886
- case "Right-Center":
887
- return "left";
888
- case "Right-Bottom":
889
- return "left-end";
890
- }
891
- })();
892
-
893
- const commonProps = {
894
- title: props["Title#62535:0"].value,
895
- ...(props["Show Description#62499:0"].value && {
896
- description: props["Description#62535:98"].value,
897
- }),
898
- showCloseButton: props["Show Close Button"].value === "True",
899
- defaultOpen: true,
900
- placement,
901
- };
902
-
903
- return createElement(
904
- "HelpBubbleTrigger",
905
- commonProps,
906
- createElement("ActionButton", undefined, "열기", "HelpBubble을 여는 요소를 제공해주세요."),
907
- );
908
- },
909
- };
910
-
911
- const identityPlaceholderHandler: ComponentHandler<IdentityPlaceholderProperties> = {
912
- key: metadata.identityPlaceholder.key,
913
- codegen: async ({ componentProperties: props }) => {
914
- const commonProps = {
915
- identity: camelCase(props.Identity.value),
916
- };
917
-
918
- return createElement("IdentityPlaceholder", commonProps);
919
- },
920
- };
921
-
922
- const inlineBannerHandler: ComponentHandler<InlineBannerProperties> = {
923
- key: metadata.inlineBanner.key,
924
- codegen: async (node) => {
925
- const { componentProperties: props } = node;
926
-
927
- const tag = (() => {
928
- switch (props.Interaction.value) {
929
- case "Default":
930
- return "InlineBanner";
931
- case "Actionable":
932
- return "ActionableInlineBanner";
933
- case "Dismissible":
934
- return "DismissibleInlineBanner";
935
- case "Link":
936
- return "InlineBanner";
937
- default:
938
- return "InlineBanner";
939
- }
940
- })();
941
-
942
- const textNode = findOne(
943
- node,
944
- (child) => child.type === "TEXT" && child.name === "Label",
945
- ) as NormalizedTextNode | null;
946
-
947
- if (!textNode) {
948
- return createElement(tag, undefined, undefined, "내용을 제공해주세요.");
949
- }
950
-
951
- const slices = textNode.segments;
952
-
953
- let title: string | undefined;
954
- let description: string | undefined;
955
-
956
- switch (slices.length) {
957
- case 1: {
958
- description = slices[0]?.characters.trim();
959
-
960
- break;
961
- }
962
- case 2: {
963
- title = slices[0]?.characters.trim();
964
- description = slices[1]?.characters.trim();
965
-
966
- break;
967
- }
968
- }
969
-
970
- const iconNode = findOne(
971
- node,
972
- (child) => child.type === "INSTANCE" && child.name === "icon",
973
- ) as NormalizedInstanceNode | null;
974
-
975
- const iconComponentKey =
976
- props["Show Icon#11840:27"] && iconNode ? iconNode.componentKey : undefined;
977
- const prefixIcon = iconComponentKey
978
- ? createElement(createIconTagNameFromKey(iconComponentKey))
979
- : undefined;
980
-
981
- const commonProps = {
982
- variant: camelCase(props.Variant.value),
983
- title,
984
- description,
985
- ...(props.Interaction.value === "Link" && {
986
- linkProps: {
987
- children: props["Link Label#1547:81"].value,
988
- },
989
- }),
990
- prefixIcon,
991
- };
992
-
993
- return createElement(tag, commonProps);
994
- },
995
- };
996
-
997
- const mannerTempBadgeHandler: ComponentHandler<MannerTempBadgeProperties> = {
998
- key: metadata.mannerTempBadge.key,
999
- codegen: async ({ children }) => {
1000
- const textNode = children.find((child) => child.type === "TEXT");
1001
-
1002
- const commonProps = {
1003
- temperature: Number(textNode?.characters.replace(/[^\d.-]/g, "") ?? "-1"),
1004
- };
1005
-
1006
- return createElement("MannerTempBadge", commonProps);
1007
- },
1008
- };
1009
-
1010
- const multilineTextFieldHandler: ComponentHandler<MultilineTextFieldProperties> = {
1011
- key: metadata.multilineTextField.key,
1012
- codegen: async ({ componentProperties: props }) => {
1013
- const {
1014
- Size: { value: size },
1015
- State: { value: state },
1016
- Filled: { value: filled },
1017
- "Show Header#870:0": { value: showHeader },
1018
- "Label#15327:323": { value: label },
1019
- "Show Indicator#1259:0": { value: showIndicator },
1020
- "Indicator#15327:286": { value: indicator },
1021
- "Placeholder#958:0": { value: placeholder },
1022
- "Filled Text#1304:0": { value: defaultValue },
1023
- "Show Footer#958:25": { value: showFooter },
1024
- "Show Description#958:50": { value: showDescription },
1025
- "Description#15327:212": { value: description },
1026
- "Show Character count#958:75": { value: showCharacterCount },
1027
- "Character Count#15327:360": { value: _characterCount },
1028
- "Max Character Count#15327:175": { value: maxCharacterCount },
1029
- } = props;
1030
-
1031
- const states = state.split("-");
1032
-
1033
- const commonProps = {
1034
- size: handleSize(size),
1035
- // header
1036
- ...(showHeader && {
1037
- label,
1038
- }),
1039
- ...(showHeader &&
1040
- showIndicator && {
1041
- indicator,
1042
- }),
1043
- // input
1044
- ...(filled === "True" && {
1045
- defaultValue,
1046
- }),
1047
- ...(states.includes("Invalid") && {
1048
- invalid: true,
1049
- }),
1050
- ...(states.includes("Disabled") && {
1051
- disabled: true,
1052
- }),
1053
- ...(states.includes("Read Only") && {
1054
- readOnly: true,
1055
- }),
1056
- // footer
1057
- ...(showFooter &&
1058
- showDescription &&
1059
- states.includes("Invalid") && {
1060
- // invalid인 경우 description을 error로 사용
1061
- errorMessage: description,
1062
- }),
1063
- ...(showFooter &&
1064
- showDescription &&
1065
- !states.includes("Invalid") && {
1066
- // invalid가 아닌 경우 description을 description으로 사용
1067
- description,
1068
- }),
1069
- ...(showFooter &&
1070
- showCharacterCount && {
1071
- maxGraphemeCount: Number(maxCharacterCount),
1072
- }),
1073
- };
1074
-
1075
- const inputProps = {
1076
- placeholder,
1077
- };
1078
-
1079
- const TextFieldChildren = createElement("TextFieldTextarea", inputProps);
1080
-
1081
- return createElement("TextField", commonProps, TextFieldChildren);
1082
- },
1083
- };
1084
-
1085
- const progressCircleHandler: ComponentHandler<ProgressCircleProperties> = {
1086
- key: metadata.progressCircle.key,
1087
- codegen: async ({ componentProperties: props }) => {
1088
- const { value, minValue, maxValue } = match(props.Value.value)
1089
- .with("Indeterminate", () => ({
1090
- value: undefined,
1091
- minValue: undefined,
1092
- maxValue: undefined,
1093
- }))
1094
- .with("0%", () => ({
1095
- value: 0,
1096
- minValue: 0,
1097
- maxValue: 100,
1098
- }))
1099
- .with("25%", () => ({
1100
- value: 25,
1101
- minValue: 0,
1102
- maxValue: 100,
1103
- }))
1104
- .with("75%", () => ({
1105
- value: 75,
1106
- minValue: 0,
1107
- maxValue: 100,
1108
- }))
1109
- .with("100%", () => ({
1110
- value: 100,
1111
- minValue: 0,
1112
- maxValue: 100,
1113
- }))
1114
- .exhaustive();
1115
-
1116
- const commonProps = {
1117
- value,
1118
- minValue,
1119
- maxValue,
1120
- size: props.Size.value,
1121
- tone: camelCase(props.Tone.value),
1122
- };
1123
-
1124
- return createElement("ProgressCircle", commonProps);
1125
- },
1126
- };
1127
-
1128
- const reactionButtonHandler: ComponentHandler<ReactionButtonProperties> = {
1129
- key: metadata.reactionButton.key,
1130
- codegen: async ({ componentProperties: props }) => {
1131
- const states = props.State.value.split("-");
1132
-
1133
- const commonProps = {
1134
- size: handleSize(props.Size.value),
1135
- ...(states.includes("Loading") && {
1136
- loading: true,
1137
- }),
1138
- ...(states.includes("Disabled") && {
1139
- disabled: true,
1140
- }),
1141
- ...(states.includes("Selected") && {
1142
- defaultPressed: true,
1143
- }),
1144
- };
1145
-
1146
- return createElement("ReactionButton", commonProps, [
1147
- createElement("PrefixIcon", {
1148
- svg: createElement(createIconTagNameFromKey(props["Icon#12379:0"].componentKey)),
1149
- }),
1150
- props["Label#6397:0"].value,
1151
- props["Show Count#6397:33"].value
1152
- ? createElement("Count", {}, props["Count#15816:0"].value)
1153
- : undefined,
1154
- ]);
1155
- },
1156
- };
1157
-
1158
- const segmentedControlHandler: ComponentHandler<SegmentedControlProperties> = {
1159
- key: metadata.segmentedControl.key,
1160
- codegen: async (node) => {
1161
- const segments = await findAllInstances<SegmentedControlItemProperties>({
1162
- node,
1163
- key: segmentedControlItemHandler.key,
1164
- });
1165
-
1166
- const selectedSegment = segments.find((segment) =>
1167
- segment.componentProperties.State.value.split("-").includes("Selected"),
1168
- );
1169
-
1170
- const segmentedControlChildren = await Promise.all(
1171
- segments.map(segmentedControlItemHandler.codegen),
1172
- );
1173
-
1174
- const commonProps = {
1175
- ...(selectedSegment && {
1176
- defaultValue: selectedSegment.componentProperties["Label#11366:15"].value,
1177
- }),
1178
- };
1179
-
1180
- return createElement(
1181
- "SegmentedControl",
1182
- commonProps,
1183
- segmentedControlChildren,
1184
- "aria-label이나 aria-labelledby 중 하나를 제공해야 합니다.",
1185
- );
1186
- },
1187
- };
1188
-
1189
- const segmentedControlItemHandler: ComponentHandler<SegmentedControlItemProperties> = {
1190
- key: "9a7ba0d4c041ddbce84ee48881788434fd6bccc8",
1191
- codegen: async ({ componentProperties: props }) => {
1192
- const states = props.State.value.split("-");
1193
- const commonProps = {
1194
- value: props["Label#11366:15"].value,
1195
- ...(states.includes("Disabled") && {
1196
- disabled: true,
1197
- }),
1198
- };
1199
-
1200
- return createElement("SegmentedControlItem", commonProps, props["Label#11366:15"].value);
1201
- },
1202
- };
1203
-
1204
- const selectBoxGroupHandler: ComponentHandler<SelectBoxGroupProperties> = {
1205
- key: metadata.templateSelectBoxGroup.key,
1206
- codegen: async (node) => {
1207
- const props = node.componentProperties;
1208
-
1209
- const tag = (() => {
1210
- switch (props.Control.value) {
1211
- case "Checkbox":
1212
- return "CheckSelectBoxGroup";
1213
- case "Radio":
1214
- return "RadioSelectBoxGroup";
1215
- }
1216
- })();
1217
-
1218
- const selectBoxes = await findAllInstances<SelectBoxProperties>({
1219
- node,
1220
- key: selectBoxHandler.key,
1221
- });
1222
-
1223
- const selectedSelectBox = selectBoxes.find((selectBox) =>
1224
- selectBox.componentProperties.State.value.split("-").includes("Selected"),
1225
- );
1226
-
1227
- const stack = createElement(
1228
- "Stack",
1229
- { gap: "spacingY.componentDefault" },
1230
- await Promise.all(selectBoxes.map(selectBoxHandler.codegen)),
1231
- );
1232
-
1233
- const commonProps = {
1234
- ...(tag === "RadioSelectBoxGroup" && {
1235
- defaultValue: selectedSelectBox?.componentProperties["Label#3635:0"].value,
1236
- }),
1237
- };
1238
-
1239
- return createElement(tag, commonProps, stack);
1240
- },
1241
- };
1242
-
1243
- const selectBoxHandler: ComponentHandler<SelectBoxProperties> = {
1244
- key: metadata.selectBox.key,
1245
- codegen: async ({ componentProperties: props }) => {
1246
- const tag = (() => {
1247
- switch (props.Control.value) {
1248
- case "Checkbox":
1249
- return "CheckSelectBox";
1250
- case "Radio":
1251
- return "RadioSelectBox";
1252
- }
1253
- })();
1254
-
1255
- const states = props.State.value.split("-");
1256
-
1257
- const commonProps = {
1258
- label: props["Label#3635:0"].value,
1259
- ...(props["Show Description#3033:0"].value && {
1260
- description: props["Description #3033:5"].value,
1261
- }),
1262
- ...(tag === "RadioSelectBox" && {
1263
- value: props["Label#3635:0"].value,
1264
- }),
1265
- ...(tag === "CheckSelectBox" &&
1266
- states.includes("Selected") && {
1267
- defaultChecked: true,
1268
- }),
1269
- };
1270
-
1271
- return createElement(tag, commonProps);
1272
- },
1273
- };
1274
-
1275
- const skeletonHandler: ComponentHandler<SkeletonProperties> = {
1276
- key: metadata.skeleton.key,
1277
- codegen: async ({
1278
- componentProperties: props,
1279
- absoluteBoundingBox,
1280
- layoutSizingHorizontal,
1281
- layoutSizingVertical,
1282
- boundVariables,
1283
- }) => {
1284
- const commonProps = {
1285
- radius: camelCase(props.Radius.value),
1286
- width: (() => {
1287
- switch (layoutSizingHorizontal) {
1288
- case "FIXED": {
1289
- const variableId = boundVariables?.size?.x?.id;
1290
- if (variableId) return getLayoutVariableName(variableId);
1291
-
1292
- return `${absoluteBoundingBox?.width}px`;
1293
- }
1294
- case "FILL":
1295
- return "full";
1296
- default:
1297
- return "full";
1298
- }
1299
- })(),
1300
- height: (() => {
1301
- switch (layoutSizingVertical) {
1302
- case "FIXED": {
1303
- const variableId = boundVariables?.size?.y?.id;
1304
- if (variableId) return getLayoutVariableName(variableId);
1305
-
1306
- return `${absoluteBoundingBox?.height}px`;
1307
- }
1308
- case "FILL":
1309
- return "full";
1310
- default:
1311
- return "full";
1312
- }
1313
- })(),
1314
- };
1315
-
1316
- return createElement("Skeleton", commonProps);
1317
- },
1318
- };
1319
-
1320
- const snackbarHandler: ComponentHandler<SnackbarProperties> = {
1321
- key: metadata.snackbar.key,
1322
- codegen: async ({ componentProperties: props }) => {
1323
- const commonProps = {
1324
- message: props["Message#1528:4"].value,
1325
- variant: camelCase(props.Variant.value),
1326
- ...(props["Show Action Button#1528:0"].value && {
1327
- actionLabel: props["Action Button Label#1528:8"].value,
1328
- }),
1329
- };
1330
-
1331
- // TODO: adapter.create({ render })
1332
- return createElement("Snackbar", commonProps);
1333
- },
1334
- };
1335
-
1336
- const tabsHandler: ComponentHandler<TabsProperties> = {
1337
- key: metadata.tablist.key,
1338
- codegen: async ({ componentProperties: props, children }) => {
1339
- const tabsItems = children
1340
- .map((child) => {
1341
- if (child.type !== "INSTANCE") return null;
1342
-
1343
- const componentKey = child.componentSetKey ? child.componentSetKey : child.componentKey;
1344
-
1345
- if (componentKey === tabsHugItemHandler.key)
1346
- return {
1347
- triggerLayout: "hug" as const,
1348
- node: child as NormalizedInstanceNode & { componentProperties: TabsHugItemProperties },
1349
- };
1350
-
1351
- if (componentKey === tabsFillItemHandler.key)
1352
- return {
1353
- triggerLayout: "fill" as const,
1354
- node: child as NormalizedInstanceNode & { componentProperties: TabsFillItemProperties },
1355
- };
1356
-
1357
- return null;
1358
- })
1359
- .filter((tabsItem) => tabsItem !== null);
1360
-
1361
- const selectedTabsItem = tabsItems.find(({ node: { componentProperties } }) =>
1362
- componentProperties.State.value.split("-").includes("Selected"),
1363
- )?.node;
1364
-
1365
- const tabTriggerList = createElement(
1366
- "TabsList",
1367
- undefined,
1368
- await Promise.all(
1369
- tabsItems.map(({ triggerLayout, node }) => {
1370
- switch (triggerLayout) {
1371
- case "hug":
1372
- return tabsHugItemHandler.codegen(node);
1373
- case "fill":
1374
- return tabsFillItemHandler.codegen(node);
1375
- }
1376
- }),
1377
- ),
1378
- );
1379
-
1380
- const tabContents = tabsItems.map(({ node }) => {
1381
- const value = node.componentProperties["Label#4478:2"].value;
1382
-
1383
- return createElement("TabsContent", { value }, "{/* TODO: 컨텐츠 추가 */}");
1384
- });
1385
-
1386
- const commonProps = {
1387
- triggerLayout: camelCase(props.Layout.value),
1388
- size: handleSize(props.Size.value),
1389
- ...(selectedTabsItem && {
1390
- defaultValue: selectedTabsItem.componentProperties["Label#4478:2"].value,
1391
- }),
1392
- };
1393
-
1394
- return createElement("TabsRoot", commonProps, [tabTriggerList, ...tabContents]);
1395
- },
1396
- };
1397
-
1398
- const tabsHugItemHandler: ComponentHandler<TabsHugItemProperties> = {
1399
- key: "c242492543b327ceb84fa9933841512fc62a898c",
1400
- codegen: async ({ componentProperties: props }) => {
1401
- const states = props.State.value.split("-");
1402
-
1403
- const commonProps = {
1404
- value: props["Label#4478:2"].value,
1405
- ...(props.Notification.value === "True" && {
1406
- alert: true,
1407
- }),
1408
- ...(states.includes("Disabled") && {
1409
- disabled: true,
1410
- }),
1411
- };
1412
-
1413
- return createElement("TabsTrigger", commonProps, props["Label#4478:2"].value);
1414
- },
1415
- };
1416
-
1417
- const tabsFillItemHandler: ComponentHandler<TabsFillItemProperties> = {
1418
- key: "7275293344efb40ee9a3f5248ba2659b94a0b305",
1419
- codegen: async ({ componentProperties: props }) => {
1420
- const states = props.State.value.split("-");
1421
-
1422
- const commonProps = {
1423
- value: props["Label#4478:2"].value,
1424
- ...(props.Notification.value === "True" && {
1425
- alert: true,
1426
- }),
1427
- ...(states.includes("Disabled") && {
1428
- disabled: true,
1429
- }),
1430
- };
1431
-
1432
- return createElement("TabsTrigger", commonProps, props["Label#4478:2"].value);
1433
- },
1434
- };
1435
-
1436
- const textButtonHandler: ComponentHandler<TextButtonProperties> = {
1437
- key: metadata.textButton.key,
1438
- codegen: async (node) => {
1439
- const { componentProperties: props } = node;
1440
-
1441
- const states = props.State.value.split("-");
1442
-
1443
- const { prefixIcon, suffixIcon, children } = await match(props.Layout.value)
1444
- .with("Icon First", async () => ({
1445
- prefixIcon: createElement(
1446
- createIconTagNameFromKey(props["Prefix Icon#7561:0"].componentKey),
1447
- ),
1448
- suffixIcon: undefined,
1449
- children: props["Label#6148:0"].value,
1450
- }))
1451
- .with("Icon Last", () => {
1452
- const suffixIconNode = findOne(
1453
- node,
1454
- (node) => node.type === "INSTANCE" && node.name === "Suffix Icon",
1455
- ) as NormalizedInstanceNode | null;
1456
-
1457
- const suffixIconComponentKey = suffixIconNode?.componentKey;
1458
-
1459
- return {
1460
- prefixIcon: undefined,
1461
- suffixIcon: suffixIconComponentKey
1462
- ? createElement(createIconTagNameFromKey(suffixIconComponentKey))
1463
- : undefined,
1464
- children: props["Label#6148:0"].value,
1465
- };
1466
- })
1467
- .exhaustive();
1468
-
1469
- const commonProps = {
1470
- tone: camelCase(props.Tone.value),
1471
- size: handleSize(props.Size.value),
1472
- prefixIcon,
1473
- suffixIcon,
1474
- ...(states.includes("Disabled") && {
1475
- disabled: true,
1476
- }),
1477
- };
1478
-
1479
- return createElement("TextButton", commonProps, children);
1480
- },
1481
- };
1482
-
1483
- const textFieldHandler: ComponentHandler<TextFieldProperties> = {
1484
- key: metadata.textField.key,
1485
- codegen: async ({ componentProperties: props }) => {
1486
- const {
1487
- Size: { value: size },
1488
- State: { value: state },
1489
- Filled: { value: filled },
1490
- "Show Header#870:0": { value: showHeader },
1491
- "Label#14964:0": { value: label },
1492
- "Show Indicator#1259:0": { value: showIndicator },
1493
- "Indicator#15327:249": { value: indicator },
1494
- "Show Prefix#958:125": { value: showPrefix },
1495
- "Show Prefix Icon#1267:50": { value: showPrefixIcon },
1496
- "Prefix Icon#1267:25": { value: prefixIcon },
1497
- "Show Prefix Text#1267:0": { value: showPrefixText },
1498
- "Prefix Text#15327:101": { value: prefix },
1499
- "Placeholder#958:0": { value: placeholder },
1500
- "Filled Text#1304:0": { value: defaultValue },
1501
- "Show Suffix#958:100": { value: showSuffix },
1502
- "Show Suffix Icon#1267:75": { value: showSuffixIcon },
1503
- "Suffix Icon #1267:100": { value: suffixIcon },
1504
- "Show Suffix Text#1267:125": { value: showSuffixText },
1505
- "Suffix Text#15327:138": { value: suffix },
1506
- "Show Footer#958:25": { value: showFooter },
1507
- "Show Description#958:50": { value: showDescription },
1508
- "Description#12626:5": { value: description },
1509
- "Show Character Count#958:75": { value: showCharacterCount },
1510
- "Character Count#15327:64": { value: _characterCount },
1511
- "Max Character Count#15327:27": { value: maxCharacterCount },
1512
- } = props;
1513
-
1514
- const states = state.split("-");
1515
-
1516
- const commonProps = {
1517
- size: handleSize(size),
1518
- // header
1519
- ...(showHeader && {
1520
- label,
1521
- }),
1522
- ...(showHeader &&
1523
- showIndicator && {
1524
- indicator,
1525
- }),
1526
- // input affixes
1527
- ...(showPrefix &&
1528
- showPrefixIcon && {
1529
- prefixIcon: createElement(createIconTagNameFromKey(prefixIcon)),
1530
- }),
1531
- ...(showPrefix &&
1532
- showPrefixText && {
1533
- prefix,
1534
- }),
1535
- ...(showSuffix &&
1536
- showSuffixIcon && {
1537
- suffixIcon: createElement(createIconTagNameFromKey(suffixIcon)),
1538
- }),
1539
- ...(showSuffix &&
1540
- showSuffixText && {
1541
- suffix,
1542
- }),
1543
- // input
1544
- ...(filled === "True" && {
1545
- defaultValue,
1546
- }),
1547
- ...(states.includes("Invalid") && {
1548
- invalid: true,
1549
- }),
1550
- ...(states.includes("Disabled") && {
1551
- disabled: true,
1552
- }),
1553
- ...(states.includes("Read Only") && {
1554
- readOnly: true,
1555
- }),
1556
- // footer
1557
- ...(showFooter &&
1558
- showDescription &&
1559
- states.includes("Invalid") && {
1560
- // invalid인 경우 description을 error로 사용
1561
- errorMessage: description,
1562
- }),
1563
- ...(showFooter &&
1564
- showDescription &&
1565
- !states.includes("Invalid") && {
1566
- // invalid가 아닌 경우 description을 description으로 사용
1567
- description,
1568
- }),
1569
- ...(showFooter &&
1570
- showCharacterCount && {
1571
- maxGraphemeCount: Number(maxCharacterCount),
1572
- }),
1573
- };
1574
-
1575
- const inputProps = {
1576
- placeholder,
1577
- };
1578
-
1579
- const TextFieldChildren = createElement("TextFieldInput", inputProps);
1580
-
1581
- return createElement("TextField", commonProps, TextFieldChildren);
1582
- },
1583
- };
1584
-
1585
- const switchHandler: ComponentHandler<SwitchProperties> = {
1586
- key: metadata.switch.key,
1587
- codegen: async ({ componentProperties: props }) => {
1588
- const states = props.State.value.split("-");
1589
-
1590
- const size = handleSize(props.Size.value);
1591
-
1592
- const commonProps = {
1593
- size,
1594
- ...(size === "small" && {
1595
- label: props["Label#15191:2"].value,
1596
- }),
1597
- ...(states.includes("Selected") && {
1598
- defaultChecked: true,
1599
- }),
1600
- ...(states.includes("Disabled") && {
1601
- disabled: true,
1602
- }),
1603
- };
1604
-
1605
- return createElement("Switch", commonProps);
1606
- },
1607
- };
1608
-
1609
- const toggleButtonHandler: ComponentHandler<ToggleButtonProperties> = {
1610
- key: metadata.toggleButton.key,
1611
- codegen: async ({ componentProperties: props }) => {
1612
- const states = props.State.value.split("-");
1613
-
1614
- const commonProps = {
1615
- variant: camelCase(props.Variant.value),
1616
- size: handleSize(props.Size.value),
1617
- ...(states.includes("Selected") && {
1618
- defaultPressed: true,
1619
- }),
1620
- ...(states.includes("Disabled") && {
1621
- disabled: true,
1622
- }),
1623
- ...(states.includes("Loading") && {
1624
- loading: true,
1625
- }),
1626
- };
1627
-
1628
- return createElement("ToggleButton", commonProps, [
1629
- props["Show Prefix Icon#6122:392"].value
1630
- ? createElement("PrefixIcon", {
1631
- svg: createElement(createIconTagNameFromKey(props["Prefix Icon#6122:98"].componentKey)),
1632
- })
1633
- : undefined,
1634
- props["Label#6122:49"].value,
1635
- props["Show Suffix Icon#6122:147"].value
1636
- ? createElement("SuffixIcon", {
1637
- svg: createElement(
1638
- createIconTagNameFromKey(props["Suffix Icon#6122:343"].componentKey),
1639
- ),
1640
- })
1641
- : undefined,
1642
- ]);
1643
- },
1644
- };
1
+ import { actionButtonHandler } from "./handlers/action-button";
2
+ import { actionChipHandler } from "./handlers/action-chip";
3
+ import { actionSheetHandler } from "./handlers/action-sheet";
4
+ import { appBarHandler } from "./handlers/app-bar";
5
+ import { avatarHandler } from "./handlers/avatar";
6
+ import { avatarStackHandler } from "./handlers/avatar-stack";
7
+ import { badgeHandler } from "./handlers/badge";
8
+ import { calloutHandler } from "./handlers/callout";
9
+ import { checkboxHandler } from "./handlers/checkbox";
10
+ import { chipTabsHandler } from "./handlers/chip-tabs";
11
+ import { controlChipHandler } from "./handlers/control-chip";
12
+ import { errorStateHandler } from "./handlers/error-state";
13
+ import { extendedActionSheetHandler } from "./handlers/extended-action-sheet";
14
+ import { extendedFabHandler } from "./handlers/extended-fab";
15
+ import { fabHandler } from "./handlers/fab";
16
+ import { helpBubbleHandler } from "./handlers/help-bubble";
17
+ import { identityPlaceholderHandler } from "./handlers/identity-placeholder";
18
+ import { inlineBannerHandler } from "./handlers/inline-banner";
19
+ import { mannerTempBadgeHandler } from "./handlers/manner-temp-badge";
20
+ import { multilineTextFieldHandler } from "./handlers/multiline-text-field";
21
+ import { progressCircleHandler } from "./handlers/progress-circle";
22
+ import { reactionButtonHandler } from "./handlers/reaction-button";
23
+ import { segmentedControlHandler } from "./handlers/segmented-control";
24
+ import { selectBoxGroupHandler, selectBoxHandler } from "./handlers/select-box";
25
+ import { skeletonHandler } from "./handlers/skeleton";
26
+ import { snackbarHandler } from "./handlers/snackbar";
27
+ import { switchHandler } from "./handlers/switch";
28
+ import { tabsHandler } from "./handlers/tabs";
29
+ import { textButtonHandler } from "./handlers/text-button";
30
+ import { textFieldHandler } from "./handlers/text-field";
31
+ import { toggleButtonHandler } from "./handlers/toggle-button";
32
+ import type { ComponentHandler } from "./type-helper";
1645
33
 
1646
34
  const componentHandlers = [
1647
35
  actionButtonHandler,