@aurea-uds/react 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions.d.ts +17 -9
- package/dist/actions.js +30 -9
- package/dist/calendar.js +1 -1
- package/dist/code-editor.js +7 -7
- package/dist/feedback-client.d.ts +3 -1
- package/dist/feedback-client.js +4 -2
- package/dist/identity-client.d.ts +6 -1
- package/dist/identity-client.js +2 -5
- package/dist/index.d.ts +1 -1
- package/dist/inputs-client.d.ts +31 -2
- package/dist/inputs-client.js +40 -9
- package/dist/internal.d.ts +6 -4
- package/dist/internal.js +2 -1
- package/dist/markup.d.ts +46 -6
- package/dist/markup.js +42 -9
- package/dist/navigation-client.d.ts +7 -3
- package/dist/navigation-client.js +26 -14
- package/dist/overlays.js +7 -7
- package/dist/pure.d.ts +7 -0
- package/dist/pure.js +2 -2
- package/dist/system.d.ts +8 -5
- package/dist/system.js +36 -5
- package/package.json +1 -1
package/dist/actions.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { type ButtonHTMLAttributes, type HTMLAttributes, type ReactElement, type RefAttributes } from "react";
|
|
2
2
|
import { type Orientation, type Responsive } from "./pure.js";
|
|
3
|
-
import { type IconName } from "./system.js";
|
|
4
|
-
export type ButtonVariant = "primary" | "secondary" | "tertiary" | "outline" | "ghost" | "primary-outline" | "primary-ghost" | "danger" | "danger-outline" | "danger-ghost" | "link" | "link-primary" | "link-danger" | "nav";
|
|
5
|
-
export type ButtonAppearance = "solid" | "outline" | "ghost" | "link" | "nav";
|
|
3
|
+
import { type IconName, type AureaIcon } from "./system.js";
|
|
4
|
+
export type ButtonVariant = "primary" | "secondary" | "tertiary" | "outline" | "ghost" | "primary-outline" | "primary-ghost" | "danger" | "danger-outline" | "danger-ghost" | "link" | "link-primary" | "link-danger" | "nav" | "danger-soft";
|
|
5
|
+
export type ButtonAppearance = "solid" | "outline" | "ghost" | "link" | "nav" | "soft";
|
|
6
6
|
export type ButtonTone = "neutral" | "brand" | "danger" | "success" | "warning" | "info";
|
|
7
7
|
export type ComponentSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
8
8
|
/** Resolve os dois eixos (ou o atalho) na classe que o core pinta. Exportada porque o teste
|
|
@@ -20,10 +20,13 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, Re
|
|
|
20
20
|
tone?: ButtonTone;
|
|
21
21
|
size?: Responsive<ComponentSize>;
|
|
22
22
|
loading?: boolean;
|
|
23
|
-
leadingIcon?:
|
|
24
|
-
trailingIcon?:
|
|
23
|
+
leadingIcon?: AureaIcon;
|
|
24
|
+
trailingIcon?: AureaIcon;
|
|
25
25
|
href?: string;
|
|
26
26
|
fullWidth?: boolean;
|
|
27
|
+
/** Menos peso (15/10/2026): a letra apagada e um degrau menor (12 no `sm`) — o botão de ferramenta de um topo de
|
|
28
|
+
* site, como o "Theme" da referência. A caixa e o fundo são os da aparência escolhida. */
|
|
29
|
+
quiet?: boolean;
|
|
27
30
|
/** C-03 (24/09/2026): numa fila (`Cluster`), divide o espaço em partes iguais com os outros botões
|
|
28
31
|
* que também têm `grow`. O `fullWidth` não serve ali: ele pede a linha inteira. */
|
|
29
32
|
grow?: boolean;
|
|
@@ -50,7 +53,9 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, Re
|
|
|
50
53
|
* quebrar, e por isso este é o momento mais barato que vai existir.
|
|
51
54
|
*/
|
|
52
55
|
pressed?: boolean;
|
|
53
|
-
|
|
56
|
+
/** O atalho, à mostra e anunciado. Texto: uma caixinha só ("⌘K"). LISTA (15/10/2026): uma caixinha por tecla, como
|
|
57
|
+
* a busca da referência (`["Ctrl", "K"]`), e o leitor de tela recebe a combinação (`Control+K`). */
|
|
58
|
+
kbd?: string | readonly string[];
|
|
54
59
|
/**
|
|
55
60
|
* GAR-14 (0.28.0): o botão COMPARTILHA. Ele pergunta ao navegador se sabe compartilhar este link
|
|
56
61
|
* (`navigator.canShare`) — detectar o recurso, e não adivinhar o aparelho, é o padrão da web. Sabe
|
|
@@ -96,15 +101,18 @@ export type ToggleProps = ToggleBase & ({
|
|
|
96
101
|
export declare function Toggle({ pressed, defaultPressed, onPressedChange, value, icon, label, size: sizePedido, disabled, id, className, children, variant }: ToggleProps): React.JSX.Element;
|
|
97
102
|
export interface IconButtonProps extends Omit<ButtonProps, "children"> {
|
|
98
103
|
label: string;
|
|
99
|
-
icon:
|
|
104
|
+
icon: AureaIcon;
|
|
100
105
|
}
|
|
101
106
|
export declare const IconButton: React.ForwardRefExoticComponent<Omit<IconButtonProps, "ref"> & RefAttributes<HTMLButtonElement>>;
|
|
102
|
-
export interface CloseButtonProps extends Omit<ButtonProps, "variant" | "appearance" | "tone" | "size" | "loading" | "leadingIcon" | "trailingIcon" | "href" | "target" | "rel" | "download" | "render" | "kbd" | "fullWidth" | "grow" | "pressed" | "share"> {
|
|
107
|
+
export interface CloseButtonProps extends Omit<ButtonProps, "quiet" | "variant" | "appearance" | "tone" | "size" | "loading" | "leadingIcon" | "trailingIcon" | "href" | "target" | "rel" | "download" | "render" | "kbd" | "fullWidth" | "grow" | "pressed" | "share"> {
|
|
103
108
|
/** O nome que o leitor de tela anuncia. Padrão: a frase `close` ("Close"/"Fechar"). */
|
|
104
109
|
label?: string;
|
|
105
110
|
}
|
|
106
111
|
export declare const CloseButton: React.ForwardRefExoticComponent<Omit<CloseButtonProps, "ref"> & RefAttributes<HTMLButtonElement>>;
|
|
107
|
-
export interface ThemeToggleProps extends Omit<IconButtonProps, "icon" | "label" | "onClick" | "variant" | "appearance" | "tone" | "href" | "target" | "rel" | "download" | "render" | "kbd" | "loading" | "leadingIcon" | "trailingIcon" | "fullWidth" | "share"> {
|
|
112
|
+
export interface ThemeToggleProps extends Omit<IconButtonProps, "quiet" | "icon" | "label" | "onClick" | "variant" | "appearance" | "tone" | "href" | "target" | "rel" | "download" | "render" | "kbd" | "loading" | "leadingIcon" | "trailingIcon" | "fullWidth" | "share"> {
|
|
113
|
+
/** `"light-dark"` (o padrão): o botão que alterna. `"light-dark-system"` (15/10/2026): a chave de três posições do
|
|
114
|
+
* topo da referência — claro, escuro e sistema (seguir o do computador, e mudar junto). */
|
|
115
|
+
mode?: "light-dark" | "light-dark-system";
|
|
108
116
|
}
|
|
109
117
|
export declare const ThemeToggle: React.ForwardRefExoticComponent<Omit<ThemeToggleProps, "ref"> & RefAttributes<HTMLButtonElement>>;
|
|
110
118
|
export interface ButtonGroupProps extends HTMLAttributes<HTMLDivElement>, RefAttributes<HTMLDivElement> {
|
package/dist/actions.js
CHANGED
|
@@ -24,13 +24,16 @@ const EIXOS = {
|
|
|
24
24
|
"primary-outline": ["outline", "brand"], "primary-ghost": ["ghost", "brand"],
|
|
25
25
|
danger: ["solid", "danger"], "danger-outline": ["outline", "danger"], "danger-ghost": ["ghost", "danger"],
|
|
26
26
|
link: ["link", "neutral"], "link-primary": ["link", "brand"], "link-danger": ["link", "danger"],
|
|
27
|
-
nav: ["nav", "neutral"]
|
|
27
|
+
nav: ["nav", "neutral"], "danger-soft": ["soft", "danger"]
|
|
28
28
|
};
|
|
29
|
+
// Atalhos que NÃO têm classe própria (15/10/2026): saem como os dois eixos (`btn-soft btn-tone-danger`), e herdam as
|
|
30
|
+
// regras de cor do tom nos dois temas em vez de repeti-las numa classe nova.
|
|
31
|
+
const SO_EIXOS = new Set(["danger-soft"]);
|
|
29
32
|
// caminho de volta: par → nome antigo. Existir aqui significa "o core já pinta esta célula com
|
|
30
33
|
// uma classe própria", e é o que garante que NENHUMA baseline se mexe: `appearance="outline"`
|
|
31
34
|
// + `tone="danger"` emite `.btn-danger-outline`, o mesmo DOM de sempre.
|
|
32
35
|
const CLASSE_ANTIGA = new Map(Object.entries(EIXOS)
|
|
33
|
-
.filter(([v]) => v !== "secondary").map(([v, [a, t]]) => [`${a}/${t}`, v]));
|
|
36
|
+
.filter(([v]) => v !== "secondary" && !SO_EIXOS.has(v)).map(([v, [a, t]]) => [`${a}/${t}`, v]));
|
|
34
37
|
/** Resolve os dois eixos (ou o atalho) na classe que o core pinta. Exportada porque o teste
|
|
35
38
|
* cobra a matriz inteira, e porque quem monta um botão à mão precisa da mesma conta.
|
|
36
39
|
*
|
|
@@ -41,7 +44,7 @@ const CLASSE_ANTIGA = new Map(Object.entries(EIXOS)
|
|
|
41
44
|
* que se pede, nunca o que sobra quando a nossa paleta não dá conta. */
|
|
42
45
|
export function buttonSkin(variant, appearance, tone) {
|
|
43
46
|
// A variação sem eixo pedido é a própria classe — é o caminho do `secondary`, que não tem célula.
|
|
44
|
-
if (appearance === undefined && tone === undefined)
|
|
47
|
+
if (appearance === undefined && tone === undefined && !(variant && SO_EIXOS.has(variant)))
|
|
45
48
|
return `btn-${variant ?? "tertiary"}`;
|
|
46
49
|
const [a0, t0] = EIXOS[variant ?? "tertiary"];
|
|
47
50
|
const a = appearance ?? a0, t = tone ?? t0;
|
|
@@ -100,7 +103,13 @@ const GrupoDeBotoesContext = React.createContext(null);
|
|
|
100
103
|
// type="button" por default: o default do HTML é submit, e um "Cancelar"/"Remover"
|
|
101
104
|
// dentro de <form> dispararia a ação principal (auditoria 18/07/2026, ALTO 1).
|
|
102
105
|
// Quem quer submeter passa type="submit" explícito (como o MessageComposer faz).
|
|
103
|
-
|
|
106
|
+
// O nome da combinação para o `aria-keyshortcuts`: as teclas juntas por "+", com os nomes da especificação (o ESPAÇO
|
|
107
|
+
// separa atalhos ALTERNATIVOS — "Ctrl K" quer dizer "Ctrl" ou "K"). O texto solto passa como veio, como antes.
|
|
108
|
+
const NOME_DA_TECLA = { ctrl: "Control", control: "Control", "⌃": "Control", cmd: "Meta", command: "Meta", "⌘": "Meta", meta: "Meta",
|
|
109
|
+
shift: "Shift", "⇧": "Shift", alt: "Alt", option: "Alt", "⌥": "Alt", enter: "Enter", "↵": "Enter", esc: "Escape", escape: "Escape" };
|
|
110
|
+
const atalhoAnunciado = (kbd) => typeof kbd === "string" ? (kbd || undefined)
|
|
111
|
+
: kbd && kbd.length > 0 ? kbd.map(k => NOME_DA_TECLA[k.toLowerCase()] ?? k).join("+") : undefined;
|
|
112
|
+
export const Button = forwardRef(function Button({ variant: variantPedida, appearance, tone, size: sizePedido, quiet, loading, leadingIcon, trailingIcon, className, children, disabled: disabledPedido, type = "button", href, fullWidth, grow, target, rel, download, pressed, kbd, onClick, onClickCapture, "aria-disabled": ariaDisabled, render, share, ...props }, ref) {
|
|
104
113
|
const grupo = React.useContext(GrupoDeBotoesContext);
|
|
105
114
|
const variant = variantPedida ?? grupo?.variant;
|
|
106
115
|
const size = sizePedido ?? grupo?.size ?? "md";
|
|
@@ -112,7 +121,7 @@ export const Button = forwardRef(function Button({ variant: variantPedida, appea
|
|
|
112
121
|
// Quem decide é o CSS: nada aqui observa largura, e o HTML do servidor já sai correto.
|
|
113
122
|
const responsivo = ehResponsivo(size);
|
|
114
123
|
const base = valorBase(size) ?? "md";
|
|
115
|
-
const cls = cx("btn", buttonSkin(variant, appearance, tone), responsivo ? classesResponsivas("size", size) : (base !== "md" && `btn-${base}`), fullWidth && "btn-block", grow && "btn-grow", className);
|
|
124
|
+
const cls = cx("btn", buttonSkin(variant, appearance, tone), responsivo ? classesResponsivas("size", size) : (base !== "md" && `btn-${base}`), fullWidth && "btn-block", grow && "btn-grow", quiet && "btn-quiet", className);
|
|
116
125
|
// kbd dentro do botão: mostra o atalho E o anuncia (aria-keyshortcuts), senão é enfeite.
|
|
117
126
|
// 🔴 OCUPADO TROCA, NÃO ACRESCENTA (01/10/2026, achado pelo Victor no aureauds.dev): a rodinha
|
|
118
127
|
// entrava ANTES do ícone, e no `IconButton` — 36 de largura fixa — rodinha e glifo não cabiam:
|
|
@@ -122,7 +131,7 @@ export const Button = forwardRef(function Button({ variant: variantPedida, appea
|
|
|
122
131
|
// da frente; e sem conteúdo (o `IconButton` ocupado) o invólucro vazio some, senão o `gap` dele
|
|
123
132
|
// empurraria a rodinha para fora do centro. Fora do estado ocupado o HTML é o mesmo de antes.
|
|
124
133
|
const temConteudo = children != null && children !== false;
|
|
125
|
-
const inner = _jsxs(_Fragment, { children: [loading ? _jsx("span", { className: "spinner" }) : leadingIcon && _jsx(Icon, { name: leadingIcon }), (temConteudo || !loading) && _jsx("span", { children: children }), kbd && _jsx(Kbd, { className: "btn-kbd", children: kbd }), trailingIcon && _jsx(Icon, { name: trailingIcon })] });
|
|
134
|
+
const inner = _jsxs(_Fragment, { children: [loading ? _jsx("span", { className: "spinner" }) : leadingIcon && _jsx(Icon, { name: leadingIcon }), (temConteudo || !loading) && _jsx("span", { children: children }), typeof kbd === "string" ? (kbd && _jsx(Kbd, { className: "btn-kbd", children: kbd })) : kbd && kbd.length > 0 && _jsx("span", { className: "btn-kbds", children: kbd.map((k, i) => _jsx(Kbd, { className: "btn-kbd", children: k }, i)) }), trailingIcon && _jsx(Icon, { name: trailingIcon })] });
|
|
126
135
|
// INERTE ≠ DESABILITADO, e a diferença é medida (M4, 13/08/2026): `disabled` tira o botão da
|
|
127
136
|
// ordem de foco, então quem navega por teclado nunca alcança a explicação de POR QUE não dá — e
|
|
128
137
|
// "não dá porque você não tem permissão" é justamente o caso em que a explicação é tudo. O
|
|
@@ -132,7 +141,7 @@ export const Button = forwardRef(function Button({ variant: variantPedida, appea
|
|
|
132
141
|
// Mesmo remendo do AUD-0004, que já barrava o link desabilitado; aqui ele alcança o <button>.
|
|
133
142
|
const inerte = ariaDisabled === true || ariaDisabled === "true";
|
|
134
143
|
const off = disabled || loading;
|
|
135
|
-
const shared = { "aria-keyshortcuts": kbd
|
|
144
|
+
const shared = { "aria-keyshortcuts": atalhoAnunciado(kbd), "aria-busy": loading || undefined };
|
|
136
145
|
// GAR-14: o `share` emite a mesma marcação que o `aurea.js` lê ([data-aurea-share]) — o catálogo
|
|
137
146
|
// estático não hidrata, e é ela que faz o botão funcionar lá. Os textos vão junto, na língua do app.
|
|
138
147
|
const s = useAureaStrings();
|
|
@@ -225,10 +234,22 @@ export const CloseButton = forwardRef(function CloseButton({ label, className, c
|
|
|
225
234
|
const s = useAureaStrings();
|
|
226
235
|
return _jsx(Button, { ref: ref, variant: "tertiary", className: cx("close-button", className), "aria-label": label ?? s.close, ...props, children: children ?? _jsx(Icon, { name: "x", weight: "bold" }) });
|
|
227
236
|
});
|
|
228
|
-
export const ThemeToggle = forwardRef(function ThemeToggle({ className, ...props }, ref) {
|
|
229
|
-
const { theme, toggleTheme } = useAureaTheme();
|
|
237
|
+
export const ThemeToggle = forwardRef(function ThemeToggle({ className, mode = "light-dark", ...props }, ref) {
|
|
238
|
+
const { theme, preference, toggleTheme, setTheme } = useAureaTheme();
|
|
230
239
|
const s = useAureaStrings();
|
|
231
240
|
const escuro = theme === "dark";
|
|
241
|
+
const nome = React.useId();
|
|
242
|
+
// A CHAVE DE TRÊS POSIÇÕES (15/10/2026, o Victor: "A, B, C, pode"): a do topo da referência, medida nela — a
|
|
243
|
+
// cápsula de 34 com as três opções de 26 e o glifo de 16. São botões de opção NATIVOS, como as amostras do
|
|
244
|
+
// `ColorSwatch`: a escolha única e as setas são do navegador. A escolhida tem o glifo cheio (ADR-0053) e a pele da
|
|
245
|
+
// aba escolhida (ADR-0059). Quem escolhe é o provider (`"system"` segue o sistema).
|
|
246
|
+
if (mode === "light-dark-system") {
|
|
247
|
+
const opcoes = [["light", "sun", s.themeLight], ["dark", "moon", s.themeDark], ["system", "monitor", s.themeSystem]];
|
|
248
|
+
return _jsx("div", { role: "radiogroup", "aria-label": s.themeChoice, className: cx("theme-switch", className), children: opcoes.map(([v, icone, rotulo]) => {
|
|
249
|
+
const marcada = preference === v;
|
|
250
|
+
return _jsxs("label", { className: "theme-switch-option", children: [_jsx("input", { type: "radio", className: "theme-switch-input", name: nome, value: v, checked: marcada, disabled: props.disabled, "aria-label": rotulo, onChange: () => setTheme(v) }), _jsx(Icon, { name: icone, size: "sm", weight: marcada ? "fill" : "regular" })] }, v);
|
|
251
|
+
}) });
|
|
252
|
+
}
|
|
232
253
|
// O corpo do `IconButton`, escrito aqui só para o glifo sair na forma CHEIA (ADR-0053: a lua e o
|
|
233
254
|
// sol cheios, como os do conjunto de ícones anterior, aprovados pela imagem em 25/09/2026). O `IconButton` público não
|
|
234
255
|
// tem peso de ícone.
|
package/dist/calendar.js
CHANGED
|
@@ -133,7 +133,7 @@ export function DatePicker(props) {
|
|
|
133
133
|
setIdDoRotulo(gatilho.current?.labels?.[0]?.id || undefined);
|
|
134
134
|
}
|
|
135
135
|
setAberta(o);
|
|
136
|
-
}, children: [_jsxs(BasePopover.Trigger, { ref: gatilho, disabled: disabled, id: id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "aria-describedby": ariaDescribedby, className: cx("select", "select-trigger", "date-picker-trigger", peleDoEixo("select", size), className), children: [_jsx("span", { className: "select-value", "data-placeholder": vazio ? "" : undefined, lang: vazio ? undefined : locale?.code, children: texto ?? placeholder ?? (props.range ? s.dateRangePlaceholder : s.datePlaceholder) }), icon !== false && _jsx(Icon, { name: icon })] }), name && _jsx("input", { type: "hidden", name: name, value: campo ?? "" }), _jsx(BasePopover.Portal, { container: portal, children: _jsx(BasePopover.Positioner, { side: "bottom", align: "start", sideOffset: 6, children: _jsx(BasePopover.Popup, { className: "popover date-picker-popover", "aria-labelledby": ariaLabelledby ?? idDoRotulo, "aria-label": (ariaLabelledby ?? idDoRotulo) ? undefined
|
|
136
|
+
}, children: [_jsxs(BasePopover.Trigger, { ref: gatilho, disabled: disabled, id: id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "aria-describedby": ariaDescribedby, className: cx("select", "select-trigger", "date-picker-trigger", peleDoEixo("select", size), className), children: [_jsx("span", { className: "select-value", "data-placeholder": vazio ? "" : undefined, lang: vazio ? undefined : locale?.code, children: texto ?? placeholder ?? (props.range ? s.dateRangePlaceholder : s.datePlaceholder) }), icon !== false && _jsx(Icon, { name: icon })] }), name && _jsx("input", { type: "hidden", name: name, value: campo ?? "" }), _jsx(BasePopover.Portal, { container: portal, children: _jsx(BasePopover.Positioner, { className: "positioner", side: "bottom", align: "start", sideOffset: 6, children: _jsx(BasePopover.Popup, { className: "popover date-picker-popover", "aria-labelledby": ariaLabelledby ?? idDoRotulo, "aria-label": (ariaLabelledby ?? idDoRotulo) ? undefined
|
|
137
137
|
: ariaLabel ?? (props.range ? s.dateRangePlaceholder : s.datePlaceholder), children: calendario }) }) })] });
|
|
138
138
|
}
|
|
139
139
|
// O `Field` nomeia o gatilho com `<label for>`: o `id` que ele injeta vai para o botão (ver `internal.tsx`).
|
package/dist/code-editor.js
CHANGED
|
@@ -37,18 +37,18 @@ import { cx, useAureaStrings } from "./internal.js";
|
|
|
37
37
|
// (auditoria 18/07/2026, ALTO 5). Com a anotação + sideEffects:false, o tema e o
|
|
38
38
|
// CodeEditor (e o CodeMirror) somem quando não usados. Split por subpath = decisão do Victor.
|
|
39
39
|
export const aureaEditorTheme = /*@__PURE__*/ EditorView.theme({
|
|
40
|
-
"&": { backgroundColor: "var(--surface-inset)", color: "var(--foreground)", border: "var(--border-width) solid
|
|
40
|
+
"&": { backgroundColor: "var(--surface-inset)", color: "var(--foreground)", border: "var(--border-width) solid transparent", borderRadius: "var(--radius-lg)", fontSize: "var(--text-xs)" },
|
|
41
41
|
"&.cm-focused": { outline: "2px solid var(--focus-strong)", outlineOffset: "-2px" },
|
|
42
42
|
".cm-scroller": { fontFamily: "var(--font-code)", lineHeight: "var(--leading-relaxed)", borderRadius: "inherit" },
|
|
43
43
|
".cm-content": { caretColor: "var(--foreground)", padding: "var(--space-2) 0" },
|
|
44
44
|
".cm-line": { padding: "0 var(--space-3)" },
|
|
45
|
-
".cm-cursor, .cm-dropCursor": { borderLeftColor: "var(--foreground)" },
|
|
46
|
-
"&.cm-focused .cm-cursor": { borderLeftColor: "var(--foreground)" },
|
|
45
|
+
".cm-cursor, .cm-dropCursor": { borderLeftColor: "transparent", width: "calc(2 * var(--border-width))", marginLeft: "calc(-1 * var(--border-width))", backgroundColor: "var(--foreground)" },
|
|
46
|
+
"&.cm-focused .cm-cursor": { borderLeftColor: "transparent", backgroundColor: "var(--foreground)" },
|
|
47
47
|
".cm-selectionBackground, ::selection": { backgroundColor: "var(--selection)" },
|
|
48
48
|
"&.cm-focused .cm-selectionBackground": { backgroundColor: "var(--selection)" },
|
|
49
49
|
".cm-selectionMatch": { backgroundColor: "var(--selection)" },
|
|
50
50
|
".cm-activeLine": { backgroundColor: "color-mix(in srgb,var(--foreground) 5%,transparent)" },
|
|
51
|
-
".cm-gutters": { backgroundColor: "var(--surface-inset)", color: "var(--muted-foreground)", border: "none", borderRight: "var(--border-width) solid
|
|
51
|
+
".cm-gutters": { backgroundColor: "var(--surface-inset)", color: "var(--muted-foreground)", border: "none", borderRight: "var(--border-width) solid transparent" },
|
|
52
52
|
".cm-gutterElement": { padding: "0 var(--space-2)" },
|
|
53
53
|
".cm-activeLineGutter": { backgroundColor: "color-mix(in srgb,var(--foreground) 5%,transparent)", color: "var(--foreground)" },
|
|
54
54
|
".cm-matchingBracket, &.cm-focused .cm-matchingBracket": { backgroundColor: "color-mix(in srgb,var(--foreground) 16%,transparent)", color: "var(--foreground)", outline: "none" },
|
|
@@ -56,9 +56,9 @@ export const aureaEditorTheme = /*@__PURE__*/ EditorView.theme({
|
|
|
56
56
|
".cm-searchMatch": { backgroundColor: "color-mix(in srgb,var(--warning-400) 30%,transparent)" },
|
|
57
57
|
".cm-searchMatch.cm-searchMatch-selected": { backgroundColor: "var(--selection)" },
|
|
58
58
|
".cm-panels": { backgroundColor: "var(--surface-2)", color: "var(--foreground)" },
|
|
59
|
-
".cm-panels.cm-panels-top": { borderBottom: "var(--border-width) solid
|
|
60
|
-
".cm-panels.cm-panels-bottom": { borderTop: "var(--border-width) solid
|
|
61
|
-
".cm-tooltip": { backgroundColor: "var(--popover)", color: "var(--popover-foreground)", border: "var(--border-width) solid
|
|
59
|
+
".cm-panels.cm-panels-top": { borderBottom: "var(--border-width) solid transparent" },
|
|
60
|
+
".cm-panels.cm-panels-bottom": { borderTop: "var(--border-width) solid transparent" },
|
|
61
|
+
".cm-tooltip": { backgroundColor: "var(--popover)", color: "var(--popover-foreground)", border: "var(--border-width) solid transparent", borderRadius: "var(--radius-md)" },
|
|
62
62
|
".cm-tooltip-autocomplete ul li[aria-selected]": { backgroundColor: "color-mix(in srgb,var(--primary) 14%,transparent)", color: "var(--foreground)" },
|
|
63
63
|
".cm-completionLabel": { color: "var(--foreground)" },
|
|
64
64
|
});
|
|
@@ -9,12 +9,14 @@ export declare function Status({ variant, state, children, className, ...props }
|
|
|
9
9
|
state?: UniversalState;
|
|
10
10
|
}): React.JSX.Element;
|
|
11
11
|
export type AlertVariant = "info" | "success" | "warning" | "danger" | "accent";
|
|
12
|
-
export declare function Alert({ variant, state, title, icon, onDismiss, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
12
|
+
export declare function Alert({ variant, state, title, icon, onDismiss, action, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
13
13
|
variant?: AlertVariant;
|
|
14
14
|
state?: UniversalState;
|
|
15
15
|
title?: ReactNode;
|
|
16
16
|
icon?: IconName;
|
|
17
17
|
onDismiss?: () => void;
|
|
18
|
+
/** O botão do aviso ("Atualizar", "Desfazer"): depois do texto, antes do X. No celular, embaixo do texto. */
|
|
19
|
+
action?: ReactNode;
|
|
18
20
|
}): React.JSX.Element;
|
|
19
21
|
export type BannerVariant = "info" | "success" | "warning" | "danger";
|
|
20
22
|
export declare function Banner({ variant, state, title, icon, onDismiss, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
package/dist/feedback-client.js
CHANGED
|
@@ -51,7 +51,9 @@ const ICONE_DA_VARIANTE = { info: "info",
|
|
|
51
51
|
// universal. Quem passa só `state` recebe a cor derivada da gravidade e o rótulo universal
|
|
52
52
|
// quando não há filho; quem passa os dois manda, porque só o consumidor sabe se aquele
|
|
53
53
|
// "esperando" dele é grave.
|
|
54
|
-
|
|
54
|
+
// `action` (15/10/2026, o "Upgrade" da referência): o botão do aviso, depois do texto e antes do X; no celular ele desce
|
|
55
|
+
// para baixo do texto, na mesma coluna (a referência repete o botão; aqui ele só muda de lugar).
|
|
56
|
+
export function Alert({ variant, state, title, icon, onDismiss, action, children, className, ...props }) { const s = useAureaStrings(); const v = variant ?? (state ? stateSeverity(state) : "info"); return _jsxs("div", { className: cx("alert", `alert-${v}`, action != null && "alert-has-action", className), role: v === "danger" ? "alert" : "status", "data-state": state, ...props, children: [_jsx(Icon, { name: icon ?? ICONE_DA_VARIANTE[v], weight: icon ? undefined : "fill" }), _jsxs("div", { children: [title && _jsx("strong", { children: title }), children ?? (state ? s.universalState[state] : null)] }), action != null && _jsx("div", { className: "alert-action", children: action }), onDismiss ? _jsx(CloseButton, { onClick: onDismiss }) : _jsx("span", {})] }); }
|
|
55
57
|
export function Banner({ variant, state, title, icon, onDismiss, children, className, ...props }) { const s = useAureaStrings(); const v = variant ?? (state ? stateSeverity(state) : "info"); return _jsxs("div", { className: cx("banner", `banner-${v}`, className), role: v === "danger" ? "alert" : "status", "data-state": state, ...props, children: [icon ? _jsx(Icon, { name: icon }) : _jsx("span", {}), _jsxs("div", { children: [title && _jsx("strong", { children: title }), children ?? (state ? s.universalState[state] : null)] }), onDismiss ? _jsx(IconButton, { variant: "ghost", size: "sm", icon: "x", label: s.close, onClick: onDismiss }) : _jsx("span", {})] }); }
|
|
56
58
|
export function Spinner({ size = "md", label, decorative, className, ...props }) { const s = useAureaStrings(); return _jsx("span", { className: cx("spinner", peleDoEixo("spinner", size, "sm", "spinner"), className), ...(decorative ? { "aria-hidden": true } : { role: "status", "aria-label": label ?? s.loading }), ...props }); }
|
|
57
59
|
// `children` como FUNÇÃO é de propósito para o caso `loading`: assim o consumidor não paga o
|
|
@@ -138,7 +140,7 @@ export function NotificationCenter({ items, onItemClick, onMarkAllRead, label, i
|
|
|
138
140
|
? _jsx("button", { type: "button", className: "notification-item", "data-read": it.read || undefined, onClick: () => { it.onClick?.(); onItemClick?.(it); }, children: body })
|
|
139
141
|
: _jsx("div", { className: "notification-item", "data-read": it.read || undefined, children: body });
|
|
140
142
|
};
|
|
141
|
-
return _jsxs(BasePopover.Root, { children: [_jsxs("span", { className: "notification-trigger", children: [_jsx(BasePopover.Trigger, { render: _jsx(IconButton, { variant: "ghost", icon: icon, label: unread ? `${title} (${unread})` : title }) }), unread > 0 && _jsx("span", { className: "notification-count", "aria-hidden": "true", children: unread > 99 ? "99+" : unread })] }), _jsx(BasePopover.Portal, { container: portal, children: _jsx(BasePopover.Positioner, { side: side, sideOffset: 8, children: _jsxs(BasePopover.Popup, { className: "popover notification-panel", "aria-label": title, children: [_jsxs("div", { className: "notification-head", children: [_jsx(BasePopover.Title, { render: _jsx("strong", {}), children: title }), unread > 0 && onMarkAllRead && _jsx(Button, { variant: "ghost", size: "sm", onClick: onMarkAllRead, children: s.notificationMarkAll })] }), items.length
|
|
143
|
+
return _jsxs(BasePopover.Root, { children: [_jsxs("span", { className: "notification-trigger", children: [_jsx(BasePopover.Trigger, { render: _jsx(IconButton, { variant: "ghost", icon: icon, label: unread ? `${title} (${unread})` : title }) }), unread > 0 && _jsx("span", { className: "notification-count", "aria-hidden": "true", children: unread > 99 ? "99+" : unread })] }), _jsx(BasePopover.Portal, { container: portal, children: _jsx(BasePopover.Positioner, { className: "positioner", side: side, sideOffset: 8, children: _jsxs(BasePopover.Popup, { className: "popover notification-panel", "aria-label": title, children: [_jsxs("div", { className: "notification-head", children: [_jsx(BasePopover.Title, { render: _jsx("strong", {}), children: title }), unread > 0 && onMarkAllRead && _jsx(Button, { variant: "ghost", size: "sm", onClick: onMarkAllRead, children: s.notificationMarkAll })] }), items.length
|
|
142
144
|
? _jsx("div", { className: "notification-list", children: groups.map((g, gi) => {
|
|
143
145
|
const gid = baseId + gi;
|
|
144
146
|
return _jsxs(React.Fragment, { children: [g.label && _jsx("p", { className: "notification-group-label", id: gid, children: g.label }), _jsx("ul", { className: "notification-sublist", "aria-labelledby": g.label ? gid : undefined, children: g.items.map(it => _jsx("li", { children: renderRow(it) }, it.id)) })] }, gi);
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { type Responsive } from "./pure.js";
|
|
2
2
|
import React, { type ReactNode } from "react";
|
|
3
3
|
import type { AvatarSize } from "./markup.js";
|
|
4
|
-
export
|
|
4
|
+
export type AvatarTone = "neutral" | "brand" | "danger" | "success" | "warning" | "info";
|
|
5
|
+
export declare function Avatar({ src, alt, fallback, size, tone, emphasis, className }: {
|
|
5
6
|
src?: string;
|
|
6
7
|
alt?: string;
|
|
7
8
|
fallback?: ReactNode;
|
|
8
9
|
size?: Responsive<AvatarSize>;
|
|
10
|
+
/** A cor da letra ou do ícone de reserva: o que ele significa. */
|
|
11
|
+
tone?: AvatarTone;
|
|
12
|
+
/** `soft`: sem a moldura, com o fundo clarinho do tom. */
|
|
13
|
+
emphasis?: "default" | "soft";
|
|
9
14
|
className?: string;
|
|
10
15
|
}): React.JSX.Element;
|
package/dist/identity-client.js
CHANGED
|
@@ -6,11 +6,8 @@ import { peleDoEixo } from "./pure.js";
|
|
|
6
6
|
// internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
7
7
|
import React from "react";
|
|
8
8
|
import { cx } from "./internal.js";
|
|
9
|
-
|
|
10
|
-
// componente tinha perdido a capacidade quando este arquivo entrou da `main`. Mesma perda
|
|
11
|
-
// silenciosa do `Input`, do `Tabs` e do `NumberField` — a ficha documentava, o código não fazia.
|
|
12
|
-
export function Avatar({ src, alt = "", fallback, size, className }) {
|
|
9
|
+
export function Avatar({ src, alt = "", fallback, size, tone, emphasis, className }) {
|
|
13
10
|
const [falhou, setFalhou] = React.useState(false);
|
|
14
11
|
React.useEffect(() => { setFalhou(false); }, [src]);
|
|
15
|
-
return _jsx("span", { className: cx("avatar", peleDoEixo("avatar", size), className), children: src && !falhou ? _jsx("img", { src: src, alt: alt, onError: () => setFalhou(true) }) : fallback });
|
|
12
|
+
return _jsx("span", { className: cx("avatar", peleDoEixo("avatar", size), tone && tone !== "neutral" && `avatar-tone-${tone}`, emphasis === "soft" && "avatar-soft", className), children: src && !falhou ? _jsx("img", { src: src, alt: alt, onError: () => setFalhou(true) }) : fallback });
|
|
16
13
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { cx, defaultStrings, ptBR, defaultSpriteUrl, gridStateToParams, gridStateFromParams, screenStateToParams, screenStateFromParams, universalStates, stateSeverity, type AureaStrings, type AureaTheme, type AureaDensity, type GridState, type ScreenState, type UniversalState } from "./pure.js";
|
|
1
|
+
export { cx, defaultStrings, ptBR, defaultSpriteUrl, gridStateToParams, gridStateFromParams, screenStateToParams, screenStateFromParams, universalStates, stateSeverity, type AureaStrings, type AureaTheme, type AureaThemePreference, type AureaDensity, type GridState, type ScreenState, type UniversalState } from "./pure.js";
|
|
2
2
|
export { useAureaStrings, useSpriteUrl, useTheme, useDensity } from "./internal.js";
|
|
3
3
|
export { type Responsive, type Breakpoint, type ContainerBreakpoint, type Orientation, ESCALA, ESCALA_CONTAINER } from "./pure.js";
|
|
4
4
|
export { ContainerScope, useValorResponsivo } from "./responsivo-runtime.js";
|
package/dist/inputs-client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { type ButtonHTMLAttributes, type HTMLAttributes, type InputHTMLAttributes, type RefAttributes, type ReactNode } from "react";
|
|
2
2
|
import { type Responsive } from "./pure.js";
|
|
3
3
|
import { type ColorChannel, type ColorSpace } from "./color.js";
|
|
4
|
-
import { type ColorSwatchOption, type FieldSize, type FieldVariant } from "./markup.js";
|
|
4
|
+
import { Radio, type ColorSwatchOption, type FieldSize, type FieldVariant } from "./markup.js";
|
|
5
5
|
import { type IconName } from "./system.js";
|
|
6
6
|
export { FileInput, matchesAccept, type FileRejection, type UploadContext, type UploadFn } from "./file-input.js";
|
|
7
7
|
export type FieldOrientation = "vertical" | "horizontal";
|
|
@@ -76,6 +76,29 @@ export interface CheckboxGroupProps extends Omit<HTMLAttributes<HTMLDivElement>,
|
|
|
76
76
|
required?: boolean;
|
|
77
77
|
}
|
|
78
78
|
export declare function CheckboxGroup({ label, description, error, value, defaultValue, onValueChange, name, disabled, required, children, className, ...props }: CheckboxGroupProps): React.JSX.Element;
|
|
79
|
+
export interface RadioGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, "defaultValue" | "onChange">, RefAttributes<HTMLDivElement> {
|
|
80
|
+
label: ReactNode;
|
|
81
|
+
/** O nome sai da tela e fica para o leitor de tela, como no `Checkbox` (a fileira de controles da vitrine da referência). */
|
|
82
|
+
labelHidden?: boolean;
|
|
83
|
+
description?: ReactNode;
|
|
84
|
+
error?: ReactNode;
|
|
85
|
+
value?: string;
|
|
86
|
+
defaultValue?: string;
|
|
87
|
+
onValueChange?: (value: string) => void;
|
|
88
|
+
/** O `name` de todas as opções, para o formulário. Sem ele, um nome próprio do grupo. */
|
|
89
|
+
name?: string;
|
|
90
|
+
disabled?: boolean;
|
|
91
|
+
/** Pinta todas as opções de erro, como o `invalid` do nativo. Com `error`, já vale. */
|
|
92
|
+
invalid?: boolean;
|
|
93
|
+
/** `vertical` (o padrão) ou `horizontal`, como a referência e o nativo. */
|
|
94
|
+
orientation?: "vertical" | "horizontal";
|
|
95
|
+
/** O asterisco no rótulo, como o `Field`. */
|
|
96
|
+
required?: boolean;
|
|
97
|
+
}
|
|
98
|
+
export declare function RadioGroup({ label, labelHidden, description, error, value, defaultValue, onValueChange, name, disabled, invalid, orientation, required, children, className, ...props }: RadioGroupProps): React.JSX.Element;
|
|
99
|
+
export declare namespace RadioGroup {
|
|
100
|
+
export { Radio as Item };
|
|
101
|
+
}
|
|
79
102
|
export interface ListBoxItem {
|
|
80
103
|
id: string;
|
|
81
104
|
label: ReactNode;
|
|
@@ -86,6 +109,8 @@ export interface ListBoxItem {
|
|
|
86
109
|
disabled?: boolean;
|
|
87
110
|
/** O item de perigo ("Excluir"), na cor de perigo. */
|
|
88
111
|
danger?: boolean;
|
|
112
|
+
/** O atalho do item ("⌘N"), à direita, como na lista da referência (15/10/2026). Só mostra: quem liga a tecla é o app. */
|
|
113
|
+
kbd?: string;
|
|
89
114
|
}
|
|
90
115
|
export interface ListBoxSection {
|
|
91
116
|
title: ReactNode;
|
|
@@ -269,7 +294,7 @@ export interface ColorPickerProps {
|
|
|
269
294
|
className?: string;
|
|
270
295
|
}
|
|
271
296
|
export declare function ColorPicker({ label, value, defaultValue, onValueChange, onValueCommitted, swatches, variant, children, disabled, name, id, className }: ColorPickerProps): React.JSX.Element;
|
|
272
|
-
export declare function OTPField({ length, value, defaultValue, onValueChange, mask, disabled, required, label, id, className }: {
|
|
297
|
+
export declare function OTPField({ length, value, defaultValue, onValueChange, mask, disabled, required, label, id, className, groupSize, variant }: {
|
|
273
298
|
length: number;
|
|
274
299
|
value?: string;
|
|
275
300
|
defaultValue?: string;
|
|
@@ -280,6 +305,10 @@ export declare function OTPField({ length, value, defaultValue, onValueChange, m
|
|
|
280
305
|
label?: string;
|
|
281
306
|
id?: string;
|
|
282
307
|
className?: string;
|
|
308
|
+
/** O tracinho entre os grupos: a cada `groupSize` caixas (3 num código de 6). */
|
|
309
|
+
groupSize?: number;
|
|
310
|
+
/** `secondary`: o fundo neutro do `Input` secundário, para o campo dentro de um cartão. */
|
|
311
|
+
variant?: "primary" | "secondary";
|
|
283
312
|
}): React.JSX.Element;
|
|
284
313
|
export declare function SegmentedControl({ items, value, onChange, label, fullWidth }: {
|
|
285
314
|
items: Array<{
|
package/dist/inputs-client.js
CHANGED
|
@@ -22,7 +22,7 @@ import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
|
22
22
|
// diretiva — são marcação, e quem escuta `onChange` é o consumidor. Voltam IMPORTADOS e não só
|
|
23
23
|
// reexportados porque o `ehControle` do `Field` compara por IDENTIDADE de referência: dois
|
|
24
24
|
// objetos diferentes com o mesmo nome quebrariam o rótulo do campo em silêncio.
|
|
25
|
-
import { Textarea, Checkbox, Radio, Switch, Range, InputGroup, InputGroupAddon, ColorSwatch } from "./markup.js";
|
|
25
|
+
import { Textarea, Checkbox, Radio, Switch, Range, InputGroup, InputGroupAddon, ColorSwatch, Kbd } from "./markup.js";
|
|
26
26
|
import { Icon } from "./system.js";
|
|
27
27
|
import { IconButton } from "./actions.js";
|
|
28
28
|
// A FAMÍLIA DE COR (0.32.0, ADR-0069) — as peças INTERNAS moram aqui, no topo, antes do primeiro export (auxiliar
|
|
@@ -383,7 +383,8 @@ export const Input = forwardRef(function Input({ className, formatOnBlur, size,
|
|
|
383
383
|
// `.input-wrap-end` para o botão do PasswordField —, e o grupo é a terceira vez virando uma. O
|
|
384
384
|
// merge das duas linhagens tinha trazido de volta a versão com `.input-wrap`, contra um core
|
|
385
385
|
// que já não a pinta.
|
|
386
|
-
|
|
386
|
+
// `search-field` (15/10/2026): a busca tem a medida própria da referência — 12, a lupa, 8 (ver o core).
|
|
387
|
+
export function SearchField({ icon = "magnifying-glass", className, size, width, ...props }) { return _jsxs(InputGroup, { className: cx("search-field", className), width: width, children: [_jsx(InputGroupAddon, { children: _jsx(Icon, { name: icon, size: valorBase(size) === "sm" ? "sm" : undefined }) }), _jsx(Input, { type: "search", size: size, ...props })] }); }
|
|
387
388
|
// labelHidden: coluna de seleção de tabela precisa do rótulo POR LINHA para o leitor de
|
|
388
389
|
// tela ("Select Analyst"), mas mostrá-lo engorda a coluna. O rótulo continua no DOM, só
|
|
389
390
|
// sai da tela (.sr-only) — nunca trocar por aria-label solto num <label> visível vazio.
|
|
@@ -432,6 +433,33 @@ export function CheckboxGroup({ label, description, error, value, defaultValue,
|
|
|
432
433
|
});
|
|
433
434
|
return _jsxs("div", { role: "group", "aria-labelledby": idRotulo, "aria-describedby": [idDescricao, idErro].filter(Boolean).join(" ") || undefined, className: cx("checkbox-group", className), ...props, children: [_jsx("span", { className: "label", id: idRotulo, children: _jsxs("span", { children: [label, required ? _jsx("span", { className: "label-required", "aria-hidden": "true", children: "*" }) : null] }) }), description && _jsx("span", { className: "field-description", id: idDescricao, children: description }), caixas, error && _jsx("span", { className: "field-error", id: idErro, children: error })] });
|
|
434
435
|
}
|
|
436
|
+
export function RadioGroup({ label, labelHidden, description, error, value, defaultValue, onValueChange, name, disabled, invalid, orientation = "vertical", required, children, className, ...props }) {
|
|
437
|
+
const auto = React.useId();
|
|
438
|
+
const [proprio, setProprio] = React.useState(defaultValue);
|
|
439
|
+
const escolhido = value ?? proprio;
|
|
440
|
+
const idRotulo = `${auto}-label`, idDescricao = description ? `${auto}-description` : undefined, idErro = error ? `${auto}-error` : undefined;
|
|
441
|
+
const opcoes = React.Children.map(children, filho => {
|
|
442
|
+
if (!React.isValidElement(filho))
|
|
443
|
+
return filho;
|
|
444
|
+
const p = filho.props;
|
|
445
|
+
if (typeof p.value !== "string")
|
|
446
|
+
return filho;
|
|
447
|
+
const v = p.value;
|
|
448
|
+
return React.cloneElement(filho, { checked: escolhido === v, name: name ?? auto, required,
|
|
449
|
+
disabled: p.disabled ?? disabled, ...(error || invalid ? { "aria-invalid": true } : null),
|
|
450
|
+
onChange: (e) => {
|
|
451
|
+
p.onChange?.(e);
|
|
452
|
+
if (!e.currentTarget.checked)
|
|
453
|
+
return;
|
|
454
|
+
if (value === undefined)
|
|
455
|
+
setProprio(v);
|
|
456
|
+
onValueChange?.(v);
|
|
457
|
+
} });
|
|
458
|
+
});
|
|
459
|
+
return _jsxs("div", { role: "radiogroup", "aria-labelledby": idRotulo, "aria-describedby": [idDescricao, idErro].filter(Boolean).join(" ") || undefined, "aria-orientation": orientation, "aria-required": required || undefined, "aria-invalid": error || invalid ? true : undefined, className: cx("radio-group", orientation === "horizontal" && "radio-group-horizontal", labelHidden && "radio-group-bare", className), ...props, children: [_jsx("span", { className: cx("label", labelHidden && "sr-only"), id: idRotulo, children: _jsxs("span", { children: [label, required ? _jsx("span", { className: "label-required", "aria-hidden": "true", children: "*" }) : null] }) }), description && _jsx("span", { className: "field-description", id: idDescricao, children: description }), orientation === "horizontal" ? _jsx("div", { className: "radio-group-items", children: opcoes }) : opcoes, error && _jsx("span", { className: "field-error", id: idErro, children: error })] });
|
|
460
|
+
}
|
|
461
|
+
/** A opção do grupo: o `Radio`, como o `RadioGroup.Item` do nativo. */
|
|
462
|
+
RadioGroup.Item = Radio;
|
|
435
463
|
const ehSecao = (x) => "items" in x;
|
|
436
464
|
const textoDoItem = (it) => it.textValue ?? (typeof it.label === "string" ? it.label : "");
|
|
437
465
|
export function ListBox({ label, items, selectionMode = "single", value, defaultValue, onValueChange, onAction, className, ...props }) {
|
|
@@ -502,7 +530,7 @@ export function ListBox({ label, items, selectionMode = "single", value, default
|
|
|
502
530
|
refs.current.delete(it.id); }, role: "option", "aria-selected": selectionMode === "none" ? undefined : escolhido, "aria-disabled": it.disabled || undefined, "aria-describedby": idDesc, tabIndex: it.id === alvo ? 0 : -1, className: cx("list-box-item", it.danger && "list-box-item-danger"), onClick: () => { if (!it.disabled) {
|
|
503
531
|
setAtivo(it.id);
|
|
504
532
|
escolher(it);
|
|
505
|
-
} }, onKeyDown: e => aoTeclar(e, it), onFocus: () => setAtivo(it.id), children: [it.icon && _jsx(Icon, { name: it.icon }), _jsxs("span", { className: "list-box-item-text", children: [_jsx("span", { className: "list-box-item-label", children: it.label }), it.description && _jsx("span", { className: "list-box-item-description", id: idDesc, children: it.description })] }), escolhido && _jsx(Icon, { name: "check", className: "list-box-item-indicator" })] }, it.id);
|
|
533
|
+
} }, onKeyDown: e => aoTeclar(e, it), onFocus: () => setAtivo(it.id), children: [it.icon && _jsx(Icon, { name: it.icon }), _jsxs("span", { className: "list-box-item-text", children: [_jsx("span", { className: "list-box-item-label", children: it.label }), it.description && _jsx("span", { className: "list-box-item-description", id: idDesc, children: it.description })] }), it.kbd && _jsx(Kbd, { className: "list-box-item-kbd", children: it.kbd }), escolhido && _jsx(Icon, { name: "check", className: "list-box-item-indicator" })] }, it.id);
|
|
506
534
|
};
|
|
507
535
|
return _jsx("div", { role: "listbox", "aria-label": label, "aria-multiselectable": selectionMode === "multiple" || undefined, className: cx("list-box", className), ...props, children: items.map((x, i) => ehSecao(x)
|
|
508
536
|
? _jsxs("div", { role: "group", "aria-labelledby": `${auto}-s${i}`, className: "list-box-section", children: [_jsx("span", { className: "list-box-section-title", id: `${auto}-s${i}`, role: "presentation", children: x.title }), x.items.map(item)] }, `s${i}`)
|
|
@@ -682,7 +710,7 @@ export function ColorPicker({ label, value, defaultValue, onValueChange, onValue
|
|
|
682
710
|
// O foco fica PRESO na janela (`trap-focus`), como na referência: com quatro peças dentro, o Tab que saía depois
|
|
683
711
|
// do código fechava a janela (medido no navegador). O motor pede um botão de fechar dentro, para o leitor de tela
|
|
684
712
|
// por toque sair; ele fica invisível e fora do Tab — quem usa teclado tem o Esc, e o foco nunca some na tela.
|
|
685
|
-
return _jsxs(BasePopover.Root, { modal: "trap-focus", children: [_jsxs(BasePopover.Trigger, { disabled: disabled, id: id, "aria-label": `${label}, ${nome}`, className: cx("color-picker-trigger", className), children: [_jsx(ColorSwatch, { color: hex, "aria-hidden": "true" }), _jsx("span", { children: label })] }), name && _jsx("input", { type: "hidden", name: name, value: hex }), _jsx(BasePopover.Portal, { container: portal, children: _jsx(BasePopover.Positioner, { side: "bottom", align: "start", sideOffset: 6, children: _jsxs(BasePopover.Popup, { className: "popover color-picker-popover", "aria-label": label, children: [_jsx(CorDoSeletor.Provider, { value: contexto, children: children ?? _jsxs(_Fragment, { children: [variant !== "swatches" && _jsxs(_Fragment, { children: [_jsx(AreaDeCor, { cor: cor, onCor: mudar, space: "hsb", x: "saturation", y: "brightness", "aria-label": label }), _jsx(TrilhaDeCor, { cor: cor, onCor: mudar, channel: "hue", label: s.colorChannel.hue, labelHidden: true, showValue: false })] }), amostras && _jsx(ColorSwatch, { options: amostras, name: `${idGrupo}-amostras`, label: s.colorSwatches, value: escolhida, onChange: (e) => mudar(corDoTexto(e.target.value, cor), true) }), _jsx(ColorField, { "aria-label": s.colorHex })] }) }), _jsx(BasePopover.Close, { className: "sr-only", tabIndex: -1, children: s.close })] }) }) })] });
|
|
713
|
+
return _jsxs(BasePopover.Root, { modal: "trap-focus", children: [_jsxs(BasePopover.Trigger, { disabled: disabled, id: id, "aria-label": `${label}, ${nome}`, className: cx("color-picker-trigger", className), children: [_jsx(ColorSwatch, { color: hex, "aria-hidden": "true" }), _jsx("span", { children: label })] }), name && _jsx("input", { type: "hidden", name: name, value: hex }), _jsx(BasePopover.Portal, { container: portal, children: _jsx(BasePopover.Positioner, { className: "positioner", side: "bottom", align: "start", sideOffset: 6, children: _jsxs(BasePopover.Popup, { className: "popover color-picker-popover", "aria-label": label, children: [_jsx(CorDoSeletor.Provider, { value: contexto, children: children ?? _jsxs(_Fragment, { children: [variant !== "swatches" && _jsxs(_Fragment, { children: [_jsx(AreaDeCor, { cor: cor, onCor: mudar, space: "hsb", x: "saturation", y: "brightness", "aria-label": label }), _jsx(TrilhaDeCor, { cor: cor, onCor: mudar, channel: "hue", label: s.colorChannel.hue, labelHidden: true, showValue: false })] }), amostras && _jsx(ColorSwatch, { options: amostras, name: `${idGrupo}-amostras`, label: s.colorSwatches, value: escolhida, onChange: (e) => mudar(corDoTexto(e.target.value, cor), true) }), _jsx(ColorField, { "aria-label": s.colorHex })] }) }), _jsx(BasePopover.Close, { className: "sr-only", tabIndex: -1, children: s.close })] }) }) })] });
|
|
686
714
|
}
|
|
687
715
|
// OTPField (Lote 1 do BUILDING.md). Um campo por dígito, com o comportamento que ninguém acerta
|
|
688
716
|
// à mão: colar o código inteiro distribui pelos campos, Backspace volta um, e o
|
|
@@ -695,9 +723,12 @@ export function ColorPicker({ label, value, defaultValue, onValueChange, onValue
|
|
|
695
723
|
// formulário anônimos. Um leitor de tela anunciaria "editar texto" seis vezes seguidas sem
|
|
696
724
|
// dizer qual é qual. O grupo continua nomeado (`role="group"`), que é o que diz para que serve
|
|
697
725
|
// o código; o nome de cada caixa é o que diz onde você está.
|
|
698
|
-
|
|
726
|
+
// 15/10/2026 (o Victor: "A, B, C, pode"), como o campo de código da referência: `groupSize` põe o TRACINHO a cada N
|
|
727
|
+
// caixas (o 3 + 3 da vitrine dela; o `Separator` do motor, de 6 × 2), e `variant="secondary"` dá às caixas o fundo
|
|
728
|
+
// neutro do `Input` secundário. Sem os dois, a marcação é a de antes.
|
|
729
|
+
export function OTPField({ length, value, defaultValue, onValueChange, mask, disabled, required, label, id, className, groupSize, variant }) {
|
|
699
730
|
const s = useAureaStrings();
|
|
700
|
-
return _jsx(BaseOTPField.Root, { id: id, length: length, value: value, defaultValue: defaultValue, onValueChange: soOValor(onValueChange), mask: mask, disabled: disabled, required: required, role: "group", "aria-label": label, className: cx("otp-field", className), children: Array.from({ length }, (_, i) => _jsx(BaseOTPField.Input, { render: _jsx("input", { "aria-label": `${s.otpDigit} ${i + 1}` }), className: "input otp-slot" }, i)) });
|
|
731
|
+
return _jsx(BaseOTPField.Root, { id: id, length: length, value: value, defaultValue: defaultValue, onValueChange: soOValor(onValueChange), mask: mask, disabled: disabled, required: required, role: "group", "aria-label": label, className: cx("otp-field", className), children: Array.from({ length }, (_, i) => _jsxs(React.Fragment, { children: [_jsx(BaseOTPField.Input, { render: _jsx("input", { "aria-label": `${s.otpDigit} ${i + 1}` }), className: cx("input otp-slot", variant === "secondary" && "input-secondary") }), groupSize && groupSize > 0 && (i + 1) % groupSize === 0 && i < length - 1 ? _jsx(BaseOTPField.Separator, { className: "otp-separator" }) : null] }, i)) });
|
|
701
732
|
}
|
|
702
733
|
// SegmentedControl — achado M20, fechado na Parte C do PLANO-1.0 em 07/08/2026.
|
|
703
734
|
//
|
|
@@ -759,7 +790,7 @@ export function Combobox({ items, value, onValueChange, placeholder, label, empt
|
|
|
759
790
|
const portal = usePortalContainer();
|
|
760
791
|
const autoId = React.useId();
|
|
761
792
|
const inputId = id ?? autoId;
|
|
762
|
-
return _jsxs(BaseCombobox.Root, { items: items, value: value, onValueChange: soOValor(onValueChange), disabled: disabled, itemToStringLabel: (i) => i.label, children: [_jsxs("div", { className: cx("field", className), children: [label && _jsx("label", { className: "label", htmlFor: inputId, children: label }), _jsxs(BaseCombobox.InputGroup, { className: "combobox-group", children: [_jsx(BaseCombobox.Input, { id: inputId, placeholder: placeholder, className: cx("input", peleDoEixo("input", size)), "aria-describedby": descrito, "aria-invalid": invalido, "aria-label": rotulo }), _jsxs("span", { className: "combobox-actions", children: [_jsx(BaseCombobox.Clear, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "x", label: s.comboboxClear }) }), _jsx(BaseCombobox.Trigger, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "caret-down", label: s.comboboxOpen }) })] })] })] }), _jsx(BaseCombobox.Portal, { container: portal, children: _jsx(BaseCombobox.Positioner, { sideOffset: 6, children: _jsxs(BaseCombobox.Popup, { className: "menu combobox-popup", children: [_jsx(BaseCombobox.Empty, { className: "combobox-empty", children: empty ?? s.comboboxEmpty }), listaCombobox(items)] }) }) })] });
|
|
793
|
+
return _jsxs(BaseCombobox.Root, { items: items, value: value, onValueChange: soOValor(onValueChange), disabled: disabled, itemToStringLabel: (i) => i.label, children: [_jsxs("div", { className: cx("field", className), children: [label && _jsx("label", { className: "label", htmlFor: inputId, children: label }), _jsxs(BaseCombobox.InputGroup, { className: "combobox-group", children: [_jsx(BaseCombobox.Input, { id: inputId, placeholder: placeholder, className: cx("input", peleDoEixo("input", size)), "aria-describedby": descrito, "aria-invalid": invalido, "aria-label": rotulo }), _jsxs("span", { className: "combobox-actions", children: [_jsx(BaseCombobox.Clear, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "x", label: s.comboboxClear }) }), _jsx(BaseCombobox.Trigger, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "caret-down", label: s.comboboxOpen }) })] })] })] }), _jsx(BaseCombobox.Portal, { container: portal, children: _jsx(BaseCombobox.Positioner, { className: "positioner", sideOffset: 6, children: _jsxs(BaseCombobox.Popup, { className: "menu combobox-popup", children: [_jsx(BaseCombobox.Empty, { className: "combobox-empty", children: empty ?? s.comboboxEmpty }), listaCombobox(items)] }) }) })] });
|
|
763
794
|
}
|
|
764
795
|
// MultiCombobox (Fase 4): multi-seleção com chips, opções agrupadas e filtro
|
|
765
796
|
// externo (async). Reusa .combobox-popup/-item/-empty do básico.
|
|
@@ -774,7 +805,7 @@ export function MultiCombobox({ items, value, onValueChange, onInputChange, load
|
|
|
774
805
|
const autoId = React.useId();
|
|
775
806
|
const inputId = id ?? autoId;
|
|
776
807
|
return _jsxs(BaseCombobox.Root, { multiple: true, items: items, value: value, onValueChange: soOValor(onValueChange), disabled: disabled, itemToStringLabel: (i) => i.label, filter: onInputChange ? null : undefined, onInputValueChange: onInputChange ? ((v, d) => { if (d.reason !== "item-press")
|
|
777
|
-
onInputChange(v); }) : undefined, children: [_jsxs("div", { className: cx("field", className), children: [label && _jsx("label", { className: "label", htmlFor: inputId, children: label }), _jsxs(BaseCombobox.InputGroup, { className: "combobox-multi", children: [_jsx(BaseCombobox.Chips, { className: "combobox-chips", children: _jsx(BaseCombobox.Value, { children: (selected) => _jsxs(_Fragment, { children: [selected.map((item) => _jsxs(BaseCombobox.Chip, { className: "combobox-chip", children: [item.label, _jsx(BaseCombobox.ChipRemove, { className: "combobox-chip-remove", "aria-label": `${s.comboboxRemove} ${item.label}`, children: _jsx(Icon, { name: "x", size: "sm" }) })] }, item.value)), _jsx(BaseCombobox.Input, { id: inputId, placeholder: selected.length ? undefined : placeholder, className: "combobox-chip-input", "aria-describedby": descrito, "aria-invalid": invalido, "aria-label": rotulo })] }) }) }), _jsxs("span", { className: "combobox-actions", children: [_jsx(BaseCombobox.Clear, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "x", label: s.comboboxClear }) }), _jsx(BaseCombobox.Trigger, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "caret-down", label: s.comboboxOpen }) })] })] })] }), _jsx(BaseCombobox.Portal, { container: portal, children: _jsx(BaseCombobox.Positioner, { sideOffset: 6, children: _jsxs(BaseCombobox.Popup, { className: "menu combobox-popup", children: [_jsx(BaseCombobox.Empty, { className: "combobox-empty", children: loading ? s.comboboxLoading : (empty ?? s.comboboxEmpty) }), listaCombobox(items)] }) }) })] });
|
|
808
|
+
onInputChange(v); }) : undefined, children: [_jsxs("div", { className: cx("field", className), children: [label && _jsx("label", { className: "label", htmlFor: inputId, children: label }), _jsxs(BaseCombobox.InputGroup, { className: "combobox-multi", children: [_jsx(BaseCombobox.Chips, { className: "combobox-chips", children: _jsx(BaseCombobox.Value, { children: (selected) => _jsxs(_Fragment, { children: [selected.map((item) => _jsxs(BaseCombobox.Chip, { className: "combobox-chip", children: [item.label, _jsx(BaseCombobox.ChipRemove, { className: "combobox-chip-remove", "aria-label": `${s.comboboxRemove} ${item.label}`, children: _jsx(Icon, { name: "x", size: "sm" }) })] }, item.value)), _jsx(BaseCombobox.Input, { id: inputId, placeholder: selected.length ? undefined : placeholder, className: "combobox-chip-input", "aria-describedby": descrito, "aria-invalid": invalido, "aria-label": rotulo })] }) }) }), _jsxs("span", { className: "combobox-actions", children: [_jsx(BaseCombobox.Clear, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "x", label: s.comboboxClear }) }), _jsx(BaseCombobox.Trigger, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "caret-down", label: s.comboboxOpen }) })] })] })] }), _jsx(BaseCombobox.Portal, { container: portal, children: _jsx(BaseCombobox.Positioner, { className: "positioner", sideOffset: 6, children: _jsxs(BaseCombobox.Popup, { className: "menu combobox-popup", children: [_jsx(BaseCombobox.Empty, { className: "combobox-empty", children: loading ? s.comboboxLoading : (empty ?? s.comboboxEmpty) }), listaCombobox(items)] }) }) })] });
|
|
778
809
|
}
|
|
779
810
|
const ehGrupoDoSelect = (i) => typeof i === "object" && i != null && "items" in i;
|
|
780
811
|
// Lê `<option>`/`<optgroup>` como o navegador lê: `value` ausente vale o TEXTO da opção.
|
|
@@ -804,7 +835,7 @@ export const Select = forwardRef(function Select({ items, children, value, defau
|
|
|
804
835
|
onValueChange?.(valor);
|
|
805
836
|
onChange?.({ target: { value: valor, name }, currentTarget: { value: valor, name } });
|
|
806
837
|
};
|
|
807
|
-
return _jsxs(BaseSelect.Root, { items: planas.map(o => ({ value: o.value, label: o.label })), ...(value !== undefined ? { value } : { defaultValue: inicial }), onValueChange: v => mudar(v), name: name, required: required, disabled: disabled, children: [_jsx(BaseSelect.Trigger, { ref: ref, className: cx("select", "select-trigger", peleDoEixo("select", size), className), ...props, children: _jsx(BaseSelect.Value, { placeholder: placeholder, className: "select-value" }) }), _jsx(BaseSelect.Portal, { container: portal, children: _jsx(BaseSelect.Positioner, { sideOffset: 6, alignItemWithTrigger: false, children: _jsx(BaseSelect.Popup, { className: "menu combobox-popup", children: _jsx(BaseSelect.List, { children: lista.map((i, n) => ehGrupoDoSelect(i)
|
|
838
|
+
return _jsxs(BaseSelect.Root, { items: planas.map(o => ({ value: o.value, label: o.label })), ...(value !== undefined ? { value } : { defaultValue: inicial }), onValueChange: v => mudar(v), name: name, required: required, disabled: disabled, children: [_jsx(BaseSelect.Trigger, { ref: ref, className: cx("select", "select-trigger", peleDoEixo("select", size), className), ...props, children: _jsx(BaseSelect.Value, { placeholder: placeholder, className: "select-value" }) }), _jsx(BaseSelect.Portal, { container: portal, children: _jsx(BaseSelect.Positioner, { className: "positioner", sideOffset: 6, alignItemWithTrigger: false, children: _jsx(BaseSelect.Popup, { className: "menu combobox-popup", children: _jsx(BaseSelect.List, { children: lista.map((i, n) => ehGrupoDoSelect(i)
|
|
808
839
|
? _jsxs(BaseSelect.Group, { className: "combobox-section", children: [_jsx(BaseSelect.GroupLabel, { className: "combobox-group-label", children: i.label }), i.items.map(itemDoSelect)] }, n)
|
|
809
840
|
: itemDoSelect(i)) }) }) }) })] });
|
|
810
841
|
});
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { type AureaStrings, type AureaTheme, type AureaDensity } from "./pure.js";
|
|
3
|
-
export { cx, fundirRender, defaultStrings, ptBR, defaultSpriteUrl, universalStates, stateSeverity, type AureaStrings, type UniversalState, type AureaTheme, type AureaDensity } from "./pure.js";
|
|
2
|
+
import { type AureaStrings, type AureaTheme, type AureaThemePreference, type AureaDensity } from "./pure.js";
|
|
3
|
+
export { cx, fundirRender, defaultStrings, ptBR, defaultSpriteUrl, universalStates, stateSeverity, type AureaStrings, type UniversalState, type AureaTheme, type AureaThemePreference, type AureaDensity } from "./pure.js";
|
|
4
4
|
export declare const controlesRotulaveis: WeakSet<object>;
|
|
5
5
|
export declare const StringsContext: React.Context<AureaStrings>;
|
|
6
6
|
export declare const useAureaStrings: () => AureaStrings;
|
|
@@ -8,14 +8,16 @@ export declare const SpriteContext: React.Context<string>;
|
|
|
8
8
|
export declare const useSpriteUrl: () => string;
|
|
9
9
|
export declare const ThemeContext: React.Context<{
|
|
10
10
|
theme?: AureaTheme;
|
|
11
|
-
|
|
11
|
+
preference?: AureaThemePreference;
|
|
12
|
+
setTheme: (t: AureaThemePreference) => void;
|
|
12
13
|
toggleTheme: () => void;
|
|
13
14
|
}>;
|
|
14
15
|
/** Tema atual e como trocá-lo. Fora de um `AureaProvider`, devolve `undefined` e no-ops — não
|
|
15
16
|
* lança: um componente isolado num teste não deve morrer por falta de provider. */
|
|
16
17
|
export declare const useTheme: () => {
|
|
17
18
|
theme?: AureaTheme;
|
|
18
|
-
|
|
19
|
+
preference?: AureaThemePreference;
|
|
20
|
+
setTheme: (t: AureaThemePreference) => void;
|
|
19
21
|
toggleTheme: () => void;
|
|
20
22
|
};
|
|
21
23
|
export declare const DensityContext: React.Context<{
|
package/dist/internal.js
CHANGED
|
@@ -35,7 +35,8 @@ export const useSpriteUrl = () => useContext(SpriteContext);
|
|
|
35
35
|
// diferente de "escuro". Um default concreto aqui faria o provider sobrescrever, na primeira
|
|
36
36
|
// pintura, o `data-theme` que o documento já traz no markup — e esse atributo existe justamente
|
|
37
37
|
// para não haver piscada de tema ao carregar.
|
|
38
|
-
|
|
38
|
+
// `preference` (15/10/2026): o que foi ESCOLHIDO, que pode ser `"system"`; `theme` é o que está na tela.
|
|
39
|
+
export const ThemeContext = createContext({ theme: undefined, preference: undefined, setTheme: () => { }, toggleTheme: () => { } });
|
|
39
40
|
/** Tema atual e como trocá-lo. Fora de um `AureaProvider`, devolve `undefined` e no-ops — não
|
|
40
41
|
* lança: um componente isolado num teste não deve morrer por falta de provider. */
|
|
41
42
|
export const useTheme = () => useContext(ThemeContext);
|