@primitiv-ui/tokens 0.1.21 → 0.1.22
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 +1 -0
- package/package.json +1 -1
- package/src/dtcg.test.ts +35 -0
- package/src/dtcg.ts +13 -8
- package/src/elevation.json +149 -0
- package/src/motion.json +96 -0
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.
|
|
3
|
+
"version": "0.1.22",
|
|
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/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) => [
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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/motion.json
ADDED
|
@@ -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
|
+
}
|