@react-xp/design-system 1.0.0-beta.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.
Files changed (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +325 -0
  3. package/dist/cjs/helpers/a11y.js +176 -0
  4. package/dist/cjs/helpers/index.js +18 -0
  5. package/dist/cjs/helpers/styles.js +172 -0
  6. package/dist/cjs/index.js +19 -0
  7. package/dist/cjs/styles/avatars.js +63 -0
  8. package/dist/cjs/styles/badges.js +59 -0
  9. package/dist/cjs/styles/bottomSheets.js +76 -0
  10. package/dist/cjs/styles/buttons.js +129 -0
  11. package/dist/cjs/styles/cards.js +71 -0
  12. package/dist/cjs/styles/checkboxes.js +70 -0
  13. package/dist/cjs/styles/chips.js +98 -0
  14. package/dist/cjs/styles/datePickers.js +113 -0
  15. package/dist/cjs/styles/dividers.js +12 -0
  16. package/dist/cjs/styles/emptyStates.js +40 -0
  17. package/dist/cjs/styles/forms.js +32 -0
  18. package/dist/cjs/styles/headers.js +46 -0
  19. package/dist/cjs/styles/index.js +43 -0
  20. package/dist/cjs/styles/inputs.js +101 -0
  21. package/dist/cjs/styles/listItems.js +65 -0
  22. package/dist/cjs/styles/modals.js +92 -0
  23. package/dist/cjs/styles/pagination.js +39 -0
  24. package/dist/cjs/styles/popovers.js +64 -0
  25. package/dist/cjs/styles/progress.js +33 -0
  26. package/dist/cjs/styles/radios.js +70 -0
  27. package/dist/cjs/styles/selects.js +137 -0
  28. package/dist/cjs/styles/skeletons.js +34 -0
  29. package/dist/cjs/styles/steppers.js +71 -0
  30. package/dist/cjs/styles/switches.js +76 -0
  31. package/dist/cjs/styles/tables.js +57 -0
  32. package/dist/cjs/styles/tabs.js +71 -0
  33. package/dist/cjs/styles/toasts.js +82 -0
  34. package/dist/cjs/styles/tooltips.js +46 -0
  35. package/dist/cjs/types/index.js +18 -0
  36. package/dist/cjs/types/states.js +8 -0
  37. package/dist/cjs/types/tokens.js +18 -0
  38. package/dist/esm/helpers/a11y.js +169 -0
  39. package/dist/esm/helpers/index.js +2 -0
  40. package/dist/esm/helpers/styles.js +158 -0
  41. package/dist/esm/index.js +3 -0
  42. package/dist/esm/styles/avatars.js +59 -0
  43. package/dist/esm/styles/badges.js +55 -0
  44. package/dist/esm/styles/bottomSheets.js +72 -0
  45. package/dist/esm/styles/buttons.js +125 -0
  46. package/dist/esm/styles/cards.js +67 -0
  47. package/dist/esm/styles/checkboxes.js +66 -0
  48. package/dist/esm/styles/chips.js +94 -0
  49. package/dist/esm/styles/datePickers.js +108 -0
  50. package/dist/esm/styles/dividers.js +8 -0
  51. package/dist/esm/styles/emptyStates.js +36 -0
  52. package/dist/esm/styles/forms.js +28 -0
  53. package/dist/esm/styles/headers.js +42 -0
  54. package/dist/esm/styles/index.js +27 -0
  55. package/dist/esm/styles/inputs.js +97 -0
  56. package/dist/esm/styles/listItems.js +61 -0
  57. package/dist/esm/styles/modals.js +88 -0
  58. package/dist/esm/styles/pagination.js +35 -0
  59. package/dist/esm/styles/popovers.js +60 -0
  60. package/dist/esm/styles/progress.js +27 -0
  61. package/dist/esm/styles/radios.js +66 -0
  62. package/dist/esm/styles/selects.js +133 -0
  63. package/dist/esm/styles/skeletons.js +29 -0
  64. package/dist/esm/styles/steppers.js +66 -0
  65. package/dist/esm/styles/switches.js +72 -0
  66. package/dist/esm/styles/tables.js +53 -0
  67. package/dist/esm/styles/tabs.js +66 -0
  68. package/dist/esm/styles/toasts.js +77 -0
  69. package/dist/esm/styles/tooltips.js +42 -0
  70. package/dist/esm/types/index.js +2 -0
  71. package/dist/esm/types/states.js +3 -0
  72. package/dist/esm/types/tokens.js +12 -0
  73. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  74. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  75. package/dist/types/helpers/a11y.d.ts +20 -0
  76. package/dist/types/helpers/a11y.d.ts.map +1 -0
  77. package/dist/types/helpers/index.d.ts +3 -0
  78. package/dist/types/helpers/index.d.ts.map +1 -0
  79. package/dist/types/helpers/styles.d.ts +31 -0
  80. package/dist/types/helpers/styles.d.ts.map +1 -0
  81. package/dist/types/index.d.ts +4 -0
  82. package/dist/types/index.d.ts.map +1 -0
  83. package/dist/types/styles/avatars.d.ts +10 -0
  84. package/dist/types/styles/avatars.d.ts.map +1 -0
  85. package/dist/types/styles/badges.d.ts +8 -0
  86. package/dist/types/styles/badges.d.ts.map +1 -0
  87. package/dist/types/styles/bottomSheets.d.ts +15 -0
  88. package/dist/types/styles/bottomSheets.d.ts.map +1 -0
  89. package/dist/types/styles/buttons.d.ts +22 -0
  90. package/dist/types/styles/buttons.d.ts.map +1 -0
  91. package/dist/types/styles/cards.d.ts +18 -0
  92. package/dist/types/styles/cards.d.ts.map +1 -0
  93. package/dist/types/styles/checkboxes.d.ts +18 -0
  94. package/dist/types/styles/checkboxes.d.ts.map +1 -0
  95. package/dist/types/styles/chips.d.ts +20 -0
  96. package/dist/types/styles/chips.d.ts.map +1 -0
  97. package/dist/types/styles/datePickers.d.ts +30 -0
  98. package/dist/types/styles/datePickers.d.ts.map +1 -0
  99. package/dist/types/styles/dividers.d.ts +4 -0
  100. package/dist/types/styles/dividers.d.ts.map +1 -0
  101. package/dist/types/styles/emptyStates.d.ts +10 -0
  102. package/dist/types/styles/emptyStates.d.ts.map +1 -0
  103. package/dist/types/styles/forms.d.ts +10 -0
  104. package/dist/types/styles/forms.d.ts.map +1 -0
  105. package/dist/types/styles/headers.d.ts +11 -0
  106. package/dist/types/styles/headers.d.ts.map +1 -0
  107. package/dist/types/styles/index.d.ts +28 -0
  108. package/dist/types/styles/index.d.ts.map +1 -0
  109. package/dist/types/styles/inputs.d.ts +19 -0
  110. package/dist/types/styles/inputs.d.ts.map +1 -0
  111. package/dist/types/styles/listItems.d.ts +19 -0
  112. package/dist/types/styles/listItems.d.ts.map +1 -0
  113. package/dist/types/styles/modals.d.ts +15 -0
  114. package/dist/types/styles/modals.d.ts.map +1 -0
  115. package/dist/types/styles/pagination.d.ts +9 -0
  116. package/dist/types/styles/pagination.d.ts.map +1 -0
  117. package/dist/types/styles/popovers.d.ts +12 -0
  118. package/dist/types/styles/popovers.d.ts.map +1 -0
  119. package/dist/types/styles/progress.d.ts +11 -0
  120. package/dist/types/styles/progress.d.ts.map +1 -0
  121. package/dist/types/styles/radios.d.ts +17 -0
  122. package/dist/types/styles/radios.d.ts.map +1 -0
  123. package/dist/types/styles/selects.d.ts +25 -0
  124. package/dist/types/styles/selects.d.ts.map +1 -0
  125. package/dist/types/styles/skeletons.d.ts +13 -0
  126. package/dist/types/styles/skeletons.d.ts.map +1 -0
  127. package/dist/types/styles/steppers.d.ts +21 -0
  128. package/dist/types/styles/steppers.d.ts.map +1 -0
  129. package/dist/types/styles/switches.d.ts +17 -0
  130. package/dist/types/styles/switches.d.ts.map +1 -0
  131. package/dist/types/styles/tables.d.ts +13 -0
  132. package/dist/types/styles/tables.d.ts.map +1 -0
  133. package/dist/types/styles/tabs.d.ts +19 -0
  134. package/dist/types/styles/tabs.d.ts.map +1 -0
  135. package/dist/types/styles/toasts.d.ts +13 -0
  136. package/dist/types/styles/toasts.d.ts.map +1 -0
  137. package/dist/types/styles/tooltips.d.ts +9 -0
  138. package/dist/types/styles/tooltips.d.ts.map +1 -0
  139. package/dist/types/types/index.d.ts +3 -0
  140. package/dist/types/types/index.d.ts.map +1 -0
  141. package/dist/types/types/states.d.ts +26 -0
  142. package/dist/types/types/states.d.ts.map +1 -0
  143. package/dist/types/types/tokens.d.ts +16 -0
  144. package/dist/types/types/tokens.d.ts.map +1 -0
  145. package/package.json +73 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Fábio Maia
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,325 @@
1
+ # Component Specs (P0) — Buttons, Inputs, Modal, Card, Skeleton
2
+
3
+ > Objetivo: especificações **copy-paste** e **token-first** para futura implementação React (Web + Native).
4
+ > Regra: **todas as properties de estilo referenciam tokens** (ou tokens P0 adicionais explicitamente listados).
5
+
6
+ ---
7
+
8
+ ## 0) Convenções (aplicável a todos)
9
+
10
+ ### 0.1 Estados (nomenclatura)
11
+
12
+ - `default`
13
+ - `hover` (web) / `pressed` (native)
14
+ - `focus` (web) / `focus-visible` (web) / `focused` (native)
15
+ - `disabled`
16
+ - `loading` (quando aplicável)
17
+ - `error` (inputs)
18
+
19
+ ### 0.2 Motion (quando houver animação)
20
+
21
+ - Entrar (ex: Modal): `emphasis-enter` → `duration-regular` + `ease-emphasized`
22
+ - Sair (ex: Modal): `emphasis-exit` → `duration-fast` + `ease-accelerated`
23
+ - Micro feedback (hover/pressed): `micro-interaction` → `duration-fast` + `ease-standard`
24
+
25
+ ### 0.3 Acessibilidade (mínimos P0)
26
+
27
+ - Focus sempre visível: usar `color-focus-ring`.
28
+ - Conteúdo desativado: usar `color-state-disabled-bg` + `color-state-disabled-fg`.
29
+ - Texto: `font-family-base`, tamanhos `font-size-*`, pesos `font-weight-*`, line-height `line-height-*`.
30
+
31
+ ---
32
+
33
+ ## 1) Tokens P0 adicionais (para evitar “magic numbers”)
34
+
35
+ > Estes tokens **não estão no style guide base**, mas são recomendados para o pacote de tokens do DS,
36
+ > porque são muito usados em componentes e garantem consistência entre Web/RN.
37
+
38
+ | Token P0 sugerido | Papel | Valor sugerido (P0) |
39
+ |-----------------------------|--------------------------------------|---------------------|
40
+ | `border-width-default` | Borda padrão | `1px` |
41
+ | `border-width-focus` | Borda/outline em foco | `2px` |
42
+ | `opacity-pressed` | Feedback pressed (fallback) | `0.92` |
43
+ | `opacity-disabled` | Feedback disabled (fallback) | `1` *(preferir cores disabled)* |
44
+ | `tap-target-min` | Área mínima (touch) | `44px` |
45
+ | `focus-ring-gap` | Distância do ring ao componente | `2px` |
46
+
47
+ > Nota: sempre que possível, o “disabled” deve ser **por cor** (tokens) e não por opacity.
48
+
49
+ ---
50
+
51
+ ## 2) BUTTON (P0)
52
+
53
+ ### 2.1 Anatomia
54
+
55
+ - Container (pressable)
56
+ - Label (texto)
57
+ - (Opcional) Left icon / Right icon
58
+ - (Opcional) Spinner (loading)
59
+
60
+ ### 2.2 Variantes (cores por tema)
61
+
62
+ | Variant | Background token | Foreground token | Border token |
63
+ |-------------|-------------------------------|--------------------------------|-------------------------|
64
+ | `primary` | `color-action-primary` | `color-action-primary-fg` | `color-action-primary` |
65
+ | `secondary` | `color-action-secondary` | `color-action-secondary-fg` | `color-action-secondary`|
66
+ | `ghost` | `color-surface` *(ou transparente)* | `color-fg-default` | `color-border-subtle` |
67
+ | `danger` | `color-status-error` | `color-status-error-fg` | `color-status-error` |
68
+
69
+ > `ghost` usa fundo “neutro” para manter legibilidade cross-theme.
70
+
71
+ ### 2.3 Tamanhos (P0)
72
+
73
+ | Size | Font token | Padding Y token | Padding X token | Radius token | Min height |
74
+ |-------|----------------|-----------------|-----------------|-------------|-----------|
75
+ | `sm` | `font-size-2` | `space-2` | `space-3` | `radius-3` | `tap-target-min` |
76
+ | `md` | `font-size-3` | `space-2` | `space-4` | `radius-3` | `tap-target-min` |
77
+ | `lg` | `font-size-3` | `space-3` | `space-5` | `radius-3` | `tap-target-min` |
78
+
79
+ ### 2.4 Estilo (tokens por property)
80
+
81
+ **Container**
82
+
83
+ - `backgroundColor`: conforme variante (ex: `color-action-primary`)
84
+ - `borderColor`: conforme variante (ex: `color-action-primary`), ou `color-border-subtle` (ghost)
85
+ - `borderWidth`: `border-width-default`
86
+ - `borderRadius`: `radius-3`
87
+ - `paddingVertical`: `space-2` (md) / ver tabela
88
+ - `paddingHorizontal`: `space-4` (md) / ver tabela
89
+ - `shadow`:
90
+ - `default`: nenhum (ou `shadow-level-1` se quiseres botões “raised”)
91
+ - `hover` (web): `shadow-level-2`
92
+ - `pressed` (web+native): `shadow-level-1`
93
+
94
+ **Label**
95
+
96
+ - `color`: conforme variante (ex: `color-action-primary-fg`)
97
+ - `fontFamily`: `font-family-base`
98
+ - `fontSize`: conforme size (ex: `font-size-3`)
99
+ - `fontWeight`: `font-weight-medium`
100
+ - `lineHeight`: `line-height-default`
101
+
102
+ **Icon**
103
+
104
+ - `color`: igual ao label
105
+ - `size`: alinhado ao `font-size-*` do botão
106
+
107
+ ### 2.5 Estados
108
+
109
+ | State | O que muda (token-first) |
110
+ |--------------|---------------------------|
111
+ | `hover` | `shadow-level-2` + motion `micro-interaction` |
112
+ | `pressed` | `shadow-level-1` + (fallback) `opacity-pressed` |
113
+ | `focus` | `outlineColor`: `color-focus-ring` + `borderWidth`: `border-width-focus` |
114
+ | `disabled` | `backgroundColor`: `color-state-disabled-bg`, `labelColor`: `color-state-disabled-fg`, remover shadow |
115
+ | `loading` | manter cores da variante + mostrar spinner (spinner usa cor do label) |
116
+
117
+ ---
118
+
119
+ ## 3) INPUT (TextField) (P0)
120
+
121
+ ### 3.1 Anatomia
122
+
123
+ - Label (opcional)
124
+ - Field container (borda + fundo)
125
+ - Text input
126
+ - Helper text (opcional)
127
+ - Error text (opcional)
128
+ - (Opcional) Leading / trailing icon
129
+
130
+ ### 3.2 Estilo base (tokens por property)
131
+
132
+ **Label**
133
+
134
+ - `color`: `color-fg-muted`
135
+ - `fontFamily`: `font-family-base`
136
+ - `fontSize`: `font-size-2`
137
+ - `fontWeight`: `font-weight-medium`
138
+ - `lineHeight`: `line-height-default`
139
+ - `marginBottom`: `space-1`
140
+
141
+ **Field container**
142
+
143
+ - `backgroundColor`: `color-input-bg`
144
+ - `borderColor`: `color-input-border`
145
+ - `borderWidth`: `border-width-default`
146
+ - `borderRadius`: `radius-2`
147
+ - `paddingVertical`: `space-2`
148
+ - `paddingHorizontal`: `space-3`
149
+ - `shadow`: nenhum
150
+
151
+ **Text**
152
+
153
+ - `color`: `color-fg-default`
154
+ - `fontFamily`: `font-family-base`
155
+ - `fontSize`: `font-size-3`
156
+ - `lineHeight`: `line-height-default`
157
+
158
+ **Placeholder**
159
+
160
+ - `color`: `color-input-placeholder`
161
+
162
+ **Helper**
163
+
164
+ - `color`: `color-fg-subtle`
165
+ - `fontSize`: `font-size-1`
166
+ - `marginTop`: `space-1`
167
+
168
+ ### 3.3 Estados
169
+
170
+ | State | Border / Ring | Texto |
171
+ |--------------|---------------|-------|
172
+ | `default` | `borderColor: color-input-border` | `color-fg-default` |
173
+ | `focused` | `borderColor: color-input-border-focus` + ring `color-focus-ring` | idem |
174
+ | `disabled` | `backgroundColor: color-state-disabled-bg` | `color: color-state-disabled-fg` |
175
+ | `error` | `borderColor: color-status-error` + ring `color-status-error` | helper/error usa `color-status-error` |
176
+
177
+ > `error text` (linha abaixo):
178
+ >
179
+ > - `color`: `color-status-error`
180
+ > - `fontSize`: `font-size-1`
181
+ > - `marginTop`: `space-1`
182
+
183
+ ---
184
+
185
+ ## 4) MODAL / DIALOG (P0)
186
+
187
+ ### 4.1 Anatomia
188
+
189
+ - Backdrop (scrim)
190
+ - Surface (content)
191
+ - Header (título + optional close)
192
+ - Body
193
+ - Footer (ações)
194
+
195
+ ### 4.2 Camadas (z-layer)
196
+
197
+ - Backdrop: `z-layer-overlay`
198
+ - Modal surface: `z-layer-modal`
199
+
200
+ ### 4.3 Estilo (tokens por property)
201
+
202
+ **Backdrop**
203
+
204
+ - `backgroundColor`: `color-overlay-backdrop`
205
+ - `zIndex`: `z-layer-overlay`
206
+
207
+ **Surface**
208
+
209
+ - `backgroundColor`: `color-surface`
210
+ - `borderRadius`: `radius-4`
211
+ - `shadow`: `shadow-level-4`
212
+ - `padding`: `space-4` (mobile) / `space-5` (tablet/desktop)
213
+ - `zIndex`: `z-layer-modal`
214
+
215
+ **Header**
216
+
217
+ - `marginBottom`: `space-3`
218
+ - Title:
219
+ - `color`: `color-fg-default`
220
+ - `fontFamily`: `font-family-heading`
221
+ - `fontSize`: `font-size-5`
222
+ - `fontWeight`: `font-weight-strong`
223
+ - `lineHeight`: `line-height-tight`
224
+
225
+ **Body**
226
+
227
+ - `color`: `color-fg-default`
228
+ - `fontSize`: `font-size-3`
229
+ - `lineHeight`: `line-height-default`
230
+
231
+ **Footer**
232
+
233
+ - `marginTop`: `space-4`
234
+ - `gap` entre botões: `space-2`
235
+
236
+ ### 4.4 Motion
237
+
238
+ - Open: `emphasis-enter` (duration/easing tokens)
239
+ - Close: `emphasis-exit` (duration/easing tokens)
240
+
241
+ ---
242
+
243
+ ## 5) CARD (P0)
244
+
245
+ ### 5.1 Variantes
246
+
247
+ | Variant | Background token | Border token | Shadow token |
248
+ |----------------|-------------------|----------------------|---------------------|
249
+ | `default` | `color-surface` | `color-border-subtle`| `shadow-level-1` |
250
+ | `elevated` | `color-surface` | `color-border-subtle`| `shadow-level-2` |
251
+ | `highlight` | `color-surface-alt` | `color-border-strong` | `shadow-level-2` |
252
+
253
+ ### 5.2 Estilo base
254
+
255
+ - `backgroundColor`: conforme variante
256
+ - `borderColor`: conforme variante
257
+ - `borderWidth`: `border-width-default`
258
+ - `borderRadius`: `radius-3`
259
+ - `padding`: `space-4`
260
+ - `shadow`: conforme variante
261
+
262
+ **Título (opcional)**
263
+
264
+ - `color`: `color-fg-default`
265
+ - `fontFamily`: `font-family-heading`
266
+ - `fontSize`: `font-size-4`
267
+ - `fontWeight`: `font-weight-strong`
268
+ - `marginBottom`: `space-2`
269
+
270
+ **Texto**
271
+
272
+ - `color`: `color-fg-muted`
273
+ - `fontSize`: `font-size-3`
274
+ - `lineHeight`: `line-height-default`
275
+
276
+ ### 5.3 Interação (opcional)
277
+
278
+ - Hover (web): elevar `shadow-level-2` → `shadow-level-3` + motion `micro-interaction`
279
+
280
+ ---
281
+
282
+ ## 6) SKELETON (P0)
283
+
284
+ ### 6.1 Tipos
285
+
286
+ - `text-line` (linha)
287
+ - `avatar` (círculo)
288
+ - `block` (retângulo para cards/imagens)
289
+
290
+ ### 6.2 Estilo base (token-first)
291
+
292
+ - `backgroundColor`: `color-surface-alt`
293
+ - `borderRadius`:
294
+ - `text-line`: `radius-2`
295
+ - `block`: `radius-3`
296
+ - `avatar`: `radius-full`
297
+
298
+ ### 6.3 Spacing recomendada
299
+
300
+ - Entre linhas: `space-2`
301
+ - Dentro de cards: respeitar `padding` do card (`space-4`)
302
+
303
+ ### 6.4 Animação (opcional)
304
+
305
+ - `pulse` usando `duration-slower` + `ease-standard`
306
+
307
+ > Se quiseres shimmer “clássico”, recomenda-se criar tokens próprios (ex: `duration-skeleton`).
308
+
309
+ ---
310
+
311
+ ## 7) Checklist de implementação (para React Web + RN)
312
+
313
+ - Todos os componentes:
314
+ - Lêem tokens por tema (multi-tenant) e por modo (light/dark).
315
+ - Não têm cores hardcoded.
316
+ - Focus ring sempre: `color-focus-ring`.
317
+ - Botão:
318
+ - `disabled` via `color-state-disabled-*`
319
+ - `loading` sem mudar layout (substitui label por spinner com a mesma largura, quando possível).
320
+ - Input:
321
+ - `focused` usa `color-input-border-focus` + `color-focus-ring`
322
+ - `error` usa `color-status-error`
323
+ - Modal:
324
+ - Backdrop `color-overlay-backdrop` + layers `z-layer-*`
325
+ - Motion `emphasis-enter/exit`
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ // styles/a11y.checks.ts
3
+ // Checker WCAG AA para pares de tokens (bg/fg)
4
+ // - Útil para CI: garante contraste mínimo no tema (multi-tenant).
5
+ // - Sem deps externas.
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.assertThemeContrast = exports.getContrastFailures = exports.validateThemeContrast = exports.defaultContrastRules = void 0;
8
+ const clamp01 = (n) => Math.min(1, Math.max(0, n));
9
+ const parseHex = (hex) => {
10
+ // #RGB, #RRGGBB
11
+ const h = hex.trim();
12
+ if (!h.startsWith('#'))
13
+ return null;
14
+ const raw = h.slice(1);
15
+ if (raw.length === 3 && raw[0] && raw[1] && raw[2]) {
16
+ const r = Number.parseInt(raw[0] + raw[0], 16);
17
+ const g = Number.parseInt(raw[1] + raw[1], 16);
18
+ const b = Number.parseInt(raw[2] + raw[2], 16);
19
+ return { r, g, b, a: 1 };
20
+ }
21
+ if (raw.length === 6) {
22
+ const r = Number.parseInt(raw.slice(0, 2), 16);
23
+ const g = Number.parseInt(raw.slice(2, 4), 16);
24
+ const b = Number.parseInt(raw.slice(4, 6), 16);
25
+ return { r, g, b, a: 1 };
26
+ }
27
+ return null;
28
+ };
29
+ const parseRgbLike = (input) => {
30
+ // rgb(0,0,0) / rgba(0,0,0,0.5)
31
+ const m = input.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);
32
+ if (!m)
33
+ return null;
34
+ const r = Number(m[1]);
35
+ const g = Number(m[2]);
36
+ const b = Number(m[3]);
37
+ const a = m[4] ? Number(m[4]) : 1;
38
+ return { r, g, b, a: clamp01(a) };
39
+ };
40
+ const parseColor = (input) => {
41
+ if (typeof input !== 'string')
42
+ return null;
43
+ // Nota: se usares tokens tipo "var(--x)" isto não consegue resolver.
44
+ // Ideal: no tema final, tokens sejam cores concretas (#hex / rgb(a)).
45
+ return parseHex(input) ?? parseRgbLike(input);
46
+ };
47
+ const srgbToLinear = (c) => {
48
+ const v = c / 255;
49
+ return v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
50
+ };
51
+ const relativeLuminance = (rgb) => {
52
+ const r = srgbToLinear(rgb.r);
53
+ const g = srgbToLinear(rgb.g);
54
+ const b = srgbToLinear(rgb.b);
55
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
56
+ };
57
+ const contrastRatio = (a, b) => {
58
+ // WCAG formula (ignora alpha — assume cores finais já resolvidas)
59
+ const L1 = relativeLuminance(a);
60
+ const L2 = relativeLuminance(b);
61
+ const light = Math.max(L1, L2);
62
+ const dark = Math.min(L1, L2);
63
+ return (light + 0.05) / (dark + 0.05);
64
+ };
65
+ const threshold = (level, size) => {
66
+ if (level === 'AAA')
67
+ return size === 'large' ? 4.5 : 7;
68
+ return size === 'large' ? 3 : 4.5;
69
+ };
70
+ const defaultContrastRules = () => [
71
+ // Base surfaces
72
+ {
73
+ name: 'Default BG / Default FG',
74
+ bg: 'color-bg-default',
75
+ fg: 'color-fg-default',
76
+ },
77
+ { name: 'Surface / Default FG', bg: 'color-surface', fg: 'color-fg-default' },
78
+ {
79
+ name: 'Surface-alt / Default FG',
80
+ bg: 'color-surface-alt',
81
+ fg: 'color-fg-default',
82
+ },
83
+ {
84
+ name: 'Default BG / Muted FG',
85
+ bg: 'color-bg-default',
86
+ fg: 'color-fg-muted',
87
+ },
88
+ // Actions
89
+ {
90
+ name: 'Primary Action',
91
+ bg: 'color-action-primary',
92
+ fg: 'color-action-primary-fg',
93
+ },
94
+ {
95
+ name: 'Secondary Action',
96
+ bg: 'color-action-secondary',
97
+ fg: 'color-action-secondary-fg',
98
+ },
99
+ { name: 'Accent', bg: 'color-accent', fg: 'color-accent-fg' },
100
+ // Status
101
+ {
102
+ name: 'Success',
103
+ bg: 'color-status-success',
104
+ fg: 'color-status-success-fg',
105
+ },
106
+ {
107
+ name: 'Warning',
108
+ bg: 'color-status-warning',
109
+ fg: 'color-status-warning-fg',
110
+ },
111
+ { name: 'Error', bg: 'color-status-error', fg: 'color-status-error-fg' },
112
+ { name: 'Info', bg: 'color-status-info', fg: 'color-status-info-fg' },
113
+ // Inputs (texto/placeholder em fundo input)
114
+ {
115
+ name: 'Input BG / Default FG',
116
+ bg: 'color-input-bg',
117
+ fg: 'color-fg-default',
118
+ },
119
+ {
120
+ name: 'Input BG / Placeholder',
121
+ bg: 'color-input-bg',
122
+ fg: 'color-input-placeholder',
123
+ textSize: 'large',
124
+ }, // placeholder pode ser menos exigente; ajusta se quiseres
125
+ // Inverted (tooltip/overlays)
126
+ {
127
+ name: 'Inverted FG on Default FG',
128
+ bg: 'color-fg-default',
129
+ fg: 'color-fg-on-inverted',
130
+ },
131
+ // Disabled
132
+ {
133
+ name: 'Disabled BG / Disabled FG',
134
+ bg: 'color-state-disabled-bg',
135
+ fg: 'color-state-disabled-fg',
136
+ textSize: 'large',
137
+ },
138
+ ];
139
+ exports.defaultContrastRules = defaultContrastRules;
140
+ const validateThemeContrast = (tokens, rules = (0, exports.defaultContrastRules)()) => {
141
+ return rules.map((r) => {
142
+ const bgRaw = tokens[r.bg];
143
+ const fgRaw = tokens[r.fg];
144
+ const bg = parseColor(bgRaw);
145
+ const fg = parseColor(fgRaw);
146
+ // Se não conseguimos parse, falha (porque não dá para validar)
147
+ if (!bg || !fg) {
148
+ return {
149
+ rule: r,
150
+ contrastRatio: 0,
151
+ pass: false,
152
+ };
153
+ }
154
+ const ratio = contrastRatio(bg, fg);
155
+ const lvl = r.level ?? 'AA';
156
+ const size = r.textSize ?? 'normal';
157
+ const pass = ratio >= threshold(lvl, size);
158
+ return { rule: r, contrastRatio: ratio, pass };
159
+ });
160
+ };
161
+ exports.validateThemeContrast = validateThemeContrast;
162
+ const getContrastFailures = (results) => results.filter((r) => !r.pass);
163
+ exports.getContrastFailures = getContrastFailures;
164
+ const assertThemeContrast = (tokens, rules) => {
165
+ const results = (0, exports.validateThemeContrast)(tokens, rules);
166
+ const fails = (0, exports.getContrastFailures)(results);
167
+ if (fails.length === 0)
168
+ return;
169
+ const lines = fails.map((f) => {
170
+ const lvl = f.rule.level ?? 'AA';
171
+ const size = f.rule.textSize ?? 'normal';
172
+ return `- ${f.rule.name}: ${String(f.rule.bg)} / ${String(f.rule.fg)} => ${f.contrastRatio.toFixed(2)} (min ${threshold(lvl, size)})`;
173
+ });
174
+ throw new Error(`Theme contrast validation failed:\n${lines.join('\n')}`);
175
+ };
176
+ exports.assertThemeContrast = assertThemeContrast;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./a11y"), exports);
18
+ __exportStar(require("./styles"), exports);