@seed-design/figma 0.0.6 → 0.0.17
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/index.cjs +5548 -4901
- package/lib/index.d.ts +489 -189
- package/lib/index.js +5535 -4888
- package/package.json +3 -2
- package/src/codegen/core/codegen.ts +65 -0
- package/src/codegen/core/component.ts +15 -27
- package/src/codegen/core/component.types.ts +29 -0
- package/src/codegen/core/element.ts +13 -0
- package/src/codegen/core/index.ts +13 -8
- package/src/codegen/core/infer-layout.test.ts +285 -0
- package/src/codegen/core/infer-layout.ts +416 -0
- package/src/codegen/core/jsx.ts +12 -0
- package/src/codegen/core/props.ts +81 -0
- package/src/codegen/core/value.ts +289 -0
- package/src/codegen/index.ts +39 -6
- package/src/codegen/targets/figma/context.ts +139 -0
- package/src/codegen/targets/figma/frame.ts +37 -0
- package/src/codegen/targets/figma/index.ts +6 -0
- package/src/codegen/targets/figma/instance.ts +16 -0
- package/src/codegen/targets/figma/props.ts +244 -0
- package/src/codegen/targets/figma/shape.ts +62 -0
- package/src/codegen/targets/figma/text.ts +33 -0
- package/src/codegen/targets/index.ts +2 -0
- package/src/codegen/{domain/seed-component → targets/react/component}/deps.interface.ts +2 -2
- package/src/codegen/{domain/seed-component → targets/react/component}/index.ts +36 -34
- package/src/codegen/{domain/seed-component → targets/react/component}/properties.type.ts +2 -2
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/action-button.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/action-chip.ts +3 -4
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/action-sheet.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/app-bar.ts +5 -6
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/avatar-stack.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/avatar.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/badge.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/callout.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/checkbox.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/chip-tabs.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/control-chip.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/error-state.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/extended-action-sheet.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/extended-fab.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/fab.ts +2 -2
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/help-bubble.ts +2 -2
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/identity-placeholder.ts +2 -2
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/inline-banner.ts +5 -6
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/manner-temp-badge.ts +3 -4
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/multiline-text-field.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/progress-circle.ts +3 -4
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/reaction-button.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/segmented-control.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/select-box.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/skeleton.ts +3 -4
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/snackbar.ts +3 -4
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/switch.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/tabs.ts +5 -6
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/text-button.ts +6 -7
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/text-field.ts +4 -5
- package/src/codegen/{domain/seed-component → targets/react/component}/transformers/toggle-button.ts +4 -5
- package/src/codegen/targets/react/context.ts +170 -0
- package/src/codegen/targets/react/frame.ts +75 -0
- package/src/codegen/targets/react/index.ts +7 -0
- package/src/codegen/{domain/instance.service.ts → targets/react/instance.ts} +20 -33
- package/src/codegen/targets/react/props.ts +361 -0
- package/src/codegen/targets/react/shape.ts +36 -0
- package/src/codegen/targets/react/text.ts +33 -0
- package/src/{codegen → entities}/data/icons.ts +1 -1
- package/src/{codegen → entities}/data/styles.ts +1 -1
- package/src/{codegen → entities}/data/variable-collections.ts +1 -1
- package/src/{codegen → entities}/data/variables.ts +1 -1
- package/src/entities/index.ts +41 -0
- package/src/{codegen/domain → entities}/style.repository.ts +6 -2
- package/src/{codegen/domain → entities}/style.service.ts +1 -1
- package/src/{codegen/domain → entities}/variable.repository.ts +17 -4
- package/src/{codegen/domain → entities}/variable.service.ts +47 -9
- package/src/index.ts +1 -0
- package/src/normalizer/from-plugin.ts +3 -0
- package/src/normalizer/types.ts +28 -24
- package/src/utils/common.ts +4 -0
- package/src/utils/css.ts +10 -4
- package/src/utils/figma-node.ts +42 -2
- package/src/codegen/context.ts +0 -148
- package/src/codegen/core/transformer.ts +0 -40
- package/src/codegen/domain/codegen.service.ts +0 -69
- package/src/codegen/domain/figma-component.service.ts +0 -21
- package/src/codegen/domain/frame.service.ts +0 -108
- package/src/codegen/domain/index.ts +0 -22
- package/src/codegen/domain/props/container-layout-props.service.ts +0 -248
- package/src/codegen/domain/props/fill-props.service.ts +0 -75
- package/src/codegen/domain/props/radius-props.service.ts +0 -105
- package/src/codegen/domain/props/self-layout-props.service.ts +0 -127
- package/src/codegen/domain/props/stroke-props.service.ts +0 -45
- package/src/codegen/domain/props/type-style-props.service.ts +0 -31
- package/src/codegen/domain/rectangle.service.ts +0 -31
- package/src/codegen/domain/text.service.ts +0 -62
- /package/src/codegen/{domain/seed-component → targets/react/component}/size.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/action-button.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/action-button.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/action-chip.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/action-chip.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/action-sheet.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/action-sheet.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/avatar-stack.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/avatar-stack.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/avatar.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/avatar.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/badge.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/badge.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-navigation-global.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-navigation-global.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-navigation-kr.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-navigation-kr.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-sheet.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/bottom-sheet.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/callout.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/callout.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/checkbox.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/checkbox.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/chip-tablist.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/chip-tablist.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/control-chip.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/control-chip.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/divider.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/divider.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/error-state.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/error-state.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/extended-action-sheet.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/extended-action-sheet.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/extended-floating-action-button.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/extended-floating-action-button.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/floating-action-button.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/floating-action-button.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/help-bubble.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/help-bubble.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/identity-placeholder.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/identity-placeholder.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/index.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/index.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/inline-banner.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/inline-banner.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/main-tab-navigation-global.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/main-tab-navigation-global.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/main-tab-navigation-kr.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/main-tab-navigation-kr.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp-badge.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp-badge.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp-bar.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp-bar.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/manner-temp.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/multiline-text-field.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/multiline-text-field.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/progress-circle.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/progress-circle.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/radio.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/radio.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/range-slider.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/range-slider.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/reaction-button.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/reaction-button.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/segmented-control.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/segmented-control.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/select-box.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/select-box.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/skeleton.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/skeleton.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/slider.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/slider.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/snackbar.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/snackbar.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/standard-navigation.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/standard-navigation.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/switch.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/switch.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/tablist.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/tablist.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-bottom-fixed-bar.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-bottom-fixed-bar.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-button-group.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-button-group.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-chip-group.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-chip-group.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-select-box-group.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-select-box-group.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-top-navigation.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/template-top-navigation.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/text-button.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/text-button.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/text-field.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/text-field.mjs +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/toggle-button.d.ts +0 -0
- /package/src/{codegen → entities}/data/__generated__/component-sets/toggle-button.mjs +0 -0
- /package/src/{codegen/domain → entities}/icon.interface.ts +0 -0
- /package/src/{codegen/domain → entities}/icon.repository.ts +0 -0
- /package/src/{codegen/domain → entities}/icon.service.ts +0 -0
- /package/src/{codegen/domain → entities}/style.interface.ts +0 -0
- /package/src/{codegen/domain → entities}/variable.interface.ts +0 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createPropsTransformer,
|
|
3
|
+
definePropsTransformer,
|
|
4
|
+
type PropsTransformer,
|
|
5
|
+
type ValueTransformer,
|
|
6
|
+
} from "@/codegen/core";
|
|
7
|
+
import type { StyleService } from "@/entities";
|
|
8
|
+
import type {
|
|
9
|
+
NormalizedCornerTrait,
|
|
10
|
+
NormalizedHasChildrenTrait,
|
|
11
|
+
NormalizedHasFramePropertiesTrait,
|
|
12
|
+
NormalizedHasGeometryTrait,
|
|
13
|
+
NormalizedHasLayoutTrait,
|
|
14
|
+
NormalizedIsLayerTrait,
|
|
15
|
+
NormalizedTypePropertiesTrait,
|
|
16
|
+
} from "@/normalizer";
|
|
17
|
+
import { match } from "ts-pattern";
|
|
18
|
+
|
|
19
|
+
export interface PropsTransformers {
|
|
20
|
+
containerLayout: PropsTransformer<ContainerLayoutTrait, ContainerLayoutProps>;
|
|
21
|
+
selfLayout: PropsTransformer<SelfLayoutTrait, SelfLayoutProps>;
|
|
22
|
+
iconSelfLayout: PropsTransformer<SelfLayoutTrait, IconSelfLayoutProps>;
|
|
23
|
+
radius: PropsTransformer<RadiusTrait, RadiusProps>;
|
|
24
|
+
frameFill: PropsTransformer<FillTrait, FrameFillProps>;
|
|
25
|
+
shapeFill: PropsTransformer<FillTrait, ShapeFillProps>;
|
|
26
|
+
textFill: PropsTransformer<FillTrait, TextFillProps>;
|
|
27
|
+
stroke: PropsTransformer<StrokeTrait, StrokeProps>;
|
|
28
|
+
typeStyle: PropsTransformer<TypeStyleTrait, TypeStyleProps>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type ContainerLayoutTrait = NormalizedHasFramePropertiesTrait &
|
|
32
|
+
NormalizedHasChildrenTrait &
|
|
33
|
+
NormalizedHasLayoutTrait &
|
|
34
|
+
NormalizedIsLayerTrait;
|
|
35
|
+
|
|
36
|
+
export type SelfLayoutTrait = NormalizedIsLayerTrait & NormalizedHasLayoutTrait;
|
|
37
|
+
|
|
38
|
+
export type RadiusTrait = NormalizedCornerTrait & NormalizedIsLayerTrait;
|
|
39
|
+
|
|
40
|
+
export type FillTrait = NormalizedIsLayerTrait & NormalizedHasGeometryTrait;
|
|
41
|
+
|
|
42
|
+
export type StrokeTrait = NormalizedIsLayerTrait & NormalizedHasGeometryTrait;
|
|
43
|
+
|
|
44
|
+
export type TypeStyleTrait = NormalizedTypePropertiesTrait & NormalizedIsLayerTrait;
|
|
45
|
+
|
|
46
|
+
export interface ContainerLayoutProps {
|
|
47
|
+
direction?: "row" | "column";
|
|
48
|
+
justify?: "flex-start" | "center" | "flex-end" | "space-between";
|
|
49
|
+
align?: "stretch" | "flex-start" | "center" | "flex-end" | "baseline";
|
|
50
|
+
wrap?: "wrap" | "nowrap" | true;
|
|
51
|
+
gap?: string | 0;
|
|
52
|
+
pb?: string | 0;
|
|
53
|
+
pl?: string | 0;
|
|
54
|
+
pr?: string | 0;
|
|
55
|
+
pt?: string | 0;
|
|
56
|
+
px?: string | 0;
|
|
57
|
+
py?: string | 0;
|
|
58
|
+
p?: string | 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type ReactValueTransformer = ValueTransformer<string, string, string, number>;
|
|
62
|
+
|
|
63
|
+
export function createContainerLayoutPropsTransformer(
|
|
64
|
+
valueTransformer: ReactValueTransformer,
|
|
65
|
+
): PropsTransformer<ContainerLayoutTrait, ContainerLayoutProps> {
|
|
66
|
+
return createPropsTransformer({
|
|
67
|
+
_types: {
|
|
68
|
+
trait: {} as ContainerLayoutTrait,
|
|
69
|
+
props: {} as ContainerLayoutProps,
|
|
70
|
+
},
|
|
71
|
+
handlers: {
|
|
72
|
+
direction: ({ layoutMode }) =>
|
|
73
|
+
match(layoutMode)
|
|
74
|
+
.with("HORIZONTAL", () => "row" as const)
|
|
75
|
+
.with("VERTICAL", () => "column" as const)
|
|
76
|
+
.with("NONE", () => undefined)
|
|
77
|
+
.with(undefined, () => undefined)
|
|
78
|
+
.exhaustive(),
|
|
79
|
+
justify: ({ primaryAxisAlignItems }) =>
|
|
80
|
+
match(primaryAxisAlignItems)
|
|
81
|
+
.with("MIN", () => "flex-start" as const)
|
|
82
|
+
.with("CENTER", () => "center" as const)
|
|
83
|
+
.with("MAX", () => "flex-end" as const)
|
|
84
|
+
.with("SPACE_BETWEEN", () => "space-between" as const)
|
|
85
|
+
.with(undefined, () => undefined)
|
|
86
|
+
.exhaustive(),
|
|
87
|
+
align: ({ counterAxisAlignItems, children }) => {
|
|
88
|
+
const isStretch = children.every((child) => {
|
|
89
|
+
if (!("layoutAlign" in child)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return child.layoutAlign === "STRETCH";
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (isStretch) {
|
|
97
|
+
return "stretch";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return match(counterAxisAlignItems)
|
|
101
|
+
.with("MIN", () => "flex-start" as const)
|
|
102
|
+
.with("CENTER", () => "center" as const)
|
|
103
|
+
.with("MAX", () => "flex-end" as const)
|
|
104
|
+
.with("BASELINE", () => "baseline" as const)
|
|
105
|
+
.with(undefined, () => undefined)
|
|
106
|
+
.exhaustive();
|
|
107
|
+
},
|
|
108
|
+
wrap: ({ layoutWrap }) =>
|
|
109
|
+
match(layoutWrap)
|
|
110
|
+
.with("WRAP", () => true as const)
|
|
111
|
+
.with("NO_WRAP", () => "nowrap" as const)
|
|
112
|
+
.with(undefined, () => undefined)
|
|
113
|
+
.exhaustive(),
|
|
114
|
+
gap: (node) => {
|
|
115
|
+
if (node.children.length <= 1) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (node.primaryAxisAlignItems === "SPACE_BETWEEN") {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return valueTransformer.getFormattedValue.itemSpacing(node);
|
|
124
|
+
},
|
|
125
|
+
pt: (node) => valueTransformer.getFormattedValue.paddingTop(node),
|
|
126
|
+
pb: (node) => valueTransformer.getFormattedValue.paddingBottom(node),
|
|
127
|
+
pl: (node) => valueTransformer.getFormattedValue.paddingLeft(node),
|
|
128
|
+
pr: (node) => valueTransformer.getFormattedValue.paddingRight(node),
|
|
129
|
+
},
|
|
130
|
+
shorthands: {
|
|
131
|
+
p: ["pt", "pb", "pl", "pr"],
|
|
132
|
+
px: ["pl", "pr"],
|
|
133
|
+
py: ["pt", "pb"],
|
|
134
|
+
},
|
|
135
|
+
defaults: {
|
|
136
|
+
justify: "flex-start",
|
|
137
|
+
align: "stretch",
|
|
138
|
+
wrap: "nowrap",
|
|
139
|
+
gap: 0,
|
|
140
|
+
p: 0,
|
|
141
|
+
px: 0,
|
|
142
|
+
py: 0,
|
|
143
|
+
pb: 0,
|
|
144
|
+
pl: 0,
|
|
145
|
+
pr: 0,
|
|
146
|
+
pt: 0,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface SelfLayoutProps {
|
|
152
|
+
grow?: 0 | 1 | true;
|
|
153
|
+
alignSelf?: "stretch";
|
|
154
|
+
width?: string | number;
|
|
155
|
+
height?: string | number;
|
|
156
|
+
minWidth?: string | number;
|
|
157
|
+
minHeight?: string | number;
|
|
158
|
+
maxWidth?: string | number;
|
|
159
|
+
maxHeight?: string | number;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function createSelfLayoutPropsTransformer(
|
|
163
|
+
valueTransformer: ReactValueTransformer,
|
|
164
|
+
): PropsTransformer<SelfLayoutTrait, SelfLayoutProps> {
|
|
165
|
+
return createPropsTransformer({
|
|
166
|
+
_types: {
|
|
167
|
+
trait: {} as SelfLayoutTrait,
|
|
168
|
+
props: {} as SelfLayoutProps,
|
|
169
|
+
},
|
|
170
|
+
handlers: {
|
|
171
|
+
grow: ({ layoutGrow }) => (layoutGrow === 1 ? true : layoutGrow),
|
|
172
|
+
alignSelf: ({ layoutAlign }) =>
|
|
173
|
+
match(layoutAlign)
|
|
174
|
+
.with("STRETCH", () => "stretch" as const)
|
|
175
|
+
.with("INHERIT", () => undefined)
|
|
176
|
+
.with("MIN", () => undefined) // Deprecated in Figma
|
|
177
|
+
.with("CENTER", () => undefined) // Deprecated in Figma
|
|
178
|
+
.with("MAX", () => undefined) // Deprecated in Figma
|
|
179
|
+
.with(undefined, () => undefined)
|
|
180
|
+
.exhaustive(),
|
|
181
|
+
height: (node) =>
|
|
182
|
+
node.layoutSizingVertical === "FIXED"
|
|
183
|
+
? valueTransformer.getFormattedValue.height(node)
|
|
184
|
+
: undefined,
|
|
185
|
+
width: (node) =>
|
|
186
|
+
node.layoutSizingHorizontal === "FIXED"
|
|
187
|
+
? valueTransformer.getFormattedValue.width(node)
|
|
188
|
+
: undefined,
|
|
189
|
+
minHeight: (node) =>
|
|
190
|
+
node.layoutSizingVertical === "HUG"
|
|
191
|
+
? valueTransformer.getFormattedValue.minHeight(node)
|
|
192
|
+
: undefined,
|
|
193
|
+
maxHeight: (node) =>
|
|
194
|
+
node.layoutSizingVertical === "HUG"
|
|
195
|
+
? valueTransformer.getFormattedValue.maxHeight(node)
|
|
196
|
+
: undefined,
|
|
197
|
+
minWidth: (node) =>
|
|
198
|
+
node.layoutSizingHorizontal === "HUG"
|
|
199
|
+
? valueTransformer.getFormattedValue.minWidth(node)
|
|
200
|
+
: undefined,
|
|
201
|
+
maxWidth: (node) =>
|
|
202
|
+
node.layoutSizingHorizontal === "HUG"
|
|
203
|
+
? valueTransformer.getFormattedValue.maxWidth(node)
|
|
204
|
+
: undefined,
|
|
205
|
+
},
|
|
206
|
+
defaults: {
|
|
207
|
+
grow: 0,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export interface IconSelfLayoutProps {
|
|
213
|
+
size?: string | number;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function createIconSelfLayoutPropsTransformer(valueTransformer: ReactValueTransformer) {
|
|
217
|
+
return createPropsTransformer({
|
|
218
|
+
_types: {
|
|
219
|
+
trait: {} as SelfLayoutTrait,
|
|
220
|
+
props: {} as IconSelfLayoutProps,
|
|
221
|
+
},
|
|
222
|
+
handlers: {
|
|
223
|
+
size: (node) => valueTransformer.getFormattedValue.width(node),
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export interface RadiusProps {
|
|
229
|
+
borderRadius?: string | 0;
|
|
230
|
+
borderTopLeftRadius?: string | 0;
|
|
231
|
+
borderTopRightRadius?: string | 0;
|
|
232
|
+
borderBottomLeftRadius?: string | 0;
|
|
233
|
+
borderBottomRightRadius?: string | 0;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function createRadiusPropsTransformer(valueTransformer: ReactValueTransformer) {
|
|
237
|
+
return createPropsTransformer({
|
|
238
|
+
_types: {
|
|
239
|
+
trait: {} as RadiusTrait,
|
|
240
|
+
props: {} as RadiusProps,
|
|
241
|
+
},
|
|
242
|
+
handlers: {
|
|
243
|
+
borderTopLeftRadius: (node) => valueTransformer.getFormattedValue.topLeftRadius(node),
|
|
244
|
+
borderTopRightRadius: (node) => valueTransformer.getFormattedValue.topRightRadius(node),
|
|
245
|
+
borderBottomLeftRadius: (node) => valueTransformer.getFormattedValue.bottomLeftRadius(node),
|
|
246
|
+
borderBottomRightRadius: (node) => valueTransformer.getFormattedValue.bottomRightRadius(node),
|
|
247
|
+
},
|
|
248
|
+
shorthands: {
|
|
249
|
+
borderRadius: [
|
|
250
|
+
"borderTopLeftRadius",
|
|
251
|
+
"borderTopRightRadius",
|
|
252
|
+
"borderBottomLeftRadius",
|
|
253
|
+
"borderBottomRightRadius",
|
|
254
|
+
],
|
|
255
|
+
},
|
|
256
|
+
defaults: {
|
|
257
|
+
borderRadius: 0,
|
|
258
|
+
borderTopLeftRadius: 0,
|
|
259
|
+
borderTopRightRadius: 0,
|
|
260
|
+
borderBottomLeftRadius: 0,
|
|
261
|
+
borderBottomRightRadius: 0,
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export interface TypeStyleProps {
|
|
267
|
+
textStyle?: string;
|
|
268
|
+
fontSize?: string;
|
|
269
|
+
fontWeight?: string | number;
|
|
270
|
+
lineHeight?: string;
|
|
271
|
+
maxLines?: number;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export function createTypeStylePropsTransformer({
|
|
275
|
+
valueTransformer,
|
|
276
|
+
styleService,
|
|
277
|
+
}: {
|
|
278
|
+
valueTransformer: ReactValueTransformer;
|
|
279
|
+
styleService: StyleService;
|
|
280
|
+
}): PropsTransformer<TypeStyleTrait, TypeStyleProps> {
|
|
281
|
+
return definePropsTransformer((node) => {
|
|
282
|
+
const styleName = node.textStyleKey ? styleService.getStyleName(node.textStyleKey) : undefined;
|
|
283
|
+
const maxLines =
|
|
284
|
+
node.style.textTruncation === "ENDING" ? (node.style.maxLines ?? undefined) : undefined;
|
|
285
|
+
|
|
286
|
+
if (styleName) {
|
|
287
|
+
return {
|
|
288
|
+
textStyle: styleName,
|
|
289
|
+
maxLines,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
fontSize: valueTransformer.getFormattedValue.fontSize(node),
|
|
295
|
+
fontWeight: valueTransformer.getFormattedValue.fontWeight(node),
|
|
296
|
+
lineHeight: valueTransformer.getFormattedValue.lineHeight(node),
|
|
297
|
+
maxLines,
|
|
298
|
+
};
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface FrameFillProps {
|
|
303
|
+
bg?: string;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export function createFrameFillPropsTransformer(valueTransformer: ReactValueTransformer) {
|
|
307
|
+
return definePropsTransformer<FillTrait, FrameFillProps>((node) => {
|
|
308
|
+
const bg = valueTransformer.getFormattedValue.frameFill(node);
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
bg,
|
|
312
|
+
};
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export interface ShapeFillProps {
|
|
317
|
+
color?: string;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function createShapeFillPropsTransformer(valueTransformer: ReactValueTransformer) {
|
|
321
|
+
return definePropsTransformer<FillTrait, ShapeFillProps>((node) => {
|
|
322
|
+
const color = valueTransformer.getFormattedValue.shapeFill(node);
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
color,
|
|
326
|
+
};
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export interface TextFillProps {
|
|
331
|
+
color?: string;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export function createTextFillPropsTransformer(valueTransformer: ReactValueTransformer) {
|
|
335
|
+
return definePropsTransformer<FillTrait, TextFillProps>((node) => {
|
|
336
|
+
const color = valueTransformer.getFormattedValue.textFill(node);
|
|
337
|
+
|
|
338
|
+
return {
|
|
339
|
+
color,
|
|
340
|
+
};
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export interface StrokeProps {
|
|
345
|
+
borderWidth?: number;
|
|
346
|
+
borderColor?: string;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export function createStrokePropsTransformer(
|
|
350
|
+
valueTransformer: ReactValueTransformer,
|
|
351
|
+
): PropsTransformer<StrokeTrait, StrokeProps> {
|
|
352
|
+
return definePropsTransformer((node) => {
|
|
353
|
+
const borderColor = valueTransformer.getFormattedValue.stroke(node);
|
|
354
|
+
const borderWidth = borderColor ? node.strokeWeight : undefined;
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
borderColor,
|
|
358
|
+
borderWidth,
|
|
359
|
+
};
|
|
360
|
+
});
|
|
361
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NormalizedBooleanOperationNode,
|
|
3
|
+
NormalizedRectangleNode,
|
|
4
|
+
NormalizedVectorNode,
|
|
5
|
+
} from "@/normalizer";
|
|
6
|
+
import { createElement, defineElementTransformer, type ElementTransformer } from "../../core";
|
|
7
|
+
import type { PropsTransformers } from "./props";
|
|
8
|
+
|
|
9
|
+
export interface RectangleTransformerDeps {
|
|
10
|
+
propsTransformers: PropsTransformers;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createRectangleTransformer({
|
|
14
|
+
propsTransformers,
|
|
15
|
+
}: RectangleTransformerDeps): ElementTransformer<NormalizedRectangleNode> {
|
|
16
|
+
return defineElementTransformer((node: NormalizedRectangleNode, traverse) => {
|
|
17
|
+
return createElement(
|
|
18
|
+
"Box",
|
|
19
|
+
{ ...propsTransformers.selfLayout(node, traverse), background: "palette.gray200" },
|
|
20
|
+
undefined,
|
|
21
|
+
"Rectangle Node Placeholder",
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function createVectorTransformer(): ElementTransformer<NormalizedVectorNode> {
|
|
27
|
+
return defineElementTransformer(() => {
|
|
28
|
+
return createElement("svg", {}, [], "Vector Node Placeholder");
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function createBooleanOperationTransformer(): ElementTransformer<NormalizedBooleanOperationNode> {
|
|
33
|
+
return defineElementTransformer(() => {
|
|
34
|
+
return createElement("svg", {}, [], "Boolean Operation Node Placeholder");
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { NormalizedTextNode } from "@/normalizer";
|
|
2
|
+
import { compactObject } from "@/utils/common";
|
|
3
|
+
import { createElement, defineElementTransformer, type ElementTransformer } from "../../core";
|
|
4
|
+
import type { PropsTransformers } from "./props";
|
|
5
|
+
|
|
6
|
+
export interface TextTransformerDeps {
|
|
7
|
+
propsTransformers: PropsTransformers;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function createTextTransformer({
|
|
11
|
+
propsTransformers,
|
|
12
|
+
}: TextTransformerDeps): ElementTransformer<NormalizedTextNode> {
|
|
13
|
+
return defineElementTransformer((node: NormalizedTextNode, traverse) => {
|
|
14
|
+
const hasMultipleFills = node.fills.length > 1;
|
|
15
|
+
|
|
16
|
+
const fillProps = propsTransformers.textFill(node, traverse);
|
|
17
|
+
const typeStyleProps = propsTransformers.typeStyle(node, traverse);
|
|
18
|
+
|
|
19
|
+
const props = compactObject({
|
|
20
|
+
...typeStyleProps,
|
|
21
|
+
...fillProps,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return createElement(
|
|
25
|
+
"Text",
|
|
26
|
+
props,
|
|
27
|
+
node.characters.replace(/\n/g, "<br />"),
|
|
28
|
+
hasMultipleFills
|
|
29
|
+
? "Multiple fills in Text node encountered, only the first fill is used."
|
|
30
|
+
: "",
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createStaticIconRepository } from "./icon.repository";
|
|
2
|
+
import { FIGMA_ICONS } from "./data/icons";
|
|
3
|
+
import { FIGMA_TEXT_STYLES } from "./data/styles";
|
|
4
|
+
import { FIGMA_VARIABLE_COLLECTIONS } from "./data/variable-collections";
|
|
5
|
+
import { FIGMA_VARIABLES } from "./data/variables";
|
|
6
|
+
import { createStaticStyleRepository } from "./style.repository";
|
|
7
|
+
import { createStaticVariableRepository } from "./variable.repository";
|
|
8
|
+
|
|
9
|
+
export * from "./icon.interface";
|
|
10
|
+
export * from "./icon.repository";
|
|
11
|
+
export * from "./icon.service";
|
|
12
|
+
export * from "./style.interface";
|
|
13
|
+
export * from "./style.repository";
|
|
14
|
+
export * from "./style.service";
|
|
15
|
+
export * from "./variable.interface";
|
|
16
|
+
export * from "./variable.repository";
|
|
17
|
+
export * from "./variable.service";
|
|
18
|
+
|
|
19
|
+
export const styleRepository = createStaticStyleRepository(FIGMA_TEXT_STYLES);
|
|
20
|
+
export const variableRepository = createStaticVariableRepository({
|
|
21
|
+
variables: FIGMA_VARIABLES,
|
|
22
|
+
variableCollections: FIGMA_VARIABLE_COLLECTIONS,
|
|
23
|
+
});
|
|
24
|
+
export const iconRepository = createStaticIconRepository(FIGMA_ICONS);
|
|
25
|
+
|
|
26
|
+
export function getFigmaVariableKey(name: string) {
|
|
27
|
+
return variableRepository.findVariableByName(name)?.key;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getFigmaStyleKey(name: string) {
|
|
31
|
+
return styleRepository.findOneByName(name)?.key;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getFigmaColorVariableNames(scopes: Array<"fg" | "bg" | "stroke" | "palette">) {
|
|
35
|
+
const variables = variableRepository.getVariableList();
|
|
36
|
+
return variables
|
|
37
|
+
.filter((variable) =>
|
|
38
|
+
scopes.includes(variable.name.split("/")[0] as "fg" | "bg" | "stroke" | "palette"),
|
|
39
|
+
)
|
|
40
|
+
.map((variable) => variable.name);
|
|
41
|
+
}
|
|
@@ -4,20 +4,24 @@ export interface StyleRepository {
|
|
|
4
4
|
getAll(): Style[];
|
|
5
5
|
getTextStyles(): Style[];
|
|
6
6
|
getColorStyles(): Style[];
|
|
7
|
-
|
|
7
|
+
findOneByKey(key: string): Style | undefined;
|
|
8
|
+
findOneByName(name: string): Style | undefined;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export function createStaticStyleRepository(styles: Style[]): StyleRepository {
|
|
11
12
|
const stylesMap = new Map<string, Style>();
|
|
13
|
+
const stylesNameMap = new Map<string, Style>();
|
|
12
14
|
|
|
13
15
|
for (const style of styles) {
|
|
14
16
|
stylesMap.set(style.key, style);
|
|
17
|
+
stylesNameMap.set(style.name, style);
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
return {
|
|
18
21
|
getAll: () => styles,
|
|
19
22
|
getTextStyles: () => styles.filter((style) => style.styleType === "TEXT"),
|
|
20
23
|
getColorStyles: () => styles.filter((style) => style.styleType === "FILL"),
|
|
21
|
-
|
|
24
|
+
findOneByKey: (key) => stylesMap.get(key),
|
|
25
|
+
findOneByName: (name) => stylesNameMap.get(name),
|
|
22
26
|
};
|
|
23
27
|
}
|
|
@@ -13,7 +13,7 @@ export function createStyleService({
|
|
|
13
13
|
styleNameTransformer: ({ slug }: { slug: string[] }) => string;
|
|
14
14
|
}): StyleService {
|
|
15
15
|
function getFigmaStyleName(id: string) {
|
|
16
|
-
const style = styleRepository.
|
|
16
|
+
const style = styleRepository.findOneByKey(id);
|
|
17
17
|
|
|
18
18
|
if (!style) {
|
|
19
19
|
throw new Error(`Style not found: ${id}`);
|
|
@@ -5,6 +5,7 @@ export interface VariableRepository {
|
|
|
5
5
|
getVariableCollectionList(): VariableCollection[];
|
|
6
6
|
findVariableByKey(key: string): Variable | undefined;
|
|
7
7
|
findVariableById(id: string): Variable | undefined;
|
|
8
|
+
findVariableByName(name: string): Variable | undefined;
|
|
8
9
|
findVariableCollectionByKey(key: string): VariableCollection | undefined;
|
|
9
10
|
findVariableCollectionById(id: string): VariableCollection | undefined;
|
|
10
11
|
}
|
|
@@ -18,24 +19,36 @@ export function createStaticVariableRepository({
|
|
|
18
19
|
}): VariableRepository {
|
|
19
20
|
const variablesKeyMap = new Map<string, Variable>();
|
|
20
21
|
const variablesIdMap = new Map<string, Variable>();
|
|
22
|
+
const variablesNameMap = new Map<string, Variable>();
|
|
21
23
|
const variableCollectionsKeyMap = new Map<string, VariableCollection>();
|
|
22
24
|
const variableCollectionsIdMap = new Map<string, VariableCollection>();
|
|
23
|
-
const variablesList = Object.values(variables);
|
|
24
|
-
const variableCollectionsList = Object.values(variableCollections);
|
|
25
25
|
|
|
26
|
-
for (const variable of
|
|
26
|
+
for (const variable of Object.values(variables)) {
|
|
27
|
+
if (variable.remote) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
27
31
|
variablesKeyMap.set(variable.key, variable);
|
|
28
32
|
variablesIdMap.set(variable.id, variable);
|
|
33
|
+
variablesNameMap.set(variable.name, variable);
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
for (const variableCollection of
|
|
36
|
+
for (const variableCollection of Object.values(variableCollections)) {
|
|
37
|
+
if (variableCollection.remote) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
32
41
|
variableCollectionsKeyMap.set(variableCollection.key, variableCollection);
|
|
33
42
|
variableCollectionsIdMap.set(variableCollection.id, variableCollection);
|
|
34
43
|
}
|
|
35
44
|
|
|
45
|
+
const variablesList = [...variablesKeyMap.values()];
|
|
46
|
+
const variableCollectionsList = [...variableCollectionsKeyMap.values()];
|
|
47
|
+
|
|
36
48
|
return {
|
|
37
49
|
getVariableList: () => variablesList,
|
|
38
50
|
getVariableCollectionList: () => variableCollectionsList,
|
|
51
|
+
findVariableByName: (name: string) => variablesNameMap.get(name),
|
|
39
52
|
findVariableByKey: (key: string) => variablesKeyMap.get(key),
|
|
40
53
|
findVariableById: (id: string) => variablesIdMap.get(id),
|
|
41
54
|
findVariableCollectionByKey: (key: string) => variableCollectionsKeyMap.get(key),
|
|
@@ -4,17 +4,19 @@ import type { VariableRepository } from "./variable.repository";
|
|
|
4
4
|
|
|
5
5
|
export interface VariableService {
|
|
6
6
|
getVariableName: (id: string) => string;
|
|
7
|
-
inferVariableName: (
|
|
7
|
+
inferVariableName: (value: VariableValueResolved, scope: VariableScope) => string | undefined;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export interface VariableServiceDeps {
|
|
11
11
|
variableRepository: VariableRepository;
|
|
12
12
|
variableNameTransformer: ({ slug }: { slug: string[] }) => string;
|
|
13
|
+
inferCompareFunction: (name1: string, name2: string) => number;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function createVariableService({
|
|
16
17
|
variableRepository,
|
|
17
18
|
variableNameTransformer,
|
|
19
|
+
inferCompareFunction,
|
|
18
20
|
}: VariableServiceDeps): VariableService {
|
|
19
21
|
const variables = variableRepository.getVariableList();
|
|
20
22
|
|
|
@@ -67,25 +69,61 @@ export function createVariableService({
|
|
|
67
69
|
return value;
|
|
68
70
|
}
|
|
69
71
|
|
|
72
|
+
function isIdenticalVariableValue(value1: VariableValueResolved, value2: VariableValueResolved) {
|
|
73
|
+
if (typeof value1 !== typeof value2) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (typeof value1 === "string" || typeof value1 === "number" || typeof value1 === "boolean") {
|
|
78
|
+
return value1 === value2;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
value1.r === (value2 as RGBA).r &&
|
|
83
|
+
value1.g === (value2 as RGBA).g &&
|
|
84
|
+
value1.b === (value2 as RGBA).b &&
|
|
85
|
+
value1.a === (value2 as RGBA).a
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isInsideScope(variable: Variable, scope: VariableScope) {
|
|
90
|
+
if (variable.scopes.includes("ALL_SCOPES")) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (variable.scopes.includes("ALL_FILLS")) {
|
|
95
|
+
if (scope === "FRAME_FILL" || scope === "SHAPE_FILL" || scope === "TEXT_FILL") {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return variable.scopes.includes(scope);
|
|
101
|
+
}
|
|
102
|
+
|
|
70
103
|
// public
|
|
71
104
|
function getVariableName(key: string) {
|
|
72
105
|
const slug = getFigmaVariableSlug(key);
|
|
73
106
|
return variableNameTransformer({ slug });
|
|
74
107
|
}
|
|
75
108
|
|
|
76
|
-
function inferVariableName(
|
|
109
|
+
function inferVariableName(value: VariableValueResolved, scope: VariableScope) {
|
|
77
110
|
// NOTE: We assume that the variable is in the default mode or value is equal between all modes for simplicity.
|
|
78
|
-
const
|
|
111
|
+
const inferredVariables = variables.filter(
|
|
79
112
|
(variable) =>
|
|
80
|
-
variable
|
|
81
|
-
|
|
113
|
+
isInsideScope(variable, scope) &&
|
|
114
|
+
isIdenticalVariableValue(
|
|
115
|
+
resolveVariableValue(variable.id, getDefaultModeId(variable)),
|
|
116
|
+
value,
|
|
117
|
+
),
|
|
82
118
|
);
|
|
83
119
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
120
|
+
const inferredVariableNames = inferredVariables.map((variable) =>
|
|
121
|
+
getVariableName(variable.key),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const sortedVariableNames = inferredVariableNames.sort(inferCompareFunction);
|
|
87
125
|
|
|
88
|
-
return
|
|
126
|
+
return sortedVariableNames[0];
|
|
89
127
|
}
|
|
90
128
|
|
|
91
129
|
return {
|
package/src/index.ts
CHANGED