@primitiv-ui/tokens 0.1.21 → 0.1.23

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
@@ -17,6 +17,7 @@ token transformer (e.g. CSS variables, Tailwind config) reads from.
17
17
  | `src/index.ts` | Public entry; re-exports the transform, the server, and types |
18
18
  | `src/*.test.ts` | Vitest unit tests, 100% coverage |
19
19
  | `src/{primitives,palette,intent,context,interaction}.json` | DTCG output written by the sync server. **Committed** — these files are the repo's source of truth for downstream transformers. |
20
+ | `src/motion.json` | **Code-only** DTCG (motion durations + easing curves + the semantic `motion.*` layer). Hand-authored, *not* a sync target — Figma has no `cubicBezier` variable type, so motion can't round-trip. Sits outside the five-file write-set, so a backup never touches it. |
20
21
 
21
22
  ## Backing up tokens (end-to-end)
22
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primitiv-ui/tokens",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "The DTCG-conformant design-token layer for the Primitiv ecosystem, plus helpers that transform Figma variable exports into DTCG JSON.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/context.json CHANGED
@@ -1463,73 +1463,73 @@
1463
1463
  "sm": {
1464
1464
  "radius": {
1465
1465
  "$type": "number",
1466
- "$value": 8
1466
+ "$value": "{radii.8}"
1467
1467
  },
1468
1468
  "padding-inline": {
1469
1469
  "$type": "number",
1470
- "$value": 16
1470
+ "$value": "{space.space-16}"
1471
1471
  },
1472
1472
  "padding-block": {
1473
1473
  "$type": "number",
1474
- "$value": 10
1474
+ "$value": "{space.space-10}"
1475
1475
  },
1476
1476
  "gap": {
1477
1477
  "$type": "number",
1478
- "$value": 10
1478
+ "$value": "{space.space-10}"
1479
1479
  }
1480
1480
  },
1481
1481
  "md": {
1482
1482
  "radius": {
1483
1483
  "$type": "number",
1484
- "$value": 10
1484
+ "$value": "{radii.10}"
1485
1485
  },
1486
1486
  "padding-inline": {
1487
1487
  "$type": "number",
1488
- "$value": 20
1488
+ "$value": "{space.space-20}"
1489
1489
  },
1490
1490
  "padding-block": {
1491
1491
  "$type": "number",
1492
- "$value": 12
1492
+ "$value": "{space.space-12}"
1493
1493
  },
1494
1494
  "gap": {
1495
1495
  "$type": "number",
1496
- "$value": 12
1496
+ "$value": "{space.space-12}"
1497
1497
  }
1498
1498
  },
1499
1499
  "lg": {
1500
1500
  "radius": {
1501
1501
  "$type": "number",
1502
- "$value": 12
1502
+ "$value": "{radii.12}"
1503
1503
  },
1504
1504
  "padding-inline": {
1505
1505
  "$type": "number",
1506
- "$value": 24
1506
+ "$value": "{space.space-24}"
1507
1507
  },
1508
1508
  "padding-block": {
1509
1509
  "$type": "number",
1510
- "$value": 14
1510
+ "$value": "{space.space-14}"
1511
1511
  },
1512
1512
  "gap": {
1513
1513
  "$type": "number",
1514
- "$value": 14
1514
+ "$value": "{space.space-14}"
1515
1515
  }
1516
1516
  },
1517
1517
  "xl": {
1518
1518
  "radius": {
1519
1519
  "$type": "number",
1520
- "$value": 16
1520
+ "$value": "{radii.16}"
1521
1521
  },
1522
1522
  "padding-inline": {
1523
1523
  "$type": "number",
1524
- "$value": 28
1524
+ "$value": "{space.space-28}"
1525
1525
  },
1526
1526
  "padding-block": {
1527
1527
  "$type": "number",
1528
- "$value": 16
1528
+ "$value": "{space.space-16}"
1529
1529
  },
1530
1530
  "gap": {
1531
1531
  "$type": "number",
1532
- "$value": 16
1532
+ "$value": "{space.space-16}"
1533
1533
  }
1534
1534
  },
1535
1535
  "border-width": {
@@ -3098,73 +3098,73 @@
3098
3098
  "sm": {
3099
3099
  "radius": {
3100
3100
  "$type": "number",
3101
- "$value": 6
3101
+ "$value": "{radii.6}"
3102
3102
  },
3103
3103
  "padding-inline": {
3104
3104
  "$type": "number",
3105
- "$value": 14
3105
+ "$value": "{space.space-14}"
3106
3106
  },
3107
3107
  "padding-block": {
3108
3108
  "$type": "number",
3109
- "$value": 8
3109
+ "$value": "{space.space-8}"
3110
3110
  },
3111
3111
  "gap": {
3112
3112
  "$type": "number",
3113
- "$value": 8
3113
+ "$value": "{space.space-8}"
3114
3114
  }
3115
3115
  },
3116
3116
  "md": {
3117
3117
  "radius": {
3118
3118
  "$type": "number",
3119
- "$value": 8
3119
+ "$value": "{radii.8}"
3120
3120
  },
3121
3121
  "padding-inline": {
3122
3122
  "$type": "number",
3123
- "$value": 16
3123
+ "$value": "{space.space-16}"
3124
3124
  },
3125
3125
  "padding-block": {
3126
3126
  "$type": "number",
3127
- "$value": 10
3127
+ "$value": "{space.space-10}"
3128
3128
  },
3129
3129
  "gap": {
3130
3130
  "$type": "number",
3131
- "$value": 10
3131
+ "$value": "{space.space-10}"
3132
3132
  }
3133
3133
  },
3134
3134
  "lg": {
3135
3135
  "radius": {
3136
3136
  "$type": "number",
3137
- "$value": 10
3137
+ "$value": "{radii.10}"
3138
3138
  },
3139
3139
  "padding-inline": {
3140
3140
  "$type": "number",
3141
- "$value": 20
3141
+ "$value": "{space.space-20}"
3142
3142
  },
3143
3143
  "padding-block": {
3144
3144
  "$type": "number",
3145
- "$value": 10
3145
+ "$value": "{space.space-10}"
3146
3146
  },
3147
3147
  "gap": {
3148
3148
  "$type": "number",
3149
- "$value": 12
3149
+ "$value": "{space.space-12}"
3150
3150
  }
3151
3151
  },
3152
3152
  "xl": {
3153
3153
  "radius": {
3154
3154
  "$type": "number",
3155
- "$value": 12
3155
+ "$value": "{radii.12}"
3156
3156
  },
3157
3157
  "padding-inline": {
3158
3158
  "$type": "number",
3159
- "$value": 24
3159
+ "$value": "{space.space-24}"
3160
3160
  },
3161
3161
  "padding-block": {
3162
3162
  "$type": "number",
3163
- "$value": 12
3163
+ "$value": "{space.space-12}"
3164
3164
  },
3165
3165
  "gap": {
3166
3166
  "$type": "number",
3167
- "$value": 12
3167
+ "$value": "{space.space-12}"
3168
3168
  }
3169
3169
  },
3170
3170
  "border-width": {
@@ -4733,73 +4733,73 @@
4733
4733
  "sm": {
4734
4734
  "radius": {
4735
4735
  "$type": "number",
4736
- "$value": 10
4736
+ "$value": "{radii.10}"
4737
4737
  },
4738
4738
  "padding-inline": {
4739
4739
  "$type": "number",
4740
- "$value": 20
4740
+ "$value": "{space.space-20}"
4741
4741
  },
4742
4742
  "padding-block": {
4743
4743
  "$type": "number",
4744
- "$value": 12
4744
+ "$value": "{space.space-12}"
4745
4745
  },
4746
4746
  "gap": {
4747
4747
  "$type": "number",
4748
- "$value": 12
4748
+ "$value": "{space.space-12}"
4749
4749
  }
4750
4750
  },
4751
4751
  "md": {
4752
4752
  "radius": {
4753
4753
  "$type": "number",
4754
- "$value": 12
4754
+ "$value": "{radii.12}"
4755
4755
  },
4756
4756
  "padding-inline": {
4757
4757
  "$type": "number",
4758
- "$value": 24
4758
+ "$value": "{space.space-24}"
4759
4759
  },
4760
4760
  "padding-block": {
4761
4761
  "$type": "number",
4762
- "$value": 14
4762
+ "$value": "{space.space-14}"
4763
4763
  },
4764
4764
  "gap": {
4765
4765
  "$type": "number",
4766
- "$value": 16
4766
+ "$value": "{space.space-16}"
4767
4767
  }
4768
4768
  },
4769
4769
  "lg": {
4770
4770
  "radius": {
4771
4771
  "$type": "number",
4772
- "$value": 16
4772
+ "$value": "{radii.16}"
4773
4773
  },
4774
4774
  "padding-inline": {
4775
4775
  "$type": "number",
4776
- "$value": 28
4776
+ "$value": "{space.space-28}"
4777
4777
  },
4778
4778
  "padding-block": {
4779
4779
  "$type": "number",
4780
- "$value": 16
4780
+ "$value": "{space.space-16}"
4781
4781
  },
4782
4782
  "gap": {
4783
4783
  "$type": "number",
4784
- "$value": 18
4784
+ "$value": "{space.space-16}"
4785
4785
  }
4786
4786
  },
4787
4787
  "xl": {
4788
4788
  "radius": {
4789
4789
  "$type": "number",
4790
- "$value": 20
4790
+ "$value": "{radii.20}"
4791
4791
  },
4792
4792
  "padding-inline": {
4793
4793
  "$type": "number",
4794
- "$value": 32
4794
+ "$value": "{space.space-32}"
4795
4795
  },
4796
4796
  "padding-block": {
4797
4797
  "$type": "number",
4798
- "$value": 20
4798
+ "$value": "{space.space-20}"
4799
4799
  },
4800
4800
  "gap": {
4801
4801
  "$type": "number",
4802
- "$value": 20
4802
+ "$value": "{space.space-20}"
4803
4803
  }
4804
4804
  },
4805
4805
  "border-width": {
@@ -6368,73 +6368,73 @@
6368
6368
  "sm": {
6369
6369
  "radius": {
6370
6370
  "$type": "number",
6371
- "$value": 4
6371
+ "$value": "{radii.4}"
6372
6372
  },
6373
6373
  "padding-inline": {
6374
6374
  "$type": "number",
6375
- "$value": 12
6375
+ "$value": "{space.space-12}"
6376
6376
  },
6377
6377
  "padding-block": {
6378
6378
  "$type": "number",
6379
- "$value": 6
6379
+ "$value": "{space.space-6}"
6380
6380
  },
6381
6381
  "gap": {
6382
6382
  "$type": "number",
6383
- "$value": 6
6383
+ "$value": "{space.space-6}"
6384
6384
  }
6385
6385
  },
6386
6386
  "md": {
6387
6387
  "radius": {
6388
6388
  "$type": "number",
6389
- "$value": 6
6389
+ "$value": "{radii.6}"
6390
6390
  },
6391
6391
  "padding-inline": {
6392
6392
  "$type": "number",
6393
- "$value": 14
6393
+ "$value": "{space.space-14}"
6394
6394
  },
6395
6395
  "padding-block": {
6396
6396
  "$type": "number",
6397
- "$value": 8
6397
+ "$value": "{space.space-8}"
6398
6398
  },
6399
6399
  "gap": {
6400
6400
  "$type": "number",
6401
- "$value": 8
6401
+ "$value": "{space.space-8}"
6402
6402
  }
6403
6403
  },
6404
6404
  "lg": {
6405
6405
  "radius": {
6406
6406
  "$type": "number",
6407
- "$value": 8
6407
+ "$value": "{radii.8}"
6408
6408
  },
6409
6409
  "padding-inline": {
6410
6410
  "$type": "number",
6411
- "$value": 16
6411
+ "$value": "{space.space-16}"
6412
6412
  },
6413
6413
  "padding-block": {
6414
6414
  "$type": "number",
6415
- "$value": 8
6415
+ "$value": "{space.space-8}"
6416
6416
  },
6417
6417
  "gap": {
6418
6418
  "$type": "number",
6419
- "$value": 8
6419
+ "$value": "{space.space-8}"
6420
6420
  }
6421
6421
  },
6422
6422
  "xl": {
6423
6423
  "radius": {
6424
6424
  "$type": "number",
6425
- "$value": 10
6425
+ "$value": "{radii.10}"
6426
6426
  },
6427
6427
  "padding-inline": {
6428
6428
  "$type": "number",
6429
- "$value": 20
6429
+ "$value": "{space.space-20}"
6430
6430
  },
6431
6431
  "padding-block": {
6432
6432
  "$type": "number",
6433
- "$value": 10
6433
+ "$value": "{space.space-10}"
6434
6434
  },
6435
6435
  "gap": {
6436
6436
  "$type": "number",
6437
- "$value": 10
6437
+ "$value": "{space.space-10}"
6438
6438
  }
6439
6439
  },
6440
6440
  "border-width": {
package/src/dtcg.test.ts CHANGED
@@ -479,6 +479,41 @@ describe('figmaVarsToDtcg', () => {
479
479
  })
480
480
  })
481
481
 
482
+ it('merges two modes that collapse to the same top-level key', () => {
483
+ // Mode names are lowercased before they become keys, so 'Light' and 'light'
484
+ // both target intent.light. The second merge must reuse the existing group
485
+ // rather than recreate it — exercising the "key already present" path.
486
+ const DUP_MODE_COLL: FigmaCollection = {
487
+ id: 'cdup',
488
+ name: 'Intent',
489
+ modes: [
490
+ { modeId: 'mL', name: 'Light' },
491
+ { modeId: 'ml', name: 'light' },
492
+ ],
493
+ defaultModeId: 'mL',
494
+ }
495
+ const result = figmaVarsToDtcg(
496
+ [DUP_MODE_COLL],
497
+ [
498
+ {
499
+ id: 'v1',
500
+ name: 'action/primary/default',
501
+ resolvedType: 'COLOR',
502
+ variableCollectionId: 'cdup',
503
+ valuesByMode: {
504
+ mL: { r: 0, g: 0, b: 0, a: 1 },
505
+ ml: { r: 1, g: 1, b: 1, a: 1 },
506
+ },
507
+ },
508
+ ],
509
+ )
510
+
511
+ // The later 'light' mode wins, proving its merge landed in the existing key.
512
+ expect(result.intent.light).toEqual({
513
+ action: { primary: { default: { $type: 'color', $value: '#ffffff' } } },
514
+ })
515
+ })
516
+
482
517
  it('routes Primitives / Foreground per-mode into foreground, resolving aliases', () => {
483
518
  const result = figmaVarsToDtcg(
484
519
  [FOREGROUND_COLL],
package/src/dtcg.ts CHANGED
@@ -128,12 +128,13 @@ export function figmaVarsToDtcg(
128
128
  const foreground = collections.find((c) => c.name === 'Primitives / Foreground')
129
129
  const intent = collections.find((c) => c.name === 'Intent')
130
130
  const context = collections.find((c) => c.name === 'Context')
131
- const singleMode = collections.filter(
132
- (c) => c.name === 'Primitives' || c.name === 'Interaction',
133
- )
131
+ const singleMode = collections.filter((c) => c.name in SINGLE_MODE_FILES)
134
132
 
135
133
  const routes = new Map<string, Routing>(
136
- singleMode.map((c) => [c.id, routeCollection(c.name)]),
134
+ singleMode.map((c) => [
135
+ c.id,
136
+ { file: SINGLE_MODE_FILES[c.name], prefix: [] },
137
+ ]),
137
138
  )
138
139
 
139
140
  // All variables are addressable by their natural name path — no collection prefix.
@@ -200,10 +201,14 @@ export function figmaVarsToDtcg(
200
201
  return files
201
202
  }
202
203
 
203
- function routeCollection(name: string): Routing {
204
- if (name === 'Primitives') return { file: 'primitives', prefix: [] }
205
- if (name === 'Interaction') return { file: 'interaction', prefix: [] }
206
- throw new Error(`Unrecognised collection name: "${name}"`)
204
+ /**
205
+ * Single-mode collection names mapped to their output file. The keys are the
206
+ * single source of truth for both the `singleMode` filter and the routing
207
+ * lookup, so the two can never drift apart.
208
+ */
209
+ const SINGLE_MODE_FILES: Record<string, keyof DtcgFiles> = {
210
+ Primitives: 'primitives',
211
+ Interaction: 'interaction',
207
212
  }
208
213
 
209
214
  function mergeIntoPrefix(
@@ -0,0 +1,149 @@
1
+ {
2
+ "shadow": {
3
+ "color": {
4
+ "strong": {
5
+ "$type": "color",
6
+ "$value": "#00000014"
7
+ },
8
+ "medium": {
9
+ "$type": "color",
10
+ "$value": "#0000000f"
11
+ },
12
+ "soft": {
13
+ "$type": "color",
14
+ "$value": "#0000000a"
15
+ }
16
+ },
17
+ "1": {
18
+ "$type": "shadow",
19
+ "$value": [
20
+ {
21
+ "color": "{shadow.color.strong}",
22
+ "offsetX": "{space.space-0}",
23
+ "offsetY": "{space.space-1}",
24
+ "blur": "{space.space-2}",
25
+ "spread": "{space.space-0}"
26
+ }
27
+ ]
28
+ },
29
+ "2": {
30
+ "$type": "shadow",
31
+ "$value": [
32
+ {
33
+ "color": "{shadow.color.strong}",
34
+ "offsetX": "{space.space-0}",
35
+ "offsetY": "{space.space-1}",
36
+ "blur": "{space.space-2}",
37
+ "spread": "{space.space-0}"
38
+ },
39
+ {
40
+ "color": "{shadow.color.soft}",
41
+ "offsetX": "{space.space-0}",
42
+ "offsetY": "{space.space-2}",
43
+ "blur": "{space.space-4}",
44
+ "spread": "{space.space-0}"
45
+ }
46
+ ]
47
+ },
48
+ "3": {
49
+ "$type": "shadow",
50
+ "$value": [
51
+ {
52
+ "color": "{shadow.color.strong}",
53
+ "offsetX": "{space.space-0}",
54
+ "offsetY": "{space.space-2}",
55
+ "blur": "{space.space-4}",
56
+ "spread": "{space.space-0}"
57
+ },
58
+ {
59
+ "color": "{shadow.color.medium}",
60
+ "offsetX": "{space.space-0}",
61
+ "offsetY": "{space.space-4}",
62
+ "blur": "{space.space-8}",
63
+ "spread": "{space.space-0}"
64
+ },
65
+ {
66
+ "color": "{shadow.color.soft}",
67
+ "offsetX": "{space.space-0}",
68
+ "offsetY": "{space.space-8}",
69
+ "blur": "{space.space-16}",
70
+ "spread": "{space.space-0}"
71
+ }
72
+ ]
73
+ },
74
+ "4": {
75
+ "$type": "shadow",
76
+ "$value": [
77
+ {
78
+ "color": "{shadow.color.strong}",
79
+ "offsetX": "{space.space-0}",
80
+ "offsetY": "{space.space-4}",
81
+ "blur": "{space.space-8}",
82
+ "spread": "{space.space-0}"
83
+ },
84
+ {
85
+ "color": "{shadow.color.medium}",
86
+ "offsetX": "{space.space-0}",
87
+ "offsetY": "{space.space-8}",
88
+ "blur": "{space.space-16}",
89
+ "spread": "{space.space-0}"
90
+ },
91
+ {
92
+ "color": "{shadow.color.soft}",
93
+ "offsetX": "{space.space-0}",
94
+ "offsetY": "{space.space-16}",
95
+ "blur": "{space.space-24}",
96
+ "spread": "{space.space-0}"
97
+ }
98
+ ]
99
+ },
100
+ "5": {
101
+ "$type": "shadow",
102
+ "$value": [
103
+ {
104
+ "color": "{shadow.color.strong}",
105
+ "offsetX": "{space.space-0}",
106
+ "offsetY": "{space.space-8}",
107
+ "blur": "{space.space-16}",
108
+ "spread": "{space.space-0}"
109
+ },
110
+ {
111
+ "color": "{shadow.color.medium}",
112
+ "offsetX": "{space.space-0}",
113
+ "offsetY": "{space.space-16}",
114
+ "blur": "{space.space-32}",
115
+ "spread": "{space.space-0}"
116
+ },
117
+ {
118
+ "color": "{shadow.color.soft}",
119
+ "offsetX": "{space.space-0}",
120
+ "offsetY": "{space.space-24}",
121
+ "blur": "{space.space-48}",
122
+ "spread": "{space.space-0}"
123
+ }
124
+ ]
125
+ }
126
+ },
127
+ "elevation": {
128
+ "flat": {
129
+ "$type": "shadow",
130
+ "$value": []
131
+ },
132
+ "raised": {
133
+ "$type": "shadow",
134
+ "$value": "{shadow.2}"
135
+ },
136
+ "overlay": {
137
+ "$type": "shadow",
138
+ "$value": "{shadow.3}"
139
+ },
140
+ "floating": {
141
+ "$type": "shadow",
142
+ "$value": "{shadow.4}"
143
+ },
144
+ "modal": {
145
+ "$type": "shadow",
146
+ "$value": "{shadow.5}"
147
+ }
148
+ }
149
+ }
package/src/intent.json CHANGED
@@ -186,6 +186,10 @@
186
186
  "$value": "{color.neutral.800}"
187
187
  }
188
188
  },
189
+ "scrim": {
190
+ "$type": "color",
191
+ "$value": "#00000080"
192
+ },
189
193
  "content": {
190
194
  "primary": {
191
195
  "$type": "color",
@@ -462,6 +466,10 @@
462
466
  "$value": "{color.neutral.100}"
463
467
  }
464
468
  },
469
+ "scrim": {
470
+ "$type": "color",
471
+ "$value": "#00000080"
472
+ },
465
473
  "content": {
466
474
  "primary": {
467
475
  "$type": "color",
@@ -0,0 +1,96 @@
1
+ {
2
+ "duration": {
3
+ "0": {
4
+ "$type": "number",
5
+ "$value": 0
6
+ },
7
+ "75": {
8
+ "$type": "number",
9
+ "$value": 75
10
+ },
11
+ "100": {
12
+ "$type": "number",
13
+ "$value": 100
14
+ },
15
+ "150": {
16
+ "$type": "number",
17
+ "$value": 150
18
+ },
19
+ "200": {
20
+ "$type": "number",
21
+ "$value": 200
22
+ },
23
+ "300": {
24
+ "$type": "number",
25
+ "$value": 300
26
+ },
27
+ "500": {
28
+ "$type": "number",
29
+ "$value": 500
30
+ },
31
+ "700": {
32
+ "$type": "number",
33
+ "$value": 700
34
+ },
35
+ "1000": {
36
+ "$type": "number",
37
+ "$value": 1000
38
+ }
39
+ },
40
+ "easing": {
41
+ "linear": {
42
+ "$type": "cubicBezier",
43
+ "$value": [0, 0, 1, 1]
44
+ },
45
+ "in": {
46
+ "$type": "cubicBezier",
47
+ "$value": [0.4, 0, 1, 1]
48
+ },
49
+ "out": {
50
+ "$type": "cubicBezier",
51
+ "$value": [0, 0, 0.2, 1]
52
+ },
53
+ "in-out": {
54
+ "$type": "cubicBezier",
55
+ "$value": [0.4, 0, 0.2, 1]
56
+ }
57
+ },
58
+ "motion": {
59
+ "duration": {
60
+ "feedback": {
61
+ "$type": "number",
62
+ "$value": "{duration.75}"
63
+ },
64
+ "control": {
65
+ "$type": "number",
66
+ "$value": "{duration.150}"
67
+ },
68
+ "expand": {
69
+ "$type": "number",
70
+ "$value": "{duration.200}"
71
+ },
72
+ "overlay": {
73
+ "$type": "number",
74
+ "$value": "{duration.300}"
75
+ }
76
+ },
77
+ "easing": {
78
+ "default": {
79
+ "$type": "cubicBezier",
80
+ "$value": "{easing.in-out}"
81
+ },
82
+ "enter": {
83
+ "$type": "cubicBezier",
84
+ "$value": "{easing.out}"
85
+ },
86
+ "exit": {
87
+ "$type": "cubicBezier",
88
+ "$value": "{easing.in}"
89
+ },
90
+ "linear": {
91
+ "$type": "cubicBezier",
92
+ "$value": "{easing.linear}"
93
+ }
94
+ }
95
+ }
96
+ }