@rowkit/tokens 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 ADDED
@@ -0,0 +1,70 @@
1
+ # @rowkit/tokens
2
+
3
+ [![npm](https://img.shields.io/npm/v/@rowkit/tokens?color=3b5bdb)](https://www.npmjs.com/package/@rowkit/tokens)
4
+ [![license](https://img.shields.io/npm/l/@rowkit/tokens)](https://github.com/NikolaiKushner/rowkit/blob/main/LICENSE)
5
+
6
+ The design tokens behind [rowkit](https://www.npmjs.com/package/rowkit) — colour, spacing, typography, radii, shadows, layers and motion.
7
+
8
+ Usable on its own. Nothing here depends on Vue, so a chart library, a design tool or an email template can read the same values the components use.
9
+
10
+ **[Live reference](https://rowkit.dev/foundations/tokens)** · **[GitHub](https://github.com/NikolaiKushner/rowkit)**
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm i @rowkit/tokens
16
+ ```
17
+
18
+ ## Two layers
19
+
20
+ **Primitives** are the raw ramps: `--color-primary-600` is one specific blue and means nothing on its own. **Semantic** tokens name a role — `--color-card`, `--color-muted-foreground`, `--color-border` — and point at a primitive through `var()`.
21
+
22
+ Only the semantic layer changes under `.dark`, which is what makes dark mode a matter of repointing references rather than hunting hex codes.
23
+
24
+ ## Use
25
+
26
+ As a Tailwind v4 theme:
27
+
28
+ ```css
29
+ @import 'tailwindcss';
30
+ @import '@rowkit/tokens/css';
31
+ ```
32
+
33
+ Every token becomes a theme value, so `bg-card`, `text-muted-foreground`, `p-4`, `rounded-md` and `shadow-lg` resolve to the scales above.
34
+
35
+ As CSS custom properties, for anything Tailwind does not cover:
36
+
37
+ ```css
38
+ .my-thing {
39
+ background: var(--color-muted);
40
+ border-radius: var(--radius-md);
41
+ }
42
+ ```
43
+
44
+ Or in TypeScript, fully typed, when a value has to reach JavaScript:
45
+
46
+ ```ts
47
+ import { tokens } from '@rowkit/tokens'
48
+
49
+ tokens.color.primary[600] // 'oklch(0.546 0.209 259)'
50
+
51
+ const series = [tokens.color.primary[500], tokens.color.success[500]]
52
+ ```
53
+
54
+ `tokens` is grouped by scale rather than flattened, so `tokens.color.primary[600]` narrows to its literal type and autocompletes at every level.
55
+
56
+ ## Notes on the values
57
+
58
+ **Colour is OKLCH, clamped to sRGB.** Every chromatic family shares one lightness ramp, so `primary-600`, `danger-600` and `success-600` carry the same perceptual weight. Chroma is clamped to the sRGB gamut on purpose: OKLCH can express colours outside it, and browsers gamut-map those by their own rules — which makes a token render differently on a P3 laptop than on an sRGB monitor.
59
+
60
+ **Contrast is asserted, not claimed.** Every semantic pairing is checked against WCAG AA in the package's own tests, in both themes.
61
+
62
+ **Spacing keys are multiples of 4px.** `4` is 1rem, `2` is 8px — the convention most Vue and Tailwind developers already carry.
63
+
64
+ **Layer order is a build gate.** `z-index.test.ts` asserts a modal sits above an overlay, a tooltip above everything, and that consecutive layers stay at least 100 apart.
65
+
66
+ ## License
67
+
68
+ MIT © Nikolai Kushner
69
+
70
+ Design language based on [shadcn/ui](https://ui.shadcn.com) by shadcn, adapted for Vue. shadcn/ui is MIT licensed; rowkit adopts its token values and class recipes, not its code.
package/dist/blur.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Backdrop blur radii.
3
+ *
4
+ * One entry, and named for its job rather than a t-shirt size. Blur is not a
5
+ * scale rowkit designs with — it appears in exactly one place, behind a modal,
6
+ * and a second value would be a decision nobody has had to make yet.
7
+ *
8
+ * Deliberately small. The scrim separates the planes; the blur only stops the
9
+ * page behind from competing for the eye. Anything heavier reads as an effect
10
+ * and makes the content behind unrecognisable, which defeats the reason a
11
+ * modal shows its context at all.
12
+ */
13
+ export declare const blur: {
14
+ /** The dialog scrim. The reference `backdrop-blur-xs`. */
15
+ readonly overlay: "4px";
16
+ };
17
+ /** Names of every blur token. */
18
+ export type BlurName = keyof typeof blur;
package/dist/color.d.ts CHANGED
@@ -97,6 +97,171 @@ export declare const danger: {
97
97
  readonly 900: "oklch(0.396 0.135 25)";
98
98
  readonly 950: "oklch(0.282 0.086 25)";
99
99
  };
100
+ /**
101
+ * Greys keyed by OKLCH lightness × 1000, so `gray-922` is lightness 0.922.
102
+ *
103
+ * Most steps stay zero-chroma — the reference design's quiet base. A few carry
104
+ * a cool cast (hue 264, the same as {@link neutral}): lighter hairlines and
105
+ * soft recessed surfaces. That is rowkit's own signal inside an otherwise
106
+ * clean, reference-shaped palette — enough to read as itself on a long session,
107
+ * not enough to look like a tinted theme.
108
+ */
109
+ export declare const gray: {
110
+ /** Soft cool page. Slightly off pure white so a day of table work is less glare. */
111
+ readonly 988: "oklch(0.988 0.002 264)";
112
+ /** the reference `--primary-foreground`, `--foreground` (dark). */
113
+ readonly 985: "oklch(0.985 0 0)";
114
+ /**
115
+ * Cool recessed surface — muted toolbars, row hover, quiet chips.
116
+ *
117
+ * Lighter and cooler than the reference `--muted` (0.97 0 0): same job, less
118
+ * ink on the page.
119
+ */
120
+ readonly 972: "oklch(0.972 0.003 264)";
121
+ /** the reference `--secondary`, `--muted`, `--accent` — kept for dark primary fill. */
122
+ readonly 970: "oklch(0.97 0 0)";
123
+ /**
124
+ * Cool decorative hairline. Lighter than the reference `--border` (0.922) and
125
+ * barely tinted — table row rules and card outlines that stay visible without
126
+ * dividing the page into boxes.
127
+ */
128
+ readonly 940: "oklch(0.940 0.004 264)";
129
+ /** the reference `--border`. Kept for pressed fills that still need a step of weight. */
130
+ readonly 922: "oklch(0.922 0 0)";
131
+ /**
132
+ * Cool emphasised hairline. rowkit's; the reference design has no "strong border".
133
+ * Softer than the old 0.87 step so structure reads without shouting.
134
+ */
135
+ readonly 905: "oklch(0.905 0.006 264)";
136
+ /** Emphasised hairline (legacy weight). Prefer {@link gray[905]} for new chrome. */
137
+ readonly 870: "oklch(0.87 0 0)";
138
+ /** the reference `--muted-foreground` (dark), where it clears AA at 7.63:1. */
139
+ readonly 708: "oklch(0.708 0 0)";
140
+ /**
141
+ * rowkit's correction to the reference `--ring` and `--input` in light mode.
142
+ *
143
+ * the reference design puts them at 0.708 and 0.922, which measure 2.59:1 and 1.26:1
144
+ * against a white page — a focus ring and a control boundary that both fail
145
+ * WCAG 1.4.11.
146
+ *
147
+ * Not the mathematical minimum. Solving in floating point gave 0.669 and a
148
+ * tidy 3.00:1; the browser paints `#959595` and axe measured **2.995:1**,
149
+ * because a colour is quantised to eight bits per channel before anyone sees
150
+ * it. Anything solved exactly onto a threshold lands on whichever side the
151
+ * rounding chooses. 0.635 is 3.45:1 against the page and 3.17:1 against
152
+ * `surface-subtle`, which clears the bar on both sides of the rounding.
153
+ */
154
+ readonly 635: "oklch(0.635 0 0)";
155
+ /**
156
+ * Cool control boundary. Softer and cooler than the a11y floor at 0.635, still
157
+ * clears 3:1 on the page, a card and a recessed toolbar — so inputs speak the
158
+ * same language as the cool hairlines without failing WCAG 1.4.11.
159
+ */
160
+ readonly 642: "oklch(0.642 0.012 264)";
161
+ /** the reference `--ring` (dark), 4.18:1 against the dark page. */
162
+ readonly 556: "oklch(0.556 0 0)";
163
+ /**
164
+ * rowkit's correction to the reference `--muted-foreground` in light mode.
165
+ *
166
+ * The reference design's 0.556 is 4.73:1 on white but only 4.34:1 on `--muted`, the
167
+ * recessed surface a table header sits on — and a table header is the single
168
+ * most common use this token has.
169
+ *
170
+ * 0.547 was the first attempt and shipped 4.51:1 in floating point; axe,
171
+ * reading the painted `#717171`, called it 4.47:1 and failed twenty-four
172
+ * stories. See {@link gray[635]} — same lesson, same cause. 0.535 measures
173
+ * 4.75:1 on `--muted` and 5.17:1 on the page.
174
+ */
175
+ readonly 535: "oklch(0.535 0 0)";
176
+ /** Pressed row in dark mode. */
177
+ readonly 371: "oklch(0.371 0 0)";
178
+ /** the reference `--secondary`, `--muted`, `--accent` (dark). */
179
+ readonly 269: "oklch(0.269 0 0)";
180
+ /** the reference `--primary` (light), `--card` and `--popover` (dark). */
181
+ readonly 205: "oklch(0.205 0 0)";
182
+ /** the reference `--foreground` (light), `--background` (dark). */
183
+ readonly 145: "oklch(0.145 0 0)";
184
+ };
185
+ /**
186
+ * The reference design's destructive red, clamped into sRGB. Keyed by lightness, like `gray`.
187
+ *
188
+ * the reference design publishes `oklch(0.577 0.245 27.325)`, and that chroma **does not fit
189
+ * in sRGB** — 0.235 is the maximum at this lightness and hue. The difference is
190
+ * invisible; what it buys is a colour that renders identically on an sRGB
191
+ * monitor and a P3 laptop, instead of one each browser gamut-maps by its own
192
+ * rules. rowkit clamps every chromatic primitive for this reason, and
193
+ * `color.test.ts` enforces it.
194
+ *
195
+ * One red serves both themes. The reference design's dark `--destructive` is a lighter
196
+ * `oklch(0.704 …)`, which carries its white label at **2.86:1** — the single
197
+ * worst failure in the reference design's default set. Reusing the light value gives 4.90:1
198
+ * on the label in both themes and still clears 4.04:1 against the dark page.
199
+ */
200
+ export declare const red: {
201
+ /** Destructive fill. The reference design's lightness, chroma clamped. */
202
+ readonly 577: "oklch(0.577 0.235 27.325)";
203
+ /** Destructive hover — darkens in both themes, so the white label improves. */
204
+ readonly 520: "oklch(0.52 0.212 27.325)";
205
+ };
206
+ /**
207
+ * Success and warning, at the reference design's weight. Keyed by lightness, like `gray`.
208
+ *
209
+ * the reference design has no equivalent to copy, so the rule is consistency rather than
210
+ * fidelity: the solid step sits at the same lightness band as `red-577` and
211
+ * carries a white label, so a success, a warning and a destructive button are
212
+ * the same perceptual weight and only differ in hue.
213
+ *
214
+ * That is a real change for warning, which used to be bright amber with dark
215
+ * text. Bright amber is the loudest thing on a the reference design page — the language is
216
+ * built on restraint, and one saturated chip undoes it. Chroma is clamped to
217
+ * the sRGB boundary at every step, as everywhere else.
218
+ */
219
+ export declare const green: {
220
+ /** Badge fill, light. */
221
+ readonly 950: "oklch(0.95 0.05 152)";
222
+ /** Badge border, light. */
223
+ readonly 880: "oklch(0.88 0.05 152)";
224
+ /** Badge text, dark. */
225
+ readonly 850: "oklch(0.85 0.12 152)";
226
+ /** Solid fill, both themes. White label at 4.56:1. */
227
+ readonly 550: "oklch(0.55 0.144 152)";
228
+ /** Solid hover — darkens, so the white label improves. */
229
+ readonly 520: "oklch(0.52 0.136 152)";
230
+ /** Badge text, light. */
231
+ readonly 400: "oklch(0.4 0.105 152)";
232
+ /** Badge border, dark. */
233
+ readonly 350: "oklch(0.35 0.092 152)";
234
+ /** Badge fill, dark. */
235
+ readonly 260: "oklch(0.26 0.068 152)";
236
+ };
237
+ /** Warning, mirroring {@link green} step for step. */
238
+ export declare const amber: {
239
+ readonly 950: "oklch(0.95 0.04 75)";
240
+ readonly 880: "oklch(0.88 0.05 75)";
241
+ readonly 850: "oklch(0.85 0.12 75)";
242
+ /** Solid fill, both themes. White label at 4.96:1. */
243
+ readonly 550: "oklch(0.55 0.116 75)";
244
+ readonly 520: "oklch(0.52 0.109 75)";
245
+ readonly 400: "oklch(0.4 0.084 75)";
246
+ readonly 350: "oklch(0.35 0.074 75)";
247
+ readonly 260: "oklch(0.26 0.055 75)";
248
+ };
249
+ /**
250
+ * White at a fraction of opacity, for dark-mode borders.
251
+ *
252
+ * Alpha, not a solid grey: a grey tuned for `--background` draws too hard a
253
+ * line once the same border sits on `--card`. The reference uses 10% / 15%;
254
+ * rowkit softens the decorative hairline to 8% so dense tables stay quiet in
255
+ * dark mode the same way the cool light hairline does.
256
+ */
257
+ export declare const whiteAlpha: {
258
+ /** Soft decorative hairline in dark mode. */
259
+ readonly 8: "oklch(1 0 0 / 8%)";
260
+ /** the reference dark `--border`. */
261
+ readonly 10: "oklch(1 0 0 / 10%)";
262
+ /** Emphasised dark hairline / the reference dark `--input`. */
263
+ readonly 15: "oklch(1 0 0 / 15%)";
264
+ };
100
265
  /**
101
266
  * Every primitive colour, keyed by the CSS custom property it becomes.
102
267
  *
@@ -159,6 +324,44 @@ export declare const colorPrimitives: {
159
324
  readonly "neutral-800": string;
160
325
  readonly "neutral-900": string;
161
326
  readonly "neutral-950": string;
327
+ readonly "white-alpha-8": string;
328
+ readonly "white-alpha-10": string;
329
+ readonly "white-alpha-15": string;
330
+ readonly "amber-400": string;
331
+ readonly "amber-950": string;
332
+ readonly "amber-520": string;
333
+ readonly "amber-880": string;
334
+ readonly "amber-850": string;
335
+ readonly "amber-550": string;
336
+ readonly "amber-350": string;
337
+ readonly "amber-260": string;
338
+ readonly "green-400": string;
339
+ readonly "green-950": string;
340
+ readonly "green-520": string;
341
+ readonly "green-880": string;
342
+ readonly "green-850": string;
343
+ readonly "green-550": string;
344
+ readonly "green-350": string;
345
+ readonly "green-260": string;
346
+ readonly "red-577": string;
347
+ readonly "red-520": string;
348
+ readonly "gray-988": string;
349
+ readonly "gray-985": string;
350
+ readonly "gray-972": string;
351
+ readonly "gray-970": string;
352
+ readonly "gray-940": string;
353
+ readonly "gray-922": string;
354
+ readonly "gray-905": string;
355
+ readonly "gray-870": string;
356
+ readonly "gray-708": string;
357
+ readonly "gray-635": string;
358
+ readonly "gray-642": string;
359
+ readonly "gray-556": string;
360
+ readonly "gray-535": string;
361
+ readonly "gray-371": string;
362
+ readonly "gray-269": string;
363
+ readonly "gray-205": string;
364
+ readonly "gray-145": string;
162
365
  readonly white: "oklch(1 0 0)";
163
366
  readonly black: "oklch(0 0 0)";
164
367
  };
@@ -172,17 +375,29 @@ export type ColorRef = `var(--color-${string})`;
172
375
  * hunting down hex codes. `semantic.test.ts` enforces this.
173
376
  */
174
377
  export declare const semanticColorLight: {
175
- /** Page background, behind all surfaces. */
378
+ /**
379
+ * Page background, behind all surfaces.
380
+ *
381
+ * Soft cool off-white rather than the reference pure white — less glare over
382
+ * a long session, and enough lift that a white `card` still reads as a plane.
383
+ */
176
384
  readonly background: `var(--color-${string})`;
177
- /** Cards, panels, table bodies — the plane content sits on. */
178
- readonly surface: `var(--color-${string})`;
179
- /** Table headers, toolbars: a surface that recedes slightly. */
180
- readonly 'surface-subtle': `var(--color-${string})`;
385
+ /** Cards, panels, table bodies — the plane content sits on. The reference `--card`. */
386
+ readonly card: `var(--color-${string})`;
387
+ /**
388
+ * Table headers, toolbars: a surface that recedes slightly.
389
+ *
390
+ * Cool and a touch lighter than the reference `--muted`. Same role as
391
+ * `accent` out of the box — separate override points, not different colours.
392
+ */
393
+ readonly muted: `var(--color-${string})`;
181
394
  /** Row hover. */
182
- readonly 'surface-hover': `var(--color-${string})`;
183
- /** Row press / active. */
395
+ readonly accent: `var(--color-${string})`;
396
+ /** Row press / active. One step past hover; the reference design has no press token. */
184
397
  readonly 'surface-active': `var(--color-${string})`;
185
- /** Selected table row. */
398
+ /**
399
+ * Selected table row. Quiet primary wash — distinct from hover, not a shout.
400
+ */
186
401
  readonly 'surface-selected': `var(--color-${string})`;
187
402
  /** Disabled control background. */
188
403
  readonly 'surface-disabled': `var(--color-${string})`;
@@ -198,18 +413,17 @@ export declare const semanticColorLight: {
198
413
  * reader to perceive and WCAG 1.4.11 does not apply.
199
414
  */
200
415
  readonly skeleton: `var(--color-${string})`;
201
- /** Primary body and heading text. */
202
- readonly text: `var(--color-${string})`;
416
+ /** Primary body and heading text. The reference `--foreground`. */
417
+ readonly foreground: `var(--color-${string})`;
203
418
  /**
204
- * Secondary text, column labels, help text.
419
+ * Secondary text, column labels, help text. The reference `--muted-foreground`.
205
420
  *
206
- * `neutral-600`, not `500`. A table header is muted text on `surface-subtle`,
207
- * and at `500` that pairing reached only 4.41:1 — passing on white, failing
208
- * WCAG 1.4.3 on the recessed surface this token is most often used against.
209
- * `600` clears it at 6.90:1 and is still 2.3× lighter than `text`, so the
210
- * hierarchy survives.
421
+ * `gray-535`, not the reference design's 0.556. The same trap the old `neutral-500` fell
422
+ * into: a table header is muted text on `surface-subtle`, and the reference design's value
423
+ * reaches 4.73:1 on white but only 4.34:1 on the recessed surface this token
424
+ * is most often used against. Nine thousandths of lightness buy the pass.
211
425
  */
212
- readonly 'text-muted': `var(--color-${string})`;
426
+ readonly 'muted-foreground': `var(--color-${string})`;
213
427
  /** Placeholders and de-emphasised metadata. */
214
428
  readonly 'text-subtle': `var(--color-${string})`;
215
429
  /** Text on a disabled control. */
@@ -217,8 +431,9 @@ export declare const semanticColorLight: {
217
431
  /**
218
432
  * Decorative hairline: row separators, card outlines.
219
433
  *
220
- * Deliberately below 3:1 against the surface. Do not use it for the boundary
221
- * of an interactive control — see {@link semanticColorLight['border-control']}.
434
+ * Cool and lighter than the reference 0.922. Deliberately below 3:1 — do not
435
+ * use it for the boundary of an interactive control; see
436
+ * {@link semanticColorLight['input']}.
222
437
  */
223
438
  readonly border: `var(--color-${string})`;
224
439
  /** Emphasised decorative border: dividers that need to read as structure. */
@@ -229,14 +444,18 @@ export declare const semanticColorLight: {
229
444
  * Boundary of an interactive control — text inputs, checkboxes, outlined
230
445
  * buttons.
231
446
  *
232
- * WCAG 1.4.11 requires 3:1 against the adjacent surface for the visual
233
- * boundary of a UI component. `border` manages only 1.24:1 and
234
- * `border-strong` 1.49:1, so neither is legal here; this token is the
235
- * lightest neutral that clears the bar (4.83:1 on `surface`).
447
+ * Cooler and a touch lighter than the old pure `gray-635`, still ≥3:1 on the
448
+ * page, a card and a toolbar. Matches the cool hairline language without
449
+ * dropping below WCAG 1.4.11.
450
+ */
451
+ readonly input: `var(--color-${string})`;
452
+ /**
453
+ * Focus ring. Never remove the ring — recolour it.
454
+ *
455
+ * Matches the brand primary so focused controls and the primary button speak
456
+ * one language. Clears 1.4.11 against the page and recessed surfaces.
236
457
  */
237
- readonly 'border-control': `var(--color-${string})`;
238
- /** Focus ring. Never remove the ring — recolour it. */
239
- readonly 'focus-ring': `var(--color-${string})`;
458
+ readonly ring: `var(--color-${string})`;
240
459
  /** Base colour shadows are mixed from. */
241
460
  readonly shadow: `var(--color-${string})`;
242
461
  readonly 'neutral-solid': `var(--color-${string})`;
@@ -281,22 +500,22 @@ export declare const semanticColorLight: {
281
500
  */
282
501
  export declare const semanticColorDark: {
283
502
  readonly background: `var(--color-${string})`;
284
- readonly surface: `var(--color-${string})`;
285
- readonly 'surface-subtle': `var(--color-${string})`;
286
- readonly 'surface-hover': `var(--color-${string})`;
503
+ readonly card: `var(--color-${string})`;
504
+ readonly muted: `var(--color-${string})`;
505
+ readonly accent: `var(--color-${string})`;
287
506
  readonly 'surface-active': `var(--color-${string})`;
288
507
  readonly 'surface-selected': `var(--color-${string})`;
289
508
  readonly 'surface-disabled': `var(--color-${string})`;
290
509
  readonly skeleton: `var(--color-${string})`;
291
- readonly text: `var(--color-${string})`;
292
- readonly 'text-muted': `var(--color-${string})`;
510
+ readonly foreground: `var(--color-${string})`;
511
+ readonly 'muted-foreground': `var(--color-${string})`;
293
512
  readonly 'text-subtle': `var(--color-${string})`;
294
513
  readonly 'text-disabled': `var(--color-${string})`;
295
514
  readonly border: `var(--color-${string})`;
296
515
  readonly 'border-strong': `var(--color-${string})`;
297
516
  readonly 'border-subtle': `var(--color-${string})`;
298
- readonly 'border-control': `var(--color-${string})`;
299
- readonly 'focus-ring': `var(--color-${string})`;
517
+ readonly input: `var(--color-${string})`;
518
+ readonly ring: `var(--color-${string})`;
300
519
  readonly shadow: `var(--color-${string})`;
301
520
  readonly 'neutral-solid': `var(--color-${string})`;
302
521
  readonly 'neutral-solid-hover': `var(--color-${string})`;