@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.
- package/lib/codegen/index.cjs +23543 -0
- package/lib/codegen/index.d.ts +2957 -0
- package/lib/codegen/index.d.ts.map +1 -0
- package/lib/codegen/index.js +23514 -0
- package/lib/codegen/targets/react/index.cjs +31980 -0
- package/lib/codegen/targets/react/index.d.ts +308 -0
- package/lib/codegen/targets/react/index.d.ts.map +1 -0
- package/lib/codegen/targets/react/index.js +31961 -0
- package/lib/index.cjs +26905 -0
- package/lib/index.d.ts +221 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +26884 -0
- package/package.json +56 -0
- package/src/codegen/component-properties.archive.ts +1019 -0
- package/src/codegen/component-properties.ts +369 -0
- package/src/codegen/core/codegen.ts +112 -0
- package/src/codegen/core/component-handler.ts +23 -0
- package/src/codegen/core/component-type-helper.ts +35 -0
- package/src/codegen/core/element-transformer.ts +13 -0
- package/src/codegen/core/index.ts +19 -0
- package/src/codegen/core/infer-layout.test.ts +286 -0
- package/src/codegen/core/infer-layout.ts +416 -0
- package/src/codegen/core/jsx.ts +174 -0
- package/src/codegen/core/props-converter.ts +78 -0
- package/src/codegen/core/value-resolver.ts +381 -0
- package/src/codegen/default-services.ts +44 -0
- package/src/codegen/index.ts +3 -0
- package/src/codegen/skip-components.ts +7 -0
- package/src/codegen/targets/figma/frame.ts +38 -0
- package/src/codegen/targets/figma/index.ts +6 -0
- package/src/codegen/targets/figma/instance.ts +36 -0
- package/src/codegen/targets/figma/pipeline.ts +106 -0
- package/src/codegen/targets/figma/props.ts +262 -0
- package/src/codegen/targets/figma/shape.ts +65 -0
- package/src/codegen/targets/figma/text.ts +30 -0
- package/src/codegen/targets/figma/value-resolver.ts +75 -0
- package/src/codegen/targets/index.ts +2 -0
- package/src/codegen/targets/react/component/deps.interface.ts +7 -0
- package/src/codegen/targets/react/component/handlers/action-button.ts +149 -0
- package/src/codegen/targets/react/component/handlers/alert-dialog.ts +120 -0
- package/src/codegen/targets/react/component/handlers/app-bar.ts +169 -0
- package/src/codegen/targets/react/component/handlers/archive/action-button.ts +144 -0
- package/src/codegen/targets/react/component/handlers/archive/alert-dialog.ts +122 -0
- package/src/codegen/targets/react/component/handlers/archive/app-bar.ts +149 -0
- package/src/codegen/targets/react/component/handlers/archive/avatar-stack.ts +35 -0
- package/src/codegen/targets/react/component/handlers/archive/avatar.ts +55 -0
- package/src/codegen/targets/react/component/handlers/archive/badge.ts +18 -0
- package/src/codegen/targets/react/component/handlers/archive/bottom-sheet.ts +70 -0
- package/src/codegen/targets/react/component/handlers/archive/callout.ts +88 -0
- package/src/codegen/targets/react/component/handlers/archive/checkbox.ts +43 -0
- package/src/codegen/targets/react/component/handlers/archive/checkmark.ts +29 -0
- package/src/codegen/targets/react/component/handlers/archive/chip.ts +90 -0
- package/src/codegen/targets/react/component/handlers/archive/contextual-floating-button.ts +52 -0
- package/src/codegen/targets/react/component/handlers/archive/divider.ts +25 -0
- package/src/codegen/targets/react/component/handlers/archive/field-button.ts +197 -0
- package/src/codegen/targets/react/component/handlers/archive/field.ts +167 -0
- package/src/codegen/targets/react/component/handlers/archive/floating-action-button.ts +48 -0
- package/src/codegen/targets/react/component/handlers/archive/help-bubble.ts +73 -0
- package/src/codegen/targets/react/component/handlers/archive/identity-placeholder.ts +21 -0
- package/src/codegen/targets/react/component/handlers/archive/index.ts +40 -0
- package/src/codegen/targets/react/component/handlers/archive/legacy-select-box.ts +89 -0
- package/src/codegen/targets/react/component/handlers/archive/legacy-text-field.ts +198 -0
- package/src/codegen/targets/react/component/handlers/archive/list-header.ts +20 -0
- package/src/codegen/targets/react/component/handlers/archive/list-item.ts +162 -0
- package/src/codegen/targets/react/component/handlers/archive/manner-temp-badge.ts +21 -0
- package/src/codegen/targets/react/component/handlers/archive/manner-temp.ts +18 -0
- package/src/codegen/targets/react/component/handlers/archive/menu-sheet.ts +108 -0
- package/src/codegen/targets/react/component/handlers/archive/page-banner.ts +101 -0
- package/src/codegen/targets/react/component/handlers/archive/progress-circle.ts +55 -0
- package/src/codegen/targets/react/component/handlers/archive/radio-group.ts +31 -0
- package/src/codegen/targets/react/component/handlers/archive/radiomark.ts +27 -0
- package/src/codegen/targets/react/component/handlers/archive/reaction-button.ts +37 -0
- package/src/codegen/targets/react/component/handlers/archive/result-section.ts +67 -0
- package/src/codegen/targets/react/component/handlers/archive/segmented-control.ts +64 -0
- package/src/codegen/targets/react/component/handlers/archive/skeleton.ts +26 -0
- package/src/codegen/targets/react/component/handlers/archive/slider.ts +114 -0
- package/src/codegen/targets/react/component/handlers/archive/snackbar.ts +25 -0
- package/src/codegen/targets/react/component/handlers/archive/switch.ts +39 -0
- package/src/codegen/targets/react/component/handlers/archive/switchmark.ts +26 -0
- package/src/codegen/targets/react/component/handlers/archive/tabs.ts +297 -0
- package/src/codegen/targets/react/component/handlers/archive/tag-group.ts +86 -0
- package/src/codegen/targets/react/component/handlers/archive/text-field.ts +264 -0
- package/src/codegen/targets/react/component/handlers/archive/toggle-button.ts +43 -0
- package/src/codegen/targets/react/component/handlers/avatar-stack.ts +38 -0
- package/src/codegen/targets/react/component/handlers/avatar.ts +58 -0
- package/src/codegen/targets/react/component/handlers/badge.ts +18 -0
- package/src/codegen/targets/react/component/handlers/bottom-sheet.ts +74 -0
- package/src/codegen/targets/react/component/handlers/callout.ts +88 -0
- package/src/codegen/targets/react/component/handlers/checkbox.ts +129 -0
- package/src/codegen/targets/react/component/handlers/checkmark.ts +29 -0
- package/src/codegen/targets/react/component/handlers/chip.ts +93 -0
- package/src/codegen/targets/react/component/handlers/content-placeholder.ts +20 -0
- package/src/codegen/targets/react/component/handlers/contextual-floating-button.ts +52 -0
- package/src/codegen/targets/react/component/handlers/divider.ts +25 -0
- package/src/codegen/targets/react/component/handlers/field-button.ts +192 -0
- package/src/codegen/targets/react/component/handlers/field.ts +164 -0
- package/src/codegen/targets/react/component/handlers/floating-action-button.ts +45 -0
- package/src/codegen/targets/react/component/handlers/help-bubble.ts +73 -0
- package/src/codegen/targets/react/component/handlers/identity-placeholder.ts +20 -0
- package/src/codegen/targets/react/component/handlers/image-frame.ts +147 -0
- package/src/codegen/targets/react/component/handlers/index.ts +43 -0
- package/src/codegen/targets/react/component/handlers/legacy-select-box.ts +87 -0
- package/src/codegen/targets/react/component/handlers/legacy-text-field.ts +196 -0
- package/src/codegen/targets/react/component/handlers/list-header.ts +20 -0
- package/src/codegen/targets/react/component/handlers/list-item.ts +163 -0
- package/src/codegen/targets/react/component/handlers/manner-temp-badge.ts +21 -0
- package/src/codegen/targets/react/component/handlers/manner-temp.ts +18 -0
- package/src/codegen/targets/react/component/handlers/menu-sheet.ts +111 -0
- package/src/codegen/targets/react/component/handlers/page-banner.ts +106 -0
- package/src/codegen/targets/react/component/handlers/progress-circle.ts +55 -0
- package/src/codegen/targets/react/component/handlers/radio-group.ts +109 -0
- package/src/codegen/targets/react/component/handlers/radiomark.ts +27 -0
- package/src/codegen/targets/react/component/handlers/reaction-button.ts +37 -0
- package/src/codegen/targets/react/component/handlers/result-section.ts +67 -0
- package/src/codegen/targets/react/component/handlers/segmented-control.ts +63 -0
- package/src/codegen/targets/react/component/handlers/select-box.ts +333 -0
- package/src/codegen/targets/react/component/handlers/skeleton.ts +26 -0
- package/src/codegen/targets/react/component/handlers/slider.ts +117 -0
- package/src/codegen/targets/react/component/handlers/snackbar.ts +25 -0
- package/src/codegen/targets/react/component/handlers/switch.ts +35 -0
- package/src/codegen/targets/react/component/handlers/switchmark.ts +26 -0
- package/src/codegen/targets/react/component/handlers/tabs.ts +298 -0
- package/src/codegen/targets/react/component/handlers/tag-group.ts +90 -0
- package/src/codegen/targets/react/component/handlers/text-field.ts +253 -0
- package/src/codegen/targets/react/component/handlers/toggle-button.ts +43 -0
- package/src/codegen/targets/react/component/index.ts +24 -0
- package/src/codegen/targets/react/component/size.ts +22 -0
- package/src/codegen/targets/react/element-factories.ts +59 -0
- package/src/codegen/targets/react/frame.ts +96 -0
- package/src/codegen/targets/react/icon.ts +55 -0
- package/src/codegen/targets/react/index.ts +7 -0
- package/src/codegen/targets/react/instance.ts +82 -0
- package/src/codegen/targets/react/pipeline.ts +133 -0
- package/src/codegen/targets/react/props.ts +417 -0
- package/src/codegen/targets/react/shape.ts +47 -0
- package/src/codegen/targets/react/text.ts +31 -0
- package/src/codegen/targets/react/value-resolver.ts +93 -0
- package/src/entities/component.interface.ts +7 -0
- package/src/entities/component.repository.ts +16 -0
- package/src/entities/data/__generated__/archive/component-sets/index.d.ts +2074 -0
- package/src/entities/data/__generated__/archive/component-sets/index.mjs +2074 -0
- package/src/entities/data/__generated__/archive/components/index.d.ts +116 -0
- package/src/entities/data/__generated__/archive/components/index.mjs +116 -0
- package/src/entities/data/__generated__/archive/styles/index.d.ts +3 -0
- package/src/entities/data/__generated__/archive/styles/index.mjs +429 -0
- package/src/entities/data/__generated__/archive/variable-collections/index.d.ts +3 -0
- package/src/entities/data/__generated__/archive/variable-collections/index.mjs +501 -0
- package/src/entities/data/__generated__/archive/variables/index.d.ts +3 -0
- package/src/entities/data/__generated__/archive/variables/index.mjs +7019 -0
- package/src/entities/data/__generated__/component-sets/index.d.ts +4325 -0
- package/src/entities/data/__generated__/component-sets/index.mjs +4325 -0
- package/src/entities/data/__generated__/components/index.d.ts +378 -0
- package/src/entities/data/__generated__/components/index.mjs +378 -0
- package/src/entities/data/__generated__/icons/index.d.ts +3 -0
- package/src/entities/data/__generated__/icons/index.mjs +3476 -0
- package/src/entities/data/__generated__/styles/index.d.ts +3 -0
- package/src/entities/data/__generated__/styles/index.mjs +436 -0
- package/src/entities/data/__generated__/variable-collections/index.d.ts +3 -0
- package/src/entities/data/__generated__/variable-collections/index.mjs +479 -0
- package/src/entities/data/__generated__/variables/index.d.ts +3 -0
- package/src/entities/data/__generated__/variables/index.mjs +6969 -0
- package/src/entities/icon.interface.ts +5 -0
- package/src/entities/icon.repository.ts +11 -0
- package/src/entities/icon.service.ts +26 -0
- package/src/entities/index.ts +60 -0
- package/src/entities/style.interface.ts +5 -0
- package/src/entities/style.repository.ts +27 -0
- package/src/entities/style.service.ts +36 -0
- package/src/entities/variable.interface.ts +18 -0
- package/src/entities/variable.repository.ts +57 -0
- package/src/entities/variable.service.ts +101 -0
- package/src/index.ts +3 -0
- package/src/normalizer/from-plugin.ts +602 -0
- package/src/normalizer/from-rest.ts +577 -0
- package/src/normalizer/index.ts +3 -0
- package/src/normalizer/types.ts +208 -0
- package/src/utils/common.ts +38 -0
- package/src/utils/css.ts +19 -0
- package/src/utils/figma-gradient.ts +72 -0
- package/src/utils/figma-node.ts +95 -0
- package/src/utils/figma-variable.ts +49 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ComponentHandler } from "@/codegen/core";
|
|
2
|
+
import type { NormalizedInstanceNode } from "@/normalizer";
|
|
3
|
+
import type { ComponentHandlerDeps } from "./deps.interface";
|
|
4
|
+
|
|
5
|
+
import * as archivedHandlers from "./handlers/archive";
|
|
6
|
+
import * as currentHandlers from "./handlers";
|
|
7
|
+
|
|
8
|
+
export type { ComponentHandlerDeps };
|
|
9
|
+
export type UnboundComponentHandler<T extends NormalizedInstanceNode["componentProperties"]> = (
|
|
10
|
+
deps: ComponentHandlerDeps,
|
|
11
|
+
) => ComponentHandler<T>;
|
|
12
|
+
|
|
13
|
+
export function bindComponentHandler<T extends NormalizedInstanceNode["componentProperties"]>(
|
|
14
|
+
unbound: UnboundComponentHandler<T>,
|
|
15
|
+
deps: ComponentHandlerDeps,
|
|
16
|
+
): ComponentHandler<T> {
|
|
17
|
+
return unbound(deps);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// biome-ignore lint/suspicious/noExplicitAny: handlers have different component property types
|
|
21
|
+
export const unboundSeedComponentHandlers: Array<UnboundComponentHandler<any>> = [
|
|
22
|
+
...Object.values(archivedHandlers),
|
|
23
|
+
...Object.values(currentHandlers),
|
|
24
|
+
];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// TODO: move this file to relevant directory
|
|
2
|
+
|
|
3
|
+
import { camelCase } from "change-case";
|
|
4
|
+
|
|
5
|
+
type SizeProp = "XSmall" | "Small" | "Medium" | "Large" | "XLarge" | ({} & string);
|
|
6
|
+
|
|
7
|
+
export function handleSizeProp(size: SizeProp) {
|
|
8
|
+
switch (size) {
|
|
9
|
+
case "XSmall":
|
|
10
|
+
return "xsmall";
|
|
11
|
+
case "Small":
|
|
12
|
+
return "small";
|
|
13
|
+
case "Medium":
|
|
14
|
+
return "medium";
|
|
15
|
+
case "Large":
|
|
16
|
+
return "large";
|
|
17
|
+
case "XLarge":
|
|
18
|
+
return "xlarge";
|
|
19
|
+
default:
|
|
20
|
+
return camelCase(size);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createElement, type ElementNode } from "@/codegen/core";
|
|
2
|
+
|
|
3
|
+
const SEED_REACT_IMPORT_PATH = "@seed-design/react";
|
|
4
|
+
const LOCAL_SNIPPET_BASE_PATH = "seed-design/ui";
|
|
5
|
+
const MONOCHROME_ICON_IMPORT_PATH = "@karrotmarket/react-monochrome-icon";
|
|
6
|
+
const MULTICOLOR_ICON_IMPORT_PATH = "@karrotmarket/react-multicolor-icon";
|
|
7
|
+
|
|
8
|
+
type CreateElementArgs = Parameters<typeof createElement>;
|
|
9
|
+
|
|
10
|
+
export function createSeedReactElement(
|
|
11
|
+
tag: CreateElementArgs[0],
|
|
12
|
+
props?: CreateElementArgs[1],
|
|
13
|
+
children?: CreateElementArgs[2],
|
|
14
|
+
meta?: CreateElementArgs[3],
|
|
15
|
+
): ElementNode {
|
|
16
|
+
return createElement(tag, props, children, {
|
|
17
|
+
importPath: SEED_REACT_IMPORT_PATH,
|
|
18
|
+
...meta,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function createMonochromeIconElement(
|
|
23
|
+
tag: CreateElementArgs[0],
|
|
24
|
+
props?: CreateElementArgs[1],
|
|
25
|
+
children?: CreateElementArgs[2],
|
|
26
|
+
meta?: CreateElementArgs[3],
|
|
27
|
+
): ElementNode {
|
|
28
|
+
return createElement(tag, props, children, {
|
|
29
|
+
...meta,
|
|
30
|
+
importPath: MONOCHROME_ICON_IMPORT_PATH,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function createMulticolorIconElement(
|
|
35
|
+
tag: CreateElementArgs[0],
|
|
36
|
+
props?: CreateElementArgs[1],
|
|
37
|
+
children?: CreateElementArgs[2],
|
|
38
|
+
meta?: CreateElementArgs[3],
|
|
39
|
+
): ElementNode {
|
|
40
|
+
return createElement(tag, props, children, { ...meta, importPath: MULTICOLOR_ICON_IMPORT_PATH });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function createLocalSnippetHelper(moduleName: string) {
|
|
44
|
+
function createLocalSnippetElement(
|
|
45
|
+
tag: CreateElementArgs[0],
|
|
46
|
+
props?: CreateElementArgs[1],
|
|
47
|
+
children?: CreateElementArgs[2],
|
|
48
|
+
meta?: CreateElementArgs[3],
|
|
49
|
+
): ElementNode {
|
|
50
|
+
return createElement(tag, props, children, {
|
|
51
|
+
importPath: `${LOCAL_SNIPPET_BASE_PATH}/${moduleName}`,
|
|
52
|
+
...meta,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
createLocalSnippetElement,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NormalizedComponentNode,
|
|
3
|
+
NormalizedFrameNode,
|
|
4
|
+
NormalizedInstanceNode,
|
|
5
|
+
} from "@/normalizer";
|
|
6
|
+
import {
|
|
7
|
+
cloneElement,
|
|
8
|
+
createElement,
|
|
9
|
+
defineElementTransformer,
|
|
10
|
+
type ElementTransformer,
|
|
11
|
+
} from "../../core";
|
|
12
|
+
import { createSeedReactElement } from "./element-factories";
|
|
13
|
+
import type { ContainerLayoutProps, PropsConverters } from "./props";
|
|
14
|
+
|
|
15
|
+
export interface FrameTransformerDeps {
|
|
16
|
+
propsConverters: PropsConverters;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createFrameTransformer({
|
|
20
|
+
propsConverters,
|
|
21
|
+
}: FrameTransformerDeps): ElementTransformer<
|
|
22
|
+
NormalizedFrameNode | NormalizedInstanceNode | NormalizedComponentNode
|
|
23
|
+
> {
|
|
24
|
+
function inferLayoutComponent(props: ContainerLayoutProps, isFlex: boolean) {
|
|
25
|
+
if (!isFlex) {
|
|
26
|
+
return "Box";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (props.direction === "column") {
|
|
30
|
+
return "VStack";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return "HStack";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return defineElementTransformer(
|
|
37
|
+
(node: NormalizedFrameNode | NormalizedInstanceNode | NormalizedComponentNode, traverse) => {
|
|
38
|
+
const children = node.children;
|
|
39
|
+
const transformedChildren = children.map(traverse);
|
|
40
|
+
const isFlex = node.layoutMode === "HORIZONTAL" || node.layoutMode === "VERTICAL";
|
|
41
|
+
|
|
42
|
+
const props = {
|
|
43
|
+
...propsConverters.radius(node),
|
|
44
|
+
...(isFlex ? propsConverters.containerLayout(node) : {}),
|
|
45
|
+
...propsConverters.selfLayout(node),
|
|
46
|
+
...propsConverters.frameFill(node),
|
|
47
|
+
...propsConverters.stroke(node),
|
|
48
|
+
...propsConverters.shadow(node),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const isStretch = props.align === undefined || props.align === "stretch";
|
|
52
|
+
|
|
53
|
+
const layoutComponent = inferLayoutComponent(props, isFlex);
|
|
54
|
+
|
|
55
|
+
const hasSpacingMismatch =
|
|
56
|
+
node.layoutWrap === "WRAP" &&
|
|
57
|
+
node.counterAxisSpacing !== undefined &&
|
|
58
|
+
node.itemSpacing !== node.counterAxisSpacing;
|
|
59
|
+
|
|
60
|
+
const hasImageFill = node.fills.some(({ type }) => type === "IMAGE");
|
|
61
|
+
const imgElement = hasImageFill
|
|
62
|
+
? createElement("img", {
|
|
63
|
+
src: `https://placehold.co/${node.absoluteBoundingBox?.width ?? 100}x${node.absoluteBoundingBox?.height ?? 100}`,
|
|
64
|
+
})
|
|
65
|
+
: undefined;
|
|
66
|
+
|
|
67
|
+
const processedChildren = [
|
|
68
|
+
imgElement,
|
|
69
|
+
...(isStretch
|
|
70
|
+
? transformedChildren.map((child) =>
|
|
71
|
+
child ? cloneElement(child, { alignSelf: undefined }) : child,
|
|
72
|
+
)
|
|
73
|
+
: transformedChildren),
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const comment = [
|
|
77
|
+
hasSpacingMismatch &&
|
|
78
|
+
// currently counterAxisSpacing is only supported when direction=row
|
|
79
|
+
`row-gap과 column-gap이 다릅니다. (row-gap: ${node.counterAxisSpacing}, column-gap: ${node.itemSpacing})`,
|
|
80
|
+
]
|
|
81
|
+
.filter((cmt) => cmt)
|
|
82
|
+
.join(" ");
|
|
83
|
+
|
|
84
|
+
switch (layoutComponent) {
|
|
85
|
+
case "VStack":
|
|
86
|
+
case "HStack": {
|
|
87
|
+
const { direction: _direction, ...rest } = props;
|
|
88
|
+
|
|
89
|
+
return createSeedReactElement(layoutComponent, rest, processedChildren, { comment });
|
|
90
|
+
}
|
|
91
|
+
case "Box":
|
|
92
|
+
return createSeedReactElement("Box", props, processedChildren, { comment });
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { IconService } from "@/entities";
|
|
2
|
+
import { pascalCase } from "change-case";
|
|
3
|
+
import { type ElementNode, createElement } from "../../core";
|
|
4
|
+
import { createMonochromeIconElement, createMulticolorIconElement } from "./element-factories";
|
|
5
|
+
|
|
6
|
+
export interface IconHandler {
|
|
7
|
+
isIconInstance: (node: { componentKey: string }) => boolean;
|
|
8
|
+
transform: (node: { componentKey: string }) => ElementNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface IconHandlerDeps {
|
|
12
|
+
iconService: IconService;
|
|
13
|
+
iconNameFormatter?: (props: { name: string; weight?: string }) => string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const defaultIconNameFormatter = ({ name, weight }: { name: string; weight?: string }) =>
|
|
17
|
+
pascalCase(`${name}${weight ? weight : ""}`);
|
|
18
|
+
|
|
19
|
+
export function createIconHandler({
|
|
20
|
+
iconService,
|
|
21
|
+
iconNameFormatter = defaultIconNameFormatter,
|
|
22
|
+
}: IconHandlerDeps): IconHandler {
|
|
23
|
+
function isIconInstance(node: { componentKey: string }): boolean {
|
|
24
|
+
const key = node.componentKey;
|
|
25
|
+
|
|
26
|
+
if (!key) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return iconService.isAvailable(key);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function transform(node: { componentKey: string }): ElementNode {
|
|
34
|
+
const key = node.componentKey;
|
|
35
|
+
const iconData = iconService.getOne(key);
|
|
36
|
+
if (!iconData) {
|
|
37
|
+
return createElement("UnknownIcon");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const { name, weight, type } = iconData;
|
|
41
|
+
|
|
42
|
+
const tagName = iconNameFormatter({ name, weight });
|
|
43
|
+
|
|
44
|
+
if (type === "multicolor") {
|
|
45
|
+
return createMulticolorIconElement(tagName);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return createMonochromeIconElement(tagName);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
isIconInstance,
|
|
53
|
+
transform,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { NormalizedInstanceNode } from "@/normalizer";
|
|
2
|
+
import {
|
|
3
|
+
defineElementTransformer,
|
|
4
|
+
type ComponentHandler,
|
|
5
|
+
type ElementTransformer,
|
|
6
|
+
} from "../../core";
|
|
7
|
+
import { createSeedReactElement } from "./element-factories";
|
|
8
|
+
import type { IconHandler } from "./icon";
|
|
9
|
+
import type { PropsConverters } from "./props";
|
|
10
|
+
|
|
11
|
+
const OVERRIDE_ACCEPTABLE_PROPERTIES: Set<NodeChangeProperty> = new Set([
|
|
12
|
+
"characters",
|
|
13
|
+
"parent",
|
|
14
|
+
"locked",
|
|
15
|
+
"visible",
|
|
16
|
+
"name",
|
|
17
|
+
"x",
|
|
18
|
+
"y",
|
|
19
|
+
"componentProperties",
|
|
20
|
+
"componentPropertyDefinitions",
|
|
21
|
+
"componentPropertyReferences",
|
|
22
|
+
] satisfies NodeChangeProperty[]);
|
|
23
|
+
|
|
24
|
+
export interface InstanceTransformerDeps {
|
|
25
|
+
iconHandler?: IconHandler;
|
|
26
|
+
propsConverters: PropsConverters;
|
|
27
|
+
componentHandlers: Record<string, ComponentHandler>;
|
|
28
|
+
frameTransformer: ElementTransformer<NormalizedInstanceNode>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function createInstanceTransformer({
|
|
32
|
+
iconHandler,
|
|
33
|
+
propsConverters,
|
|
34
|
+
componentHandlers,
|
|
35
|
+
frameTransformer,
|
|
36
|
+
}: InstanceTransformerDeps): ElementTransformer<NormalizedInstanceNode> {
|
|
37
|
+
const transform = defineElementTransformer((node: NormalizedInstanceNode, traverse) => {
|
|
38
|
+
const { componentKey, componentSetKey } = node;
|
|
39
|
+
|
|
40
|
+
if (iconHandler?.isIconInstance(node)) {
|
|
41
|
+
const props = {
|
|
42
|
+
...propsConverters.iconSelfLayout(node),
|
|
43
|
+
...propsConverters.vectorChildrenFill(node),
|
|
44
|
+
};
|
|
45
|
+
return createSeedReactElement("Icon", { svg: iconHandler.transform(node), ...props });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const componentHandler = componentSetKey
|
|
49
|
+
? componentHandlers[componentSetKey]
|
|
50
|
+
: componentHandlers[componentKey];
|
|
51
|
+
|
|
52
|
+
if (componentHandler) {
|
|
53
|
+
const handled = componentHandler.transform(node, traverse);
|
|
54
|
+
|
|
55
|
+
if (node.overrides && node.overrides.length > 0) {
|
|
56
|
+
const overriddenFields = node.overrides
|
|
57
|
+
.flatMap(({ overriddenFields }) => overriddenFields)
|
|
58
|
+
.filter(
|
|
59
|
+
(field) => OVERRIDE_ACCEPTABLE_PROPERTIES.has(field as NodeChangeProperty) === false,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (overriddenFields.length === 0) {
|
|
63
|
+
return handled;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
...handled,
|
|
68
|
+
meta: {
|
|
69
|
+
...handled.meta,
|
|
70
|
+
comment: `${handled.meta.comment ? `${handled.meta.comment} ` : ""}오버라이드된 필드: ${Array.from(new Set(overriddenFields)).join(", ")}`,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return handled;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return frameTransformer(node, traverse);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return transform;
|
|
82
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { createCodeGenerator, createValueResolver } from "@/codegen/core";
|
|
2
|
+
import { iconService, styleService, variableService } from "@/codegen/default-services";
|
|
3
|
+
import { SKIP_COMPONENT_KEYS } from "@/codegen/skip-components";
|
|
4
|
+
import {
|
|
5
|
+
type UnboundComponentHandler,
|
|
6
|
+
bindComponentHandler,
|
|
7
|
+
unboundSeedComponentHandlers,
|
|
8
|
+
} from "./component";
|
|
9
|
+
import { createFrameTransformer } from "./frame";
|
|
10
|
+
import { createIconHandler } from "./icon";
|
|
11
|
+
import { createInstanceTransformer } from "./instance";
|
|
12
|
+
import {
|
|
13
|
+
createContainerLayoutPropsConverter,
|
|
14
|
+
createFrameFillPropsConverter,
|
|
15
|
+
createIconSelfLayoutPropsConverter,
|
|
16
|
+
createRadiusPropsConverter,
|
|
17
|
+
createSelfLayoutPropsConverter,
|
|
18
|
+
createShadowPropsConverter,
|
|
19
|
+
createShapeFillPropsConverter,
|
|
20
|
+
createStrokePropsConverter,
|
|
21
|
+
createTextFillPropsConverter,
|
|
22
|
+
createTypeStylePropsConverter,
|
|
23
|
+
createVectorChildrenFillPropsConverter,
|
|
24
|
+
} from "./props";
|
|
25
|
+
import {
|
|
26
|
+
createBooleanOperationTransformer,
|
|
27
|
+
createRectangleTransformer,
|
|
28
|
+
createVectorTransformer,
|
|
29
|
+
} from "./shape";
|
|
30
|
+
import { createTextTransformer } from "./text";
|
|
31
|
+
import {
|
|
32
|
+
defaultEffectStyleNameFormatter,
|
|
33
|
+
defaultFillStyleResolver,
|
|
34
|
+
defaultRawValueFormatters,
|
|
35
|
+
defaultTextStyleNameFormatter,
|
|
36
|
+
defaultVariableNameFormatter,
|
|
37
|
+
} from "./value-resolver";
|
|
38
|
+
|
|
39
|
+
export interface CreatePipelineConfig {
|
|
40
|
+
shouldInferAutoLayout?: boolean;
|
|
41
|
+
shouldInferVariableName?: boolean;
|
|
42
|
+
extend?: {
|
|
43
|
+
componentHandlers?: Array<UnboundComponentHandler<any>>;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const iconHandler = createIconHandler({
|
|
48
|
+
iconService,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export function createPipeline(options: CreatePipelineConfig = {}) {
|
|
52
|
+
const { shouldInferAutoLayout = true, shouldInferVariableName = true, extend = {} } = options;
|
|
53
|
+
|
|
54
|
+
const valueResolver = createValueResolver({
|
|
55
|
+
variableService,
|
|
56
|
+
variableNameFormatter: defaultVariableNameFormatter,
|
|
57
|
+
styleService,
|
|
58
|
+
textStyleNameFormatter: defaultTextStyleNameFormatter,
|
|
59
|
+
effectStyleNameFormatter: defaultEffectStyleNameFormatter,
|
|
60
|
+
fillStyleResolver: defaultFillStyleResolver,
|
|
61
|
+
rawValueFormatters: defaultRawValueFormatters,
|
|
62
|
+
shouldInferVariableName,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const containerLayoutPropsConverter = createContainerLayoutPropsConverter(valueResolver);
|
|
66
|
+
const selfLayoutPropsConverter = createSelfLayoutPropsConverter(valueResolver);
|
|
67
|
+
const iconSelfLayoutPropsConverter = createIconSelfLayoutPropsConverter(valueResolver);
|
|
68
|
+
const frameFillPropsConverter = createFrameFillPropsConverter(valueResolver);
|
|
69
|
+
const shapeFillPropsConverter = createShapeFillPropsConverter(valueResolver);
|
|
70
|
+
const textFillPropsConverter = createTextFillPropsConverter(valueResolver);
|
|
71
|
+
const vectorChildrenFillPropsConverter = createVectorChildrenFillPropsConverter(valueResolver);
|
|
72
|
+
const radiusPropsConverter = createRadiusPropsConverter(valueResolver);
|
|
73
|
+
const strokePropsConverter = createStrokePropsConverter(valueResolver);
|
|
74
|
+
const shadowPropsConverter = createShadowPropsConverter(valueResolver);
|
|
75
|
+
const typeStylePropsConverter = createTypeStylePropsConverter({
|
|
76
|
+
valueResolver,
|
|
77
|
+
});
|
|
78
|
+
const propsConverters = {
|
|
79
|
+
containerLayout: containerLayoutPropsConverter,
|
|
80
|
+
selfLayout: selfLayoutPropsConverter,
|
|
81
|
+
iconSelfLayout: iconSelfLayoutPropsConverter,
|
|
82
|
+
frameFill: frameFillPropsConverter,
|
|
83
|
+
shapeFill: shapeFillPropsConverter,
|
|
84
|
+
textFill: textFillPropsConverter,
|
|
85
|
+
vectorChildrenFill: vectorChildrenFillPropsConverter,
|
|
86
|
+
radius: radiusPropsConverter,
|
|
87
|
+
stroke: strokePropsConverter,
|
|
88
|
+
shadow: shadowPropsConverter,
|
|
89
|
+
typeStyle: typeStylePropsConverter,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const componentHandlers = Object.fromEntries(
|
|
93
|
+
[...unboundSeedComponentHandlers, ...(extend.componentHandlers ?? [])]
|
|
94
|
+
.map((h) =>
|
|
95
|
+
bindComponentHandler(h, {
|
|
96
|
+
valueResolver,
|
|
97
|
+
iconHandler,
|
|
98
|
+
}),
|
|
99
|
+
)
|
|
100
|
+
.map((t) => [t.key, t]),
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const frameTransformer = createFrameTransformer({
|
|
104
|
+
propsConverters,
|
|
105
|
+
});
|
|
106
|
+
const instanceTransformer = createInstanceTransformer({
|
|
107
|
+
iconHandler,
|
|
108
|
+
propsConverters,
|
|
109
|
+
componentHandlers,
|
|
110
|
+
frameTransformer,
|
|
111
|
+
});
|
|
112
|
+
const textTransformer = createTextTransformer({
|
|
113
|
+
propsConverters,
|
|
114
|
+
});
|
|
115
|
+
const rectangleTransformer = createRectangleTransformer({
|
|
116
|
+
propsConverters,
|
|
117
|
+
});
|
|
118
|
+
const vectorTransformer = createVectorTransformer();
|
|
119
|
+
const booleanOperationTransformer = createBooleanOperationTransformer();
|
|
120
|
+
|
|
121
|
+
const codeGenerator = createCodeGenerator({
|
|
122
|
+
frameTransformer,
|
|
123
|
+
textTransformer,
|
|
124
|
+
rectangleTransformer,
|
|
125
|
+
instanceTransformer,
|
|
126
|
+
vectorTransformer,
|
|
127
|
+
booleanOperationTransformer,
|
|
128
|
+
shouldInferAutoLayout,
|
|
129
|
+
skipComponentKeys: SKIP_COMPONENT_KEYS,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return codeGenerator;
|
|
133
|
+
}
|