@aurea-uds/native 0.8.1 → 0.8.3
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.d.ts +22 -2
- package/dist/actions.js +23 -6
- package/dist/display.d.ts +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -1
- package/dist/inputs.d.ts +107 -4
- package/dist/inputs.js +113 -27
- package/dist/layout.d.ts +22 -0
- package/dist/layout.js +30 -1
- package/dist/strings.d.ts +8 -0
- package/dist/strings.js +4 -0
- package/dist/text.d.ts +2 -2
- package/dist/text.js +5 -1
- package/package.json +2 -2
package/dist/actions.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type PressableProps } from "react-native";
|
|
|
3
3
|
import { type AureaIconRegistry, type IconName } from "./icon.js";
|
|
4
4
|
/** Quanto peso a caixa tem. */
|
|
5
5
|
export type AureaButtonAppearance = "solid" | "outline" | "ghost";
|
|
6
|
-
/** O que a cor significa. Mesmos nomes da web (ADR-
|
|
6
|
+
/** O que a cor significa. Mesmos nomes da web (ADR-0044). */
|
|
7
7
|
export type AureaButtonTone = "neutral" | "brand" | "danger" | "success" | "warning" | "info";
|
|
8
8
|
/** As cinco alturas de controle, todas de token de densidade. */
|
|
9
9
|
export type AureaButtonSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
@@ -14,6 +14,26 @@ export interface ButtonProps extends Omit<PressableProps, "children" | "style">
|
|
|
14
14
|
size?: AureaButtonSize;
|
|
15
15
|
leadingIcon?: IconName;
|
|
16
16
|
trailingIcon?: IconName;
|
|
17
|
+
/**
|
|
18
|
+
* Um desenho QUALQUER na frente do texto, para quando a marca não pode ser um ícone nosso.
|
|
19
|
+
*
|
|
20
|
+
* ⚠ **Ele existe por causa de MARCA REGISTRADA, não por conveniência.** O botão "Entrar com
|
|
21
|
+
* Google" e o "Entrar com Apple" exigem o desenho oficial de cada um, e nenhum dos dois pode
|
|
22
|
+
* viver dentro desta biblioteca: o Google proíbe redesenhar e manda usar o arquivo do pacote
|
|
23
|
+
* dele; a Apple proíbe usar o logo sem licença escrita. **Então a marca entra pelo app**, e o
|
|
24
|
+
* que a Aurea dá é a cápsula em volta.
|
|
25
|
+
*
|
|
26
|
+
* <Button appearance="outline" leading={<RNImage source={logoGoogle} style={{width: 18, height: 18}} />}>
|
|
27
|
+
* Entrar com Google
|
|
28
|
+
* </Button>
|
|
29
|
+
*
|
|
30
|
+
* ⚠ **A cor do texto NÃO atravessa para cá** — o que entra desenha a própria cor, e é assim
|
|
31
|
+
* que tem de ser: a marca do Google tem cor fixa, e tingi-la seria justamente o que a regra
|
|
32
|
+
* dele proíbe. Um `leadingIcon` nosso continua herdando a cor do botão.
|
|
33
|
+
*/
|
|
34
|
+
leading?: React.ReactNode;
|
|
35
|
+
/** O mesmo, do outro lado. */
|
|
36
|
+
trailing?: React.ReactNode;
|
|
17
37
|
/** Registro de ícones, quando não há um em contexto. Ver `criarRegistroDeIcones`. */
|
|
18
38
|
icons?: AureaIconRegistry;
|
|
19
39
|
fullWidth?: boolean;
|
|
@@ -29,7 +49,7 @@ export interface ButtonProps extends Omit<PressableProps, "children" | "style">
|
|
|
29
49
|
* descreve: lá, um botão desabilitado some da ordem de foco e a explicação pendurada nele não é
|
|
30
50
|
* lida por ninguém. Aqui não há o dilema, então não há o par `aria-disabled` — um só basta.
|
|
31
51
|
*/
|
|
32
|
-
export declare function Button({ children, appearance, tone, size, leadingIcon, trailingIcon, icons, fullWidth, pressed, disabled, accessibilityLabel, ...rest }: ButtonProps): React.JSX.Element;
|
|
52
|
+
export declare function Button({ children, appearance, tone, size, leadingIcon, trailingIcon, leading, trailing, icons, fullWidth, pressed, disabled, accessibilityLabel, ...rest }: ButtonProps): React.JSX.Element;
|
|
33
53
|
export interface IconButtonProps extends Omit<ButtonProps, "children" | "leadingIcon" | "trailingIcon" | "fullWidth"> {
|
|
34
54
|
name: IconName;
|
|
35
55
|
/** **Obrigatório**: um botão que só tem glifo não tem texto para o leitor de tela anunciar. */
|
package/dist/actions.js
CHANGED
|
@@ -5,7 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
// Medida a ficha da web antes de escrever (passo 1 do BUILDING.md). Lá existem TRÊS props que
|
|
6
6
|
// pintam a mesma coisa, e a própria ficha diz qual é qual: *"`variant` é atalho para o par
|
|
7
7
|
// (appearance, tone). Os treze nomes continuam valendo e pintam exatamente o mesmo; a API de dois
|
|
8
|
-
// eixos é appearance + tone"* — a ADR-
|
|
8
|
+
// eixos é appearance + tone"* — a ADR-0044.
|
|
9
9
|
//
|
|
10
10
|
// O `variant` existe lá porque a Aurea **está publicada** e aqueles treze nomes são contrato com
|
|
11
11
|
// quem instalou. **Aqui não há nada publicado**, e nascer com o atalho seria nascer com a dívida:
|
|
@@ -42,8 +42,25 @@ const ICONE = {
|
|
|
42
42
|
function pintar(t, tone) {
|
|
43
43
|
const m = {
|
|
44
44
|
neutral: { solido: t.color.secondary, texto: t.color.secondaryForeground, sobre: t.color.foreground },
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
// ⚠ O TOM DA MARCA TEM DUAS CORES, e confundi-las foi defeito publicado na `0.8.2`.
|
|
46
|
+
//
|
|
47
|
+
// `solido` é o amarelo da marca, que é FUNDO: o texto por cima é escuro e lê bem.
|
|
48
|
+
// `sobre` é o mesmo amarelo virando TEXTO — e aí ele some. Medido sobre o fundo do tema
|
|
49
|
+
// claro: **1,73:1**, contra os 4,5:1 que a WCAG exige para texto normal. No escuro dá 10,34.
|
|
50
|
+
//
|
|
51
|
+
// O token certo existe desde sempre e é o `link`: mesmo matiz (86.047), mais escuro,
|
|
52
|
+
// **5,02:1** no claro — e no escuro ele É o amarelo da marca, então nada muda lá. A
|
|
53
|
+
// identidade não foi tocada: o amarelo de preencher continua invariável, como manda o
|
|
54
|
+
// `CLAUDE.md`. O que mudou é qual dos dois se usa para ESCREVER.
|
|
55
|
+
//
|
|
56
|
+
// ⚠ Achado pelo app na tela de entrar, não por teste nosso — os 1430 passavam por cima.
|
|
57
|
+
brand: { solido: t.color.primary, texto: t.color.primaryForeground, sobre: t.color.link },
|
|
58
|
+
// ⚠ MESMO DEFEITO DO TOM DA MARCA, achado por medir os outros tons em vez de parar no
|
|
59
|
+
// primeiro: `destructive` escrito sobre o tema claro dá **4,30:1** — reprova por pouco, mas
|
|
60
|
+
// reprova. O `danger400` passa nos DOIS temas (6,86 no claro, 7,47 no escuro), e não é
|
|
61
|
+
// invenção: o `Input` já usa esse token para a borda de inválido.
|
|
62
|
+
// O `solido` continua no `destructive`, porque ali ele é FUNDO e o texto por cima é claro.
|
|
63
|
+
danger: { solido: t.color.destructive, texto: t.color.destructiveForeground, sobre: t.color.danger400 ?? t.color.destructive },
|
|
47
64
|
success: { solido: t.color.success, texto: t.color.successForeground, sobre: t.color.success },
|
|
48
65
|
warning: { solido: t.color.warning, texto: t.color.warningForeground, sobre: t.color.warning },
|
|
49
66
|
info: { solido: t.color.info, texto: t.color.infoForeground, sobre: t.color.info },
|
|
@@ -88,7 +105,7 @@ const folha = criarFolha((t) => ({
|
|
|
88
105
|
* descreve: lá, um botão desabilitado some da ordem de foco e a explicação pendurada nele não é
|
|
89
106
|
* lida por ninguém. Aqui não há o dilema, então não há o par `aria-disabled` — um só basta.
|
|
90
107
|
*/
|
|
91
|
-
export function Button({ children, appearance = "solid", tone = "neutral", size = "md", leadingIcon, trailingIcon, icons, fullWidth = false, pressed, disabled, accessibilityLabel, ...rest }) {
|
|
108
|
+
export function Button({ children, appearance = "solid", tone = "neutral", size = "md", leadingIcon, trailingIcon, leading, trailing, icons, fullWidth = false, pressed, disabled, accessibilityLabel, ...rest }) {
|
|
92
109
|
const t = useAureaTokens();
|
|
93
110
|
const s = folha(t);
|
|
94
111
|
const cor = pintar(t, tone);
|
|
@@ -104,9 +121,9 @@ export function Button({ children, appearance = "solid", tone = "neutral", size
|
|
|
104
121
|
return (_jsx(Pressable, { disabled: disabled, accessibilityRole: "button", accessibilityLabel: accessibilityLabel, accessibilityState: { disabled: !!disabled, ...(pressed === undefined ? null : { checked: pressed }) }, style: ({ pressed: tocando }) => [
|
|
105
122
|
s.alvo, fullWidth && s.alvoLargura,
|
|
106
123
|
tocando && s.pressionado, disabled && s.inerte,
|
|
107
|
-
], ...rest, children: _jsxs(View, { style: [s.caixa, caixa], children: [leadingIcon ? _jsx(Icon, { name: leadingIcon, size: ICONE[size], color: corDoTexto, icons: icons }) : null, typeof children === "string"
|
|
124
|
+
], ...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"
|
|
108
125
|
? _jsx(Text, { size: FONTE[size], weight: 500, leading: "none", style: { color: corDoTexto }, children: children })
|
|
109
|
-
: children, trailingIcon ? _jsx(Icon, { name: trailingIcon, size: ICONE[size], color: corDoTexto, icons: icons }) : null] }) }));
|
|
126
|
+
: children, trailingIcon ? _jsx(Icon, { name: trailingIcon, size: ICONE[size], color: corDoTexto, icons: icons }) : null, trailing ?? null] }) }));
|
|
110
127
|
}
|
|
111
128
|
/**
|
|
112
129
|
* Botão quadrado, só glifo.
|
package/dist/display.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare const formatarContagem: (count: number, max?: number) => string;
|
|
|
10
10
|
export interface BadgeProps extends ViewProps {
|
|
11
11
|
/**
|
|
12
12
|
* O tom. Chama-se `tone` e não `variant`, como no `Button` do Lote 1 — o vocabulário de cor
|
|
13
|
-
* com significado é `tone` em todo o alvo nativo (ADR-
|
|
13
|
+
* com significado é `tone` em todo o alvo nativo (ADR-0044 é quem separa os dois na web).
|
|
14
14
|
*/
|
|
15
15
|
tone?: AureaBadgeTone;
|
|
16
16
|
emphasis?: AureaBadgeEmphasis;
|
package/dist/index.d.ts
CHANGED
|
@@ -9,8 +9,8 @@ export { Icon, IconRegistryProvider, criarRegistroDeIcones } from "./icon.js";
|
|
|
9
9
|
export type { IconProps, IconName, AureaIconComponent, AureaIconRegistry, AureaIconSize, } from "./icon.js";
|
|
10
10
|
export { Screen } from "./screen.js";
|
|
11
11
|
export type { ScreenProps, AureaScreenBackground, AureaScreenEdge } from "./screen.js";
|
|
12
|
-
export { Stack, Cluster, Grid, Card } from "./layout.js";
|
|
13
|
-
export type { StackProps, GridProps, CardProps, AureaCardVariant } from "./layout.js";
|
|
12
|
+
export { Stack, Cluster, Grid, Card, Separator } from "./layout.js";
|
|
13
|
+
export type { StackProps, GridProps, CardProps, SeparatorProps, AureaCardVariant } from "./layout.js";
|
|
14
14
|
export { Button, IconButton } from "./actions.js";
|
|
15
15
|
export type { ButtonProps, IconButtonProps, AureaButtonAppearance, AureaButtonSize, AureaButtonTone, } from "./actions.js";
|
|
16
16
|
export { Spinner, Skeleton, Progress, Alert, EmptyState, DataState, ICONE_DA_VARIANTE } from "./feedback.js";
|
|
@@ -25,6 +25,8 @@ export { BottomNav, Topbar, NavList, Stepper } from "./navigation.js";
|
|
|
25
25
|
export type { BottomNavProps, TopbarProps, NavListProps, StepperProps, AureaNavItem, AureaNavListItem, AureaStepItem, AureaStepState, AureaBottomNavVariant, AureaBottomNavIndicator, AureaTopbarVariant, } from "./navigation.js";
|
|
26
26
|
export { Field, Label, Input, Textarea, Select, Switch, Checkbox, Radio, SegmentedControl, Form, KeyboardAvoiding, useCampo, } from "./inputs.js";
|
|
27
27
|
export type { FieldProps, LabelProps, InputProps, TextareaProps, SelectProps, SwitchProps, CheckboxProps, RadioProps, SegmentedControlProps, FormProps, KeyboardAvoidingProps, AureaFieldSize, } from "./inputs.js";
|
|
28
|
+
export { InputGroup, InputGroupAddon, PasswordField, useGrupoDeCampo } from "./inputs.js";
|
|
29
|
+
export type { InputGroupProps, InputGroupAddonProps, PasswordFieldProps } from "./inputs.js";
|
|
28
30
|
export { Dialog, ConfirmDialog, Drawer, BottomSheet } from "./overlays.js";
|
|
29
31
|
export type { DialogProps, ConfirmDialogProps, DrawerProps, BottomSheetProps, AureaDrawerSide, } from "./overlays.js";
|
|
30
32
|
export { ToastHost, Toast, useToast } from "./toast.js";
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ export { Icon, IconRegistryProvider, criarRegistroDeIcones } from "./icon.js";
|
|
|
33
33
|
// A ÚNICA peça do Lote 1 com dependência de terceiro — `react-native-safe-area-context`,
|
|
34
34
|
// autorizada pelo Victor em 03/09/2026 depois de o lote parar por ela (`BUILDING.md` §3).
|
|
35
35
|
export { Screen } from "./screen.js";
|
|
36
|
-
export { Stack, Cluster, Grid, Card } from "./layout.js";
|
|
36
|
+
export { Stack, Cluster, Grid, Card, Separator } from "./layout.js";
|
|
37
37
|
export { Button, IconButton } from "./actions.js";
|
|
38
38
|
// ── Lote 2 — o painel, que é só leitura ────────────────────────────────────────────────────
|
|
39
39
|
export { Spinner, Skeleton, Progress, Alert, EmptyState, DataState, ICONE_DA_VARIANTE } from "./feedback.js";
|
|
@@ -54,6 +54,11 @@ export { BottomNav, Topbar, NavList, Stepper } from "./navigation.js";
|
|
|
54
54
|
// nome, a dica e o estado de inválido para o controle por CONTEXTO. É a tradução que decidiu o
|
|
55
55
|
// lote — o RN não tem `id` nem `htmlFor`.
|
|
56
56
|
export { Field, Label, Input, Textarea, Select, Switch, Checkbox, Radio, SegmentedControl, Form, KeyboardAvoiding, useCampo, } from "./inputs.js";
|
|
57
|
+
// ⚠ O GRUPO e o campo de SENHA entraram depois do Lote 4, medidos pelo app na tela de entrar
|
|
58
|
+
// (15/09/2026): o campo não tinha onde encaixar glifo, e `secureTextEntry` esconde a senha sem
|
|
59
|
+
// dar botão para mostrá-la. **Os dois já existiam na web desde 29/08/2026** — a falta era só
|
|
60
|
+
// deste lado, e o desenho daqui é o de lá traduzido, não um desenho novo.
|
|
61
|
+
export { InputGroup, InputGroupAddon, PasswordField, useGrupoDeCampo } from "./inputs.js";
|
|
57
62
|
// ⚠ `DatePicker` e `PhotoInput` NÃO saem daqui, e é de propósito: eles vivem em
|
|
58
63
|
// `@aurea-uds/native/system`, pela mesma razão que os ícones vivem em `./icons/*` (ADR-0038).
|
|
59
64
|
// Sair por este barril traria os dois módulos NATIVOS ao grafo de todo app — inclusive de quem
|
package/dist/inputs.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { type KeyboardTypeOptions, type StyleProp, type TextStyle, type ViewProps, type ViewStyle } from "react-native";
|
|
3
|
-
import { type IconName } from "./icon.js";
|
|
2
|
+
import { TextInput, type KeyboardTypeOptions, type StyleProp, type TextInputProps, type TextStyle, type ViewProps, type ViewStyle } from "react-native";
|
|
3
|
+
import { type AureaIconRegistry, type IconName } from "./icon.js";
|
|
4
4
|
export type AureaFieldSize = "sm" | "md" | "lg";
|
|
5
5
|
type ContextoDeCampo = {
|
|
6
6
|
label?: string;
|
|
@@ -11,6 +11,14 @@ type ContextoDeCampo = {
|
|
|
11
11
|
};
|
|
12
12
|
/** O que os controles leem do `Field` acima deles. Público porque um controle novo vai precisar. */
|
|
13
13
|
export declare function useCampo(): ContextoDeCampo | null;
|
|
14
|
+
interface ContextoDeGrupo {
|
|
15
|
+
size: AureaFieldSize;
|
|
16
|
+
disabled: boolean;
|
|
17
|
+
/** O campo avisa o grupo quando ganha e perde o foco — no RN não existe `:focus-within`. */
|
|
18
|
+
aoFocar: (v: boolean) => void;
|
|
19
|
+
}
|
|
20
|
+
/** O grupo em volta do campo, quando existe um. `null` quando o campo está sozinho. */
|
|
21
|
+
export declare function useGrupoDeCampo(): ContextoDeGrupo | null;
|
|
14
22
|
export interface FieldProps extends ViewProps {
|
|
15
23
|
label?: string;
|
|
16
24
|
hint?: React.ReactNode;
|
|
@@ -51,7 +59,30 @@ export interface LabelProps extends ViewProps {
|
|
|
51
59
|
* entrega. Um `Label` solto é decoração; use-o dentro de um `Field`.
|
|
52
60
|
*/
|
|
53
61
|
export declare function Label({ children, trailing, style, ...rest }: LabelProps): React.JSX.Element;
|
|
54
|
-
|
|
62
|
+
/**
|
|
63
|
+
* ⚠ **O `Input` HERDA do `TextInput`, e isso é conserto de defeito publicado na `0.8.2`.**
|
|
64
|
+
*
|
|
65
|
+
* Até ali a interface listava catorze props e o componente desestruturava as catorze **sem
|
|
66
|
+
* `...rest`**: tudo o que não estivesse na lista era **descartado em silêncio**. O app achou na
|
|
67
|
+
* tela de entrar, e o efeito não aparece na tela — aparece no uso: sem `autoComplete` e
|
|
68
|
+
* `textContentType` o gerenciador de senhas não reconhece os campos; sem `autoCorrect` o teclado
|
|
69
|
+
* "corrige" o e-mail; sem `returnKeyType`/`onSubmitEditing` o botão "próximo" não pula para a
|
|
70
|
+
* senha; e sem `ref` não há como focar o campo por código.
|
|
71
|
+
*
|
|
72
|
+
* ⚠ **Era pior do que parece:** o `PasswordField` repassa `...rest` ao `Input` — e o `Input`
|
|
73
|
+
* jogava fora. Duas camadas concordando em perder a prop.
|
|
74
|
+
*
|
|
75
|
+
* O que continua sendo da Aurea está no `Omit` abaixo, e a razão de cada um está ao lado.
|
|
76
|
+
*/
|
|
77
|
+
export interface InputProps extends Omit<TextInputProps, "style" | "editable" | "placeholderTextColor" | "onBlur" | "onFocus" | "accessibilityLabel" | "accessibilityHint" | "accessibilityState"> {
|
|
78
|
+
/**
|
|
79
|
+
* O nó do `TextInput` lá dentro — para focar por código (`ref.current?.focus()`), que é como
|
|
80
|
+
* o "próximo" do teclado pula de um campo para o outro.
|
|
81
|
+
*
|
|
82
|
+
* Chega por PROPS e atravessa no `...rest`: é o padrão do React 19, sem `forwardRef`, o mesmo
|
|
83
|
+
* que o `layout.tsx` já documenta. **Faltava na `0.8.2`** — não havia como focar campo nenhum.
|
|
84
|
+
*/
|
|
85
|
+
ref?: React.Ref<React.ComponentRef<typeof TextInput>>;
|
|
55
86
|
value?: string;
|
|
56
87
|
defaultValue?: string;
|
|
57
88
|
onChangeText?: (v: string) => void;
|
|
@@ -103,7 +134,7 @@ export interface InputProps {
|
|
|
103
134
|
* (`aurea.css:686`); **não há ponteiro no telefone**. O foco continua existindo e é o que marca o
|
|
104
135
|
* campo ativo.
|
|
105
136
|
*/
|
|
106
|
-
export declare function Input({ value, defaultValue, onChangeText, placeholder, disabled, size, keyboardType, secureTextEntry, autoCapitalize, formatOnBlur, onBlur, onFocus, multiline, style, testID, }: InputProps): React.JSX.Element;
|
|
137
|
+
export declare function Input({ value, defaultValue, onChangeText, placeholder, disabled, size, keyboardType, secureTextEntry, autoCapitalize, formatOnBlur, onBlur, onFocus, multiline, style, testID, ...rest }: InputProps): React.JSX.Element;
|
|
107
138
|
export interface TextareaProps extends InputProps {
|
|
108
139
|
/** Linhas visíveis. Vira altura mínima, porque no RN não há `rows`. */
|
|
109
140
|
rows?: number;
|
|
@@ -120,6 +151,78 @@ interface ControleProps {
|
|
|
120
151
|
style?: StyleProp<ViewStyle>;
|
|
121
152
|
testID?: string;
|
|
122
153
|
}
|
|
154
|
+
export interface InputGroupProps extends ViewProps {
|
|
155
|
+
/** O degrau do sistema. Cai no `Field` em volta quando não vem, como no `Input`. */
|
|
156
|
+
size?: AureaFieldSize;
|
|
157
|
+
disabled?: boolean;
|
|
158
|
+
testID?: string;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* A caixa de campo que aceita coisas dentro — glifo na frente, botão atrás, os dois.
|
|
162
|
+
*
|
|
163
|
+
* <InputGroup>
|
|
164
|
+
* <InputGroupAddon><Icon name="email" size="sm" /></InputGroupAddon>
|
|
165
|
+
* <Input value={email} onChangeText={setEmail} keyboardType="email-address" />
|
|
166
|
+
* </InputGroup>
|
|
167
|
+
*
|
|
168
|
+
* ⚠ **O `Input` lá dentro para de desenhar a própria caixa** — quem desenha borda, fundo, altura,
|
|
169
|
+
* foco e inválido passa a ser o grupo. Isso é automático: o campo enxerga o grupo por contexto.
|
|
170
|
+
*/
|
|
171
|
+
export declare function InputGroup({ size, disabled, children, style, testID, ...rest }: InputGroupProps): React.JSX.Element;
|
|
172
|
+
export interface InputGroupAddonProps extends ViewProps {
|
|
173
|
+
testID?: string;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Um encaixe dentro do `InputGroup`. **A posição é a do JSX** — antes do campo fica na frente,
|
|
177
|
+
* depois fica atrás. Não há prop de lado, e o porquê está no bloco do grupo lá em cima.
|
|
178
|
+
*/
|
|
179
|
+
export declare function InputGroupAddon({ children, style, testID, ...rest }: InputGroupAddonProps): React.JSX.Element;
|
|
180
|
+
/**
|
|
181
|
+
* O campo de senha, com o botão que mostra e esconde.
|
|
182
|
+
*
|
|
183
|
+
* <Field label="Senha"><PasswordField value={senha} onChangeText={setSenha} /></Field>
|
|
184
|
+
*
|
|
185
|
+
* ⚠ **`secureTextEntry` não entra**: um campo de senha que aceitasse essa prop deixaria de ser
|
|
186
|
+
* um. É a mesma razão pela qual o `type` não atravessa no `PasswordField` da web.
|
|
187
|
+
*
|
|
188
|
+
* ⚠ **O rótulo do botão é o anúncio do estado** — ele troca entre "Mostrar senha" e "Ocultar
|
|
189
|
+
* senha". Não há estado de pressionado junto, e isso é decisão copiada da web: com os dois, o
|
|
190
|
+
* leitor de tela lê a mesma informação duas vezes.
|
|
191
|
+
*
|
|
192
|
+
* ⚠ **`autoCapitalize` nasce em `none`.** No Android o teclado maiúsculiza a primeira letra por
|
|
193
|
+
* padrão, e numa senha isso é o erro de digitação mais caro que existe: o campo está escondido,
|
|
194
|
+
* então ninguém vê o que deu errado.
|
|
195
|
+
*/
|
|
196
|
+
export interface PasswordFieldProps extends Omit<InputProps, "secureTextEntry" | "multiline" | "keyboardType"> {
|
|
197
|
+
/** Começa visível. Padrão: escondida. */
|
|
198
|
+
defaultVisible?: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* Um desenho na FRENTE do campo — o cadeado, quase sempre.
|
|
201
|
+
*
|
|
202
|
+
* ⚠ **Faltava na `0.8.2`, e a falta era de desenho meu:** o `PasswordField` monta o grupo por
|
|
203
|
+
* dentro, então não havia onde encaixar nada antes do campo. Quem quisesse um cadeado teria de
|
|
204
|
+
* desmontar a peça e remontar à mão, perdendo o olho, o rótulo que anuncia o estado e o
|
|
205
|
+
* `autoCapitalize` que nasce em `none`.
|
|
206
|
+
*
|
|
207
|
+
* <PasswordField leading={<Icon name="locked" size="sm" />} … />
|
|
208
|
+
*/
|
|
209
|
+
leading?: React.ReactNode;
|
|
210
|
+
/**
|
|
211
|
+
* O registro de glifos, quando o do `AureaProvider` não tem os dois que este componente usa.
|
|
212
|
+
*
|
|
213
|
+
* 🔴 **ELE PRECISA DE DOIS ÍCONES, e isto não estava escrito em lugar nenhum — defeito da
|
|
214
|
+
* `0.8.2`:** o olho é `view` e `view--off`. Se faltarem no registro, **o botão fica invisível**
|
|
215
|
+
* e o aviso sai só em desenvolvimento: em produção a pessoa simplesmente não consegue ver a
|
|
216
|
+
* senha que digitou, sem nada na tela explicando.
|
|
217
|
+
*
|
|
218
|
+
* import Olho from "@aurea-uds/native/icons/view";
|
|
219
|
+
* import OlhoOff from "@aurea-uds/native/icons/view--off";
|
|
220
|
+
* const ICONES = criarRegistroDeIcones({view: Olho, "view--off": OlhoOff});
|
|
221
|
+
* // no provider, junto dos outros — ou aqui: <PasswordField icons={ICONES} />
|
|
222
|
+
*/
|
|
223
|
+
icons?: AureaIconRegistry;
|
|
224
|
+
}
|
|
225
|
+
export declare function PasswordField({ defaultVisible, size, disabled, autoCapitalize, leading, icons, testID, style, ...rest }: PasswordFieldProps): React.JSX.Element;
|
|
123
226
|
export type CheckboxProps = ControleProps;
|
|
124
227
|
export type RadioProps = ControleProps;
|
|
125
228
|
/** A caixa que marca. `accessibilityRole="checkbox"` + `state.checked`. */
|
package/dist/inputs.js
CHANGED
|
@@ -40,10 +40,11 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
40
40
|
import * as React from "react";
|
|
41
41
|
import { Animated, KeyboardAvoidingView as KeyboardAvoidingViewRN, Modal, Platform, Pressable, ScrollView, TextInput, View, } from "react-native";
|
|
42
42
|
import { criarFolha } from "./estilos.js";
|
|
43
|
+
import { IconButton } from "./actions.js";
|
|
43
44
|
import { Icon } from "./icon.js";
|
|
44
45
|
import { useReduceMotion } from "./movimento.js";
|
|
45
46
|
import { Text } from "./text.js";
|
|
46
|
-
import { useAureaTokens } from "./theme.js";
|
|
47
|
+
import { useAureaStrings, useAureaTokens } from "./theme.js";
|
|
47
48
|
const alturaDoTamanho = (t, s) => s === "sm" ? t.size.controlHSm : s === "lg" ? t.size.controlHLg : t.size.controlHMd;
|
|
48
49
|
const fonteDoTamanho = (t, s) => s === "sm" ? t.size.textXs : s === "lg" ? t.size.textBase : t.size.textMd;
|
|
49
50
|
const respiroDoTamanho = (t, s) => s === "sm" ? t.size.space3 : s === "lg" ? t.size.space4 : 13;
|
|
@@ -61,6 +62,21 @@ const folha = criarFolha((t) => ({
|
|
|
61
62
|
areaDeTexto: { minHeight: 104, paddingVertical: t.size.space3, borderRadius: t.size.radiusLg },
|
|
62
63
|
invalido: { borderColor: t.color.danger400 ?? t.color.destructive },
|
|
63
64
|
desabilitado: { opacity: 0.5 },
|
|
65
|
+
// O GRUPO é a mesma caixa do campo virada em LINHA, e os números são os mesmos: mesma borda,
|
|
66
|
+
// mesmo raio de controle, mesmo fundo. A altura e o respiro horizontal entram por tamanho, como
|
|
67
|
+
// no `Input`, porque é o grupo que passa a desenhar a caixa quando existe um.
|
|
68
|
+
grupo: {
|
|
69
|
+
flexDirection: "row", alignItems: "center", width: "100%", minWidth: 0,
|
|
70
|
+
borderWidth: t.size.borderWidth, borderColor: t.color.borderStrong,
|
|
71
|
+
borderRadius: t.size.radiusControl, backgroundColor: t.color.fieldBg,
|
|
72
|
+
gap: t.size.space1,
|
|
73
|
+
},
|
|
74
|
+
// Dentro do grupo o campo perde a caixa e vira só o texto — a borda passou a ser do grupo.
|
|
75
|
+
// ⚠ As DUAS últimas linhas continuam obrigatórias: são o conserto de Android de 09/09/2026
|
|
76
|
+
// (`paddingVertical: 0` desliga a injeção do tema, `textAlignVertical` tira o texto do topo).
|
|
77
|
+
// É o mesmo par que o `campoDeTexto` do `busca.tsx` carrega pela mesma razão.
|
|
78
|
+
campoNoGrupo: { flex: 1, minWidth: 0, paddingVertical: 0, textAlignVertical: "center" },
|
|
79
|
+
encaixe: { flexDirection: "row", alignItems: "center", flexShrink: 0, gap: t.size.space1 },
|
|
64
80
|
marcaBase: {
|
|
65
81
|
alignItems: "center", justifyContent: "center", marginTop: 1,
|
|
66
82
|
borderWidth: t.size.borderWidth, borderColor: t.color.borderStrong,
|
|
@@ -96,6 +112,11 @@ const CampoCtx = React.createContext(null);
|
|
|
96
112
|
export function useCampo() {
|
|
97
113
|
return React.useContext(CampoCtx);
|
|
98
114
|
}
|
|
115
|
+
const GrupoDeCampo = React.createContext(null);
|
|
116
|
+
/** O grupo em volta do campo, quando existe um. `null` quando o campo está sozinho. */
|
|
117
|
+
export function useGrupoDeCampo() {
|
|
118
|
+
return React.useContext(GrupoDeCampo);
|
|
119
|
+
}
|
|
99
120
|
/**
|
|
100
121
|
* Rótulo, controle, dica e erro — na ordem, com o respiro do CSS.
|
|
101
122
|
*
|
|
@@ -147,15 +168,25 @@ export function Label({ children, trailing, style, ...rest }) {
|
|
|
147
168
|
* (`aurea.css:686`); **não há ponteiro no telefone**. O foco continua existindo e é o que marca o
|
|
148
169
|
* campo ativo.
|
|
149
170
|
*/
|
|
150
|
-
export function Input({ value, defaultValue, onChangeText, placeholder, disabled, size, keyboardType, secureTextEntry, autoCapitalize, formatOnBlur, onBlur, onFocus, multiline, style, testID,
|
|
171
|
+
export function Input({ value, defaultValue, onChangeText, placeholder, disabled, size, keyboardType, secureTextEntry, autoCapitalize, formatOnBlur, onBlur, onFocus, multiline, style, testID,
|
|
172
|
+
// ⚠ O `...rest` NÃO é enfeite: sem ele, toda prop do `TextInput` que a lista acima não nomeia
|
|
173
|
+
// era descartada em silêncio — `autoComplete`, `textContentType`, `autoCorrect`,
|
|
174
|
+
// `returnKeyType`, `onSubmitEditing`, `maxLength`. Defeito publicado na `0.8.2`.
|
|
175
|
+
...rest }) {
|
|
151
176
|
const t = useAureaTokens();
|
|
152
177
|
const s = folha(t);
|
|
153
178
|
const campo = useCampo();
|
|
154
|
-
const
|
|
155
|
-
const
|
|
179
|
+
const grupo = useGrupoDeCampo();
|
|
180
|
+
const tam = size ?? grupo?.size ?? campo?.size ?? "md";
|
|
181
|
+
const inativo = disabled ?? grupo?.disabled ?? campo?.disabled;
|
|
156
182
|
const [focado, setFocado] = React.useState(false);
|
|
157
|
-
return (_jsx(TextInput
|
|
183
|
+
return (_jsx(TextInput
|
|
184
|
+
// O resto vem PRIMEIRO de propósito: o que a Aurea calcula (respiro, cor, nome do `Field`,
|
|
185
|
+
// `editable`) tem de vencer, e as props que ela redefine estão no `Omit` da interface —
|
|
186
|
+
// então não chegam por aqui e não há o que sobrescrever por acidente.
|
|
187
|
+
, { ...rest, testID: testID, value: value, defaultValue: defaultValue, onChangeText: onChangeText, placeholder: placeholder, placeholderTextColor: t.color.subtleForeground, editable: !inativo, keyboardType: keyboardType, secureTextEntry: secureTextEntry, autoCapitalize: autoCapitalize, multiline: multiline, onFocus: () => { setFocado(true); grupo?.aoFocar(true); onFocus?.(); }, onBlur: () => {
|
|
158
188
|
setFocado(false);
|
|
189
|
+
grupo?.aoFocar(false);
|
|
159
190
|
// Só avisa quando o texto MUDOU: emitir o mesmo valor a cada saída de foco faria o app
|
|
160
191
|
// re-renderizar sem motivo, e num formulário de dez campos isso é dez renders por
|
|
161
192
|
// preenchimento. Mesma guarda da web (`inputs-client.tsx:194`).
|
|
@@ -169,30 +200,36 @@ export function Input({ value, defaultValue, onChangeText, placeholder, disabled
|
|
|
169
200
|
// O nome e a dica vêm do `Field` — ver o bloco acima sobre por que a ligação da web não
|
|
170
201
|
// atravessa. Sem isto, o campo é um nó anônimo para o leitor de tela.
|
|
171
202
|
accessibilityLabel: campo?.label, accessibilityHint: campo?.hint, accessibilityState: { disabled: !!inativo }, "aria-invalid": campo?.invalido, style: [
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
203
|
+
// DENTRO DE UM GRUPO o campo não desenha caixa nenhuma: borda, fundo, altura, respiro,
|
|
204
|
+
// inválido, foco e desabilitado passam a ser do grupo. Manter qualquer um dos dois
|
|
205
|
+
// desenhando daria borda dentro de borda — que é exatamente o defeito que o `.input-group
|
|
206
|
+
// > .input` da web zera à mão (`aurea.css:751`).
|
|
207
|
+
grupo ? s.campoNoGrupo : s.caixa,
|
|
208
|
+
grupo
|
|
209
|
+
? { fontSize: fonteDoTamanho(t, tam), fontFamily: t.font.ui[400], color: t.color.foreground }
|
|
210
|
+
: { height: alturaDoTamanho(t, tam), paddingHorizontal: respiroDoTamanho(t, tam),
|
|
211
|
+
fontSize: fonteDoTamanho(t, tam), fontFamily: t.font.ui[400], color: t.color.foreground,
|
|
212
|
+
// ⚠ AS DUAS LINHAS ABAIXO NÃO SÃO ENFEITE — sem elas o texto sobe e é CORTADO no
|
|
213
|
+
// Android, e foi assim que este campo chegou ao vidro em 09/09/2026.
|
|
214
|
+
//
|
|
215
|
+
// `padding-block:0` é LITERAL na web (`aurea.css:685`) e não atravessou. No RN a falta
|
|
216
|
+
// dele não é "sem padding": o `AndroidTextInputComponentDescriptor.h:101-107` INJETA o
|
|
217
|
+
// padding do tema do Android no nó do Yoga sempre que as props não trazem `padding`,
|
|
218
|
+
// `paddingTop`/`paddingBottom` nem `paddingVertical` — e o `hasPaddingVertical` é
|
|
219
|
+
// exatamente o que desliga a injeção. Com `height` fixa, esse padding come a altura por
|
|
220
|
+
// dentro e a caixa de texto fica menor que a linha: daí o corte.
|
|
221
|
+
//
|
|
222
|
+
// O `textAlignVertical` é o outro lado da mesma conta. Na web, um campo com
|
|
223
|
+
// `block-size` centraliza a linha sozinho; no Android o `setTextAlignVertical` do
|
|
224
|
+
// `ReactTextInputManager.kt:571` traduz `null`/`auto` para `Gravity.NO_GRAVITY`, que
|
|
225
|
+
// deixa o `EditText` no topo. `center` é o que reproduz a web — e o `Textarea` o
|
|
226
|
+
// sobrescreve para `top`, que é o que uma caixa alta faz nos dois lados.
|
|
227
|
+
paddingVertical: 0, textAlignVertical: "center" },
|
|
228
|
+
!grupo && campo?.invalido && s.invalido,
|
|
192
229
|
// O foco é o único estado que sobra do trio da web (hover/focus/active), e ele importa
|
|
193
230
|
// mais aqui: no telefone é a única pista de qual campo o teclado está alimentando.
|
|
194
|
-
focado && { borderColor: t.color.focusStrong },
|
|
195
|
-
inativo && s.desabilitado,
|
|
231
|
+
!grupo && focado && { borderColor: t.color.focusStrong },
|
|
232
|
+
!grupo && inativo && s.desabilitado,
|
|
196
233
|
style,
|
|
197
234
|
] }));
|
|
198
235
|
}
|
|
@@ -211,6 +248,55 @@ export function Textarea({ rows, size, style, ...rest }) {
|
|
|
211
248
|
style,
|
|
212
249
|
], multiline: true }));
|
|
213
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* A caixa de campo que aceita coisas dentro — glifo na frente, botão atrás, os dois.
|
|
253
|
+
*
|
|
254
|
+
* <InputGroup>
|
|
255
|
+
* <InputGroupAddon><Icon name="email" size="sm" /></InputGroupAddon>
|
|
256
|
+
* <Input value={email} onChangeText={setEmail} keyboardType="email-address" />
|
|
257
|
+
* </InputGroup>
|
|
258
|
+
*
|
|
259
|
+
* ⚠ **O `Input` lá dentro para de desenhar a própria caixa** — quem desenha borda, fundo, altura,
|
|
260
|
+
* foco e inválido passa a ser o grupo. Isso é automático: o campo enxerga o grupo por contexto.
|
|
261
|
+
*/
|
|
262
|
+
export function InputGroup({ size, disabled, children, style, testID, ...rest }) {
|
|
263
|
+
const t = useAureaTokens();
|
|
264
|
+
const s = folha(t);
|
|
265
|
+
const campo = useCampo();
|
|
266
|
+
const tam = size ?? campo?.size ?? "md";
|
|
267
|
+
const inativo = disabled ?? campo?.disabled ?? false;
|
|
268
|
+
const [focado, setFocado] = React.useState(false);
|
|
269
|
+
// O contexto muda de identidade a cada render se for objeto literal, e isso re-renderiza todo
|
|
270
|
+
// campo de todo formulário a cada tecla. Mesma memoização do `Field`.
|
|
271
|
+
const ctx = React.useMemo(() => ({ size: tam, disabled: inativo, aoFocar: setFocado }), [tam, inativo]);
|
|
272
|
+
return (_jsx(View, { testID: testID, style: [
|
|
273
|
+
s.grupo,
|
|
274
|
+
{ height: alturaDoTamanho(t, tam), paddingHorizontal: respiroDoTamanho(t, tam) },
|
|
275
|
+
campo?.invalido && s.invalido,
|
|
276
|
+
// O foco vem do campo lá dentro, por contexto: no React Native não existe `:focus-within`,
|
|
277
|
+
// e sem isto a única pista de qual campo o teclado alimenta sumiria ao entrar num grupo.
|
|
278
|
+
focado && { borderColor: t.color.focusStrong },
|
|
279
|
+
inativo && s.desabilitado,
|
|
280
|
+
style,
|
|
281
|
+
], ...rest, children: _jsx(GrupoDeCampo.Provider, { value: ctx, children: children }) }));
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Um encaixe dentro do `InputGroup`. **A posição é a do JSX** — antes do campo fica na frente,
|
|
285
|
+
* depois fica atrás. Não há prop de lado, e o porquê está no bloco do grupo lá em cima.
|
|
286
|
+
*/
|
|
287
|
+
export function InputGroupAddon({ children, style, testID, ...rest }) {
|
|
288
|
+
const t = useAureaTokens();
|
|
289
|
+
const s = folha(t);
|
|
290
|
+
return _jsx(View, { testID: testID, style: [s.encaixe, style], ...rest, children: children });
|
|
291
|
+
}
|
|
292
|
+
export function PasswordField({ defaultVisible = false, size, disabled, autoCapitalize = "none", leading, icons, testID, style, ...rest }) {
|
|
293
|
+
const strings = useAureaStrings();
|
|
294
|
+
const campo = useCampo();
|
|
295
|
+
const [visivel, setVisivel] = React.useState(defaultVisible);
|
|
296
|
+
const tam = size ?? campo?.size ?? "md";
|
|
297
|
+
const inativo = disabled ?? campo?.disabled;
|
|
298
|
+
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 }) })] }));
|
|
299
|
+
}
|
|
214
300
|
function ControleMarcado({ papel, label, description, checked, onChange, disabled, size, style, testID, }) {
|
|
215
301
|
const t = useAureaTokens();
|
|
216
302
|
const s = folha(t);
|
package/dist/layout.d.ts
CHANGED
|
@@ -33,6 +33,28 @@ export interface GridProps extends ViewProps {
|
|
|
33
33
|
*/
|
|
34
34
|
export declare function Grid({ minColumnWidth, style, children, ...rest }: GridProps): React.JSX.Element;
|
|
35
35
|
/** Qual superfície o cartão é. Mesmos seis nomes da ficha da web. */
|
|
36
|
+
export interface SeparatorProps extends ViewProps {
|
|
37
|
+
orientation?: "horizontal" | "vertical";
|
|
38
|
+
/**
|
|
39
|
+
* Um texto NO MEIO da linha — "ou entre com", numa tela de entrar.
|
|
40
|
+
*
|
|
41
|
+
* ⚠ **Isto NÃO existe na web, e a divergência fica declarada em vez de escondida.** Lá o
|
|
42
|
+
* `.separator` é só a linha, e um rótulo no meio nunca foi pedido. Aqui foi: o app mediu essa
|
|
43
|
+
* lacuna na tela de entrar, e a demanda manda no nativo desde o Lote 7. **Com `label`, a
|
|
44
|
+
* orientação é sempre horizontal** — texto no meio de uma linha vertical não é a mesma peça.
|
|
45
|
+
*/
|
|
46
|
+
label?: React.ReactNode;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A linha de divisão do sistema. Mesma cor e mesma espessura do `.separator` da web.
|
|
50
|
+
*
|
|
51
|
+
* ⚠ **Ela NÃO recebe papel de acessibilidade, e isso é escolha medida, não esquecimento.** O
|
|
52
|
+
* `<hr>` da web traz o papel `separator` de graça; no React Native esse papel **não existe na
|
|
53
|
+
* lista** — inventar o mais parecido diria uma coisa errada ao leitor de tela, que é exatamente
|
|
54
|
+
* a armadilha que o Lote 5 e a `Table` do Lote 6 já pagaram. Uma linha decorativa calada é o
|
|
55
|
+
* comportamento certo.
|
|
56
|
+
*/
|
|
57
|
+
export declare function Separator({ orientation, label, style, ...rest }: SeparatorProps): React.JSX.Element;
|
|
36
58
|
export type AureaCardVariant = "base" | "raised" | "interactive" | "inset" | "selected" | "danger";
|
|
37
59
|
export interface CardProps extends ViewProps {
|
|
38
60
|
variant?: AureaCardVariant;
|
package/dist/layout.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// Aurea nativo — os primitivos de layout: `Stack`, `Cluster`, `Grid`, `Card`.
|
|
3
3
|
//
|
|
4
4
|
// Medidos no core da web antes de escrever (passo 1 do BUILDING.md), e o que eles são lá:
|
|
@@ -18,8 +18,18 @@ import { View } from "react-native";
|
|
|
18
18
|
// envelope). O `ViewProps`/`TextProps` do RN 0.87 ja' declaram `ref`, entao ele viaja no
|
|
19
19
|
// `...rest` sem nada a mais.
|
|
20
20
|
import { criarFolha } from "./estilos.js";
|
|
21
|
+
import { Text } from "./text.js";
|
|
21
22
|
import { useAureaTokens } from "./theme.js";
|
|
22
23
|
const folha = criarFolha((t) => ({
|
|
24
|
+
// A LINHA DO SISTEMA, e os números são os mesmos do `.separator` da web (`aurea.css`): cor de
|
|
25
|
+
// `border` e espessura de UM pixel. ⚠ Um pixel não sai de `--space-*` de propósito — a linha
|
|
26
|
+
// do sistema é de um pixel, e um pixel não é espaçamento. A mesma frase está no CSS.
|
|
27
|
+
separador: { backgroundColor: t.color.border },
|
|
28
|
+
separadorH: { height: t.size.borderWidth, width: "100%" },
|
|
29
|
+
separadorV: { width: t.size.borderWidth, alignSelf: "stretch", minHeight: t.size.space5 },
|
|
30
|
+
// A linha COM texto no meio: duas linhas que esticam e o rótulo entre elas, sem encolher.
|
|
31
|
+
separadorRotulado: { flexDirection: "row", alignItems: "center", gap: t.size.space3, width: "100%" },
|
|
32
|
+
separadorPedaco: { flex: 1, height: t.size.borderWidth, backgroundColor: t.color.border },
|
|
23
33
|
// `gap` no RN existe desde a 0.71 e é o mesmo conceito do flex gap do CSS — medido no contrato
|
|
24
34
|
// do `react-native` 0.86/0.87 que o pacote declara como peer (>=0.76).
|
|
25
35
|
stack: { flexDirection: "column", gap: t.size.space4 },
|
|
@@ -74,6 +84,25 @@ export function Grid({ minColumnWidth = 240, style, children, ...rest }) {
|
|
|
74
84
|
const celula = React.useMemo(() => ({ flexGrow: 0, flexShrink: 1, flexBasis: minColumnWidth, minWidth: minColumnWidth, maxWidth: "100%" }), [minColumnWidth]);
|
|
75
85
|
return (_jsx(View, { style: [s.grid, style], ...rest, children: React.Children.map(children, (filho) => React.isValidElement(filho) ? _jsx(View, { style: celula, children: filho }) : filho) }));
|
|
76
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* A linha de divisão do sistema. Mesma cor e mesma espessura do `.separator` da web.
|
|
89
|
+
*
|
|
90
|
+
* ⚠ **Ela NÃO recebe papel de acessibilidade, e isso é escolha medida, não esquecimento.** O
|
|
91
|
+
* `<hr>` da web traz o papel `separator` de graça; no React Native esse papel **não existe na
|
|
92
|
+
* lista** — inventar o mais parecido diria uma coisa errada ao leitor de tela, que é exatamente
|
|
93
|
+
* a armadilha que o Lote 5 e a `Table` do Lote 6 já pagaram. Uma linha decorativa calada é o
|
|
94
|
+
* comportamento certo.
|
|
95
|
+
*/
|
|
96
|
+
export function Separator({ orientation = "horizontal", label, style, ...rest }) {
|
|
97
|
+
const t = useAureaTokens();
|
|
98
|
+
const s = folha(t);
|
|
99
|
+
if (label != null) {
|
|
100
|
+
return (_jsxs(View, { style: [s.separadorRotulado, style], ...rest, children: [_jsx(View, { style: s.separadorPedaco }), typeof label === "string"
|
|
101
|
+
? _jsx(Text, { size: "sm", tone: "muted", children: label })
|
|
102
|
+
: label, _jsx(View, { style: s.separadorPedaco })] }));
|
|
103
|
+
}
|
|
104
|
+
return (_jsx(View, { style: [s.separador, orientation === "vertical" ? s.separadorV : s.separadorH, style], ...rest }));
|
|
105
|
+
}
|
|
77
106
|
/**
|
|
78
107
|
* Superfície flutuante, raio 22 (`--radius-card`) — identidade declarada INTOCÁVEL.
|
|
79
108
|
*
|
package/dist/strings.d.ts
CHANGED
|
@@ -32,6 +32,14 @@ export interface AureaStrings {
|
|
|
32
32
|
openSettings: string;
|
|
33
33
|
/** O rótulo do botão que tira uma foto anexada. */
|
|
34
34
|
photoRemove: string;
|
|
35
|
+
/**
|
|
36
|
+
* O botão que revela a senha no `PasswordField`, e o que a esconde de volta. Mesmos nomes da
|
|
37
|
+
* web (`pure.tsx`), porque é a mesma peça com a mesma decisão: **o rótulo é que anuncia o
|
|
38
|
+
* estado**, e não um `accessibilityState` de pressionado — com os dois, o leitor de tela diz
|
|
39
|
+
* a mesma coisa duas vezes.
|
|
40
|
+
*/
|
|
41
|
+
passwordShow: string;
|
|
42
|
+
passwordHide: string;
|
|
35
43
|
/** O botão de fechar do `Dialog` e do `Drawer`. Mesmo nome da web. */
|
|
36
44
|
close: string;
|
|
37
45
|
/** A saída do `ConfirmDialog`. Mesmo nome da web. */
|
package/dist/strings.js
CHANGED
|
@@ -37,6 +37,8 @@ export const defaultStrings = {
|
|
|
37
37
|
cameraDenied: "Camera access is off. Turn it on in Settings to attach a photo.",
|
|
38
38
|
openSettings: "Open Settings",
|
|
39
39
|
photoRemove: "Remove photo",
|
|
40
|
+
passwordShow: "Show password",
|
|
41
|
+
passwordHide: "Hide password",
|
|
40
42
|
close: "Close",
|
|
41
43
|
confirmCancel: "Cancel",
|
|
42
44
|
confirmProceed: "Continue",
|
|
@@ -72,6 +74,8 @@ export const ptBR = {
|
|
|
72
74
|
cameraDenied: "O acesso à câmera está desligado. Ligue nas configurações para anexar uma foto.",
|
|
73
75
|
openSettings: "Abrir configurações",
|
|
74
76
|
photoRemove: "Remover foto",
|
|
77
|
+
passwordShow: "Mostrar senha",
|
|
78
|
+
passwordHide: "Ocultar senha",
|
|
75
79
|
close: "Fechar",
|
|
76
80
|
confirmCancel: "Cancelar",
|
|
77
81
|
confirmProceed: "Continuar",
|
package/dist/text.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ export type AureaTextSize = "xs" | "sm" | "md" | "base" | "lg" | "xl" | "2xl" |
|
|
|
6
6
|
export type AureaTextWeight = 400 | 500 | 600 | 700;
|
|
7
7
|
/** Papel de tipografia — os três `--font-*` da Aurea. */
|
|
8
8
|
export type AureaTextFont = "ui" | "editorial" | "code";
|
|
9
|
-
/** O que a cor SIGNIFICA. Mesmo vocabulário do `tone` do Button (ADR-
|
|
10
|
-
export type AureaTextTone = "default" | "muted" | "subtle" | "primary" | "danger" | "success" | "warning" | "info";
|
|
9
|
+
/** O que a cor SIGNIFICA. Mesmo vocabulário do `tone` do Button (ADR-0044). */
|
|
10
|
+
export type AureaTextTone = "default" | "muted" | "subtle" | "primary" | "link" | "danger" | "success" | "warning" | "info";
|
|
11
11
|
export type AureaTextLeading = "none" | "tight" | "normal" | "relaxed";
|
|
12
12
|
export interface TextProps extends TextPropsRN {
|
|
13
13
|
size?: AureaTextSize;
|
package/dist/text.js
CHANGED
|
@@ -32,7 +32,11 @@ const ENTRELINHA = {
|
|
|
32
32
|
};
|
|
33
33
|
const COR = {
|
|
34
34
|
default: "foreground", muted: "mutedForeground", subtle: "subtleForeground",
|
|
35
|
-
|
|
35
|
+
// ⚠ `primary` e `link` são o MESMO amarelo em matiz, e NÃO são intercambiáveis.
|
|
36
|
+
// `primary` é o amarelo de PREENCHER, e escrito sobre o tema claro ele mede 1,73:1 — some.
|
|
37
|
+
// `link` é o de ESCREVER: mesmo matiz, mais escuro, 5,02:1 no claro, e no escuro é o próprio
|
|
38
|
+
// amarelo da marca. Quem quer texto amarelo legível nos dois temas usa `link`.
|
|
39
|
+
primary: "primary", link: "link", danger: "destructive", success: "success",
|
|
36
40
|
warning: "warning", info: "info",
|
|
37
41
|
};
|
|
38
42
|
// A folha cobre só o que NÃO depende das props — a cor por tom. O resto (tamanho, peso, família)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurea-uds/native",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "React Native target for Aurea UDS: the theme x density provider, the first components and the Carbon icons, drawn on react-native-svg.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aurea",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"NOTICE"
|
|
48
48
|
],
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@aurea-uds/tokens": "^0.8.
|
|
50
|
+
"@aurea-uds/tokens": "^0.8.3"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"@react-native-community/datetimepicker": ">=8",
|