@omkarux/vela 0.4.0 → 0.6.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/CHANGELOG.md CHANGED
@@ -3,6 +3,36 @@
3
3
  All notable changes to this project are documented here.
4
4
  This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
5
 
6
+ ## [0.6.0] — 2026-09-11
7
+
8
+ ### Added
9
+ - **Spec → Figma description sync.** `npm run guidelines:figma` compiles each component spec's
10
+ intent, code call, Figma-property→prop mapping, hard rules and source paths into that component
11
+ set's Figma description, so a spec edit lands in Inspect the same way a token edit does. Same
12
+ generated-script route as tokens; idempotent by page + name. What it deliberately does not do:
13
+ add or change variants — a spec that adds a prop is design work in Figma and code both.
14
+ - A test asserts every spec keeps the sections the sync compiles (Props with a `tsx` example,
15
+ Hard constraints, Figma mapping naming its page, Anti-patterns), so a spec that drifts in shape
16
+ fails the build rather than silently producing a thinner description.
17
+
18
+ ## [0.5.0] — 2026-09-10
19
+
20
+ ### Added
21
+ - **A single token source.** `tokens/vela.tokens.json` (W3C Design Tokens 2025.10) now holds every
22
+ value once. `src/styles/tokens.*.css` are generated from it and were proven byte-identical to the
23
+ hand-written files before the switch. `npm run tokens:check` runs in the gate and fails if the
24
+ CSS is edited directly.
25
+ - **Figma sync.** `npm run tokens:figma` generates a Plugin API script that creates-or-updates every
26
+ variable in the library by name — values per mode, aliases, scopes, descriptions and the
27
+ `var(--vela-*)` code syntax. Idempotent: 0 created / 223 updated on its first run against the live
28
+ file. This closes the gap where the Figma library was a one-time export that would drift from
29
+ the code. The REST route was not an option: writing variables needs an Enterprise plan.
30
+ - The JSON ships in the package as `@omkarux/vela/tokens.json` for other stacks and tools
31
+ (Style Dictionary, Tokens Studio, Terrazzo all read the format).
32
+ - 5 tests guard the pipeline: every CSS declaration has a source token and vice versa, no
33
+ dangling alias, primitives hold raw values and semantics hold aliases only, every token carries
34
+ its Figma name, and regenerating the CSS changes nothing.
35
+
6
36
  ## [0.4.0] — 2026-09-10
7
37
 
8
38
  ### Added
package/README.md CHANGED
@@ -101,6 +101,29 @@ npm run contrast # WCAG report for both themes
101
101
  npm run verify # typecheck + tests + build + pack-and-consume gate
102
102
  ```
103
103
 
104
+ ## Editing tokens — one source, three targets
105
+
106
+ `tokens/vela.tokens.json` is the only place a value is written. It uses the W3C Design Tokens
107
+ format (2025.10), ships inside the package as `@omkarux/vela/tokens.json`, and everything else is
108
+ generated from it:
109
+
110
+ ```bash
111
+ npm run tokens # → src/styles/tokens.light.css + tokens.dark.body.css
112
+ npm run tokens:figma # → a Plugin API script that creates-or-updates every Figma variable
113
+ npm run tokens:check # fails if the CSS was hand-edited instead of the JSON (runs in CI)
114
+ npm run guidelines:figma # → a script that writes each spec's summary into its Figma description
115
+ ```
116
+
117
+ The component specs in `guidelines/` follow the same rule: edit the markdown, and the package,
118
+ the agent docs and the Figma descriptions follow. The one thing no script can do is add a
119
+ variant — a spec that gains a prop is built in Figma and in code, by people, which is what the
120
+ API review is for.
121
+
122
+ Figma's REST API only lets Enterprise plans write variables, so the Figma half is a generated
123
+ script run inside the file (through the Figma MCP or the Scripter plugin). It looks each variable
124
+ up by collection and name, so re-running never duplicates: the first run against the live library
125
+ reported 0 created / 223 updated, then created the 11 numeric tokens Figma had never had.
126
+
104
127
  ## Using it on another stack
105
128
 
106
129
  Worth being precise about what travels and what doesn't:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omkarux/vela",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "A token-first design system: framework-agnostic tokens and component specs with a React implementation. Two-layer color architecture, separate severity and risk taxonomies, light and dark theming, WCAG AA asserted in CI, zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,18 +26,24 @@
26
26
  "./styles.css": "./dist/vela.css",
27
27
  "./tokens.css": "./dist/tokens.css",
28
28
  "./guidelines/*": "./guidelines/*",
29
- "./package.json": "./package.json"
29
+ "./package.json": "./package.json",
30
+ "./tokens.json": "./tokens/vela.tokens.json"
30
31
  },
31
32
  "files": [
32
33
  "dist",
33
34
  "guidelines",
34
35
  "README.md",
35
36
  "CHANGELOG.md",
36
- "LICENSE"
37
+ "LICENSE",
38
+ "tokens"
37
39
  ],
38
40
  "scripts": {
39
41
  "clean": "rm -rf dist",
40
- "build": "npm run clean && npm run build:js && npm run build:css",
42
+ "tokens": "node scripts/build-tokens.mjs",
43
+ "tokens:figma": "node scripts/sync-figma.mjs",
44
+ "guidelines:figma": "node scripts/sync-figma-descriptions.mjs",
45
+ "tokens:check": "node scripts/build-tokens.mjs && git diff --exit-code -- src/styles/tokens.light.css src/styles/tokens.dark.body.css",
46
+ "build": "npm run clean && npm run tokens && npm run build:js && npm run build:css",
41
47
  "build:js": "vite build",
42
48
  "build:css": "node scripts/build-css.mjs",
43
49
  "predev": "npm run build:css",
@@ -48,7 +54,7 @@
48
54
  "test:watch": "vitest",
49
55
  "typecheck": "tsc --noEmit",
50
56
  "contrast": "node scripts/contrast-report.mjs",
51
- "verify": "npm run typecheck && npm run test && npm run build && node scripts/verify-pack.mjs",
57
+ "verify": "npm run tokens:check && npm run typecheck && npm run test && npm run build && node scripts/verify-pack.mjs",
52
58
  "prepublishOnly": "npm run verify"
53
59
  },
54
60
  "peerDependencies": {
@@ -0,0 +1,152 @@
1
+ /* ============================================================================
2
+ DARK THEME
3
+ Note what is NOT here: primitives. Not one raw hex is redefined below.
4
+ Dark mode is achieved entirely by re-pointing semantic tokens onto a
5
+ different part of the same scale. That is the return on the two-layer
6
+ architecture — and the reason components never bind primitives directly.
7
+ Contrast ratios are asserted in src/styles/contrast.test.ts.
8
+ ============================================================================ */
9
+ color-scheme: dark;
10
+
11
+ /* ---- Surface ---- */
12
+ @bg-global
13
+ @bg-container
14
+ @bg-raised
15
+ @bg-hover
16
+ @bg-tooltip
17
+ @bg-inactive
18
+ @bg-selected
19
+ @primary-tint
20
+ @primary-active-bg
21
+
22
+ /* ---- Border ---- */
23
+ @border-default
24
+ @border-subtle
25
+ @border-active
26
+ @border-inactive
27
+ @border-action
28
+
29
+ /* ---- Text ---- */
30
+ @text-default
31
+ @text-heading
32
+ @text-de-emphasized
33
+ @text-inactive
34
+ @text-link
35
+ @text-on-brand
36
+ @text-on-tint
37
+ @text-error
38
+
39
+ /* ---- Icon ---- */
40
+ @icon-default
41
+ @icon-strong
42
+ @icon-selected
43
+ @icon-disabled
44
+ @icon-on-brand
45
+
46
+ /* ---- Button ---- */
47
+ @btn-primary-bg
48
+ @btn-primary-hover-bg
49
+ @btn-primary-border
50
+ @btn-primary-text
51
+ @btn-standard-bg
52
+ @btn-standard-hover-bg
53
+ @btn-standard-text
54
+ @btn-hollow-primary-text
55
+ @btn-hollow-primary-border
56
+ @btn-disabled-bg
57
+ @btn-disabled-text
58
+
59
+
60
+ @btn-destructive-bg
61
+ @btn-destructive-hover-bg
62
+ @btn-destructive-text
63
+ @btn-destructive-hollow-text
64
+ @btn-standard-border
65
+ @btn-hollow-hover-bg
66
+
67
+ /* ---- Form control ---- */
68
+ @control-bg
69
+ @control-border
70
+ @control-border-hover
71
+ @control-border-active
72
+ @control-border-error
73
+ @control-bg-disabled
74
+ @control-placeholder
75
+ @toggle-off-bg
76
+ @toggle-on-bg
77
+ @toggle-knob
78
+
79
+ /* ---- Severity (6) ---- */
80
+ @bg-severity-success
81
+ @border-severity-success
82
+ @signal-severity-success
83
+ @icon-severity-success
84
+ @text-severity-success
85
+ @border-severity-success-indicator
86
+
87
+ @bg-severity-info
88
+ @border-severity-info
89
+ @signal-severity-info
90
+ @icon-severity-info
91
+ @text-severity-info
92
+ @border-severity-info-indicator
93
+
94
+ @bg-severity-warning
95
+ @border-severity-warning
96
+ @signal-severity-warning
97
+ @icon-severity-warning
98
+ @text-severity-warning
99
+ @border-severity-warning-indicator
100
+
101
+ @bg-severity-minor
102
+ @border-severity-minor
103
+ @signal-severity-minor
104
+ @icon-severity-minor
105
+ @text-severity-minor
106
+ @border-severity-minor-indicator
107
+
108
+ @bg-severity-major
109
+ @border-severity-major
110
+ @signal-severity-major
111
+ @icon-severity-major
112
+ @text-severity-major
113
+ @border-severity-major-indicator
114
+
115
+ @bg-severity-critical
116
+ @border-severity-critical
117
+ @signal-severity-critical
118
+ @icon-severity-critical
119
+ @text-severity-critical
120
+ @border-severity-critical-indicator
121
+
122
+ /* ---- Risk (3) ---- */
123
+ @bg-risk-low
124
+ @border-risk-low
125
+ @signal-risk-low
126
+ @icon-risk-low
127
+ @text-risk-low
128
+ @border-risk-low-indicator
129
+
130
+ @bg-risk-medium
131
+ @border-risk-medium
132
+ @signal-risk-medium
133
+ @icon-risk-medium
134
+ @text-risk-medium
135
+ @border-risk-medium-indicator
136
+
137
+ @bg-risk-high
138
+ @border-risk-high
139
+ @signal-risk-high
140
+ @icon-risk-high
141
+ @text-risk-high
142
+ @border-risk-high-indicator
143
+
144
+ /* ---- Status (5 dots) ---- */
145
+ @signal-status-unknown
146
+ @signal-status-healthy
147
+ @signal-status-warning
148
+ @signal-status-medium
149
+ @signal-status-unhealthy
150
+
151
+ /* ---- Focus ---- */
152
+ @focus-ring-color
@@ -0,0 +1,293 @@
1
+ /* ============================================================================
2
+ VELA — Design tokens
3
+ Two layers: primitives (raw scale values) and semantics (role-named).
4
+ Always bind to semantics. Primitives exist so semantics can be re-pointed
5
+ for theming — binding a primitive directly defeats the entire architecture.
6
+ Numeric tokens carry their unit. Use them directly; never calc(... * 1px).
7
+ ============================================================================ */
8
+
9
+ :root {
10
+ color-scheme: light;
11
+
12
+ /* ---- Primitives: neutral ---- */
13
+ @black
14
+ @white
15
+ @grey-50
16
+ @grey-100
17
+ @grey-200
18
+ @grey-300
19
+ @grey-400
20
+ @grey-500
21
+ @grey-600 /* AA-safe de-emphasized text on white */
22
+ @grey-700
23
+ @grey-800
24
+ @grey-850
25
+ @grey-900
26
+ @grey-950
27
+
28
+ /* ---- Primitives: brand / blue ---- */
29
+ @primary-300
30
+ @primary-400
31
+ @primary-500
32
+ @primary-600
33
+ @blue-100
34
+ @blue-150
35
+ @blue-300
36
+ @blue-500
37
+ @blue-700
38
+ @blue-950
39
+
40
+ /* ---- Primitives: red / critical ---- */
41
+ @red-100
42
+ @red-300
43
+ @red-500
44
+ @red-700
45
+ @red-950
46
+ @critical-100
47
+ @critical-300
48
+ @critical-500
49
+ @critical-700
50
+ @critical-950
51
+
52
+ /* ---- Primitives: yellow / orange / green ---- */
53
+ @yellow-100
54
+ @yellow-300
55
+ @yellow-500
56
+ @yellow-600
57
+ @yellow-700
58
+ @yellow-800
59
+ @yellow-950
60
+ @orange-100
61
+ @orange-300
62
+ @orange-500
63
+ @orange-600 /* AA-safe status dot on white */
64
+ @orange-700
65
+ @orange-950
66
+ @green-100
67
+ @green-300
68
+ @green-500
69
+ @green-700
70
+ @green-800 /* AA-safe success text on green-100 */
71
+ @green-950
72
+
73
+ /* ---- Semantic: surface ---- */
74
+ @bg-global
75
+ @bg-container
76
+ @bg-raised
77
+ @bg-hover
78
+ @bg-tooltip
79
+ @bg-inactive
80
+ @bg-selected
81
+ @primary-tint
82
+ @primary-active-bg
83
+
84
+ /* ---- Semantic: border ---- */
85
+ @border-default
86
+ @border-subtle
87
+ @border-active
88
+ @border-inactive
89
+ @border-action
90
+
91
+ /* ---- Semantic: text ---- */
92
+ @text-default
93
+ @text-heading
94
+ @text-de-emphasized
95
+ @text-inactive
96
+ @text-link
97
+ @text-on-brand
98
+ @text-on-tint
99
+ @text-error
100
+
101
+ /* ---- Semantic: icon ---- */
102
+ @icon-default
103
+ @icon-strong
104
+ @icon-selected
105
+ @icon-disabled
106
+ @icon-on-brand
107
+
108
+ /* ---- Semantic: button ---- */
109
+ @btn-primary-bg
110
+ @btn-primary-hover-bg
111
+ @btn-primary-border
112
+ @btn-primary-text
113
+ @btn-standard-bg
114
+ @btn-standard-hover-bg
115
+ @btn-standard-text
116
+ @btn-hollow-primary-text
117
+ @btn-hollow-primary-border
118
+ @btn-disabled-bg
119
+ @btn-disabled-text
120
+
121
+
122
+ /* ---- Semantic: destructive button ----
123
+ NOTE: red-500 on white is 4.08:1 and fails WCAG AA for normal text.
124
+ Destructive filled therefore binds red-700 (6.57:1). This is a
125
+ deliberate divergence from a naive "use the signal color" mapping. */
126
+ @btn-destructive-bg
127
+ @btn-destructive-hover-bg
128
+ @btn-destructive-text
129
+ @btn-destructive-hollow-text
130
+ @btn-standard-border
131
+ @btn-hollow-hover-bg
132
+
133
+ /* ---- Semantic: form control ---- */
134
+ @control-bg
135
+ @control-border
136
+ @control-border-hover
137
+ @control-border-active
138
+ @control-border-error
139
+ @control-bg-disabled
140
+ @control-placeholder
141
+ @toggle-off-bg
142
+ @toggle-on-bg
143
+ @toggle-knob
144
+
145
+ /* ============================================================================
146
+ SEVERITY — 6 levels. Describes events and alerts.
147
+ Never interchange with Risk or Status. There is no "high severity".
148
+ Every level defines the full row: bg, border, signal, icon, text, indicator.
149
+ ============================================================================ */
150
+ @bg-severity-success
151
+ @border-severity-success
152
+ @signal-severity-success
153
+ @icon-severity-success
154
+ @text-severity-success
155
+ @border-severity-success-indicator
156
+
157
+ @bg-severity-info
158
+ @border-severity-info
159
+ @signal-severity-info
160
+ @icon-severity-info
161
+ @text-severity-info
162
+ @border-severity-info-indicator
163
+
164
+ @bg-severity-warning
165
+ @border-severity-warning
166
+ @signal-severity-warning
167
+ @icon-severity-warning
168
+ @text-severity-warning
169
+ @border-severity-warning-indicator
170
+
171
+ @bg-severity-minor
172
+ @border-severity-minor
173
+ @signal-severity-minor
174
+ @icon-severity-minor
175
+ @text-severity-minor
176
+ @border-severity-minor-indicator
177
+
178
+ @bg-severity-major
179
+ @border-severity-major
180
+ @signal-severity-major
181
+ @icon-severity-major
182
+ @text-severity-major
183
+ @border-severity-major-indicator
184
+
185
+ @bg-severity-critical
186
+ @border-severity-critical
187
+ @signal-severity-critical
188
+ @icon-severity-critical
189
+ @text-severity-critical
190
+ @border-severity-critical-indicator
191
+
192
+ /* ============================================================================
193
+ RISK — 3 levels. Describes scoring. There is no "critical risk".
194
+ ============================================================================ */
195
+ @bg-risk-low
196
+ @border-risk-low
197
+ @signal-risk-low
198
+ @icon-risk-low
199
+ @text-risk-low
200
+ @border-risk-low-indicator
201
+
202
+ @bg-risk-medium
203
+ @border-risk-medium
204
+ @signal-risk-medium
205
+ @icon-risk-medium
206
+ @text-risk-medium
207
+ @border-risk-medium-indicator
208
+
209
+ @bg-risk-high
210
+ @border-risk-high
211
+ @signal-risk-high
212
+ @icon-risk-high
213
+ @text-risk-high
214
+ @border-risk-high-indicator
215
+
216
+ /* ============================================================================
217
+ STATUS — 5 health states. Status Indicator dots only. Neither of the above.
218
+ ============================================================================ */
219
+ @signal-status-unknown
220
+ @signal-status-healthy
221
+ @signal-status-warning
222
+ @signal-status-medium
223
+ @signal-status-unhealthy
224
+
225
+ /* ---- Spacing: 5px base. 25 exists; 50 does not. ---- */
226
+ @space-5
227
+ @space-10
228
+ @space-15
229
+ @space-20
230
+ @space-25
231
+ @space-30
232
+ @space-40
233
+ @space-60
234
+ @space-80
235
+
236
+ /* ---- Icon sizes ---- */
237
+ @icon-12
238
+ @icon-16
239
+ @icon-20
240
+ @icon-24
241
+
242
+ /* ---- Control heights ---- */
243
+ @control-height-24
244
+ @control-height-25
245
+ @control-height-26
246
+ @control-height-35
247
+ @control-height-40
248
+ @control-height-48
249
+ @control-height-60
250
+
251
+ /* ---- Radius ---- */
252
+ @radius-3
253
+ @radius-4
254
+ @radius-8
255
+ @radius-12
256
+ @radius-full
257
+
258
+ /* ---- Typography: family & weight ---- */
259
+ @font-family-primary
260
+ @font-family-display
261
+ @font-weight-light
262
+ @font-weight-regular
263
+ @font-weight-semibold
264
+
265
+ /* ---- Typography: scale (size / weight / line-height triples) ---- */
266
+ @text-h1-size --vela-text-h1-weight: 300; --vela-text-h1-line-height: 42px;
267
+ @text-h2-size --vela-text-h2-weight: 300; --vela-text-h2-line-height: 33px;
268
+ @text-h3-size --vela-text-h3-weight: 300; --vela-text-h3-line-height: 27px;
269
+ @text-h4-size --vela-text-h4-weight: 400; --vela-text-h4-line-height: 24px;
270
+ @text-h5-size --vela-text-h5-weight: 600; --vela-text-h5-line-height: 21px;
271
+ @text-h6-size --vela-text-h6-weight: 600; --vela-text-h6-line-height: 18px;
272
+ @text-body-size --vela-text-body-weight: 400; --vela-text-body-line-height: 21px;
273
+ @text-meta-size --vela-text-meta-weight: 400; --vela-text-meta-line-height: 18px;
274
+ @text-meta-tracking
275
+
276
+ @text-button-tiny-size --vela-text-button-tiny-line-height: 18px;
277
+ @text-button-regular-size --vela-text-button-regular-line-height: 21px;
278
+ @text-button-large-size --vela-text-button-large-line-height: 22px;
279
+ @text-button-huge-size --vela-text-button-huge-line-height: 24px;
280
+
281
+ @text-tab-size --vela-text-tab-line-height: 19px;
282
+ @text-tab-large-size --vela-text-tab-large-line-height: 25px;
283
+
284
+ /* ---- Focus ---- */
285
+ @focus-ring-width
286
+ @focus-ring-offset
287
+ @focus-ring-color
288
+
289
+ /* ---- Motion (respects reduced-motion in components.css) ---- */
290
+ @duration-fast
291
+ @duration-base
292
+ @ease-standard
293
+ }