@aurea-uds/native 0.25.0 → 0.27.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 +5 -3
- package/dist/data.d.ts +2 -2
- package/dist/display.d.ts +30 -3
- package/dist/display.js +66 -15
- package/dist/estilos.d.ts +6 -0
- package/dist/estilos.js +10 -0
- package/dist/feedback.js +6 -6
- package/dist/index.d.ts +1 -1
- package/dist/sistema.js +89 -8
- package/dist/toast.js +6 -6
- package/package.json +2 -2
package/dist/actions.js
CHANGED
|
@@ -61,9 +61,11 @@ function pintar(t, tone) {
|
|
|
61
61
|
// invenção: o `Input` já usa esse token para a borda de inválido.
|
|
62
62
|
// O `solido` continua no `destructive`, porque ali ele é FUNDO e o texto por cima é claro.
|
|
63
63
|
danger: { solido: t.color.destructive, texto: t.color.destructiveForeground, sobre: t.color.danger400 ?? t.color.destructive },
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
// `sobre` é a LETRA do tom em cima da superfície (contorno, fantasma): o par `-400`. Desde a
|
|
65
|
+
// 0.27.0 (ADR-0061) o `success`/`warning`/`info` é o fundo cheio, fundo demais para letra no escuro.
|
|
66
|
+
success: { solido: t.color.success, texto: t.color.successForeground, sobre: t.color.success400 ?? t.color.success },
|
|
67
|
+
warning: { solido: t.color.warning, texto: t.color.warningForeground, sobre: t.color.warning400 ?? t.color.warning },
|
|
68
|
+
info: { solido: t.color.info, texto: t.color.infoForeground, sobre: t.color.info400 ?? t.color.info },
|
|
67
69
|
};
|
|
68
70
|
return m[tone];
|
|
69
71
|
}
|
package/dist/data.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type StyleProp, type ViewStyle } from "react-native";
|
|
3
|
-
import type { AureaBadgeTone } from "./display.js";
|
|
3
|
+
import type { AureaBadgeCategory, AureaBadgeTone } from "./display.js";
|
|
4
4
|
import type { AureaIcon } from "./icon.js";
|
|
5
5
|
type Virtualizavel = {
|
|
6
6
|
/** Vira `FlatList`. ⚠ Então este componente é o rolador — não o ponha dentro de `<Screen scroll>`. */
|
|
@@ -18,7 +18,7 @@ export type AureaTimelineItem = {
|
|
|
18
18
|
*/
|
|
19
19
|
icon?: AureaIcon;
|
|
20
20
|
/** A cor da moldura, com o vocabulário do `Badge`. Sem `icon`, não faz nada. Padrão: `neutral`. */
|
|
21
|
-
tone?: AureaBadgeTone
|
|
21
|
+
tone?: Exclude<AureaBadgeTone, AureaBadgeCategory>;
|
|
22
22
|
/** O que vai à DIREITA do título — um valor, um selo. */
|
|
23
23
|
trailing?: React.ReactNode;
|
|
24
24
|
/**
|
package/dist/display.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type ImageSourcePropType, type StyleProp, type ViewProps, type ViewStyle } from "react-native";
|
|
3
|
+
import { type TomDeCor } from "./estilos.js";
|
|
3
4
|
import { type AureaUniversalState } from "./strings.js";
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* GAR-07 (ADR-0060, 09/10/2026): as oito cores de CATEGORIA — marcam grupo, não estado ("Motos",
|
|
7
|
+
* "Carros"). As mesmas da web, com os mesmos nomes; o amarelo fica de fora porque é da marca.
|
|
8
|
+
*/
|
|
9
|
+
export type AureaBadgeCategory = "red" | "orange" | "green" | "teal" | "cyan" | "blue" | "violet" | "pink";
|
|
10
|
+
export type AureaBadgeTone = TomDeCor | AureaBadgeCategory;
|
|
5
11
|
export type AureaBadgeEmphasis = "soft" | "outline" | "solid";
|
|
6
12
|
export type AureaBadgeSize = "xs" | "sm" | "md" | "lg";
|
|
7
13
|
export type AureaBadgeAnchor = "top-end" | "top-start" | "bottom-end" | "bottom-start";
|
|
@@ -93,14 +99,29 @@ export interface AvatarProps {
|
|
|
93
99
|
* `source` muda. Sem isso, uma URL quebrada deixa um buraco cinza permanente na lista.
|
|
94
100
|
*/
|
|
95
101
|
export declare function Avatar({ source, alt, fallback, size, style, testID }: AvatarProps): React.JSX.Element;
|
|
102
|
+
/** GAR-09 (ADR-0060, 09/10/2026): para onde a métrica foi. Os mesmos nomes da web. */
|
|
103
|
+
export type AureaKPIDirection = "up" | "down" | "flat";
|
|
104
|
+
export type AureaKPITone = "success" | "danger" | "neutral";
|
|
105
|
+
export type AureaKPIVariant = "card" | "plain";
|
|
96
106
|
export interface KPIProps extends ViewProps {
|
|
97
107
|
label: React.ReactNode;
|
|
98
108
|
value: React.ReactNode;
|
|
99
109
|
trend?: React.ReactNode;
|
|
110
|
+
/**
|
|
111
|
+
* Para onde foi. Desenha a seta (`trend-up`, `trend-down`, `minus` — o app registra os três, como
|
|
112
|
+
* todo glifo do nativo), pinta a tendência e põe a palavra no nome que o leitor de tela ouve.
|
|
113
|
+
*/
|
|
114
|
+
direction?: AureaKPIDirection;
|
|
115
|
+
/** A cor da tendência. Padrão: alta = `success`, baixa = `danger`, estável = `neutral`. */
|
|
116
|
+
tone?: AureaKPITone;
|
|
117
|
+
/** A palavra do leitor de tela. Padrão em inglês, como na web: "Up", "Down", "No change". */
|
|
118
|
+
directionLabel?: string;
|
|
119
|
+
/** `plain` tira o cartão: o número dentro de um cartão que já existe (MNT-04). */
|
|
120
|
+
variant?: AureaKPIVariant;
|
|
100
121
|
}
|
|
101
122
|
/**
|
|
102
123
|
* Um número com nome. **É um `Card`** — medido em `markup.tsx:105`, e não no CSS, que só mostra
|
|
103
|
-
* a coluna.
|
|
124
|
+
* a coluna. Com `variant="plain"`, é só a coluna.
|
|
104
125
|
*
|
|
105
126
|
* A ficha da web declara `role="group"`, e **o React Native não tem esse papel** — medido na lista
|
|
106
127
|
* de `accessibilityRole`, que vai de `button` a `toolbar` e não inclui `group`. O que ele tem é
|
|
@@ -109,5 +130,11 @@ export interface KPIProps extends ViewProps {
|
|
|
109
130
|
*
|
|
110
131
|
* Inventar `accessibilityRole="summary"` porque o nome parece próximo seria pior que não ter papel:
|
|
111
132
|
* `summary` tem significado próprio (o resumo de um bloco expansível) e diria uma coisa errada.
|
|
133
|
+
*
|
|
134
|
+
* Com `direction`, o nome do nó é escrito aqui (rótulo, número, palavra e tendência), porque a seta
|
|
135
|
+
* é desenho e não tem texto para o leitor juntar — a web resolve com o `.sr-only`, que o nativo não
|
|
136
|
+
* tem. Só quando as partes são texto; com nó próprio, o app dá o `accessibilityLabel`.
|
|
137
|
+
*
|
|
138
|
+
* O número em `3xl` e a tendência em `sm` desde a `0.26.0`: os mesmos da web (`0.24.1`).
|
|
112
139
|
*/
|
|
113
|
-
export declare function KPI({ label, value, trend, style, ...rest }: KPIProps): React.JSX.Element;
|
|
140
|
+
export declare function KPI({ label, value, trend, direction, tone, directionLabel, variant, style, ...rest }: KPIProps): React.JSX.Element;
|
package/dist/display.js
CHANGED
|
@@ -24,9 +24,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
24
24
|
import * as React from "react";
|
|
25
25
|
import { Image, View } from "react-native";
|
|
26
26
|
import { IconButton, folgaDoToque } from "./actions.js";
|
|
27
|
-
import { canto, acentoDoTom, criarFolha, fundoDoTom } from "./estilos.js";
|
|
27
|
+
import { canto, acentoDoTom, criarFolha, fundoDoTom, preenchimentoDoTom } from "./estilos.js";
|
|
28
28
|
import { Card } from "./layout.js";
|
|
29
29
|
import { gravidadeDoEstado } from "./strings.js";
|
|
30
|
+
import { Icon } from "./icon.js";
|
|
30
31
|
import { Text } from "./text.js";
|
|
31
32
|
import { useAureaStrings, useAureaTokens } from "./theme.js";
|
|
32
33
|
const folha = criarFolha((t) => ({
|
|
@@ -79,7 +80,11 @@ const folha = criarFolha((t) => ({
|
|
|
79
80
|
},
|
|
80
81
|
imagem: { width: "100%", height: "100%" },
|
|
81
82
|
// ── KPI ────────────────────────────────────────────────────────────────────────────────────
|
|
82
|
-
kpi: { gap:
|
|
83
|
+
kpi: { gap: t.size.space1 },
|
|
84
|
+
// A seta fica na PRIMEIRA linha (quando a tendência quebra, `center` a deixava entre as duas):
|
|
85
|
+
// a caixa dela tem a altura de uma linha do texto `sm` (que no telefone é o `textBase`, ADR-0050).
|
|
86
|
+
tendencia: { flexDirection: "row", alignItems: "flex-start", gap: t.size.space1 },
|
|
87
|
+
seta: { height: t.size.textBase * t.size.leadingNormal, justifyContent: "center" },
|
|
83
88
|
}));
|
|
84
89
|
/** `count > max ? `${max}+` : String(count)` — a mesma linha do `markup.tsx:140`. */
|
|
85
90
|
export const formatarContagem = (count, max = 99) => count > max ? `${max}+` : String(count);
|
|
@@ -107,16 +112,20 @@ const LETRA_DO_SELO = (t, size) => size === "lg" ? { fontSize: t.size.textBase,
|
|
|
107
112
|
export function Badge({ tone = "neutral", emphasis = "soft", size = "md", dot, count, max = 99, showZero, leading, trailing, fit = "auto", anchor, badgeContent, invisible, children, style, ...rest }) {
|
|
108
113
|
const t = useAureaTokens();
|
|
109
114
|
const s = folha(t);
|
|
110
|
-
const
|
|
111
|
-
const
|
|
115
|
+
const categoria = ehCategoria(tone) ? coresDaCategoria(t)[tone] : null;
|
|
116
|
+
const acento = categoria ? categoria[0] : acentoDoTom(t, tone);
|
|
117
|
+
const fundo = categoria ? categoria[1] : fundoDoTom(t, tone);
|
|
118
|
+
// O selo cheio de ESTADO é o botão cheio do mesmo tom (a cor funda e a letra dele); categoria,
|
|
119
|
+
// marca e neutro enchem com o acento, como antes.
|
|
120
|
+
const cheio = categoria ? undefined : preenchimentoDoTom(t, tone);
|
|
112
121
|
const pele = emphasis === "solid"
|
|
113
|
-
? { backgroundColor: acento, borderColor: "transparent" }
|
|
122
|
+
? { backgroundColor: cheio ? cheio[0] : acento, borderColor: "transparent" }
|
|
114
123
|
: emphasis === "outline"
|
|
115
124
|
? { backgroundColor: "transparent", borderColor: acento }
|
|
116
125
|
: tone === "neutral"
|
|
117
126
|
? {}
|
|
118
127
|
: { backgroundColor: fundo, borderColor: acento };
|
|
119
|
-
const corDoTexto = emphasis === "solid" ? t.color.background
|
|
128
|
+
const corDoTexto = emphasis === "solid" ? (cheio ? cheio[1] : t.color.background)
|
|
120
129
|
: tone === "neutral" ? t.color.secondaryForeground : acento;
|
|
121
130
|
const numero = count != null ? formatarContagem(count, max) : undefined;
|
|
122
131
|
const miolo = anchor ? (numero ?? badgeContent) : (numero ?? children);
|
|
@@ -161,6 +170,24 @@ export function Badge({ tone = "neutral", emphasis = "soft", size = "md", dot, c
|
|
|
161
170
|
const escondido = invisible || (count === 0 && !showZero) || (miolo == null && !dot);
|
|
162
171
|
return _jsxs(View, { style: s.ancora, ...rest, children: [children, !escondido && selo] });
|
|
163
172
|
}
|
|
173
|
+
const CATEGORIAS = new Set(["red", "orange", "green", "teal", "cyan", "blue", "violet", "pink"]);
|
|
174
|
+
const ehCategoria = (tom) => CATEGORIAS.has(tom);
|
|
175
|
+
/**
|
|
176
|
+
* O acento e o fundo suave de cada categoria — os tokens `--category-*` e `--category-*-bg`, os
|
|
177
|
+
* mesmos da web. Ficam AQUI, e não no `acentoDoTom`, de propósito: a moldura do ícone (R-15, R-18)
|
|
178
|
+
* usa aquele mapa, e as categorias são do selo; levá-las para lá abriria a `Timeline` a cores que
|
|
179
|
+
* a da web não tem.
|
|
180
|
+
*/
|
|
181
|
+
const coresDaCategoria = (t) => ({
|
|
182
|
+
red: [t.color.categoryRed, t.color.categoryRedBg],
|
|
183
|
+
orange: [t.color.categoryOrange, t.color.categoryOrangeBg],
|
|
184
|
+
green: [t.color.categoryGreen, t.color.categoryGreenBg],
|
|
185
|
+
teal: [t.color.categoryTeal, t.color.categoryTealBg],
|
|
186
|
+
cyan: [t.color.categoryCyan, t.color.categoryCyanBg],
|
|
187
|
+
blue: [t.color.categoryBlue, t.color.categoryBlueBg],
|
|
188
|
+
violet: [t.color.categoryViolet, t.color.categoryVioletBg],
|
|
189
|
+
pink: [t.color.categoryPink, t.color.categoryPinkBg],
|
|
190
|
+
});
|
|
164
191
|
/** O mínimo do selo preso, da referência principal: 16 no `xs` e no `sm`, 28 no `md`, 32 no `lg`. */
|
|
165
192
|
const MINIMO_PRESO = (t, size) => size === "lg" ? t.size.space8 : size === "md" ? t.size.space7 : t.size.space4;
|
|
166
193
|
/**
|
|
@@ -197,10 +224,10 @@ export function Status({ variant, state, children, style, ...rest }) {
|
|
|
197
224
|
// Mesma linha do `feedback-client.tsx:34`: `offline` é ele mesmo; o resto vira a gravidade.
|
|
198
225
|
const v = variant
|
|
199
226
|
?? (state ? (state === "offline" ? "offline" : gravidadeDoEstado(state)) : "neutral");
|
|
200
|
-
const cor = v === "online" || v === "success" ? t.color.success
|
|
201
|
-
: v === "away" || v === "warning" ? t.color.warning
|
|
227
|
+
const cor = v === "online" || v === "success" ? (t.color.success400 ?? t.color.success)
|
|
228
|
+
: v === "away" || v === "warning" ? (t.color.warning400 ?? t.color.warning)
|
|
202
229
|
: v === "busy" || v === "danger" ? (t.color.danger400 ?? t.color.destructive)
|
|
203
|
-
: v === "info" ? t.color.info
|
|
230
|
+
: v === "info" ? (t.color.info400 ?? t.color.info)
|
|
204
231
|
: v === "offline" ? t.color.subtleForeground
|
|
205
232
|
: t.color.mutedForeground;
|
|
206
233
|
const rotulo = children ?? (state ? strings.universalState[state] : null);
|
|
@@ -236,9 +263,13 @@ export function Avatar({ source, alt, fallback, size = "md", style, testID }) {
|
|
|
236
263
|
? _jsx(Text, { size: size === "sm" ? "xs" : "md", weight: 700, children: fallback })
|
|
237
264
|
: fallback }));
|
|
238
265
|
}
|
|
266
|
+
const TOM_DA_DIRECAO = { up: "success", down: "danger", flat: "neutral" };
|
|
267
|
+
const PALAVRA_DA_DIRECAO = { up: "Up", down: "Down", flat: "No change" };
|
|
268
|
+
const GLIFO_DA_DIRECAO = { up: "trend-up", down: "trend-down", flat: "minus" };
|
|
269
|
+
const comoTexto = (n) => typeof n === "string" || typeof n === "number" ? String(n) : null;
|
|
239
270
|
/**
|
|
240
271
|
* Um número com nome. **É um `Card`** — medido em `markup.tsx:105`, e não no CSS, que só mostra
|
|
241
|
-
* a coluna.
|
|
272
|
+
* a coluna. Com `variant="plain"`, é só a coluna.
|
|
242
273
|
*
|
|
243
274
|
* A ficha da web declara `role="group"`, e **o React Native não tem esse papel** — medido na lista
|
|
244
275
|
* de `accessibilityRole`, que vai de `button` a `toolbar` e não inclui `group`. O que ele tem é
|
|
@@ -247,10 +278,30 @@ export function Avatar({ source, alt, fallback, size = "md", style, testID }) {
|
|
|
247
278
|
*
|
|
248
279
|
* Inventar `accessibilityRole="summary"` porque o nome parece próximo seria pior que não ter papel:
|
|
249
280
|
* `summary` tem significado próprio (o resumo de um bloco expansível) e diria uma coisa errada.
|
|
281
|
+
*
|
|
282
|
+
* Com `direction`, o nome do nó é escrito aqui (rótulo, número, palavra e tendência), porque a seta
|
|
283
|
+
* é desenho e não tem texto para o leitor juntar — a web resolve com o `.sr-only`, que o nativo não
|
|
284
|
+
* tem. Só quando as partes são texto; com nó próprio, o app dá o `accessibilityLabel`.
|
|
285
|
+
*
|
|
286
|
+
* O número em `3xl` e a tendência em `sm` desde a `0.26.0`: os mesmos da web (`0.24.1`).
|
|
250
287
|
*/
|
|
251
|
-
export function KPI({ label, value, trend, style, ...rest }) {
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
288
|
+
export function KPI({ label, value, trend, direction, tone, directionLabel, variant = "card", style, ...rest }) {
|
|
289
|
+
const t = useAureaTokens();
|
|
290
|
+
const s = folha(t);
|
|
291
|
+
const tom = direction ? (tone ?? TOM_DA_DIRECAO[direction]) : undefined;
|
|
292
|
+
const cor = tom === "success" ? (t.color.success400 ?? t.color.success)
|
|
293
|
+
: tom === "danger" ? (t.color.danger400 ?? t.color.destructive)
|
|
294
|
+
: t.color.mutedForeground;
|
|
295
|
+
const palavra = direction ? (directionLabel ?? PALAVRA_DA_DIRECAO[direction]) : undefined;
|
|
296
|
+
const temTendencia = trend != null && trend !== false && trend !== "";
|
|
297
|
+
const textoDaTendencia = typeof trend === "string" || typeof trend === "number"
|
|
298
|
+
? _jsx(Text, { size: "sm", tone: direction ? undefined : "muted", style: direction ? { color: cor } : undefined, children: trend })
|
|
299
|
+
: trend;
|
|
300
|
+
const partes = [comoTexto(label), comoTexto(value), palavra ?? "", temTendencia ? comoTexto(trend) : ""];
|
|
301
|
+
const nome = direction && partes.every((p) => p !== null) ? partes.filter(Boolean).join(", ") : undefined;
|
|
302
|
+
const Caixa = variant === "plain" ? View : Card;
|
|
303
|
+
return (_jsxs(Caixa, { style: [s.kpi, style], accessible: true, accessibilityLabel: nome, ...rest, children: [typeof label === "string" ? _jsx(Text, { size: "sm", tone: "muted", children: label }) : label, typeof value === "string" || typeof value === "number"
|
|
304
|
+
? _jsx(Text, { size: "3xl", weight: 700, children: value }) : value, direction
|
|
305
|
+
? _jsxs(View, { style: s.tendencia, children: [_jsx(View, { style: s.seta, children: _jsx(Icon, { name: GLIFO_DA_DIRECAO[direction], size: "sm", color: cor }) }), temTendencia && textoDaTendencia] })
|
|
306
|
+
: temTendencia && textoDaTendencia] }));
|
|
256
307
|
}
|
package/dist/estilos.d.ts
CHANGED
|
@@ -87,6 +87,12 @@ export type TomDeCor = "neutral" | "primary" | "info" | "success" | "warning" |
|
|
|
87
87
|
* nomeia — e o dia em que um tom novo entra numa só.
|
|
88
88
|
*/
|
|
89
89
|
export declare const acentoDoTom: (t: AureaTokens, tom: TomDeCor) => string;
|
|
90
|
+
/**
|
|
91
|
+
* O FUNDO CHEIO de um tom de estado e a letra em cima dele — o par do botão cheio (ADR-0061, 0.27.0):
|
|
92
|
+
* o selo cheio é o botão cheio do mesmo tom. `primary` e `neutral` não têm o par: `undefined`, e
|
|
93
|
+
* quem chama enche com o acento, como antes.
|
|
94
|
+
*/
|
|
95
|
+
export declare const preenchimentoDoTom: (t: AureaTokens, tom: TomDeCor) => [string, string] | undefined;
|
|
90
96
|
/** O fundo SUAVE de um tom (`--<tom>-bg`). `primary` e `neutral` não têm token: `undefined`. */
|
|
91
97
|
export declare const fundoDoTom: (t: AureaTokens, tom: TomDeCor) => string | undefined;
|
|
92
98
|
/**
|
package/dist/estilos.js
CHANGED
|
@@ -95,6 +95,16 @@ export const acentoDoTom = (t, tom) => tom === "primary" ? t.color.primaryEmphas
|
|
|
95
95
|
: tom === "warning" ? t.color.warning400 ?? t.color.warning
|
|
96
96
|
: tom === "danger" ? t.color.danger400 ?? t.color.destructive
|
|
97
97
|
: t.color.secondaryForeground;
|
|
98
|
+
/**
|
|
99
|
+
* O FUNDO CHEIO de um tom de estado e a letra em cima dele — o par do botão cheio (ADR-0061, 0.27.0):
|
|
100
|
+
* o selo cheio é o botão cheio do mesmo tom. `primary` e `neutral` não têm o par: `undefined`, e
|
|
101
|
+
* quem chama enche com o acento, como antes.
|
|
102
|
+
*/
|
|
103
|
+
export const preenchimentoDoTom = (t, tom) => tom === "success" ? [t.color.success, t.color.successForeground]
|
|
104
|
+
: tom === "warning" ? [t.color.warning, t.color.warningForeground]
|
|
105
|
+
: tom === "info" ? [t.color.info, t.color.infoForeground]
|
|
106
|
+
: tom === "danger" ? [t.color.destructive, t.color.destructiveForeground]
|
|
107
|
+
: undefined;
|
|
98
108
|
/** O fundo SUAVE de um tom (`--<tom>-bg`). `primary` e `neutral` não têm token: `undefined`. */
|
|
99
109
|
export const fundoDoTom = (t, tom) => tom === "info" ? t.color.infoBg
|
|
100
110
|
: tom === "success" ? t.color.successBg
|
package/dist/feedback.js
CHANGED
|
@@ -72,9 +72,9 @@ const folha = criarFolha((t) => ({
|
|
|
72
72
|
flex: 1, minWidth: 0,
|
|
73
73
|
flexDirection: "row", alignItems: "flex-start", gap: t.size.space3,
|
|
74
74
|
},
|
|
75
|
-
alerta_info: { backgroundColor: t.color.infoBg, borderColor: t.color.info },
|
|
76
|
-
alerta_success: { backgroundColor: t.color.successBg, borderColor: t.color.success },
|
|
77
|
-
alerta_warning: { backgroundColor: t.color.warningBg, borderColor: t.color.warning },
|
|
75
|
+
alerta_info: { backgroundColor: t.color.infoBg, borderColor: t.color.info400 ?? t.color.info },
|
|
76
|
+
alerta_success: { backgroundColor: t.color.successBg, borderColor: t.color.success400 ?? t.color.success },
|
|
77
|
+
alerta_warning: { backgroundColor: t.color.warningBg, borderColor: t.color.warning400 ?? t.color.warning },
|
|
78
78
|
alerta_danger: { backgroundColor: t.color.dangerBg, borderColor: t.color.danger400 ?? t.color.destructive },
|
|
79
79
|
corpoDoAlerta: { flex: 1, gap: 2 },
|
|
80
80
|
// ── EmptyState ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -255,10 +255,10 @@ accessibilityLabel, accessibilityHint, ...rest }) {
|
|
|
255
255
|
const s = folha(t);
|
|
256
256
|
const strings = useAureaStrings();
|
|
257
257
|
const v = variant ?? (state ? gravidadeDoEstado(state) : "info");
|
|
258
|
-
const corDoIcone = v === "success" ? t.color.success
|
|
259
|
-
: v === "warning" ? t.color.warning
|
|
258
|
+
const corDoIcone = v === "success" ? (t.color.success400 ?? t.color.success)
|
|
259
|
+
: v === "warning" ? (t.color.warning400 ?? t.color.warning)
|
|
260
260
|
: v === "danger" ? (t.color.danger400 ?? t.color.destructive)
|
|
261
|
-
: t.color.info;
|
|
261
|
+
: (t.color.info400 ?? t.color.info);
|
|
262
262
|
return (_jsxs(View
|
|
263
263
|
// Android: a região viva é o que faz o leitor falar sem foco, e ela cobre a moldura
|
|
264
264
|
// inteira de propósito — o que muda é o conteúdo, e o "X" some junto quando o aviso fecha.
|
package/dist/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type { ButtonProps, IconButtonProps, LinkButtonProps, ThemeToggleProps, A
|
|
|
17
17
|
export { Spinner, Skeleton, Progress, Alert, EmptyState, DataState, ICONE_DA_VARIANTE } from "./feedback.js";
|
|
18
18
|
export type { SpinnerProps, SkeletonProps, ProgressProps, AlertProps, EmptyStateProps, DataStateProps, AureaSpinnerSize, AureaAlertVariant, AureaDataStateValue, AureaProgressTone, } from "./feedback.js";
|
|
19
19
|
export { Badge, Status, Avatar, KPI, formatarContagem } from "./display.js";
|
|
20
|
-
export type { BadgeProps, StatusProps, AvatarProps, KPIProps, AureaBadgeAnchor, AureaBadgeEmphasis, AureaBadgeFit, AureaBadgeSize, AureaBadgeTone, AureaStatusVariant, AureaAvatarSize, } from "./display.js";
|
|
20
|
+
export type { BadgeProps, StatusProps, AvatarProps, KPIProps, AureaKPIDirection, AureaKPITone, AureaKPIVariant, AureaBadgeAnchor, AureaBadgeCategory, AureaBadgeEmphasis, AureaBadgeFit, AureaBadgeSize, AureaBadgeTone, AureaStatusVariant, AureaAvatarSize, } from "./display.js";
|
|
21
21
|
export { useAureaStrings } from "./theme.js";
|
|
22
22
|
export { defaultStrings, ptBR, gravidadeDoEstado, AUREA_UNIVERSAL_STATES } from "./strings.js";
|
|
23
23
|
export type { AureaStrings, AureaUniversalState } from "./strings.js";
|
package/dist/sistema.js
CHANGED
|
@@ -49,6 +49,9 @@ const folha = criarFolha((t) => ({
|
|
|
49
49
|
...canto(t.size.radiusControl), backgroundColor: t.color.fieldBg,
|
|
50
50
|
},
|
|
51
51
|
invalido: { borderColor: t.color.danger400 ?? t.color.destructive },
|
|
52
|
+
// No navegador o texto e o ícone vão numa caixa escondida do leitor de tela (E16): a mesma
|
|
53
|
+
// fileira do gatilho, ocupando a largura dele.
|
|
54
|
+
mioloWeb: { flex: 1, flexDirection: "row", alignItems: "center", justifyContent: "space-between" },
|
|
52
55
|
desabilitado: { opacity: t.size.opacityDisabled },
|
|
53
56
|
// R-22 (02/10/2026), a "B" da prancha: miniatura QUADRADA de 64 — o `Avatar` `lg` da
|
|
54
57
|
// referência, e a medida que o botão de pôr foto passou a ter também (era 72, número à mão) — e o X
|
|
@@ -73,6 +76,46 @@ const folha = criarFolha((t) => ({
|
|
|
73
76
|
/** Quanto o X do `PhotoInput` sai da foto: metade do desenho (30) mais metade do alvo (44). */
|
|
74
77
|
const foraDoX = (t) => (t.size.controlHSm + Math.max(t.size.controlHSm, t.size.targetMin)) / 2;
|
|
75
78
|
const alturaDoTamanho = (t, s) => s === "sm" ? t.size.controlHSm : s === "lg" ? t.size.controlHLg : t.size.controlHMd;
|
|
79
|
+
// E16 (09/10/2026) · NO NAVEGADOR, o calendário "deles" é o do NAVEGADOR. A biblioteca de data não
|
|
80
|
+
// tem versão web: o arquivo genérico dela devolve `null` e só avisa no console — tocar no campo não
|
|
81
|
+
// abria nada (achado do app rodando no `react-native-web`). A saída é o `<input type="date">` do
|
|
82
|
+
// próprio navegador, INVISÍVEL e POR CIMA do nosso gatilho: a pele continua a nossa, o toque cai no
|
|
83
|
+
// campo do navegador, e é ele que o leitor de tela anuncia. Por cima, e não escondido e aberto por
|
|
84
|
+
// código, porque o `showPicker()` não existe no Safari do iPhone (dados de compatibilidade do MDN,
|
|
85
|
+
// 8.1.5): lá quem abre o seletor é o toque no próprio campo. No computador, o clique chama o
|
|
86
|
+
// `showPicker()` (Chrome e Edge 99, Firefox 101, Safari 17.4).
|
|
87
|
+
// E o ícone de calendário do próprio campo, esticado sobre ele inteiro: o clique vira um clique de
|
|
88
|
+
// verdade no ícone, e o navegador abre o seletor SEM o `showPicker()`. É o que vale dentro de uma
|
|
89
|
+
// página de outro endereço (moldura), onde o Chrome recusa o `showPicker()` — medido: "called from
|
|
90
|
+
// cross-origin iframe". O pseudo-elemento só existe no Chrome, no Edge e no Safari; o Firefox já
|
|
91
|
+
// abre o seletor no clique. O React 19 (o mínimo do pacote) põe a regra no topo da página UMA vez.
|
|
92
|
+
const REGRA_DO_CAMPO_WEB = "input[data-aurea-campo-data]::-webkit-calendar-picker-indicator{"
|
|
93
|
+
+ "position:absolute;top:0;left:0;width:100%;height:100%;margin:0;padding:0;opacity:0;cursor:pointer}";
|
|
94
|
+
const doisDigitos = (n) => String(n).padStart(2, "0");
|
|
95
|
+
/** A data no formato do campo do navegador: `AAAA-MM-DD` (data) ou `HH:MM` (hora), no fuso local. */
|
|
96
|
+
const paraCampoWeb = (d, mode) => mode === "time"
|
|
97
|
+
? `${doisDigitos(d.getHours())}:${doisDigitos(d.getMinutes())}`
|
|
98
|
+
: `${d.getFullYear()}-${doisDigitos(d.getMonth() + 1)}-${doisDigitos(d.getDate())}`;
|
|
99
|
+
/**
|
|
100
|
+
* O texto do campo de volta para `Date`, mexendo só no que o campo escolhe: a data mantém a hora de
|
|
101
|
+
* `base`, e a hora mantém a data — como o seletor do aparelho, que parte do `value` (ou de agora).
|
|
102
|
+
* Texto incompleto ou vazio (a pessoa apagou) não vira data: `undefined`, e `onChange` não é chamado.
|
|
103
|
+
*/
|
|
104
|
+
const doCampoWeb = (texto, mode, base) => {
|
|
105
|
+
const d = new Date(base.getTime());
|
|
106
|
+
if (mode === "time") {
|
|
107
|
+
const m = /^(\d{2}):(\d{2})/.exec(texto);
|
|
108
|
+
if (!m)
|
|
109
|
+
return undefined;
|
|
110
|
+
d.setHours(Number(m[1]), Number(m[2]), 0, 0);
|
|
111
|
+
return d;
|
|
112
|
+
}
|
|
113
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(texto);
|
|
114
|
+
if (!m)
|
|
115
|
+
return undefined;
|
|
116
|
+
d.setFullYear(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
|
117
|
+
return d;
|
|
118
|
+
};
|
|
76
119
|
/**
|
|
77
120
|
* O campo de data — **a nossa pele, o calendário DELES**.
|
|
78
121
|
*
|
|
@@ -119,14 +162,52 @@ export function DatePicker({ value, onChange, mode = "date", minimumDate, maximu
|
|
|
119
162
|
setAbertoNoIOS(true);
|
|
120
163
|
}, [value, mode, minimumDate, maximumDate, receber]);
|
|
121
164
|
const mostrarSeletorIOS = abertoNoIOS && Platform.OS !== "android";
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
165
|
+
const conteudo = (_jsxs(_Fragment, { children: [_jsx(Text, { size: tam === "sm" ? "xs" : tam === "lg" ? "base" : "md", tone: value ? "default" : "subtle", numberOfLines: 1, children: texto }), icon && _jsx(Icon, { name: icon, size: "sm", color: t.color.subtleForeground })] }));
|
|
166
|
+
const pele = [
|
|
167
|
+
s.gatilho,
|
|
168
|
+
{ height: alturaDoTamanho(t, tam),
|
|
169
|
+
paddingHorizontal: tam === "sm" ? t.size.space3 : tam === "lg" ? t.size.space4 : 13 },
|
|
170
|
+
campo?.invalido && s.invalido,
|
|
171
|
+
inativo && s.desabilitado,
|
|
172
|
+
style,
|
|
173
|
+
];
|
|
174
|
+
if (Platform.OS === "web") {
|
|
175
|
+
// O gatilho vira só desenho: sem toque, fora do Tab e escondido do leitor de tela. Quem recebe
|
|
176
|
+
// o toque, o foco e o nome é o campo do navegador, por cima dele.
|
|
177
|
+
const campoDoNavegador = React.createElement("input", {
|
|
178
|
+
type: mode === "time" ? "time" : "date",
|
|
179
|
+
value: value ? paraCampoWeb(value, mode) : "",
|
|
180
|
+
min: minimumDate && mode === "date" ? paraCampoWeb(minimumDate, mode) : undefined,
|
|
181
|
+
max: maximumDate && mode === "date" ? paraCampoWeb(maximumDate, mode) : undefined,
|
|
182
|
+
disabled: inativo,
|
|
183
|
+
"aria-label": campo?.label ?? (value ? texto : placeholder ?? strings.datePlaceholder),
|
|
184
|
+
"aria-invalid": campo?.invalido || undefined,
|
|
185
|
+
"aria-description": campo?.hint,
|
|
186
|
+
"data-testid": testID ? `${testID}-campo` : undefined,
|
|
187
|
+
"data-aurea-campo-data": "",
|
|
188
|
+
onChange: (e) => {
|
|
189
|
+
const data = doCampoWeb(e.currentTarget.value, mode, value ?? new Date());
|
|
190
|
+
if (data)
|
|
191
|
+
onChange?.(data);
|
|
192
|
+
},
|
|
193
|
+
onClick: (e) => {
|
|
194
|
+
// Sem `showPicker` (Safari do iPhone) o próprio toque já abriu o seletor; e ele pode
|
|
195
|
+
// recusar (página dentro de outra), caso em que o campo continua lá, focado.
|
|
196
|
+
try {
|
|
197
|
+
e.currentTarget.showPicker?.();
|
|
198
|
+
}
|
|
199
|
+
catch { /* o toque no campo basta */ }
|
|
200
|
+
},
|
|
201
|
+
style: {
|
|
202
|
+
position: "absolute", top: 0, left: 0, width: "100%", height: "100%", margin: 0,
|
|
203
|
+
padding: 0, border: 0, opacity: 0, cursor: inativo ? "default" : "pointer",
|
|
204
|
+
// O calendário do navegador segue o tema da Aurea, e não o do sistema operacional.
|
|
205
|
+
colorScheme: t.theme,
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
return (_jsxs(Pressable, { testID: testID, disabled: inativo, focusable: false, style: pele, children: [_jsx(View, { importantForAccessibility: "no-hide-descendants", style: s.mioloWeb, children: conteudo }), React.createElement("style", { href: "aurea-campo-data", precedence: "default" }, REGRA_DO_CAMPO_WEB), campoDoNavegador] }));
|
|
209
|
+
}
|
|
210
|
+
return (_jsxs(_Fragment, { children: [_jsx(Pressable, { testID: testID, onPress: inativo ? undefined : abrir, disabled: inativo, accessibilityRole: "button", accessibilityLabel: campo?.label, accessibilityHint: campo?.hint, accessibilityValue: { text: value ? texto : undefined }, ...estadoAcessivel({ disabled: !!inativo }), style: pele, children: conteudo }), mostrarSeletorIOS && (_jsx(RNDateTimePicker, { value: value ?? new Date(), mode: mode, minimumDate: minimumDate, maximumDate: maximumDate, onChange: receber }))] }));
|
|
130
211
|
}
|
|
131
212
|
// R-23 (06/10/2026) · a data em que a foto foi tirada, e NADA MAIS do EXIF.
|
|
132
213
|
//
|
package/dist/toast.js
CHANGED
|
@@ -81,9 +81,9 @@ const folha = criarFolha((t) => ({
|
|
|
81
81
|
...(t.shadow.shadowMd ? { boxShadow: [t.shadow.shadowMd] } : null),
|
|
82
82
|
},
|
|
83
83
|
texto: { flex: 1, minWidth: 0, gap: 2 },
|
|
84
|
-
aviso_info: { backgroundColor: t.color.infoBg, borderColor: t.color.info },
|
|
85
|
-
aviso_success: { backgroundColor: t.color.successBg, borderColor: t.color.success },
|
|
86
|
-
aviso_warning: { backgroundColor: t.color.warningBg, borderColor: t.color.warning },
|
|
84
|
+
aviso_info: { backgroundColor: t.color.infoBg, borderColor: t.color.info400 ?? t.color.info },
|
|
85
|
+
aviso_success: { backgroundColor: t.color.successBg, borderColor: t.color.success400 ?? t.color.success },
|
|
86
|
+
aviso_warning: { backgroundColor: t.color.warningBg, borderColor: t.color.warning400 ?? t.color.warning },
|
|
87
87
|
aviso_danger: {
|
|
88
88
|
backgroundColor: t.color.dangerBg,
|
|
89
89
|
borderColor: t.color.danger400 ?? t.color.destructive,
|
|
@@ -193,10 +193,10 @@ export function Toast({ toast, onClose }) {
|
|
|
193
193
|
laco.start();
|
|
194
194
|
return () => laco.stop();
|
|
195
195
|
}, [reduzir, entrada, t.easing.easeEmphasized]);
|
|
196
|
-
const corDoIcone = tipo === "success" ? t.color.success
|
|
197
|
-
: tipo === "warning" ? t.color.warning
|
|
196
|
+
const corDoIcone = tipo === "success" ? (t.color.success400 ?? t.color.success)
|
|
197
|
+
: tipo === "warning" ? (t.color.warning400 ?? t.color.warning)
|
|
198
198
|
: tipo === "danger" ? (t.color.danger400 ?? t.color.destructive)
|
|
199
|
-
: t.color.info;
|
|
199
|
+
: (t.color.info400 ?? t.color.info);
|
|
200
200
|
const glifo = toast.icon === false ? null : (toast.icon ?? ICONE_DA_VARIANTE[tipo]);
|
|
201
201
|
return (_jsxs(Animated.View, { accessible: true, ...(tipo === "danger" ? { accessibilityRole: "alert" } : null), accessibilityLiveRegion: tipo === "danger" ? "assertive" : "polite", style: [
|
|
202
202
|
s.aviso, s[`aviso_${tipo}`],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurea-uds/native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.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.27.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@react-native-community/datetimepicker": ">=8",
|