terrazzo-plugin-figma-json 0.1.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/LICENSE +21 -0
- package/README.md +253 -0
- package/dist/build.d.ts +18 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/constants.d.ts +30 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/converters/color.d.ts +24 -0
- package/dist/converters/color.d.ts.map +1 -0
- package/dist/converters/dimension.d.ts +17 -0
- package/dist/converters/dimension.d.ts.map +1 -0
- package/dist/converters/duration.d.ts +17 -0
- package/dist/converters/duration.d.ts.map +1 -0
- package/dist/converters/font-family.d.ts +17 -0
- package/dist/converters/font-family.d.ts.map +1 -0
- package/dist/converters/font-weight.d.ts +17 -0
- package/dist/converters/font-weight.d.ts.map +1 -0
- package/dist/converters/index.d.ts +25 -0
- package/dist/converters/index.d.ts.map +1 -0
- package/dist/converters/line-height.d.ts +55 -0
- package/dist/converters/line-height.d.ts.map +1 -0
- package/dist/converters/number.d.ts +17 -0
- package/dist/converters/number.d.ts.map +1 -0
- package/dist/converters/typography.d.ts +19 -0
- package/dist/converters/typography.d.ts.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1454 -0
- package/dist/index.js.map +1 -0
- package/dist/transform.d.ts +12 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/types.d.ts +182 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +64 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 dgtlntv
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# terrazzo-plugin-figma-json
|
|
2
|
+
|
|
3
|
+
A [Terrazzo](https://terrazzo.app) plugin that converts W3C DTCG design tokens into Figma-compatible JSON format for import into Figma Variables.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install terrazzo-plugin-figma-json
|
|
9
|
+
# or
|
|
10
|
+
pnpm add terrazzo-plugin-figma-json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Basic Usage
|
|
14
|
+
|
|
15
|
+
Add the plugin to your `terrazzo.config.ts`:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { defineConfig } from "@terrazzo/cli";
|
|
19
|
+
import figmaJson from "terrazzo-plugin-figma-json";
|
|
20
|
+
|
|
21
|
+
export default defineConfig({
|
|
22
|
+
outDir: "./tokens/",
|
|
23
|
+
plugins: [
|
|
24
|
+
figmaJson({
|
|
25
|
+
filename: "tokens.figma.json",
|
|
26
|
+
}),
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Run the Terrazzo build:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx tz build
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Configuration Options
|
|
38
|
+
|
|
39
|
+
| Option | Type | Default | Description |
|
|
40
|
+
|--------|------|---------|-------------|
|
|
41
|
+
| `filename` | `string` | `"tokens.figma.json"` | Output filename (used as suffix when using resolver) |
|
|
42
|
+
| `exclude` | `string[]` | `[]` | Glob patterns to exclude tokens from output |
|
|
43
|
+
| `transform` | `(token) => unknown` | `undefined` | Custom transform function to override token values |
|
|
44
|
+
| `tokenName` | `(token) => string` | `undefined` | Custom function to control token names in output |
|
|
45
|
+
| `skipBuild` | `boolean` | `false` | Skip generating the output file |
|
|
46
|
+
| `remBasePx` | `number` | `16` | Base pixel value for rem to px conversion |
|
|
47
|
+
| `warnOnUnsupported` | `boolean` | `true` | Log warnings for unsupported token types |
|
|
48
|
+
| `preserveReferences` | `boolean` | `true` | Preserve token aliases in output (see [Alias Handling](#alias-handling)) |
|
|
49
|
+
|
|
50
|
+
## Output Structure
|
|
51
|
+
|
|
52
|
+
When using a resolver file (recommended), the plugin automatically splits output by resolver sets and modifier contexts:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
dist/
|
|
56
|
+
├── primitive.figma.json # From "primitive" set
|
|
57
|
+
├── semantic.figma.json # From "semantic" set
|
|
58
|
+
├── colorScheme-light.figma.json
|
|
59
|
+
├── colorScheme-dark.figma.json
|
|
60
|
+
└── breakpoint-small.figma.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Without a resolver, all tokens are output to a single file.
|
|
64
|
+
|
|
65
|
+
## Supported Token Types
|
|
66
|
+
|
|
67
|
+
| DTCG Type | Figma Variable Type | Transformation |
|
|
68
|
+
|-----------|---------------------|----------------|
|
|
69
|
+
| `color` | Color | sRGB and HSL pass through; other color spaces converted to sRGB |
|
|
70
|
+
| `dimension` | Number | `px` values pass through; `rem` converted to `px` |
|
|
71
|
+
| `duration` | Number | `s` values pass through; `ms` converted to `s` |
|
|
72
|
+
| `fontFamily` | String | Strings pass through; arrays truncated to first element |
|
|
73
|
+
| `fontWeight` | Number or String | Values pass through with validation |
|
|
74
|
+
| `number` | Number or Boolean | Numbers pass through; use `com.figma.type: "boolean"` for booleans |
|
|
75
|
+
| `typography` | Split tokens | Split into fontFamily, fontSize, fontWeight, lineHeight, letterSpacing |
|
|
76
|
+
|
|
77
|
+
### Typography Token Splitting
|
|
78
|
+
|
|
79
|
+
Figma doesn't support composite typography tokens, so they're automatically split into individual sub-tokens:
|
|
80
|
+
|
|
81
|
+
**Input:**
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"typography": {
|
|
85
|
+
"$type": "typography",
|
|
86
|
+
"heading": {
|
|
87
|
+
"$value": {
|
|
88
|
+
"fontFamily": "Inter",
|
|
89
|
+
"fontSize": { "value": 24, "unit": "px" },
|
|
90
|
+
"fontWeight": 700,
|
|
91
|
+
"lineHeight": 1.2,
|
|
92
|
+
"letterSpacing": { "value": 0, "unit": "px" }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Output:**
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"typography": {
|
|
103
|
+
"heading": {
|
|
104
|
+
"fontFamily": { "$type": "fontFamily", "$value": "Inter" },
|
|
105
|
+
"fontSize": { "$type": "dimension", "$value": { "value": 24, "unit": "px" } },
|
|
106
|
+
"fontWeight": { "$type": "fontWeight", "$value": 700 },
|
|
107
|
+
"lineHeight": { "$type": "dimension", "$value": { "value": 29, "unit": "px" } },
|
|
108
|
+
"letterSpacing": { "$type": "dimension", "$value": { "value": 0, "unit": "px" } }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Note: `lineHeight` is converted from a unitless multiplier to absolute px (see [Figma Limitations](#figma-limitations)).
|
|
115
|
+
|
|
116
|
+
## Unsupported Token Types
|
|
117
|
+
|
|
118
|
+
The following DTCG token types are **not supported** by Figma and will be skipped:
|
|
119
|
+
|
|
120
|
+
- `shadow`, `border`, `gradient`, `transition`, `strokeStyle`, `cubicBezier`
|
|
121
|
+
|
|
122
|
+
## Alias Handling
|
|
123
|
+
|
|
124
|
+
When `preserveReferences: true` (default):
|
|
125
|
+
|
|
126
|
+
- **Same-file references**: Use curly brace syntax in `$value` (e.g., `"{color.primary}"`)
|
|
127
|
+
- **Cross-file references**: Use resolved `$value` + `com.figma.aliasData` extension
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"color": {
|
|
132
|
+
"brand": {
|
|
133
|
+
"$type": "color",
|
|
134
|
+
"$value": "{color.palette.blue.500}"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
For cross-collection aliases (referencing tokens in a different output file):
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"color": {
|
|
145
|
+
"text": {
|
|
146
|
+
"$type": "color",
|
|
147
|
+
"$value": { "colorSpace": "srgb", "components": [0.2, 0.4, 0.8], "alpha": 1 },
|
|
148
|
+
"$extensions": {
|
|
149
|
+
"com.figma.aliasData": {
|
|
150
|
+
"targetVariableSetName": "primitive",
|
|
151
|
+
"targetVariableName": "color/palette/blue/500"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Color Space Conversion
|
|
160
|
+
|
|
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.
|
|
168
|
+
|
|
169
|
+
## Boolean Tokens
|
|
170
|
+
|
|
171
|
+
Use the `number` type with the `com.figma.type` extension:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"feature-flags": {
|
|
176
|
+
"$type": "number",
|
|
177
|
+
"dark-mode-enabled": {
|
|
178
|
+
"$value": 1,
|
|
179
|
+
"$extensions": { "com.figma.type": "boolean" }
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
- `0` → `false`
|
|
186
|
+
- Non-zero → `true`
|
|
187
|
+
|
|
188
|
+
## Examples
|
|
189
|
+
|
|
190
|
+
### Excluding Tokens
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
figmaJson({
|
|
194
|
+
exclude: [
|
|
195
|
+
"internal.*", // Exclude "internal" group
|
|
196
|
+
"*.deprecated.*", // Exclude "deprecated" tokens
|
|
197
|
+
],
|
|
198
|
+
})
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Custom Token Names
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
figmaJson({
|
|
205
|
+
tokenName: (token) => token.id.replace("color.", "brand.color."),
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Custom Transform
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
figmaJson({
|
|
213
|
+
transform: (token) => {
|
|
214
|
+
if (token.id === "color.special") {
|
|
215
|
+
return { colorSpace: "srgb", components: [1, 0, 0], alpha: 1 };
|
|
216
|
+
}
|
|
217
|
+
return undefined; // Use default transformation
|
|
218
|
+
},
|
|
219
|
+
})
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Figma Limitations
|
|
223
|
+
|
|
224
|
+
Figma Variables have constraints that differ from the W3C DTCG specification. This plugin handles these automatically, but be aware of the following:
|
|
225
|
+
|
|
226
|
+
### lineHeight Conversion
|
|
227
|
+
|
|
228
|
+
W3C DTCG specifies `lineHeight` as a unitless number (multiplier relative to fontSize, e.g., `1.5`). Figma requires `lineHeight` to be a dimension with px units.
|
|
229
|
+
|
|
230
|
+
The plugin converts by multiplying: `lineHeight × fontSize`. For example, `lineHeight: 1.5` with `fontSize: 16px` becomes `24px`.
|
|
231
|
+
|
|
232
|
+
**Trade-off**: Any reference to a primitive number token for lineHeight is lost, since the computed px value cannot maintain an alias to the original multiplier.
|
|
233
|
+
|
|
234
|
+
### $root Token Naming
|
|
235
|
+
|
|
236
|
+
The DTCG spec uses `$root` for default mode values. Figma doesn't allow `$` in variable names, so the plugin converts `$root` to `root` in the output.
|
|
237
|
+
|
|
238
|
+
### Cross-File Alias Resolution
|
|
239
|
+
|
|
240
|
+
When a token uses a JSON pointer (`$ref`) that points to another token using curly-brace alias syntax, the intermediate reference is lost. For example:
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"a": { "$value": { "x": "{b.x}" } },
|
|
245
|
+
"c": { "$ref": "#/a/$value/x" }
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Token `c` will resolve to `b.x`, not `a.x`. This is a limitation of how the Terrazzo parser resolves references.
|
|
250
|
+
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
MIT
|
package/dist/build.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BuildHookOptions, Resolver } from '@terrazzo/parser';
|
|
2
|
+
import type { FigmaJsonPluginOptions } from './types.js';
|
|
3
|
+
export interface BuildOptions {
|
|
4
|
+
exclude: FigmaJsonPluginOptions['exclude'];
|
|
5
|
+
tokenName?: FigmaJsonPluginOptions['tokenName'];
|
|
6
|
+
getTransforms: BuildHookOptions['getTransforms'];
|
|
7
|
+
preserveReferences?: FigmaJsonPluginOptions['preserveReferences'];
|
|
8
|
+
resolver?: Resolver;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Build the Figma-compatible JSON output from transformed tokens.
|
|
12
|
+
* Requires a resolver file - legacy mode is not supported.
|
|
13
|
+
* Always returns output split by resolver structure (sets and modifier contexts).
|
|
14
|
+
*
|
|
15
|
+
* @returns Map of output name to JSON string (e.g., "primitive" -> "{...}")
|
|
16
|
+
*/
|
|
17
|
+
export default function buildFigmaJson({ getTransforms, exclude, tokenName, preserveReferences, resolver, }: BuildOptions): Map<string, string>;
|
|
18
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const PLUGIN_NAME = "terrazzo-plugin-figma-json";
|
|
2
|
+
export declare const FORMAT_ID = "figma-json";
|
|
3
|
+
/**
|
|
4
|
+
* Internal metadata property keys used for token processing.
|
|
5
|
+
* These are added during transform and removed during build.
|
|
6
|
+
*/
|
|
7
|
+
export declare const INTERNAL_KEYS: {
|
|
8
|
+
/** Target token ID for alias references */
|
|
9
|
+
readonly ALIAS_OF: "_aliasOf";
|
|
10
|
+
/** Parent token ID for split sub-tokens (e.g., typography) */
|
|
11
|
+
readonly SPLIT_FROM: "_splitFrom";
|
|
12
|
+
/** Token ID for split sub-tokens */
|
|
13
|
+
readonly TOKEN_ID: "_tokenId";
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Token types supported by Figma.
|
|
17
|
+
*/
|
|
18
|
+
export declare const SUPPORTED_TYPES: readonly ["color", "dimension", "duration", "fontFamily", "fontWeight", "number", "typography"];
|
|
19
|
+
export type SupportedType = (typeof SUPPORTED_TYPES)[number];
|
|
20
|
+
/**
|
|
21
|
+
* Token types that are not supported by Figma and will be dropped with a warning.
|
|
22
|
+
*/
|
|
23
|
+
export declare const UNSUPPORTED_TYPES: readonly ["shadow", "border", "gradient", "transition", "strokeStyle", "cubicBezier"];
|
|
24
|
+
export type UnsupportedType = (typeof UNSUPPORTED_TYPES)[number];
|
|
25
|
+
/**
|
|
26
|
+
* Color spaces that Figma natively supports.
|
|
27
|
+
*/
|
|
28
|
+
export declare const FIGMA_COLOR_SPACES: readonly ["srgb", "hsl"];
|
|
29
|
+
export type FigmaColorSpace = (typeof FIGMA_COLOR_SPACES)[number];
|
|
30
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG color value to Figma-compatible format.
|
|
4
|
+
* Figma only supports sRGB and HSL color spaces.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // sRGB colors pass through unchanged
|
|
8
|
+
* convertColor({
|
|
9
|
+
* colorSpace: "srgb",
|
|
10
|
+
* components: [0.5, 0.5, 0.5],
|
|
11
|
+
* alpha: 1
|
|
12
|
+
* }, context);
|
|
13
|
+
* // => { value: { colorSpace: "srgb", components: [0.5, 0.5, 0.5], alpha: 1 } }
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // OKLCH colors are converted to sRGB
|
|
17
|
+
* convertColor({
|
|
18
|
+
* colorSpace: "oklch",
|
|
19
|
+
* components: [0.7, 0.15, 150]
|
|
20
|
+
* }, context);
|
|
21
|
+
* // => { value: { colorSpace: "srgb", components: [...], alpha: 1 } }
|
|
22
|
+
*/
|
|
23
|
+
export declare function convertColor(value: unknown, context: ConverterContext): ConverterResult;
|
|
24
|
+
//# sourceMappingURL=color.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/converters/color.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAkB,MAAM,aAAa,CAAC;AAoDrF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAoFvF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG dimension value to Figma-compatible format.
|
|
4
|
+
* Figma only supports px units.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // px values pass through unchanged
|
|
8
|
+
* convertDimension({ value: 16, unit: "px" }, context);
|
|
9
|
+
* // => { value: { value: 16, unit: "px" } }
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // rem values are converted to px (default base: 16px)
|
|
13
|
+
* convertDimension({ value: 1.5, unit: "rem" }, context);
|
|
14
|
+
* // => { value: { value: 24, unit: "px" } }
|
|
15
|
+
*/
|
|
16
|
+
export declare function convertDimension(value: unknown, context: ConverterContext): ConverterResult;
|
|
17
|
+
//# sourceMappingURL=dimension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dimension.d.ts","sourceRoot":"","sources":["../../src/converters/dimension.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGrE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAoD3F"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG duration value to Figma-compatible format.
|
|
4
|
+
* Figma only supports seconds (s) unit.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // s values pass through unchanged
|
|
8
|
+
* convertDuration({ value: 0.5, unit: "s" }, context);
|
|
9
|
+
* // => { value: { value: 0.5, unit: "s" } }
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // ms values are converted to s
|
|
13
|
+
* convertDuration({ value: 500, unit: "ms" }, context);
|
|
14
|
+
* // => { value: { value: 0.5, unit: "s" } }
|
|
15
|
+
*/
|
|
16
|
+
export declare function convertDuration(value: unknown, context: ConverterContext): ConverterResult;
|
|
17
|
+
//# sourceMappingURL=duration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duration.d.ts","sourceRoot":"","sources":["../../src/converters/duration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGrE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAoD1F"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG fontFamily value to Figma-compatible format.
|
|
4
|
+
* Figma requires a single string, not an array.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // String values pass through unchanged
|
|
8
|
+
* convertFontFamily("Inter", context);
|
|
9
|
+
* // => { value: "Inter" }
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Arrays are truncated to the first element
|
|
13
|
+
* convertFontFamily(["Inter", "Helvetica", "sans-serif"], context);
|
|
14
|
+
* // => { value: "Inter" } (with warning about dropped fallbacks)
|
|
15
|
+
*/
|
|
16
|
+
export declare function convertFontFamily(value: unknown, context: ConverterContext): ConverterResult;
|
|
17
|
+
//# sourceMappingURL=font-family.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-family.d.ts","sourceRoot":"","sources":["../../src/converters/font-family.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAErE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAqC5F"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG fontWeight value to Figma-compatible format.
|
|
4
|
+
* Output type matches input type (string stays string, number stays number).
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // Number values pass through with validation (1-1000)
|
|
8
|
+
* convertFontWeight(400, context);
|
|
9
|
+
* // => { value: 400 }
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // String aliases pass through if valid
|
|
13
|
+
* convertFontWeight("bold", context);
|
|
14
|
+
* // => { value: "bold" }
|
|
15
|
+
*/
|
|
16
|
+
export declare function convertFontWeight(value: unknown, context: ConverterContext): ConverterResult;
|
|
17
|
+
//# sourceMappingURL=font-weight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-weight.d.ts","sourceRoot":"","sources":["../../src/converters/font-weight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA0BrE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAqC5F"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { TokenNormalized } from '@terrazzo/parser';
|
|
2
|
+
import { type SupportedType } from '../constants.js';
|
|
3
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Converter function signature.
|
|
6
|
+
*/
|
|
7
|
+
export type Converter = (value: unknown, context: ConverterContext) => ConverterResult;
|
|
8
|
+
/**
|
|
9
|
+
* Check if a token type is supported by Figma.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isSupportedType(type: string): type is SupportedType;
|
|
12
|
+
/**
|
|
13
|
+
* Check if a value is an alias reference (curly brace syntax).
|
|
14
|
+
*/
|
|
15
|
+
export declare function isAlias(value: unknown): value is string;
|
|
16
|
+
/**
|
|
17
|
+
* Convert a token value to Figma-compatible format.
|
|
18
|
+
*
|
|
19
|
+
* @param token - The normalized token
|
|
20
|
+
* @param value - The token value to convert
|
|
21
|
+
* @param context - Converter context with logger and options
|
|
22
|
+
* @returns Converted value or skip indicator
|
|
23
|
+
*/
|
|
24
|
+
export declare function convertToken(token: TokenNormalized, value: unknown, context: ConverterContext): ConverterResult;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult, DTCGDimensionValue } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Context for lineHeight conversion, extending the base converter context
|
|
4
|
+
* with the fontSize value needed for calculating absolute lineHeight.
|
|
5
|
+
*/
|
|
6
|
+
export interface LineHeightConverterContext extends ConverterContext {
|
|
7
|
+
/**
|
|
8
|
+
* The resolved fontSize dimension value from the typography token.
|
|
9
|
+
* Required to calculate absolute lineHeight from the multiplier.
|
|
10
|
+
* Should already be converted to px units.
|
|
11
|
+
*/
|
|
12
|
+
fontSize?: DTCGDimensionValue;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Convert a W3C DTCG lineHeight value to Figma-compatible format.
|
|
16
|
+
*
|
|
17
|
+
* ## W3C DTCG vs Figma Incompatibility
|
|
18
|
+
*
|
|
19
|
+
* The W3C DTCG specification defines lineHeight as a **number** type -
|
|
20
|
+
* a unitless multiplier relative to fontSize (e.g., `1.5` means 1.5× the
|
|
21
|
+
* font size). This matches CSS behavior where `line-height: 1.5` is unitless.
|
|
22
|
+
*
|
|
23
|
+
* However, Figma Variables require lineHeight to be a **dimension** type
|
|
24
|
+
* with explicit px units. There is no way to represent a unitless multiplier
|
|
25
|
+
* in Figma's variable system.
|
|
26
|
+
*
|
|
27
|
+
* ## Conversion Strategy
|
|
28
|
+
*
|
|
29
|
+
* This converter calculates the absolute lineHeight by multiplying the
|
|
30
|
+
* unitless multiplier with the fontSize:
|
|
31
|
+
*
|
|
32
|
+
* `absoluteLineHeight = lineHeight × fontSize`
|
|
33
|
+
*
|
|
34
|
+
* For example: `lineHeight: 1.5` with `fontSize: 16px` → `24px`
|
|
35
|
+
*
|
|
36
|
+
* ## Trade-off: Loss of Token Reference
|
|
37
|
+
*
|
|
38
|
+
* When converting a multiplier to an absolute dimension, any reference to
|
|
39
|
+
* a primitive number token is lost. This is unavoidable because:
|
|
40
|
+
*
|
|
41
|
+
* 1. Figma does not support unitless multipliers for lineHeight
|
|
42
|
+
* 2. We must compute a concrete px value at build time
|
|
43
|
+
* 3. The computed value cannot maintain an alias to the original number token
|
|
44
|
+
*
|
|
45
|
+
* This approach is the most token-setup-agnostic solution, as it works
|
|
46
|
+
* regardless of how the source tokens are structured.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // Input: W3C DTCG typography with number lineHeight
|
|
50
|
+
* // lineHeight: 1.5, fontSize: { value: 16, unit: "px" }
|
|
51
|
+
* convertLineHeight(1.5, { ...context, fontSize: { value: 16, unit: "px" } });
|
|
52
|
+
* // Output: { value: { value: 24, unit: "px" } }
|
|
53
|
+
*/
|
|
54
|
+
export declare function convertLineHeight(value: unknown, context: LineHeightConverterContext): ConverterResult;
|
|
55
|
+
//# sourceMappingURL=line-height.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line-height.d.ts","sourceRoot":"","sources":["../../src/converters/line-height.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEzF;;;GAGG;AACH,MAAM,WAAW,0BAA2B,SAAQ,gBAAgB;IAClE;;;;OAIG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,0BAA0B,GAAG,eAAe,CAoDtG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG number value to Figma-compatible format.
|
|
4
|
+
* Can output as Boolean if token has com.figma.type extension set to "boolean".
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // Regular number token
|
|
8
|
+
* convertNumber(1.5, context) // => { value: 1.5 }
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // Boolean extension: 0 becomes false, non-zero becomes true
|
|
12
|
+
* // Token with $extensions: { "com.figma": { "type": "boolean" } }
|
|
13
|
+
* convertNumber(0, contextWithBooleanExt) // => { value: false }
|
|
14
|
+
* convertNumber(1, contextWithBooleanExt) // => { value: true }
|
|
15
|
+
*/
|
|
16
|
+
export declare function convertNumber(value: unknown, context: ConverterContext): ConverterResult;
|
|
17
|
+
//# sourceMappingURL=number.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number.d.ts","sourceRoot":"","sources":["../../src/converters/number.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAErE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA6BxF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG typography value to Figma-compatible format.
|
|
4
|
+
* Typography tokens are split into individual sub-tokens since Figma
|
|
5
|
+
* doesn't support the composite typography type.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Input typography token
|
|
9
|
+
* convertTypography({
|
|
10
|
+
* fontFamily: "Inter",
|
|
11
|
+
* fontSize: { value: 16, unit: "px" },
|
|
12
|
+
* fontWeight: 400,
|
|
13
|
+
* lineHeight: 1.5,
|
|
14
|
+
* letterSpacing: { value: 0, unit: "px" }
|
|
15
|
+
* }, context);
|
|
16
|
+
* // => { value: undefined, split: true, subTokens: [...] }
|
|
17
|
+
*/
|
|
18
|
+
export declare function convertTypography(value: unknown, context: ConverterContext): ConverterResult;
|
|
19
|
+
//# sourceMappingURL=typography.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Plugin } from '@terrazzo/parser';
|
|
2
|
+
import type { FigmaJsonPluginOptions } from './types.js';
|
|
3
|
+
export * from './build.js';
|
|
4
|
+
export * from './constants.js';
|
|
5
|
+
export * from './transform.js';
|
|
6
|
+
export * from './types.js';
|
|
7
|
+
export * from './utils.js';
|
|
8
|
+
/**
|
|
9
|
+
* Terrazzo plugin to convert DTCG design tokens to Figma-compatible JSON format.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Basic usage
|
|
13
|
+
* import { defineConfig } from "@terrazzo/cli";
|
|
14
|
+
* import figmaJson from "terrazzo-plugin-figma-json";
|
|
15
|
+
*
|
|
16
|
+
* export default defineConfig({
|
|
17
|
+
* plugins: [
|
|
18
|
+
* figmaJson({ filename: "tokens.figma.json" }),
|
|
19
|
+
* ],
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // With all options
|
|
24
|
+
* figmaJson({
|
|
25
|
+
* filename: "design-tokens.figma.json",
|
|
26
|
+
* exclude: ["internal.*", "deprecated.*"],
|
|
27
|
+
* remBasePx: 16,
|
|
28
|
+
* warnOnUnsupported: true,
|
|
29
|
+
* preserveReferences: true,
|
|
30
|
+
* tokenName: (token) => token.id.replace("color.", "brand."),
|
|
31
|
+
* transform: (token) => {
|
|
32
|
+
* if (token.id === "special.token") return { custom: true };
|
|
33
|
+
* return undefined; // Use default transformation
|
|
34
|
+
* },
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
*/
|
|
38
|
+
export default function figmaJsonPlugin(options?: FigmaJsonPluginOptions): Plugin;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI/C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CA4ChF"}
|