@aurea-uds/native 0.10.1 → 0.12.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/README.md +10 -0
- package/dist/actions.d.ts +14 -5
- package/dist/actions.js +69 -20
- package/dist/busca.d.ts +9 -2
- package/dist/busca.js +14 -5
- package/dist/display.d.ts +0 -16
- package/dist/display.js +21 -7
- package/dist/icon-names.d.ts +14 -0
- package/dist/icon-names.js +3 -0
- package/dist/icon.d.ts +4 -4
- package/dist/index.d.ts +7 -6
- package/dist/index.js +2 -2
- package/dist/inputs.d.ts +10 -1
- package/dist/inputs.js +16 -8
- package/dist/layout.d.ts +19 -7
- package/dist/layout.js +40 -11
- package/dist/navigation.d.ts +4 -1
- package/dist/navigation.js +2 -2
- package/dist/numero.d.ts +3 -4
- package/dist/overlays.js +12 -5
- package/dist/rolagem.d.ts +8 -1
- package/dist/rolagem.js +7 -2
- package/dist/screen.d.ts +10 -0
- package/dist/screen.js +84 -2
- package/dist/strings.d.ts +3 -0
- package/dist/strings.js +4 -0
- package/dist/text.d.ts +38 -1
- package/dist/text.js +45 -4
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -4,16 +4,16 @@ export { BottomNavProvider, useBottomNavSpace } from "./barranav.js";
|
|
|
4
4
|
export { resolverTokens } from "./tokens.js";
|
|
5
5
|
export type { AureaDensity, AureaFontFamilies, AureaFontInput, AureaFontScale, AureaShadow, AureaThemeName, AureaTokens, } from "./tokens.js";
|
|
6
6
|
export { criarFolha, comOpacidade } from "./estilos.js";
|
|
7
|
-
export { Text } from "./text.js";
|
|
8
|
-
export type { TextProps, AureaTextFont, AureaTextLeading, AureaTextSize, AureaTextTone, AureaTextWeight, } from "./text.js";
|
|
7
|
+
export { Text, Heading, Paragraph, Code } from "./text.js";
|
|
8
|
+
export type { TextProps, AureaTextFont, AureaTextLeading, AureaTextSize, AureaTextTone, AureaTextWeight, AureaTextType, HeadingProps, ParagraphProps, CodeProps, AureaTypographyColor, AureaTypographyWeight, AureaTypographyAlign, } from "./text.js";
|
|
9
9
|
export { Icon, IconRegistryProvider, criarRegistroDeIcones, criarGlifo } from "./icon.js";
|
|
10
|
-
export type { IconProps, IconName, AureaIconComponent, AureaIconRegistry, AureaIconSize, AureaGlifoDesenho, AureaGlifoCaminho, AureaGlifoCirculo, AureaGlifoRetangulo, } from "./icon.js";
|
|
10
|
+
export type { IconProps, IconName, CarbonIconName, AureaIconNames, AureaIconComponent, AureaIconRegistry, AureaIconSize, AureaGlifoDesenho, AureaGlifoCaminho, AureaGlifoCirculo, AureaGlifoRetangulo, } from "./icon.js";
|
|
11
11
|
export { Screen } from "./screen.js";
|
|
12
12
|
export type { ScreenProps, AureaScreenBackground, AureaScreenEdge } from "./screen.js";
|
|
13
13
|
export { Stack, Cluster, Grid, Card, Separator } from "./layout.js";
|
|
14
|
-
export type { StackProps, ClusterProps, AureaClusterAlign, AureaClusterJustify, GridProps, CardProps, SeparatorProps, AureaCardVariant, } from "./layout.js";
|
|
15
|
-
export { Button, IconButton } from "./actions.js";
|
|
16
|
-
export type { ButtonProps, IconButtonProps, AureaButtonAppearance, AureaButtonSize, AureaButtonTone, } from "./actions.js";
|
|
14
|
+
export type { StackProps, ClusterProps, AureaStackAlign, AureaClusterAlign, AureaClusterJustify, GridProps, CardProps, SeparatorProps, AureaCardVariant, } from "./layout.js";
|
|
15
|
+
export { Button, IconButton, LinkButton, ThemeToggle } from "./actions.js";
|
|
16
|
+
export type { ButtonProps, IconButtonProps, LinkButtonProps, ThemeToggleProps, AureaButtonAppearance, AureaButtonSize, AureaButtonTone, } from "./actions.js";
|
|
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, } from "./feedback.js";
|
|
19
19
|
export { Badge, Status, Avatar, KPI, formatarContagem } from "./display.js";
|
|
@@ -42,3 +42,4 @@ export { NumberField, formatarNumero, lerNumero, separadoresDoLocale } from "./n
|
|
|
42
42
|
export type { NumberFieldProps, AureaSeparadores } from "./numero.js";
|
|
43
43
|
export { Image, Gallery } from "./midia.js";
|
|
44
44
|
export type { ImageProps, GalleryProps, AureaGalleryItem, AureaImageSource, } from "./midia.js";
|
|
45
|
+
export type { AureaFilaJustify } from "./rolagem.js";
|
package/dist/index.js
CHANGED
|
@@ -31,13 +31,13 @@ export { resolverTokens } from "./tokens.js";
|
|
|
31
31
|
// A fábrica de folhas memoizada por (tema, densidade). Pública porque o consumidor tem o mesmo
|
|
32
32
|
// problema que os componentes daqui — e a medição em aparelho mostrou que ele é real.
|
|
33
33
|
export { criarFolha, comOpacidade } from "./estilos.js";
|
|
34
|
-
export { Text } from "./text.js";
|
|
34
|
+
export { Text, Heading, Paragraph, Code } from "./text.js";
|
|
35
35
|
export { Icon, IconRegistryProvider, criarRegistroDeIcones, criarGlifo } from "./icon.js";
|
|
36
36
|
// A ÚNICA peça do Lote 1 com dependência de terceiro — `react-native-safe-area-context`,
|
|
37
37
|
// autorizada pelo Victor em 03/09/2026 depois de o lote parar por ela (`BUILDING.md` §3).
|
|
38
38
|
export { Screen } from "./screen.js";
|
|
39
39
|
export { Stack, Cluster, Grid, Card, Separator } from "./layout.js";
|
|
40
|
-
export { Button, IconButton } from "./actions.js";
|
|
40
|
+
export { Button, IconButton, LinkButton, ThemeToggle } from "./actions.js";
|
|
41
41
|
// ── Lote 2 — o painel, que é só leitura ────────────────────────────────────────────────────
|
|
42
42
|
export { Spinner, Skeleton, Progress, Alert, EmptyState, DataState, ICONE_DA_VARIANTE } from "./feedback.js";
|
|
43
43
|
export { Badge, Status, Avatar, KPI, formatarContagem } from "./display.js";
|
package/dist/inputs.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { TextInput, type KeyboardTypeOptions, type StyleProp, type TextInputProps, type TextStyle, type ViewProps, type ViewStyle } from "react-native";
|
|
3
|
+
import { type AureaFilaJustify } from "./rolagem.js";
|
|
3
4
|
import { type AureaIconRegistry, type IconName } from "./icon.js";
|
|
4
5
|
export type AureaFieldSize = "sm" | "md" | "lg";
|
|
5
6
|
type ContextoDeCampo = {
|
|
@@ -150,6 +151,12 @@ interface ControleProps {
|
|
|
150
151
|
size?: AureaFieldSize;
|
|
151
152
|
style?: StyleProp<ViewStyle>;
|
|
152
153
|
testID?: string;
|
|
154
|
+
/**
|
|
155
|
+
* Onde a marca fica na altura do texto — E5, 25/09/2026. `center` (o padrão) põe a marca no meio
|
|
156
|
+
* do bloco, como o HeroUI Native (`radio.css` e `control-field.css`: `align-items: center`).
|
|
157
|
+
* `start` a põe no meio da PRIMEIRA linha, para rótulo longo, de várias linhas.
|
|
158
|
+
*/
|
|
159
|
+
align?: "center" | "start";
|
|
153
160
|
/**
|
|
154
161
|
* O nome para quem usa leitor de tela, quando ele NÃO deve aparecer escrito no controle.
|
|
155
162
|
*
|
|
@@ -275,6 +282,8 @@ export interface SegmentedControlProps extends ViewProps {
|
|
|
275
282
|
/** Nome do grupo para o leitor de tela. */
|
|
276
283
|
label?: string;
|
|
277
284
|
disabled?: boolean;
|
|
285
|
+
/** Onde o controle fica quando cabe na linha: `start` (padrão), `center` ou `end` (E3). */
|
|
286
|
+
justify?: AureaFilaJustify;
|
|
278
287
|
}
|
|
279
288
|
/**
|
|
280
289
|
* Um de poucos, lado a lado.
|
|
@@ -284,7 +293,7 @@ export interface SegmentedControlProps extends ViewProps {
|
|
|
284
293
|
* há teclado aqui**, então o que resta é o que já se faz à mão: papel de grupo de rádio, um
|
|
285
294
|
* `radio` por segmento, e o estado `selected` em quem está escolhido.
|
|
286
295
|
*/
|
|
287
|
-
export declare function SegmentedControl({ items, value, onChange, label, disabled, style, ...rest }: SegmentedControlProps): React.JSX.Element;
|
|
296
|
+
export declare function SegmentedControl({ items, value, onChange, label, disabled, justify, style, ...rest }: SegmentedControlProps): React.JSX.Element;
|
|
288
297
|
export interface SelectProps {
|
|
289
298
|
items: Array<{
|
|
290
299
|
value: string;
|
package/dist/inputs.js
CHANGED
|
@@ -44,6 +44,7 @@ import { FilaRolante } from "./rolagem.js";
|
|
|
44
44
|
import { IconButton } from "./actions.js";
|
|
45
45
|
import { Icon } from "./icon.js";
|
|
46
46
|
import { useReduceMotion } from "./movimento.js";
|
|
47
|
+
import { RecuoDaFolha } from "./screen.js";
|
|
47
48
|
import { Text } from "./text.js";
|
|
48
49
|
import { useAureaStrings, useAureaTokens, usePeleSobreAMarca, ForaDaMarca } from "./theme.js";
|
|
49
50
|
const alturaDoTamanho = (t, s) => s === "sm" ? t.size.controlHSm : s === "lg" ? t.size.controlHLg : t.size.controlHMd;
|
|
@@ -79,11 +80,14 @@ const folha = criarFolha((t) => ({
|
|
|
79
80
|
campoNoGrupo: { flex: 1, minWidth: 0, paddingVertical: 0, textAlignVertical: "center" },
|
|
80
81
|
encaixe: { flexDirection: "row", alignItems: "center", flexShrink: 0, gap: t.size.space1 },
|
|
81
82
|
marcaBase: {
|
|
82
|
-
alignItems: "center", justifyContent: "center",
|
|
83
|
+
alignItems: "center", justifyContent: "center",
|
|
83
84
|
borderWidth: t.size.borderWidth, borderColor: t.color.borderStrong,
|
|
84
85
|
backgroundColor: t.color.fieldBg,
|
|
85
86
|
},
|
|
86
|
-
|
|
87
|
+
// E5: a marca no MEIO da altura do texto, como o HeroUI Native. Era `flex-start` com um
|
|
88
|
+
// `marginTop: 1` fixo, e a bolinha ficava presa no topo do rótulo.
|
|
89
|
+
linhaDeControle: { flexDirection: "row", alignItems: "center", gap: 9 },
|
|
90
|
+
linhaNoTopo: { alignItems: "flex-start" },
|
|
87
91
|
trilho: { borderRadius: t.size.radiusFull, backgroundColor: t.color.muted,
|
|
88
92
|
borderWidth: t.size.borderWidth, borderColor: t.color.border, justifyContent: "center" },
|
|
89
93
|
polegar: { position: "absolute", left: 3, borderRadius: t.size.radiusFull },
|
|
@@ -327,7 +331,7 @@ export function PasswordField({ defaultVisible = false, size, disabled, autoCapi
|
|
|
327
331
|
const inativo = disabled ?? campo?.disabled;
|
|
328
332
|
return (_jsxs(InputGroup, { size: tam, disabled: inativo, testID: testID, children: [leading ? _jsx(InputGroupAddon, { children: leading }) : null, _jsx(Input, { ...rest, size: tam, disabled: inativo, autoCapitalize: autoCapitalize, secureTextEntry: !visivel, style: style, testID: testID ? `${testID}-campo` : undefined }), _jsx(InputGroupAddon, { children: _jsx(IconButton, { name: visivel ? "view--off" : "view", label: visivel ? strings.passwordHide : strings.passwordShow, appearance: "ghost", size: tam === "lg" ? "md" : "sm", disabled: inativo, icons: icons, onPress: () => setVisivel(v => !v), testID: testID ? `${testID}-olho` : undefined }) })] }));
|
|
329
333
|
}
|
|
330
|
-
function ControleMarcado({ papel, label, description, checked, onChange, disabled, size, style, testID, accessibilityLabel, }) {
|
|
334
|
+
function ControleMarcado({ papel, label, description, checked, onChange, disabled, size, style, testID, accessibilityLabel, align = "center", }) {
|
|
331
335
|
const t = useAureaTokens();
|
|
332
336
|
const s = folha(t);
|
|
333
337
|
const campo = useCampo();
|
|
@@ -339,12 +343,16 @@ function ControleMarcado({ papel, label, description, checked, onChange, disable
|
|
|
339
343
|
// A marca é METADE da altura do controle — `aurea.css:871`, e é o que faz ela crescer junto
|
|
340
344
|
// com a densidade sem token próprio.
|
|
341
345
|
const lado = alturaDoTamanho(t, tam) / 2;
|
|
346
|
+
// `start`: o meio da marca no meio da PRIMEIRA linha do rótulo. A linha é a do `Text size="sm"`
|
|
347
|
+
// do rótulo (entrelinha normal), então a conta sai dos mesmos tokens que desenham o texto.
|
|
348
|
+
const linha = t.size.textBase * t.size.leadingNormal;
|
|
349
|
+
const noTopo = align === "start" ? { marginTop: Math.max(0, (linha - lado) / 2) } : null;
|
|
342
350
|
return (_jsxs(Pressable, { testID: testID, onPress: inativo ? undefined : () => onChange?.(!checked), disabled: inativo, accessibilityRole: papel, accessibilityState: { checked: !!checked, disabled: !!inativo },
|
|
343
351
|
// ⚠ O `accessibilityLabel` de fora vence o `label` escrito, e existe para o caso em que o
|
|
344
352
|
// nome JÁ está na tela ao lado — uma linha de `NavList`, por exemplo. Sem ele, ou o nome
|
|
345
353
|
// aparece escrito duas vezes, ou o controle sobe MUDO para quem usa leitor de tela.
|
|
346
|
-
accessibilityLabel: accessibilityLabel ?? (typeof label === "string" ? label : campo?.label), accessibilityHint: typeof description === "string" ? description : campo?.hint, style: [s.linhaDeControle, inativo && s.desabilitado, style], children: [_jsx(View, { style: [
|
|
347
|
-
s.marcaBase,
|
|
354
|
+
accessibilityLabel: accessibilityLabel ?? (typeof label === "string" ? label : campo?.label), accessibilityHint: typeof description === "string" ? description : campo?.hint, style: [s.linhaDeControle, align === "start" && s.linhaNoTopo, inativo && s.desabilitado, style], children: [_jsx(View, { style: [
|
|
355
|
+
s.marcaBase, noTopo,
|
|
348
356
|
{ width: lado, height: lado,
|
|
349
357
|
borderRadius: papel === "radio" ? t.size.radiusFull : 5 },
|
|
350
358
|
checked && { backgroundColor: t.color.controlSelected, borderColor: t.color.controlSelected },
|
|
@@ -452,12 +460,12 @@ export function Switch({ label, description, checked, onChange, disabled, size,
|
|
|
452
460
|
* há teclado aqui**, então o que resta é o que já se faz à mão: papel de grupo de rádio, um
|
|
453
461
|
* `radio` por segmento, e o estado `selected` em quem está escolhido.
|
|
454
462
|
*/
|
|
455
|
-
export function SegmentedControl({ items, value, onChange, label, disabled, style, ...rest }) {
|
|
463
|
+
export function SegmentedControl({ items, value, onChange, label, disabled, justify, style, ...rest }) {
|
|
456
464
|
const t = useAureaTokens();
|
|
457
465
|
const s = folha(t);
|
|
458
466
|
const campo = useCampo();
|
|
459
467
|
const inativo = disabled ?? campo?.disabled;
|
|
460
|
-
return (_jsx(FilaRolante, { children: _jsx(View, { accessibilityRole: "radiogroup", accessibilityLabel: label ?? campo?.label, style: [s.segmentada, inativo && s.desabilitado, style], ...rest, children: items.map((it) => {
|
|
468
|
+
return (_jsx(FilaRolante, { justify: justify, children: _jsx(View, { accessibilityRole: "radiogroup", accessibilityLabel: label ?? campo?.label, style: [s.segmentada, inativo && s.desabilitado, style], ...rest, children: items.map((it) => {
|
|
461
469
|
const ativo = it.value === value;
|
|
462
470
|
return (_jsxs(Pressable, { onPress: inativo ? undefined : () => onChange?.(it.value), disabled: inativo, accessibilityRole: "radio", accessibilityState: { checked: ativo, disabled: !!inativo }, accessibilityLabel: typeof it.label === "string" ? it.label : undefined, style: [s.segmento, ativo && s.segmentoAtivo], children: [typeof it.label === "string"
|
|
463
471
|
? _jsx(Text, { size: "sm", weight: ativo ? 600 : 400,
|
|
@@ -519,7 +527,7 @@ export function Select({ items, value, onChange, placeholder, disabled, size, ch
|
|
|
519
527
|
peleDaMarca,
|
|
520
528
|
inativo && s.desabilitado,
|
|
521
529
|
style,
|
|
522
|
-
], children: [_jsx(Text, { size: tam === "sm" ? "xs" : tam === "lg" ? "base" : "md", tone: escolhido ? "default" : "subtle", numberOfLines: 1, children: escolhido?.label ?? placeholder ?? "" }), chevron && _jsx(Icon, { name: chevron, size: "sm", color: peleDaMarca?.color ?? t.color.subtleForeground })] }), _jsx(ForaDaMarca, { children: _jsx(Modal, { visible: aberto, transparent: true, animationType: "slide", onRequestClose: () => setAberto(false), children: _jsxs(View, { style: s.fundoDaLista, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: () => setAberto(false), accessible: false }),
|
|
530
|
+
], children: [_jsx(Text, { size: tam === "sm" ? "xs" : tam === "lg" ? "base" : "md", tone: escolhido ? "default" : "subtle", numberOfLines: 1, children: escolhido?.label ?? placeholder ?? "" }), chevron && _jsx(Icon, { name: chevron, size: "sm", color: peleDaMarca?.color ?? t.color.subtleForeground })] }), _jsx(ForaDaMarca, { children: _jsx(Modal, { visible: aberto, transparent: true, animationType: "slide", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: () => setAberto(false), children: _jsxs(View, { style: s.fundoDaLista, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: () => setAberto(false), accessible: false }), _jsxs(View, { style: s.lista, children: [_jsx(ScrollView, { children: items.map((it) => (_jsx(Pressable, { disabled: it.disabled, onPress: () => { onChange?.(it.value); setAberto(false); }, accessibilityRole: "menuitem", accessibilityState: { selected: it.value === value, disabled: !!it.disabled }, style: [s.opcao, it.disabled && s.desabilitado], children: _jsx(Text, { size: "md", weight: it.value === value ? 600 : 400, children: it.label }) }, it.value))) }), _jsx(RecuoDaFolha, {})] })] }) }) })] }));
|
|
523
531
|
}
|
|
524
532
|
/**
|
|
525
533
|
* A pilha de campos, com o respiro do `--space-5`.
|
package/dist/layout.d.ts
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type ViewProps } from "react-native";
|
|
3
|
+
/** Eixo cruzado do `Stack` — os MESMOS valores do `Stack` da web (B-01). */
|
|
4
|
+
export type AureaStackAlign = "start" | "center" | "end" | "stretch";
|
|
3
5
|
export interface StackProps extends ViewProps {
|
|
4
6
|
children?: React.ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* Eixo cruzado (o horizontal). Padrão `stretch`: os filhos ocupam a largura, como sempre e como
|
|
9
|
+
* na web. E2, 25/09/2026: desde que o `Button` passou a obedecer o pai (como no HeroUI Native e
|
|
10
|
+
* na web), é aqui que se diz "botão do tamanho do texto" (`start`) ou "no meio" (`center`).
|
|
11
|
+
*/
|
|
12
|
+
align?: AureaStackAlign;
|
|
5
13
|
}
|
|
6
14
|
/** Coluna com `--space-4` entre os filhos. **Sem prop de espaçamento, de propósito.** */
|
|
7
|
-
export declare function Stack({ style, ...rest }: StackProps): React.JSX.Element;
|
|
15
|
+
export declare function Stack({ align, style, ...rest }: StackProps): React.JSX.Element;
|
|
8
16
|
export type AureaClusterAlign = "start" | "center" | "end" | "baseline";
|
|
9
17
|
export type AureaClusterJustify = "start" | "center" | "end" | "between";
|
|
10
|
-
export interface ClusterProps extends StackProps {
|
|
18
|
+
export interface ClusterProps extends Omit<StackProps, "align"> {
|
|
11
19
|
/** Eixo cruzado (o vertical). Padrão `center`, o `align-items:center` do `.cluster`. */
|
|
12
20
|
align?: AureaClusterAlign;
|
|
13
21
|
/** Eixo principal (o horizontal). Padrão `start`. `between` espalha o que sobrar entre os itens. */
|
|
@@ -41,15 +49,19 @@ export interface GridProps extends ViewProps {
|
|
|
41
49
|
* sozinho e ESTICA a última linha. **No React Native não existe CSS Grid**: o layout é flexbox e
|
|
42
50
|
* nada mais (medido no contrato do `react-native`; não há `display:grid`).
|
|
43
51
|
*
|
|
44
|
-
* O que se faz aqui é o mais próximo honesto: `flexWrap` com uma largura mínima por filho. A
|
|
45
|
-
* diferença visível é uma
|
|
46
|
-
*
|
|
47
|
-
*
|
|
52
|
+
* ~~O que se faz aqui é o mais próximo honesto: `flexWrap` com uma largura mínima por filho. A
|
|
53
|
+
* diferença visível é uma só (…) os itens da última linha não esticam para preencher a sobra.~~
|
|
54
|
+
* **E11 (0.12.1):** a diferença era maior do que a declarada — nenhuma linha repartia a sobra.
|
|
55
|
+
* Com `minColumnWidth={150}` numa linha de 372 ficavam duas colunas de 150 e 56 vazios (medido no
|
|
56
|
+
* Yoga). Agora a grade mede a própria largura (`onLayout`) e faz a conta do `auto-fill` da web:
|
|
57
|
+
* cabem `⌊(largura + vão) / (mínimo + vão)⌋` colunas, e a sobra se reparte entre elas. Na última
|
|
58
|
+
* linha a célula continua do tamanho de UMA coluna, como na web. Antes da medida (o primeiro
|
|
59
|
+
* quadro), vale a largura mínima de sempre.
|
|
48
60
|
*
|
|
49
61
|
* O `min(…, 100%)` da web tem par aqui: `maxWidth: "100%"` no filho, para a coluna não estourar o
|
|
50
62
|
* contêiner quando o texto cresce — a mesma lição que a Fase 11 registrou no CSS.
|
|
51
63
|
*/
|
|
52
|
-
export declare function Grid({ minColumnWidth, style, children, ...rest }: GridProps): React.JSX.Element;
|
|
64
|
+
export declare function Grid({ minColumnWidth, style, children, onLayout, ...rest }: GridProps): React.JSX.Element;
|
|
53
65
|
/** Qual superfície o cartão é. Mesmos seis nomes da ficha da web. */
|
|
54
66
|
export interface SeparatorProps extends ViewProps {
|
|
55
67
|
orientation?: "horizontal" | "vertical";
|
package/dist/layout.js
CHANGED
|
@@ -12,7 +12,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
12
12
|
// do `Stack` na web escreve o porquê — *"um primitivo de layout que aceita qualquer espaçamento é
|
|
13
13
|
// como um sistema deixa de ter espaçamento"*. Reabrir isso no nativo criaria dois sistemas.
|
|
14
14
|
import * as React from "react";
|
|
15
|
-
import { Pressable, View } from "react-native";
|
|
15
|
+
import { Pressable, StyleSheet, View } from "react-native";
|
|
16
16
|
// `ref` chega por PROPS, sem `forwardRef` — e' o padrao do React 19, e e' o que o
|
|
17
17
|
// `@aurea-uds/react` ja' faz (o `Stack` da web e' `HTMLAttributes & RefAttributes`, sem
|
|
18
18
|
// envelope). O `ViewProps`/`TextProps` do RN 0.87 ja' declaram `ref`, entao ele viaja no
|
|
@@ -59,10 +59,11 @@ const folha = criarFolha((t) => ({
|
|
|
59
59
|
// A ação fica embaixo, separada pelo mesmo respiro que o resto da casa usa entre blocos.
|
|
60
60
|
acaoDaMarca: { marginTop: t.size.space3 },
|
|
61
61
|
}));
|
|
62
|
+
const ALINHAR_COLUNA = { start: "flex-start", center: "center", end: "flex-end", stretch: "stretch" };
|
|
62
63
|
/** Coluna com `--space-4` entre os filhos. **Sem prop de espaçamento, de propósito.** */
|
|
63
|
-
export function Stack({ style, ...rest }) {
|
|
64
|
+
export function Stack({ align, style, ...rest }) {
|
|
64
65
|
const s = folha(useAureaTokens());
|
|
65
|
-
return _jsx(View, { style: [s.stack, style], ...rest });
|
|
66
|
+
return _jsx(View, { style: [s.stack, align != null && { alignItems: ALINHAR_COLUNA[align] }, style], ...rest });
|
|
66
67
|
}
|
|
67
68
|
const ALINHAR = { start: "flex-start", center: "center", end: "flex-end", baseline: "baseline" };
|
|
68
69
|
const JUSTIFICAR = { start: "flex-start", center: "center", end: "flex-end", between: "space-between" };
|
|
@@ -93,18 +94,44 @@ export function Cluster({ align, justify, wrap, style, ...rest }) {
|
|
|
93
94
|
* sozinho e ESTICA a última linha. **No React Native não existe CSS Grid**: o layout é flexbox e
|
|
94
95
|
* nada mais (medido no contrato do `react-native`; não há `display:grid`).
|
|
95
96
|
*
|
|
96
|
-
* O que se faz aqui é o mais próximo honesto: `flexWrap` com uma largura mínima por filho. A
|
|
97
|
-
* diferença visível é uma
|
|
98
|
-
*
|
|
99
|
-
*
|
|
97
|
+
* ~~O que se faz aqui é o mais próximo honesto: `flexWrap` com uma largura mínima por filho. A
|
|
98
|
+
* diferença visível é uma só (…) os itens da última linha não esticam para preencher a sobra.~~
|
|
99
|
+
* **E11 (0.12.1):** a diferença era maior do que a declarada — nenhuma linha repartia a sobra.
|
|
100
|
+
* Com `minColumnWidth={150}` numa linha de 372 ficavam duas colunas de 150 e 56 vazios (medido no
|
|
101
|
+
* Yoga). Agora a grade mede a própria largura (`onLayout`) e faz a conta do `auto-fill` da web:
|
|
102
|
+
* cabem `⌊(largura + vão) / (mínimo + vão)⌋` colunas, e a sobra se reparte entre elas. Na última
|
|
103
|
+
* linha a célula continua do tamanho de UMA coluna, como na web. Antes da medida (o primeiro
|
|
104
|
+
* quadro), vale a largura mínima de sempre.
|
|
100
105
|
*
|
|
101
106
|
* O `min(…, 100%)` da web tem par aqui: `maxWidth: "100%"` no filho, para a coluna não estourar o
|
|
102
107
|
* contêiner quando o texto cresce — a mesma lição que a Fase 11 registrou no CSS.
|
|
103
108
|
*/
|
|
104
|
-
export function Grid({ minColumnWidth = 240, style, children, ...rest }) {
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
|
|
109
|
+
export function Grid({ minColumnWidth = 240, style, children, onLayout, ...rest }) {
|
|
110
|
+
const t = useAureaTokens();
|
|
111
|
+
const s = folha(t);
|
|
112
|
+
const [largura, setLargura] = React.useState(null);
|
|
113
|
+
const plano = (StyleSheet.flatten([s.grid, style]) ?? {});
|
|
114
|
+
const vao = numero(plano.columnGap) ?? numero(plano.gap) ?? t.size.space4;
|
|
115
|
+
// A largura por dentro: o `onLayout` dá a de fora, e o recuo e a borda do `style` saem dela.
|
|
116
|
+
const recuo = (numero(plano.paddingLeft) ?? numero(plano.paddingHorizontal) ?? numero(plano.padding) ?? 0)
|
|
117
|
+
+ (numero(plano.paddingRight) ?? numero(plano.paddingHorizontal) ?? numero(plano.padding) ?? 0)
|
|
118
|
+
+ (numero(plano.borderLeftWidth) ?? numero(plano.borderWidth) ?? 0)
|
|
119
|
+
+ (numero(plano.borderRightWidth) ?? numero(plano.borderWidth) ?? 0);
|
|
120
|
+
const celula = React.useMemo(() => {
|
|
121
|
+
if (largura == null || largura <= 0) {
|
|
122
|
+
return { flexGrow: 0, flexShrink: 1, flexBasis: minColumnWidth, minWidth: minColumnWidth, maxWidth: "100%" };
|
|
123
|
+
}
|
|
124
|
+
// `repeat(auto-fill, minmax(min(mínimo, 100%), 1fr))` da web, em conta.
|
|
125
|
+
const colunas = Math.max(1, Math.floor((largura + vao) / (minColumnWidth + vao)));
|
|
126
|
+
const coluna = (largura - vao * (colunas - 1)) / colunas;
|
|
127
|
+
// ⚠ A base vai ARREDONDADA PARA BAIXO e o teto é o número exato: o motor arredonda cada
|
|
128
|
+
// largura ao pixel do aparelho, e duas colunas exatas podiam somar um fio a mais que a linha
|
|
129
|
+
// e cair uma para a linha de baixo. Com a base menor elas sempre cabem, e o `flexGrow` as
|
|
130
|
+
// leva até o teto — a linha cheia fecha certo, e a célula sozinha da última linha para no
|
|
131
|
+
// tamanho de uma coluna.
|
|
132
|
+
return { flexGrow: 1, flexShrink: 1, flexBasis: Math.floor(coluna), maxWidth: coluna, minWidth: 0 };
|
|
133
|
+
}, [largura, minColumnWidth, vao]);
|
|
134
|
+
return (_jsx(View, { style: [s.grid, style], ...rest, onLayout: (e) => { setLargura(e.nativeEvent.layout.width - recuo); onLayout?.(e); }, children: React.Children.map(children, (filho) => {
|
|
108
135
|
if (!React.isValidElement(filho))
|
|
109
136
|
return filho;
|
|
110
137
|
// 🔴 O `flexGrow: 1` É O ITEM C14, e ele existe porque a célula NÃO basta.
|
|
@@ -128,6 +155,8 @@ export function Grid({ minColumnWidth = 240, style, children, ...rest }) {
|
|
|
128
155
|
return _jsx(View, { style: celula, children: estica });
|
|
129
156
|
}) }));
|
|
130
157
|
}
|
|
158
|
+
/** O número de um estilo, ou nada — porcentagem e `"auto"` não entram na conta da grade. */
|
|
159
|
+
const numero = (v) => (typeof v === "number" ? v : undefined);
|
|
131
160
|
/**
|
|
132
161
|
* A linha de divisão do sistema. Mesma cor e mesma espessura do `.separator` da web.
|
|
133
162
|
*
|
package/dist/navigation.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type ViewProps } from "react-native";
|
|
3
3
|
import { type IconName } from "./icon.js";
|
|
4
|
+
import { type AureaFilaJustify } from "./rolagem.js";
|
|
4
5
|
export interface AureaNavItem {
|
|
5
6
|
id: string;
|
|
6
7
|
label: React.ReactNode;
|
|
@@ -197,6 +198,8 @@ export interface TabsProps extends ViewProps {
|
|
|
197
198
|
onChange?: (id: string) => void;
|
|
198
199
|
/** Nome da fila de abas para o leitor de tela. */
|
|
199
200
|
label?: string;
|
|
201
|
+
/** Onde a fila de abas fica quando cabe: `start` (padrão), `center` ou `end` (E3). */
|
|
202
|
+
justify?: AureaFilaJustify;
|
|
200
203
|
}
|
|
201
204
|
/**
|
|
202
205
|
* As abas DENTRO da tela — trocar o painel, não trocar de página.
|
|
@@ -231,4 +234,4 @@ export interface TabsProps extends ViewProps {
|
|
|
231
234
|
* largura de tela grande. Não há tablet medido neste projeto, e no nativo vale demanda antes de
|
|
232
235
|
* cobertura — a mesma decisão da `Table` do Lote 6.
|
|
233
236
|
*/
|
|
234
|
-
export declare function Tabs({ tabs, value, onChange, label, style, ...rest }: TabsProps): React.JSX.Element;
|
|
237
|
+
export declare function Tabs({ tabs, value, onChange, label, justify, style, ...rest }: TabsProps): React.JSX.Element;
|
package/dist/navigation.js
CHANGED
|
@@ -413,12 +413,12 @@ export function Stepper({ items, label, doneIcon = "checkmark", errorIcon = "err
|
|
|
413
413
|
* largura de tela grande. Não há tablet medido neste projeto, e no nativo vale demanda antes de
|
|
414
414
|
* cobertura — a mesma decisão da `Table` do Lote 6.
|
|
415
415
|
*/
|
|
416
|
-
export function Tabs({ tabs, value, onChange, label, style, ...rest }) {
|
|
416
|
+
export function Tabs({ tabs, value, onChange, label, justify, style, ...rest }) {
|
|
417
417
|
const t = useAureaTokens();
|
|
418
418
|
const s = folha(t);
|
|
419
419
|
const strings = useAureaStrings();
|
|
420
420
|
const aberta = tabs.find((it) => it.id === value);
|
|
421
|
-
return (_jsxs(View, { style: style, ...rest, children: [_jsx(FilaRolante, { children: _jsx(View, { accessibilityRole: "tablist", accessibilityLabel: label ?? strings.tabsLabel, style: s.abas, children: tabs.map((it) => {
|
|
421
|
+
return (_jsxs(View, { style: style, ...rest, children: [_jsx(FilaRolante, { justify: justify, children: _jsx(View, { accessibilityRole: "tablist", accessibilityLabel: label ?? strings.tabsLabel, style: s.abas, children: tabs.map((it) => {
|
|
422
422
|
const ativa = it.id === value;
|
|
423
423
|
return (_jsx(Pressable, { onPress: it.disabled ? undefined : () => onChange?.(it.id), disabled: it.disabled, accessibilityRole: "tab", accessibilityState: { selected: ativa, disabled: !!it.disabled }, accessibilityLabel: typeof it.label === "string" ? it.label : undefined, style: [s.abaDeTab, ativa && s.abaDeTabAtiva, it.disabled && { opacity: t.size.opacityDisabled }], children: typeof it.label === "string"
|
|
424
424
|
? _jsx(Text, { size: "sm", weight: ativa ? 600 : 400, style: { color: ativa ? t.color.foreground : t.color.mutedForeground }, children: it.label })
|
package/dist/numero.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type StyleProp, type ViewStyle } from "react-native";
|
|
3
|
+
import type { IconName } from "./icon-names.js";
|
|
3
4
|
import { type AureaFieldSize } from "./inputs.js";
|
|
4
5
|
/** Os separadores de um locale, derivados de um número-sonda. */
|
|
5
6
|
export type AureaSeparadores = {
|
|
@@ -71,13 +72,12 @@ export interface NumberFieldProps {
|
|
|
71
72
|
keyboardType?: "numeric" | "decimal-pad" | "number-pad" | "numbers-and-punctuation";
|
|
72
73
|
/** Os glifos dos botões. Registre-os, ou passe `false` para tirar os dois. */
|
|
73
74
|
icons?: {
|
|
74
|
-
increment:
|
|
75
|
-
decrement:
|
|
75
|
+
increment: IconName;
|
|
76
|
+
decrement: IconName;
|
|
76
77
|
} | false;
|
|
77
78
|
style?: StyleProp<ViewStyle>;
|
|
78
79
|
testID?: string;
|
|
79
80
|
}
|
|
80
|
-
type IconNameLocal = string;
|
|
81
81
|
/**
|
|
82
82
|
* O número que se digita OU se empurra de um em um.
|
|
83
83
|
*
|
|
@@ -116,4 +116,3 @@ type IconNameLocal = string;
|
|
|
116
116
|
* partir de outros dois funcionar.
|
|
117
117
|
*/
|
|
118
118
|
export declare function NumberField({ value, defaultValue, onValueChange, min, max, step, format, locale, disabled, readOnly, size, fullWidth, label, placeholder, keyboardType, icons, style, testID, }: NumberFieldProps): React.JSX.Element;
|
|
119
|
-
export {};
|
package/dist/overlays.js
CHANGED
|
@@ -60,6 +60,7 @@ import { Animated, Easing, Modal, PanResponder, Pressable, ScrollView, View, } f
|
|
|
60
60
|
import { Button } from "./actions.js";
|
|
61
61
|
import { criarFolha } from "./estilos.js";
|
|
62
62
|
import { IconButton } from "./actions.js";
|
|
63
|
+
import { RecuoDaFolha } from "./screen.js";
|
|
63
64
|
import { Text } from "./text.js";
|
|
64
65
|
import { useAureaStrings, useAureaTokens, ForaDaMarca } from "./theme.js";
|
|
65
66
|
import { useReduceMotion } from "./movimento.js";
|
|
@@ -133,8 +134,14 @@ const DURACAO = 280;
|
|
|
133
134
|
// afirmação mais forte que "passou no teste", mas não é o vidro. Foi exatamente confiar em
|
|
134
135
|
// "passou no teste" que produziu a primeira tentativa.
|
|
135
136
|
//
|
|
136
|
-
// O `naoAtravessa` FICA no painel como segunda linha: agora é redundante, e redundância que
|
|
137
|
-
// não custa nada num caminho que já falhou uma vez se paga
|
|
137
|
+
// ~~O `naoAtravessa` FICA no painel como segunda linha: agora é redundante, e redundância que
|
|
138
|
+
// não custa nada num caminho que já falhou uma vez se paga.~~ — **E4, 25/09/2026: ela CUSTAVA.**
|
|
139
|
+
// No Android, um `View` que vira dono do toque pelo JavaScript passa a interceptar os movimentos
|
|
140
|
+
// seguintes (`JSResponderHandler.onInterceptTouchEvent`), e o `ScrollView` de dentro deixa de
|
|
141
|
+
// rolar. O app viu a lista do `Select` e a do `Combobox` sem rolar; a suspeita não está confirmada
|
|
142
|
+
// no aparelho, mas a linha era redundante por construção e saiu dos painéis que têm rolagem dentro
|
|
143
|
+
// (`Dialog`, `Drawer`, `Select`, `Combobox`). Fica no `ConfirmDialog` (sem fundo tocável e sem
|
|
144
|
+
// rolagem) e no `BottomSheet`, onde os `panHandlers` do arrasto já a sobrescrevem.
|
|
138
145
|
//
|
|
139
146
|
// ⚠ Vale para os QUATRO que têm esta forma: `Dialog`, `Drawer`, `BottomSheet` e o `Select` do
|
|
140
147
|
// Lote 4 (`inputs.tsx`). O `ConfirmDialog` é imune desde que nasceu — o fundo dele não tem
|
|
@@ -157,7 +164,7 @@ export function Dialog({ open, title, children, footer, onClose, scroll = true,
|
|
|
157
164
|
const s = folha(t);
|
|
158
165
|
const strings = useAureaStrings();
|
|
159
166
|
const Corpo = scroll ? ScrollView : View;
|
|
160
|
-
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: "fade", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: [s.fundo, s.centro], children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(View, {
|
|
167
|
+
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: "fade", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: [s.fundo, s.centro], children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(View, { style: [s.superficie, style], children: [_jsxs(View, { style: s.cabecalho, children: [_jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }), _jsx(IconButton, { name: "close", label: strings.close, appearance: "ghost", size: "sm", onPress: onClose })] }), _jsx(Corpo, { ...(scroll ? { contentContainerStyle: s.corpo } : { style: s.corpo }), children: children }), footer ? _jsx(View, { style: s.rodape, children: footer }) : null] })] }) }) }));
|
|
161
168
|
}
|
|
162
169
|
/**
|
|
163
170
|
* A decisão que não se desfaz.
|
|
@@ -229,7 +236,7 @@ export function Drawer({ open, title, children, onClose, side = "right", scroll
|
|
|
229
236
|
inputRange: [0, 1],
|
|
230
237
|
outputRange: [side === "right" ? 480 : -480, 0],
|
|
231
238
|
});
|
|
232
|
-
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: "none", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: s.fundo, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, {
|
|
239
|
+
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: "none", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: s.fundo, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, { style: [
|
|
233
240
|
s.gaveta, side === "right" ? s.gavetaDireita : s.gavetaEsquerda,
|
|
234
241
|
{ transform: [{ translateX: desloca }] }, style,
|
|
235
242
|
], children: [_jsxs(View, { style: s.cabecalho, children: [_jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }), _jsx(IconButton, { name: "close", label: strings.close, appearance: "ghost", size: "sm", onPress: onClose })] }), _jsx(Corpo, { ...(scroll ? { contentContainerStyle: s.corpo } : { style: s.corpo }), children: children })] })] }) }) }));
|
|
@@ -287,5 +294,5 @@ export function BottomSheet({ open, title, children, onClose, grabber = true, dr
|
|
|
287
294
|
}).start();
|
|
288
295
|
},
|
|
289
296
|
}), [draggable, onClose, arrasto, reduzir, t.easing.easeEmphasized]);
|
|
290
|
-
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: reduzir !== false ? "none" : "slide", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: s.fundo, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, { ...naoAtravessa, ...gestos.panHandlers, onLayout: (e) => { altura.current = e.nativeEvent.layout.height; }, style: [s.folhaBaixo, { transform: [{ translateY: arrasto }] }, style], children: [grabber ? (_jsx(View, { style: s.puxadorArea, accessible: false, importantForAccessibility: "no-hide-descendants", children: _jsx(View, { style: s.puxador }) })) : null, title ? (_jsx(View, { style: s.cabecalho, children: _jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }) })) : null, _jsx(Corpo, { ...(scroll ? { contentContainerStyle: s.corpo } : { style: s.corpo }), children: children })] })] }) }) }));
|
|
297
|
+
return (_jsx(ForaDaMarca, { children: _jsx(Modal, { visible: open, transparent: true, animationType: reduzir !== false ? "none" : "slide", statusBarTranslucent: true, navigationBarTranslucent: true, onRequestClose: onClose, testID: testID, children: _jsxs(View, { style: s.fundo, children: [_jsx(Pressable, { style: s.fundoDeToque, onPress: onClose, accessible: false, testID: testID ? `${testID}-fundo` : undefined }), _jsxs(Animated.View, { ...naoAtravessa, ...gestos.panHandlers, onLayout: (e) => { altura.current = e.nativeEvent.layout.height; }, style: [s.folhaBaixo, { transform: [{ translateY: arrasto }] }, style], children: [grabber ? (_jsx(View, { style: s.puxadorArea, accessible: false, importantForAccessibility: "no-hide-descendants", children: _jsx(View, { style: s.puxador }) })) : null, title ? (_jsx(View, { style: s.cabecalho, children: _jsx(Text, { size: "lg", weight: 600, accessibilityRole: "header", style: s.titulo, children: title }) })) : null, _jsx(Corpo, { ...(scroll ? { contentContainerStyle: s.corpo } : { style: s.corpo }), children: children }), _jsx(RecuoDaFolha, {})] })] }) }) }));
|
|
291
298
|
}
|
package/dist/rolagem.d.ts
CHANGED
|
@@ -6,11 +6,18 @@ export interface FilaRolanteProps {
|
|
|
6
6
|
/** Estilo do invólucro externo, não do conteúdo. */
|
|
7
7
|
style?: StyleProp<ViewStyle>;
|
|
8
8
|
testID?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Onde a fila fica quando CABE — E3, 25/09/2026. `start` (o padrão, o de sempre), `center` ou
|
|
11
|
+
* `end`. Quando não cabe, ela rola, e o alinhamento deixa de existir: começa no início.
|
|
12
|
+
*/
|
|
13
|
+
justify?: AureaFilaJustify;
|
|
9
14
|
}
|
|
15
|
+
/** Onde a fila fica, na linha, quando cabe. O nome é o do `Cluster` (R-09): o eixo da fileira. */
|
|
16
|
+
export type AureaFilaJustify = "start" | "center" | "end";
|
|
10
17
|
/**
|
|
11
18
|
* Uma linha que rola para o lado quando não cabe, e que sabe QUANDO não cabe.
|
|
12
19
|
*
|
|
13
20
|
* O componente fica com a informação em vez de adivinhar: `onLayout` dá a largura visível e
|
|
14
21
|
* `onContentSizeChange` dá a do conteúdo. Com as duas, `transbordou` é uma conta, não um palpite.
|
|
15
22
|
*/
|
|
16
|
-
export declare function FilaRolante({ children, style, testID }: FilaRolanteProps): React.JSX.Element;
|
|
23
|
+
export declare function FilaRolante({ children, style, testID, justify }: FilaRolanteProps): React.JSX.Element;
|
package/dist/rolagem.js
CHANGED
|
@@ -25,13 +25,14 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
25
25
|
// iOS.** O que está provado aqui é a medição, não a leitura.
|
|
26
26
|
import * as React from "react";
|
|
27
27
|
import { ScrollView } from "react-native";
|
|
28
|
+
const JUSTIFICAR = { center: "center", end: "flex-end" };
|
|
28
29
|
/**
|
|
29
30
|
* Uma linha que rola para o lado quando não cabe, e que sabe QUANDO não cabe.
|
|
30
31
|
*
|
|
31
32
|
* O componente fica com a informação em vez de adivinhar: `onLayout` dá a largura visível e
|
|
32
33
|
* `onContentSizeChange` dá a do conteúdo. Com as duas, `transbordou` é uma conta, não um palpite.
|
|
33
34
|
*/
|
|
34
|
-
export function FilaRolante({ children, style, testID }) {
|
|
35
|
+
export function FilaRolante({ children, style, testID, justify = "start" }) {
|
|
35
36
|
const [visivel, setVisivel] = React.useState(0);
|
|
36
37
|
const [conteudo, setConteudo] = React.useState(0);
|
|
37
38
|
const transbordou = conteudo > visivel && visivel > 0;
|
|
@@ -41,5 +42,9 @@ export function FilaRolante({ children, style, testID }) {
|
|
|
41
42
|
showsHorizontalScrollIndicator: transbordou,
|
|
42
43
|
// Sem isto o conteúdo estica até a largura do rolador, e o respiro da cápsula aparece como
|
|
43
44
|
// faixa vazia à direita quando os itens cabem.
|
|
44
|
-
|
|
45
|
+
// E3: centralizar ou ir para o fim exige o contrário — o recipiente do conteúdo cresce até a
|
|
46
|
+
// largura do rolador (`flexGrow: 1`) e POSICIONA a cápsula lá dentro. Ela não estica: na
|
|
47
|
+
// fileira, o filho tem a largura dele. Medido pelo app: rolador 335 de largura, fileira 281,
|
|
48
|
+
// encostada à esquerda, e um `Cluster justify="center"` em volta não mudava nada.
|
|
49
|
+
contentContainerStyle: justify === "start" ? { flexGrow: 0 } : { flexGrow: 1, justifyContent: JUSTIFICAR[justify] }, style: style, children: children }));
|
|
45
50
|
}
|
package/dist/screen.d.ts
CHANGED
|
@@ -66,3 +66,13 @@ export interface ScreenProps extends ViewProps {
|
|
|
66
66
|
* nenhum). Quem exige o provider são os HOOKS — e quem usa `react-navigation` já o tem.
|
|
67
67
|
*/
|
|
68
68
|
export declare function Screen({ edges, padded, scroll, background, onRefresh, refreshing, footer, style, children, ...rest }: ScreenProps): React.JSX.Element;
|
|
69
|
+
/** O recuo de baixo do sistema (barra de botões ou de gestos), em dp. */
|
|
70
|
+
export declare function useRecuoDoSistema(): number;
|
|
71
|
+
/**
|
|
72
|
+
* O espaço do recuo do sistema no fim de uma folha de baixo. Uso interno.
|
|
73
|
+
* `comTeclado`: com o teclado aberto a folha sobe acima dele e deixa de ficar atrás da barra do
|
|
74
|
+
* sistema, e o espaço vai a zero — senão sobraria uma faixa vazia entre a lista e o teclado.
|
|
75
|
+
*/
|
|
76
|
+
export declare function RecuoDaFolha({ comTeclado }: {
|
|
77
|
+
comTeclado?: boolean;
|
|
78
|
+
}): React.JSX.Element;
|
package/dist/screen.js
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
// Aurea nativo — `Screen`, a casca de uma tela.
|
|
3
|
+
//
|
|
4
|
+
// **NÃO TEM PAR NA WEB, e a razão é a plataforma.** Lá o `<body>` já é a tela: o navegador
|
|
5
|
+
// desenha a barra de status, o browser resolve o entalhe, e a única regra da Aurea é
|
|
6
|
+
// `body { background: var(--background) }` (medido no `packages/core/src/aurea.css`). No React
|
|
7
|
+
// Native não há `<body>`: a raiz de cada tela é um `View` que alguém precisa mandar preencher,
|
|
8
|
+
// pintar e afastar do entalhe.
|
|
9
|
+
//
|
|
10
|
+
// ── A DEPENDÊNCIA, E POR QUE ELA EXISTE ──────────────────────────────────────────────────────
|
|
11
|
+
// Este é o único componente do Lote 1 que precisou de dependência nova, e por isso ele parou o
|
|
12
|
+
// lote e voltou para o Victor (`BUILDING.md` §3). Ele autorizou o peer em 03/09/2026.
|
|
13
|
+
//
|
|
14
|
+
// O que foi medido antes de pedir:
|
|
15
|
+
// • o `SafeAreaView` do PRÓPRIO React Native está **deprecado** desde a 0.81 — e nunca fez nada
|
|
16
|
+
// no Android, onde ele é literalmente um `View`;
|
|
17
|
+
// • o substituto de fato é `react-native-safe-area-context` (**MIT**), que é o que o
|
|
18
|
+
// `react-navigation` e o `expo-router` já arrastam. Adotá-lo como peer não adiciona peso ao
|
|
19
|
+
// app: declara o que já ia estar lá;
|
|
20
|
+
// • ele é **módulo nativo** (`android/`, `ios/`, `common/cpp/` no tarball) — vem embutido no
|
|
21
|
+
// Expo Go, então o caminho de smoke test continua valendo.
|
|
22
|
+
//
|
|
23
|
+
// ── POR QUE `SafeAreaView` E NÃO `useSafeAreaInsets` ─────────────────────────────────────────
|
|
24
|
+
// A biblioteca oferece os dois. O hook devolve números e deixa você somar; o componente resolve
|
|
25
|
+
// no lado NATIVO. Escolhi o componente, e a razão saiu da leitura do fonte C++
|
|
26
|
+
// (`RNCSafeAreaViewShadowNode.cpp`, versão 5.9.1), não de preferência:
|
|
27
|
+
//
|
|
28
|
+
// getEdgeValue: "off" -> só o seu padding
|
|
29
|
+
// "maximum" -> max(inset, padding)
|
|
30
|
+
// qualquer outro (o padrão é "additive") -> inset + padding
|
|
31
|
+
//
|
|
32
|
+
// Ou seja: o inset **SOMA** ao padding que a folha da Aurea já pôs, no cálculo de layout do Yoga,
|
|
33
|
+
// antes do primeiro frame. Com o hook, o padding sairia de um `useState` que só tem valor DEPOIS
|
|
34
|
+
// que o nativo avisa — um quadro com o conteúdo embaixo do entalhe, e um re-render a cada
|
|
35
|
+
// rotação. O componente não tem esse quadro.
|
|
36
|
+
//
|
|
37
|
+
// ⚠ Um limite que o mesmo fonte declara e que herdamos: **padding em porcentagem não é
|
|
38
|
+
// suportado** na soma. Os tokens da Aurea são todos numéricos (dp), então isto não morde aqui —
|
|
39
|
+
// mas morde quem passar `padding: "5%"` no `style`.
|
|
40
|
+
import * as React from "react";
|
|
41
|
+
import { Keyboard, RefreshControl, ScrollView, View } from "react-native";
|
|
42
|
+
import { SafeAreaInsetsContext, SafeAreaView, initialWindowMetrics } from "react-native-safe-area-context";
|
|
4
43
|
import { useBottomNavSpace } from "./barranav.js";
|
|
5
44
|
import { criarFolha } from "./estilos.js";
|
|
6
45
|
import { useAureaTokens } from "./theme.js";
|
|
@@ -95,3 +134,46 @@ function Rodape({ dentroDoRespiro, pegaABorda, respiroDaBarra, children }) {
|
|
|
95
134
|
return _jsx(View, { style: recuo, children: children });
|
|
96
135
|
return _jsx(SafeAreaView, { edges: ["bottom"], style: recuo, children: children });
|
|
97
136
|
}
|
|
137
|
+
// ── E10 · O RECUO DAS FOLHAS DE BAIXO (`Select`, `Combobox`, `BottomSheet`) ──────────────────
|
|
138
|
+
// 🔴 DENTRO DE UM `Modal`, O `SafeAreaView` NÃO SERVE, e a razão foi lida no fonte da biblioteca
|
|
139
|
+
// (`SafeAreaView.kt` e `SafeAreaUtils.kt`, versão 5.9.1), não presumida:
|
|
140
|
+
//
|
|
141
|
+
// findProvider(): sobe pelos pais atrás de um `SafeAreaProvider`; sem achar, usa A SI MESMO.
|
|
142
|
+
// getSafeAreaInsets(view): if (view.height == 0) return null // "ainda sem layout"
|
|
143
|
+
//
|
|
144
|
+
// O `Modal` é outra janela do Android: o `SafeAreaProvider` do app não é pai de nada lá dentro.
|
|
145
|
+
// Então a peça mede a si mesma — e a da 0.11.0 era VAZIA, de altura 0, esperando o recuo para
|
|
146
|
+
// ganhar altura. Nunca ganhava: o recuo ficava em zero e o último item, atrás dos botões do
|
|
147
|
+
// sistema (achado E10 do app).
|
|
148
|
+
//
|
|
149
|
+
// A saída é a do HeroUI Native (`select.tsx`, `useSafeAreaInsets`): o número vem do CONTEXTO
|
|
150
|
+
// do React, que atravessa o `Modal`, e vira um espaço de altura conhecida no fim da folha. Sem
|
|
151
|
+
// `SafeAreaProvider` no app, vale a medida da abertura (`initialWindowMetrics`), que a
|
|
152
|
+
// biblioteca calcula sem provider — e o componente não quebra quem não tem provider.
|
|
153
|
+
// ⚠ As três folhas cobrem a tela toda (`navigationBarTranslucent`): é o que faz o recuo do
|
|
154
|
+
// contexto, que é o da janela do app, ser exatamente o que a folha fica atrás da barra.
|
|
155
|
+
/** O recuo de baixo do sistema (barra de botões ou de gestos), em dp. */
|
|
156
|
+
export function useRecuoDoSistema() {
|
|
157
|
+
const doContexto = React.useContext(SafeAreaInsetsContext);
|
|
158
|
+
return (doContexto ?? initialWindowMetrics?.insets)?.bottom ?? 0;
|
|
159
|
+
}
|
|
160
|
+
/** O teclado está aberto? Pelos avisos do próprio React Native. */
|
|
161
|
+
function useTecladoAberto() {
|
|
162
|
+
const [aberto, setAberto] = React.useState(false);
|
|
163
|
+
React.useEffect(() => {
|
|
164
|
+
const mostra = Keyboard.addListener("keyboardDidShow", () => setAberto(true));
|
|
165
|
+
const esconde = Keyboard.addListener("keyboardDidHide", () => setAberto(false));
|
|
166
|
+
return () => { mostra.remove(); esconde.remove(); };
|
|
167
|
+
}, []);
|
|
168
|
+
return aberto;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* O espaço do recuo do sistema no fim de uma folha de baixo. Uso interno.
|
|
172
|
+
* `comTeclado`: com o teclado aberto a folha sobe acima dele e deixa de ficar atrás da barra do
|
|
173
|
+
* sistema, e o espaço vai a zero — senão sobraria uma faixa vazia entre a lista e o teclado.
|
|
174
|
+
*/
|
|
175
|
+
export function RecuoDaFolha({ comTeclado = false }) {
|
|
176
|
+
const recuo = useRecuoDoSistema();
|
|
177
|
+
const teclado = useTecladoAberto();
|
|
178
|
+
return _jsx(View, { style: { height: comTeclado && teclado ? 0 : recuo } });
|
|
179
|
+
}
|
package/dist/strings.d.ts
CHANGED
|
@@ -62,6 +62,9 @@ export interface AureaStrings {
|
|
|
62
62
|
comboboxEmpty: string;
|
|
63
63
|
/** O botão que desfaz a escolha do `Combobox`. Mesmo nome da web. */
|
|
64
64
|
comboboxClear: string;
|
|
65
|
+
/** O nome do `ThemeToggle` quando ele leva ao tema escuro, e ao claro. Mesmos nomes da web. */
|
|
66
|
+
themeToDark: string;
|
|
67
|
+
themeToLight: string;
|
|
65
68
|
/** O que o `Combobox` anuncia enquanto a busca remota não voltou. Mesmo nome da web. */
|
|
66
69
|
comboboxLoading: string;
|
|
67
70
|
/**
|