@aurea-uds/native 0.10.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions.js +28 -10
- package/dist/busca.d.ts +9 -2
- package/dist/busca.js +14 -5
- package/dist/display.d.ts +0 -16
- package/dist/display.js +21 -7
- package/dist/index.d.ts +1 -0
- package/dist/inputs.d.ts +10 -1
- package/dist/inputs.js +16 -8
- package/dist/navigation.d.ts +4 -1
- package/dist/navigation.js +2 -2
- package/dist/overlays.js +12 -5
- package/dist/rolagem.d.ts +8 -1
- package/dist/rolagem.js +7 -2
- package/package.json +2 -2
package/dist/actions.js
CHANGED
|
@@ -82,12 +82,24 @@ function pintar(t, tone) {
|
|
|
82
82
|
* sobre o amarelo, que é o único desenho que se enxerga nos dois temas;
|
|
83
83
|
* - **contornado e sem fundo** — contorno e letra viram a tinta.
|
|
84
84
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
85
|
+
* ~~⚠ **O tom pedido é IGNORADO aqui**~~ — **E7, 25/09/2026: no botão CHEIO com tom, ele vale.**
|
|
86
|
+
* O Victor quis as cores (confirmar em verde, "agora não" em vermelho). Medido antes, nos dois
|
|
87
|
+
* temas: a letra sobre o próprio fundo do botão passa sempre (sucesso 6,3 e 9,39; perigo 4,57 e
|
|
88
|
+
* 6,32), mas o FUNDO do botão contra o amarelo não se distingue (sucesso no escuro **1,00**,
|
|
89
|
+
* perigo 1,51, aviso 1,36; no claro perigo 2,50) — o formato sumiria. Então o botão cheio com tom
|
|
90
|
+
* mantém a cor dele e ganha **contorno na tinta do cartão** (4,54 contra o amarelo): a cor diz o
|
|
91
|
+
* que ele faz, o contorno diz onde ele está.
|
|
92
|
+
*
|
|
93
|
+
* ⚠ **No contornado e no sem fundo o tom continua ignorado**: ali a letra colorida fica direto
|
|
94
|
+
* sobre o amarelo, e nenhum tom passa de 4,5 — obedecer entregaria um botão ilegível. O neutro e
|
|
95
|
+
* o da marca também seguem na tinta (neutro 1,61; marca é amarelo no amarelo, 1,00).
|
|
87
96
|
*/
|
|
88
|
-
|
|
97
|
+
const TONS_COM_COR = new Set(["success", "danger", "warning", "info"]);
|
|
98
|
+
function pintarSobreAMarca(base, marca, tone, appearance) {
|
|
89
99
|
if (marca == null)
|
|
90
100
|
return base;
|
|
101
|
+
if (appearance === "solid" && TONS_COM_COR.has(tone))
|
|
102
|
+
return { ...base, contorno: marca.tinta };
|
|
91
103
|
return { solido: marca.tinta, texto: marca.fundo, sobre: marca.tinta };
|
|
92
104
|
}
|
|
93
105
|
const folha = criarFolha((t) => ({
|
|
@@ -131,22 +143,28 @@ export function Button({ children, appearance = "solid", tone = "neutral", size
|
|
|
131
143
|
const t = useAureaTokens();
|
|
132
144
|
const s = folha(t);
|
|
133
145
|
const marca = useSobreAMarca();
|
|
134
|
-
const cor = pintarSobreAMarca(pintar(t, tone), marca);
|
|
146
|
+
const cor = pintarSobreAMarca(pintar(t, tone), marca, tone, appearance);
|
|
135
147
|
const corDaBorda = marca?.tinta ?? t.color.border;
|
|
136
148
|
const caixa = React.useMemo(() => ({
|
|
137
149
|
height: t.size[ALTURA[size]],
|
|
138
150
|
paddingHorizontal: PADDING[size],
|
|
139
151
|
gap: GAP[size],
|
|
140
152
|
backgroundColor: appearance === "solid" ? cor.solido : "transparent",
|
|
141
|
-
borderColor: appearance === "outline" ? corDaBorda : "transparent",
|
|
153
|
+
borderColor: cor.contorno ?? (appearance === "outline" ? corDaBorda : "transparent"),
|
|
142
154
|
...(fullWidth ? { flex: 1 } : null),
|
|
143
|
-
}), [t, size, appearance, cor.solido, corDaBorda, fullWidth]);
|
|
155
|
+
}), [t, size, appearance, cor.solido, cor.contorno, corDaBorda, fullWidth]);
|
|
144
156
|
const corDoTexto = appearance === "solid" ? cor.texto : cor.sobre;
|
|
145
157
|
return (_jsx(Pressable, { disabled: disabled, accessibilityRole: "button", accessibilityLabel: accessibilityLabel, accessibilityState: { disabled: !!disabled, ...(pressed === undefined ? null : { checked: pressed }) }, style: ({ pressed: tocando }) => [
|
|
146
158
|
s.alvo, fullWidth && s.alvoLargura,
|
|
147
159
|
tocando && s.pressionado, disabled && s.inerte,
|
|
148
160
|
], ...rest, children: _jsxs(View, { style: [s.caixa, caixa], children: [leading ?? null, leadingIcon ? _jsx(Icon, { name: leadingIcon, size: ICONE[size], color: corDoTexto, icons: icons }) : null, typeof children === "string"
|
|
149
|
-
|
|
161
|
+
// E1 (25/09/2026): entrelinha NORMAL (1,5), como o rótulo do botão do HeroUI Native
|
|
162
|
+
// (`button.css`: `line-height: var(--text-*--line-height)`). Era `none` (1,0), e o IBM
|
|
163
|
+
// Plex precisa de 1,3 em para caber inteiro (sobe 1,025 e desce 0,275): no Android o RN
|
|
164
|
+
// corta o que passa da linha, e a perna do g, do p e do ç sumia. Cabe em todo tamanho e
|
|
165
|
+
// densidade (medido): `xs`/`sm` têm linha de 21 e o menor botão mede 24 (compacto); os
|
|
166
|
+
// maiores têm linha de 24 e medem 32 ou mais.
|
|
167
|
+
? _jsx(Text, { size: FONTE[size], weight: 500, leading: "normal", style: { color: corDoTexto }, children: children })
|
|
150
168
|
: children, trailingIcon ? _jsx(Icon, { name: trailingIcon, size: ICONE[size], color: corDoTexto, icons: icons }) : null, trailing ?? null] }) }));
|
|
151
169
|
}
|
|
152
170
|
/**
|
|
@@ -162,15 +180,15 @@ export function IconButton({ name, label, appearance = "ghost", tone = "neutral"
|
|
|
162
180
|
const t = useAureaTokens();
|
|
163
181
|
const s = folha(t);
|
|
164
182
|
const marca = useSobreAMarca();
|
|
165
|
-
const cor = pintarSobreAMarca(pintar(t, tone), marca);
|
|
183
|
+
const cor = pintarSobreAMarca(pintar(t, tone), marca, tone, appearance);
|
|
166
184
|
const corDaBorda = marca?.tinta ?? t.color.border;
|
|
167
185
|
const lado = t.size[ALTURA[size]];
|
|
168
186
|
const caixa = React.useMemo(() => ({
|
|
169
187
|
height: lado, width: lado, paddingHorizontal: 0,
|
|
170
188
|
borderRadius: size === "xs" || size === "sm" ? t.size.radiusSm : t.size.radiusMd,
|
|
171
189
|
backgroundColor: appearance === "solid" ? cor.solido : "transparent",
|
|
172
|
-
borderColor: appearance === "outline" ? corDaBorda : "transparent",
|
|
173
|
-
}), [t, lado, size, appearance, cor.solido, corDaBorda]);
|
|
190
|
+
borderColor: cor.contorno ?? (appearance === "outline" ? corDaBorda : "transparent"),
|
|
191
|
+
}), [t, lado, size, appearance, cor.solido, cor.contorno, corDaBorda]);
|
|
174
192
|
return (_jsx(Pressable, { disabled: disabled, accessibilityRole: "button", accessibilityLabel: label, accessibilityState: { disabled: !!disabled, ...(pressed === undefined ? null : { checked: pressed }) }, style: ({ pressed: tocando }) => [
|
|
175
193
|
s.alvo, { minWidth: t.size.targetMin, alignItems: "center" },
|
|
176
194
|
tocando && s.pressionado, disabled && s.inerte,
|
package/dist/busca.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { type StyleProp, type ViewStyle } from "react-native";
|
|
2
|
+
import { type TextInputProps, type StyleProp, type ViewStyle } from "react-native";
|
|
3
3
|
import { type IconName } from "./icon.js";
|
|
4
4
|
import { type AureaFieldSize } from "./inputs.js";
|
|
5
5
|
/** Uma linha do catálogo. **Mesma forma da web** (`ComboboxOption`), mais o `disabled` que o `Select` daqui já tinha. */
|
|
@@ -59,6 +59,13 @@ export interface ComboboxProps {
|
|
|
59
59
|
chevron?: IconName | false;
|
|
60
60
|
/** O glifo da lupa no campo da folha. Registre-o, ou passe `false`. */
|
|
61
61
|
searchIcon?: IconName | false;
|
|
62
|
+
/**
|
|
63
|
+
* O teclado do campo de busca da folha — E6, 25/09/2026. Para buscar um ANO ou um código, passe
|
|
64
|
+
* `"number-pad"`: sem isto abre o teclado de letras. É o `keyboardType` do `TextInput`, com o
|
|
65
|
+
* mesmo prefixo `search` do `searchPlaceholder` e do `searchIcon`, que também são do campo da
|
|
66
|
+
* folha e não do gatilho. Padrão: o teclado de texto.
|
|
67
|
+
*/
|
|
68
|
+
searchKeyboardType?: TextInputProps["keyboardType"];
|
|
62
69
|
style?: StyleProp<ViewStyle>;
|
|
63
70
|
testID?: string;
|
|
64
71
|
}
|
|
@@ -91,7 +98,7 @@ export interface ComboboxProps {
|
|
|
91
98
|
* na web e pela mesma razão do achado I1 da auditoria: um componente com a sua própria cópia do
|
|
92
99
|
* estado é a segunda fonte de verdade que ninguém sabe que existe.
|
|
93
100
|
*/
|
|
94
|
-
export declare function Combobox({ items, value, onValueChange, onSearchChange, searchDelay, loading, onEndReached, placeholder, searchPlaceholder, empty, clearable, draggable, disabled, size, chevron, searchIcon, style, testID, }: ComboboxProps): React.JSX.Element;
|
|
101
|
+
export declare function Combobox({ items, value, onValueChange, onSearchChange, searchDelay, loading, onEndReached, placeholder, searchPlaceholder, empty, clearable, draggable, disabled, size, chevron, searchIcon, searchKeyboardType, style, testID, }: ComboboxProps): React.JSX.Element;
|
|
95
102
|
export interface SearchFieldProps {
|
|
96
103
|
value?: string;
|
|
97
104
|
onChangeText?: (v: string) => void;
|
package/dist/busca.js
CHANGED
|
@@ -68,6 +68,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
68
68
|
// folha, e ele leva `search` — que mapeia nos dois.
|
|
69
69
|
import * as React from "react";
|
|
70
70
|
import { Animated, Easing, FlatList, Modal, PanResponder, Pressable, TextInput, View, } from "react-native";
|
|
71
|
+
import { SafeAreaView } from "react-native-safe-area-context";
|
|
71
72
|
import { IconButton } from "./actions.js";
|
|
72
73
|
import { criarFolha } from "./estilos.js";
|
|
73
74
|
import { Spinner } from "./feedback.js";
|
|
@@ -130,7 +131,15 @@ const folha = criarFolha((t) => ({
|
|
|
130
131
|
// para abrir. `accessible={false}` no JSX porque o gatilho JÁ anuncia tudo: um segundo botão
|
|
131
132
|
// aqui seria a mesma informação duas vezes. O `Icon` sem rótulo já se esconde sozinho
|
|
132
133
|
// (`icon.tsx:104`), então não sobra nada para o leitor de tela tropeçar.
|
|
133
|
-
|
|
134
|
+
// E8 (25/09/2026): a seta tem a MESMA caixa de toque do X — `targetMin` (44) de altura mínima,
|
|
135
|
+
// conteúdo no meio —, e duas caixas iguais numa fila centralizada têm o mesmo centro, com ou
|
|
136
|
+
// sem o X. Era `height: "100%"`, e a fila `acoes` não tem altura: medido no Yoga 3 (o motor do
|
|
137
|
+
// RN), com a errata de compatibilidade (`Errata.All`) o 100% se resolvia errado — a seta ficava
|
|
138
|
+
// com 25 de altura e o centro dela 5 abaixo do centro do X e do campo, que é o que o app viu no
|
|
139
|
+
// Android. Nos outros modos o defeito some. Com a caixa igual, os três centros coincidem nas 18
|
|
140
|
+
// combinações medidas (3 erratas × campo de 32/36/40 × com e sem X), e o toque da seta sobe de
|
|
141
|
+
// 16 para 44 de altura.
|
|
142
|
+
setaToque: { minHeight: t.size.targetMin, justifyContent: "center" },
|
|
134
143
|
// A folha, com a mesma anatomia da do `Select` (`inputs.tsx:98-113`) — e é de propósito que
|
|
135
144
|
// sejam iguais: são o mesmo gesto, e duas folhas diferentes para o mesmo gesto é como uma
|
|
136
145
|
// biblioteca deixa de ter linguagem.
|
|
@@ -202,7 +211,7 @@ const folha = criarFolha((t) => ({
|
|
|
202
211
|
* na web e pela mesma razão do achado I1 da auditoria: um componente com a sua própria cópia do
|
|
203
212
|
* estado é a segunda fonte de verdade que ninguém sabe que existe.
|
|
204
213
|
*/
|
|
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, }) {
|
|
214
|
+
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", searchKeyboardType, style, testID, }) {
|
|
206
215
|
const t = useAureaTokens();
|
|
207
216
|
const s = folha(t);
|
|
208
217
|
const peleDaMarca = usePeleSobreAMarca();
|
|
@@ -297,7 +306,7 @@ export function Combobox({ items, value, onValueChange, onSearchChange, searchDe
|
|
|
297
306
|
peleDaMarca,
|
|
298
307
|
inativo && s.desabilitado,
|
|
299
308
|
style,
|
|
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; },
|
|
309
|
+
], 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; }, 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
310
|
// ⚠ `autoFocus` é o que faz a folha valer a pena: abrir um campo de busca e
|
|
302
311
|
// exigir um segundo toque para o teclado subir é um toque a mais em cada
|
|
303
312
|
// cadastro. O foco entra com a folha; o teclado vem junto.
|
|
@@ -307,7 +316,7 @@ export function Combobox({ items, value, onValueChange, onSearchChange, searchDe
|
|
|
307
316
|
// `returnKeyType="search"` troca o "enter" do teclado pela lupa. É pista de
|
|
308
317
|
// plataforma, não decoração: diz à pessoa que aquele campo é de busca antes de
|
|
309
318
|
// ela digitar a primeira letra.
|
|
310
|
-
returnKeyType: "search", style: [
|
|
319
|
+
returnKeyType: "search", keyboardType: searchKeyboardType, style: [
|
|
311
320
|
s.campoDeTexto,
|
|
312
321
|
{ fontSize: fonteDoTamanho(t, tam), fontFamily: t.font.ui[400],
|
|
313
322
|
color: t.color.foreground },
|
|
@@ -319,7 +328,7 @@ export function Combobox({ items, value, onValueChange, onSearchChange, searchDe
|
|
|
319
328
|
s.opcao,
|
|
320
329
|
item.value === value?.value && s.opcaoEscolhida,
|
|
321
330
|
item.disabled && s.desabilitado,
|
|
322
|
-
], children: _jsx(Text, { size: "md", weight: item.value === value?.value ? 600 : 400, children: item.label }) })) })] })] }) }) })] }));
|
|
331
|
+
], children: _jsx(Text, { size: "md", weight: item.value === value?.value ? 600 : 400, children: item.label }) })) }), _jsx(SafeAreaView, { edges: ["bottom"] })] })] }) }) })] }));
|
|
323
332
|
}
|
|
324
333
|
// ── A DOBRA DE ACENTO, e por que ela é sondada em vez de presumida ───────────────────────────
|
|
325
334
|
// Buscar "acucar" tem de achar "açúcar" — num catálogo em português, exigir o acento certo é
|
package/dist/display.d.ts
CHANGED
|
@@ -57,22 +57,6 @@ export interface BadgeProps extends ViewProps {
|
|
|
57
57
|
invisible?: boolean;
|
|
58
58
|
children?: React.ReactNode;
|
|
59
59
|
}
|
|
60
|
-
/**
|
|
61
|
-
* A pílula pequena — rótulo, contagem ou ponto.
|
|
62
|
-
*
|
|
63
|
-
* ⚠ **Ancorado, o número é DECORATIVO para o leitor de tela.** Ele some da árvore, e quem carrega
|
|
64
|
-
* a informação é o rótulo de quem foi decorado. Sem isso o leitor anuncia *"sino, 8"* e a pessoa
|
|
65
|
-
* não sabe o que é o 8 — regra lida em três fontes de acessibilidade em 17/08/2026 e registrada
|
|
66
|
-
* no fonte da web. **Quem usa contagem ancorada escreve o rótulo do alvo**, sempre:
|
|
67
|
-
*
|
|
68
|
-
* <Badge count={8} anchor="top-end">
|
|
69
|
-
* <IconButton name="notification" label="Avisos, 8 não lidos" onPress={abrir} />
|
|
70
|
-
* </Badge>
|
|
71
|
-
*
|
|
72
|
-
* ⚠ **`image`/`imageAlt` da web NÃO atravessaram.** Nenhuma das sete telas do consumidor medido
|
|
73
|
-
* usa selo com miniatura, e prop sem consumidor é superfície pública para manter de graça. Volta
|
|
74
|
-
* quando houver tela que peça.
|
|
75
|
-
*/
|
|
76
60
|
export declare function Badge({ tone, emphasis, size, dot, count, max, showZero, leading, trailing, fit, anchor, badgeContent, invisible, children, style, ...rest }: BadgeProps): React.JSX.Element;
|
|
77
61
|
export type AureaStatusVariant = "neutral" | "online" | "offline" | "busy" | "away" | "success" | "warning" | "danger" | "info";
|
|
78
62
|
export interface StatusProps extends ViewProps {
|
package/dist/display.js
CHANGED
|
@@ -30,18 +30,27 @@ import { Text } from "./text.js";
|
|
|
30
30
|
import { useAureaStrings, useAureaTokens } from "./theme.js";
|
|
31
31
|
const folha = criarFolha((t) => ({
|
|
32
32
|
// ── Badge ──────────────────────────────────────────────────────────────────────────────────
|
|
33
|
-
//
|
|
34
|
-
//
|
|
33
|
+
// 🔴 AS MEDIDAS SÃO AS DO `Chip` DO HeroUI NATIVE (1.0.10, `chip.css`) — ordem do Victor de
|
|
34
|
+
// 25/09/2026: "se o HeroUI já tem, vamos usar as deles". Recheio, letra, linha e vão:
|
|
35
|
+
// sm 8 × 2 · letra 12 · linha 16 md 12 × 4 · letra 14 · linha 20
|
|
36
|
+
// lg 16 × 6 · letra 16 · linha 24 vão 4 entre ponto, texto e adornos
|
|
37
|
+
// Até a 0.10.1 eram `3px 9px` e `gap:6` crus, e o texto saía com entrelinha 1,0: no Android a
|
|
38
|
+
// perna do g e do p era cortada (a mesma causa do E1 no `Button`). A linha do HeroUI é ≥ 1,33 ×
|
|
39
|
+
// a letra, e o IBM Plex precisa de 1,3. O raio continua a cápsula da Aurea (identidade) e a
|
|
40
|
+
// borda continua nossa.
|
|
41
|
+
// ⚠ O `xs` NÃO existe no HeroUI (é o contador sobre ícone): fica a medida nossa, 16 de altura,
|
|
42
|
+
// agora com letra 12 e linha 16 para caber a letra inteira.
|
|
35
43
|
selo: {
|
|
36
|
-
flexDirection: "row", alignItems: "center", justifyContent: "center", gap:
|
|
37
|
-
|
|
44
|
+
flexDirection: "row", alignItems: "center", justifyContent: "center", gap: t.size.space1,
|
|
45
|
+
paddingVertical: t.size.space1, paddingHorizontal: t.size.space3,
|
|
38
46
|
borderWidth: t.size.borderWidth, borderRadius: t.size.radiusControl,
|
|
39
47
|
backgroundColor: t.color.secondary, borderColor: t.color.border,
|
|
40
48
|
},
|
|
41
49
|
selo_xs: { minHeight: t.size.space4, paddingVertical: 0, paddingHorizontal: t.size.space1, borderWidth: 0 },
|
|
42
|
-
selo_sm: {
|
|
50
|
+
selo_sm: { paddingVertical: t.size.space05, paddingHorizontal: t.size.space2 },
|
|
43
51
|
selo_md: {},
|
|
44
|
-
|
|
52
|
+
// 6 de recheio vertical: no HeroUI é `calc(var(--spacing) * 1.5)`, e `--spacing` é o `space1`.
|
|
53
|
+
selo_lg: { paddingVertical: t.size.space1 * 1.5, paddingHorizontal: t.size.space4 },
|
|
45
54
|
ponto: { width: t.size.space2, height: t.size.space2, borderRadius: t.size.radiusFull },
|
|
46
55
|
// `fit="content"` (R-01): o mesmo `alignSelf` que a âncora abaixo já usa para não esticar.
|
|
47
56
|
justo: { alignSelf: "flex-start" },
|
|
@@ -85,6 +94,11 @@ export const formatarContagem = (count, max = 99) => count > max ? `${max}+` : S
|
|
|
85
94
|
* usa selo com miniatura, e prop sem consumidor é superfície pública para manter de graça. Volta
|
|
86
95
|
* quando houver tela que peça.
|
|
87
96
|
*/
|
|
97
|
+
/** A letra e a linha do selo, do `Chip` do HeroUI Native (ver a folha). O token direto, e não o
|
|
98
|
+
* `size` do `Text`, que no telefone sobe um degrau (ADR-0050) — o HeroUI não sobe no chip. */
|
|
99
|
+
const LETRA_DO_SELO = (t, size) => size === "lg" ? { fontSize: t.size.textBase, lineHeight: t.size.space6 }
|
|
100
|
+
: size === "md" ? { fontSize: t.size.textSm, lineHeight: t.size.space5 }
|
|
101
|
+
: { fontSize: t.size.textXs, lineHeight: t.size.space4 };
|
|
88
102
|
export function Badge({ tone = "neutral", emphasis = "soft", size = "md", dot, count, max = 99, showZero, leading, trailing, fit = "auto", anchor, badgeContent, invisible, children, style, ...rest }) {
|
|
89
103
|
const t = useAureaTokens();
|
|
90
104
|
const s = folha(t);
|
|
@@ -123,7 +137,7 @@ export function Badge({ tone = "neutral", emphasis = "soft", size = "md", dot, c
|
|
|
123
137
|
style,
|
|
124
138
|
], ...(anchor ? { accessibilityElementsHidden: true,
|
|
125
139
|
importantForAccessibility: "no-hide-descendants" } : rest), children: [dot && !soPonto && _jsx(View, { style: [s.ponto, { backgroundColor: corDoTexto }] }), !soPonto && leading, typeof miolo === "string" || typeof miolo === "number"
|
|
126
|
-
? _jsx(Text, {
|
|
140
|
+
? _jsx(Text, { weight: 500, style: [LETRA_DO_SELO(t, size), { color: corDoTexto }], children: miolo })
|
|
127
141
|
: miolo, !soPonto && trailing] }));
|
|
128
142
|
if (!anchor)
|
|
129
143
|
return selo;
|
package/dist/index.d.ts
CHANGED
|
@@ -42,3 +42,4 @@ export { NumberField, formatarNumero, lerNumero, separadoresDoLocale } from "./n
|
|
|
42
42
|
export type { NumberFieldProps, AureaSeparadores } from "./numero.js";
|
|
43
43
|
export { Image, Gallery } from "./midia.js";
|
|
44
44
|
export type { ImageProps, GalleryProps, AureaGalleryItem, AureaImageSource, } from "./midia.js";
|
|
45
|
+
export type { AureaFilaJustify } from "./rolagem.js";
|
package/dist/inputs.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { TextInput, type KeyboardTypeOptions, type StyleProp, type TextInputProps, type TextStyle, type ViewProps, type ViewStyle } from "react-native";
|
|
3
|
+
import { type AureaFilaJustify } from "./rolagem.js";
|
|
3
4
|
import { type AureaIconRegistry, type IconName } from "./icon.js";
|
|
4
5
|
export type AureaFieldSize = "sm" | "md" | "lg";
|
|
5
6
|
type ContextoDeCampo = {
|
|
@@ -150,6 +151,12 @@ interface ControleProps {
|
|
|
150
151
|
size?: AureaFieldSize;
|
|
151
152
|
style?: StyleProp<ViewStyle>;
|
|
152
153
|
testID?: string;
|
|
154
|
+
/**
|
|
155
|
+
* Onde a marca fica na altura do texto — E5, 25/09/2026. `center` (o padrão) põe a marca no meio
|
|
156
|
+
* do bloco, como o HeroUI Native (`radio.css` e `control-field.css`: `align-items: center`).
|
|
157
|
+
* `start` a põe no meio da PRIMEIRA linha, para rótulo longo, de várias linhas.
|
|
158
|
+
*/
|
|
159
|
+
align?: "center" | "start";
|
|
153
160
|
/**
|
|
154
161
|
* O nome para quem usa leitor de tela, quando ele NÃO deve aparecer escrito no controle.
|
|
155
162
|
*
|
|
@@ -275,6 +282,8 @@ export interface SegmentedControlProps extends ViewProps {
|
|
|
275
282
|
/** Nome do grupo para o leitor de tela. */
|
|
276
283
|
label?: string;
|
|
277
284
|
disabled?: boolean;
|
|
285
|
+
/** Onde o controle fica quando cabe na linha: `start` (padrão), `center` ou `end` (E3). */
|
|
286
|
+
justify?: AureaFilaJustify;
|
|
278
287
|
}
|
|
279
288
|
/**
|
|
280
289
|
* Um de poucos, lado a lado.
|
|
@@ -284,7 +293,7 @@ export interface SegmentedControlProps extends ViewProps {
|
|
|
284
293
|
* há teclado aqui**, então o que resta é o que já se faz à mão: papel de grupo de rádio, um
|
|
285
294
|
* `radio` por segmento, e o estado `selected` em quem está escolhido.
|
|
286
295
|
*/
|
|
287
|
-
export declare function SegmentedControl({ items, value, onChange, label, disabled, style, ...rest }: SegmentedControlProps): React.JSX.Element;
|
|
296
|
+
export declare function SegmentedControl({ items, value, onChange, label, disabled, justify, style, ...rest }: SegmentedControlProps): React.JSX.Element;
|
|
288
297
|
export interface SelectProps {
|
|
289
298
|
items: Array<{
|
|
290
299
|
value: string;
|
package/dist/inputs.js
CHANGED
|
@@ -39,6 +39,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
39
39
|
// .segmented :922 linha, gap 3, padding 3, minH controlHMd, fundo muted
|
|
40
40
|
import * as React from "react";
|
|
41
41
|
import { Animated, KeyboardAvoidingView as KeyboardAvoidingViewRN, Modal, Platform, Pressable, ScrollView, TextInput, View, } from "react-native";
|
|
42
|
+
import { SafeAreaView } from "react-native-safe-area-context";
|
|
42
43
|
import { comOpacidade, criarFolha } from "./estilos.js";
|
|
43
44
|
import { FilaRolante } from "./rolagem.js";
|
|
44
45
|
import { IconButton } from "./actions.js";
|
|
@@ -79,11 +80,14 @@ const folha = criarFolha((t) => ({
|
|
|
79
80
|
campoNoGrupo: { flex: 1, minWidth: 0, paddingVertical: 0, textAlignVertical: "center" },
|
|
80
81
|
encaixe: { flexDirection: "row", alignItems: "center", flexShrink: 0, gap: t.size.space1 },
|
|
81
82
|
marcaBase: {
|
|
82
|
-
alignItems: "center", justifyContent: "center",
|
|
83
|
+
alignItems: "center", justifyContent: "center",
|
|
83
84
|
borderWidth: t.size.borderWidth, borderColor: t.color.borderStrong,
|
|
84
85
|
backgroundColor: t.color.fieldBg,
|
|
85
86
|
},
|
|
86
|
-
|
|
87
|
+
// E5: a marca no MEIO da altura do texto, como o HeroUI Native. Era `flex-start` com um
|
|
88
|
+
// `marginTop: 1` fixo, e a bolinha ficava presa no topo do rótulo.
|
|
89
|
+
linhaDeControle: { flexDirection: "row", alignItems: "center", gap: 9 },
|
|
90
|
+
linhaNoTopo: { alignItems: "flex-start" },
|
|
87
91
|
trilho: { borderRadius: t.size.radiusFull, backgroundColor: t.color.muted,
|
|
88
92
|
borderWidth: t.size.borderWidth, borderColor: t.color.border, justifyContent: "center" },
|
|
89
93
|
polegar: { position: "absolute", left: 3, borderRadius: t.size.radiusFull },
|
|
@@ -327,7 +331,7 @@ export function PasswordField({ defaultVisible = false, size, disabled, autoCapi
|
|
|
327
331
|
const inativo = disabled ?? campo?.disabled;
|
|
328
332
|
return (_jsxs(InputGroup, { size: tam, disabled: inativo, testID: testID, children: [leading ? _jsx(InputGroupAddon, { children: leading }) : null, _jsx(Input, { ...rest, size: tam, disabled: inativo, autoCapitalize: autoCapitalize, secureTextEntry: !visivel, style: style, testID: testID ? `${testID}-campo` : undefined }), _jsx(InputGroupAddon, { children: _jsx(IconButton, { name: visivel ? "view--off" : "view", label: visivel ? strings.passwordHide : strings.passwordShow, appearance: "ghost", size: tam === "lg" ? "md" : "sm", disabled: inativo, icons: icons, onPress: () => setVisivel(v => !v), testID: testID ? `${testID}-olho` : undefined }) })] }));
|
|
329
333
|
}
|
|
330
|
-
function ControleMarcado({ papel, label, description, checked, onChange, disabled, size, style, testID, accessibilityLabel, }) {
|
|
334
|
+
function ControleMarcado({ papel, label, description, checked, onChange, disabled, size, style, testID, accessibilityLabel, align = "center", }) {
|
|
331
335
|
const t = useAureaTokens();
|
|
332
336
|
const s = folha(t);
|
|
333
337
|
const campo = useCampo();
|
|
@@ -339,12 +343,16 @@ function ControleMarcado({ papel, label, description, checked, onChange, disable
|
|
|
339
343
|
// A marca é METADE da altura do controle — `aurea.css:871`, e é o que faz ela crescer junto
|
|
340
344
|
// com a densidade sem token próprio.
|
|
341
345
|
const lado = alturaDoTamanho(t, tam) / 2;
|
|
346
|
+
// `start`: o meio da marca no meio da PRIMEIRA linha do rótulo. A linha é a do `Text size="sm"`
|
|
347
|
+
// do rótulo (entrelinha normal), então a conta sai dos mesmos tokens que desenham o texto.
|
|
348
|
+
const linha = t.size.textBase * t.size.leadingNormal;
|
|
349
|
+
const noTopo = align === "start" ? { marginTop: Math.max(0, (linha - lado) / 2) } : null;
|
|
342
350
|
return (_jsxs(Pressable, { testID: testID, onPress: inativo ? undefined : () => onChange?.(!checked), disabled: inativo, accessibilityRole: papel, accessibilityState: { checked: !!checked, disabled: !!inativo },
|
|
343
351
|
// ⚠ O `accessibilityLabel` de fora vence o `label` escrito, e existe para o caso em que o
|
|
344
352
|
// nome JÁ está na tela ao lado — uma linha de `NavList`, por exemplo. Sem ele, ou o nome
|
|
345
353
|
// aparece escrito duas vezes, ou o controle sobe MUDO para quem usa leitor de tela.
|
|
346
|
-
accessibilityLabel: accessibilityLabel ?? (typeof label === "string" ? label : campo?.label), accessibilityHint: typeof description === "string" ? description : campo?.hint, style: [s.linhaDeControle, inativo && s.desabilitado, style], children: [_jsx(View, { style: [
|
|
347
|
-
s.marcaBase,
|
|
354
|
+
accessibilityLabel: accessibilityLabel ?? (typeof label === "string" ? label : campo?.label), accessibilityHint: typeof description === "string" ? description : campo?.hint, style: [s.linhaDeControle, align === "start" && s.linhaNoTopo, inativo && s.desabilitado, style], children: [_jsx(View, { style: [
|
|
355
|
+
s.marcaBase, noTopo,
|
|
348
356
|
{ width: lado, height: lado,
|
|
349
357
|
borderRadius: papel === "radio" ? t.size.radiusFull : 5 },
|
|
350
358
|
checked && { backgroundColor: t.color.controlSelected, borderColor: t.color.controlSelected },
|
|
@@ -452,12 +460,12 @@ export function Switch({ label, description, checked, onChange, disabled, size,
|
|
|
452
460
|
* há teclado aqui**, então o que resta é o que já se faz à mão: papel de grupo de rádio, um
|
|
453
461
|
* `radio` por segmento, e o estado `selected` em quem está escolhido.
|
|
454
462
|
*/
|
|
455
|
-
export function SegmentedControl({ items, value, onChange, label, disabled, style, ...rest }) {
|
|
463
|
+
export function SegmentedControl({ items, value, onChange, label, disabled, justify, style, ...rest }) {
|
|
456
464
|
const t = useAureaTokens();
|
|
457
465
|
const s = folha(t);
|
|
458
466
|
const campo = useCampo();
|
|
459
467
|
const inativo = disabled ?? campo?.disabled;
|
|
460
|
-
return (_jsx(FilaRolante, { children: _jsx(View, { accessibilityRole: "radiogroup", accessibilityLabel: label ?? campo?.label, style: [s.segmentada, inativo && s.desabilitado, style], ...rest, children: items.map((it) => {
|
|
468
|
+
return (_jsx(FilaRolante, { justify: justify, children: _jsx(View, { accessibilityRole: "radiogroup", accessibilityLabel: label ?? campo?.label, style: [s.segmentada, inativo && s.desabilitado, style], ...rest, children: items.map((it) => {
|
|
461
469
|
const ativo = it.value === value;
|
|
462
470
|
return (_jsxs(Pressable, { onPress: inativo ? undefined : () => onChange?.(it.value), disabled: inativo, accessibilityRole: "radio", accessibilityState: { checked: ativo, disabled: !!inativo }, accessibilityLabel: typeof it.label === "string" ? it.label : undefined, style: [s.segmento, ativo && s.segmentoAtivo], children: [typeof it.label === "string"
|
|
463
471
|
? _jsx(Text, { size: "sm", weight: ativo ? 600 : 400,
|
|
@@ -519,7 +527,7 @@ export function Select({ items, value, onChange, placeholder, disabled, size, ch
|
|
|
519
527
|
peleDaMarca,
|
|
520
528
|
inativo && s.desabilitado,
|
|
521
529
|
style,
|
|
522
|
-
], 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(
|
|
530
|
+
], 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(SafeAreaView, { edges: ["bottom"], style: s.lista, 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))) }) })] }) }) })] }));
|
|
523
531
|
}
|
|
524
532
|
/**
|
|
525
533
|
* A pilha de campos, com o respiro do `--space-5`.
|
package/dist/navigation.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type ViewProps } from "react-native";
|
|
3
3
|
import { type IconName } from "./icon.js";
|
|
4
|
+
import { type AureaFilaJustify } from "./rolagem.js";
|
|
4
5
|
export interface AureaNavItem {
|
|
5
6
|
id: string;
|
|
6
7
|
label: React.ReactNode;
|
|
@@ -197,6 +198,8 @@ export interface TabsProps extends ViewProps {
|
|
|
197
198
|
onChange?: (id: string) => void;
|
|
198
199
|
/** Nome da fila de abas para o leitor de tela. */
|
|
199
200
|
label?: string;
|
|
201
|
+
/** Onde a fila de abas fica quando cabe: `start` (padrão), `center` ou `end` (E3). */
|
|
202
|
+
justify?: AureaFilaJustify;
|
|
200
203
|
}
|
|
201
204
|
/**
|
|
202
205
|
* As abas DENTRO da tela — trocar o painel, não trocar de página.
|
|
@@ -231,4 +234,4 @@ export interface TabsProps extends ViewProps {
|
|
|
231
234
|
* largura de tela grande. Não há tablet medido neste projeto, e no nativo vale demanda antes de
|
|
232
235
|
* cobertura — a mesma decisão da `Table` do Lote 6.
|
|
233
236
|
*/
|
|
234
|
-
export declare function Tabs({ tabs, value, onChange, label, style, ...rest }: TabsProps): React.JSX.Element;
|
|
237
|
+
export declare function Tabs({ tabs, value, onChange, label, justify, style, ...rest }: TabsProps): React.JSX.Element;
|
package/dist/navigation.js
CHANGED
|
@@ -413,12 +413,12 @@ export function Stepper({ items, label, doneIcon = "checkmark", errorIcon = "err
|
|
|
413
413
|
* largura de tela grande. Não há tablet medido neste projeto, e no nativo vale demanda antes de
|
|
414
414
|
* cobertura — a mesma decisão da `Table` do Lote 6.
|
|
415
415
|
*/
|
|
416
|
-
export function Tabs({ tabs, value, onChange, label, style, ...rest }) {
|
|
416
|
+
export function Tabs({ tabs, value, onChange, label, justify, style, ...rest }) {
|
|
417
417
|
const t = useAureaTokens();
|
|
418
418
|
const s = folha(t);
|
|
419
419
|
const strings = useAureaStrings();
|
|
420
420
|
const aberta = tabs.find((it) => it.id === value);
|
|
421
|
-
return (_jsxs(View, { style: style, ...rest, children: [_jsx(FilaRolante, { children: _jsx(View, { accessibilityRole: "tablist", accessibilityLabel: label ?? strings.tabsLabel, style: s.abas, children: tabs.map((it) => {
|
|
421
|
+
return (_jsxs(View, { style: style, ...rest, children: [_jsx(FilaRolante, { justify: justify, children: _jsx(View, { accessibilityRole: "tablist", accessibilityLabel: label ?? strings.tabsLabel, style: s.abas, children: tabs.map((it) => {
|
|
422
422
|
const ativa = it.id === value;
|
|
423
423
|
return (_jsx(Pressable, { onPress: it.disabled ? undefined : () => onChange?.(it.id), disabled: it.disabled, accessibilityRole: "tab", accessibilityState: { selected: ativa, disabled: !!it.disabled }, accessibilityLabel: typeof it.label === "string" ? it.label : undefined, style: [s.abaDeTab, ativa && s.abaDeTabAtiva, it.disabled && { opacity: t.size.opacityDisabled }], children: typeof it.label === "string"
|
|
424
424
|
? _jsx(Text, { size: "sm", weight: ativa ? 600 : 400, style: { color: ativa ? t.color.foreground : t.color.mutedForeground }, children: it.label })
|
package/dist/overlays.js
CHANGED
|
@@ -57,6 +57,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
57
57
|
// mesma função interna com uma largura diferente.
|
|
58
58
|
import * as React from "react";
|
|
59
59
|
import { Animated, Easing, Modal, PanResponder, Pressable, ScrollView, View, } from "react-native";
|
|
60
|
+
import { SafeAreaView } from "react-native-safe-area-context";
|
|
60
61
|
import { Button } from "./actions.js";
|
|
61
62
|
import { criarFolha } from "./estilos.js";
|
|
62
63
|
import { IconButton } from "./actions.js";
|
|
@@ -133,8 +134,14 @@ const DURACAO = 280;
|
|
|
133
134
|
// afirmação mais forte que "passou no teste", mas não é o vidro. Foi exatamente confiar em
|
|
134
135
|
// "passou no teste" que produziu a primeira tentativa.
|
|
135
136
|
//
|
|
136
|
-
// O `naoAtravessa` FICA no painel como segunda linha: agora é redundante, e redundância que
|
|
137
|
-
// não custa nada num caminho que já falhou uma vez se paga
|
|
137
|
+
// ~~O `naoAtravessa` FICA no painel como segunda linha: agora é redundante, e redundância que
|
|
138
|
+
// não custa nada num caminho que já falhou uma vez se paga.~~ — **E4, 25/09/2026: ela CUSTAVA.**
|
|
139
|
+
// No Android, um `View` que vira dono do toque pelo JavaScript passa a interceptar os movimentos
|
|
140
|
+
// seguintes (`JSResponderHandler.onInterceptTouchEvent`), e o `ScrollView` de dentro deixa de
|
|
141
|
+
// rolar. O app viu a lista do `Select` e a do `Combobox` sem rolar; a suspeita não está confirmada
|
|
142
|
+
// no aparelho, mas a linha era redundante por construção e saiu dos painéis que têm rolagem dentro
|
|
143
|
+
// (`Dialog`, `Drawer`, `Select`, `Combobox`). Fica no `ConfirmDialog` (sem fundo tocável e sem
|
|
144
|
+
// rolagem) e no `BottomSheet`, onde os `panHandlers` do arrasto já a sobrescrevem.
|
|
138
145
|
//
|
|
139
146
|
// ⚠ Vale para os QUATRO que têm esta forma: `Dialog`, `Drawer`, `BottomSheet` e o `Select` do
|
|
140
147
|
// Lote 4 (`inputs.tsx`). O `ConfirmDialog` é imune desde que nasceu — o fundo dele não tem
|
|
@@ -157,7 +164,7 @@ export function Dialog({ open, title, children, footer, onClose, scroll = true,
|
|
|
157
164
|
const s = folha(t);
|
|
158
165
|
const strings = useAureaStrings();
|
|
159
166
|
const Corpo = scroll ? ScrollView : View;
|
|
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, {
|
|
167
|
+
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, { 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
168
|
}
|
|
162
169
|
/**
|
|
163
170
|
* A decisão que não se desfaz.
|
|
@@ -229,7 +236,7 @@ export function Drawer({ open, title, children, onClose, side = "right", scroll
|
|
|
229
236
|
inputRange: [0, 1],
|
|
230
237
|
outputRange: [side === "right" ? 480 : -480, 0],
|
|
231
238
|
});
|
|
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, {
|
|
239
|
+
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, { style: [
|
|
233
240
|
s.gaveta, side === "right" ? s.gavetaDireita : s.gavetaEsquerda,
|
|
234
241
|
{ transform: [{ translateX: desloca }] }, style,
|
|
235
242
|
], 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 })] })] }) }) }));
|
|
@@ -287,5 +294,5 @@ export function BottomSheet({ open, title, children, onClose, grabber = true, dr
|
|
|
287
294
|
}).start();
|
|
288
295
|
},
|
|
289
296
|
}), [draggable, onClose, arrasto, reduzir, t.easing.easeEmphasized]);
|
|
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 })] })] }) }) }));
|
|
297
|
+
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 }), _jsx(SafeAreaView, { edges: ["bottom"] })] })] }) }) }));
|
|
291
298
|
}
|
package/dist/rolagem.d.ts
CHANGED
|
@@ -6,11 +6,18 @@ export interface FilaRolanteProps {
|
|
|
6
6
|
/** Estilo do invólucro externo, não do conteúdo. */
|
|
7
7
|
style?: StyleProp<ViewStyle>;
|
|
8
8
|
testID?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Onde a fila fica quando CABE — E3, 25/09/2026. `start` (o padrão, o de sempre), `center` ou
|
|
11
|
+
* `end`. Quando não cabe, ela rola, e o alinhamento deixa de existir: começa no início.
|
|
12
|
+
*/
|
|
13
|
+
justify?: AureaFilaJustify;
|
|
9
14
|
}
|
|
15
|
+
/** Onde a fila fica, na linha, quando cabe. O nome é o do `Cluster` (R-09): o eixo da fileira. */
|
|
16
|
+
export type AureaFilaJustify = "start" | "center" | "end";
|
|
10
17
|
/**
|
|
11
18
|
* Uma linha que rola para o lado quando não cabe, e que sabe QUANDO não cabe.
|
|
12
19
|
*
|
|
13
20
|
* O componente fica com a informação em vez de adivinhar: `onLayout` dá a largura visível e
|
|
14
21
|
* `onContentSizeChange` dá a do conteúdo. Com as duas, `transbordou` é uma conta, não um palpite.
|
|
15
22
|
*/
|
|
16
|
-
export declare function FilaRolante({ children, style, testID }: FilaRolanteProps): React.JSX.Element;
|
|
23
|
+
export declare function FilaRolante({ children, style, testID, justify }: FilaRolanteProps): React.JSX.Element;
|
package/dist/rolagem.js
CHANGED
|
@@ -25,13 +25,14 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
25
25
|
// iOS.** O que está provado aqui é a medição, não a leitura.
|
|
26
26
|
import * as React from "react";
|
|
27
27
|
import { ScrollView } from "react-native";
|
|
28
|
+
const JUSTIFICAR = { center: "center", end: "flex-end" };
|
|
28
29
|
/**
|
|
29
30
|
* Uma linha que rola para o lado quando não cabe, e que sabe QUANDO não cabe.
|
|
30
31
|
*
|
|
31
32
|
* O componente fica com a informação em vez de adivinhar: `onLayout` dá a largura visível e
|
|
32
33
|
* `onContentSizeChange` dá a do conteúdo. Com as duas, `transbordou` é uma conta, não um palpite.
|
|
33
34
|
*/
|
|
34
|
-
export function FilaRolante({ children, style, testID }) {
|
|
35
|
+
export function FilaRolante({ children, style, testID, justify = "start" }) {
|
|
35
36
|
const [visivel, setVisivel] = React.useState(0);
|
|
36
37
|
const [conteudo, setConteudo] = React.useState(0);
|
|
37
38
|
const transbordou = conteudo > visivel && visivel > 0;
|
|
@@ -41,5 +42,9 @@ export function FilaRolante({ children, style, testID }) {
|
|
|
41
42
|
showsHorizontalScrollIndicator: transbordou,
|
|
42
43
|
// Sem isto o conteúdo estica até a largura do rolador, e o respiro da cápsula aparece como
|
|
43
44
|
// faixa vazia à direita quando os itens cabem.
|
|
44
|
-
|
|
45
|
+
// E3: centralizar ou ir para o fim exige o contrário — o recipiente do conteúdo cresce até a
|
|
46
|
+
// largura do rolador (`flexGrow: 1`) e POSICIONA a cápsula lá dentro. Ela não estica: na
|
|
47
|
+
// fileira, o filho tem a largura dele. Medido pelo app: rolador 335 de largura, fileira 281,
|
|
48
|
+
// encostada à esquerda, e um `Cluster justify="center"` em volta não mudava nada.
|
|
49
|
+
contentContainerStyle: justify === "start" ? { flexGrow: 0 } : { flexGrow: 1, justifyContent: JUSTIFICAR[justify] }, style: style, children: children }));
|
|
45
50
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurea-uds/native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "A Aurea UDS para React Native: o provider de tema e densidade, os componentes e os ícones do Carbon sobre react-native-svg.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aurea",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"NOTICE"
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@aurea-uds/tokens": "^0.
|
|
54
|
+
"@aurea-uds/tokens": "^0.11.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"@react-native-community/datetimepicker": ">=8",
|