@aurea-uds/native 0.13.0 → 0.14.1

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/busca.d.ts CHANGED
@@ -6,6 +6,12 @@ import { type AureaFieldSize } from "./inputs.js";
6
6
  export interface AureaComboboxItem {
7
7
  value: string;
8
8
  label: string;
9
+ /**
10
+ * Uma segunda linha embaixo do rótulo, apagada ("Pacote de 1 kg") — R-14, 01/10/2026. É o
11
+ * `Select.ItemDescription` do HeroUI Native 1.0.10 (`styles/components/select.css:117`): letra
12
+ * `text-sm` (14), cor apagada. A busca continua olhando só o `label`.
13
+ */
14
+ description?: string;
9
15
  disabled?: boolean;
10
16
  }
11
17
  export interface ComboboxProps {
package/dist/busca.js CHANGED
@@ -322,13 +322,13 @@ export function Combobox({ items, value, onValueChange, onSearchChange, searchDe
322
322
  color: t.color.foreground },
323
323
  ] }), texto.length > 0 && (_jsx(IconButton, { name: "x", label: strings.searchClear, appearance: "ghost", size: "sm", onPress: () => digitar(""), testID: testID ? `${testID}-busca-limpar` : undefined }))] }), loading && (_jsx(View, { style: s.carregando, children: _jsx(Spinner, { label: strings.comboboxLoading }) })), nada && (_jsx(View, { style: s.vazio, children: typeof empty === "string" || empty == null
324
324
  ? _jsx(Text, { size: "sm", tone: "muted", children: empty ?? strings.comboboxEmpty })
325
- : empty })), _jsx(FlatList, { data: filtrados, keyExtractor: (i) => i.value, keyboardShouldPersistTaps: "handled", onEndReached: onEndReached, onEndReachedThreshold: ANTECEDENCIA_DE_PAGINA, renderItem: ({ item }) => (_jsx(Pressable, { disabled: item.disabled, onPress: () => { onValueChange?.(item); fechar(); }, accessibilityRole: "menuitem", ...estadoAcessivel({
325
+ : empty })), _jsx(FlatList, { data: filtrados, keyExtractor: (i) => i.value, keyboardShouldPersistTaps: "handled", onEndReached: onEndReached, onEndReachedThreshold: ANTECEDENCIA_DE_PAGINA, renderItem: ({ item }) => (_jsxs(Pressable, { disabled: item.disabled, onPress: () => { onValueChange?.(item); fechar(); }, accessibilityRole: "menuitem", ...estadoAcessivel({
326
326
  selected: item.value === value?.value, disabled: !!item.disabled,
327
- }), style: [
327
+ }), accessibilityHint: item.description, style: [
328
328
  s.opcao,
329
329
  item.value === value?.value && s.opcaoEscolhida,
330
330
  item.disabled && s.desabilitado,
331
- ], children: _jsx(Text, { size: "md", weight: item.value === value?.value ? 600 : 400, children: item.label }) })) }), _jsx(RecuoDaFolha, { comTeclado: true })] })] }) }) })] }));
331
+ ], children: [_jsx(Text, { size: "md", weight: item.value === value?.value ? 600 : 400, children: item.label }), item.description != null && (_jsx(Text, { size: "xs", tone: "muted", children: item.description }))] })) }), _jsx(RecuoDaFolha, { comTeclado: true })] })] }) }) })] }));
332
332
  }
333
333
  // ── A DOBRA DE ACENTO, e por que ela é sondada em vez de presumida ───────────────────────────
334
334
  // Buscar "acucar" tem de achar "açúcar" — num catálogo em português, exigir o acento certo é
package/dist/estilos.d.ts CHANGED
@@ -33,6 +33,23 @@ export declare function criarFolha<T extends NamedStyles<T> | NamedStyles<Record
33
33
  * um ícone) não tinha como escrevê-lo sem número à mão. O `check 39` cobra o teste dele.
34
34
  */
35
35
  export declare const comOpacidade: (cor: string, pct: number) => string;
36
+ /**
37
+ * 🔴 O FIO AMARELO DO ESCOLHIDO — o sinal único da casa para "este é o escolhido".
38
+ *
39
+ * O `aurea.css:1037-1039` põe este fio em TODOS os selecionados (`.is-selected`, botão alternado,
40
+ * `.segmented button.active`, item ativo da lateral), e o comentário de lá diz por quê: *"Um
41
+ * usuário aprende uma vez e reconhece em todo lugar (pedido do Victor, 24/07)."* Os três números
42
+ * saem daquela linha, não daqui: altura 2 (fração de pixel borra), recuo 15 de cada lado
43
+ * (`inset-inline:15px`), e o amarelo a 75% (cheio ele grita mais que o próprio rótulo).
44
+ *
45
+ * ⚠ **Morava dentro do `SegmentedControl` e mudou de casa em 01/10/2026**, quando a aba de
46
+ * `<Tabs variant="secondary">` (R-12) passou a precisar do mesmo fio. Copiar os números para o
47
+ * segundo arquivo é o defeito que o `CLAUDE.md` nomeia. Quem desenha o fio, desenha este.
48
+ *
49
+ * ⚠ Em peça estreita o recuo de 15 de cada lado zera a largura e o fio some — **e é o mesmo
50
+ * comportamento da web**, onde `inset-inline:15px` numa caixa estreita não desenha nada.
51
+ */
52
+ export declare const fioDoEscolhido: (t: AureaTokens) => ViewStyle;
36
53
  /**
37
54
  * A reação ao TOQUE de tudo que é alvo inteiro — hoje o `Button`, o `IconButton` e o `Card` com
38
55
  * `onPress`. Os números são os do core: `.btn:active { transform:scale(.97); opacity:.9 }` e
package/dist/estilos.js CHANGED
@@ -49,6 +49,26 @@ export function criarFolha(descrever) {
49
49
  export const comOpacidade = (cor, pct) => /^#[0-9a-fA-F]{6}$/.test(cor)
50
50
  ? cor + Math.round(Math.max(0, Math.min(1, pct)) * 255).toString(16).padStart(2, "0")
51
51
  : cor;
52
+ /**
53
+ * 🔴 O FIO AMARELO DO ESCOLHIDO — o sinal único da casa para "este é o escolhido".
54
+ *
55
+ * O `aurea.css:1037-1039` põe este fio em TODOS os selecionados (`.is-selected`, botão alternado,
56
+ * `.segmented button.active`, item ativo da lateral), e o comentário de lá diz por quê: *"Um
57
+ * usuário aprende uma vez e reconhece em todo lugar (pedido do Victor, 24/07)."* Os três números
58
+ * saem daquela linha, não daqui: altura 2 (fração de pixel borra), recuo 15 de cada lado
59
+ * (`inset-inline:15px`), e o amarelo a 75% (cheio ele grita mais que o próprio rótulo).
60
+ *
61
+ * ⚠ **Morava dentro do `SegmentedControl` e mudou de casa em 01/10/2026**, quando a aba de
62
+ * `<Tabs variant="secondary">` (R-12) passou a precisar do mesmo fio. Copiar os números para o
63
+ * segundo arquivo é o defeito que o `CLAUDE.md` nomeia. Quem desenha o fio, desenha este.
64
+ *
65
+ * ⚠ Em peça estreita o recuo de 15 de cada lado zera a largura e o fio some — **e é o mesmo
66
+ * comportamento da web**, onde `inset-inline:15px` numa caixa estreita não desenha nada.
67
+ */
68
+ export const fioDoEscolhido = (t) => ({
69
+ position: "absolute", left: 15, right: 15, bottom: 0, height: 2,
70
+ borderRadius: t.size.radiusFull, backgroundColor: comOpacidade(t.color.primary, 0.75),
71
+ });
52
72
  /**
53
73
  * A reação ao TOQUE de tudo que é alvo inteiro — hoje o `Button`, o `IconButton` e o `Card` com
54
74
  * `onPress`. Os números são os do core: `.btn:active { transform:scale(.97); opacity:.9 }` e
package/dist/index.d.ts CHANGED
@@ -23,7 +23,7 @@ export { defaultStrings, ptBR, gravidadeDoEstado, AUREA_UNIVERSAL_STATES } from
23
23
  export type { AureaStrings, AureaUniversalState } from "./strings.js";
24
24
  export { useReduceMotion } from "./movimento.js";
25
25
  export { BottomNav, Topbar, NavList, Stepper, Tabs } from "./navigation.js";
26
- export type { BottomNavProps, TopbarProps, NavListProps, StepperProps, AureaNavItem, AureaNavListItem, AureaStepItem, AureaStepState, AureaBottomNavVariant, AureaBottomNavIndicator, AureaBottomNavWidth, AureaTopbarVariant, AureaTopbarInset, TabsProps, AureaTabItem, } from "./navigation.js";
26
+ export type { BottomNavProps, TopbarProps, NavListProps, StepperProps, AureaNavItem, AureaNavListItem, AureaStepItem, AureaStepState, AureaBottomNavVariant, AureaBottomNavIndicator, AureaBottomNavWidth, AureaTopbarVariant, AureaTopbarInset, TabsProps, AureaTabItem, AureaTabsVariant, } from "./navigation.js";
27
27
  export { Field, Label, Input, Textarea, Select, Switch, Checkbox, Radio, RadioGroup, SegmentedControl, Form, KeyboardAvoiding, useCampo, } from "./inputs.js";
28
28
  export type { FieldProps, LabelProps, InputProps, TextareaProps, SelectProps, SwitchProps, CheckboxProps, RadioProps, RadioGroupProps, RadioGroupItemProps, AureaRadioIndicatorPlacement, SegmentedControlProps, FormProps, KeyboardAvoidingProps, AureaFieldSize, } from "./inputs.js";
29
29
  export { InputGroup, InputGroupAddon, PasswordField, useGrupoDeCampo } from "./inputs.js";
@@ -39,7 +39,7 @@ export type { ChartProps, ChartLegendProps, AureaSeries, AureaChartMark } from "
39
39
  export { Combobox, SearchField } from "./busca.js";
40
40
  export type { ComboboxProps, SearchFieldProps, AureaComboboxItem } from "./busca.js";
41
41
  export { NumberField, formatarNumero, lerNumero, separadoresDoLocale } from "./numero.js";
42
- export type { NumberFieldProps, AureaSeparadores } from "./numero.js";
42
+ export type { NumberFieldProps, AureaSeparadores, AureaNumberFieldSize } from "./numero.js";
43
43
  export { Image, Gallery } from "./midia.js";
44
44
  export type { ImageProps, GalleryProps, AureaGalleryItem, AureaImageSource, } from "./midia.js";
45
45
  export type { AureaFilaJustify } from "./rolagem.js";
package/dist/inputs.d.ts CHANGED
@@ -282,10 +282,18 @@ export interface RadioGroupItemProps extends Omit<PressableProps, "children" | "
282
282
  invalid?: boolean;
283
283
  /** O lado da marca só neste item; sem ele, vale o do grupo. */
284
284
  indicatorPlacement?: AureaRadioIndicatorPlacement;
285
+ /**
286
+ * Um ícone antes do texto (R-19, 01/10/2026). O HeroUI não tem esta prop: no `RadioGroup.Item`
287
+ * dele o ícone entra como mais um filho, e a Aurea traduz filho livre em nome de ícone, como em
288
+ * todo o resto. Tamanho `iconLg` (24, o mesmo da marca; o HeroUI usa 22 nos ícones de lista, que
289
+ * não existe aqui — escolha do Victor), vão de 12 até o texto. Na opção escolhida sai a forma
290
+ * cheia (ADR-0053), se o registro a tiver.
291
+ */
292
+ icon?: IconName;
285
293
  style?: StyleProp<ViewStyle>;
286
294
  }
287
295
  declare function RaizDoGrupoDeRadio({ value, onValueChange, disabled, invalid, label, orientation, indicatorPlacement, style, children, ...rest }: RadioGroupProps): React.JSX.Element;
288
- declare function ItemDoGrupoDeRadio({ value, label, description, disabled, invalid, indicatorPlacement, style, accessibilityLabel, ...rest }: RadioGroupItemProps): React.JSX.Element;
296
+ declare function ItemDoGrupoDeRadio({ value, label, description, disabled, invalid, indicatorPlacement, icon, style, accessibilityLabel, ...rest }: RadioGroupItemProps): React.JSX.Element;
289
297
  /**
290
298
  * Um conjunto de opções em que só uma fica escolhida — o `RadioGroup` do HeroUI Native.
291
299
  *
package/dist/inputs.js CHANGED
@@ -39,7 +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 { comOpacidade, criarFolha, estadoAcessivel } from "./estilos.js";
42
+ import { criarFolha, estadoAcessivel, fioDoEscolhido } from "./estilos.js";
43
43
  import { FilaRolante } from "./rolagem.js";
44
44
  import { IconButton } from "./actions.js";
45
45
  import { Icon } from "./icon.js";
@@ -99,20 +99,9 @@ const folha = criarFolha((t) => ({
99
99
  segmento: { flex: 1, alignItems: "center", justifyContent: "center",
100
100
  paddingHorizontal: 14, borderRadius: t.size.radiusControl },
101
101
  segmentoAtivo: { backgroundColor: t.color.secondary },
102
- // 🔴 O FIO AMARELO DO ESCOLHIDO — ele faltava, e a falta era metade do defeito C4.
103
- // O `aurea.css:958-960` põe este fio em TODOS os selecionados da casa (`.is-selected`, aba
104
- // ativa, botão alternado e `.segmented button.active`), e o bloco de comentário acima dele
105
- // diz por quê, com data: *"Item de nav ativo, aba ativa, item de lista lateral e botão
106
- // alternado ligado mostram o MESMO sinal (…) Um usuário aprende uma vez e reconhece em todo
107
- // lugar (pedido do Victor, 24/07)."*
108
- // Os três números saem daquela linha, não de mim: altura 2 (fração de pixel borra), recuo 15,
109
- // e o amarelo a 75% (cheio ele grita mais que o próprio rótulo).
110
- // ⚠ Em segmento estreito o recuo de 15 de cada lado zera a largura e o fio some — **e é o
111
- // mesmo comportamento da web**, onde `inset-inline:15px` num box estreito não desenha nada.
112
- fioDoSegmento: {
113
- position: "absolute", left: 15, right: 15, bottom: 0, height: 2,
114
- borderRadius: t.size.radiusFull, backgroundColor: comOpacidade(t.color.primary, 0.75),
115
- },
102
+ // 🔴 O FIO AMARELO DO ESCOLHIDO — ele faltava, e a falta era metade do defeito C4. Os números
103
+ // e a razão moram no `fioDoEscolhido` (`estilos.ts`), que a aba do `Tabs` secundário também usa.
104
+ fioDoSegmento: fioDoEscolhido(t),
116
105
  formulario: { gap: t.size.space5 },
117
106
  // A folha do `Select`: no RN não existe `<select>`, então a lista é um `Modal` — que é
118
107
  // exatamente o "motor novo sobre `Modal`" que a §5.2.4 previu.
@@ -388,7 +377,7 @@ function RaizDoGrupoDeRadio({ value, onValueChange, disabled, invalid, label, or
388
377
  const contexto = React.useMemo(() => ({ value, onValueChange, disabled, invalid, indicatorPlacement }), [value, onValueChange, disabled, invalid, indicatorPlacement]);
389
378
  return (_jsx(GrupoDeRadio.Provider, { value: contexto, children: _jsx(View, { accessibilityRole: "radiogroup", accessibilityLabel: label, ...estadoAcessivel({ disabled: !!disabled }), style: [{ gap: t.size.space3, flexDirection: orientation === "horizontal" ? "row" : "column" }, style], ...rest, children: children }) }));
390
379
  }
391
- function ItemDoGrupoDeRadio({ value, label, description, disabled, invalid, indicatorPlacement, style, accessibilityLabel, ...rest }) {
380
+ function ItemDoGrupoDeRadio({ value, label, description, disabled, invalid, indicatorPlacement, icon, style, accessibilityLabel, ...rest }) {
392
381
  const t = useAureaTokens();
393
382
  const s = folha(t);
394
383
  const grupo = React.useContext(GrupoDeRadio);
@@ -403,7 +392,7 @@ function ItemDoGrupoDeRadio({ value, label, description, disabled, invalid, indi
403
392
  const noInicio = (indicatorPlacement ?? grupo?.indicatorPlacement ?? "end") === "start";
404
393
  const texto = (label != null || description != null) && (_jsxs(View, { style: { flex: 1, minWidth: 0 }, children: [typeof label === "string"
405
394
  ? _jsx(Text, { size: "base", weight: 500, tone: erro ? "danger" : "default", children: label }) : label, description != null && (typeof description === "string"
406
- ? _jsx(Text, { size: "sm", tone: "muted", children: description }) : description)] }, "texto"));
395
+ ? _jsx(Text, { size: "xs", tone: "muted", children: description }) : description)] }, "texto"));
407
396
  const marcaDesenhada = (_jsx(View, { style: [
408
397
  s.marcaBase,
409
398
  { width: marca, height: marca, borderRadius: t.size.radiusFull },
@@ -412,11 +401,14 @@ function ItemDoGrupoDeRadio({ value, label, description, disabled, invalid, indi
412
401
  borderColor: erro ? perigo : t.color.controlSelected },
413
402
  ], children: escolhido && _jsx(View, { style: { width: ponto, height: ponto, borderRadius: t.size.radiusFull,
414
403
  backgroundColor: t.color.controlSelectedForeground } }) }, "marca"));
404
+ // O ícone é decorativo: o rótulo já diz o que a opção é, e o `Icon` sem `label` sai da árvore
405
+ // de acessibilidade. A cor acompanha a do rótulo, inclusive no erro.
406
+ const glifo = icon != null && (_jsx(Icon, { name: icon, size: "lg", weight: escolhido ? "fill" : "regular", color: erro ? perigo : t.color.foreground }, "icone"));
415
407
  return (_jsx(Pressable, { onPress: inativo || escolhido ? undefined : () => grupo?.onValueChange?.(value), disabled: inativo, accessibilityRole: "radio", ...estadoAcessivel({ checked: escolhido, disabled: !!inativo }), accessibilityLabel: accessibilityLabel ?? (typeof label === "string" ? label : undefined), accessibilityHint: typeof description === "string" ? description : undefined, style: [
416
408
  { flexDirection: "row", alignItems: "center", justifyContent: "space-between",
417
409
  gap: t.size.space3, minHeight: t.size.targetMin },
418
410
  inativo && s.desabilitado, style,
419
- ], ...rest, children: noInicio ? [marcaDesenhada, texto] : [texto, marcaDesenhada] }));
411
+ ], ...rest, children: noInicio ? [marcaDesenhada, glifo, texto] : [glifo, texto, marcaDesenhada] }));
420
412
  }
421
413
  /**
422
414
  * Um conjunto de opções em que só uma fica escolhida — o `RadioGroup` do HeroUI Native.
@@ -200,7 +200,16 @@ export interface TabsProps extends ViewProps {
200
200
  label?: string;
201
201
  /** Onde a fila de abas fica quando cabe: `start` (padrão), `center` ou `end` (E3). */
202
202
  justify?: AureaFilaJustify;
203
+ /**
204
+ * O jeito da fila, com os nomes do HeroUI (R-12, 01/10/2026):
205
+ * - `primary` (padrão): a cápsula, com a aba aberta num fundo `secondary`.
206
+ * - `secondary`: sem cápsula — um fio fino embaixo da fila inteira e o **fio amarelo** da casa
207
+ * embaixo da aba aberta, o mesmo do `SegmentedControl`.
208
+ */
209
+ variant?: AureaTabsVariant;
203
210
  }
211
+ /** Os dois jeitos da fila de abas, com os nomes do `Tabs` do HeroUI Native. */
212
+ export type AureaTabsVariant = "primary" | "secondary";
204
213
  /**
205
214
  * As abas DENTRO da tela — trocar o painel, não trocar de página.
206
215
  *
@@ -234,4 +243,4 @@ export interface TabsProps extends ViewProps {
234
243
  * largura de tela grande. Não há tablet medido neste projeto, e no nativo vale demanda antes de
235
244
  * cobertura — a mesma decisão da `Table` do Lote 6.
236
245
  */
237
- export declare function Tabs({ tabs, value, onChange, label, justify, style, ...rest }: TabsProps): React.JSX.Element;
246
+ export declare function Tabs({ tabs, value, onChange, label, justify, variant, style, ...rest }: TabsProps): React.JSX.Element;
@@ -3,7 +3,7 @@ import { Pressable, View } from "react-native";
3
3
  import { useSafeAreaInsets } from "react-native-safe-area-context";
4
4
  import { useAnotarBottomNav } from "./barranav.js";
5
5
  import { Badge } from "./display.js";
6
- import { comOpacidade, criarFolha, estadoAcessivel } from "./estilos.js";
6
+ import { comOpacidade, criarFolha, estadoAcessivel, fioDoEscolhido } from "./estilos.js";
7
7
  import { Icon } from "./icon.js";
8
8
  import { Card } from "./layout.js";
9
9
  import { FilaRolante } from "./rolagem.js";
@@ -133,6 +133,24 @@ const folha = criarFolha((t) => ({
133
133
  paddingHorizontal: 14, borderRadius: t.size.radiusControl,
134
134
  },
135
135
  abaDeTabAtiva: { backgroundColor: t.color.secondary },
136
+ // `variant="secondary"` (R-12, 01/10/2026): o `secondary` do HeroUI Native 1.0.10
137
+ // (`styles/components/tabs.css`), com o fio da casa no lugar do indicador azul deles.
138
+ // .tabs__list--variant-secondary padding 0 · border-bottom 1px, cor da borda
139
+ // .tabs__list gap `* 1` → space1
140
+ // .tabs__trigger padding-inline `* 3` → space3 · padding-block `* 1.5`
141
+ // → space1 + space05. Rótulo `text-base` + entrelinha 1.5 dá
142
+ // 36, que é o `controlHMd`: a altura da fila da cápsula, então
143
+ // trocar de variante não muda a altura da fila.
144
+ // .tabs__indicator--variant-secondary border-bottom 2px na cor de destaque → `fioDoEscolhido`
145
+ abasSecundarias: {
146
+ flexDirection: "row", gap: t.size.space1,
147
+ borderBottomWidth: t.size.borderWidth, borderColor: t.color.border,
148
+ },
149
+ abaSecundaria: {
150
+ alignItems: "center", justifyContent: "center", minHeight: t.size.controlHMd,
151
+ paddingHorizontal: t.size.space3, paddingVertical: t.size.space1 + t.size.space05,
152
+ },
153
+ fioDaAba: fioDoEscolhido(t),
136
154
  painel: { marginTop: t.size.space3 },
137
155
  // ── Stepper ────────────────────────────────────────────────────────────────────────────────
138
156
  trilha: { flexDirection: "row" },
@@ -418,16 +436,21 @@ export function Stepper({ items, label, doneIcon = "check", errorIcon = "x-circl
418
436
  * largura de tela grande. Não há tablet medido neste projeto, e no nativo vale demanda antes de
419
437
  * cobertura — a mesma decisão da `Table` do Lote 6.
420
438
  */
421
- export function Tabs({ tabs, value, onChange, label, justify, style, ...rest }) {
439
+ export function Tabs({ tabs, value, onChange, label, justify, variant = "primary", style, ...rest }) {
422
440
  const t = useAureaTokens();
423
441
  const s = folha(t);
424
442
  const strings = useAureaStrings();
425
443
  const aberta = tabs.find((it) => it.id === value);
426
- 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) => {
444
+ const secundaria = variant === "secondary";
445
+ return (_jsxs(View, { style: style, ...rest, children: [_jsx(FilaRolante, { justify: justify, children: _jsx(View, { accessibilityRole: "tablist", accessibilityLabel: label ?? strings.tabsLabel, style: secundaria ? s.abasSecundarias : s.abas, children: tabs.map((it) => {
427
446
  const ativa = it.id === value;
428
- return (_jsx(Pressable, { onPress: it.disabled ? undefined : () => onChange?.(it.id), disabled: it.disabled, accessibilityRole: "tab", ...estadoAcessivel({ 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"
429
- ? _jsx(Text, { size: "sm", weight: ativa ? 600 : 400, style: { color: ativa ? t.color.foreground : t.color.mutedForeground }, children: it.label })
430
- : it.label }, it.id));
447
+ return (_jsxs(Pressable, { onPress: it.disabled ? undefined : () => onChange?.(it.id), disabled: it.disabled, accessibilityRole: "tab", ...estadoAcessivel({ selected: ativa, disabled: !!it.disabled }), accessibilityLabel: typeof it.label === "string" ? it.label : undefined, style: [
448
+ secundaria ? s.abaSecundaria : s.abaDeTab,
449
+ ativa && !secundaria && s.abaDeTabAtiva,
450
+ it.disabled && { opacity: t.size.opacityDisabled },
451
+ ], children: [typeof it.label === "string"
452
+ ? _jsx(Text, { size: "sm", weight: ativa ? 600 : 400, style: { color: ativa ? t.color.foreground : t.color.mutedForeground }, children: it.label })
453
+ : it.label, ativa && secundaria && _jsx(View, { style: s.fioDaAba })] }, it.id));
431
454
  }) }) }), aberta
432
455
  ? (_jsx(Card, { variant: "inset", accessibilityLabel: typeof aberta.label === "string" ? aberta.label : undefined, style: s.painel, children: aberta.content }))
433
456
  : null] }));
package/dist/numero.d.ts CHANGED
@@ -2,6 +2,18 @@ import * as React from "react";
2
2
  import { type StyleProp, type ViewStyle } from "react-native";
3
3
  import type { IconName } from "./icon-names.js";
4
4
  import { type AureaFieldSize } from "./inputs.js";
5
+ /**
6
+ * Os tamanhos do `NumberField`: os três do campo e mais o `display` (R-16, 01/10/2026), o número
7
+ * grande de destaque. Nenhuma referência da fila tem esse tamanho (o `NumberField` do HeroUI web
8
+ * só tem `variant`; o telefone dele nem tem a peça; o ReUI também não), então ele é peça nossa —
9
+ * e as medidas saem de escalas que JÁ existem, nenhuma nova:
10
+ * letra `text3xl` (30) em seminegrito — o título 2 (`h2` do B-02). Escolha do Victor.
11
+ * altura `controlHXl` — o degrau seguinte da escala de altura dos controles, que muda com a
12
+ * densidade como as outras três.
13
+ * largura `space24` (96): o `space16` (64) do campo comum não cabe "1.234" em 30.
14
+ * botões os do `lg`, o maior do `IconButton`.
15
+ */
16
+ export type AureaNumberFieldSize = AureaFieldSize | "display";
5
17
  /** Os separadores de um locale, derivados de um número-sonda. */
6
18
  export type AureaSeparadores = {
7
19
  decimal: string;
@@ -52,7 +64,11 @@ export interface NumberFieldProps {
52
64
  disabled?: boolean;
53
65
  /** Mostra o valor e não deixa editar — os botões também somem. */
54
66
  readOnly?: boolean;
55
- size?: AureaFieldSize;
67
+ /**
68
+ * `sm` · `md` · `lg`, como os outros campos, e `display`: o número grande de destaque, com a
69
+ * letra do título 2 (30). Ver `AureaNumberFieldSize`. Moeda em `display` pede `fullWidth`.
70
+ */
71
+ size?: AureaNumberFieldSize;
56
72
  /**
57
73
  * Ocupa a largura disponível em vez de abraçar o conteúdo. Padrão **false**.
58
74
  *
package/dist/numero.js CHANGED
@@ -50,8 +50,10 @@ import { IconButton } from "./actions.js";
50
50
  import { criarFolha, estadoAcessivel } from "./estilos.js";
51
51
  import { useCampo } from "./inputs.js";
52
52
  import { useAureaStrings, useAureaTokens, usePeleSobreAMarca } from "./theme.js";
53
- const alturaDoTamanho = (t, s) => s === "sm" ? t.size.controlHSm : s === "lg" ? t.size.controlHLg : t.size.controlHMd;
54
- const fonteDoTamanho = (t, s) => s === "sm" ? t.size.textSm : s === "lg" ? t.size.textLg : t.size.textBase; // ADR-0050: um degrau acima da web
53
+ const alturaDoTamanho = (t, s) => s === "sm" ? t.size.controlHSm : s === "lg" ? t.size.controlHLg
54
+ : s === "display" ? t.size.controlHXl : t.size.controlHMd;
55
+ const fonteDoTamanho = (t, s) => s === "sm" ? t.size.textSm : s === "lg" ? t.size.textLg
56
+ : s === "display" ? t.size.text3xl : t.size.textBase; // ADR-0050: um degrau acima da web
55
57
  const folha = criarFolha((t) => ({
56
58
  // 🔴 ELE ESTICAVA, E NÃO DEVIA — achado em 12/09/2026, olhando a primeira imagem da vitrine.
57
59
  //
@@ -79,6 +81,7 @@ const folha = criarFolha((t) => ({
79
81
  paddingVertical: 0, textAlignVertical: "center",
80
82
  },
81
83
  campoLargo: { width: undefined, flex: 1, minWidth: t.size.space16 },
84
+ campoDisplay: { width: t.size.space24 },
82
85
  invalido: { borderColor: t.color.danger400 ?? t.color.destructive },
83
86
  desabilitado: { opacity: t.size.opacityDisabled },
84
87
  }));
@@ -250,6 +253,7 @@ export function NumberField({ value, defaultValue, onValueChange, min, max, step
250
253
  const strings = useAureaStrings();
251
254
  const campo = useCampo();
252
255
  const tam = size ?? campo?.size ?? "md";
256
+ const tamDoBotao = tam === "display" ? "lg" : tam;
253
257
  const inativo = disabled ?? campo?.disabled;
254
258
  const [interno, setInterno] = React.useState(defaultValue ?? null);
255
259
  const numero = value !== undefined ? value : interno;
@@ -355,14 +359,15 @@ export function NumberField({ value, defaultValue, onValueChange, min, max, step
355
359
  // (`aurea.css:685`), com os dois botões FORA dela. O estado que faltava é o deles; a geometria
356
360
  // continua sendo a nossa.
357
361
  const [focado, setFocado] = React.useState(false);
358
- return (_jsxs(View, { testID: testID, style: [s.grupo, fullWidth && s.grupoLargo, inativo && s.desabilitado, style], children: [mostrarBotoes && (_jsx(IconButton, { name: icons.decrement, label: strings.decrement, appearance: "ghost", size: tam, disabled: inativo || noLimite(-1), onPress: () => empurrar(-1), testID: testID ? `${testID}-menos` : undefined })), _jsx(TextInput, { testID: testID ? `${testID}-campo` : undefined, value: mostrar, onChangeText: digitar, onFocus: () => { setFocado(true); setEmEdicao(paraEdicao(numero, locale)); }, onBlur: () => { setFocado(false); confirmar(); }, editable: !inativo && !readOnly, placeholder: placeholder, placeholderTextColor: peleDaMarca?.color ?? t.color.subtleForeground, keyboardType: keyboardType ?? tecladoPadrao,
362
+ return (_jsxs(View, { testID: testID, style: [s.grupo, fullWidth && s.grupoLargo, inativo && s.desabilitado, style], children: [mostrarBotoes && (_jsx(IconButton, { name: icons.decrement, label: strings.decrement, appearance: "ghost", size: tamDoBotao, disabled: inativo || noLimite(-1), onPress: () => empurrar(-1), testID: testID ? `${testID}-menos` : undefined })), _jsx(TextInput, { testID: testID ? `${testID}-campo` : undefined, value: mostrar, onChangeText: digitar, onFocus: () => { setFocado(true); setEmEdicao(paraEdicao(numero, locale)); }, onBlur: () => { setFocado(false); confirmar(); }, editable: !inativo && !readOnly, placeholder: placeholder, placeholderTextColor: peleDaMarca?.color ?? t.color.subtleForeground, keyboardType: keyboardType ?? tecladoPadrao,
359
363
  // O nome vem do `Field`, como em todo controle deste pacote — e `label` cobre quem usa o
360
364
  // campo solto. Sem um dos dois, é um nó anônimo para o leitor de tela.
361
365
  accessibilityLabel: label ?? campo?.label, accessibilityHint: campo?.hint, ...estadoAcessivel({ disabled: !!inativo }), "aria-invalid": campo?.invalido, style: [
362
366
  s.campo,
367
+ tam === "display" && s.campoDisplay,
363
368
  fullWidth && s.campoLargo,
364
369
  { height: alturaDoTamanho(t, tam), fontSize: fonteDoTamanho(t, tam),
365
- fontFamily: t.font.ui[400], color: t.color.foreground },
370
+ fontFamily: t.font.ui[tam === "display" ? 600 : 400], color: t.color.foreground },
366
371
  campo?.invalido && s.invalido,
367
372
  // A ORDEM IMPORTA e é a mesma do `Input` do Lote 4: o inválido vem antes, o foco
368
373
  // depois. Um campo inválido que está sendo corrigido tem de mostrar que está ativo —
@@ -373,5 +378,5 @@ export function NumberField({ value, defaultValue, onValueChange, min, max, step
373
378
  // O foco continua existindo, por espessura.
374
379
  peleDaMarca,
375
380
  peleDaMarca && focado && { borderWidth: t.size.borderWidth * 2 },
376
- ] }), mostrarBotoes && (_jsx(IconButton, { name: icons.increment, label: strings.increment, appearance: "ghost", size: tam, disabled: inativo || noLimite(1), onPress: () => empurrar(1), testID: testID ? `${testID}-mais` : undefined }))] }));
381
+ ] }), mostrarBotoes && (_jsx(IconButton, { name: icons.increment, label: strings.increment, appearance: "ghost", size: tamDoBotao, disabled: inativo || noLimite(1), onPress: () => empurrar(1), testID: testID ? `${testID}-mais` : undefined }))] }));
377
382
  }
package/dist/text.js CHANGED
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  //
4
4
  // É o **bloqueio 3** da §5.2 do NATIVE.md, e a razão dele é estrutural, não de escopo:
5
5
  //
6
- // web: body { font-family:var(--font-ui); font-size:var(--text-md);
6
+ // web: body { font-family:var(--font-ui); font-size:var(--text-sm);
7
7
  // line-height:var(--leading-normal) } ← e TODO <p>/<span>/<h1> herda
8
8
  // nativo: não há cascata de estilo de texto através de `View`, e não há `<p>`.
9
9
  //
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurea-uds/native",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
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",
@@ -51,7 +51,7 @@
51
51
  "NOTICE"
52
52
  ],
53
53
  "dependencies": {
54
- "@aurea-uds/tokens": "^0.13.0"
54
+ "@aurea-uds/tokens": "^0.14.1"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "@react-native-community/datetimepicker": ">=8",