@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,38 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NormalizedComponentNode,
|
|
3
|
+
NormalizedFrameNode,
|
|
4
|
+
NormalizedInstanceNode,
|
|
5
|
+
} from "@/normalizer";
|
|
6
|
+
import { createElement, defineElementTransformer, type ElementTransformer } from "../../core";
|
|
7
|
+
import type { PropsConverters } from "./props";
|
|
8
|
+
|
|
9
|
+
export interface FrameTransformerDeps {
|
|
10
|
+
propsConverters: PropsConverters;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createFrameTransformer({
|
|
14
|
+
propsConverters,
|
|
15
|
+
}: FrameTransformerDeps): ElementTransformer<
|
|
16
|
+
NormalizedFrameNode | NormalizedInstanceNode | NormalizedComponentNode
|
|
17
|
+
> {
|
|
18
|
+
return defineElementTransformer(
|
|
19
|
+
(node: NormalizedFrameNode | NormalizedInstanceNode | NormalizedComponentNode, traverse) => {
|
|
20
|
+
const children = node.children;
|
|
21
|
+
|
|
22
|
+
const props = {
|
|
23
|
+
...propsConverters.radius(node),
|
|
24
|
+
...propsConverters.containerLayout(node),
|
|
25
|
+
...propsConverters.selfLayout(node),
|
|
26
|
+
...propsConverters.frameFill(node),
|
|
27
|
+
...propsConverters.stroke(node),
|
|
28
|
+
...propsConverters.shadow(node),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return createElement(
|
|
32
|
+
"Frame",
|
|
33
|
+
props,
|
|
34
|
+
children.map((child) => traverse(child)),
|
|
35
|
+
);
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ComponentRepository } from "@/entities";
|
|
2
|
+
import type { NormalizedInstanceNode } from "@/normalizer";
|
|
3
|
+
import { camelCase } from "change-case";
|
|
4
|
+
import { createElement, defineElementTransformer, type ElementTransformer } from "../../core";
|
|
5
|
+
|
|
6
|
+
export interface InstanceTransformerDeps {
|
|
7
|
+
frameTransformer: ElementTransformer<NormalizedInstanceNode>;
|
|
8
|
+
componentRepository?: ComponentRepository;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createInstanceTransformer({
|
|
12
|
+
frameTransformer,
|
|
13
|
+
componentRepository,
|
|
14
|
+
}: InstanceTransformerDeps): ElementTransformer<NormalizedInstanceNode> {
|
|
15
|
+
const transform = defineElementTransformer((node: NormalizedInstanceNode, traverse) => {
|
|
16
|
+
const component = componentRepository?.getOne(node.componentSetKey ?? node.componentKey);
|
|
17
|
+
|
|
18
|
+
if (component) {
|
|
19
|
+
return createElement("Instance", {
|
|
20
|
+
componentName: component.name,
|
|
21
|
+
...Object.fromEntries(
|
|
22
|
+
Object.entries(node.componentProperties)
|
|
23
|
+
.filter(([_, props]) => props.type === "VARIANT" || props.type === "TEXT")
|
|
24
|
+
.map(([key, props]) => [
|
|
25
|
+
camelCase(key.split("#")[0]),
|
|
26
|
+
camelCase(props.value as string),
|
|
27
|
+
]),
|
|
28
|
+
),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return frameTransformer(node, traverse);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return transform;
|
|
36
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { createCodeGenerator, createValueResolver } from "@/codegen/core";
|
|
2
|
+
import type { CodeGenerator } from "@/codegen/core/codegen";
|
|
3
|
+
import { styleService, variableService } from "@/codegen/default-services";
|
|
4
|
+
import { SKIP_COMPONENT_KEYS } from "@/codegen/skip-components";
|
|
5
|
+
import { componentRepository } from "@/entities";
|
|
6
|
+
import { createFrameTransformer } from "./frame";
|
|
7
|
+
import { createInstanceTransformer } from "./instance";
|
|
8
|
+
import {
|
|
9
|
+
createContainerLayoutPropsConverter,
|
|
10
|
+
createFrameFillPropsConverter,
|
|
11
|
+
createRadiusPropsConverter,
|
|
12
|
+
createSelfLayoutPropsConverter,
|
|
13
|
+
createShadowPropsConverter,
|
|
14
|
+
createShapeFillPropsConverter,
|
|
15
|
+
createStrokePropsConverter,
|
|
16
|
+
createTextFillPropsConverter,
|
|
17
|
+
createTypeStylePropsConverter,
|
|
18
|
+
} from "./props";
|
|
19
|
+
import {
|
|
20
|
+
createBooleanOperationTransformer,
|
|
21
|
+
createRectangleTransformer,
|
|
22
|
+
createVectorTransformer,
|
|
23
|
+
} from "./shape";
|
|
24
|
+
import { createTextTransformer } from "./text";
|
|
25
|
+
import {
|
|
26
|
+
defaultEffectStyleNameFormatter,
|
|
27
|
+
defaultFillStyleResolver,
|
|
28
|
+
defaultRawValueFormatters,
|
|
29
|
+
defaultTextStyleNameFormatter,
|
|
30
|
+
defaultVariableNameFormatter,
|
|
31
|
+
} from "./value-resolver";
|
|
32
|
+
|
|
33
|
+
export interface CreatePipelineConfig {
|
|
34
|
+
shouldInferAutoLayout?: boolean;
|
|
35
|
+
shouldInferVariableName?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createPipeline(options: CreatePipelineConfig = {}): CodeGenerator {
|
|
39
|
+
const { shouldInferAutoLayout = true, shouldInferVariableName = true } = options;
|
|
40
|
+
|
|
41
|
+
const valueResolver = createValueResolver({
|
|
42
|
+
variableService,
|
|
43
|
+
variableNameFormatter: defaultVariableNameFormatter,
|
|
44
|
+
styleService,
|
|
45
|
+
textStyleNameFormatter: defaultTextStyleNameFormatter,
|
|
46
|
+
effectStyleNameFormatter: defaultEffectStyleNameFormatter,
|
|
47
|
+
fillStyleResolver: defaultFillStyleResolver,
|
|
48
|
+
rawValueFormatters: defaultRawValueFormatters,
|
|
49
|
+
shouldInferVariableName,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const containerLayoutPropsConverter = createContainerLayoutPropsConverter(valueResolver);
|
|
53
|
+
const selfLayoutPropsConverter = createSelfLayoutPropsConverter(valueResolver);
|
|
54
|
+
const frameFillPropsConverter = createFrameFillPropsConverter(valueResolver);
|
|
55
|
+
const shapeFillPropsConverter = createShapeFillPropsConverter(valueResolver);
|
|
56
|
+
const textFillPropsConverter = createTextFillPropsConverter(valueResolver);
|
|
57
|
+
const radiusPropsConverter = createRadiusPropsConverter(valueResolver);
|
|
58
|
+
const strokePropsConverter = createStrokePropsConverter(valueResolver);
|
|
59
|
+
const shadowPropsConverter = createShadowPropsConverter(valueResolver);
|
|
60
|
+
const typeStylePropsConverter = createTypeStylePropsConverter(valueResolver);
|
|
61
|
+
|
|
62
|
+
const propsConverters = {
|
|
63
|
+
containerLayout: containerLayoutPropsConverter,
|
|
64
|
+
selfLayout: selfLayoutPropsConverter,
|
|
65
|
+
frameFill: frameFillPropsConverter,
|
|
66
|
+
shapeFill: shapeFillPropsConverter,
|
|
67
|
+
textFill: textFillPropsConverter,
|
|
68
|
+
radius: radiusPropsConverter,
|
|
69
|
+
stroke: strokePropsConverter,
|
|
70
|
+
shadow: shadowPropsConverter,
|
|
71
|
+
typeStyle: typeStylePropsConverter,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const frameTransformer = createFrameTransformer({
|
|
75
|
+
propsConverters,
|
|
76
|
+
});
|
|
77
|
+
const instanceTransformer = createInstanceTransformer({
|
|
78
|
+
frameTransformer,
|
|
79
|
+
componentRepository,
|
|
80
|
+
});
|
|
81
|
+
const textTransformer = createTextTransformer({
|
|
82
|
+
propsConverters,
|
|
83
|
+
});
|
|
84
|
+
const rectangleTransformer = createRectangleTransformer({
|
|
85
|
+
propsConverters,
|
|
86
|
+
});
|
|
87
|
+
const vectorTransformer = createVectorTransformer({
|
|
88
|
+
propsConverters,
|
|
89
|
+
});
|
|
90
|
+
const booleanOperationTransformer = createBooleanOperationTransformer({
|
|
91
|
+
propsConverters,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const codegenTransformer = createCodeGenerator({
|
|
95
|
+
frameTransformer,
|
|
96
|
+
textTransformer,
|
|
97
|
+
rectangleTransformer,
|
|
98
|
+
instanceTransformer,
|
|
99
|
+
vectorTransformer,
|
|
100
|
+
booleanOperationTransformer,
|
|
101
|
+
shouldInferAutoLayout,
|
|
102
|
+
skipComponentKeys: SKIP_COMPONENT_KEYS,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return codegenTransformer;
|
|
106
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { createPropsConverter, definePropsConverter, type PropsConverter } from "@/codegen/core";
|
|
2
|
+
import type {
|
|
3
|
+
NormalizedCornerTrait,
|
|
4
|
+
NormalizedHasChildrenTrait,
|
|
5
|
+
NormalizedHasEffectsTrait,
|
|
6
|
+
NormalizedHasFramePropertiesTrait,
|
|
7
|
+
NormalizedHasGeometryTrait,
|
|
8
|
+
NormalizedHasLayoutTrait,
|
|
9
|
+
NormalizedIsLayerTrait,
|
|
10
|
+
NormalizedTypePropertiesTrait,
|
|
11
|
+
} from "@/normalizer";
|
|
12
|
+
import type { FigmaValueResolver } from "./value-resolver";
|
|
13
|
+
|
|
14
|
+
export interface PropsConverters {
|
|
15
|
+
containerLayout: PropsConverter<ContainerLayoutTrait, ContainerLayoutProps>;
|
|
16
|
+
selfLayout: PropsConverter<SelfLayoutTrait, SelfLayoutProps>;
|
|
17
|
+
radius: PropsConverter<RadiusTrait, RadiusProps>;
|
|
18
|
+
frameFill: PropsConverter<FillTrait, FillProps>;
|
|
19
|
+
shapeFill: PropsConverter<FillTrait, FillProps>;
|
|
20
|
+
textFill: PropsConverter<FillTrait, FillProps>;
|
|
21
|
+
stroke: PropsConverter<StrokeTrait, StrokeProps>;
|
|
22
|
+
shadow: PropsConverter<ShadowTrait, ShadowProps>;
|
|
23
|
+
typeStyle: PropsConverter<TypeStyleTrait, TypeStyleProps>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type ContainerLayoutTrait = NormalizedHasFramePropertiesTrait &
|
|
27
|
+
NormalizedHasChildrenTrait &
|
|
28
|
+
NormalizedHasLayoutTrait &
|
|
29
|
+
NormalizedIsLayerTrait;
|
|
30
|
+
|
|
31
|
+
export type SelfLayoutTrait = NormalizedIsLayerTrait & NormalizedHasLayoutTrait;
|
|
32
|
+
|
|
33
|
+
export type RadiusTrait = NormalizedCornerTrait & NormalizedIsLayerTrait;
|
|
34
|
+
|
|
35
|
+
export type FillTrait = NormalizedIsLayerTrait & NormalizedHasGeometryTrait;
|
|
36
|
+
|
|
37
|
+
export type StrokeTrait = NormalizedIsLayerTrait & NormalizedHasGeometryTrait;
|
|
38
|
+
|
|
39
|
+
export type ShadowTrait = NormalizedIsLayerTrait & NormalizedHasEffectsTrait;
|
|
40
|
+
|
|
41
|
+
export type TypeStyleTrait = NormalizedTypePropertiesTrait & NormalizedIsLayerTrait;
|
|
42
|
+
|
|
43
|
+
export interface ContainerLayoutProps {
|
|
44
|
+
layoutMode?: "HORIZONTAL" | "VERTICAL" | "NONE";
|
|
45
|
+
primaryAxisAlignItems?: "MIN" | "CENTER" | "MAX" | "SPACE_BETWEEN";
|
|
46
|
+
counterAxisAlignItems?: "MIN" | "CENTER" | "MAX" | "BASELINE";
|
|
47
|
+
layoutWrap?: "WRAP" | "NO_WRAP";
|
|
48
|
+
itemSpacing?: number | string; // string when variable
|
|
49
|
+
counterAxisSpacing?: number | string; // string when variable
|
|
50
|
+
paddingTop?: number | string; // string when variable
|
|
51
|
+
paddingBottom?: number | string; // string when variable
|
|
52
|
+
paddingLeft?: number | string; // string when variable
|
|
53
|
+
paddingRight?: number | string; // string when variable
|
|
54
|
+
horizontalPadding?: number | string; // string when variable
|
|
55
|
+
verticalPadding?: number | string; // string when variable
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function createContainerLayoutPropsConverter(
|
|
59
|
+
valueResolver: FigmaValueResolver,
|
|
60
|
+
): PropsConverter<ContainerLayoutTrait, ContainerLayoutProps> {
|
|
61
|
+
return createPropsConverter({
|
|
62
|
+
_types: {
|
|
63
|
+
trait: {} as ContainerLayoutTrait,
|
|
64
|
+
props: {} as ContainerLayoutProps,
|
|
65
|
+
},
|
|
66
|
+
handlers: {
|
|
67
|
+
layoutMode: ({ layoutMode }) => (!layoutMode || layoutMode === "GRID" ? "NONE" : layoutMode),
|
|
68
|
+
primaryAxisAlignItems: ({ primaryAxisAlignItems }) => primaryAxisAlignItems,
|
|
69
|
+
counterAxisAlignItems: ({ counterAxisAlignItems }) => counterAxisAlignItems,
|
|
70
|
+
layoutWrap: ({ layoutWrap }) => layoutWrap,
|
|
71
|
+
itemSpacing: (node) => valueResolver.getFormattedValue.itemSpacing(node),
|
|
72
|
+
counterAxisSpacing: (node) => valueResolver.getFormattedValue.counterAxisSpacing(node),
|
|
73
|
+
paddingTop: (node) => valueResolver.getFormattedValue.paddingTop(node),
|
|
74
|
+
paddingBottom: (node) => valueResolver.getFormattedValue.paddingBottom(node),
|
|
75
|
+
paddingLeft: (node) => valueResolver.getFormattedValue.paddingLeft(node),
|
|
76
|
+
paddingRight: (node) => valueResolver.getFormattedValue.paddingRight(node),
|
|
77
|
+
},
|
|
78
|
+
shorthands: {
|
|
79
|
+
horizontalPadding: ["paddingLeft", "paddingRight"],
|
|
80
|
+
verticalPadding: ["paddingTop", "paddingBottom"],
|
|
81
|
+
},
|
|
82
|
+
defaults: {},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface SelfLayoutProps {
|
|
87
|
+
layoutGrow?: number;
|
|
88
|
+
layoutAlign?: "STRETCH" | "INHERIT" | "MIN" | "CENTER" | "MAX";
|
|
89
|
+
layoutSizingVertical?: "FIXED" | "HUG" | "FILL";
|
|
90
|
+
layoutSizingHorizontal?: "FIXED" | "HUG" | "FILL";
|
|
91
|
+
width?: string | number; // string when variable
|
|
92
|
+
height?: string | number; // string when variable
|
|
93
|
+
minWidth?: string | number; // string when variable
|
|
94
|
+
minHeight?: string | number; // string when variable
|
|
95
|
+
maxWidth?: string | number; // string when variable
|
|
96
|
+
maxHeight?: string | number; // string when variable
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function createSelfLayoutPropsConverter(
|
|
100
|
+
valueResolver: FigmaValueResolver,
|
|
101
|
+
): PropsConverter<SelfLayoutTrait, SelfLayoutProps> {
|
|
102
|
+
return createPropsConverter({
|
|
103
|
+
_types: {
|
|
104
|
+
trait: {} as SelfLayoutTrait,
|
|
105
|
+
props: {} as SelfLayoutProps,
|
|
106
|
+
},
|
|
107
|
+
handlers: {
|
|
108
|
+
layoutGrow: ({ layoutGrow }) => layoutGrow,
|
|
109
|
+
layoutAlign: ({ layoutAlign }) => layoutAlign,
|
|
110
|
+
layoutSizingVertical: ({ layoutSizingVertical }) => layoutSizingVertical,
|
|
111
|
+
layoutSizingHorizontal: ({ layoutSizingHorizontal }) => layoutSizingHorizontal,
|
|
112
|
+
width: (node) => valueResolver.getFormattedValue.width(node),
|
|
113
|
+
height: (node) => valueResolver.getFormattedValue.height(node),
|
|
114
|
+
minWidth: (node) => valueResolver.getFormattedValue.minWidth(node),
|
|
115
|
+
minHeight: (node) => valueResolver.getFormattedValue.minHeight(node),
|
|
116
|
+
maxWidth: (node) => valueResolver.getFormattedValue.maxWidth(node),
|
|
117
|
+
maxHeight: (node) => valueResolver.getFormattedValue.maxHeight(node),
|
|
118
|
+
},
|
|
119
|
+
defaults: {},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface RadiusProps {
|
|
124
|
+
cornerRadius?: number | string; // string when variable
|
|
125
|
+
topLeftRadius?: number | string; // string when variable
|
|
126
|
+
topRightRadius?: number | string; // string when variable
|
|
127
|
+
bottomLeftRadius?: number | string; // string when variable
|
|
128
|
+
bottomRightRadius?: number | string; // string when variable
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function createRadiusPropsConverter(valueResolver: FigmaValueResolver) {
|
|
132
|
+
return createPropsConverter({
|
|
133
|
+
_types: {
|
|
134
|
+
trait: {} as RadiusTrait,
|
|
135
|
+
props: {} as RadiusProps,
|
|
136
|
+
},
|
|
137
|
+
handlers: {
|
|
138
|
+
topLeftRadius: (node) => valueResolver.getFormattedValue.topLeftRadius(node),
|
|
139
|
+
topRightRadius: (node) => valueResolver.getFormattedValue.topRightRadius(node),
|
|
140
|
+
bottomLeftRadius: (node) => valueResolver.getFormattedValue.bottomLeftRadius(node),
|
|
141
|
+
bottomRightRadius: (node) => valueResolver.getFormattedValue.bottomRightRadius(node),
|
|
142
|
+
},
|
|
143
|
+
shorthands: {
|
|
144
|
+
cornerRadius: ["topLeftRadius", "topRightRadius", "bottomLeftRadius", "bottomRightRadius"],
|
|
145
|
+
},
|
|
146
|
+
defaults: {
|
|
147
|
+
cornerRadius: 0,
|
|
148
|
+
topLeftRadius: 0,
|
|
149
|
+
topRightRadius: 0,
|
|
150
|
+
bottomLeftRadius: 0,
|
|
151
|
+
bottomRightRadius: 0,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface FillProps {
|
|
157
|
+
fill?: string | { value: string; direction?: string };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function createFrameFillPropsConverter(valueResolver: FigmaValueResolver) {
|
|
161
|
+
return definePropsConverter<FillTrait, FillProps>((node: FillTrait) => {
|
|
162
|
+
const fill = valueResolver.getFormattedValue.frameFill(node);
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
fill,
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function createShapeFillPropsConverter(valueResolver: FigmaValueResolver) {
|
|
171
|
+
return definePropsConverter<FillTrait, FillProps>((node: FillTrait) => {
|
|
172
|
+
const fill = valueResolver.getFormattedValue.shapeFill(node);
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
fill,
|
|
176
|
+
};
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function createTextFillPropsConverter(valueResolver: FigmaValueResolver) {
|
|
181
|
+
return definePropsConverter<FillTrait, FillProps>((node: FillTrait) => {
|
|
182
|
+
const fill = valueResolver.getFormattedValue.textFill(node);
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
fill,
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface StrokeProps {
|
|
191
|
+
stroke?: string;
|
|
192
|
+
strokeWeight?: number;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function createStrokePropsConverter(
|
|
196
|
+
valueResolver: FigmaValueResolver,
|
|
197
|
+
): PropsConverter<StrokeTrait, StrokeProps> {
|
|
198
|
+
return definePropsConverter((node: StrokeTrait) => {
|
|
199
|
+
const stroke = valueResolver.getFormattedValue.stroke(node);
|
|
200
|
+
const strokeWeight = node.strokeWeight;
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
stroke,
|
|
204
|
+
strokeWeight,
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface TypeStyleProps {
|
|
210
|
+
textStyle?: string;
|
|
211
|
+
fontSize?: string | number;
|
|
212
|
+
fontWeight?: string | number;
|
|
213
|
+
lineHeight?: string | number;
|
|
214
|
+
maxLines?: number;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function createTypeStylePropsConverter(
|
|
218
|
+
valueResolver: FigmaValueResolver,
|
|
219
|
+
): PropsConverter<TypeStyleTrait, TypeStyleProps> {
|
|
220
|
+
return definePropsConverter((node) => {
|
|
221
|
+
const styleName = valueResolver.getTextStyleValue(node);
|
|
222
|
+
const maxLines =
|
|
223
|
+
node.style.textTruncation === "ENDING" ? (node.style.maxLines ?? undefined) : undefined;
|
|
224
|
+
|
|
225
|
+
if (styleName) {
|
|
226
|
+
return {
|
|
227
|
+
textStyle: styleName,
|
|
228
|
+
maxLines,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
fontSize: valueResolver.getFormattedValue.fontSize(node),
|
|
234
|
+
fontWeight: valueResolver.getFormattedValue.fontWeight(node),
|
|
235
|
+
lineHeight: valueResolver.getFormattedValue.lineHeight(node),
|
|
236
|
+
maxLines,
|
|
237
|
+
};
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export interface ShadowProps {
|
|
242
|
+
boxShadowStyle?: string;
|
|
243
|
+
boxShadow?: string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function createShadowPropsConverter(
|
|
247
|
+
valueResolver: FigmaValueResolver,
|
|
248
|
+
): PropsConverter<ShadowTrait, ShadowProps> {
|
|
249
|
+
return definePropsConverter((node: ShadowTrait) => {
|
|
250
|
+
const effectStyleName = valueResolver.getEffectStyleValue(node);
|
|
251
|
+
if (effectStyleName) {
|
|
252
|
+
return {
|
|
253
|
+
boxShadowStyle: effectStyleName,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const boxShadow = valueResolver.getFormattedValue.boxShadow(node);
|
|
258
|
+
return {
|
|
259
|
+
boxShadow,
|
|
260
|
+
};
|
|
261
|
+
});
|
|
262
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NormalizedBooleanOperationNode,
|
|
3
|
+
NormalizedRectangleNode,
|
|
4
|
+
NormalizedVectorNode,
|
|
5
|
+
} from "@/normalizer";
|
|
6
|
+
import { createElement, defineElementTransformer, type ElementTransformer } from "../../core";
|
|
7
|
+
import type { PropsConverters } from "./props";
|
|
8
|
+
|
|
9
|
+
export interface RectangleTransformerDeps {
|
|
10
|
+
propsConverters: PropsConverters;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createRectangleTransformer({
|
|
14
|
+
propsConverters,
|
|
15
|
+
}: RectangleTransformerDeps): ElementTransformer<NormalizedRectangleNode> {
|
|
16
|
+
return defineElementTransformer((node: NormalizedRectangleNode) => {
|
|
17
|
+
return createElement("Rectangle", { ...propsConverters.selfLayout(node) });
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface VectorTransformerDeps {
|
|
22
|
+
propsConverters: PropsConverters;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createVectorTransformer({
|
|
26
|
+
propsConverters,
|
|
27
|
+
}: VectorTransformerDeps): ElementTransformer<NormalizedVectorNode> {
|
|
28
|
+
return defineElementTransformer((node) => {
|
|
29
|
+
return createElement(
|
|
30
|
+
"Vector",
|
|
31
|
+
{
|
|
32
|
+
...propsConverters.selfLayout(node),
|
|
33
|
+
...propsConverters.radius(node),
|
|
34
|
+
...propsConverters.stroke(node),
|
|
35
|
+
...propsConverters.shapeFill(node),
|
|
36
|
+
...propsConverters.shadow(node),
|
|
37
|
+
},
|
|
38
|
+
[],
|
|
39
|
+
{
|
|
40
|
+
comment: "Vector Node Placeholder",
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface BooleanOperationTransformerDeps {
|
|
47
|
+
propsConverters: PropsConverters;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function createBooleanOperationTransformer({
|
|
51
|
+
propsConverters,
|
|
52
|
+
}: BooleanOperationTransformerDeps): ElementTransformer<NormalizedBooleanOperationNode> {
|
|
53
|
+
return defineElementTransformer((node, traverse) => {
|
|
54
|
+
return createElement(
|
|
55
|
+
"BooleanOperation",
|
|
56
|
+
{
|
|
57
|
+
...propsConverters.selfLayout(node),
|
|
58
|
+
...propsConverters.radius(node),
|
|
59
|
+
...propsConverters.stroke(node),
|
|
60
|
+
...propsConverters.shapeFill(node),
|
|
61
|
+
},
|
|
62
|
+
node.children.map(traverse),
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { NormalizedTextNode } from "@/normalizer";
|
|
2
|
+
import { compactObject } from "@/utils/common";
|
|
3
|
+
import { createElement, defineElementTransformer, type ElementTransformer } from "../../core";
|
|
4
|
+
import type { PropsConverters } from "./props";
|
|
5
|
+
|
|
6
|
+
export interface TextTransformerDeps {
|
|
7
|
+
propsConverters: PropsConverters;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function createTextTransformer({
|
|
11
|
+
propsConverters,
|
|
12
|
+
}: TextTransformerDeps): ElementTransformer<NormalizedTextNode> {
|
|
13
|
+
return defineElementTransformer((node: NormalizedTextNode) => {
|
|
14
|
+
const hasMultipleFills = node.fills.length > 1;
|
|
15
|
+
|
|
16
|
+
const fillProps = propsConverters.textFill(node);
|
|
17
|
+
const typeStyleProps = propsConverters.typeStyle(node);
|
|
18
|
+
|
|
19
|
+
const props = compactObject({
|
|
20
|
+
...typeStyleProps,
|
|
21
|
+
...fillProps,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return createElement("Text", props, node.characters, {
|
|
25
|
+
comment: hasMultipleFills
|
|
26
|
+
? "Multiple fills in Text node encountered, only the first fill is used."
|
|
27
|
+
: undefined,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ValueResolver } from "@/codegen/core";
|
|
2
|
+
import { toCssRgba } from "@/utils/css";
|
|
3
|
+
import type { RGBA } from "@figma/rest-api-spec";
|
|
4
|
+
import { camelCase } from "change-case";
|
|
5
|
+
|
|
6
|
+
export type FigmaValueResolver = ValueResolver<
|
|
7
|
+
string,
|
|
8
|
+
{ value: string; direction?: string },
|
|
9
|
+
number,
|
|
10
|
+
number,
|
|
11
|
+
number
|
|
12
|
+
>;
|
|
13
|
+
|
|
14
|
+
export const defaultVariableNameFormatter = ({ slug }: { slug: string[] }) =>
|
|
15
|
+
slug
|
|
16
|
+
.filter((s) => s !== "dimension")
|
|
17
|
+
.map((s) => s.replaceAll(",", "_"))
|
|
18
|
+
.join("/");
|
|
19
|
+
|
|
20
|
+
export const defaultTextStyleNameFormatter = ({ slug }: { slug: string[] }) =>
|
|
21
|
+
slug[slug.length - 1]!;
|
|
22
|
+
|
|
23
|
+
export const defaultEffectStyleNameFormatter = ({ slug }: { slug: string[] }) =>
|
|
24
|
+
slug[slug.length - 1]!;
|
|
25
|
+
|
|
26
|
+
export const defaultFillStyleResolver = ({ slug }: { slug: string[] }) => {
|
|
27
|
+
const [, ...rest] = slug;
|
|
28
|
+
|
|
29
|
+
if (rest.includes("fade")) {
|
|
30
|
+
// ["fade", "layer-default", "↓(to-bottom)"]
|
|
31
|
+
|
|
32
|
+
const last = rest[rest.length - 1];
|
|
33
|
+
|
|
34
|
+
const direction = (() => {
|
|
35
|
+
if (last.startsWith("↓")) return "to bottom";
|
|
36
|
+
if (last.startsWith("↑")) return "to top";
|
|
37
|
+
if (last.startsWith("→")) return "to right";
|
|
38
|
+
if (last.startsWith("←")) return "to left";
|
|
39
|
+
|
|
40
|
+
return "unknown";
|
|
41
|
+
})();
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
value: camelCase(rest.slice(0, -1).join("-"), { mergeAmbiguousCharacters: true }),
|
|
45
|
+
direction,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
value: camelCase(rest.join("-"), { mergeAmbiguousCharacters: true }),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function formatBoxShadow(value: {
|
|
55
|
+
type: "DROP_SHADOW" | "INNER_SHADOW";
|
|
56
|
+
color: RGBA;
|
|
57
|
+
offset: { x: number; y: number };
|
|
58
|
+
radius: number;
|
|
59
|
+
spread?: number;
|
|
60
|
+
}): string {
|
|
61
|
+
const { type, color, offset, radius, spread } = value;
|
|
62
|
+
const inset = type === "INNER_SHADOW" ? "inset " : "";
|
|
63
|
+
const colorStr = toCssRgba(color);
|
|
64
|
+
const spreadStr = spread !== undefined ? ` ${spread}px` : "";
|
|
65
|
+
|
|
66
|
+
return `${inset}${offset.x}px ${offset.y}px ${radius}px${spreadStr} ${colorStr}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const defaultRawValueFormatters = {
|
|
70
|
+
color: (value: RGBA) => toCssRgba(value),
|
|
71
|
+
dimension: (value: number) => value,
|
|
72
|
+
fontDimension: (value: number) => value,
|
|
73
|
+
fontWeight: (value: number) => value,
|
|
74
|
+
boxShadow: formatBoxShadow,
|
|
75
|
+
};
|