@orangesys/tokens 0.0.0-stage → 0.5.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/dist/index.js ADDED
@@ -0,0 +1,650 @@
1
+ /**
2
+ * Orange design tokens — fonte única da verdade.
3
+ *
4
+ * `primitives` são valores crus (paletas). `themeDefinitions` mapeiam essas
5
+ * primitivas (por nome) para tokens semânticos (`--or-color-*`) usados por
6
+ * todos os componentes; `themes` traz os mesmos tokens já resolvidos em cor.
7
+ * O script `scripts/build.ts` gera `css/tokens.css` e os arquivos DTCG
8
+ * (`dist/tokens.dtcg.json`) a partir deste arquivo.
9
+ */
10
+ export const primitives = {
11
+ carbon: {
12
+ 0: '#0a0a0d',
13
+ 50: '#0f0f12',
14
+ 100: '#16161a',
15
+ 150: '#1c1c21',
16
+ 200: '#2a2a30',
17
+ 300: '#3a3a42',
18
+ 400: '#55555e',
19
+ 500: '#75757f',
20
+ 600: '#9c9588',
21
+ 700: '#b8b0a0',
22
+ 800: '#d4cdb5',
23
+ 900: '#f0ebdb',
24
+ 950: '#faf7ec',
25
+ },
26
+ paper: {
27
+ 0: '#fffdf6',
28
+ 50: '#faf7ec',
29
+ 100: '#f0ebdb',
30
+ 200: '#ece7d7',
31
+ 300: '#e2ddcd',
32
+ 400: '#d9d3bf',
33
+ 500: '#c9c4b5',
34
+ 600: '#8a8478',
35
+ 700: '#666057',
36
+ 800: '#525252',
37
+ 900: '#2a2a2a',
38
+ 950: '#0f0f12',
39
+ },
40
+ orange: {
41
+ 50: '#fff3eb',
42
+ 100: '#fde2cf',
43
+ 200: '#fbc6a2',
44
+ 300: '#f8a675',
45
+ 400: '#f6945f',
46
+ 500: '#f58549',
47
+ 550: '#e06a2c',
48
+ 600: '#d4622a',
49
+ 700: '#b85a24',
50
+ 800: '#9c4416',
51
+ /** Acento do tema claro de alto contraste: ≥ 7:1 com o papel dos dois lados. */
52
+ 850: '#8a3a10',
53
+ 900: '#6b2e0e',
54
+ },
55
+ green: {
56
+ 100: '#e4f1d1',
57
+ 300: '#a6d16a',
58
+ 500: '#7fb236',
59
+ /** Sucesso pleno no claro de alto contraste: ≥ 3:1 sobre o papel e ≥ 4.5:1 com texto carvão. */
60
+ 600: '#5f8f22',
61
+ 700: '#3d6614',
62
+ 900: '#22390b',
63
+ },
64
+ blue: {
65
+ 100: '#dfe5f8',
66
+ 300: '#8da2ea',
67
+ 400: '#6b85e0',
68
+ 500: '#4a66d4',
69
+ 700: '#2a4494',
70
+ 900: '#18275a',
71
+ },
72
+ red: {
73
+ 100: '#fde4e1',
74
+ 300: '#f79a8f',
75
+ 500: '#ef6a5a',
76
+ 700: '#b42318',
77
+ /** Erro no claro de alto contraste: ≥ 7:1 sobre o papel e com texto claro por cima. */
78
+ 800: '#961d13',
79
+ 900: '#6e140d',
80
+ },
81
+ amber: {
82
+ 100: '#faefcd',
83
+ 300: '#efd27f',
84
+ 500: '#e8c15a',
85
+ /** Atenção plena no claro de alto contraste: ≥ 3:1 sobre o papel e ≥ 4.5:1 com texto carvão. */
86
+ 600: '#a57c10',
87
+ 700: '#8a5a00',
88
+ 900: '#4d3200',
89
+ },
90
+ };
91
+ /** `true` quando `name` é uma primitiva existente (`orange-500`, `carbon-0`…). */
92
+ export function isPrimitiveName(name) {
93
+ const at = name.lastIndexOf('-');
94
+ if (at <= 0)
95
+ return false;
96
+ const family = primitives[name.slice(0, at)];
97
+ return family !== undefined && Object.hasOwn(family, name.slice(at + 1));
98
+ }
99
+ /** Valor de uma primitiva pelo nome: `primitive('green-500')` → `#7fb236`. */
100
+ export function primitive(name) {
101
+ const at = name.lastIndexOf('-');
102
+ const family = primitives[name.slice(0, at)];
103
+ return family[name.slice(at + 1)];
104
+ }
105
+ /* ---------------------------------------------------------------------------
106
+ * Temas
107
+ * ------------------------------------------------------------------------- */
108
+ /**
109
+ * Temas prontos, na ordem dos seletores. Cada um vira um bloco
110
+ * `[data-theme='<nome>']` em `tokens.css` e um modo no Figma.
111
+ */
112
+ export const themeNames = ['dark', 'light', 'dark-hc', 'light-hc'];
113
+ export const themeMeta = {
114
+ dark: { colorScheme: 'dark', highContrast: false },
115
+ light: { colorScheme: 'light', highContrast: false },
116
+ 'dark-hc': { colorScheme: 'dark', highContrast: true },
117
+ 'light-hc': { colorScheme: 'light', highContrast: true },
118
+ };
119
+ export const themeDefinitions = {
120
+ dark: {
121
+ bg: 'carbon-50',
122
+ 'bg-subtle': 'carbon-100',
123
+ surface: 'carbon-50',
124
+ 'surface-raised': 'carbon-150',
125
+ 'surface-hover': 'carbon-200',
126
+ 'surface-active': 'carbon-300',
127
+ 'surface-inverse': 'carbon-900',
128
+ overlay: 'rgba(5, 5, 7, 0.72)',
129
+ shadow: 'rgba(0, 0, 0, 0.55)',
130
+ text: 'carbon-900',
131
+ 'text-muted': 'carbon-700',
132
+ 'text-subtle': 'carbon-600',
133
+ // ~3.4:1 sobre o fundo: legível para baixa visão, mas claramente inativo.
134
+ 'text-disabled': '#6b6b74',
135
+ 'text-inverse': 'carbon-50',
136
+ 'text-on-accent': 'carbon-50',
137
+ border: 'carbon-200',
138
+ 'border-subtle': '#1f1f26',
139
+ 'border-strong': 'carbon-300',
140
+ 'border-control': 'carbon-500',
141
+ accent: 'orange-500',
142
+ 'accent-hover': 'orange-400',
143
+ 'accent-active': 'orange-550',
144
+ 'accent-subtle': 'rgba(245, 133, 73, 0.12)',
145
+ 'accent-text': 'orange-500',
146
+ 'accent-border': 'rgba(245, 133, 73, 0.45)',
147
+ neutral: 'carbon-900',
148
+ 'neutral-hover': 'carbon-950',
149
+ 'text-on-neutral': 'carbon-50',
150
+ success: 'green-500',
151
+ 'success-subtle': 'rgba(127, 178, 54, 0.14)',
152
+ 'success-text': 'green-300',
153
+ warning: 'amber-500',
154
+ 'warning-subtle': 'rgba(232, 193, 90, 0.14)',
155
+ 'warning-text': 'amber-300',
156
+ danger: 'red-500',
157
+ 'danger-hover': 'red-300',
158
+ 'danger-subtle': 'rgba(239, 106, 90, 0.14)',
159
+ 'danger-text': 'red-300',
160
+ 'text-on-danger': 'carbon-50',
161
+ 'text-on-success': 'carbon-50',
162
+ 'text-on-warning': 'carbon-50',
163
+ 'text-on-info': 'paper-0',
164
+ info: 'blue-500',
165
+ 'info-subtle': 'rgba(74, 102, 212, 0.16)',
166
+ 'info-text': 'blue-300',
167
+ focus: 'orange-400',
168
+ 'grid-line': 'rgba(240, 235, 219, 0.045)',
169
+ 'code-bg': 'carbon-0',
170
+ 'code-text': 'carbon-800',
171
+ selection: 'rgba(245, 133, 73, 0.32)',
172
+ },
173
+ light: {
174
+ bg: 'paper-50',
175
+ 'bg-subtle': 'paper-100',
176
+ surface: 'paper-0',
177
+ 'surface-raised': 'paper-0',
178
+ 'surface-hover': 'paper-200',
179
+ 'surface-active': 'paper-300',
180
+ 'surface-inverse': 'paper-950',
181
+ overlay: 'rgba(15, 15, 18, 0.48)',
182
+ // Bem mais leve que no escuro: a mesma sombra virava um halo cinza pesado sobre o papel.
183
+ shadow: 'rgba(15, 15, 18, 0.14)',
184
+ text: 'paper-950',
185
+ 'text-muted': 'paper-800',
186
+ 'text-subtle': 'paper-700',
187
+ 'text-disabled': 'paper-600',
188
+ 'text-inverse': 'paper-50',
189
+ 'text-on-accent': 'paper-950',
190
+ border: 'paper-400',
191
+ 'border-subtle': 'paper-300',
192
+ 'border-strong': 'paper-500',
193
+ 'border-control': '#7a7468',
194
+ // Laranja mais fechado no tema claro: ≥ 3:1 contra o papel (WCAG 1.4.11)
195
+ // e ≥ 4.5:1 para o texto escuro sobre ele.
196
+ accent: 'orange-600',
197
+ 'accent-hover': 'orange-550',
198
+ 'accent-active': 'orange-700',
199
+ 'accent-subtle': 'rgba(212, 98, 42, 0.12)',
200
+ 'accent-text': 'orange-800',
201
+ 'accent-border': 'rgba(184, 90, 36, 0.5)',
202
+ neutral: 'paper-950',
203
+ 'neutral-hover': '#2b2b2c',
204
+ 'text-on-neutral': 'paper-50',
205
+ success: 'green-500',
206
+ 'success-subtle': 'rgba(127, 178, 54, 0.16)',
207
+ 'success-text': 'green-700',
208
+ warning: 'amber-500',
209
+ 'warning-subtle': 'rgba(232, 193, 90, 0.22)',
210
+ 'warning-text': 'amber-700',
211
+ danger: 'red-700',
212
+ 'danger-hover': '#c9301f',
213
+ 'danger-subtle': 'rgba(180, 35, 24, 0.1)',
214
+ 'danger-text': 'red-700',
215
+ 'text-on-danger': '#ffffff',
216
+ 'text-on-success': 'carbon-50',
217
+ 'text-on-warning': 'carbon-50',
218
+ 'text-on-info': 'paper-0',
219
+ info: 'blue-700',
220
+ 'info-subtle': 'rgba(42, 68, 148, 0.1)',
221
+ 'info-text': 'blue-700',
222
+ focus: 'orange-700',
223
+ 'grid-line': 'rgba(15, 15, 18, 0.05)',
224
+ 'code-bg': 'carbon-50',
225
+ 'code-text': 'carbon-800',
226
+ selection: 'rgba(245, 133, 73, 0.28)',
227
+ },
228
+ /*
229
+ * Alto contraste (WCAG AAA). Mesma identidade — carvão, creme e laranja —, com:
230
+ * texto ≥ 7:1 sobre fundos e superfícies, bordas e foco ≥ 4.5:1, pares de acento
231
+ * ≥ 7:1 e textos de status ≥ 7:1. Validado em `contrast.test.ts`.
232
+ */
233
+ 'dark-hc': {
234
+ // Fundo mais fundo que o escuro padrão; superfícies separadas por borda, não por cinza.
235
+ bg: 'carbon-0',
236
+ 'bg-subtle': 'carbon-50',
237
+ surface: 'carbon-0',
238
+ 'surface-raised': 'carbon-50',
239
+ 'surface-hover': 'carbon-150',
240
+ 'surface-active': 'carbon-200',
241
+ 'surface-inverse': 'carbon-950',
242
+ overlay: 'rgba(0, 0, 0, 0.8)',
243
+ shadow: 'rgba(0, 0, 0, 0.7)',
244
+ text: 'carbon-950',
245
+ 'text-muted': 'carbon-800',
246
+ 'text-subtle': 'carbon-700',
247
+ // ≥ 4.5:1: legível, mas um degrau abaixo do texto sutil (≥ 7:1).
248
+ 'text-disabled': '#85858e',
249
+ 'text-inverse': 'carbon-0',
250
+ 'text-on-accent': 'carbon-0',
251
+ // Todas as bordas ≥ 4.5:1 — a mais fraca já supera a border-strong do tema padrão.
252
+ border: 'carbon-600',
253
+ 'border-subtle': '#85858e',
254
+ 'border-strong': 'carbon-700',
255
+ 'border-control': 'carbon-700',
256
+ accent: 'orange-500',
257
+ 'accent-hover': 'orange-400',
258
+ 'accent-active': 'orange-300',
259
+ 'accent-subtle': 'rgba(245, 133, 73, 0.16)',
260
+ 'accent-text': 'orange-400',
261
+ 'accent-border': 'orange-500',
262
+ neutral: 'carbon-950',
263
+ 'neutral-hover': 'carbon-900',
264
+ 'text-on-neutral': 'carbon-0',
265
+ success: 'green-500',
266
+ 'success-subtle': 'rgba(127, 178, 54, 0.16)',
267
+ 'success-text': 'green-300',
268
+ warning: 'amber-500',
269
+ 'warning-subtle': 'rgba(232, 193, 90, 0.16)',
270
+ 'warning-text': 'amber-300',
271
+ danger: 'red-300',
272
+ 'danger-hover': 'red-100',
273
+ 'danger-subtle': 'rgba(239, 106, 90, 0.16)',
274
+ 'danger-text': 'red-300',
275
+ 'text-on-danger': 'carbon-0',
276
+ 'text-on-success': 'carbon-0',
277
+ 'text-on-warning': 'carbon-0',
278
+ 'text-on-info': 'carbon-0',
279
+ // Azul pleno fica no 500: mais claro, o texto claro do Badge informativo cairia abaixo de 4.5:1.
280
+ info: 'blue-300',
281
+ 'info-subtle': 'rgba(74, 102, 212, 0.16)',
282
+ 'info-text': 'blue-300',
283
+ focus: 'orange-300',
284
+ 'grid-line': 'rgba(250, 247, 236, 0.08)',
285
+ 'code-bg': 'carbon-50',
286
+ 'code-text': 'carbon-900',
287
+ selection: 'rgba(245, 133, 73, 0.4)',
288
+ },
289
+ 'light-hc': {
290
+ bg: 'paper-0',
291
+ 'bg-subtle': 'paper-50',
292
+ surface: 'paper-0',
293
+ 'surface-raised': 'paper-0',
294
+ 'surface-hover': 'paper-200',
295
+ 'surface-active': 'paper-300',
296
+ 'surface-inverse': 'paper-950',
297
+ overlay: 'rgba(15, 15, 18, 0.64)',
298
+ shadow: 'rgba(15, 15, 18, 0.28)',
299
+ text: 'paper-950',
300
+ 'text-muted': 'paper-900',
301
+ 'text-subtle': 'paper-800',
302
+ 'text-disabled': 'paper-700',
303
+ 'text-inverse': 'paper-0',
304
+ // O acento escurece (laranja 850) para o texto claro por cima passar de 7:1.
305
+ 'text-on-accent': 'paper-0',
306
+ border: 'paper-800',
307
+ 'border-subtle': 'paper-700',
308
+ 'border-strong': 'paper-900',
309
+ 'border-control': 'paper-900',
310
+ accent: 'orange-850',
311
+ 'accent-hover': 'orange-900',
312
+ 'accent-active': 'orange-900',
313
+ 'accent-subtle': 'rgba(138, 58, 16, 0.08)',
314
+ 'accent-text': 'orange-900',
315
+ 'accent-border': 'orange-850',
316
+ neutral: 'paper-950',
317
+ 'neutral-hover': 'paper-900',
318
+ 'text-on-neutral': 'paper-0',
319
+ // Plenos de sucesso e atenção no meio-termo: ≥ 3:1 sobre o papel (ícones, bordas)
320
+ // sem derrubar o texto carvão do Badge abaixo de 4.5:1.
321
+ success: 'green-900',
322
+ 'success-subtle': 'rgba(61, 102, 20, 0.1)',
323
+ 'success-text': 'green-900',
324
+ warning: 'amber-900',
325
+ 'warning-subtle': 'rgba(165, 124, 16, 0.14)',
326
+ 'warning-text': 'amber-900',
327
+ danger: 'red-800',
328
+ 'danger-hover': 'red-900',
329
+ 'danger-subtle': 'rgba(150, 29, 19, 0.08)',
330
+ 'danger-text': 'red-800',
331
+ 'text-on-danger': 'paper-0',
332
+ 'text-on-success': 'paper-0',
333
+ 'text-on-warning': 'paper-0',
334
+ 'text-on-info': 'paper-0',
335
+ info: 'blue-700',
336
+ 'info-subtle': 'rgba(42, 68, 148, 0.08)',
337
+ 'info-text': 'blue-700',
338
+ focus: 'orange-900',
339
+ 'grid-line': 'rgba(15, 15, 18, 0.08)',
340
+ 'code-bg': 'carbon-0',
341
+ 'code-text': 'carbon-900',
342
+ selection: 'rgba(138, 58, 16, 0.24)',
343
+ },
344
+ };
345
+ /** Cor final de um valor de tema: primitivas viram hex; cores cruas passam direto. */
346
+ export function resolveColor(value) {
347
+ return isPrimitiveName(value) ? primitive(value) : value;
348
+ }
349
+ function resolveTheme(definition) {
350
+ const entries = Object.entries(definition);
351
+ return Object.fromEntries(entries.map(([key, value]) => [key, resolveColor(value)]));
352
+ }
353
+ /** Tokens semânticos de cada tema, já resolvidos em cor (hex ou rgba). */
354
+ export const themes = {
355
+ dark: resolveTheme(themeDefinitions.dark),
356
+ light: resolveTheme(themeDefinitions.light),
357
+ 'dark-hc': resolveTheme(themeDefinitions['dark-hc']),
358
+ 'light-hc': resolveTheme(themeDefinitions['light-hc']),
359
+ };
360
+ export const vizPalettes = {
361
+ dark: {
362
+ categorical: ['green-500', 'blue-400', 'amber-500', 'orange-600', 'red-300'],
363
+ other: 'carbon-500',
364
+ sequential: [
365
+ 'orange-900',
366
+ 'orange-800',
367
+ 'orange-700',
368
+ 'orange-600',
369
+ 'orange-500',
370
+ 'orange-300',
371
+ 'orange-100',
372
+ ],
373
+ diverging: [
374
+ 'blue-300',
375
+ 'blue-400',
376
+ 'blue-700',
377
+ 'carbon-400',
378
+ 'orange-800',
379
+ 'orange-600',
380
+ 'orange-300',
381
+ ],
382
+ },
383
+ light: {
384
+ categorical: ['green-700', 'blue-500', 'amber-700', 'orange-550', 'red-700'],
385
+ other: 'paper-600',
386
+ sequential: [
387
+ 'orange-100',
388
+ 'orange-200',
389
+ 'orange-300',
390
+ 'orange-500',
391
+ 'orange-600',
392
+ 'orange-800',
393
+ 'orange-900',
394
+ ],
395
+ diverging: [
396
+ 'blue-700',
397
+ 'blue-500',
398
+ 'blue-300',
399
+ 'paper-400',
400
+ 'orange-300',
401
+ 'orange-550',
402
+ 'orange-800',
403
+ ],
404
+ },
405
+ // Mesma ordem e famílias do escuro; azul e "outros" sobem um degrau para passar de 4.5:1, e a
406
+ // sequencial começa no 800 (o 900 sumia no fundo).
407
+ 'dark-hc': {
408
+ categorical: ['green-500', 'blue-300', 'amber-500', 'orange-600', 'red-300'],
409
+ other: 'carbon-600',
410
+ sequential: [
411
+ 'orange-800',
412
+ 'orange-700',
413
+ 'orange-600',
414
+ 'orange-500',
415
+ 'orange-400',
416
+ 'orange-300',
417
+ 'orange-100',
418
+ ],
419
+ diverging: [
420
+ 'blue-300',
421
+ 'blue-400',
422
+ 'blue-500',
423
+ 'carbon-400',
424
+ 'orange-700',
425
+ 'orange-500',
426
+ 'orange-300',
427
+ ],
428
+ },
429
+ // Sobre o papel claro, 4.5:1 só sobra para tons escuros: laranja e vermelho se separam pela
430
+ // luminosidade (laranja 900, bem mais escuro que o vermelho 700), não só pelo matiz.
431
+ 'light-hc': {
432
+ categorical: ['green-700', 'blue-500', 'amber-700', 'orange-900', 'red-700'],
433
+ other: 'paper-700',
434
+ sequential: [
435
+ 'orange-300',
436
+ 'orange-500',
437
+ 'orange-550',
438
+ 'orange-700',
439
+ 'orange-800',
440
+ 'orange-850',
441
+ 'orange-900',
442
+ ],
443
+ diverging: [
444
+ 'blue-900',
445
+ 'blue-700',
446
+ 'blue-500',
447
+ 'paper-500',
448
+ 'orange-550',
449
+ 'orange-800',
450
+ 'orange-900',
451
+ ],
452
+ },
453
+ };
454
+ /** Primitiva de cada token `viz-*` de uma paleta, na ordem de `--or-color-viz-*`. */
455
+ export function vizDefinition(palette) {
456
+ const entries = [
457
+ ...palette.categorical.map((name, i) => [`viz-${i + 1}`, name]),
458
+ ['viz-other', palette.other],
459
+ ...palette.sequential.map((name, i) => [`viz-seq-${i + 1}`, name]),
460
+ ...palette.diverging.map((name, i) => [`viz-div-${i + 1}`, name]),
461
+ ];
462
+ return Object.fromEntries(entries);
463
+ }
464
+ function vizTokens(palette) {
465
+ const entries = Object.entries(vizDefinition(palette));
466
+ return Object.fromEntries(entries.map(([key, name]) => [key, primitive(name)]));
467
+ }
468
+ /**
469
+ * Cores de gráficos por tema: `viz-1…5` (categórica, em ordem), `viz-other`,
470
+ * `viz-seq-1…7` (sequencial, do menor ao maior valor) e `viz-div-1…7`
471
+ * (divergente, de "abaixo" a "acima", com o neutro em `viz-div-4`).
472
+ */
473
+ export const vizThemes = {
474
+ dark: vizTokens(vizPalettes.dark),
475
+ light: vizTokens(vizPalettes.light),
476
+ 'dark-hc': vizTokens(vizPalettes['dark-hc']),
477
+ 'light-hc': vizTokens(vizPalettes['light-hc']),
478
+ };
479
+ export const typography = {
480
+ fontFamily: {
481
+ display: '"Space Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif',
482
+ body: 'Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',
483
+ mono: '"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',
484
+ },
485
+ fontSize: {
486
+ '2xs': '0.6875rem', // 11px
487
+ xs: '0.75rem', // 12px
488
+ sm: '0.8125rem', // 13px
489
+ md: '0.9375rem', // 15px
490
+ lg: '1.0625rem', // 17px
491
+ xl: '1.25rem', // 20px
492
+ '2xl': '1.5rem', // 24px
493
+ '3xl': '2rem', // 32px
494
+ '4xl': '2.75rem', // 44px
495
+ '5xl': '3.75rem', // 60px
496
+ display: '5.375rem', // 86px
497
+ },
498
+ fontWeight: {
499
+ regular: '400',
500
+ medium: '500',
501
+ semibold: '600',
502
+ bold: '700',
503
+ },
504
+ lineHeight: {
505
+ display: '1',
506
+ heading: '1.1',
507
+ tight: '1.35',
508
+ body: '1.55',
509
+ loose: '1.7',
510
+ },
511
+ letterSpacing: {
512
+ display: '-0.045em',
513
+ heading: '-0.03em',
514
+ body: '-0.005em',
515
+ meta: '0.14em',
516
+ },
517
+ };
518
+ export const space = {
519
+ 0: '0',
520
+ 1: '0.25rem',
521
+ 2: '0.5rem',
522
+ 3: '0.75rem',
523
+ 4: '1rem',
524
+ 5: '1.25rem',
525
+ 6: '1.5rem',
526
+ 7: '1.75rem',
527
+ 8: '2rem',
528
+ 10: '2.5rem',
529
+ 12: '3rem',
530
+ 14: '3.5rem',
531
+ 16: '4rem',
532
+ 20: '5rem',
533
+ 24: '6rem',
534
+ };
535
+ export const radius = {
536
+ none: '0',
537
+ sm: '2px',
538
+ md: '4px',
539
+ full: '9999px',
540
+ };
541
+ export const borderWidth = {
542
+ thin: '1px',
543
+ thick: '2px',
544
+ accent: '3px',
545
+ };
546
+ export const shadow = {
547
+ none: 'none',
548
+ /** Hover de cartões clicáveis (zop.dev): faixa sólida de 4px na base, na cor do texto. */
549
+ lift: '0 8px 0 -4px var(--or-color-text)',
550
+ 'hover-accent': '0 8px 0 -4px var(--or-color-accent)',
551
+ 'hover-ink': '0 4px 0 -2px var(--or-color-text)',
552
+ raised: '0 1px 0 0 var(--or-color-border-strong)',
553
+ overlay: '0 24px 64px -16px var(--or-color-shadow), 0 0 0 1px var(--or-color-border-strong)',
554
+ };
555
+ /**
556
+ * Movimento: rápido, funcional, sem bloquear. Saídas são mais curtas que
557
+ * entradas. Tudo é zerado em `prefers-reduced-motion: reduce`.
558
+ */
559
+ export const motion = {
560
+ duration: {
561
+ /** Clique/pressionar (feedback tátil). */
562
+ press: '90ms',
563
+ instant: '80ms',
564
+ /** Hover, foco, cor, borda — e saídas de sobreposições. */
565
+ fast: '160ms',
566
+ /** Entradas de sobreposições, indicadores deslizando. */
567
+ medium: '250ms',
568
+ /** Expandir/recolher, painéis, drawers. */
569
+ slow: '400ms',
570
+ /** Revelação no scroll. */
571
+ reveal: '600ms',
572
+ slower: '640ms',
573
+ /** Ciclos decorativos (pulso de status). */
574
+ loop: '2400ms',
575
+ },
576
+ easing: {
577
+ /** Padrão de entradas e hovers: desacelera no fim. */
578
+ out: 'cubic-bezier(0.22, 1, 0.36, 1)',
579
+ /** Movimentos de ida e volta, saídas e o cabeçalho que se esconde. */
580
+ 'in-out': 'cubic-bezier(0.65, 0, 0.35, 1)',
581
+ /** Indicadores (abas, segmentos, polegar do switch). */
582
+ spring: 'cubic-bezier(0.2, 0.9, 0.3, 1.05)',
583
+ snap: 'cubic-bezier(0.19, 1, 0.22, 1)',
584
+ /** Pequeno "pop" com overshoot (check, ponto do radio, badges). */
585
+ bounce: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
586
+ },
587
+ distance: {
588
+ /** Popovers, menus, tooltips. */
589
+ sm: '4px',
590
+ /** Diálogos, toasts, entrada de página. */
591
+ md: '8px',
592
+ /** Revelação no scroll. */
593
+ lg: '24px',
594
+ /** Elevação de cartões no hover. */
595
+ lift: '-4px',
596
+ },
597
+ /** Atraso entre itens de uma revelação escalonada. */
598
+ stagger: '80ms',
599
+ };
600
+ export const zIndex = {
601
+ base: '0',
602
+ raised: '10',
603
+ sticky: '100',
604
+ header: '200',
605
+ dropdown: '1000',
606
+ overlay: '1100',
607
+ modal: '1200',
608
+ popover: '1300',
609
+ toast: '1400',
610
+ tooltip: '1500',
611
+ };
612
+ export const breakpoints = {
613
+ sm: '640px',
614
+ md: '768px',
615
+ lg: '1024px',
616
+ xl: '1280px',
617
+ '2xl': '1440px',
618
+ };
619
+ export const layout = {
620
+ 'max-width': '1200px',
621
+ gutter: '2rem',
622
+ 'header-height': '4rem',
623
+ 'sidebar-width': '17.5rem',
624
+ };
625
+ /** Tamanhos de controles interativos (altura). Todos ≥ 24px (WCAG 2.5.8). */
626
+ export const controlSize = {
627
+ sm: '2rem', // 32px
628
+ md: '2.5rem', // 40px
629
+ lg: '3rem', // 48px
630
+ };
631
+ export const tokens = {
632
+ primitives,
633
+ themes,
634
+ viz: vizThemes,
635
+ typography,
636
+ space,
637
+ radius,
638
+ borderWidth,
639
+ shadow,
640
+ motion,
641
+ zIndex,
642
+ breakpoints,
643
+ layout,
644
+ controlSize,
645
+ };
646
+ /** Converte um caminho de token no nome da CSS custom property. */
647
+ export function cssVar(name) {
648
+ return `var(--or-${name})`;
649
+ }
650
+ export default tokens;
@@ -0,0 +1,9 @@
1
+ {
2
+ "tokenSetOrder": [
3
+ "primitivas",
4
+ "tema/dark",
5
+ "tema/light",
6
+ "tema/dark-hc",
7
+ "tema/light-hc"
8
+ ]
9
+ }