@aurea-uds/native 0.8.6 → 0.8.8
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/actions.js +34 -7
- package/dist/barranav.d.ts +52 -0
- package/dist/barranav.js +81 -0
- package/dist/busca.js +32 -25
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/inputs.d.ts +9 -1
- package/dist/inputs.js +56 -12
- package/dist/layout.js +32 -2
- package/dist/navigation.d.ts +49 -14
- package/dist/navigation.js +87 -19
- package/dist/numero.d.ts +11 -0
- package/dist/numero.js +52 -2
- package/dist/overlays.js +10 -10
- package/dist/screen.js +13 -1
- package/dist/text.js +31 -1
- package/dist/theme.d.ts +58 -5
- package/dist/theme.js +51 -20
- package/package.json +2 -2
package/dist/navigation.d.ts
CHANGED
|
@@ -33,31 +33,66 @@ export interface BottomNavProps extends ViewProps {
|
|
|
33
33
|
* ]} />
|
|
34
34
|
* ```
|
|
35
35
|
*
|
|
36
|
-
* ⚠ **Ela respeita a
|
|
37
|
-
* `
|
|
38
|
-
*
|
|
39
|
-
*
|
|
36
|
+
* ⚠ **Ela respeita a área do sistema sozinha, e desde 19/09/2026 POR FORA da pílula.** No
|
|
37
|
+
* `floating` a folga vira `marginBottom`: a borda de baixo fica exatamente `space4` acima do topo
|
|
38
|
+
* da área do sistema, seja ela a faixa dos três botões do Android (≈48), a linha de gesto (≈16)
|
|
39
|
+
* ou o indicador do iPhone. No `edge`, que encosta na borda, ela continua sendo recheio por
|
|
40
|
+
* dentro — igual à web, onde `.bottom-nav-edge` faz exatamente isso.
|
|
40
41
|
*
|
|
41
42
|
* ⚠ **Não é `Tabs`, e isso é decisão registrada**, não esquecimento — ver o bloco acima.
|
|
42
43
|
*
|
|
43
|
-
*
|
|
44
|
-
* barra é IRMÃ da tela, não filha: é assim que se põe uma barra fixa no RN. Só que o `Screen`
|
|
45
|
-
* pinta o tema **na própria raiz**, então o que aparece atrás desta barra é a raiz do SEU app —
|
|
46
|
-
* e raiz sem cor, no Android, é **BRANCA**. Num app de tema escuro isso é uma faixa branca no pé
|
|
47
|
-
* da tela. Envolva os dois num `View` com `flex: 1` e `backgroundColor: tokens.color.background`:
|
|
44
|
+
* ── COMO MONTAR AS ABAS, com `expo-router` ou `react-navigation` ─────────────────────────────
|
|
48
45
|
*
|
|
49
46
|
* ```tsx
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
47
|
+
* import {Tabs} from "expo-router";
|
|
48
|
+
* import {BottomNav, BottomNavProvider} from "@aurea-uds/native";
|
|
49
|
+
*
|
|
50
|
+
* const ROTAS = [
|
|
51
|
+
* {name: "index", titulo: "Início", icone: "home"},
|
|
52
|
+
* {name: "perfil", titulo: "Perfil", icone: "user"},
|
|
53
|
+
* ];
|
|
54
|
+
*
|
|
55
|
+
* <BottomNavProvider>
|
|
56
|
+
* <Tabs
|
|
57
|
+
* screenOptions={{headerShown: false}}
|
|
58
|
+
* tabBar={({state, navigation}) => (
|
|
59
|
+
* <BottomNav
|
|
60
|
+
* label="Menu principal"
|
|
61
|
+
* current={state.routes[state.index].name}
|
|
62
|
+
* items={ROTAS.map((r) => ({
|
|
63
|
+
* id: r.name, label: r.titulo, icon: r.icone,
|
|
64
|
+
* onPress: () => navigation.navigate(r.name),
|
|
65
|
+
* }))} />
|
|
66
|
+
* )} />
|
|
67
|
+
* </BottomNavProvider>
|
|
55
68
|
* ```
|
|
56
69
|
*
|
|
70
|
+
* E as telas, sem conta nenhuma de respiro: `<Screen scroll edges={["top"]}>`.
|
|
71
|
+
*
|
|
72
|
+
* 🔴 **O `BottomNav` VAI SOLTO NO `tabBar`, SEM `View` EM VOLTA — e esta linha já mandou o
|
|
73
|
+
* contrário.** Até a `0.8.7` a documentação aqui mandava embrulhar a barra num `View` pintado com
|
|
74
|
+
* o fundo do tema, porque a barra ficava no FLUXO e o que aparecia atrás dela era a raiz do app,
|
|
75
|
+
* que no Android é branca. O consumidor seguiu, e o resultado em aparelho foi uma **caixa cinza
|
|
76
|
+
* em volta da pílula**: ela não flutuava, e a tela terminava acima dela.
|
|
77
|
+
*
|
|
78
|
+
* ✅ **Hoje o `floating` é `position: absolute`** — ele sai do fluxo e passa por cima da tela,
|
|
79
|
+
* que volta a ocupar a altura inteira. Não há nada atrás da pílula para pintar, então **o
|
|
80
|
+
* embrulho não é mais necessário e atrapalha**: ele é quem desenha a faixa.
|
|
81
|
+
*
|
|
82
|
+
* ⚠ **O `edge` continua no fluxo**, e para ELE o conselho antigo continua valendo: embrulhe os
|
|
83
|
+
* dois num `View` com `flex: 1` e `backgroundColor: t.color.background`, senão sobra a faixa
|
|
84
|
+
* branca do Android no pé da tela.
|
|
85
|
+
*
|
|
57
86
|
* ⚠ **E o sintoma engana.** Visto em foto no aparelho em 10/09/2026: com a faixa branca a barra
|
|
58
87
|
* *parece* flutuando longe do pé, que é exatamente o sinal de que o respiro virou SOMA em vez de
|
|
59
88
|
* `Math.max`. A conta estava certa; o branco é que empurrava a leitura. **Antes de acusar a
|
|
60
89
|
* aritmética, pinte o fundo.**
|
|
90
|
+
*
|
|
91
|
+
* 🔴 **FLUTUAR TEM UM PREÇO, E A BIBLIOTECA É QUEM PAGA:** o fim da rolagem fica atrás da pílula.
|
|
92
|
+
* É para isso que o `BottomNavProvider` existe — a barra mede a própria altura e conta para ele,
|
|
93
|
+
* e o `Screen scroll` reserva o espaço sozinho. **O app não calcula nada.** Para uma tela que não
|
|
94
|
+
* usa `Screen` (uma fileira de botões presa no pé, por exemplo), o número está em
|
|
95
|
+
* `useBottomNavSpace()`. Fora de um provedor os dois valem zero, e nada muda.
|
|
61
96
|
*/
|
|
62
97
|
export declare function BottomNav({ items, current, variant, indicator, label, style, ...rest }: BottomNavProps): React.JSX.Element;
|
|
63
98
|
export type AureaTopbarVariant = "floating" | "flush" | "pill";
|
package/dist/navigation.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Pressable, View } from "react-native";
|
|
3
3
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
4
|
+
import { useAnotarBottomNav } from "./barranav.js";
|
|
4
5
|
import { Badge } from "./display.js";
|
|
5
6
|
import { comOpacidade, criarFolha } from "./estilos.js";
|
|
6
7
|
import { Icon } from "./icon.js";
|
|
@@ -32,14 +33,28 @@ const folha = criarFolha((t) => ({
|
|
|
32
33
|
borderRadius: t.size.radiusControl, backgroundColor: t.color.card,
|
|
33
34
|
},
|
|
34
35
|
// ── BottomNav ──────────────────────────────────────────────────────────────────────────────
|
|
36
|
+
// 🔴 `floating` FLUTUA POR CIMA DA TELA, e isto é conserto de 19/09/2026 — a variante prometia
|
|
37
|
+
// isso no nome e não fazia. `position: absolute` a tira do fluxo: a tela passa a ocupar a altura
|
|
38
|
+
// inteira e rola POR BAIXO da pílula. É o mesmo que a web faz desde sempre com
|
|
39
|
+
// `position: sticky; bottom: 0` (`aurea.css:270`) — a divergência era só deste lado.
|
|
40
|
+
//
|
|
41
|
+
// ⚠ **As margens são o que deixa o toque passar.** Com `left/right/bottom: 0` e `margin`, a
|
|
42
|
+
// caixa deste `View` É a pílula: o que sobra em volta não pertence a ela, e o dedo encontra a
|
|
43
|
+
// tela de baixo. Se a barra fosse uma faixa de largura cheia com a pílula centralizada dentro,
|
|
44
|
+
// a faixa comeria o toque em silêncio.
|
|
45
|
+
//
|
|
46
|
+
// `zSticky` é token (20), o mesmo `--z-sticky` que a web usa na mesma peça.
|
|
35
47
|
barra: {
|
|
48
|
+
position: "absolute", left: 0, right: 0, bottom: 0, zIndex: t.size.zSticky,
|
|
36
49
|
flexDirection: "row", gap: t.size.space1, margin: t.size.space4, padding: t.size.space1,
|
|
37
50
|
borderWidth: t.size.borderWidth, borderColor: t.color.border,
|
|
38
51
|
borderRadius: t.size.radiusControl, backgroundColor: t.color.card,
|
|
39
52
|
boxShadow: [t.shadow.shadowMd],
|
|
40
53
|
},
|
|
41
|
-
// `edge` encosta na borda: sem margem, sem raio, só a linha de cima
|
|
54
|
+
// `edge` encosta na borda: sem margem, sem raio, só a linha de cima — e continua NO FLUXO,
|
|
55
|
+
// porque uma barra encostada que flutuasse esconderia o fim da tela sem nada reservar.
|
|
42
56
|
barra_edge: {
|
|
57
|
+
position: "relative", left: undefined, right: undefined, bottom: undefined, zIndex: undefined,
|
|
43
58
|
margin: 0, paddingHorizontal: 0, borderRadius: 0, backgroundColor: t.color.background,
|
|
44
59
|
borderWidth: 0, borderTopWidth: t.size.borderWidth, boxShadow: undefined,
|
|
45
60
|
},
|
|
@@ -112,31 +127,66 @@ const folha = criarFolha((t) => ({
|
|
|
112
127
|
* ]} />
|
|
113
128
|
* ```
|
|
114
129
|
*
|
|
115
|
-
* ⚠ **Ela respeita a
|
|
116
|
-
* `
|
|
117
|
-
*
|
|
118
|
-
*
|
|
130
|
+
* ⚠ **Ela respeita a área do sistema sozinha, e desde 19/09/2026 POR FORA da pílula.** No
|
|
131
|
+
* `floating` a folga vira `marginBottom`: a borda de baixo fica exatamente `space4` acima do topo
|
|
132
|
+
* da área do sistema, seja ela a faixa dos três botões do Android (≈48), a linha de gesto (≈16)
|
|
133
|
+
* ou o indicador do iPhone. No `edge`, que encosta na borda, ela continua sendo recheio por
|
|
134
|
+
* dentro — igual à web, onde `.bottom-nav-edge` faz exatamente isso.
|
|
119
135
|
*
|
|
120
136
|
* ⚠ **Não é `Tabs`, e isso é decisão registrada**, não esquecimento — ver o bloco acima.
|
|
121
137
|
*
|
|
122
|
-
*
|
|
123
|
-
* barra é IRMÃ da tela, não filha: é assim que se põe uma barra fixa no RN. Só que o `Screen`
|
|
124
|
-
* pinta o tema **na própria raiz**, então o que aparece atrás desta barra é a raiz do SEU app —
|
|
125
|
-
* e raiz sem cor, no Android, é **BRANCA**. Num app de tema escuro isso é uma faixa branca no pé
|
|
126
|
-
* da tela. Envolva os dois num `View` com `flex: 1` e `backgroundColor: tokens.color.background`:
|
|
138
|
+
* ── COMO MONTAR AS ABAS, com `expo-router` ou `react-navigation` ─────────────────────────────
|
|
127
139
|
*
|
|
128
140
|
* ```tsx
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
141
|
+
* import {Tabs} from "expo-router";
|
|
142
|
+
* import {BottomNav, BottomNavProvider} from "@aurea-uds/native";
|
|
143
|
+
*
|
|
144
|
+
* const ROTAS = [
|
|
145
|
+
* {name: "index", titulo: "Início", icone: "home"},
|
|
146
|
+
* {name: "perfil", titulo: "Perfil", icone: "user"},
|
|
147
|
+
* ];
|
|
148
|
+
*
|
|
149
|
+
* <BottomNavProvider>
|
|
150
|
+
* <Tabs
|
|
151
|
+
* screenOptions={{headerShown: false}}
|
|
152
|
+
* tabBar={({state, navigation}) => (
|
|
153
|
+
* <BottomNav
|
|
154
|
+
* label="Menu principal"
|
|
155
|
+
* current={state.routes[state.index].name}
|
|
156
|
+
* items={ROTAS.map((r) => ({
|
|
157
|
+
* id: r.name, label: r.titulo, icon: r.icone,
|
|
158
|
+
* onPress: () => navigation.navigate(r.name),
|
|
159
|
+
* }))} />
|
|
160
|
+
* )} />
|
|
161
|
+
* </BottomNavProvider>
|
|
134
162
|
* ```
|
|
135
163
|
*
|
|
164
|
+
* E as telas, sem conta nenhuma de respiro: `<Screen scroll edges={["top"]}>`.
|
|
165
|
+
*
|
|
166
|
+
* 🔴 **O `BottomNav` VAI SOLTO NO `tabBar`, SEM `View` EM VOLTA — e esta linha já mandou o
|
|
167
|
+
* contrário.** Até a `0.8.7` a documentação aqui mandava embrulhar a barra num `View` pintado com
|
|
168
|
+
* o fundo do tema, porque a barra ficava no FLUXO e o que aparecia atrás dela era a raiz do app,
|
|
169
|
+
* que no Android é branca. O consumidor seguiu, e o resultado em aparelho foi uma **caixa cinza
|
|
170
|
+
* em volta da pílula**: ela não flutuava, e a tela terminava acima dela.
|
|
171
|
+
*
|
|
172
|
+
* ✅ **Hoje o `floating` é `position: absolute`** — ele sai do fluxo e passa por cima da tela,
|
|
173
|
+
* que volta a ocupar a altura inteira. Não há nada atrás da pílula para pintar, então **o
|
|
174
|
+
* embrulho não é mais necessário e atrapalha**: ele é quem desenha a faixa.
|
|
175
|
+
*
|
|
176
|
+
* ⚠ **O `edge` continua no fluxo**, e para ELE o conselho antigo continua valendo: embrulhe os
|
|
177
|
+
* dois num `View` com `flex: 1` e `backgroundColor: t.color.background`, senão sobra a faixa
|
|
178
|
+
* branca do Android no pé da tela.
|
|
179
|
+
*
|
|
136
180
|
* ⚠ **E o sintoma engana.** Visto em foto no aparelho em 10/09/2026: com a faixa branca a barra
|
|
137
181
|
* *parece* flutuando longe do pé, que é exatamente o sinal de que o respiro virou SOMA em vez de
|
|
138
182
|
* `Math.max`. A conta estava certa; o branco é que empurrava a leitura. **Antes de acusar a
|
|
139
183
|
* aritmética, pinte o fundo.**
|
|
184
|
+
*
|
|
185
|
+
* 🔴 **FLUTUAR TEM UM PREÇO, E A BIBLIOTECA É QUEM PAGA:** o fim da rolagem fica atrás da pílula.
|
|
186
|
+
* É para isso que o `BottomNavProvider` existe — a barra mede a própria altura e conta para ele,
|
|
187
|
+
* e o `Screen scroll` reserva o espaço sozinho. **O app não calcula nada.** Para uma tela que não
|
|
188
|
+
* usa `Screen` (uma fileira de botões presa no pé, por exemplo), o número está em
|
|
189
|
+
* `useBottomNavSpace()`. Fora de um provedor os dois valem zero, e nada muda.
|
|
140
190
|
*/
|
|
141
191
|
export function BottomNav({ items, current, variant = "floating", indicator = "none", label, style, ...rest }) {
|
|
142
192
|
const t = useAureaTokens();
|
|
@@ -144,11 +194,29 @@ export function BottomNav({ items, current, variant = "floating", indicator = "n
|
|
|
144
194
|
const strings = useAureaStrings();
|
|
145
195
|
const inset = useSafeAreaInsets();
|
|
146
196
|
const redondo = indicator.startsWith("circle");
|
|
147
|
-
|
|
197
|
+
const anotar = useAnotarBottomNav();
|
|
198
|
+
const flutua = variant !== "edge";
|
|
199
|
+
return (_jsx(View, { accessibilityLabel: label ?? strings.bottomNavLabel,
|
|
200
|
+
// 🔴 A BARRA CONTA A PRÓPRIA ALTURA — é o que permite o `Screen` reservar o fim da rolagem
|
|
201
|
+
// sem o app calcular nada. A conta é a pílula (o que o layout mede) mais as DUAS margens
|
|
202
|
+
// mais a folga do sistema; `edge` conta zero, porque ela fica no fluxo e já encurta a tela.
|
|
203
|
+
onLayout: anotar == null ? undefined : (e) => anotar(flutua ? e.nativeEvent.layout.height + t.size.space4 * 2 + inset.bottom : 0), style: [
|
|
148
204
|
s.barra, variant === "edge" && s.barra_edge,
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
|
|
205
|
+
// 🔴 NO `floating` A FOLGA DO SISTEMA VAI POR FORA — conserto de 19/09/2026, visto em
|
|
206
|
+
// aparelho Samsung com os três botões (|||, ○, <).
|
|
207
|
+
//
|
|
208
|
+
// Antes, os ≈48 pontos da faixa do sistema entravam como RECHEIO dentro da pílula: ela
|
|
209
|
+
// crescia para baixo e a barriga dela ficava atrás dos botões. A `margin: space4` não
|
|
210
|
+
// compensava, porque o que cresceu foi o miolo.
|
|
211
|
+
//
|
|
212
|
+
// Agora: recheio de baixo igual aos outros lados, e a folga empurra a pílula para cima.
|
|
213
|
+
// A borda de baixo fica exatamente `space4` acima do topo da área do sistema, em aparelho
|
|
214
|
+
// de botões, de gesto ou com o indicador do iPhone — os três caem na mesma conta.
|
|
215
|
+
flutua
|
|
216
|
+
? { paddingBottom: t.size.space1, marginBottom: t.size.space4 + inset.bottom }
|
|
217
|
+
// `edge` NÃO MUDA: encostada na borda, a folga é recheio mesmo, senão sobraria uma
|
|
218
|
+
// faixa de fundo entre a barra e o pé da tela. `max` e não soma, como sempre foi.
|
|
219
|
+
: { paddingBottom: Math.max(t.size.space1, inset.bottom) },
|
|
152
220
|
style,
|
|
153
221
|
], ...rest, children: items.map((it) => {
|
|
154
222
|
const ativo = it.id === current;
|
package/dist/numero.d.ts
CHANGED
|
@@ -103,6 +103,17 @@ type IconNameLocal = string;
|
|
|
103
103
|
*
|
|
104
104
|
* ⚠ **Formata no blur, e só no blur.** Enquanto o campo tem foco, ele mostra exatamente o que foi
|
|
105
105
|
* digitado — essa é a decisão inteira da ADR-0024, e o teste que a cobra está no lote.
|
|
106
|
+
*
|
|
107
|
+
* ⚠ **`onValueChange` dispara a CADA TECLA**, com o número lido pelas regras do `locale` — "12,"
|
|
108
|
+
* em pt-BR entrega `12`, "1.234,5" entrega `1234.5`, apagar tudo entrega `null`. Texto que ainda
|
|
109
|
+
* não é número (só "," ou só "-") não dispara nada. **`min`/`max` NÃO prendem durante a
|
|
110
|
+
* digitação**, só no blur — e se prender mudar o número, ele é emitido de novo.
|
|
111
|
+
*
|
|
112
|
+
* ⚠ **Com FOCO, quem manda é quem digita.** Se o pai trocar o `value` por outro número enquanto o
|
|
113
|
+
* campo está sendo editado, o texto na tela **não muda** — inclusive quando o pai só devolve o
|
|
114
|
+
* mesmo número que acabou de receber, que é o caso comum de um `useState` controlado. Sem foco, o
|
|
115
|
+
* campo obedece ao `value` e mostra o número novo formatado, que é o que faz um campo calculado a
|
|
116
|
+
* partir de outros dois funcionar.
|
|
106
117
|
*/
|
|
107
118
|
export declare function NumberField({ value, defaultValue, onValueChange, min, max, step, format, locale, disabled, readOnly, size, fullWidth, label, placeholder, keyboardType, icons, style, testID, }: NumberFieldProps): React.JSX.Element;
|
|
108
119
|
export {};
|
package/dist/numero.js
CHANGED
|
@@ -49,7 +49,7 @@ import { Platform, TextInput, View } from "react-native";
|
|
|
49
49
|
import { IconButton } from "./actions.js";
|
|
50
50
|
import { criarFolha } from "./estilos.js";
|
|
51
51
|
import { useCampo } from "./inputs.js";
|
|
52
|
-
import { useAureaStrings, useAureaTokens } from "./theme.js";
|
|
52
|
+
import { useAureaStrings, useAureaTokens, usePeleSobreAMarca } from "./theme.js";
|
|
53
53
|
const alturaDoTamanho = (t, s) => s === "sm" ? t.size.controlHSm : s === "lg" ? t.size.controlHLg : t.size.controlHMd;
|
|
54
54
|
const fonteDoTamanho = (t, s) => s === "sm" ? t.size.textXs : s === "lg" ? t.size.textBase : t.size.textMd;
|
|
55
55
|
const folha = criarFolha((t) => ({
|
|
@@ -231,10 +231,22 @@ const paraEdicao = (n, locale) => {
|
|
|
231
231
|
*
|
|
232
232
|
* ⚠ **Formata no blur, e só no blur.** Enquanto o campo tem foco, ele mostra exatamente o que foi
|
|
233
233
|
* digitado — essa é a decisão inteira da ADR-0024, e o teste que a cobra está no lote.
|
|
234
|
+
*
|
|
235
|
+
* ⚠ **`onValueChange` dispara a CADA TECLA**, com o número lido pelas regras do `locale` — "12,"
|
|
236
|
+
* em pt-BR entrega `12`, "1.234,5" entrega `1234.5`, apagar tudo entrega `null`. Texto que ainda
|
|
237
|
+
* não é número (só "," ou só "-") não dispara nada. **`min`/`max` NÃO prendem durante a
|
|
238
|
+
* digitação**, só no blur — e se prender mudar o número, ele é emitido de novo.
|
|
239
|
+
*
|
|
240
|
+
* ⚠ **Com FOCO, quem manda é quem digita.** Se o pai trocar o `value` por outro número enquanto o
|
|
241
|
+
* campo está sendo editado, o texto na tela **não muda** — inclusive quando o pai só devolve o
|
|
242
|
+
* mesmo número que acabou de receber, que é o caso comum de um `useState` controlado. Sem foco, o
|
|
243
|
+
* campo obedece ao `value` e mostra o número novo formatado, que é o que faz um campo calculado a
|
|
244
|
+
* partir de outros dois funcionar.
|
|
234
245
|
*/
|
|
235
246
|
export function NumberField({ value, defaultValue, onValueChange, min, max, step = 1, format, locale, disabled, readOnly, size, fullWidth = false, label, placeholder, keyboardType, icons = { increment: "add", decrement: "subtract" }, style, testID, }) {
|
|
236
247
|
const t = useAureaTokens();
|
|
237
248
|
const s = folha(t);
|
|
249
|
+
const peleDaMarca = usePeleSobreAMarca();
|
|
238
250
|
const strings = useAureaStrings();
|
|
239
251
|
const campo = useCampo();
|
|
240
252
|
const tam = size ?? campo?.size ?? "md";
|
|
@@ -276,8 +288,41 @@ export function NumberField({ value, defaultValue, onValueChange, min, max, step
|
|
|
276
288
|
emitir(null);
|
|
277
289
|
return;
|
|
278
290
|
}
|
|
291
|
+
// ⚠ **Só aqui é que `min`/`max` prendem**, e é no blur de propósito — ver `digitar` abaixo.
|
|
292
|
+
// Se prender mudou o número, o pai recebe o preso: quem ouviu "1" durante a digitação precisa
|
|
293
|
+
// ouvir o "10" final, senão fica com um valor que o campo não mostra mais.
|
|
279
294
|
emitir(prender(lido, min, max));
|
|
280
295
|
}, [emEdicao, locale, emitir, min, max]);
|
|
296
|
+
// 🔴 CADA TECLA ENTREGA O NÚMERO — e isto é conserto de defeito que GRAVA DADO ERRADO, não
|
|
297
|
+
// refinamento. Achado pelo consumidor em aparelho, 19/09/2026.
|
|
298
|
+
//
|
|
299
|
+
// Antes, `onChangeText` só guardava o texto aqui dentro e o pai só era avisado no blur. Num
|
|
300
|
+
// cartão com o campo e o botão de confirmar lado a lado, o `Screen` tem
|
|
301
|
+
// `keyboardShouldPersistTaps="handled"` (`screen.tsx:154`) — então o toque no botão CHEGA ao
|
|
302
|
+
// botão sem passar pelo blur. O `onPress` roda com o valor ANTIGO.
|
|
303
|
+
//
|
|
304
|
+
// ⚠ **A cara disso na tela é "o campo está vazio"**, e o dano real é maior e mudo: num
|
|
305
|
+
// formulário que corrige um número já salvo, tocar em Salvar com o teclado aberto regrava o
|
|
306
|
+
// número velho, sem erro e sem aviso.
|
|
307
|
+
//
|
|
308
|
+
// O que NÃO muda com isto, e é a ADR-0024 inteira: o campo continua mostrando o que foi
|
|
309
|
+
// digitado enquanto tem foco (`emEdicao` é quem manda em `mostrar`), e continua formatando só
|
|
310
|
+
// no blur. **Digitar nunca é interrompido** — nem pelo formato, nem pelo eco do pai: enquanto
|
|
311
|
+
// `emEdicao` não é `null`, nada que venha por `value` reescreve o texto.
|
|
312
|
+
const digitar = React.useCallback((texto) => {
|
|
313
|
+
setEmEdicao(texto);
|
|
314
|
+
const lido = lerNumero(texto, locale);
|
|
315
|
+
// Apagar tudo é VAZIO, que é diferente de ilegível: o vazio é uma intenção e vira `null`.
|
|
316
|
+
if (lido == null) {
|
|
317
|
+
if (texto.trim() === "")
|
|
318
|
+
emitir(null);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
// ⚠ **NÃO prende aqui.** Com `min={10}`, prender durante a digitação faria o "1" virar 10 na
|
|
322
|
+
// cara de quem ainda ia digitar o "5" de 15 — o campo escreveria por cima da pessoa. Prender
|
|
323
|
+
// é do blur, e só.
|
|
324
|
+
emitir(lido);
|
|
325
|
+
}, [locale, emitir]);
|
|
281
326
|
const empurrar = React.useCallback((direcao) => {
|
|
282
327
|
// Se o campo está sendo editado, o que vale é o que está escrito — empurrar por cima do valor
|
|
283
328
|
// antigo descartaria a digitação em silêncio.
|
|
@@ -310,7 +355,7 @@ export function NumberField({ value, defaultValue, onValueChange, min, max, step
|
|
|
310
355
|
// (`aurea.css:685`), com os dois botões FORA dela. O estado que faltava é o deles; a geometria
|
|
311
356
|
// continua sendo a nossa.
|
|
312
357
|
const [focado, setFocado] = React.useState(false);
|
|
313
|
-
return (_jsxs(View, { testID: testID, style: [s.grupo, fullWidth && s.grupoLargo, inativo && s.desabilitado, style], children: [mostrarBotoes && (_jsx(IconButton, { name: icons.decrement, label: strings.decrement, appearance: "ghost", size: tam, disabled: inativo || noLimite(-1), onPress: () => empurrar(-1), testID: testID ? `${testID}-menos` : undefined })), _jsx(TextInput, { testID: testID ? `${testID}-campo` : undefined, value: mostrar, onChangeText:
|
|
358
|
+
return (_jsxs(View, { testID: testID, style: [s.grupo, fullWidth && s.grupoLargo, inativo && s.desabilitado, style], children: [mostrarBotoes && (_jsx(IconButton, { name: icons.decrement, label: strings.decrement, appearance: "ghost", size: tam, disabled: inativo || noLimite(-1), onPress: () => empurrar(-1), testID: testID ? `${testID}-menos` : undefined })), _jsx(TextInput, { testID: testID ? `${testID}-campo` : undefined, value: mostrar, onChangeText: digitar, onFocus: () => { setFocado(true); setEmEdicao(paraEdicao(numero, locale)); }, onBlur: () => { setFocado(false); confirmar(); }, editable: !inativo && !readOnly, placeholder: placeholder, placeholderTextColor: peleDaMarca?.color ?? t.color.subtleForeground, keyboardType: keyboardType ?? tecladoPadrao,
|
|
314
359
|
// O nome vem do `Field`, como em todo controle deste pacote — e `label` cobre quem usa o
|
|
315
360
|
// campo solto. Sem um dos dois, é um nó anônimo para o leitor de tela.
|
|
316
361
|
accessibilityLabel: label ?? campo?.label, accessibilityHint: campo?.hint, accessibilityState: { disabled: !!inativo }, "aria-invalid": campo?.invalido, style: [
|
|
@@ -323,5 +368,10 @@ export function NumberField({ value, defaultValue, onValueChange, min, max, step
|
|
|
323
368
|
// depois. Um campo inválido que está sendo corrigido tem de mostrar que está ativo —
|
|
324
369
|
// invertendo, a pessoa digita sem pista nenhuma de onde o teclado está batendo.
|
|
325
370
|
focado && { borderColor: t.color.focusStrong },
|
|
371
|
+
// 🔴 E DENTRO DO CARTÃO DA MARCA A TINTA VENCE OS DOIS — `usePeleSobreAMarca` tem os
|
|
372
|
+
// números: sobre o amarelo o inválido mede 1,86 e o foco do tema escuro mede 1,00.
|
|
373
|
+
// O foco continua existindo, por espessura.
|
|
374
|
+
peleDaMarca,
|
|
375
|
+
peleDaMarca && focado && { borderWidth: t.size.borderWidth * 2 },
|
|
326
376
|
] }), mostrarBotoes && (_jsx(IconButton, { name: icons.increment, label: strings.increment, appearance: "ghost", size: tam, disabled: inativo || noLimite(1), onPress: () => empurrar(1), testID: testID ? `${testID}-mais` : undefined }))] }));
|
|
327
377
|
}
|
package/dist/overlays.js
CHANGED
|
@@ -61,7 +61,7 @@ import { Button } from "./actions.js";
|
|
|
61
61
|
import { criarFolha } from "./estilos.js";
|
|
62
62
|
import { IconButton } from "./actions.js";
|
|
63
63
|
import { Text } from "./text.js";
|
|
64
|
-
import { useAureaStrings, useAureaTokens } from "./theme.js";
|
|
64
|
+
import { useAureaStrings, useAureaTokens, ForaDaMarca } from "./theme.js";
|
|
65
65
|
import { useReduceMotion } from "./movimento.js";
|
|
66
66
|
const folha = criarFolha((t) => ({
|
|
67
67
|
fundo: { flex: 1, backgroundColor: t.color.overlay },
|
|
@@ -157,7 +157,7 @@ export function Dialog({ open, title, children, footer, onClose, scroll = true,
|
|
|
157
157
|
const s = folha(t);
|
|
158
158
|
const strings = useAureaStrings();
|
|
159
159
|
const Corpo = scroll ? ScrollView : View;
|
|
160
|
-
return (_jsx(Modal, { visible: open, transparent: true, animationType: "fade", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: [s.fundo, s.centro], children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(View, { ...naoAtravessa, style: [s.superficie, style], children: [_jsxs(View, { style: s.cabecalho, children: [_jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }), _jsx(IconButton, { name: "close", label: strings.close, appearance: "ghost", size: "sm", onPress: onClose })] }), _jsx(Corpo, { ...(scroll ? { contentContainerStyle: s.corpo } : { style: s.corpo }), children: children }), footer ? _jsx(View, { style: s.rodape, children: footer }) : null] })] }) }));
|
|
160
|
+
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: "fade", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: [s.fundo, s.centro], children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(View, { ...naoAtravessa, style: [s.superficie, style], children: [_jsxs(View, { style: s.cabecalho, children: [_jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }), _jsx(IconButton, { name: "close", label: strings.close, appearance: "ghost", size: "sm", onPress: onClose })] }), _jsx(Corpo, { ...(scroll ? { contentContainerStyle: s.corpo } : { style: s.corpo }), children: children }), footer ? _jsx(View, { style: s.rodape, children: footer }) : null] })] }) }) }));
|
|
161
161
|
}
|
|
162
162
|
/**
|
|
163
163
|
* A decisão que não se desfaz.
|
|
@@ -185,9 +185,9 @@ export function ConfirmDialog({ open, title, description, confirmLabel, cancelLa
|
|
|
185
185
|
const t = useAureaTokens();
|
|
186
186
|
const s = folha(t);
|
|
187
187
|
const strings = useAureaStrings();
|
|
188
|
-
return (_jsx(Modal, { visible: open, transparent: true, animationType: "fade", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onCancel, testID: testID, children: _jsx(View, { style: [s.fundo, s.centro], children: _jsxs(View, { ...naoAtravessa, style: [s.superficie, s.confirmar], children: [_jsx(View, { style: s.cabecalho, children: _jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }) }), _jsx(View, { style: s.corpo, children: typeof description === "string"
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: "fade", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onCancel, testID: testID, children: _jsx(View, { style: [s.fundo, s.centro], children: _jsxs(View, { ...naoAtravessa, style: [s.superficie, s.confirmar], children: [_jsx(View, { style: s.cabecalho, children: _jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }) }), _jsx(View, { style: s.corpo, children: typeof description === "string"
|
|
189
|
+
? _jsx(Text, { size: "md", tone: "muted", children: description })
|
|
190
|
+
: description }), _jsxs(View, { style: s.rodape, children: [_jsx(Button, { appearance: "outline", onPress: onCancel, testID: testID ? `${testID}-cancelar` : undefined, children: cancelLabel ?? strings.confirmCancel }), _jsx(Button, { appearance: "solid", tone: destructive ? "danger" : "brand", onPress: onConfirm, testID: testID ? `${testID}-confirmar` : undefined, children: confirmLabel ?? strings.confirmProceed })] })] }) }) }) }));
|
|
191
191
|
}
|
|
192
192
|
/**
|
|
193
193
|
* O painel que entra pela borda.
|
|
@@ -229,10 +229,10 @@ export function Drawer({ open, title, children, onClose, side = "right", scroll
|
|
|
229
229
|
inputRange: [0, 1],
|
|
230
230
|
outputRange: [side === "right" ? 480 : -480, 0],
|
|
231
231
|
});
|
|
232
|
-
return (_jsx(Modal, { visible: open, transparent: true, animationType: "none", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: s.fundo, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, { ...naoAtravessa, style: [
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
232
|
+
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: "none", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: s.fundo, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, { ...naoAtravessa, style: [
|
|
233
|
+
s.gaveta, side === "right" ? s.gavetaDireita : s.gavetaEsquerda,
|
|
234
|
+
{ transform: [{ translateX: desloca }] }, style,
|
|
235
|
+
], children: [_jsxs(View, { style: s.cabecalho, children: [_jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }), _jsx(IconButton, { name: "close", label: strings.close, appearance: "ghost", size: "sm", onPress: onClose })] }), _jsx(Corpo, { ...(scroll ? { contentContainerStyle: s.corpo } : { style: s.corpo }), children: children })] })] }) }) }));
|
|
236
236
|
}
|
|
237
237
|
/**
|
|
238
238
|
* A folha que sobe de baixo. **NÃO existe na web** — é o único componente deste lote sem ficha.
|
|
@@ -287,5 +287,5 @@ export function BottomSheet({ open, title, children, onClose, grabber = true, dr
|
|
|
287
287
|
}).start();
|
|
288
288
|
},
|
|
289
289
|
}), [draggable, onClose, arrasto, reduzir, t.easing.easeEmphasized]);
|
|
290
|
-
return (_jsx(Modal, { visible: open, transparent: true, animationType: reduzir !== false ? "none" : "slide", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: s.fundo, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, { ...naoAtravessa, ...gestos.panHandlers, onLayout: (e) => { altura.current = e.nativeEvent.layout.height; }, style: [s.folhaBaixo, { transform: [{ translateY: arrasto }] }, style], children: [grabber ? (_jsx(View, { style: s.puxadorArea, accessible: false, importantForAccessibility: "no-hide-descendants", children: _jsx(View, { style: s.puxador }) })) : null, title ? (_jsx(View, { style: s.cabecalho, children: _jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }) })) : null, _jsx(Corpo, { ...(scroll ? { contentContainerStyle: s.corpo } : { style: s.corpo }), children: children })] })] }) }));
|
|
290
|
+
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: reduzir !== false ? "none" : "slide", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: s.fundo, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, { ...naoAtravessa, ...gestos.panHandlers, onLayout: (e) => { altura.current = e.nativeEvent.layout.height; }, style: [s.folhaBaixo, { transform: [{ translateY: arrasto }] }, style], children: [grabber ? (_jsx(View, { style: s.puxadorArea, accessible: false, importantForAccessibility: "no-hide-descendants", children: _jsx(View, { style: s.puxador }) })) : null, title ? (_jsx(View, { style: s.cabecalho, children: _jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }) })) : null, _jsx(Corpo, { ...(scroll ? { contentContainerStyle: s.corpo } : { style: s.corpo }), children: children })] })] }) }) }));
|
|
291
291
|
}
|
package/dist/screen.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { RefreshControl, ScrollView } from "react-native";
|
|
3
3
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
4
|
+
import { useBottomNavSpace } from "./barranav.js";
|
|
4
5
|
import { criarFolha } from "./estilos.js";
|
|
5
6
|
import { useAureaTokens } from "./theme.js";
|
|
6
7
|
const folha = criarFolha((t) => ({
|
|
@@ -43,7 +44,18 @@ export function Screen({ edges = TODAS_AS_BORDAS, padded = true, scroll = false,
|
|
|
43
44
|
const t = useAureaTokens();
|
|
44
45
|
const s = folha(t);
|
|
45
46
|
const fundo = s[`fundo_${background}`];
|
|
46
|
-
|
|
47
|
+
// 🔴 O ESPAÇO DA BARRA DE ABAS, quando ela flutua por cima desta tela — ver `barranav.tsx`.
|
|
48
|
+
// **Zero** fora de um `BottomNavProvider`, que é o caso de toda tela cheia: sem abas, nada muda.
|
|
49
|
+
const respiroDaBarra = useBottomNavSpace();
|
|
50
|
+
return (_jsx(SafeAreaView, { style: [s.raiz, fundo, !scroll && padded && s.respiro, style], edges: edges, ...rest, children: scroll ? (_jsx(ScrollView, { style: s.raiz,
|
|
51
|
+
// ⚠ O respiro da barra SOMA ao do tema em vez de substituí-lo: escrever
|
|
52
|
+
// `paddingBottom` depois de `s.respiro` apagaria os 16 do tema e colaria o último
|
|
53
|
+
// item na pílula. A conta é explícita porque a folha não soma sozinha.
|
|
54
|
+
contentContainerStyle: [
|
|
55
|
+
s.conteudo, padded && s.respiro,
|
|
56
|
+
respiroDaBarra > 0
|
|
57
|
+
&& { paddingBottom: (padded ? t.size.space4 : 0) + respiroDaBarra },
|
|
58
|
+
],
|
|
47
59
|
// A rosca do sistema é a única aparência da plataforma que a Aurea aceita aqui, e a
|
|
48
60
|
// razão é que ela NÃO É desenho nosso: é o gesto do sistema operacional, com a física
|
|
49
61
|
// que a pessoa já conhece. O que dá para pintar, pintamos — a cor é do tema.
|
package/dist/text.js
CHANGED
|
@@ -23,6 +23,36 @@ import * as React from "react";
|
|
|
23
23
|
import { Text as TextRN } from "react-native";
|
|
24
24
|
import { criarFolha } from "./estilos.js";
|
|
25
25
|
import { useAureaTokens, useSobreAMarca } from "./theme.js";
|
|
26
|
+
// 🔴 A ESCALA TEM CINCO DEGRAUS QUE SE ENXERGAM, E DEZ NOMES — ordem do Victor, 19/09/2026,
|
|
27
|
+
// olhando o app no aparelho: *"o tamanho das fontes: existem variações demais, fica muito
|
|
28
|
+
// estranho"*.
|
|
29
|
+
//
|
|
30
|
+
// Medido no token antes de mexer: **12 · 13 · 14 · 16** eram quatro degraus em quatro pontos.
|
|
31
|
+
// Lado a lado, isso não lê como hierarquia — lê como erro. Uma tela só (a de Início) mostrava de
|
|
32
|
+
// 12 a 36 em SETE tamanhos.
|
|
33
|
+
//
|
|
34
|
+
// A escala nova sobe 25% por degrau, que é o mínimo para dois vizinhos serem distinguíveis a olho
|
|
35
|
+
// nu, e **nada encolhe** — o que importa, porque o Victor tem baixa visão:
|
|
36
|
+
//
|
|
37
|
+
// legenda, apoio .............. 13 (era 12)
|
|
38
|
+
// texto corrido, controle ..... 16 (era 13 e 14)
|
|
39
|
+
// nome de cartão .............. 20 (era 16 e 18)
|
|
40
|
+
// título de tela .............. 25 (era 20 e 24)
|
|
41
|
+
// número em destaque .......... 31 (era 30)
|
|
42
|
+
//
|
|
43
|
+
// ⚠ **Os DEZ nomes continuam existindo, e alguns apontam para o mesmo número** — `sm`, `md` e
|
|
44
|
+
// `base` são 16; `lg` e `xl` são 20. Isso é de propósito: `size` é API pública dos dois alvos, e
|
|
45
|
+
// apagar nome quebraria consumidor sem ganhar nada. O que encolheu foi a lista de VALORES, que é
|
|
46
|
+
// o que a pessoa vê. Por isso nenhum componente do pacote precisou trocar de degrau: os degraus é
|
|
47
|
+
// que se juntaram.
|
|
48
|
+
//
|
|
49
|
+
// ⚠ **O topo (36 e 48) não foi tocado.** A queixa é do pé da escala, e ali as razões já eram boas
|
|
50
|
+
// (1,2 e 1,33). Mexer sem queixa é inventar trabalho.
|
|
51
|
+
//
|
|
52
|
+
// ⚠ **O limite, medido e declarado:** com a letra do sistema em 1,3× o corpo de 16 vira ~21 e a
|
|
53
|
+
// linha ~29. Isso cabe em toda cápsula, MENOS o controle `sm` na densidade compacta (28 de
|
|
54
|
+
// altura), que estoura por 1 ponto. Em 1,5× vários estouram — e isso já era verdade na escala
|
|
55
|
+
// antiga.
|
|
26
56
|
const TAMANHO = {
|
|
27
57
|
xs: "textXs", sm: "textSm", md: "textMd", base: "textBase", lg: "textLg",
|
|
28
58
|
xl: "textXl", "2xl": "text2xl", "3xl": "text3xl", "4xl": "text4xl", "5xl": "text5xl",
|
|
@@ -88,5 +118,5 @@ export function Text({ size = "md", weight = 400, font = "ui", tone = "default",
|
|
|
88
118
|
// ⚠ **A consequência está declarada e não é neutra:** dentro de um cartão da marca não existe
|
|
89
119
|
// texto esmaecido. A hierarquia sai de PESO e TAMANHO.
|
|
90
120
|
// ⚠ E `style` continua por último de propósito: quem passa cor à mão assume a conta.
|
|
91
|
-
return _jsx(TextRN, { style: [s[tone], sobreAMarca && { color: sobreAMarca }, proprio, style], ...rest });
|
|
121
|
+
return _jsx(TextRN, { style: [s[tone], sobreAMarca && { color: sobreAMarca.tinta }, proprio, style], ...rest });
|
|
92
122
|
}
|
package/dist/theme.d.ts
CHANGED
|
@@ -73,13 +73,66 @@ export declare function useAureaTokens(): AureaTokens;
|
|
|
73
73
|
* `strings.ts`.
|
|
74
74
|
*/
|
|
75
75
|
export declare function useAureaStrings(): AureaStrings;
|
|
76
|
+
export interface SobreAMarcaValor {
|
|
77
|
+
/** A única cor que se pode desenhar sobre a marca: letra, contorno e glifo. 4,54 nos dois temas. */
|
|
78
|
+
tinta: string;
|
|
79
|
+
/** A cor do cartão por baixo. Serve de letra para quem se pinta com a tinta INTEIRA. */
|
|
80
|
+
fundo: string;
|
|
81
|
+
}
|
|
76
82
|
/** O provedor. Quem usa é o `Card variant="brand"`. */
|
|
77
|
-
export declare const SobreAMarca: React.Context<
|
|
83
|
+
export declare const SobreAMarca: React.Context<SobreAMarcaValor | null>;
|
|
78
84
|
/**
|
|
79
|
-
*
|
|
85
|
+
* O par de cores obrigatório quando se está sobre a marca, ou `null` quando não se está.
|
|
80
86
|
*
|
|
81
|
-
* ⚠ **
|
|
87
|
+
* ⚠ **Ele vence TODOS os tons, inclusive os explícitos.** Um `tone="danger"` sobre o amarelo
|
|
82
88
|
* mediria menos que os 4,5 da norma, então respeitá-lo entregaria texto ilegível em nome da
|
|
83
|
-
* obediência. **Sobre o amarelo existe UMA
|
|
89
|
+
* obediência. **Sobre o amarelo existe UMA tinta** — a hierarquia sai de peso e tamanho.
|
|
90
|
+
*
|
|
91
|
+
* ⚠ **E o alcance dele é DECLARADO, não completo.** Leem o contexto: `Text`, a família de campo,
|
|
92
|
+
* o `Button` e o `IconButton`. **Componente fora dessa lista continua quebrado dentro do cartão
|
|
93
|
+
* amarelo**, e gate estático nenhum vê isso — o que o consumidor encaixa não está no nosso
|
|
94
|
+
* código, exatamente o ponto cego que o `check 43` já declara.
|
|
95
|
+
*/
|
|
96
|
+
export declare function useSobreAMarca(): SobreAMarcaValor | null;
|
|
97
|
+
/**
|
|
98
|
+
* Corta a marca para dentro.
|
|
99
|
+
*
|
|
100
|
+
* 🔴 **Existe por uma armadilha do React Native que é invisível na tela e óbvia no código:** o
|
|
101
|
+
* `Modal` desenha numa camada POR CIMA de tudo, mas em React ele continua sendo FILHO de quem o
|
|
102
|
+
* escreveu. Um `Select` dentro de um `Card variant="brand"` abre a folha dele **fora** do cartão
|
|
103
|
+
* amarelo — e a folha herdaria a tinta do amarelo mesmo assim, pintando texto marrom sobre fundo
|
|
104
|
+
* normal.
|
|
105
|
+
*
|
|
106
|
+
* ⚠ **Camada visual e árvore de contexto são coisas diferentes**, e é só o segundo que manda na
|
|
107
|
+
* cor. Toda superfície que sai do fluxo — as duas folhas de escolha e os quatro sobrepostos —
|
|
108
|
+
* passa por aqui.
|
|
109
|
+
*/
|
|
110
|
+
export declare function ForaDaMarca({ children }: {
|
|
111
|
+
children?: React.ReactNode;
|
|
112
|
+
}): React.JSX.Element;
|
|
113
|
+
/**
|
|
114
|
+
* A pele que um CAMPO tem de vestir quando está dentro de um `Card variant="brand"`, ou `null`
|
|
115
|
+
* quando não está.
|
|
116
|
+
*
|
|
117
|
+
* O campo perde o fundo e passa a ser um contorno da tinta: **4,54 contra o amarelo nos dois
|
|
118
|
+
* temas**, contra os 2,43/2,24 do `borderStrong` e os 1,61 do `fieldBg` no tema claro. A norma
|
|
119
|
+
* 1.4.11 pede 3:1 para o contorno que identifica um campo, e só a tinta chega lá.
|
|
120
|
+
*
|
|
121
|
+
* ⚠ **O fundo some porque NÃO HÁ fundo possível** — medidas as três superfícies neutras do
|
|
122
|
+
* sistema contra o amarelo no tema claro: `card` 1,91 · `background` 1,73 · `secondary` 1,61.
|
|
123
|
+
* Nenhuma separa. Um contorno forte separa.
|
|
124
|
+
*
|
|
125
|
+
* 🔴 **E a tinta vence o estado de INVÁLIDO, que é o contrário do que a intuição manda.** Medido:
|
|
126
|
+
* a borda de inválido (`danger-400`, `#9f2330`) mede **1,86** contra o amarelo — ela é MENOS
|
|
127
|
+
* visível que a tinta. Pintar de vermelho ali deixaria o campo errado mais difícil de achar que o
|
|
128
|
+
* campo certo. Dentro deste cartão o erro é dito pela MENSAGEM do `Field` e pelo estado que o
|
|
129
|
+
* leitor de tela anuncia, não pela cor — que é o que a norma 1.4.1 já exige de qualquer forma.
|
|
130
|
+
*
|
|
131
|
+
* ⚠ **O texto digitado e o marcador de dica ficam da MESMA cor**, porque só existe uma tinta. É
|
|
132
|
+
* perda real de hierarquia, declarada e não escondida: sobre o amarelo não há segunda cor.
|
|
84
133
|
*/
|
|
85
|
-
export declare function
|
|
134
|
+
export declare function usePeleSobreAMarca(): {
|
|
135
|
+
borderColor: string;
|
|
136
|
+
backgroundColor: string;
|
|
137
|
+
color: string;
|
|
138
|
+
} | null;
|