@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.
- package/LICENSE +21 -0
- package/README.md +325 -0
- package/dist/cjs/helpers/a11y.js +176 -0
- package/dist/cjs/helpers/index.js +18 -0
- package/dist/cjs/helpers/styles.js +172 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/styles/avatars.js +63 -0
- package/dist/cjs/styles/badges.js +59 -0
- package/dist/cjs/styles/bottomSheets.js +76 -0
- package/dist/cjs/styles/buttons.js +129 -0
- package/dist/cjs/styles/cards.js +71 -0
- package/dist/cjs/styles/checkboxes.js +70 -0
- package/dist/cjs/styles/chips.js +98 -0
- package/dist/cjs/styles/datePickers.js +113 -0
- package/dist/cjs/styles/dividers.js +12 -0
- package/dist/cjs/styles/emptyStates.js +40 -0
- package/dist/cjs/styles/forms.js +32 -0
- package/dist/cjs/styles/headers.js +46 -0
- package/dist/cjs/styles/index.js +43 -0
- package/dist/cjs/styles/inputs.js +101 -0
- package/dist/cjs/styles/listItems.js +65 -0
- package/dist/cjs/styles/modals.js +92 -0
- package/dist/cjs/styles/pagination.js +39 -0
- package/dist/cjs/styles/popovers.js +64 -0
- package/dist/cjs/styles/progress.js +33 -0
- package/dist/cjs/styles/radios.js +70 -0
- package/dist/cjs/styles/selects.js +137 -0
- package/dist/cjs/styles/skeletons.js +34 -0
- package/dist/cjs/styles/steppers.js +71 -0
- package/dist/cjs/styles/switches.js +76 -0
- package/dist/cjs/styles/tables.js +57 -0
- package/dist/cjs/styles/tabs.js +71 -0
- package/dist/cjs/styles/toasts.js +82 -0
- package/dist/cjs/styles/tooltips.js +46 -0
- package/dist/cjs/types/index.js +18 -0
- package/dist/cjs/types/states.js +8 -0
- package/dist/cjs/types/tokens.js +18 -0
- package/dist/esm/helpers/a11y.js +169 -0
- package/dist/esm/helpers/index.js +2 -0
- package/dist/esm/helpers/styles.js +158 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/styles/avatars.js +59 -0
- package/dist/esm/styles/badges.js +55 -0
- package/dist/esm/styles/bottomSheets.js +72 -0
- package/dist/esm/styles/buttons.js +125 -0
- package/dist/esm/styles/cards.js +67 -0
- package/dist/esm/styles/checkboxes.js +66 -0
- package/dist/esm/styles/chips.js +94 -0
- package/dist/esm/styles/datePickers.js +108 -0
- package/dist/esm/styles/dividers.js +8 -0
- package/dist/esm/styles/emptyStates.js +36 -0
- package/dist/esm/styles/forms.js +28 -0
- package/dist/esm/styles/headers.js +42 -0
- package/dist/esm/styles/index.js +27 -0
- package/dist/esm/styles/inputs.js +97 -0
- package/dist/esm/styles/listItems.js +61 -0
- package/dist/esm/styles/modals.js +88 -0
- package/dist/esm/styles/pagination.js +35 -0
- package/dist/esm/styles/popovers.js +60 -0
- package/dist/esm/styles/progress.js +27 -0
- package/dist/esm/styles/radios.js +66 -0
- package/dist/esm/styles/selects.js +133 -0
- package/dist/esm/styles/skeletons.js +29 -0
- package/dist/esm/styles/steppers.js +66 -0
- package/dist/esm/styles/switches.js +72 -0
- package/dist/esm/styles/tables.js +53 -0
- package/dist/esm/styles/tabs.js +66 -0
- package/dist/esm/styles/toasts.js +77 -0
- package/dist/esm/styles/tooltips.js +42 -0
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/types/states.js +3 -0
- package/dist/esm/types/tokens.js +12 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/types/helpers/a11y.d.ts +20 -0
- package/dist/types/helpers/a11y.d.ts.map +1 -0
- package/dist/types/helpers/index.d.ts +3 -0
- package/dist/types/helpers/index.d.ts.map +1 -0
- package/dist/types/helpers/styles.d.ts +31 -0
- package/dist/types/helpers/styles.d.ts.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/styles/avatars.d.ts +10 -0
- package/dist/types/styles/avatars.d.ts.map +1 -0
- package/dist/types/styles/badges.d.ts +8 -0
- package/dist/types/styles/badges.d.ts.map +1 -0
- package/dist/types/styles/bottomSheets.d.ts +15 -0
- package/dist/types/styles/bottomSheets.d.ts.map +1 -0
- package/dist/types/styles/buttons.d.ts +22 -0
- package/dist/types/styles/buttons.d.ts.map +1 -0
- package/dist/types/styles/cards.d.ts +18 -0
- package/dist/types/styles/cards.d.ts.map +1 -0
- package/dist/types/styles/checkboxes.d.ts +18 -0
- package/dist/types/styles/checkboxes.d.ts.map +1 -0
- package/dist/types/styles/chips.d.ts +20 -0
- package/dist/types/styles/chips.d.ts.map +1 -0
- package/dist/types/styles/datePickers.d.ts +30 -0
- package/dist/types/styles/datePickers.d.ts.map +1 -0
- package/dist/types/styles/dividers.d.ts +4 -0
- package/dist/types/styles/dividers.d.ts.map +1 -0
- package/dist/types/styles/emptyStates.d.ts +10 -0
- package/dist/types/styles/emptyStates.d.ts.map +1 -0
- package/dist/types/styles/forms.d.ts +10 -0
- package/dist/types/styles/forms.d.ts.map +1 -0
- package/dist/types/styles/headers.d.ts +11 -0
- package/dist/types/styles/headers.d.ts.map +1 -0
- package/dist/types/styles/index.d.ts +28 -0
- package/dist/types/styles/index.d.ts.map +1 -0
- package/dist/types/styles/inputs.d.ts +19 -0
- package/dist/types/styles/inputs.d.ts.map +1 -0
- package/dist/types/styles/listItems.d.ts +19 -0
- package/dist/types/styles/listItems.d.ts.map +1 -0
- package/dist/types/styles/modals.d.ts +15 -0
- package/dist/types/styles/modals.d.ts.map +1 -0
- package/dist/types/styles/pagination.d.ts +9 -0
- package/dist/types/styles/pagination.d.ts.map +1 -0
- package/dist/types/styles/popovers.d.ts +12 -0
- package/dist/types/styles/popovers.d.ts.map +1 -0
- package/dist/types/styles/progress.d.ts +11 -0
- package/dist/types/styles/progress.d.ts.map +1 -0
- package/dist/types/styles/radios.d.ts +17 -0
- package/dist/types/styles/radios.d.ts.map +1 -0
- package/dist/types/styles/selects.d.ts +25 -0
- package/dist/types/styles/selects.d.ts.map +1 -0
- package/dist/types/styles/skeletons.d.ts +13 -0
- package/dist/types/styles/skeletons.d.ts.map +1 -0
- package/dist/types/styles/steppers.d.ts +21 -0
- package/dist/types/styles/steppers.d.ts.map +1 -0
- package/dist/types/styles/switches.d.ts +17 -0
- package/dist/types/styles/switches.d.ts.map +1 -0
- package/dist/types/styles/tables.d.ts +13 -0
- package/dist/types/styles/tables.d.ts.map +1 -0
- package/dist/types/styles/tabs.d.ts +19 -0
- package/dist/types/styles/tabs.d.ts.map +1 -0
- package/dist/types/styles/toasts.d.ts +13 -0
- package/dist/types/styles/toasts.d.ts.map +1 -0
- package/dist/types/styles/tooltips.d.ts +9 -0
- package/dist/types/styles/tooltips.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +3 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/types/states.d.ts +26 -0
- package/dist/types/types/states.d.ts.map +1 -0
- package/dist/types/types/tokens.d.ts +16 -0
- package/dist/types/types/tokens.d.ts.map +1 -0
- 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);
|