terrazzo-plugin-figma-json 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # terrazzo-plugin-figma-json
2
2
 
3
- A [Terrazzo](https://terrazzo.app) plugin that converts W3C DTCG design tokens into Figma-compatible JSON format for import into Figma Variables.
3
+ A [Terrazzo](https://terrazzo.app) plugin that converts W3C DTCG design tokens into Figma-compatible JSON format for [import into Figma Variables](https://help.figma.com/hc/en-us/articles/15343816063383-Modes-for-variables#h_01KAGYPSFC984XDB4YWBCNRZJ7).
4
+
5
+ ## Requirements
6
+
7
+ This plugin requires Terrazzo 2.0.0-beta.0 or later:
8
+
9
+ ```bash
10
+ npm install @terrazzo/cli@2.0.0-beta.0 @terrazzo/parser@2.0.0-beta.0
11
+ ```
4
12
 
5
13
  ## Installation
6
14
 
@@ -49,7 +57,7 @@ npx tz build
49
57
 
50
58
  ## Output Structure
51
59
 
52
- When using a resolver file (recommended), the plugin automatically splits output by resolver sets and modifier contexts:
60
+ With a resolver file, the plugin splits output by resolver sets and modifier contexts:
53
61
 
54
62
  ```
55
63
  dist/
@@ -60,7 +68,7 @@ dist/
60
68
  └── breakpoint-small.figma.json
61
69
  ```
62
70
 
63
- Without a resolver, all tokens are output to a single file.
71
+ Without a resolver, all tokens are output to a single file (`tokens.figma.json` by default).
64
72
 
65
73
  ## Supported Token Types
66
74
 
@@ -73,6 +81,9 @@ Without a resolver, all tokens are output to a single file.
73
81
  | `fontWeight` | Number or String | Values pass through with validation |
74
82
  | `number` | Number or Boolean | Numbers pass through; use `com.figma.type: "boolean"` for booleans |
75
83
  | `typography` | Split tokens | Split into fontFamily, fontSize, fontWeight, lineHeight, letterSpacing |
84
+ | `shadow` | Split tokens | Split into color, offsetX, offsetY, blur, spread; indexed for multiple layers (`inset` not applicable in Figma) |
85
+ | `border` | Split tokens (partial) | Split into color, width (`style` not applicable in Figma) |
86
+ | `gradient` | Split tokens (partial) | Stop colors extracted (`position` not applicable in Figma) |
76
87
 
77
88
  ### Typography Token Splitting
78
89
 
@@ -113,11 +124,113 @@ Figma doesn't support composite typography tokens, so they're automatically spli
113
124
 
114
125
  Note: `lineHeight` is converted from a unitless multiplier to absolute px (see [Figma Limitations](#figma-limitations)).
115
126
 
127
+ ### Shadow Token Splitting
128
+
129
+ Shadow tokens are split into individual sub-tokens. Array shadows (multiple layers) use indexed prefixes.
130
+
131
+ **Input:**
132
+ ```json
133
+ {
134
+ "shadow": {
135
+ "$type": "shadow",
136
+ "medium": {
137
+ "$value": {
138
+ "color": { "colorSpace": "srgb", "components": [0, 0, 0], "alpha": 0.2 },
139
+ "offsetX": { "value": 0, "unit": "px" },
140
+ "offsetY": { "value": 4, "unit": "px" },
141
+ "blur": { "value": 8, "unit": "px" },
142
+ "spread": { "value": 0, "unit": "px" }
143
+ }
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ **Output:**
150
+ ```json
151
+ {
152
+ "shadow": {
153
+ "medium": {
154
+ "color": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [0, 0, 0], "alpha": 0.2 } },
155
+ "offsetX": { "$type": "dimension", "$value": { "value": 0, "unit": "px" } },
156
+ "offsetY": { "$type": "dimension", "$value": { "value": 4, "unit": "px" } },
157
+ "blur": { "$type": "dimension", "$value": { "value": 8, "unit": "px" } },
158
+ "spread": { "$type": "dimension", "$value": { "value": 0, "unit": "px" } }
159
+ }
160
+ }
161
+ }
162
+ ```
163
+
164
+ Note: Single shadows produce flat sub-tokens. Multiple shadow layers (arrays with 2+ items) use indexed prefixes (`0.color`, `0.offsetX`, ..., `1.color`, etc.). The `inset` property is dropped since variables cannot be applied to inset shadows in Figma.
165
+
166
+ ### Border Token Splitting (Partial)
167
+
168
+ Border tokens are partially split — only `color` and `width` are extracted. The `style` property is dropped since variables cannot be applied to border style in Figma.
169
+
170
+ **Input:**
171
+ ```json
172
+ {
173
+ "border": {
174
+ "$type": "border",
175
+ "default": {
176
+ "$value": {
177
+ "color": { "colorSpace": "srgb", "components": [0.8, 0.8, 0.8] },
178
+ "width": { "value": 1, "unit": "px" },
179
+ "style": "solid"
180
+ }
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ **Output:**
187
+ ```json
188
+ {
189
+ "border": {
190
+ "default": {
191
+ "color": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [0.8, 0.8, 0.8], "alpha": 1 } },
192
+ "width": { "$type": "dimension", "$value": { "value": 1, "unit": "px" } }
193
+ }
194
+ }
195
+ }
196
+ ```
197
+
198
+ ### Gradient Token Splitting (Partial)
199
+
200
+ Gradient tokens are partially split — only stop colors are extracted. Stop `position` values are dropped since variables cannot be applied to gradient stop positions in Figma.
201
+
202
+ **Input:**
203
+ ```json
204
+ {
205
+ "gradient": {
206
+ "$type": "gradient",
207
+ "primary": {
208
+ "$value": [
209
+ { "color": { "colorSpace": "srgb", "components": [1, 0, 0] }, "position": 0 },
210
+ { "color": { "colorSpace": "srgb", "components": [0, 0, 1] }, "position": 1 }
211
+ ]
212
+ }
213
+ }
214
+ }
215
+ ```
216
+
217
+ **Output:**
218
+ ```json
219
+ {
220
+ "gradient": {
221
+ "primary": {
222
+ "0": { "color": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [1, 0, 0], "alpha": 1 } } },
223
+ "1": { "color": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [0, 0, 1], "alpha": 1 } } }
224
+ }
225
+ }
226
+ }
227
+ ```
228
+
116
229
  ## Unsupported Token Types
117
230
 
118
231
  The following DTCG token types are **not supported** by Figma and will be skipped:
119
232
 
120
- - `shadow`, `border`, `gradient`, `transition`, `strokeStyle`, `cubicBezier`
233
+ - `transition`, `strokeStyle`, `cubicBezier`
121
234
 
122
235
  ## Alias Handling
123
236
 
@@ -158,13 +271,7 @@ For cross-collection aliases (referencing tokens in a different output file):
158
271
 
159
272
  ## Color Space Conversion
160
273
 
161
- Figma only supports **sRGB** and **HSL** color spaces. Other color spaces are converted to sRGB:
162
-
163
- - Display P3, Rec2020, A98 RGB, ProPhoto RGB → sRGB
164
- - OKLCH, OkLab, Lab, LCH → sRGB
165
- - XYZ-D65, XYZ-D50, HWB, sRGB-linear → sRGB
166
-
167
- Colors outside the sRGB gamut will be clipped with a warning.
274
+ Figma only supports sRGB and HSL color spaces. All other color spaces defined in the DTCG spec are converted to sRGB. Colors outside the sRGB gamut are clipped with a warning.
168
275
 
169
276
  ## Boolean Tokens
170
277
 
@@ -250,4 +357,4 @@ Token `c` will resolve to `b.x`, not `a.x`. This is a limitation of how the Terr
250
357
 
251
358
  ## License
252
359
 
253
- MIT
360
+ [MIT](LICENSE)
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEnE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AASzD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;IAChD,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;IACjD,kBAAkB,CAAC,EAAE,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;IAClE,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAsSD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,aAAa,EACb,OAAO,EACP,SAAS,EACT,kBAAyB,EACzB,QAAQ,GACT,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAqOpC"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEnE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AASzD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;IAChD,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;IACjD,kBAAkB,CAAC,EAAE,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;IAClE,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAsSD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,aAAa,EACb,OAAO,EACP,SAAS,EACT,kBAAyB,EACzB,QAAQ,GACT,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA6OpC"}
@@ -15,12 +15,12 @@ export declare const INTERNAL_KEYS: {
15
15
  /**
16
16
  * Token types supported by Figma.
17
17
  */
18
- export declare const SUPPORTED_TYPES: readonly ["color", "dimension", "duration", "fontFamily", "fontWeight", "number", "typography"];
18
+ export declare const SUPPORTED_TYPES: readonly ["color", "dimension", "duration", "fontFamily", "fontWeight", "number", "typography", "shadow", "border", "gradient"];
19
19
  export type SupportedType = (typeof SUPPORTED_TYPES)[number];
20
20
  /**
21
21
  * Token types that are not supported by Figma and will be dropped with a warning.
22
22
  */
23
- export declare const UNSUPPORTED_TYPES: readonly ["shadow", "border", "gradient", "transition", "strokeStyle", "cubicBezier"];
23
+ export declare const UNSUPPORTED_TYPES: readonly ["transition", "strokeStyle", "cubicBezier"];
24
24
  export type UnsupportedType = (typeof UNSUPPORTED_TYPES)[number];
25
25
  /**
26
26
  * Color spaces that Figma natively supports.
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,+BAA+B,CAAC;AAExD,eAAO,MAAM,SAAS,eAAe,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,aAAa;IACxB,2CAA2C;;IAE3C,8DAA8D;;IAE9D,oCAAoC;;CAE5B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,eAAe,iGAQlB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D;;GAEG;AACH,eAAO,MAAM,iBAAiB,uFAAwF,CAAC;AAEvH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;;GAEG;AACH,eAAO,MAAM,kBAAkB,0BAA2B,CAAC;AAE3D,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,+BAA+B,CAAC;AAExD,eAAO,MAAM,SAAS,eAAe,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,aAAa;IACxB,2CAA2C;;IAE3C,8DAA8D;;IAE9D,oCAAoC;;CAE5B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,eAAe,iIAWlB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D;;GAEG;AACH,eAAO,MAAM,iBAAiB,uDAAwD,CAAC;AAEvF,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;;GAEG;AACH,eAAO,MAAM,kBAAkB,0BAA2B,CAAC;AAE3D,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ConverterContext, ConverterResult } from '../types.js';
2
+ /**
3
+ * Convert a DTCG border value to Figma-compatible format.
4
+ * Border tokens are partially split into individual sub-tokens.
5
+ * Only color and width are supported; style is dropped.
6
+ */
7
+ export declare function convertBorder(value: unknown, context: ConverterContext): ConverterResult;
8
+ //# sourceMappingURL=border.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"border.d.ts","sourceRoot":"","sources":["../../src/converters/border.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AAK/E;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAqExF"}
@@ -0,0 +1,8 @@
1
+ import type { ConverterContext, ConverterResult } from '../types.js';
2
+ /**
3
+ * Convert a DTCG gradient value to Figma-compatible format.
4
+ * Gradient tokens are partially split: only stop colors are extracted.
5
+ * Stop positions are dropped since they can't be represented as Figma variables.
6
+ */
7
+ export declare function convertGradient(value: unknown, context: ConverterContext): ConverterResult;
8
+ //# sourceMappingURL=gradient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gradient.d.ts","sourceRoot":"","sources":["../../src/converters/gradient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AAI/E;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA2D1F"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/converters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAgC,KAAK,aAAa,EAAqB,MAAM,iBAAiB,CAAC;AACtG,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AASrE;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,KAAK,eAAe,CAAC;AAevF;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,aAAa,CAEnE;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEvD;AA6CD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAgE/G"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/converters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAgC,KAAK,aAAa,EAAqB,MAAM,iBAAiB,CAAC;AACtG,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAYrE;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,KAAK,eAAe,CAAC;AAkBvF;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,aAAa,CAEnE;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEvD;AA6CD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAgE/G"}
@@ -0,0 +1,11 @@
1
+ import type { ConverterContext, ConverterResult } from '../types.js';
2
+ /**
3
+ * Convert a DTCG shadow value to Figma-compatible format.
4
+ * Shadow tokens are split into individual sub-tokens since Figma
5
+ * doesn't support the composite shadow type.
6
+ *
7
+ * Single shadows produce: color, offsetX, offsetY, blur, spread
8
+ * Multiple shadow layers produce indexed sub-tokens: 0.color, 0.offsetX, ..., 1.color, etc.
9
+ */
10
+ export declare function convertShadow(value: unknown, context: ConverterContext): ConverterResult;
11
+ //# sourceMappingURL=shadow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../src/converters/shadow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAA6B,MAAM,aAAa,CAAC;AAiIhG;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA0CxF"}
@@ -1 +1 @@
1
- {"version":3,"file":"typography.d.ts","sourceRoot":"","sources":["../../src/converters/typography.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AA+C/E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAiI5F"}
1
+ {"version":3,"file":"typography.d.ts","sourceRoot":"","sources":["../../src/converters/typography.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AAO/E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAiI5F"}