@seed-design/figma 1.1.13 → 1.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/lib/codegen/index.cjs +636 -114
  2. package/lib/codegen/index.d.ts +136 -96
  3. package/lib/codegen/index.d.ts.map +1 -1
  4. package/lib/codegen/index.js +636 -114
  5. package/lib/codegen/targets/react/index.cjs +682 -134
  6. package/lib/codegen/targets/react/index.d.ts +31 -11
  7. package/lib/codegen/targets/react/index.d.ts.map +1 -1
  8. package/lib/codegen/targets/react/index.js +682 -135
  9. package/lib/index.cjs +1254 -433
  10. package/lib/index.d.ts +46 -10
  11. package/lib/index.d.ts.map +1 -1
  12. package/lib/index.js +1254 -433
  13. package/package.json +1 -1
  14. package/src/codegen/component-properties.ts +5 -5
  15. package/src/codegen/core/value-resolver.ts +49 -12
  16. package/src/codegen/targets/figma/frame.ts +1 -0
  17. package/src/codegen/targets/figma/pipeline.ts +5 -0
  18. package/src/codegen/targets/figma/props.ts +30 -1
  19. package/src/codegen/targets/figma/shape.ts +1 -0
  20. package/src/codegen/targets/figma/value-resolver.ts +20 -0
  21. package/src/codegen/targets/react/component/handlers/menu-sheet.ts +1 -1
  22. package/src/codegen/targets/react/component/handlers/page-banner.ts +2 -2
  23. package/src/codegen/targets/react/component/handlers/{radio-mark.ts → radiomark.ts} +4 -4
  24. package/src/codegen/targets/react/component/handlers/result-section.ts +1 -1
  25. package/src/codegen/targets/react/component/handlers/{switch-mark.ts → switchmark.ts} +4 -4
  26. package/src/codegen/targets/react/component/index.ts +4 -4
  27. package/src/codegen/targets/react/frame.ts +16 -2
  28. package/src/codegen/targets/react/pipeline.ts +6 -1
  29. package/src/codegen/targets/react/props.ts +26 -0
  30. package/src/codegen/targets/react/shape.ts +5 -1
  31. package/src/codegen/targets/react/value-resolver.ts +26 -0
  32. package/src/entities/data/__generated__/component-sets/index.d.ts +84 -89
  33. package/src/entities/data/__generated__/component-sets/index.mjs +84 -89
  34. package/src/entities/data/__generated__/components/index.d.ts +2 -2
  35. package/src/entities/data/__generated__/components/index.mjs +2 -2
  36. package/src/entities/data/__generated__/icons/index.mjs +14 -0
  37. package/src/entities/data/__generated__/styles/index.mjs +190 -1
  38. package/src/entities/data/__generated__/variable-collections/index.mjs +11 -1
  39. package/src/entities/data/__generated__/variables/index.mjs +280 -0
  40. package/src/normalizer/from-plugin.ts +427 -258
  41. package/src/normalizer/from-rest.ts +428 -58
  42. package/src/normalizer/types.ts +63 -10
  43. package/src/utils/figma-node.ts +15 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seed-design/figma",
3
- "version": "1.1.13",
3
+ "version": "1.1.14",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/daangn/seed-design.git",
@@ -309,8 +309,8 @@ export type RadioProperties = InferComponentDefinition<
309
309
  typeof sets.radio.componentPropertyDefinitions
310
310
  >;
311
311
 
312
- export type RadioMarkProperties = InferComponentDefinition<
313
- typeof sets.radioMark.componentPropertyDefinitions
312
+ export type RadiomarkProperties = InferComponentDefinition<
313
+ typeof sets.radiomark.componentPropertyDefinitions
314
314
  >;
315
315
 
316
316
  export type ReactionButtonProperties = InferComponentDefinition<
@@ -318,7 +318,7 @@ export type ReactionButtonProperties = InferComponentDefinition<
318
318
  >;
319
319
 
320
320
  export type ResultSectionProperties = InferComponentDefinition<
321
- typeof sets.templateResultSection.componentPropertyDefinitions
321
+ typeof sets.resultSection.componentPropertyDefinitions
322
322
  >;
323
323
 
324
324
  export type SegmentedControlProperties = InferComponentDefinition<
@@ -370,8 +370,8 @@ export type SwitchProperties = InferComponentDefinition<
370
370
  typeof sets._switch.componentPropertyDefinitions
371
371
  >;
372
372
 
373
- export type SwitchMarkProperties = InferComponentDefinition<
374
- typeof sets.switchMark.componentPropertyDefinitions
373
+ export type SwitchmarkProperties = InferComponentDefinition<
374
+ typeof sets.switchmark.componentPropertyDefinitions
375
375
  >;
376
376
 
377
377
  export type ToggleButtonProperties = InferComponentDefinition<
@@ -1,6 +1,7 @@
1
1
  import type { StyleService, VariableValueResolved } from "@/entities";
2
2
  import type {
3
3
  NormalizedCornerTrait,
4
+ NormalizedHasEffectsTrait,
4
5
  NormalizedHasFramePropertiesTrait,
5
6
  NormalizedHasGeometryTrait,
6
7
  NormalizedHasLayoutTrait,
@@ -63,6 +64,9 @@ export interface ValueResolver<TColor, TGradient, TDimension, TFontDimension, TF
63
64
  itemSpacing: (
64
65
  node: NormalizedHasFramePropertiesTrait & NormalizedIsLayerTrait,
65
66
  ) => string | TDimension | undefined;
67
+ counterAxisSpacing: (
68
+ node: NormalizedHasFramePropertiesTrait & NormalizedIsLayerTrait,
69
+ ) => string | TDimension | undefined;
66
70
  topLeftRadius: (
67
71
  node: NormalizedCornerTrait & NormalizedIsLayerTrait,
68
72
  ) => string | TDimension | undefined;
@@ -84,10 +88,14 @@ export interface ValueResolver<TColor, TGradient, TDimension, TFontDimension, TF
84
88
  lineHeight: (
85
89
  node: NormalizedTypePropertiesTrait & NormalizedIsLayerTrait,
86
90
  ) => string | TFontDimension | undefined;
91
+ boxShadow: (node: NormalizedHasEffectsTrait & NormalizedIsLayerTrait) => string | undefined;
87
92
  };
88
93
  getTextStyleValue: (
89
94
  node: NormalizedTypePropertiesTrait & NormalizedIsLayerTrait,
90
95
  ) => string | undefined; // TODO: we might turn this into a generic; not sure yet
96
+ getEffectStyleValue: (
97
+ node: NormalizedHasEffectsTrait & NormalizedIsLayerTrait,
98
+ ) => string | undefined;
91
99
  }
92
100
 
93
101
  export interface ValueResolverDeps<TColor, TGradient, TDimension, TFontDimension, TFontWeight> {
@@ -95,12 +103,20 @@ export interface ValueResolverDeps<TColor, TGradient, TDimension, TFontDimension
95
103
  variableNameFormatter: (props: { slug: string[] }) => string;
96
104
  styleService: StyleService;
97
105
  textStyleNameFormatter: (props: { slug: string[] }) => string;
106
+ effectStyleNameFormatter: (props: { slug: string[] }) => string;
98
107
  fillStyleResolver: (props: { slug: string[] }) => TGradient | undefined;
99
108
  rawValueFormatters: {
100
109
  color: (value: RGBA) => string | TColor;
101
110
  dimension: (value: number) => string | TDimension;
102
111
  fontDimension: (value: number) => string | TFontDimension;
103
112
  fontWeight: (value: number) => string | TFontWeight;
113
+ boxShadow: (value: {
114
+ type: "DROP_SHADOW" | "INNER_SHADOW";
115
+ color: RGBA;
116
+ offset: { x: number; y: number };
117
+ radius: number;
118
+ spread?: number;
119
+ }) => string;
104
120
  };
105
121
  shouldInferVariableName: boolean;
106
122
  }
@@ -110,6 +126,7 @@ export function createValueResolver<TColor, TGradient, TDimension, TFontDimensio
110
126
  variableNameFormatter,
111
127
  styleService,
112
128
  textStyleNameFormatter,
129
+ effectStyleNameFormatter,
113
130
  fillStyleResolver,
114
131
  rawValueFormatters,
115
132
  shouldInferVariableName,
@@ -149,12 +166,12 @@ export function createValueResolver<TColor, TGradient, TDimension, TFontDimensio
149
166
  }
150
167
 
151
168
  function processColor(
152
- key: string | undefined,
169
+ id: string | undefined,
153
170
  value: RGBA | undefined,
154
171
  scope: "FRAME_FILL" | "SHAPE_FILL" | "STROKE_COLOR" | "TEXT_FILL",
155
172
  ) {
156
- if (key) {
157
- return getVariableName(key);
173
+ if (id) {
174
+ return getVariableName(id);
158
175
  }
159
176
 
160
177
  if (value !== undefined) {
@@ -175,12 +192,12 @@ export function createValueResolver<TColor, TGradient, TDimension, TFontDimensio
175
192
  }
176
193
 
177
194
  function processDimension(
178
- key: string | undefined,
195
+ id: string | undefined,
179
196
  value: number | undefined,
180
197
  scope: "WIDTH_HEIGHT" | "GAP" | "CORNER_RADIUS",
181
198
  ) {
182
- if (key) {
183
- return getVariableName(key);
199
+ if (id) {
200
+ return getVariableName(id);
184
201
  }
185
202
 
186
203
  if (value !== undefined) {
@@ -191,12 +208,12 @@ export function createValueResolver<TColor, TGradient, TDimension, TFontDimensio
191
208
  }
192
209
 
193
210
  function processFontDimension(
194
- key: string | undefined,
211
+ id: string | undefined,
195
212
  value: number | undefined,
196
213
  scope: "FONT_SIZE" | "LINE_HEIGHT",
197
214
  ) {
198
- if (key) {
199
- return getVariableName(key);
215
+ if (id) {
216
+ return getVariableName(id);
200
217
  }
201
218
 
202
219
  if (value !== undefined) {
@@ -206,9 +223,9 @@ export function createValueResolver<TColor, TGradient, TDimension, TFontDimensio
206
223
  return undefined;
207
224
  }
208
225
 
209
- function processFontWeight(key: string | undefined, value: number | undefined) {
210
- if (key) {
211
- return getVariableName(key);
226
+ function processFontWeight(id: string | undefined, value: number | undefined) {
227
+ if (id) {
228
+ return getVariableName(id);
212
229
  }
213
230
 
214
231
  if (value !== undefined) {
@@ -271,6 +288,8 @@ export function createValueResolver<TColor, TGradient, TDimension, TFontDimensio
271
288
  processDimension(node.boundVariables?.paddingBottom?.id, node.paddingBottom, "GAP"),
272
289
  itemSpacing: (node) =>
273
290
  processDimension(node.boundVariables?.itemSpacing?.id, node.itemSpacing, "GAP"),
291
+ counterAxisSpacing: (node) =>
292
+ processDimension(node.boundVariables?.counterAxisSpacing?.id, node.counterAxisSpacing, "GAP"),
274
293
  frameFill: (node) =>
275
294
  node.fillStyleKey
276
295
  ? processFillStyle(node.fillStyleKey)
@@ -323,6 +342,11 @@ export function createValueResolver<TColor, TGradient, TDimension, TFontDimensio
323
342
  node.style.lineHeightPx,
324
343
  "LINE_HEIGHT",
325
344
  ),
345
+ boxShadow: (node) => {
346
+ if (node.effects.length === 0) return undefined;
347
+
348
+ return node.effects.map(rawValueFormatters.boxShadow).join(", ");
349
+ },
326
350
  };
327
351
 
328
352
  function getTextStyleValue(node: NormalizedTypePropertiesTrait & NormalizedIsLayerTrait) {
@@ -337,8 +361,21 @@ export function createValueResolver<TColor, TGradient, TDimension, TFontDimensio
337
361
  return textStyleNameFormatter({ slug });
338
362
  }
339
363
 
364
+ function getEffectStyleValue(node: NormalizedHasEffectsTrait & NormalizedIsLayerTrait) {
365
+ if (!node.effectStyleKey) return undefined;
366
+
367
+ const slug = styleService.getSlug(node.effectStyleKey);
368
+
369
+ if (!slug) {
370
+ return undefined;
371
+ }
372
+
373
+ return effectStyleNameFormatter({ slug });
374
+ }
375
+
340
376
  return {
341
377
  getFormattedValue,
342
378
  getTextStyleValue,
379
+ getEffectStyleValue,
343
380
  };
344
381
  }
@@ -25,6 +25,7 @@ export function createFrameTransformer({
25
25
  ...propsConverters.selfLayout(node),
26
26
  ...propsConverters.frameFill(node),
27
27
  ...propsConverters.stroke(node),
28
+ ...propsConverters.shadow(node),
28
29
  };
29
30
 
30
31
  return createElement(
@@ -9,6 +9,7 @@ import {
9
9
  createFrameFillPropsConverter,
10
10
  createRadiusPropsConverter,
11
11
  createSelfLayoutPropsConverter,
12
+ createShadowPropsConverter,
12
13
  createShapeFillPropsConverter,
13
14
  createStrokePropsConverter,
14
15
  createTextFillPropsConverter,
@@ -21,6 +22,7 @@ import {
21
22
  } from "./shape";
22
23
  import { createTextTransformer } from "./text";
23
24
  import {
25
+ defaultEffectStyleNameFormatter,
24
26
  defaultFillStyleResolver,
25
27
  defaultRawValueFormatters,
26
28
  defaultTextStyleNameFormatter,
@@ -40,6 +42,7 @@ export function createPipeline(options: CreatePipelineConfig = {}): CodeGenerato
40
42
  variableNameFormatter: defaultVariableNameFormatter,
41
43
  styleService,
42
44
  textStyleNameFormatter: defaultTextStyleNameFormatter,
45
+ effectStyleNameFormatter: defaultEffectStyleNameFormatter,
43
46
  fillStyleResolver: defaultFillStyleResolver,
44
47
  rawValueFormatters: defaultRawValueFormatters,
45
48
  shouldInferVariableName,
@@ -52,6 +55,7 @@ export function createPipeline(options: CreatePipelineConfig = {}): CodeGenerato
52
55
  const textFillPropsConverter = createTextFillPropsConverter(valueResolver);
53
56
  const radiusPropsConverter = createRadiusPropsConverter(valueResolver);
54
57
  const strokePropsConverter = createStrokePropsConverter(valueResolver);
58
+ const shadowPropsConverter = createShadowPropsConverter(valueResolver);
55
59
  const typeStylePropsConverter = createTypeStylePropsConverter(valueResolver);
56
60
 
57
61
  const propsConverters = {
@@ -62,6 +66,7 @@ export function createPipeline(options: CreatePipelineConfig = {}): CodeGenerato
62
66
  textFill: textFillPropsConverter,
63
67
  radius: radiusPropsConverter,
64
68
  stroke: strokePropsConverter,
69
+ shadow: shadowPropsConverter,
65
70
  typeStyle: typeStylePropsConverter,
66
71
  };
67
72
 
@@ -2,6 +2,7 @@ import { createPropsConverter, definePropsConverter, type PropsConverter } from
2
2
  import type {
3
3
  NormalizedCornerTrait,
4
4
  NormalizedHasChildrenTrait,
5
+ NormalizedHasEffectsTrait,
5
6
  NormalizedHasFramePropertiesTrait,
6
7
  NormalizedHasGeometryTrait,
7
8
  NormalizedHasLayoutTrait,
@@ -18,6 +19,7 @@ export interface PropsConverters {
18
19
  shapeFill: PropsConverter<FillTrait, FillProps>;
19
20
  textFill: PropsConverter<FillTrait, FillProps>;
20
21
  stroke: PropsConverter<StrokeTrait, StrokeProps>;
22
+ shadow: PropsConverter<ShadowTrait, ShadowProps>;
21
23
  typeStyle: PropsConverter<TypeStyleTrait, TypeStyleProps>;
22
24
  }
23
25
 
@@ -34,6 +36,8 @@ export type FillTrait = NormalizedIsLayerTrait & NormalizedHasGeometryTrait;
34
36
 
35
37
  export type StrokeTrait = NormalizedIsLayerTrait & NormalizedHasGeometryTrait;
36
38
 
39
+ export type ShadowTrait = NormalizedIsLayerTrait & NormalizedHasEffectsTrait;
40
+
37
41
  export type TypeStyleTrait = NormalizedTypePropertiesTrait & NormalizedIsLayerTrait;
38
42
 
39
43
  export interface ContainerLayoutProps {
@@ -42,6 +46,7 @@ export interface ContainerLayoutProps {
42
46
  counterAxisAlignItems?: "MIN" | "CENTER" | "MAX" | "BASELINE";
43
47
  layoutWrap?: "WRAP" | "NO_WRAP";
44
48
  itemSpacing?: number | string; // string when variable
49
+ counterAxisSpacing?: number | string; // string when variable
45
50
  paddingTop?: number | string; // string when variable
46
51
  paddingBottom?: number | string; // string when variable
47
52
  paddingLeft?: number | string; // string when variable
@@ -64,6 +69,7 @@ export function createContainerLayoutPropsConverter(
64
69
  counterAxisAlignItems: ({ counterAxisAlignItems }) => counterAxisAlignItems,
65
70
  layoutWrap: ({ layoutWrap }) => layoutWrap,
66
71
  itemSpacing: (node) => valueResolver.getFormattedValue.itemSpacing(node),
72
+ counterAxisSpacing: (node) => valueResolver.getFormattedValue.counterAxisSpacing(node),
67
73
  paddingTop: (node) => valueResolver.getFormattedValue.paddingTop(node),
68
74
  paddingBottom: (node) => valueResolver.getFormattedValue.paddingBottom(node),
69
75
  paddingLeft: (node) => valueResolver.getFormattedValue.paddingLeft(node),
@@ -148,7 +154,7 @@ export function createRadiusPropsConverter(valueResolver: FigmaValueResolver) {
148
154
  }
149
155
 
150
156
  export interface FillProps {
151
- fill?: string;
157
+ fill?: string | { value: string; direction?: string };
152
158
  }
153
159
 
154
160
  export function createFrameFillPropsConverter(valueResolver: FigmaValueResolver) {
@@ -231,3 +237,26 @@ export function createTypeStylePropsConverter(
231
237
  };
232
238
  });
233
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
+ }
@@ -33,6 +33,7 @@ export function createVectorTransformer({
33
33
  ...propsConverters.radius(node),
34
34
  ...propsConverters.stroke(node),
35
35
  ...propsConverters.shapeFill(node),
36
+ ...propsConverters.shadow(node),
36
37
  },
37
38
  [],
38
39
  {
@@ -1,5 +1,6 @@
1
1
  import type { ValueResolver } from "@/codegen/core";
2
2
  import { toCssRgba } from "@/utils/css";
3
+ import type { RGBA } from "@figma/rest-api-spec";
3
4
  import { camelCase } from "change-case";
4
5
 
5
6
  export type FigmaValueResolver = ValueResolver<
@@ -19,6 +20,9 @@ export const defaultVariableNameFormatter = ({ slug }: { slug: string[] }) =>
19
20
  export const defaultTextStyleNameFormatter = ({ slug }: { slug: string[] }) =>
20
21
  slug[slug.length - 1]!;
21
22
 
23
+ export const defaultEffectStyleNameFormatter = ({ slug }: { slug: string[] }) =>
24
+ slug[slug.length - 1]!;
25
+
22
26
  export const defaultFillStyleResolver = ({ slug }: { slug: string[] }) => {
23
27
  const [, ...rest] = slug;
24
28
 
@@ -47,9 +51,25 @@ export const defaultFillStyleResolver = ({ slug }: { slug: string[] }) => {
47
51
  };
48
52
  };
49
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
+
50
69
  export const defaultRawValueFormatters = {
51
70
  color: (value: RGBA) => toCssRgba(value),
52
71
  dimension: (value: number) => value,
53
72
  fontDimension: (value: number) => value,
54
73
  fontWeight: (value: number) => value,
74
+ boxShadow: formatBoxShadow,
55
75
  };
@@ -80,7 +80,7 @@ export const createMenuSheetHandler = (ctx: ComponentHandlerDeps) => {
80
80
  // const description = props["Description Text#21827:0"].value;
81
81
 
82
82
  const { labelAlign } = match(props.Layout.value)
83
- .with("Text with Icon", "Text with Subtext", () => ({ labelAlign: "left" }))
83
+ .with("Text with Icon", () => ({ labelAlign: "left" }))
84
84
  .with("Text Only", () => ({ labelAlign: "center" }))
85
85
  .exhaustive();
86
86
 
@@ -34,7 +34,7 @@ export const createPageBannerHandler = (ctx: ComponentHandlerDeps) => {
34
34
  .with("Actionable", () => ({ tag: "ActionablePageBanner", suffix: undefined }))
35
35
  .with("Dismissible", () => ({ tag: "DismissiblePageBanner", suffix: undefined }))
36
36
  .with("Display", () => ({ tag: "PageBanner", suffix: undefined }))
37
- .with("With Action", () => {
37
+ .with("Display (With Action)", () => {
38
38
  const [buttonNode] = findAllInstances<PageBannerButtonProperties>({
39
39
  node,
40
40
  key: SUFFIX_BUTTON_KEY,
@@ -43,7 +43,7 @@ export const createPageBannerHandler = (ctx: ComponentHandlerDeps) => {
43
43
 
44
44
  return { tag: "PageBanner", suffix };
45
45
  })
46
- .with("Custom", () => ({
46
+ .with("Actionable (Custom)", () => ({
47
47
  tag: "PageBanner",
48
48
  suffix: createElement("div", undefined, "Custom Content"),
49
49
  }))
@@ -1,4 +1,4 @@
1
- import type { RadioMarkProperties } from "@/codegen/component-properties";
1
+ import type { RadiomarkProperties } from "@/codegen/component-properties";
2
2
  import { defineComponentHandler } from "@/codegen/core";
3
3
  import * as metadata from "@/entities/data/__generated__/component-sets";
4
4
  import { createLocalSnippetHelper } from "../../element-factories";
@@ -8,9 +8,9 @@ import { match } from "ts-pattern";
8
8
 
9
9
  const { createLocalSnippetElement } = createLocalSnippetHelper("radio-group");
10
10
 
11
- export const createRadioMarkHandler = (_ctx: ComponentHandlerDeps) =>
12
- defineComponentHandler<RadioMarkProperties>(
13
- metadata.radioMark.key,
11
+ export const createRadiomarkHandler = (_ctx: ComponentHandlerDeps) =>
12
+ defineComponentHandler<RadiomarkProperties>(
13
+ metadata.radiomark.key,
14
14
  ({ componentProperties: props }) => {
15
15
  const tone = match(props.Tone.value)
16
16
  .with("Neutral", () => "neutral")
@@ -18,7 +18,7 @@ export const createResultSectionHandler = (ctx: ComponentHandlerDeps) => {
18
18
  const ghostButtonHandler = createActionButtonGhostHandler(ctx);
19
19
 
20
20
  return defineComponentHandler<ResultSectionProperties>(
21
- metadata.templateResultSection.key,
21
+ metadata.resultSection.key,
22
22
  (node, traverse) => {
23
23
  const props = node.componentProperties;
24
24
 
@@ -1,4 +1,4 @@
1
- import type { SwitchMarkProperties } from "@/codegen/component-properties";
1
+ import type { SwitchmarkProperties } from "@/codegen/component-properties";
2
2
  import { defineComponentHandler } from "@/codegen/core";
3
3
  import * as metadata from "@/entities/data/__generated__/component-sets";
4
4
  import { createLocalSnippetHelper } from "../../element-factories";
@@ -7,9 +7,9 @@ import { match } from "ts-pattern";
7
7
 
8
8
  const { createLocalSnippetElement } = createLocalSnippetHelper("switch");
9
9
 
10
- export const createSwitchMarkHandler = (_ctx: ComponentHandlerDeps) =>
11
- defineComponentHandler<SwitchMarkProperties>(
12
- metadata.switchMark.key,
10
+ export const createSwitchmarkHandler = (_ctx: ComponentHandlerDeps) =>
11
+ defineComponentHandler<SwitchmarkProperties>(
12
+ metadata.switchmark.key,
13
13
  ({ componentProperties: props }) => {
14
14
  const tone = match(props.Tone.value)
15
15
  .with("Neutral", () => "neutral")
@@ -36,7 +36,7 @@ import { createMenuSheetHandler } from "./handlers/menu-sheet";
36
36
  import { createPageBannerHandler } from "./handlers/page-banner";
37
37
  import { createProgressCircleHandler } from "./handlers/progress-circle";
38
38
  import { createRadioGroupItemHandler } from "@/codegen/targets/react/component/handlers/radio-group";
39
- import { createRadioMarkHandler } from "@/codegen/targets/react/component/handlers/radio-mark";
39
+ import { createRadiomarkHandler } from "@/codegen/targets/react/component/handlers/radiomark";
40
40
  import { createReactionButtonHandler } from "./handlers/reaction-button";
41
41
  import { createResultSectionHandler } from "./handlers/result-section";
42
42
  import { createSegmentedControlHandler } from "./handlers/segmented-control";
@@ -47,7 +47,7 @@ import {
47
47
  createSliderFieldHandler,
48
48
  } from "@/codegen/targets/react/component/handlers/slider";
49
49
  import { createSnackbarHandler } from "./handlers/snackbar";
50
- import { createSwitchMarkHandler } from "@/codegen/targets/react/component/handlers/switch-mark";
50
+ import { createSwitchmarkHandler } from "@/codegen/targets/react/component/handlers/switchmark";
51
51
  import { createSwitchHandler } from "./handlers/switch";
52
52
  import { createTabsHandler } from "@/codegen/targets/react/component/handlers/tabs";
53
53
  import { createTextInputFieldHandler, createTextareaFieldHandler } from "./handlers/text-field";
@@ -89,9 +89,9 @@ export const unboundSeedComponentHandlers: Array<UnboundComponentHandler<any>> =
89
89
  createCheckboxHandler,
90
90
  createCheckmarkHandler,
91
91
  createRadioGroupItemHandler,
92
- createRadioMarkHandler,
92
+ createRadiomarkHandler,
93
93
  createSwitchHandler,
94
- createSwitchMarkHandler,
94
+ createSwitchmarkHandler,
95
95
  createAlertDialogHandler,
96
96
  createDividerHandler,
97
97
  createAvatarHandler,
@@ -45,12 +45,18 @@ export function createFrameTransformer({
45
45
  ...propsConverters.selfLayout(node),
46
46
  ...propsConverters.frameFill(node),
47
47
  ...propsConverters.stroke(node),
48
+ ...propsConverters.shadow(node),
48
49
  };
49
50
 
50
51
  const isStretch = props.align === undefined || props.align === "stretch";
51
52
 
52
53
  const layoutComponent = inferLayoutComponent(props, isFlex);
53
54
 
55
+ const hasSpacingMismatch =
56
+ node.layoutWrap === "WRAP" &&
57
+ node.counterAxisSpacing !== undefined &&
58
+ node.itemSpacing !== node.counterAxisSpacing;
59
+
54
60
  const hasImageFill = node.fills.some(({ type }) => type === "IMAGE");
55
61
  const imgElement = hasImageFill
56
62
  ? createElement("img", {
@@ -67,15 +73,23 @@ export function createFrameTransformer({
67
73
  : transformedChildren),
68
74
  ];
69
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
+
70
84
  switch (layoutComponent) {
71
85
  case "VStack":
72
86
  case "HStack": {
73
87
  const { direction: _direction, ...rest } = props;
74
88
 
75
- return createSeedReactElement(layoutComponent, rest, processedChildren);
89
+ return createSeedReactElement(layoutComponent, rest, processedChildren, { comment });
76
90
  }
77
91
  case "Box":
78
- return createSeedReactElement("Box", props, processedChildren);
92
+ return createSeedReactElement("Box", props, processedChildren, { comment });
79
93
  }
80
94
  },
81
95
  );
@@ -14,6 +14,7 @@ import {
14
14
  createIconSelfLayoutPropsConverter,
15
15
  createRadiusPropsConverter,
16
16
  createSelfLayoutPropsConverter,
17
+ createShadowPropsConverter,
17
18
  createShapeFillPropsConverter,
18
19
  createStrokePropsConverter,
19
20
  createTextFillPropsConverter,
@@ -27,9 +28,10 @@ import {
27
28
  } from "./shape";
28
29
  import { createTextTransformer } from "./text";
29
30
  import {
31
+ defaultEffectStyleNameFormatter,
32
+ defaultFillStyleResolver,
30
33
  defaultRawValueFormatters,
31
34
  defaultTextStyleNameFormatter,
32
- defaultFillStyleResolver,
33
35
  defaultVariableNameFormatter,
34
36
  } from "./value-resolver";
35
37
 
@@ -53,6 +55,7 @@ export function createPipeline(options: CreatePipelineConfig = {}) {
53
55
  variableNameFormatter: defaultVariableNameFormatter,
54
56
  styleService,
55
57
  textStyleNameFormatter: defaultTextStyleNameFormatter,
58
+ effectStyleNameFormatter: defaultEffectStyleNameFormatter,
56
59
  fillStyleResolver: defaultFillStyleResolver,
57
60
  rawValueFormatters: defaultRawValueFormatters,
58
61
  shouldInferVariableName,
@@ -67,6 +70,7 @@ export function createPipeline(options: CreatePipelineConfig = {}) {
67
70
  const vectorChildrenFillPropsConverter = createVectorChildrenFillPropsConverter(valueResolver);
68
71
  const radiusPropsConverter = createRadiusPropsConverter(valueResolver);
69
72
  const strokePropsConverter = createStrokePropsConverter(valueResolver);
73
+ const shadowPropsConverter = createShadowPropsConverter(valueResolver);
70
74
  const typeStylePropsConverter = createTypeStylePropsConverter({
71
75
  valueResolver,
72
76
  });
@@ -80,6 +84,7 @@ export function createPipeline(options: CreatePipelineConfig = {}) {
80
84
  vectorChildrenFill: vectorChildrenFillPropsConverter,
81
85
  radius: radiusPropsConverter,
82
86
  stroke: strokePropsConverter,
87
+ shadow: shadowPropsConverter,
83
88
  typeStyle: typeStylePropsConverter,
84
89
  };
85
90
 
@@ -2,6 +2,7 @@ import { createPropsConverter, definePropsConverter, type PropsConverter } from
2
2
  import type {
3
3
  NormalizedCornerTrait,
4
4
  NormalizedHasChildrenTrait,
5
+ NormalizedHasEffectsTrait,
5
6
  NormalizedHasFramePropertiesTrait,
6
7
  NormalizedHasGeometryTrait,
7
8
  NormalizedHasLayoutTrait,
@@ -21,6 +22,7 @@ export interface PropsConverters {
21
22
  textFill: PropsConverter<FillTrait, TextFillProps>;
22
23
  vectorChildrenFill: PropsConverter<ContainerLayoutTrait, VectorChildrenFillProps>;
23
24
  stroke: PropsConverter<StrokeTrait, StrokeProps>;
25
+ shadow: PropsConverter<ShadowTrait, ShadowProps>;
24
26
  typeStyle: PropsConverter<TypeStyleTrait, TypeStyleProps>;
25
27
  }
26
28
 
@@ -37,6 +39,8 @@ export type FillTrait = NormalizedIsLayerTrait & NormalizedHasGeometryTrait;
37
39
 
38
40
  export type StrokeTrait = NormalizedIsLayerTrait & NormalizedHasGeometryTrait;
39
41
 
42
+ export type ShadowTrait = NormalizedIsLayerTrait & NormalizedHasEffectsTrait;
43
+
40
44
  export type TypeStyleTrait = NormalizedTypePropertiesTrait & NormalizedIsLayerTrait;
41
45
 
42
46
  export interface ContainerLayoutProps {
@@ -389,3 +393,25 @@ export function createStrokePropsConverter(
389
393
  };
390
394
  });
391
395
  }
396
+
397
+ export interface ShadowProps {
398
+ boxShadow?: string;
399
+ }
400
+
401
+ export function createShadowPropsConverter(
402
+ valueResolver: ReactValueResolver,
403
+ ): PropsConverter<ShadowTrait, ShadowProps> {
404
+ return definePropsConverter((node: ShadowTrait) => {
405
+ const effectStyleName = valueResolver.getEffectStyleValue(node);
406
+ if (effectStyleName) {
407
+ return {
408
+ boxShadow: effectStyleName,
409
+ };
410
+ }
411
+
412
+ const boxShadow = valueResolver.getFormattedValue.boxShadow(node);
413
+ return {
414
+ boxShadow,
415
+ };
416
+ });
417
+ }
@@ -17,7 +17,11 @@ export function createRectangleTransformer({
17
17
  return defineElementTransformer((node: NormalizedRectangleNode) => {
18
18
  return createSeedReactElement(
19
19
  "Box",
20
- { ...propsConverters.selfLayout(node), background: "palette.gray200" },
20
+ {
21
+ ...propsConverters.selfLayout(node),
22
+ ...propsConverters.shadow(node),
23
+ background: "palette.gray200",
24
+ },
21
25
  undefined,
22
26
  {
23
27
  comment: "Rectangle Node Placeholder",