@aurea-uds/native 0.16.1 → 0.17.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/navigation.d.ts +1 -1
- package/dist/navigation.js +123 -34
- package/package.json +2 -2
package/dist/navigation.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface AureaNavItem {
|
|
|
14
14
|
export type AureaBottomNavVariant = "floating" | "edge";
|
|
15
15
|
/** Quanto a pílula ocupa: a tela menos a margem (`full`, o de sempre) ou só as abas (`content`). */
|
|
16
16
|
export type AureaBottomNavWidth = "full" | "content";
|
|
17
|
-
export type AureaBottomNavIndicator = "none" | "subtle" | "pill" | "circle" | "circle-raised" | "circle-outline" | "circle-bold";
|
|
17
|
+
export type AureaBottomNavIndicator = "none" | "subtle" | "pill" | "circle" | "circle-raised" | "circle-outline" | "circle-bold" | "capsule" | "expand";
|
|
18
18
|
export interface BottomNavProps extends ViewProps {
|
|
19
19
|
items: AureaNavItem[];
|
|
20
20
|
/** O `id` do item corrente. */
|
package/dist/navigation.js
CHANGED
|
@@ -80,7 +80,18 @@ const folha = criarFolha((t) => ({
|
|
|
80
80
|
flex: 1, minWidth: 0, alignItems: "center", justifyContent: "center",
|
|
81
81
|
// `space05` e não `space1` — a barra mais baixa (30/09/2026, pedido do Victor, aprovado pela
|
|
82
82
|
// imagem). Com a moldura de 32 e o vão de 4 eram 9 entre o ícone e o rótulo; ver `marca`.
|
|
83
|
-
|
|
83
|
+
// O NOME COLADO NO ÍCONE — 03/10/2026, pedido do Victor (*"o texto pode ficar mais próximo do
|
|
84
|
+
// ícone"*): vão ZERO, como no Telegram, em que o nome começa onde a caixa do ícone acaba. O
|
|
85
|
+
// `space05` daqui (30/09/2026) somava 2 aos 2 de folga da própria linha do nome; medido na
|
|
86
|
+
// bancada, eram 9 de tinta a tinta no `pill` e 13 no `circle-bold`.
|
|
87
|
+
gap: 0, minHeight: t.size.controlHLg,
|
|
88
|
+
// 🔴 A ALTURA DO TELEGRAM — 03/10/2026, pedido do Victor: *"ainda acho ele muito largo
|
|
89
|
+
// comparado a bottomnav como do telegram"*, e "largo" é a grossura. Medido no fonte do
|
|
90
|
+
// Telegram para Android 12.10.6 (`DialogsActivity.MAIN_TABS_HEIGHT = 56`, `GlassTabView`): a
|
|
91
|
+
// pílula tem 56; o botão, 48; o ícone, 24; o nome, 12. A nossa media 73 no `circle-bold`. O
|
|
92
|
+
// recheio de cima e de baixo cai de `space1` para `space05`, e o nome sai em 12 com a
|
|
93
|
+
// entrelinha justa (ver o `Text` do rótulo). Igual na web (`aurea.css`).
|
|
94
|
+
paddingHorizontal: t.size.space1, paddingVertical: t.size.space05,
|
|
84
95
|
borderRadius: t.size.radiusControl,
|
|
85
96
|
},
|
|
86
97
|
// Com a pílula do tamanho do conteúdo, `flex: 1` MATA as abas: no RN ele é base ZERO, e a soma
|
|
@@ -100,6 +111,57 @@ const folha = criarFolha((t) => ({
|
|
|
100
111
|
width: 32, height: 32, borderRadius: t.size.radiusControl },
|
|
101
112
|
marcaRedonda: { borderRadius: t.size.radiusFull },
|
|
102
113
|
contador: { position: "absolute", top: -t.size.space05, right: -t.size.space05 },
|
|
114
|
+
// ── A BARRA FICA PARADA QUANDO SE TROCA DE ABA — pedido do Victor, 03/10/2026 ──────────────
|
|
115
|
+
// *"me incomoda o bottom nav todo se mexer [...] quero ele estático, apenas os botões
|
|
116
|
+
// dinâmicos"*. Medido na bancada com o `react-native-web`: no `circle-bold` com
|
|
117
|
+
// `width="content"` a barra ia de 249 a 257 de largura conforme a aba escolhida, e por estar no
|
|
118
|
+
// centro, andava inteira. A regra daqui para baixo: NENHUMA medida depende de o item estar
|
|
119
|
+
// escolhido. Só a pintura muda. Quem cobra: `tests/unit/native-bottomnav-parada.test.tsx`.
|
|
120
|
+
//
|
|
121
|
+
// `circle-bold`: o disco amarelo é uma caixa DENTRO do item, de 56 (o `--bottomnav-bold` do
|
|
122
|
+
// `aurea.css`), em TODOS os itens. Antes o disco ERA o item escolhido: ele media 56 e os outros
|
|
123
|
+
// mediam o conteúdo, então a soma mudava com a escolha. O recheio passa do item para o disco,
|
|
124
|
+
// e a altura da barra não muda.
|
|
125
|
+
aba_disco: { paddingHorizontal: 0, paddingVertical: 0 },
|
|
126
|
+
// Sem a moldura de 32 (é o disco que desenha a forma, e não ela) e sem vão, o nome fica colado
|
|
127
|
+
// no ícone; o recheio de cima e de baixo volta a `space1` para o disco continuar quase redondo
|
|
128
|
+
// (56 × 48).
|
|
129
|
+
disco: {
|
|
130
|
+
alignItems: "center", justifyContent: "center", gap: 0,
|
|
131
|
+
width: 56, minHeight: t.size.controlHLg, borderRadius: t.size.radiusFull,
|
|
132
|
+
paddingHorizontal: t.size.space1, paddingVertical: t.size.space1,
|
|
133
|
+
},
|
|
134
|
+
// `capsule` (a "A" da bancada, o Material 3 Expressive): a moldura do ícone vira a cápsula de
|
|
135
|
+
// 56 × 32 do indicador ativo dele — os mesmos `--bottomnav-bold` e `--bottomnav-ring` do
|
|
136
|
+
// `aurea.css`, em todos os itens. O rótulo fica embaixo, fora dela.
|
|
137
|
+
marcaCapsula: { width: 56, height: 32, borderRadius: t.size.radiusFull },
|
|
138
|
+
// O contador fica no canto do ÍCONE, e não da cápsula: sem a cápsula pintada (item não
|
|
139
|
+
// escolhido) ele ficaria solto, longe do sino. São os (56 − 32) / 2 a mais para dentro.
|
|
140
|
+
contadorCapsula: { right: (56 - 32) / 2 - t.size.space05 },
|
|
141
|
+
// No `content` o item tem a largura da cápsula mais o recheio de sempre (`space1`), e não o
|
|
142
|
+
// `space3` do `aba_content`: com ele cada item teria 80 e a barra, 340.
|
|
143
|
+
aba_capsula_content: { paddingHorizontal: t.size.space1 },
|
|
144
|
+
// `expand` (a "C" da bancada): os outros itens mostram só o ícone; o escolhido vira cápsula
|
|
145
|
+
// amarela com o nome ao lado. É o ÚNICO em que o botão escolhido cresce — os botões andam, e a
|
|
146
|
+
// BARRA não: a vaga do escolhido é FIXA, e não do tamanho do nome. Ícone (24) + vão (`space2`)
|
|
147
|
+
// + lugar do nome (`space20`, 80) + recheio (`space3` dos dois lados) = 136. Nome maior que 80
|
|
148
|
+
// termina em "…". Medir o nome de cada aba daria uma barra que muda com a lista; esta não muda.
|
|
149
|
+
aba_expande: {
|
|
150
|
+
flexDirection: "row", gap: t.size.space2, paddingVertical: 0, paddingHorizontal: 0,
|
|
151
|
+
minHeight: t.size.targetMin, minWidth: t.size.targetMin,
|
|
152
|
+
},
|
|
153
|
+
aba_expande_outro_content: { flexGrow: 0, flexShrink: 0, flexBasis: "auto", width: t.size.targetMin },
|
|
154
|
+
aba_expande_escolhido: {
|
|
155
|
+
flexGrow: 0, flexShrink: 0, flexBasis: "auto",
|
|
156
|
+
width: t.size.iconLg + t.size.space2 + t.size.space20 + t.size.space3 * 2,
|
|
157
|
+
paddingHorizontal: t.size.space3, backgroundColor: t.color.primary,
|
|
158
|
+
},
|
|
159
|
+
// A moldura do ícone no `expand` tem a largura do ícone: o contador pendura nele e o nome vem
|
|
160
|
+
// logo ao lado — com 32 de moldura sobrava folga dos dois lados do ícone dentro da cápsula.
|
|
161
|
+
marcaExpande: { width: t.size.iconLg },
|
|
162
|
+
// O nome do item que NÃO é texto, nos não escolhidos do `expand`: fora da tela e sem ocupar
|
|
163
|
+
// lugar, mas na árvore — o texto simples vira `accessibilityLabel` do item.
|
|
164
|
+
rotuloEscondido: { position: "absolute", opacity: 0 },
|
|
103
165
|
// ── NavList ────────────────────────────────────────────────────────────────────────────────
|
|
104
166
|
lista: { gap: t.size.space05 },
|
|
105
167
|
linha: {
|
|
@@ -241,6 +303,9 @@ export function BottomNav({ items, current, variant = "floating", indicator = "n
|
|
|
241
303
|
const strings = useAureaStrings();
|
|
242
304
|
const inset = useSafeAreaInsets();
|
|
243
305
|
const redondo = indicator.startsWith("circle");
|
|
306
|
+
const disco = indicator === "circle-bold";
|
|
307
|
+
const capsula = indicator === "capsule";
|
|
308
|
+
const expande = indicator === "expand";
|
|
244
309
|
const anotar = useAnotarBottomNav();
|
|
245
310
|
const flutua = variant !== "edge";
|
|
246
311
|
const justa = flutua && width === "content";
|
|
@@ -270,48 +335,72 @@ export function BottomNav({ items, current, variant = "floating", indicator = "n
|
|
|
270
335
|
const ativo = it.id === current;
|
|
271
336
|
const corDoTexto = !ativo ? t.color.mutedForeground
|
|
272
337
|
: indicator === "none" ? t.color.primaryEmphasis
|
|
273
|
-
: indicator === "circle-bold" ? t.color.primaryForeground
|
|
338
|
+
: indicator === "circle-bold" || indicator === "expand" ? t.color.primaryForeground
|
|
274
339
|
: indicator === "subtle" || indicator === "pill" ? t.color.primaryEmphasis
|
|
275
340
|
: redondo ? t.color.primaryEmphasis
|
|
276
341
|
: t.color.foreground;
|
|
277
|
-
|
|
342
|
+
// Na `capsule` o ícone está SOBRE o amarelo e o rótulo não: cada um tem a sua cor.
|
|
343
|
+
const corDoIcone = ativo && capsula ? t.color.primaryForeground : corDoTexto;
|
|
344
|
+
// No `expand` o nome só aparece no escolhido; nos outros ele vira o nome do item para o
|
|
345
|
+
// leitor de tela (o texto simples) ou fica na árvore sem ocupar lugar (o que não é texto).
|
|
346
|
+
const nomeVisivel = !expande || ativo;
|
|
347
|
+
const marca = (_jsxs(View, { style: [
|
|
348
|
+
// A moldura de 32 só serve aos indicadores redondos, em que ela VIRA o círculo. Nos
|
|
349
|
+
// outros ela era folga vazia em volta do ícone de 24: fica da altura dele. A largura
|
|
350
|
+
// continua 32, que é o canto do contador. Igual na web (`aurea.css`).
|
|
351
|
+
// No `circle-bold` a moldura NÃO é o círculo (é o disco, em volta do ícone E do nome):
|
|
352
|
+
// ela fica da altura do ícone, e o nome encosta nele.
|
|
353
|
+
s.marca, redondo && !disco ? s.marcaRedonda : { height: t.size.iconLg },
|
|
354
|
+
capsula && s.marcaCapsula, expande && s.marcaExpande,
|
|
355
|
+
ativo && indicator === "circle" && { backgroundColor: comOpacidade(t.color.primary, 0.14) },
|
|
356
|
+
ativo && indicator === "circle-raised" && {
|
|
357
|
+
backgroundColor: t.color.popover, boxShadow: [t.shadow.shadowMd],
|
|
358
|
+
},
|
|
359
|
+
ativo && indicator === "circle-outline" && {
|
|
360
|
+
borderWidth: t.size.borderWidth, borderColor: t.color.primaryEmphasis,
|
|
361
|
+
},
|
|
362
|
+
ativo && capsula && { backgroundColor: t.color.primary },
|
|
363
|
+
], children: [it.icon && _jsx(Icon, { name: it.icon, size: "lg", color: corDoIcone, weight: ativo ? "fill" : undefined }), it.badge != null && it.badge !== false && (_jsx(View, { style: [s.contador, capsula && s.contadorCapsula], children: typeof it.badge === "number"
|
|
364
|
+
? _jsx(Badge, { tone: "danger", emphasis: "solid", size: "xs", count: it.badge })
|
|
365
|
+
: _jsx(Badge, { tone: "danger", emphasis: "solid", size: "xs", dot: true }) }))] }));
|
|
366
|
+
// 🔴 O PESO DO RÓTULO NÃO MUDA COM A ESCOLHA (03/10/2026). Era 500 no escolhido e 400 nos
|
|
367
|
+
// outros, e texto mais grosso é texto mais LARGO: no `content` a barra mudava de largura a
|
|
368
|
+
// cada toque, em todos os indicadores. Agora é 500 em todos — o "Label medium" do Material
|
|
369
|
+
// 3, que também deixou de engrossar o escolhido no Expressive pela mesma razão. O que marca
|
|
370
|
+
// a escolha é a cor, o ícone cheio e a forma. No `expand` o nome é `sm`: ao lado do ícone,
|
|
371
|
+
// e não embaixo dele.
|
|
372
|
+
const rotulo = typeof it.label === "string"
|
|
373
|
+
? (nomeVisivel
|
|
374
|
+
// 12 numa linha de 16, o do Telegram — e o `text-xs` da web. Antes era o `xs` do `Text`
|
|
375
|
+
// nativo, que sobe para 14 (ADR-0050) com linha de 21: era o que mais engrossava a
|
|
376
|
+
// barra. A linha é o tamanho mais `space1`, como na web: com a entrelinha justa (14,4)
|
|
377
|
+
// a perna do "j" passava da caixa. No `expand` o nome vai ao lado do ícone, em 14.
|
|
378
|
+
? _jsx(Text, { type: expande ? "body-sm" : "body-xs", weight: 500, numberOfLines: 1, style: [{ color: corDoTexto, lineHeight: (expande ? t.size.textSm : t.size.textXs) + t.size.space1 },
|
|
379
|
+
expande && { flexShrink: 1 }], children: it.label })
|
|
380
|
+
: null)
|
|
381
|
+
: (nomeVisivel ? it.label : _jsx(View, { style: s.rotuloEscondido, children: it.label }));
|
|
382
|
+
return (_jsx(Pressable, { onPress: it.onPress, disabled: it.disabled,
|
|
278
383
|
// `link` e não `tab`: uma aba troca um painel DESTA tela; isto troca de tela.
|
|
279
|
-
accessibilityRole: "link", ...estadoAcessivel({ selected: ativo, disabled: !!it.disabled }), style: [
|
|
384
|
+
accessibilityRole: "link", accessibilityLabel: !nomeVisivel && typeof it.label === "string" ? it.label : undefined, ...estadoAcessivel({ selected: ativo, disabled: !!it.disabled }), style: [
|
|
280
385
|
s.aba, justa && s.aba_content,
|
|
281
386
|
indicator === "subtle" && { borderRadius: t.size.radiusCard - t.size.space1 },
|
|
282
387
|
ativo && (indicator === "subtle" || indicator === "pill")
|
|
283
388
|
&& { backgroundColor: comOpacidade(t.color.primary, 0.12) },
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
// 🔴
|
|
389
|
+
disco && s.aba_disco,
|
|
390
|
+
capsula && justa && s.aba_capsula_content,
|
|
391
|
+
// 🔴 Larguras por EXTENSO, e não `flex: 0` — defeito visto pelo Victor no app rodando
|
|
287
392
|
// no navegador (02/10/2026): o `react-native-web` 0.21.3 passa `flex: 0` cru para o
|
|
288
|
-
// CSS, onde ele vale `0 1 0%`, e
|
|
289
|
-
//
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
},
|
|
298
|
-
|
|
299
|
-
// A moldura de 32 só serve aos indicadores redondos, em que ela VIRA o círculo. Nos
|
|
300
|
-
// outros ela era folga vazia em volta do ícone de 24: fica da altura dele. A largura
|
|
301
|
-
// continua 32, que é o canto do contador. Igual na web (`aurea.css`).
|
|
302
|
-
s.marca, redondo ? s.marcaRedonda : { height: t.size.iconLg },
|
|
303
|
-
ativo && indicator === "circle" && { backgroundColor: comOpacidade(t.color.primary, 0.14) },
|
|
304
|
-
ativo && indicator === "circle-raised" && {
|
|
305
|
-
backgroundColor: t.color.popover, boxShadow: [t.shadow.shadowMd],
|
|
306
|
-
},
|
|
307
|
-
ativo && indicator === "circle-outline" && {
|
|
308
|
-
borderWidth: t.size.borderWidth, borderColor: t.color.primaryEmphasis,
|
|
309
|
-
},
|
|
310
|
-
], children: [it.icon && _jsx(Icon, { name: it.icon, size: "lg", color: corDoTexto, weight: ativo ? "fill" : undefined }), it.badge != null && it.badge !== false && (_jsx(View, { style: s.contador, children: typeof it.badge === "number"
|
|
311
|
-
? _jsx(Badge, { tone: "danger", emphasis: "solid", size: "xs", count: it.badge })
|
|
312
|
-
: _jsx(Badge, { tone: "danger", emphasis: "solid", size: "xs", dot: true }) }))] }), typeof it.label === "string"
|
|
313
|
-
? _jsx(Text, { size: "xs", weight: ativo ? 500 : 400, numberOfLines: 1, style: { color: corDoTexto }, children: it.label })
|
|
314
|
-
: it.label] }, it.id));
|
|
393
|
+
// CSS, onde ele vale `0 1 0%`, e a peça encolhia até o recheio. No Yoga `flex: 0` é
|
|
394
|
+
// "inflexível"; as três por extenso valem o mesmo nos dois.
|
|
395
|
+
// Quem cobra: `tests/unit/native-flex-navegador.test.tsx`.
|
|
396
|
+
expande && s.aba_expande,
|
|
397
|
+
expande && !ativo && justa && s.aba_expande_outro_content,
|
|
398
|
+
expande && ativo && s.aba_expande_escolhido,
|
|
399
|
+
], children: disco
|
|
400
|
+
// O disco do `circle-bold`: 56 de largura em todos os itens, amarelo só no escolhido.
|
|
401
|
+
// É o `.bottom-nav-disc` da web.
|
|
402
|
+
? _jsxs(View, { style: [s.disco, ativo && { backgroundColor: t.color.primary }], children: [marca, rotulo] })
|
|
403
|
+
: _jsxs(_Fragment, { children: [marca, rotulo] }) }, it.id));
|
|
315
404
|
}) }));
|
|
316
405
|
}
|
|
317
406
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurea-uds/native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "A Aurea UDS para React Native: o provider de tema e densidade, os componentes e os ícones do Phosphor sobre react-native-svg.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aurea",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"NOTICE"
|
|
56
56
|
],
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@aurea-uds/tokens": "^0.
|
|
58
|
+
"@aurea-uds/tokens": "^0.17.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@react-native-community/datetimepicker": ">=8",
|