@aurea-uds/native 0.8.6 → 0.8.7
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/busca.js +32 -25
- package/dist/inputs.js +21 -3
- package/dist/layout.js +9 -1
- package/dist/numero.js +8 -2
- package/dist/overlays.js +10 -10
- package/dist/text.js +1 -1
- package/dist/theme.d.ts +58 -5
- package/dist/theme.js +51 -20
- package/package.json +2 -2
package/dist/actions.js
CHANGED
|
@@ -25,7 +25,7 @@ import { Pressable, View } from "react-native";
|
|
|
25
25
|
import { criarFolha } from "./estilos.js";
|
|
26
26
|
import { Icon } from "./icon.js";
|
|
27
27
|
import { Text } from "./text.js";
|
|
28
|
-
import { useAureaTokens } from "./theme.js";
|
|
28
|
+
import { useAureaTokens, useSobreAMarca } from "./theme.js";
|
|
29
29
|
const ALTURA = {
|
|
30
30
|
xs: "controlHXs", sm: "controlHSm", md: "controlHMd", lg: "controlHLg", xl: "controlHXl",
|
|
31
31
|
};
|
|
@@ -67,6 +67,29 @@ function pintar(t, tone) {
|
|
|
67
67
|
};
|
|
68
68
|
return m[tone];
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* O mesmo par, corrigido quando a peça está DENTRO de um `Card variant="brand"`.
|
|
72
|
+
*
|
|
73
|
+
* 🔴 **Sem isto o botão não existe sobre o amarelo — medido nas quatro aparências, 17/09/2026:**
|
|
74
|
+
* cheio neutro **1,61** no claro · cheio da marca **1,00** (amarelo no amarelo) · contornado
|
|
75
|
+
* **1,38** no claro · só-texto **1,83** no escuro. O `Card variant="brand"` EXIGE `action` no
|
|
76
|
+
* tipo, então o cartão obrigava a ter um botão e não dava a ele nenhuma forma de aparecer.
|
|
77
|
+
*
|
|
78
|
+
* A saída não é paleta nova: **uma única cor do sistema passa de 3:1 contra o amarelo nos dois
|
|
79
|
+
* temas**, e é a tinta que o cartão já manda para dentro (4,54). Então aqui:
|
|
80
|
+
*
|
|
81
|
+
* - **cheio** — o fundo vira a TINTA e a letra vira o amarelo do cartão. O botão fica escuro
|
|
82
|
+
* sobre o amarelo, que é o único desenho que se enxerga nos dois temas;
|
|
83
|
+
* - **contornado e sem fundo** — contorno e letra viram a tinta.
|
|
84
|
+
*
|
|
85
|
+
* ⚠ **O tom pedido é IGNORADO aqui**, como já acontece no `Text`: um `tone="danger"` sobre o
|
|
86
|
+
* amarelo mede menos que a norma, e obedecer entregaria um botão ilegível em nome da obediência.
|
|
87
|
+
*/
|
|
88
|
+
function pintarSobreAMarca(base, marca) {
|
|
89
|
+
if (marca == null)
|
|
90
|
+
return base;
|
|
91
|
+
return { solido: marca.tinta, texto: marca.fundo, sobre: marca.tinta };
|
|
92
|
+
}
|
|
70
93
|
const folha = criarFolha((t) => ({
|
|
71
94
|
// ⚠ O ALVO DE TOQUE, e é a decisão mais importante deste arquivo.
|
|
72
95
|
//
|
|
@@ -108,15 +131,17 @@ const folha = criarFolha((t) => ({
|
|
|
108
131
|
export function Button({ children, appearance = "solid", tone = "neutral", size = "md", leadingIcon, trailingIcon, leading, trailing, icons, fullWidth = false, pressed, disabled, accessibilityLabel, ...rest }) {
|
|
109
132
|
const t = useAureaTokens();
|
|
110
133
|
const s = folha(t);
|
|
111
|
-
const
|
|
134
|
+
const marca = useSobreAMarca();
|
|
135
|
+
const cor = pintarSobreAMarca(pintar(t, tone), marca);
|
|
136
|
+
const corDaBorda = marca?.tinta ?? t.color.border;
|
|
112
137
|
const caixa = React.useMemo(() => ({
|
|
113
138
|
height: t.size[ALTURA[size]],
|
|
114
139
|
paddingHorizontal: PADDING[size],
|
|
115
140
|
gap: GAP[size],
|
|
116
141
|
backgroundColor: appearance === "solid" ? cor.solido : "transparent",
|
|
117
|
-
borderColor: appearance === "outline" ?
|
|
142
|
+
borderColor: appearance === "outline" ? corDaBorda : "transparent",
|
|
118
143
|
...(fullWidth ? { flex: 1 } : null),
|
|
119
|
-
}), [t, size, appearance, cor.solido, fullWidth]);
|
|
144
|
+
}), [t, size, appearance, cor.solido, corDaBorda, fullWidth]);
|
|
120
145
|
const corDoTexto = appearance === "solid" ? cor.texto : cor.sobre;
|
|
121
146
|
return (_jsx(Pressable, { disabled: disabled, accessibilityRole: "button", accessibilityLabel: accessibilityLabel, accessibilityState: { disabled: !!disabled, ...(pressed === undefined ? null : { checked: pressed }) }, style: ({ pressed: tocando }) => [
|
|
122
147
|
s.alvo, fullWidth && s.alvoLargura,
|
|
@@ -137,14 +162,16 @@ export function Button({ children, appearance = "solid", tone = "neutral", size
|
|
|
137
162
|
export function IconButton({ name, label, appearance = "ghost", tone = "neutral", size = "md", icons, pressed, disabled, ...rest }) {
|
|
138
163
|
const t = useAureaTokens();
|
|
139
164
|
const s = folha(t);
|
|
140
|
-
const
|
|
165
|
+
const marca = useSobreAMarca();
|
|
166
|
+
const cor = pintarSobreAMarca(pintar(t, tone), marca);
|
|
167
|
+
const corDaBorda = marca?.tinta ?? t.color.border;
|
|
141
168
|
const lado = t.size[ALTURA[size]];
|
|
142
169
|
const caixa = React.useMemo(() => ({
|
|
143
170
|
height: lado, width: lado, paddingHorizontal: 0,
|
|
144
171
|
borderRadius: size === "xs" || size === "sm" ? t.size.radiusSm : t.size.radiusMd,
|
|
145
172
|
backgroundColor: appearance === "solid" ? cor.solido : "transparent",
|
|
146
|
-
borderColor: appearance === "outline" ?
|
|
147
|
-
}), [t, lado, size, appearance, cor.solido]);
|
|
173
|
+
borderColor: appearance === "outline" ? corDaBorda : "transparent",
|
|
174
|
+
}), [t, lado, size, appearance, cor.solido, corDaBorda]);
|
|
148
175
|
return (_jsx(Pressable, { disabled: disabled, accessibilityRole: "button", accessibilityLabel: label, accessibilityState: { disabled: !!disabled, ...(pressed === undefined ? null : { checked: pressed }) }, style: ({ pressed: tocando }) => [
|
|
149
176
|
s.alvo, { minWidth: t.size.targetMin, alignItems: "center" },
|
|
150
177
|
tocando && s.pressionado, disabled && s.inerte,
|
package/dist/busca.js
CHANGED
|
@@ -75,7 +75,7 @@ import { Icon } from "./icon.js";
|
|
|
75
75
|
import { KeyboardAvoiding, useCampo } from "./inputs.js";
|
|
76
76
|
import { useReduceMotion } from "./movimento.js";
|
|
77
77
|
import { Text } from "./text.js";
|
|
78
|
-
import { useAureaStrings, useAureaTokens } from "./theme.js";
|
|
78
|
+
import { useAureaStrings, useAureaTokens, ForaDaMarca, usePeleSobreAMarca } from "./theme.js";
|
|
79
79
|
// As mesmas contas do `inputs.tsx`, e elas são repetidas AQUI de propósito: exportá-las de lá
|
|
80
80
|
// tornaria pública uma conta interna do outro módulo, e um `import` de função privada entre
|
|
81
81
|
// módulos irmãos é o começo de um acoplamento que ninguém declara. São três linhas.
|
|
@@ -205,6 +205,7 @@ const folha = criarFolha((t) => ({
|
|
|
205
205
|
export function Combobox({ items, value, onValueChange, onSearchChange, searchDelay = ESPERA_PADRAO, loading, onEndReached, placeholder, searchPlaceholder, empty, clearable = true, draggable = true, disabled, size, chevron = "chevron--down", searchIcon = "search", style, testID, }) {
|
|
206
206
|
const t = useAureaTokens();
|
|
207
207
|
const s = folha(t);
|
|
208
|
+
const peleDaMarca = usePeleSobreAMarca();
|
|
208
209
|
const strings = useAureaStrings();
|
|
209
210
|
const campo = useCampo();
|
|
210
211
|
const tam = size ?? campo?.size ?? "md";
|
|
@@ -292,31 +293,33 @@ export function Combobox({ items, value, onValueChange, onSearchChange, searchDe
|
|
|
292
293
|
s.caixa,
|
|
293
294
|
{ height: alturaDoTamanho(t, tam), paddingHorizontal: respiroDoTamanho(t, tam) },
|
|
294
295
|
campo?.invalido && s.invalido,
|
|
296
|
+
// Sobre a marca a tinta vence inválido — ver `usePeleSobreAMarca`.
|
|
297
|
+
peleDaMarca,
|
|
295
298
|
inativo && s.desabilitado,
|
|
296
299
|
style,
|
|
297
|
-
], children: [_jsx(Pressable, { testID: testID, onPress: inativo ? undefined : () => setAberto(true), disabled: inativo, accessibilityRole: "button", accessibilityLabel: campo?.label, accessibilityHint: campo?.hint, accessibilityValue: { text: value?.label }, accessibilityState: { disabled: !!inativo, expanded: aberto }, style: s.gatilho, children: _jsx(Text, { size: tam === "sm" ? "xs" : tam === "lg" ? "base" : "md", tone: value ? "default" : "subtle", numberOfLines: 1, style: { flex: 1, minWidth: 0 }, children: value?.label ?? placeholder ?? "" }) }), _jsxs(View, { style: s.acoes, children: [clearable && value != null && !inativo && (_jsx(IconButton, { name: "close", label: strings.comboboxClear, appearance: "ghost", size: "sm", onPress: () => onValueChange?.(null), testID: testID ? `${testID}-limpar` : undefined })), chevron && (_jsx(Pressable, { accessible: false, disabled: inativo, style: s.setaToque, onPress: inativo ? undefined : () => setAberto(true), testID: testID ? `${testID}-seta` : undefined, children: _jsx(Icon, { name: chevron, size: "sm", color: t.color.subtleForeground }) }))] })] }), _jsx(Modal, { visible: aberto, transparent: true, animationType: reduzir !== false ? "none" : "slide", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: fechar, children: _jsxs(KeyboardAvoiding, { style: s.fundoDaLista, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: fechar, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, { style: [s.lista, { transform: [{ translateY: arrasto }] }], onLayout: (e) => { altura.current = e.nativeEvent.layout.height; }, onStartShouldSetResponder: () => true, children: [_jsx(View, { style: s.puxadorArea, ...(draggable ? gestos.panHandlers : null), accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: _jsx(View, { style: s.puxador }) }), _jsxs(View, { style: [s.grupo, { height: alturaDoTamanho(t, tam) }], ...(draggable ? gestos.panHandlers : null), children: [searchIcon && _jsx(Icon, { name: searchIcon, size: "sm", color: t.color.subtleForeground }), _jsx(TextInput, { testID: testID ? `${testID}-busca` : undefined, value: texto, onChangeText: digitar, placeholder: searchPlaceholder ?? strings.comboboxSearch, placeholderTextColor: t.color.subtleForeground,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
300
|
+
], children: [_jsx(Pressable, { testID: testID, onPress: inativo ? undefined : () => setAberto(true), disabled: inativo, accessibilityRole: "button", accessibilityLabel: campo?.label, accessibilityHint: campo?.hint, accessibilityValue: { text: value?.label }, accessibilityState: { disabled: !!inativo, expanded: aberto }, style: s.gatilho, children: _jsx(Text, { size: tam === "sm" ? "xs" : tam === "lg" ? "base" : "md", tone: value ? "default" : "subtle", numberOfLines: 1, style: { flex: 1, minWidth: 0 }, children: value?.label ?? placeholder ?? "" }) }), _jsxs(View, { style: s.acoes, children: [clearable && value != null && !inativo && (_jsx(IconButton, { name: "close", label: strings.comboboxClear, appearance: "ghost", size: "sm", onPress: () => onValueChange?.(null), testID: testID ? `${testID}-limpar` : undefined })), chevron && (_jsx(Pressable, { accessible: false, disabled: inativo, style: s.setaToque, onPress: inativo ? undefined : () => setAberto(true), testID: testID ? `${testID}-seta` : undefined, children: _jsx(Icon, { name: chevron, size: "sm", color: t.color.subtleForeground }) }))] })] }), _jsx(ForaDaMarca, { children: _jsx(Modal, { visible: aberto, transparent: true, animationType: reduzir !== false ? "none" : "slide", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: fechar, children: _jsxs(KeyboardAvoiding, { style: s.fundoDaLista, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: fechar, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, { style: [s.lista, { transform: [{ translateY: arrasto }] }], onLayout: (e) => { altura.current = e.nativeEvent.layout.height; }, onStartShouldSetResponder: () => true, children: [_jsx(View, { style: s.puxadorArea, ...(draggable ? gestos.panHandlers : null), accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: _jsx(View, { style: s.puxador }) }), _jsxs(View, { style: [s.grupo, { height: alturaDoTamanho(t, tam) }], ...(draggable ? gestos.panHandlers : null), children: [searchIcon && _jsx(Icon, { name: searchIcon, size: "sm", color: t.color.subtleForeground }), _jsx(TextInput, { testID: testID ? `${testID}-busca` : undefined, value: texto, onChangeText: digitar, placeholder: searchPlaceholder ?? strings.comboboxSearch, placeholderTextColor: t.color.subtleForeground,
|
|
301
|
+
// ⚠ `autoFocus` é o que faz a folha valer a pena: abrir um campo de busca e
|
|
302
|
+
// exigir um segundo toque para o teclado subir é um toque a mais em cada
|
|
303
|
+
// cadastro. O foco entra com a folha; o teclado vem junto.
|
|
304
|
+
autoFocus: true, autoCorrect: false, autoCapitalize: "none",
|
|
305
|
+
// Mapeia nos dois sistemas — conferido no fonte do RN, tabela no topo do módulo.
|
|
306
|
+
accessibilityRole: "search", accessibilityLabel: searchPlaceholder ?? strings.comboboxSearch,
|
|
307
|
+
// `returnKeyType="search"` troca o "enter" do teclado pela lupa. É pista de
|
|
308
|
+
// plataforma, não decoração: diz à pessoa que aquele campo é de busca antes de
|
|
309
|
+
// ela digitar a primeira letra.
|
|
310
|
+
returnKeyType: "search", style: [
|
|
311
|
+
s.campoDeTexto,
|
|
312
|
+
{ fontSize: fonteDoTamanho(t, tam), fontFamily: t.font.ui[400],
|
|
313
|
+
color: t.color.foreground },
|
|
314
|
+
] }), texto.length > 0 && (_jsx(IconButton, { name: "close", label: strings.searchClear, appearance: "ghost", size: "sm", onPress: () => digitar(""), testID: testID ? `${testID}-busca-limpar` : undefined }))] }), loading && (_jsx(View, { style: s.carregando, children: _jsx(Spinner, { label: strings.comboboxLoading }) })), nada && (_jsx(View, { style: s.vazio, children: typeof empty === "string" || empty == null
|
|
315
|
+
? _jsx(Text, { size: "sm", tone: "muted", children: empty ?? strings.comboboxEmpty })
|
|
316
|
+
: empty })), _jsx(FlatList, { data: filtrados, keyExtractor: (i) => i.value, keyboardShouldPersistTaps: "handled", onEndReached: onEndReached, onEndReachedThreshold: ANTECEDENCIA_DE_PAGINA, renderItem: ({ item }) => (_jsx(Pressable, { disabled: item.disabled, onPress: () => { onValueChange?.(item); fechar(); }, accessibilityRole: "menuitem", accessibilityState: {
|
|
317
|
+
selected: item.value === value?.value, disabled: !!item.disabled,
|
|
318
|
+
}, style: [
|
|
319
|
+
s.opcao,
|
|
320
|
+
item.value === value?.value && s.opcaoEscolhida,
|
|
321
|
+
item.disabled && s.desabilitado,
|
|
322
|
+
], children: _jsx(Text, { size: "md", weight: item.value === value?.value ? 600 : 400, children: item.label }) })) })] })] }) }) })] }));
|
|
320
323
|
}
|
|
321
324
|
// ── A DOBRA DE ACENTO, e por que ela é sondada em vez de presumida ───────────────────────────
|
|
322
325
|
// Buscar "acucar" tem de achar "açúcar" — num catálogo em português, exigir o acento certo é
|
|
@@ -358,6 +361,7 @@ const dobrar = (v) => {
|
|
|
358
361
|
export function SearchField({ value, onChangeText, onSearchChange, searchDelay = ESPERA_PADRAO, placeholder, disabled, size, icon = "search", clearable = true, onSubmit, style, testID, }) {
|
|
359
362
|
const t = useAureaTokens();
|
|
360
363
|
const s = folha(t);
|
|
364
|
+
const peleDaMarca = usePeleSobreAMarca();
|
|
361
365
|
const strings = useAureaStrings();
|
|
362
366
|
const campo = useCampo();
|
|
363
367
|
const tam = size ?? campo?.size ?? "md";
|
|
@@ -400,9 +404,12 @@ export function SearchField({ value, onChangeText, onSearchChange, searchDelay =
|
|
|
400
404
|
// O foco é a única pista de campo ativo que sobra no telefone — mesma decisão do `Input`
|
|
401
405
|
// do Lote 4, e ela vale igual aqui.
|
|
402
406
|
focado && { borderColor: t.color.focusStrong },
|
|
407
|
+
// Sobre a marca a tinta vence inválido e foco; o foco vira ESPESSURA — `usePeleSobreAMarca`.
|
|
408
|
+
peleDaMarca,
|
|
409
|
+
peleDaMarca && focado && { borderWidth: t.size.borderWidth * 2 },
|
|
403
410
|
inativo && s.desabilitado,
|
|
404
411
|
style,
|
|
405
|
-
], children: [icon && _jsx(Icon, { name: icon, size: "sm", color: t.color.subtleForeground }), _jsx(TextInput, { testID: testID ? `${testID}-campo` : undefined, value: value, onChangeText: digitar, placeholder: placeholder, placeholderTextColor: t.color.subtleForeground, editable: !inativo, autoCorrect: false, autoCapitalize: "none", returnKeyType: "search", onSubmitEditing: onSubmit, onFocus: () => setFocado(true), onBlur: () => setFocado(false), accessibilityRole: "search", accessibilityLabel: campo?.label ?? placeholder, accessibilityHint: campo?.hint, accessibilityState: { disabled: !!inativo }, style: [
|
|
412
|
+
], children: [icon && _jsx(Icon, { name: icon, size: "sm", color: peleDaMarca?.color ?? t.color.subtleForeground }), _jsx(TextInput, { testID: testID ? `${testID}-campo` : undefined, value: value, onChangeText: digitar, placeholder: placeholder, placeholderTextColor: peleDaMarca?.color ?? t.color.subtleForeground, editable: !inativo, autoCorrect: false, autoCapitalize: "none", returnKeyType: "search", onSubmitEditing: onSubmit, onFocus: () => setFocado(true), onBlur: () => setFocado(false), accessibilityRole: "search", accessibilityLabel: campo?.label ?? placeholder, accessibilityHint: campo?.hint, accessibilityState: { disabled: !!inativo }, style: [
|
|
406
413
|
s.campoDeTexto,
|
|
407
414
|
{ fontSize: fonteDoTamanho(t, tam), fontFamily: t.font.ui[400],
|
|
408
415
|
color: t.color.foreground },
|
package/dist/inputs.js
CHANGED
|
@@ -45,7 +45,7 @@ import { IconButton } from "./actions.js";
|
|
|
45
45
|
import { Icon } from "./icon.js";
|
|
46
46
|
import { useReduceMotion } from "./movimento.js";
|
|
47
47
|
import { Text } from "./text.js";
|
|
48
|
-
import { useAureaStrings, useAureaTokens } from "./theme.js";
|
|
48
|
+
import { useAureaStrings, useAureaTokens, usePeleSobreAMarca, ForaDaMarca } from "./theme.js";
|
|
49
49
|
const alturaDoTamanho = (t, s) => s === "sm" ? t.size.controlHSm : s === "lg" ? t.size.controlHLg : t.size.controlHMd;
|
|
50
50
|
const fonteDoTamanho = (t, s) => s === "sm" ? t.size.textXs : s === "lg" ? t.size.textBase : t.size.textMd;
|
|
51
51
|
const respiroDoTamanho = (t, s) => s === "sm" ? t.size.space3 : s === "lg" ? t.size.space4 : 13;
|
|
@@ -190,6 +190,7 @@ export function Input({ value, defaultValue, onChangeText, placeholder, disabled
|
|
|
190
190
|
...rest }) {
|
|
191
191
|
const t = useAureaTokens();
|
|
192
192
|
const s = folha(t);
|
|
193
|
+
const peleDaMarca = usePeleSobreAMarca();
|
|
193
194
|
const campo = useCampo();
|
|
194
195
|
const grupo = useGrupoDeCampo();
|
|
195
196
|
const tam = size ?? grupo?.size ?? campo?.size ?? "md";
|
|
@@ -199,7 +200,7 @@ export function Input({ value, defaultValue, onChangeText, placeholder, disabled
|
|
|
199
200
|
// O resto vem PRIMEIRO de propósito: o que a Aurea calcula (respiro, cor, nome do `Field`,
|
|
200
201
|
// `editable`) tem de vencer, e as props que ela redefine estão no `Omit` da interface —
|
|
201
202
|
// então não chegam por aqui e não há o que sobrescrever por acidente.
|
|
202
|
-
, { ...rest, testID: testID, value: value, defaultValue: defaultValue, onChangeText: onChangeText, placeholder: placeholder, placeholderTextColor: t.color.subtleForeground, editable: !inativo, keyboardType: keyboardType, secureTextEntry: secureTextEntry, autoCapitalize: autoCapitalize, multiline: multiline, onFocus: () => { setFocado(true); grupo?.aoFocar(true); onFocus?.(); }, onBlur: () => {
|
|
203
|
+
, { ...rest, testID: testID, value: value, defaultValue: defaultValue, onChangeText: onChangeText, placeholder: placeholder, placeholderTextColor: peleDaMarca?.color ?? t.color.subtleForeground, editable: !inativo, keyboardType: keyboardType, secureTextEntry: secureTextEntry, autoCapitalize: autoCapitalize, multiline: multiline, onFocus: () => { setFocado(true); grupo?.aoFocar(true); onFocus?.(); }, onBlur: () => {
|
|
203
204
|
setFocado(false);
|
|
204
205
|
grupo?.aoFocar(false);
|
|
205
206
|
// Só avisa quando o texto MUDOU: emitir o mesmo valor a cada saída de foco faria o app
|
|
@@ -244,6 +245,16 @@ export function Input({ value, defaultValue, onChangeText, placeholder, disabled
|
|
|
244
245
|
// O foco é o único estado que sobra do trio da web (hover/focus/active), e ele importa
|
|
245
246
|
// mais aqui: no telefone é a única pista de qual campo o teclado está alimentando.
|
|
246
247
|
!grupo && focado && { borderColor: t.color.focusStrong },
|
|
248
|
+
// 🔴 DENTRO DO CARTÃO DA MARCA A TINTA VENCE TUDO — inclusive inválido e foco, e isso é
|
|
249
|
+
// medição, não preferência (os números estão no `usePeleSobreAMarca`): sobre o amarelo a
|
|
250
|
+
// borda de inválido mede **1,86** e o `focusStrong` do tema ESCURO mede **1,00**, porque
|
|
251
|
+
// lá ele É o amarelo. Deixá-los vencer apagaria o campo justamente quando ele mais
|
|
252
|
+
// precisa ser achado.
|
|
253
|
+
peleDaMarca && { color: peleDaMarca.color },
|
|
254
|
+
!grupo && peleDaMarca,
|
|
255
|
+
// E o foco continua existindo, por ESPESSURA em vez de cor — a única pista que sobra
|
|
256
|
+
// quando só há uma tinta. O dobro da borda do token, não número novo.
|
|
257
|
+
!grupo && peleDaMarca && focado && { borderWidth: t.size.borderWidth * 2 },
|
|
247
258
|
!grupo && inativo && s.desabilitado,
|
|
248
259
|
style,
|
|
249
260
|
] }));
|
|
@@ -277,6 +288,7 @@ export function Textarea({ rows, size, style, ...rest }) {
|
|
|
277
288
|
export function InputGroup({ size, disabled, children, style, testID, ...rest }) {
|
|
278
289
|
const t = useAureaTokens();
|
|
279
290
|
const s = folha(t);
|
|
291
|
+
const peleDaMarca = usePeleSobreAMarca();
|
|
280
292
|
const campo = useCampo();
|
|
281
293
|
const tam = size ?? campo?.size ?? "md";
|
|
282
294
|
const inativo = disabled ?? campo?.disabled ?? false;
|
|
@@ -291,6 +303,9 @@ export function InputGroup({ size, disabled, children, style, testID, ...rest })
|
|
|
291
303
|
// O foco vem do campo lá dentro, por contexto: no React Native não existe `:focus-within`,
|
|
292
304
|
// e sem isto a única pista de qual campo o teclado alimenta sumiria ao entrar num grupo.
|
|
293
305
|
focado && { borderColor: t.color.focusStrong },
|
|
306
|
+
// Sobre a marca a tinta vence inválido e foco — ver `usePeleSobreAMarca`.
|
|
307
|
+
peleDaMarca,
|
|
308
|
+
peleDaMarca && focado && { borderWidth: t.size.borderWidth * 2 },
|
|
294
309
|
inativo && s.desabilitado,
|
|
295
310
|
style,
|
|
296
311
|
], ...rest, children: _jsx(GrupoDeCampo.Provider, { value: ctx, children: children }) }));
|
|
@@ -463,6 +478,7 @@ export function SegmentedControl({ items, value, onChange, label, disabled, styl
|
|
|
463
478
|
export function Select({ items, value, onChange, placeholder, disabled, size, chevron = "chevron--down", style, testID, }) {
|
|
464
479
|
const t = useAureaTokens();
|
|
465
480
|
const s = folha(t);
|
|
481
|
+
const peleDaMarca = usePeleSobreAMarca();
|
|
466
482
|
const campo = useCampo();
|
|
467
483
|
const tam = size ?? campo?.size ?? "md";
|
|
468
484
|
const inativo = disabled ?? campo?.disabled;
|
|
@@ -473,9 +489,11 @@ export function Select({ items, value, onChange, placeholder, disabled, size, ch
|
|
|
473
489
|
{ flexDirection: "row", alignItems: "center", justifyContent: "space-between",
|
|
474
490
|
height: alturaDoTamanho(t, tam), paddingHorizontal: respiroDoTamanho(t, tam) },
|
|
475
491
|
campo?.invalido && s.invalido,
|
|
492
|
+
// Sobre a marca a tinta vence inválido — ver `usePeleSobreAMarca`.
|
|
493
|
+
peleDaMarca,
|
|
476
494
|
inativo && s.desabilitado,
|
|
477
495
|
style,
|
|
478
|
-
], children: [_jsx(Text, { size: tam === "sm" ? "xs" : tam === "lg" ? "base" : "md", tone: escolhido ? "default" : "subtle", numberOfLines: 1, children: escolhido?.label ?? placeholder ?? "" }), chevron && _jsx(Icon, { name: chevron, size: "sm", color: t.color.subtleForeground })] }), _jsx(Modal, { visible: aberto, transparent: true, animationType: "slide", onRequestClose: () => setAberto(false), children: _jsxs(View, { style: s.fundoDaLista, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: () => setAberto(false), accessible: false }), _jsx(View, { style: s.lista, onStartShouldSetResponder: () => true, children: _jsx(ScrollView, { children: items.map((it) => (_jsx(Pressable, { disabled: it.disabled, onPress: () => { onChange?.(it.value); setAberto(false); }, accessibilityRole: "menuitem", accessibilityState: { selected: it.value === value, disabled: !!it.disabled }, style: [s.opcao, it.disabled && s.desabilitado], children: _jsx(Text, { size: "md", weight: it.value === value ? 600 : 400, children: it.label }) }, it.value))) }) })] }) })] }));
|
|
496
|
+
], children: [_jsx(Text, { size: tam === "sm" ? "xs" : tam === "lg" ? "base" : "md", tone: escolhido ? "default" : "subtle", numberOfLines: 1, children: escolhido?.label ?? placeholder ?? "" }), chevron && _jsx(Icon, { name: chevron, size: "sm", color: peleDaMarca?.color ?? t.color.subtleForeground })] }), _jsx(ForaDaMarca, { children: _jsx(Modal, { visible: aberto, transparent: true, animationType: "slide", onRequestClose: () => setAberto(false), children: _jsxs(View, { style: s.fundoDaLista, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: () => setAberto(false), accessible: false }), _jsx(View, { style: s.lista, onStartShouldSetResponder: () => true, children: _jsx(ScrollView, { children: items.map((it) => (_jsx(Pressable, { disabled: it.disabled, onPress: () => { onChange?.(it.value); setAberto(false); }, accessibilityRole: "menuitem", accessibilityState: { selected: it.value === value, disabled: !!it.disabled }, style: [s.opcao, it.disabled && s.desabilitado], children: _jsx(Text, { size: "md", weight: it.value === value ? 600 : 400, children: it.label }) }, it.value))) }) })] }) }) })] }));
|
|
479
497
|
}
|
|
480
498
|
/**
|
|
481
499
|
* A pilha de campos, com o respiro do `--space-5`.
|
package/dist/layout.js
CHANGED
|
@@ -134,7 +134,15 @@ export function Card({ variant = "base", style, ...rest }) {
|
|
|
134
134
|
// ⚠ **Consequência declarada: sobre o amarelo existe UMA cor de texto, não duas.** O tom
|
|
135
135
|
// `muted` mede 1,35 no escuro, então ele não pode sobreviver aqui. A hierarquia dentro deste
|
|
136
136
|
// cartão sai de PESO e TAMANHO, não de cor — e isso é restrição do contraste, não gosto.
|
|
137
|
+
//
|
|
138
|
+
// 🔴 **E ISTO NASCEU PELA METADE — o consumidor achou em UM DIA, 17/09/2026.** O parágrafo
|
|
139
|
+
// acima fala só de TEXTO, e foi só o texto que passou a ler o contexto. Medido depois, dentro
|
|
140
|
+
// deste mesmo cartão: contorno de campo **2,43/2,24**, fundo de campo **1,61** no claro, glifo
|
|
141
|
+
// de botão sem fundo **1,83** no escuro — e as QUATRO aparências do `action` que este tipo
|
|
142
|
+
// EXIGE, todas invisíveis (1,61 · 1,00 · 1,38 · 1,83).
|
|
143
|
+
// **A mesma frase valia para linha e glifo desde o primeiro dia, e eu parei no texto.**
|
|
144
|
+
// ✅ Hoje o contexto carrega o par (tinta, fundo), e quem lê está listado no `useSobreAMarca`.
|
|
137
145
|
return variant === "brand"
|
|
138
|
-
? _jsx(SobreAMarca.Provider, { value: t.color.primaryForeground, children: pele })
|
|
146
|
+
? _jsx(SobreAMarca.Provider, { value: { tinta: t.color.primaryForeground, fundo: t.color.primary }, children: pele })
|
|
139
147
|
: pele;
|
|
140
148
|
}
|
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) => ({
|
|
@@ -235,6 +235,7 @@ const paraEdicao = (n, locale) => {
|
|
|
235
235
|
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
236
|
const t = useAureaTokens();
|
|
237
237
|
const s = folha(t);
|
|
238
|
+
const peleDaMarca = usePeleSobreAMarca();
|
|
238
239
|
const strings = useAureaStrings();
|
|
239
240
|
const campo = useCampo();
|
|
240
241
|
const tam = size ?? campo?.size ?? "md";
|
|
@@ -310,7 +311,7 @@ export function NumberField({ value, defaultValue, onValueChange, min, max, step
|
|
|
310
311
|
// (`aurea.css:685`), com os dois botões FORA dela. O estado que faltava é o deles; a geometria
|
|
311
312
|
// continua sendo a nossa.
|
|
312
313
|
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: setEmEdicao, onFocus: () => { setFocado(true); setEmEdicao(paraEdicao(numero, locale)); }, onBlur: () => { setFocado(false); confirmar(); }, editable: !inativo && !readOnly, placeholder: placeholder, placeholderTextColor: t.color.subtleForeground, keyboardType: keyboardType ?? tecladoPadrao,
|
|
314
|
+
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: setEmEdicao, 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
315
|
// O nome vem do `Field`, como em todo controle deste pacote — e `label` cobre quem usa o
|
|
315
316
|
// campo solto. Sem um dos dois, é um nó anônimo para o leitor de tela.
|
|
316
317
|
accessibilityLabel: label ?? campo?.label, accessibilityHint: campo?.hint, accessibilityState: { disabled: !!inativo }, "aria-invalid": campo?.invalido, style: [
|
|
@@ -323,5 +324,10 @@ export function NumberField({ value, defaultValue, onValueChange, min, max, step
|
|
|
323
324
|
// depois. Um campo inválido que está sendo corrigido tem de mostrar que está ativo —
|
|
324
325
|
// invertendo, a pessoa digita sem pista nenhuma de onde o teclado está batendo.
|
|
325
326
|
focado && { borderColor: t.color.focusStrong },
|
|
327
|
+
// 🔴 E DENTRO DO CARTÃO DA MARCA A TINTA VENCE OS DOIS — `usePeleSobreAMarca` tem os
|
|
328
|
+
// números: sobre o amarelo o inválido mede 1,86 e o foco do tema escuro mede 1,00.
|
|
329
|
+
// O foco continua existindo, por espessura.
|
|
330
|
+
peleDaMarca,
|
|
331
|
+
peleDaMarca && focado && { borderWidth: t.size.borderWidth * 2 },
|
|
326
332
|
] }), 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
333
|
}
|
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/text.js
CHANGED
|
@@ -88,5 +88,5 @@ export function Text({ size = "md", weight = 400, font = "ui", tone = "default",
|
|
|
88
88
|
// ⚠ **A consequência está declarada e não é neutra:** dentro de um cartão da marca não existe
|
|
89
89
|
// texto esmaecido. A hierarquia sai de PESO e TAMANHO.
|
|
90
90
|
// ⚠ 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 });
|
|
91
|
+
return _jsx(TextRN, { style: [s[tone], sobreAMarca && { color: sobreAMarca.tinta }, proprio, style], ...rest });
|
|
92
92
|
}
|
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;
|
package/dist/theme.js
CHANGED
|
@@ -109,33 +109,64 @@ export function useAureaTokens() {
|
|
|
109
109
|
export function useAureaStrings() {
|
|
110
110
|
return usar("useAureaStrings").strings;
|
|
111
111
|
}
|
|
112
|
-
// ─────────────────────────────────────────────────────────────────────────────────────────────
|
|
113
|
-
// Sobre a marca — a cor de texto FORÇADA dentro de uma superfície amarela
|
|
114
|
-
// ─────────────────────────────────────────────────────────────────────────────────────────────
|
|
115
|
-
//
|
|
116
|
-
// 🔴 **Isto existe porque o contraste não deixou escolha**, e os números estão no `layout.tsx`:
|
|
117
|
-
// sobre o `primary`, o texto comum mede **1,83 no tema escuro** e o esmaecido **1,35**. Os dois
|
|
118
|
-
// são ilegíveis. O único par que serve nos DOIS temas é `primary-foreground`, com 4,54.
|
|
119
|
-
//
|
|
120
|
-
// ⚠ **E no React Native não há cascata de cor** — `color` num `View` não desce para o `Text` de
|
|
121
|
-
// dentro, como desceria no CSS. Então a cor tem de viajar por CONTEXTO, que é exatamente a
|
|
122
|
-
// decisão que o `Field` do Lote 4 tomou para empurrar nome, dica e estado de inválido.
|
|
123
|
-
//
|
|
124
|
-
// ⚠ **Ele mora AQUI e não no `layout.tsx` por uma razão de estrutura:** o `layout.tsx` importa o
|
|
125
|
-
// `Text`, então se ele também exportasse o contexto o `text.tsx` teria de importar de volta — um
|
|
126
|
-
// ciclo. Este módulo é o que os dois já importam.
|
|
127
|
-
//
|
|
128
|
-
// ⚠ **Não sai pela porta da frente do pacote.** É acordo interno entre o `Card` e o `Text`.
|
|
129
112
|
const SobreAMarcaCtx = React.createContext(null);
|
|
130
113
|
/** O provedor. Quem usa é o `Card variant="brand"`. */
|
|
131
114
|
export const SobreAMarca = SobreAMarcaCtx;
|
|
132
115
|
/**
|
|
133
|
-
*
|
|
116
|
+
* O par de cores obrigatório quando se está sobre a marca, ou `null` quando não se está.
|
|
134
117
|
*
|
|
135
|
-
* ⚠ **
|
|
118
|
+
* ⚠ **Ele vence TODOS os tons, inclusive os explícitos.** Um `tone="danger"` sobre o amarelo
|
|
136
119
|
* mediria menos que os 4,5 da norma, então respeitá-lo entregaria texto ilegível em nome da
|
|
137
|
-
* obediência. **Sobre o amarelo existe UMA
|
|
120
|
+
* obediência. **Sobre o amarelo existe UMA tinta** — a hierarquia sai de peso e tamanho.
|
|
121
|
+
*
|
|
122
|
+
* ⚠ **E o alcance dele é DECLARADO, não completo.** Leem o contexto: `Text`, a família de campo,
|
|
123
|
+
* o `Button` e o `IconButton`. **Componente fora dessa lista continua quebrado dentro do cartão
|
|
124
|
+
* amarelo**, e gate estático nenhum vê isso — o que o consumidor encaixa não está no nosso
|
|
125
|
+
* código, exatamente o ponto cego que o `check 43` já declara.
|
|
138
126
|
*/
|
|
139
127
|
export function useSobreAMarca() {
|
|
140
128
|
return React.useContext(SobreAMarcaCtx);
|
|
141
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Corta a marca para dentro.
|
|
132
|
+
*
|
|
133
|
+
* 🔴 **Existe por uma armadilha do React Native que é invisível na tela e óbvia no código:** o
|
|
134
|
+
* `Modal` desenha numa camada POR CIMA de tudo, mas em React ele continua sendo FILHO de quem o
|
|
135
|
+
* escreveu. Um `Select` dentro de um `Card variant="brand"` abre a folha dele **fora** do cartão
|
|
136
|
+
* amarelo — e a folha herdaria a tinta do amarelo mesmo assim, pintando texto marrom sobre fundo
|
|
137
|
+
* normal.
|
|
138
|
+
*
|
|
139
|
+
* ⚠ **Camada visual e árvore de contexto são coisas diferentes**, e é só o segundo que manda na
|
|
140
|
+
* cor. Toda superfície que sai do fluxo — as duas folhas de escolha e os quatro sobrepostos —
|
|
141
|
+
* passa por aqui.
|
|
142
|
+
*/
|
|
143
|
+
export function ForaDaMarca({ children }) {
|
|
144
|
+
return _jsx(SobreAMarcaCtx.Provider, { value: null, children: children });
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* A pele que um CAMPO tem de vestir quando está dentro de um `Card variant="brand"`, ou `null`
|
|
148
|
+
* quando não está.
|
|
149
|
+
*
|
|
150
|
+
* O campo perde o fundo e passa a ser um contorno da tinta: **4,54 contra o amarelo nos dois
|
|
151
|
+
* temas**, contra os 2,43/2,24 do `borderStrong` e os 1,61 do `fieldBg` no tema claro. A norma
|
|
152
|
+
* 1.4.11 pede 3:1 para o contorno que identifica um campo, e só a tinta chega lá.
|
|
153
|
+
*
|
|
154
|
+
* ⚠ **O fundo some porque NÃO HÁ fundo possível** — medidas as três superfícies neutras do
|
|
155
|
+
* sistema contra o amarelo no tema claro: `card` 1,91 · `background` 1,73 · `secondary` 1,61.
|
|
156
|
+
* Nenhuma separa. Um contorno forte separa.
|
|
157
|
+
*
|
|
158
|
+
* 🔴 **E a tinta vence o estado de INVÁLIDO, que é o contrário do que a intuição manda.** Medido:
|
|
159
|
+
* a borda de inválido (`danger-400`, `#9f2330`) mede **1,86** contra o amarelo — ela é MENOS
|
|
160
|
+
* visível que a tinta. Pintar de vermelho ali deixaria o campo errado mais difícil de achar que o
|
|
161
|
+
* campo certo. Dentro deste cartão o erro é dito pela MENSAGEM do `Field` e pelo estado que o
|
|
162
|
+
* leitor de tela anuncia, não pela cor — que é o que a norma 1.4.1 já exige de qualquer forma.
|
|
163
|
+
*
|
|
164
|
+
* ⚠ **O texto digitado e o marcador de dica ficam da MESMA cor**, porque só existe uma tinta. É
|
|
165
|
+
* perda real de hierarquia, declarada e não escondida: sobre o amarelo não há segunda cor.
|
|
166
|
+
*/
|
|
167
|
+
export function usePeleSobreAMarca() {
|
|
168
|
+
const marca = useSobreAMarca();
|
|
169
|
+
return marca == null
|
|
170
|
+
? null
|
|
171
|
+
: { borderColor: marca.tinta, backgroundColor: "transparent", color: marca.tinta };
|
|
172
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurea-uds/native",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
4
4
|
"description": "React Native target for Aurea UDS: the theme x density provider, the first components and the Carbon icons, drawn on react-native-svg.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aurea",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"NOTICE"
|
|
48
48
|
],
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@aurea-uds/tokens": "^0.8.
|
|
50
|
+
"@aurea-uds/tokens": "^0.8.7"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"@react-native-community/datetimepicker": ">=8",
|