@kwtv/tokens 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/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # @kwtv/tokens
2
+
3
+ KWTV design tokens: colour, typography, spacing, shape and motion, with light
4
+ and dark themes. CSS, SCSS and JSON work independently of any framework.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ npm install @kwtv/tokens
10
+ ```
11
+
12
+ Import the CSS once in your app's root layout:
13
+
14
+ ```astro
15
+ ---
16
+ import "@kwtv/tokens/tokens.css";
17
+ ---
18
+ <html lang="nl">
19
+ <body><slot /></body>
20
+ </html>
21
+ ```
22
+
23
+ The default theme follows the operating system. Set `data-theme="light"` or
24
+ `data-theme="dark"` on the root element to choose a theme explicitly.
25
+
26
+ ## Exports
27
+
28
+ | Import | Contents |
29
+ | --- | --- |
30
+ | `@kwtv/tokens/tokens.css` | CSS custom properties and theme rules. |
31
+ | `@kwtv/tokens/utilities.css` | Optional utility classes. Load after the tokens. |
32
+ | `@kwtv/tokens/tokens.json` | Token data for tools and applications. |
33
+ | `@kwtv/tokens/tokens.scss` | SCSS variables. |
34
+ | `@kwtv/tokens` | Typed token exports as TypeScript source, supported by Astro/Vite. |
35
+
36
+ The root TypeScript entry requires a toolchain that processes TypeScript
37
+ dependencies. The CSS, SCSS and JSON entries do not require it.
38
+
39
+ ```ts
40
+ import { palette } from "@kwtv/tokens";
41
+ ```
42
+
43
+ CSS modules can compose the utility classes:
44
+
45
+ ```css
46
+ .button {
47
+ composes: bg-primary text-primary-fg p-4 radius-md from "@kwtv/tokens/utilities.css";
48
+ }
49
+ ```
50
+
51
+ Prefer semantic roles over raw palette values when a colour should follow
52
+ the current theme.
53
+
54
+ ## Development
55
+
56
+ Token files are generated in the
57
+ [design-system repository](https://github.com/KWTV-willebroek/design-system).
58
+ Edit `internal/scripts/build-tokens.py`, then run:
59
+
60
+ ```bash
61
+ npm run tokens:build
62
+ npm run tokens:check
63
+ ```
64
+
65
+ The checks validate sanctioned colour pairings and generated CSS. Browse the
66
+ [explorer](https://kwtv-explorer.vercel.app) for components and colour examples.
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@kwtv/tokens",
3
+ "version": "0.1.0",
4
+ "description": "KWTV design tokens. Colour, type, space, shape and motion. Light and dark.",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/KWTV-willebroek/design-system.git",
10
+ "directory": "packages/tokens"
11
+ },
12
+ "homepage": "https://kwtv-explorer.vercel.app/colour/",
13
+ "publishConfig": { "access": "public" },
14
+ "files": ["tokens"],
15
+ "exports": {
16
+ "./tokens.css": "./tokens/tokens.css",
17
+ "./utilities.css": "./tokens/utilities.css",
18
+ "./tokens.json": "./tokens/tokens.json",
19
+ "./tokens.scss": "./tokens/tokens.scss",
20
+ ".": "./tokens/tokens.ts"
21
+ }
22
+ }
@@ -0,0 +1,390 @@
1
+ /* Generated by scripts/build-tokens.py. Do not edit by hand. */
2
+
3
+ @layer palette, theme, scale;
4
+
5
+ @layer palette {
6
+ :root {
7
+ --sage-xlight: #DCF1E8;
8
+ --sage-light: #B1C9BF;
9
+ --sage-base: #7D938A; /* brand */
10
+ --sage-text: #496158;
11
+ --sage-dark: #364A42;
12
+ --sage-xdark: #162620;
13
+
14
+ --ivory-xlight: #FAF7F0;
15
+ --ivory-light: #F1EBDC;
16
+ --ivory-base: #E9E2D2; /* brand */
17
+ --ivory-dark: #C9C2B1;
18
+
19
+ --charcoal-light: #5A6164;
20
+ --charcoal-base: #2F3437; /* brand */
21
+ --charcoal-dark: #252A2C;
22
+ --charcoal-xdark: #171B1D;
23
+
24
+ --burgundy-xlight: #F6E2E4;
25
+ --burgundy-light: #D9A3A9;
26
+ --burgundy-rose: #E97A8C;
27
+ --burgundy-base: #7A2338; /* brand */
28
+ --burgundy-text: #5C1A29;
29
+ --burgundy-dark: #47131F;
30
+ --burgundy-xdark: #2E0F18;
31
+
32
+ --amber-xlight: #FBEBD2;
33
+ --amber-light: #E8B978;
34
+ --amber-base: #8A5A16; /* brand */
35
+ --amber-dark: #5E3D0F;
36
+
37
+ --white-base: #FFFFFF;
38
+
39
+ }
40
+ }
41
+
42
+ @layer theme {
43
+ :root {
44
+ /* Both themes named explicitly, so either can be referenced
45
+ directly regardless of which one is active. */
46
+ --bg-light: var(--ivory-xlight);
47
+ --surface-light: var(--ivory-xlight);
48
+ --surface-hover-light: var(--ivory-light);
49
+ --surface-accent-light: var(--sage-light);
50
+ --surface-accent-fg-light: var(--sage-xdark);
51
+ --surface-accent-muted-light: var(--sage-dark);
52
+ --border-light: var(--ivory-dark);
53
+ --border-strong-light: var(--sage-text);
54
+ --focus-light: var(--charcoal-light);
55
+ --focus-outer-light: var(--ivory-light);
56
+ --text-light: var(--charcoal-xdark);
57
+ --text-muted-light: var(--charcoal-light);
58
+ --text-inverse-light: var(--ivory-light);
59
+ --link-light: var(--sage-dark);
60
+ --link-hover-light: var(--sage-xdark);
61
+ --primary-light: var(--sage-dark);
62
+ --primary-hover-light: var(--sage-xdark);
63
+ --primary-fg-light: var(--white-base);
64
+ --accent-light: var(--burgundy-base);
65
+ --accent-hover-light: var(--burgundy-text);
66
+ --accent-fg-light: var(--white-base);
67
+ --success-light: var(--sage-dark);
68
+ --success-bg-light: var(--sage-xlight);
69
+ --warning-light: var(--amber-base);
70
+ --warning-bg-light: var(--amber-xlight);
71
+ --danger-light: var(--burgundy-base);
72
+ --danger-bg-light: var(--burgundy-xlight);
73
+
74
+ --bg-dark: var(--charcoal-xdark);
75
+ --surface-dark: var(--sage-xdark);
76
+ --surface-hover-dark: var(--sage-dark);
77
+ --surface-accent-dark: var(--sage-text);
78
+ --surface-accent-fg-dark: var(--ivory-light);
79
+ --surface-accent-muted-dark: var(--ivory-base);
80
+ --border-dark: var(--sage-dark);
81
+ --border-strong-dark: var(--sage-base);
82
+ --focus-dark: var(--ivory-light);
83
+ --focus-outer-dark: var(--charcoal-xdark);
84
+ --text-dark: var(--ivory-light);
85
+ --text-muted-dark: var(--sage-light);
86
+ --text-inverse-dark: var(--charcoal-xdark);
87
+ --link-dark: var(--sage-light);
88
+ --link-hover-dark: var(--sage-xlight);
89
+ --primary-dark: var(--sage-light);
90
+ --primary-hover-dark: var(--sage-xlight);
91
+ --primary-fg-dark: var(--charcoal-xdark);
92
+ --accent-dark: var(--burgundy-light);
93
+ --accent-hover-dark: var(--burgundy-xlight);
94
+ --accent-fg-dark: var(--charcoal-xdark);
95
+ --success-dark: var(--sage-light);
96
+ --success-bg-dark: var(--sage-dark);
97
+ --warning-dark: var(--amber-light);
98
+ --warning-bg-dark: var(--amber-dark);
99
+ --danger-dark: var(--burgundy-rose);
100
+ --danger-bg-dark: var(--burgundy-text);
101
+
102
+ /* Active role. Light is the default. */
103
+ --bg: var(--bg-light);
104
+ --surface: var(--surface-light);
105
+ --surface-hover: var(--surface-hover-light);
106
+ --surface-accent: var(--surface-accent-light);
107
+ --surface-accent-fg: var(--surface-accent-fg-light);
108
+ --surface-accent-muted: var(--surface-accent-muted-light);
109
+ --border: var(--border-light);
110
+ --border-strong: var(--border-strong-light);
111
+ --focus: var(--focus-light);
112
+ --focus-outer: var(--focus-outer-light);
113
+ --text: var(--text-light);
114
+ --text-muted: var(--text-muted-light);
115
+ --text-inverse: var(--text-inverse-light);
116
+ --link: var(--link-light);
117
+ --link-hover: var(--link-hover-light);
118
+ --primary: var(--primary-light);
119
+ --primary-hover: var(--primary-hover-light);
120
+ --primary-fg: var(--primary-fg-light);
121
+ --accent: var(--accent-light);
122
+ --accent-hover: var(--accent-hover-light);
123
+ --accent-fg: var(--accent-fg-light);
124
+ --success: var(--success-light);
125
+ --success-bg: var(--success-bg-light);
126
+ --warning: var(--warning-light);
127
+ --warning-bg: var(--warning-bg-light);
128
+ --danger: var(--danger-light);
129
+ --danger-bg: var(--danger-bg-light);
130
+
131
+ --shadow-xs-light: 0 1px 2px rgba(44,52,47,.05);
132
+ --shadow-sm-light: 0 1px 2px rgba(44,52,47,.06), 0 1px 3px rgba(44,52,47,.08);
133
+ --shadow-md-light: 0 2px 4px rgba(44,52,47,.06), 0 4px 12px rgba(44,52,47,.08);
134
+ --shadow-lg-light: 0 4px 8px rgba(44,52,47,.06), 0 12px 28px rgba(44,52,47,.10);
135
+ --shadow-xl-light: 0 8px 16px rgba(44,52,47,.08), 0 24px 48px rgba(44,52,47,.12);
136
+ --shadow-xs-dark: 0 1px 2px rgba(0,0,0,.30);
137
+ --shadow-sm-dark: 0 1px 2px rgba(0,0,0,.36), 0 1px 3px rgba(0,0,0,.40);
138
+ --shadow-md-dark: 0 2px 4px rgba(0,0,0,.36), 0 4px 12px rgba(0,0,0,.44);
139
+ --shadow-lg-dark: 0 4px 8px rgba(0,0,0,.40), 0 12px 28px rgba(0,0,0,.50);
140
+ --shadow-xl-dark: 0 8px 16px rgba(0,0,0,.44), 0 24px 48px rgba(0,0,0,.56);
141
+ --shadow-xs: var(--shadow-xs-light);
142
+ --shadow-sm: var(--shadow-sm-light);
143
+ --shadow-md: var(--shadow-md-light);
144
+ --shadow-lg: var(--shadow-lg-light);
145
+ --shadow-xl: var(--shadow-xl-light);
146
+ }
147
+
148
+ /* System preference, unless the user pinned light. */
149
+ @media (prefers-color-scheme: dark) {
150
+ :root:not([data-theme="light"]) {
151
+ --bg: var(--bg-dark);
152
+ --surface: var(--surface-dark);
153
+ --surface-hover: var(--surface-hover-dark);
154
+ --surface-accent: var(--surface-accent-dark);
155
+ --surface-accent-fg: var(--surface-accent-fg-dark);
156
+ --surface-accent-muted: var(--surface-accent-muted-dark);
157
+ --border: var(--border-dark);
158
+ --border-strong: var(--border-strong-dark);
159
+ --focus: var(--focus-dark);
160
+ --focus-outer: var(--focus-outer-dark);
161
+ --text: var(--text-dark);
162
+ --text-muted: var(--text-muted-dark);
163
+ --text-inverse: var(--text-inverse-dark);
164
+ --link: var(--link-dark);
165
+ --link-hover: var(--link-hover-dark);
166
+ --primary: var(--primary-dark);
167
+ --primary-hover: var(--primary-hover-dark);
168
+ --primary-fg: var(--primary-fg-dark);
169
+ --accent: var(--accent-dark);
170
+ --accent-hover: var(--accent-hover-dark);
171
+ --accent-fg: var(--accent-fg-dark);
172
+ --success: var(--success-dark);
173
+ --success-bg: var(--success-bg-dark);
174
+ --warning: var(--warning-dark);
175
+ --warning-bg: var(--warning-bg-dark);
176
+ --danger: var(--danger-dark);
177
+ --danger-bg: var(--danger-bg-dark);
178
+ --shadow-xs: var(--shadow-xs-dark);
179
+ --shadow-sm: var(--shadow-sm-dark);
180
+ --shadow-md: var(--shadow-md-dark);
181
+ --shadow-lg: var(--shadow-lg-dark);
182
+ --shadow-xl: var(--shadow-xl-dark);
183
+ }
184
+ }
185
+
186
+ /* Explicit choice always wins. */
187
+ [data-theme="dark"] {
188
+ --bg: var(--bg-dark);
189
+ --surface: var(--surface-dark);
190
+ --surface-hover: var(--surface-hover-dark);
191
+ --surface-accent: var(--surface-accent-dark);
192
+ --surface-accent-fg: var(--surface-accent-fg-dark);
193
+ --surface-accent-muted: var(--surface-accent-muted-dark);
194
+ --border: var(--border-dark);
195
+ --border-strong: var(--border-strong-dark);
196
+ --focus: var(--focus-dark);
197
+ --focus-outer: var(--focus-outer-dark);
198
+ --text: var(--text-dark);
199
+ --text-muted: var(--text-muted-dark);
200
+ --text-inverse: var(--text-inverse-dark);
201
+ --link: var(--link-dark);
202
+ --link-hover: var(--link-hover-dark);
203
+ --primary: var(--primary-dark);
204
+ --primary-hover: var(--primary-hover-dark);
205
+ --primary-fg: var(--primary-fg-dark);
206
+ --accent: var(--accent-dark);
207
+ --accent-hover: var(--accent-hover-dark);
208
+ --accent-fg: var(--accent-fg-dark);
209
+ --success: var(--success-dark);
210
+ --success-bg: var(--success-bg-dark);
211
+ --warning: var(--warning-dark);
212
+ --warning-bg: var(--warning-bg-dark);
213
+ --danger: var(--danger-dark);
214
+ --danger-bg: var(--danger-bg-dark);
215
+ --shadow-xs: var(--shadow-xs-dark);
216
+ --shadow-sm: var(--shadow-sm-dark);
217
+ --shadow-md: var(--shadow-md-dark);
218
+ --shadow-lg: var(--shadow-lg-dark);
219
+ --shadow-xl: var(--shadow-xl-dark);
220
+ }
221
+
222
+ /* Progressive enhancement. Applies only when the consumer has set
223
+ color-scheme and no explicit data-theme is pinned. Everything
224
+ above already works without it.
225
+
226
+ Restricted to the light-preference case on purpose. With
227
+ color-scheme unset, light-dark() silently resolves to its light
228
+ branch, and because this block comes last it would otherwise
229
+ override the dark media query above and hand an OS-dark user a
230
+ light page. Under a light preference both paths agree, so the
231
+ enhancement is safe and the dark path stays with the media
232
+ query, which needs no opt-in. */
233
+ @supports (color: light-dark(#000, #fff)) {
234
+ @media (prefers-color-scheme: light) {
235
+ :root:not([data-theme]) {
236
+ --bg: light-dark(var(--bg-light), var(--bg-dark));
237
+ --surface: light-dark(var(--surface-light), var(--surface-dark));
238
+ --surface-hover: light-dark(var(--surface-hover-light), var(--surface-hover-dark));
239
+ --surface-accent: light-dark(var(--surface-accent-light), var(--surface-accent-dark));
240
+ --surface-accent-fg: light-dark(var(--surface-accent-fg-light), var(--surface-accent-fg-dark));
241
+ --surface-accent-muted: light-dark(var(--surface-accent-muted-light), var(--surface-accent-muted-dark));
242
+ --border: light-dark(var(--border-light), var(--border-dark));
243
+ --border-strong: light-dark(var(--border-strong-light), var(--border-strong-dark));
244
+ --focus: light-dark(var(--focus-light), var(--focus-dark));
245
+ --focus-outer: light-dark(var(--focus-outer-light), var(--focus-outer-dark));
246
+ --text: light-dark(var(--text-light), var(--text-dark));
247
+ --text-muted: light-dark(var(--text-muted-light), var(--text-muted-dark));
248
+ --text-inverse: light-dark(var(--text-inverse-light), var(--text-inverse-dark));
249
+ --link: light-dark(var(--link-light), var(--link-dark));
250
+ --link-hover: light-dark(var(--link-hover-light), var(--link-hover-dark));
251
+ --primary: light-dark(var(--primary-light), var(--primary-dark));
252
+ --primary-hover: light-dark(var(--primary-hover-light), var(--primary-hover-dark));
253
+ --primary-fg: light-dark(var(--primary-fg-light), var(--primary-fg-dark));
254
+ --accent: light-dark(var(--accent-light), var(--accent-dark));
255
+ --accent-hover: light-dark(var(--accent-hover-light), var(--accent-hover-dark));
256
+ --accent-fg: light-dark(var(--accent-fg-light), var(--accent-fg-dark));
257
+ --success: light-dark(var(--success-light), var(--success-dark));
258
+ --success-bg: light-dark(var(--success-bg-light), var(--success-bg-dark));
259
+ --warning: light-dark(var(--warning-light), var(--warning-dark));
260
+ --warning-bg: light-dark(var(--warning-bg-light), var(--warning-bg-dark));
261
+ --danger: light-dark(var(--danger-light), var(--danger-dark));
262
+ --danger-bg: light-dark(var(--danger-bg-light), var(--danger-bg-dark));
263
+ }
264
+ }
265
+ }
266
+ }
267
+
268
+ @layer scale {
269
+ :root {
270
+ /* Type family */
271
+ --font-sans: "Hanken Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
272
+ --font-serif: "Source Serif 4 Variable", "Source Serif 4", ui-serif, Georgia, serif;
273
+ --font-mono: "JetBrains Mono Variable", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
274
+
275
+ /* Weight */
276
+ --weight-regular: 400;
277
+ --weight-medium: 500;
278
+ --weight-semibold: 600;
279
+ --weight-bold: 700;
280
+
281
+ /* Tracking */
282
+ --tracking-tighter: -0.03em;
283
+ --tracking-tight: -0.015em;
284
+ --tracking-normal: 0;
285
+ --tracking-wide: 0.02em;
286
+ --tracking-wider: 0.06em;
287
+ --tracking-widest: 0.14em;
288
+
289
+ /* Space */
290
+ --space-0: 0;
291
+ --space-px: 1px;
292
+ --space-0-5: 0.125rem;
293
+ --space-1: 0.25rem;
294
+ --space-1-5: 0.375rem;
295
+ --space-2: 0.5rem;
296
+ --space-2-5: 0.625rem;
297
+ --space-3: 0.75rem;
298
+ --space-4: 1rem;
299
+ --space-4-5: 1.125rem;
300
+ --space-5: 1.25rem;
301
+ --space-6: 1.5rem;
302
+ --space-7: 1.75rem;
303
+ --space-8: 2rem;
304
+ --space-10: 2.5rem;
305
+ --space-12: 3rem;
306
+ --space-16: 4rem;
307
+ --space-20: 5rem;
308
+ --space-24: 6rem;
309
+ --space-32: 8rem;
310
+ --space-40: 10rem;
311
+ --space-48: 12rem;
312
+
313
+ /* Radius */
314
+ --radius-none: 0;
315
+ --radius-sm: 0.1875rem;
316
+ --radius-md: 0.375rem;
317
+ --radius-lg: 0.625rem;
318
+ --radius-xl: 1rem;
319
+ --radius-2xl: 1.5rem;
320
+ --radius-full: 9999px;
321
+
322
+ /* Duration */
323
+ --duration-instant: 0ms;
324
+ --duration-fast: 120ms;
325
+ --duration-base: 200ms;
326
+ --duration-slow: 320ms;
327
+ --duration-slower: 480ms;
328
+
329
+ /* Easing */
330
+ --ease-standard: cubic-bezier(.2,0,0,1);
331
+ --ease-enter: cubic-bezier(0,0,0,1);
332
+ --ease-exit: cubic-bezier(.3,0,1,1);
333
+ --ease-spring: cubic-bezier(.2,1.3,.4,1);
334
+
335
+ /* Breakpoint */
336
+ --bp-sm: 640px;
337
+ --bp-md: 768px;
338
+ --bp-lg: 1024px;
339
+ --bp-xl: 1280px;
340
+ --bp-2xl: 1536px;
341
+
342
+ /* Z index */
343
+ --z-base: 0;
344
+ --z-dropdown: 1000;
345
+ --z-sticky: 1100;
346
+ --z-overlay: 1200;
347
+ --z-modal: 1300;
348
+ --z-popover: 1400;
349
+ --z-toast: 1500;
350
+ --z-tooltip: 1600;
351
+
352
+ /* Type scale */
353
+ --text-3xs: 0.625rem;
354
+ --leading-3xs: 1rem;
355
+ --text-2xs: 0.6875rem;
356
+ --leading-2xs: 1rem;
357
+ --text-xs: 0.75rem;
358
+ --leading-xs: 1.125rem;
359
+ --text-sm: 0.875rem;
360
+ --leading-sm: 1.375rem;
361
+ --text-base: 1rem;
362
+ --leading-base: 1.625rem;
363
+ --text-lg: 1.125rem;
364
+ --leading-lg: 1.75rem;
365
+ --text-xl: 1.25rem;
366
+ --leading-xl: 1.875rem;
367
+ --text-2xl: 1.5rem;
368
+ --leading-2xl: 2rem;
369
+ --text-3xl: 1.875rem;
370
+ --leading-3xl: 2.25rem;
371
+ --text-4xl: 2.25rem;
372
+ --leading-4xl: 2.5rem;
373
+ --text-5xl: 3rem;
374
+ --leading-5xl: 1.08;
375
+ --text-6xl: 3.75rem;
376
+ --leading-6xl: 1.05;
377
+ --text-7xl: 4.5rem;
378
+ --leading-7xl: 1.02;
379
+ }
380
+
381
+ /* Honour the OS setting. */
382
+ @media (prefers-reduced-motion: reduce) {
383
+ :root {
384
+ --duration-fast: 0ms;
385
+ --duration-base: 0ms;
386
+ --duration-slow: 0ms;
387
+ --duration-slower: 0ms;
388
+ }
389
+ }
390
+ }