@aurea-uds/react 0.8.14 → 0.10.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 +9 -0
- package/dist/actions.js +3 -3
- package/dist/inputs-client.d.ts +20 -5
- package/dist/inputs-client.js +9 -8
- package/dist/layout-client.d.ts +6 -2
- package/dist/layout-client.js +8 -24
- package/dist/markup.d.ts +53 -7
- package/dist/markup.js +25 -35
- package/dist/overlays.d.ts +4 -1
- package/dist/overlays.js +6 -2
- package/package.json +1 -1
package/dist/actions.d.ts
CHANGED
|
@@ -24,6 +24,15 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, Re
|
|
|
24
24
|
trailingIcon?: IconName;
|
|
25
25
|
href?: string;
|
|
26
26
|
fullWidth?: boolean;
|
|
27
|
+
/** C-03 (24/09/2026): numa fila (`Cluster`), divide o espaço em partes iguais com os outros botões
|
|
28
|
+
* que também têm `grow`. O `fullWidth` não serve ali: ele pede a linha inteira. */
|
|
29
|
+
grow?: boolean;
|
|
30
|
+
/** C-13 (24/09/2026): atributos de LINK, que só valem com `href` — sem ele são ignorados. Antes
|
|
31
|
+
* chegavam ao `<a>` em tempo de execução, mas o tipo não os aceitava, e `target="_blank"` não
|
|
32
|
+
* compilava. */
|
|
33
|
+
target?: React.HTMLAttributeAnchorTarget;
|
|
34
|
+
rel?: string;
|
|
35
|
+
download?: boolean | string;
|
|
27
36
|
/**
|
|
28
37
|
* @deprecated Use `<Toggle>` instead. Pesquisado em 18/08/2026 nas doze referências (MUI,
|
|
29
38
|
* Fluent 2, React Aria, Spectrum, Carbon, Radix/Base UI, shadcn, ReUI, PrimeReact, HeroUI,
|
package/dist/actions.js
CHANGED
|
@@ -45,7 +45,7 @@ export function buttonSkin(variant, appearance, tone) {
|
|
|
45
45
|
// type="button" por default: o default do HTML é submit, e um "Cancelar"/"Remover"
|
|
46
46
|
// dentro de <form> dispararia a ação principal (auditoria 18/07/2026, ALTO 1).
|
|
47
47
|
// Quem quer submeter passa type="submit" explícito (como o MessageComposer faz).
|
|
48
|
-
export const Button = forwardRef(function Button({ variant, appearance, tone, size = "md", loading, leadingIcon, trailingIcon, className, children, disabled, type = "button", href, fullWidth, pressed, kbd, onClick, onClickCapture, "aria-disabled": ariaDisabled, ...props }, ref) {
|
|
48
|
+
export const Button = forwardRef(function Button({ variant, appearance, tone, size = "md", loading, leadingIcon, trailingIcon, className, children, disabled, type = "button", href, fullWidth, grow, target, rel, download, pressed, kbd, onClick, onClickCapture, "aria-disabled": ariaDisabled, ...props }, ref) {
|
|
49
49
|
// G-AXIS-04 — `size` aceita valor simples, responsivo por viewport ou adaptativo por container.
|
|
50
50
|
// SOMATIVO por construção: valor simples continua emitindo `btn-sm`, byte por byte a mesma classe
|
|
51
51
|
// de antes, e por isso nenhuma baseline se mexe. Só o valor responsivo entra pela camada genérica
|
|
@@ -53,7 +53,7 @@ export const Button = forwardRef(function Button({ variant, appearance, tone, si
|
|
|
53
53
|
// Quem decide é o CSS: nada aqui observa largura, e o HTML do servidor já sai correto.
|
|
54
54
|
const responsivo = ehResponsivo(size);
|
|
55
55
|
const base = valorBase(size) ?? "md";
|
|
56
|
-
const cls = cx("btn", buttonSkin(variant, appearance, tone), responsivo ? classesResponsivas("size", size) : (base !== "md" && `btn-${base}`), fullWidth && "btn-block", className);
|
|
56
|
+
const cls = cx("btn", buttonSkin(variant, appearance, tone), responsivo ? classesResponsivas("size", size) : (base !== "md" && `btn-${base}`), fullWidth && "btn-block", grow && "btn-grow", className);
|
|
57
57
|
// kbd dentro do botão: mostra o atalho E o anuncia (aria-keyshortcuts), senão é enfeite.
|
|
58
58
|
const inner = _jsxs(_Fragment, { children: [loading && _jsx("span", { className: "spinner" }), leadingIcon && _jsx(Icon, { name: leadingIcon }), _jsx("span", { children: children }), kbd && _jsx(Kbd, { children: kbd }), trailingIcon && _jsx(Icon, { name: trailingIcon })] });
|
|
59
59
|
// INERTE ≠ DESABILITADO, e a diferença é medida (M4, 13/08/2026): `disabled` tira o botão da
|
|
@@ -76,7 +76,7 @@ export const Button = forwardRef(function Button({ variant, appearance, tone, si
|
|
|
76
76
|
const bloqueia = (e) => { e.preventDefault(); e.stopPropagation(); };
|
|
77
77
|
const eventos = (off || inerte) ? { onClick: bloqueia, onClickCapture: bloqueia } : { onClick: onClick, onClickCapture: onClickCapture };
|
|
78
78
|
if (href !== undefined)
|
|
79
|
-
return _jsx("a", { ref: ref, className: cls, ...shared, ...props, ...(off ? { "aria-disabled": true } : { href }), ...eventos, children: inner });
|
|
79
|
+
return _jsx("a", { ref: ref, className: cls, target: target, rel: rel, download: download, ...shared, ...props, ...(off ? { "aria-disabled": true } : { href }), ...eventos, children: inner });
|
|
80
80
|
return _jsx("button", { ref: ref, type: type, className: cls, disabled: off, "aria-disabled": inerte || undefined, "aria-pressed": pressed, ...shared, ...(inerte ? { onClick: bloqueia, onClickCapture: bloqueia } : { onClick, onClickCapture }), ...props, children: inner });
|
|
81
81
|
});
|
|
82
82
|
function temConteudoVisivel(children) {
|
package/dist/inputs-client.d.ts
CHANGED
|
@@ -9,11 +9,17 @@ export interface FieldProps extends HTMLAttributes<HTMLDivElement>, RefAttribute
|
|
|
9
9
|
label: string;
|
|
10
10
|
hint?: ReactNode;
|
|
11
11
|
error?: ReactNode;
|
|
12
|
+
/** B-12 (24/09/2026): texto de ajuda que precisa de uma FRASE — mora embaixo do controle, onde
|
|
13
|
+
* cabe, e não divide a linha do rótulo. O `hint` continua o que é: nota curta ao lado do rótulo
|
|
14
|
+
* ("opcional", "em MB"). É o lugar do `Description` do HeroUI e da `description` que o
|
|
15
|
+
* `Checkbox` desta casa já tem. Entra no `aria-describedby` na ordem da tela: hint, descrição,
|
|
16
|
+
* erro. */
|
|
17
|
+
description?: ReactNode;
|
|
12
18
|
name?: string;
|
|
13
19
|
orientation?: Responsive<FieldOrientation>;
|
|
14
20
|
labelWidth?: FieldLabelWidth;
|
|
15
21
|
}
|
|
16
|
-
export declare function Field({ label, hint, error, children, className, id, name, orientation, labelWidth, style, ...props }: FieldProps): React.JSX.Element;
|
|
22
|
+
export declare function Field({ label, hint, description, error, children, className, id, name, orientation, labelWidth, style, ...props }: FieldProps): React.JSX.Element;
|
|
17
23
|
export declare function Form({ errors, onSubmit, children, className, ...props }: Omit<React.FormHTMLAttributes<HTMLFormElement>, "onSubmit"> & RefAttributes<HTMLFormElement> & {
|
|
18
24
|
errors?: Record<string, string | string[]>;
|
|
19
25
|
onSubmit?: (values: Record<string, unknown>) => void;
|
|
@@ -23,11 +29,14 @@ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
|
|
|
23
29
|
size?: Responsive<FieldSize>;
|
|
24
30
|
}
|
|
25
31
|
export declare const Input: React.ForwardRefExoticComponent<Omit<InputProps, "ref"> & RefAttributes<HTMLInputElement>>;
|
|
26
|
-
export interface SearchFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size">, RefAttributes<HTMLInputElement> {
|
|
32
|
+
export interface SearchFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "width">, RefAttributes<HTMLInputElement> {
|
|
27
33
|
icon?: IconName;
|
|
28
34
|
size?: Responsive<FieldSize>;
|
|
35
|
+
/** A-08 (24/09/2026): a largura do campo — `"20rem"` ou `"auto"`. Sem ela, 100% da linha, como
|
|
36
|
+
* sempre. O `size` muda altura e letra, nunca largura. */
|
|
37
|
+
width?: string;
|
|
29
38
|
}
|
|
30
|
-
export declare function SearchField({ icon, className, size, ...props }: SearchFieldProps): React.JSX.Element;
|
|
39
|
+
export declare function SearchField({ icon, className, size, width, ...props }: SearchFieldProps): React.JSX.Element;
|
|
31
40
|
export declare function NumberField({ value, defaultValue, onValueChange, min, max, step, disabled, readOnly, required, label, id, name, format, locale, className, scrubbable, scrubDirection }: {
|
|
32
41
|
value?: number | null;
|
|
33
42
|
defaultValue?: number;
|
|
@@ -76,7 +85,7 @@ export interface ComboboxOptGroup {
|
|
|
76
85
|
label: string;
|
|
77
86
|
items: ComboboxOption[];
|
|
78
87
|
}
|
|
79
|
-
export declare function Combobox({ items, value, onValueChange, placeholder, label, empty, disabled, size, id, className, "aria-describedby": descrito, "aria-invalid": invalido }: {
|
|
88
|
+
export declare function Combobox({ items, value, onValueChange, placeholder, label, empty, disabled, size, id, className, "aria-describedby": descrito, "aria-invalid": invalido, "aria-label": rotulo }: {
|
|
80
89
|
items: ComboboxOption[] | ComboboxOptGroup[];
|
|
81
90
|
empty?: ReactNode;
|
|
82
91
|
value?: ComboboxOption | null;
|
|
@@ -89,8 +98,11 @@ export declare function Combobox({ items, value, onValueChange, placeholder, lab
|
|
|
89
98
|
className?: string;
|
|
90
99
|
"aria-describedby"?: string;
|
|
91
100
|
"aria-invalid"?: boolean | "true" | "false";
|
|
101
|
+
/** C-01 (24/09/2026): nome para o leitor de tela quando não há `label` visível — um filtro numa
|
|
102
|
+
* grade sem rótulos. Vai direto para o campo. Com `label`, prefira o `label`. */
|
|
103
|
+
"aria-label"?: string;
|
|
92
104
|
}): React.JSX.Element;
|
|
93
|
-
export declare function MultiCombobox({ items, value, onValueChange, onInputChange, loading, placeholder, label, empty, disabled, id, className, "aria-describedby": descrito, "aria-invalid": invalido }: {
|
|
105
|
+
export declare function MultiCombobox({ items, value, onValueChange, onInputChange, loading, placeholder, label, empty, disabled, id, className, "aria-describedby": descrito, "aria-invalid": invalido, "aria-label": rotulo }: {
|
|
94
106
|
items: ComboboxOption[] | ComboboxOptGroup[];
|
|
95
107
|
empty?: ReactNode;
|
|
96
108
|
value?: ComboboxOption[];
|
|
@@ -104,6 +116,9 @@ export declare function MultiCombobox({ items, value, onValueChange, onInputChan
|
|
|
104
116
|
className?: string;
|
|
105
117
|
"aria-describedby"?: string;
|
|
106
118
|
"aria-invalid"?: boolean | "true" | "false";
|
|
119
|
+
/** C-01 (24/09/2026): nome para o leitor de tela quando não há `label` visível — um filtro numa
|
|
120
|
+
* grade sem rótulos. Vai direto para o campo. Com `label`, prefira o `label`. */
|
|
121
|
+
"aria-label"?: string;
|
|
107
122
|
}): React.JSX.Element;
|
|
108
123
|
export interface SelectOption {
|
|
109
124
|
value: string;
|
package/dist/inputs-client.js
CHANGED
|
@@ -79,7 +79,7 @@ function elementoRotulavel(tipo) {
|
|
|
79
79
|
// regra que os outros: recebe `id` e espalha `...props` no `Input`, que é o nó focal.
|
|
80
80
|
return [Input, Select, Textarea, SearchField, PasswordField, Checkbox, Radio, Switch, Range, Combobox, MultiCombobox].includes(tipo);
|
|
81
81
|
}
|
|
82
|
-
export function Field({ label, hint, error, children, className, id, name, orientation, labelWidth, style, ...props }) {
|
|
82
|
+
export function Field({ label, hint, description, error, children, className, id, name, orientation, labelWidth, style, ...props }) {
|
|
83
83
|
const auto = React.useId();
|
|
84
84
|
// Fragment não cria nó no DOM. Um Fragment com um só controle é só sintaxe; com vários,
|
|
85
85
|
// Field precisa voltar para grupo em vez de pendurar `htmlFor` num id que nunca existirá.
|
|
@@ -100,8 +100,9 @@ export function Field({ label, hint, error, children, className, id, name, orien
|
|
|
100
100
|
const idControle = unico?.props.id ?? id ?? `${auto}-control`;
|
|
101
101
|
const idRotulo = `${auto}-label`;
|
|
102
102
|
const idHint = hint ? `${auto}-hint` : undefined;
|
|
103
|
+
const idDescricao = description ? `${auto}-description` : undefined;
|
|
103
104
|
const idErro = error ? `${auto}-error` : undefined;
|
|
104
|
-
const descrito = [idHint, idErro].filter(Boolean).join(" ") || undefined;
|
|
105
|
+
const descrito = [idHint, idDescricao, idErro].filter(Boolean).join(" ") || undefined;
|
|
105
106
|
// As chaves de aria só entram quando têm VALOR. Passar `undefined` explícito não é o mesmo que
|
|
106
107
|
// não passar: quando o filho vira `Field.Control` do motor (ramo do `name`), a prop explícita
|
|
107
108
|
// do elemento vence a mesclagem, e o `aria-invalid` que o motor calculou a partir do erro
|
|
@@ -124,7 +125,7 @@ export function Field({ label, hint, error, children, className, id, name, orien
|
|
|
124
125
|
// árvore de acessibilidade enquanto a frase de erro aparece na tela. Pior que não mostrar.
|
|
125
126
|
const controleFinal = name ? _jsx(BaseField.Control, { render: controle }) : controle;
|
|
126
127
|
const estilo = labelWidth ? { ...style, "--field-label-width": labelWidth === "auto" ? "max-content" : labelWidth } : style;
|
|
127
|
-
const corpo = _jsxs("div", { className: cx("field", peleDoEixo("field", orientation, "vertical", "field"), className), ...(nomeAqui ? {} : { role: "group", "aria-labelledby": idRotulo, ...(rotulavel ? {} : { "aria-describedby": descrito }) }), style: estilo, ...props, children: [_jsxs("span", { className: "label", children: [nomeAqui ? _jsx("label", { htmlFor: idControle, children: label }) : _jsx("span", { id: idRotulo, children: label }), hint && _jsx("span", { className: "hint", id: idHint, children: hint })] }), controleFinal, error && _jsx("span", { className: "field-error", id: idErro, children: error }), name && _jsx(BaseField.Error, { className: "field-error" })] });
|
|
128
|
+
const corpo = _jsxs("div", { className: cx("field", peleDoEixo("field", orientation, "vertical", "field"), className), ...(nomeAqui ? {} : { role: "group", "aria-labelledby": idRotulo, ...(rotulavel ? {} : { "aria-describedby": descrito }) }), style: estilo, ...props, children: [_jsxs("span", { className: "label", children: [nomeAqui ? _jsx("label", { htmlFor: idControle, children: label }) : _jsx("span", { id: idRotulo, children: label }), hint && _jsx("span", { className: "hint", id: idHint, children: hint })] }), controleFinal, description && _jsx("span", { className: "field-description", id: idDescricao, children: description }), error && _jsx("span", { className: "field-error", id: idErro, children: error }), name && _jsx(BaseField.Error, { className: "field-error" })] });
|
|
128
129
|
// `Field.Root` do motor entra SÓ quando há `name`: é ele que liga o campo à chave de `errors`
|
|
129
130
|
// do formulário. Ele não desenha nada — é contexto — então a pele não muda.
|
|
130
131
|
return name ? _jsx(BaseField.Root, { name: name, invalid: error ? true : undefined, render: corpo }) : corpo;
|
|
@@ -162,7 +163,7 @@ export const Input = forwardRef(function Input({ className, formatOnBlur, size,
|
|
|
162
163
|
// `.input-wrap-end` para o botão do PasswordField —, e o grupo é a terceira vez virando uma. O
|
|
163
164
|
// merge das duas linhagens tinha trazido de volta a versão com `.input-wrap`, contra um core
|
|
164
165
|
// que já não a pinta.
|
|
165
|
-
export function SearchField({ icon = "search", className, size, ...props }) { return _jsxs(InputGroup, { className: className, children: [_jsx(InputGroupAddon, { children: _jsx(Icon, { name: icon, size: valorBase(size) === "sm" ? "sm" : undefined }) }), _jsx(Input, { type: "search", size: size, ...props })] }); }
|
|
166
|
+
export function SearchField({ icon = "search", className, size, width, ...props }) { return _jsxs(InputGroup, { className: className, width: width, children: [_jsx(InputGroupAddon, { children: _jsx(Icon, { name: icon, size: valorBase(size) === "sm" ? "sm" : undefined }) }), _jsx(Input, { type: "search", size: size, ...props })] }); }
|
|
166
167
|
// labelHidden: coluna de seleção de tabela precisa do rótulo POR LINHA para o leitor de
|
|
167
168
|
// tela ("Select Analyst"), mas mostrá-lo engorda a coluna. O rótulo continua no DOM, só
|
|
168
169
|
// sai da tela (.sr-only) — nunca trocar por aria-label solto num <label> visível vazio.
|
|
@@ -253,12 +254,12 @@ const listaCombobox = (items) => _jsx(BaseCombobox.List, { children: ehAgrupado(
|
|
|
253
254
|
// `disabled` vai na ROOT, não no Input: `Input`, `Trigger`, `Clear` e `ChipRemove` leem todos o
|
|
254
255
|
// mesmo `selectors.disabled` do store do Base UI (@base-ui/react 1.6.0). Desabilitar o Input
|
|
255
256
|
// deixaria os dois botões vivos — abrir a lista de um campo desabilitado é o defeito, não o texto.
|
|
256
|
-
export function Combobox({ items, value, onValueChange, placeholder, label, empty, disabled, size, id, className, "aria-describedby": descrito, "aria-invalid": invalido }) {
|
|
257
|
+
export function Combobox({ items, value, onValueChange, placeholder, label, empty, disabled, size, id, className, "aria-describedby": descrito, "aria-invalid": invalido, "aria-label": rotulo }) {
|
|
257
258
|
const s = useAureaStrings();
|
|
258
259
|
const portal = usePortalContainer();
|
|
259
260
|
const autoId = React.useId();
|
|
260
261
|
const inputId = id ?? autoId;
|
|
261
|
-
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 }), _jsxs("span", { className: "combobox-actions", children: [_jsx(BaseCombobox.Clear, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "close", label: s.comboboxClear }) }), _jsx(BaseCombobox.Trigger, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "chevron--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)] }) }) })] });
|
|
262
|
+
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: "close", label: s.comboboxClear }) }), _jsx(BaseCombobox.Trigger, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "chevron--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)] }) }) })] });
|
|
262
263
|
}
|
|
263
264
|
// MultiCombobox (Fase 4): multi-seleção com chips, opções agrupadas e filtro
|
|
264
265
|
// externo (async). Reusa .combobox-popup/-item/-empty do básico.
|
|
@@ -267,13 +268,13 @@ export function Combobox({ items, value, onValueChange, placeholder, label, empt
|
|
|
267
268
|
// - Async: passar onInputChange; o filtro interno do Base UI desliga
|
|
268
269
|
// (filter={null}) e o consumidor troca os items conforme a busca retorna.
|
|
269
270
|
// loading só troca o texto do vazio para não piscar "Nenhum resultado".
|
|
270
|
-
export function MultiCombobox({ items, value, onValueChange, onInputChange, loading, placeholder, label, empty, disabled, id, className, "aria-describedby": descrito, "aria-invalid": invalido }) {
|
|
271
|
+
export function MultiCombobox({ items, value, onValueChange, onInputChange, loading, placeholder, label, empty, disabled, id, className, "aria-describedby": descrito, "aria-invalid": invalido, "aria-label": rotulo }) {
|
|
271
272
|
const s = useAureaStrings();
|
|
272
273
|
const portal = usePortalContainer();
|
|
273
274
|
const autoId = React.useId();
|
|
274
275
|
const inputId = id ?? autoId;
|
|
275
276
|
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")
|
|
276
|
-
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: "close", size: "sm" }) })] }, item.value)), _jsx(BaseCombobox.Input, { id: inputId, placeholder: selected.length ? undefined : placeholder, className: "combobox-chip-input", "aria-describedby": descrito, "aria-invalid": invalido })] }) }) }), _jsxs("span", { className: "combobox-actions", children: [_jsx(BaseCombobox.Clear, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "close", label: s.comboboxClear }) }), _jsx(BaseCombobox.Trigger, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "chevron--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)] }) }) })] });
|
|
277
|
+
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: "close", 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: "close", label: s.comboboxClear }) }), _jsx(BaseCombobox.Trigger, { render: _jsx(IconButton, { variant: "ghost", size: "sm", icon: "chevron--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)] }) }) })] });
|
|
277
278
|
}
|
|
278
279
|
const ehGrupoDoSelect = (i) => typeof i === "object" && i != null && "items" in i;
|
|
279
280
|
// Lê `<option>`/`<optgroup>` como o navegador lê: `value` ausente vale o TEXTO da opção.
|
package/dist/layout-client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type HTMLAttributes, type RefAttributes, type ReactNode } from "react";
|
|
2
2
|
import { type Orientation, type Responsive } from "./pure.js";
|
|
3
3
|
import { type TopbarVariant, type SidebarVariant, type SidebarItem } from "./navigation.js";
|
|
4
|
-
export declare function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant, sidebarVariant, sidebarCollapsed, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
4
|
+
export declare function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant, topbarDivider, sidebarVariant, sidebarCollapsed, contentVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
5
5
|
brand: ReactNode;
|
|
6
6
|
navigation?: ReactNode;
|
|
7
7
|
navItems?: SidebarItem[];
|
|
@@ -9,9 +9,13 @@ export declare function AppShell({ brand, navigation, navItems, currentNavId, na
|
|
|
9
9
|
navLabel?: string;
|
|
10
10
|
topbar?: ReactNode;
|
|
11
11
|
topbarVariant?: Exclude<TopbarVariant, "pill">;
|
|
12
|
+
topbarDivider?: boolean;
|
|
12
13
|
sidebarVariant?: SidebarVariant;
|
|
13
14
|
sidebarCollapsed?: boolean;
|
|
15
|
+
contentVariant?: "surface" | "plain";
|
|
14
16
|
}): import("react").JSX.Element;
|
|
15
|
-
export
|
|
17
|
+
export type SeparatorSpacing = "none" | "tight" | "normal" | "loose";
|
|
18
|
+
export declare function Separator({ orientation, spacing, className, ...props }: HTMLAttributes<HTMLHRElement> & RefAttributes<HTMLHRElement> & {
|
|
16
19
|
orientation?: Responsive<Orientation>;
|
|
20
|
+
spacing?: SeparatorSpacing;
|
|
17
21
|
}): import("react").JSX.Element;
|
package/dist/layout-client.js
CHANGED
|
@@ -116,36 +116,20 @@ function useGavetaFechaNoDesktop() {
|
|
|
116
116
|
// texto ("8.174" virava "8.17"), medido num app real a 1400px. `navItems`/`currentNavId` vão para o
|
|
117
117
|
// Sidebar que o shell já cria, e a caixa dupla deixa de ser o único caminho. `navigation` continua
|
|
118
118
|
// valendo para quem escreve a navegação à mão, e as duas se somam: a lista vem antes.
|
|
119
|
-
|
|
119
|
+
// B-10 (24/09/2026): `contentVariant="plain"` tira a caixa do `.content`. Ela é um cartão (mesmo
|
|
120
|
+
// fundo, borda e raio do `.card`), e todo `Card` lá dentro virava caixa dentro de caixa igual — um
|
|
121
|
+
// app gastou 14 `!important` para apagá-la. `surface`, a caixa, continua o padrão.
|
|
122
|
+
// B-07: `topbarDivider` repassa a linha de baixo para a barra `flush` que o shell monta.
|
|
123
|
+
export function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant = "floating", topbarDivider, sidebarVariant, sidebarCollapsed, contentVariant = "surface", children, className, ...props }) {
|
|
120
124
|
const s = useAureaStrings();
|
|
121
125
|
useGavetaFechaNoDesktop();
|
|
122
|
-
return _jsxs("div", { className: cx("app-shell", topbarVariant === "flush" && "app-shell-flush", className), ...props, children: [_jsx("a", { className: "skip-link", href: `#${SHELL_MAIN_ID}`, children: s.skipToContent }), _jsx(Topbar, { variant: topbarVariant, brand: _jsxs(_Fragment, { children: [_jsx(IconButton, { className: "nav-toggle", icon: "menu", label: s.navigationToggle, popoverTarget: SHELL_NAV_ID }), brand] }), children: topbar }), _jsx(Sidebar, { id: SHELL_NAV_ID, popover: "auto", variant: sidebarVariant, collapsed: sidebarCollapsed, items: navItems, current: currentNavId, label: navLabel, onToggle: focoDaGaveta, children: navigation }), _jsx("main", { id: SHELL_MAIN_ID, tabIndex: -1, className: "content", children: children })] });
|
|
126
|
+
return _jsxs("div", { className: cx("app-shell", topbarVariant === "flush" && "app-shell-flush", className), ...props, children: [_jsx("a", { className: "skip-link", href: `#${SHELL_MAIN_ID}`, children: s.skipToContent }), _jsx(Topbar, { variant: topbarVariant, divider: topbarDivider, brand: _jsxs(_Fragment, { children: [_jsx(IconButton, { className: "nav-toggle", icon: "menu", label: s.navigationToggle, popoverTarget: SHELL_NAV_ID }), brand] }), children: topbar }), _jsx(Sidebar, { id: SHELL_NAV_ID, popover: "auto", variant: sidebarVariant, collapsed: sidebarCollapsed, items: navItems, current: currentNavId, label: navLabel, onToggle: focoDaGaveta, children: navigation }), _jsx("main", { id: SHELL_MAIN_ID, tabIndex: -1, className: cx("content", contentVariant === "plain" && "content-plain"), children: children })] });
|
|
123
127
|
}
|
|
124
|
-
|
|
125
|
-
// A LINHA DO SISTEMA, e ela é de CLIENTE por necessidade, não por vizinhança.
|
|
126
|
-
//
|
|
127
|
-
// Ela já foi um <hr> com orientação estática, no `markup.tsx`. O merge das duas linhagens ficou
|
|
128
|
-
// com essa versão, e o gate `comportamental.multi-motor.spec.ts` reprovou: a prova das cinco
|
|
129
|
-
// capacidades do `G-AXIS-06` — a lista que o Victor especificou — cobra do separador
|
|
130
|
-
// `data-orientation` E `aria-orientation` resolvidos pela largura do CONTÊINER, e os dois são
|
|
131
|
-
// atributo. Atributo não sai de classe CSS. Eixo comportamental precisa de runtime.
|
|
132
|
-
//
|
|
133
|
-
// E O ELEMENTO CONTINUA SENDO UM <hr>. As duas exigências pareciam brigar — a suíte de unidade
|
|
134
|
-
// cobra `<hr>` sem `role` escrito ("ARIA redundante é pior que ARIA nenhuma", aviso do próprio
|
|
135
|
-
// APG), e a prova de contêiner cobra atributo resolvido em runtime. `render` resolve as duas:
|
|
136
|
-
// o motor calcula e publica sobre o elemento que a Aurea escolhe.
|
|
137
|
-
//
|
|
138
|
-
// `role={undefined}` e o `aria-orientation` explícito são o acerto fino, e foram MEDIDOS antes
|
|
139
|
-
// de escrever: por padrão o motor escreve `role="separator"` no <hr> (redundante — o <hr> já É
|
|
140
|
-
// separator) e escreve `aria-orientation` também no HORIZONTAL, que é o default implícito do
|
|
141
|
-
// papel. As duas props passadas aqui vencem as do motor, e sobra exatamente o que se quer:
|
|
142
|
-
// vertical → <hr data-orientation="vertical" aria-orientation="vertical" class="separator separator-vertical">
|
|
143
|
-
// horizontal → <hr data-orientation="horizontal" class="separator">
|
|
144
|
-
export function Separator({ orientation, className, ...props }) {
|
|
128
|
+
export function Separator({ orientation, spacing = "none", className, ...props }) {
|
|
145
129
|
const ancora = useRef(null);
|
|
146
130
|
const resolvida = useValorResponsivo(orientation, "horizontal", ancora);
|
|
147
131
|
// O elenco existe porque o tipo do motor descreve os manipuladores sobre `HTMLDivElement` — ele
|
|
148
132
|
// não sabe que o `render` troca o elemento. O tipo PÚBLICO desta função é o certo: quem passar um
|
|
149
133
|
// `ref` recebe o <hr> que está de fato no DOM.
|
|
150
|
-
return _jsx(BaseSeparator, { ref: ancora, orientation: resolvida, render: _jsx("hr", {}), role: undefined, "aria-orientation": resolvida === "vertical" ? "vertical" : undefined, className: cx("separator", resolvida === "vertical" && "separator-vertical", className), ...props });
|
|
134
|
+
return _jsx(BaseSeparator, { ref: ancora, orientation: resolvida, render: _jsx("hr", {}), role: undefined, "aria-orientation": resolvida === "vertical" ? "vertical" : undefined, className: cx("separator", resolvida === "vertical" && "separator-vertical", spacing !== "none" && `separator-space-${spacing}`, className), ...props });
|
|
151
135
|
}
|
package/dist/markup.d.ts
CHANGED
|
@@ -4,7 +4,10 @@ import type { ComponentSize } from "./actions.js";
|
|
|
4
4
|
export type BadgeVariant = "neutral" | "primary" | "info" | "success" | "warning" | "danger" | "running" | "paused" | "offline" | "review";
|
|
5
5
|
export type AvatarSize = "sm" | "md" | "lg";
|
|
6
6
|
export type TopbarVariant = "floating" | "flush" | "pill";
|
|
7
|
-
type CardBase = HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement
|
|
7
|
+
type CardBase = HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
8
|
+
padding?: "normal" | "none";
|
|
9
|
+
orientation?: "vertical" | "horizontal";
|
|
10
|
+
};
|
|
8
11
|
export type CardProps = CardBase & ({
|
|
9
12
|
variant?: "base" | "raised" | "inset" | "selected" | "danger";
|
|
10
13
|
render?: ReactElement;
|
|
@@ -12,10 +15,50 @@ export type CardProps = CardBase & ({
|
|
|
12
15
|
variant: "interactive";
|
|
13
16
|
render: ReactElement;
|
|
14
17
|
});
|
|
15
|
-
export declare function Card({ variant, className, render, ...props }: CardProps): ReactElement<unknown, string | React.JSXElementConstructor<any>>;
|
|
16
|
-
export declare
|
|
17
|
-
export
|
|
18
|
-
|
|
18
|
+
export declare function Card({ variant, padding, orientation, className, render, ...props }: CardProps): ReactElement<unknown, string | React.JSXElementConstructor<any>>;
|
|
19
|
+
export declare namespace Card {
|
|
20
|
+
export { CardMedia as Media };
|
|
21
|
+
}
|
|
22
|
+
/** A mídia do cartão — a primeira das partes da especificação do `Card` (A-14). No vertical,
|
|
23
|
+
* primeira filha, ela SANGRA até a borda de cima e dos lados; no horizontal, fica à esquerda com a
|
|
24
|
+
* largura de miniatura, dentro do respiro, com o raio que sai da conta da casa (ADR-0033: raio do
|
|
25
|
+
* cartão menos o respiro dele). O que vai dentro — `Image`, vídeo — é do app. */
|
|
26
|
+
declare function CardMedia({ className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement>): React.JSX.Element;
|
|
27
|
+
export type LayoutGap = "tight" | "normal" | "loose";
|
|
28
|
+
export type StackAlign = "start" | "center" | "end" | "stretch";
|
|
29
|
+
export type ClusterAlign = "start" | "center" | "end" | "baseline";
|
|
30
|
+
export type ClusterJustify = "start" | "center" | "end" | "between";
|
|
31
|
+
type DivProps = HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement>;
|
|
32
|
+
export interface StackProps extends DivProps {
|
|
33
|
+
/** `tight` (--space-2), `normal` (o de sempre, --space-4) ou `loose` (--space-6). */
|
|
34
|
+
gap?: LayoutGap;
|
|
35
|
+
/** Eixo cruzado. Padrão `stretch`: os filhos ocupam a largura, como sempre. */
|
|
36
|
+
align?: StackAlign;
|
|
37
|
+
}
|
|
38
|
+
export declare function Stack({ gap, align, className, ...props }: StackProps): React.JSX.Element;
|
|
39
|
+
export interface ClusterProps extends DivProps {
|
|
40
|
+
/** `tight` (--space-2), `normal` (o de sempre, --space-3) ou `loose` (--space-6). */
|
|
41
|
+
gap?: LayoutGap;
|
|
42
|
+
/** Eixo cruzado (o vertical). Padrão `center`, como sempre. */
|
|
43
|
+
align?: ClusterAlign;
|
|
44
|
+
/** Eixo principal. `between` espalha o que sobrar: o nome à esquerda, o botão à direita. */
|
|
45
|
+
justify?: ClusterJustify;
|
|
46
|
+
/** Padrão `true`: a fila quebra linha. `false` mantém tudo numa linha só. */
|
|
47
|
+
wrap?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare function Cluster({ gap, align, justify, wrap, className, ...props }: ClusterProps): React.JSX.Element;
|
|
50
|
+
export interface GridProps extends DivProps {
|
|
51
|
+
/** `tight` (--space-2), `normal` (o de sempre, --space-4) ou `loose` (--space-6). */
|
|
52
|
+
gap?: LayoutGap;
|
|
53
|
+
/**
|
|
54
|
+
* Largura mínima de cada coluna, em unidade de CSS (`"10rem"`, `"155px"`). Padrão `15rem`. É o
|
|
55
|
+
* `--grid-min` que o CSS sempre leu e que nenhum tipo mostrava.
|
|
56
|
+
*/
|
|
57
|
+
min?: string;
|
|
58
|
+
/** Número fixo de colunas, iguais. Com ele, `min` deixa de valer. */
|
|
59
|
+
columns?: number;
|
|
60
|
+
}
|
|
61
|
+
export declare function Grid({ gap, min, columns, className, style, ...props }: GridProps): React.JSX.Element;
|
|
19
62
|
export declare function KPI({ label, value, trend, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
20
63
|
label: ReactNode;
|
|
21
64
|
value: ReactNode;
|
|
@@ -90,9 +133,10 @@ export declare function LogStream({ lines }: {
|
|
|
90
133
|
}>;
|
|
91
134
|
}): React.JSX.Element;
|
|
92
135
|
export declare function MediaPlayerShell({ children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement>): React.JSX.Element;
|
|
93
|
-
export declare function Topbar({ variant, brand, children, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
|
|
136
|
+
export declare function Topbar({ variant, divider, brand, children, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
|
|
94
137
|
variant?: TopbarVariant;
|
|
95
138
|
brand?: ReactNode;
|
|
139
|
+
divider?: boolean;
|
|
96
140
|
}): React.JSX.Element;
|
|
97
141
|
export declare function Kbd({ children, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement>): React.JSX.Element;
|
|
98
142
|
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, RefAttributes<HTMLTextAreaElement> {
|
|
@@ -123,7 +167,9 @@ export declare function Label({ htmlFor, className, children, ...props }: HTMLAt
|
|
|
123
167
|
}): React.JSX.Element;
|
|
124
168
|
export type AddonSide = "start" | "end";
|
|
125
169
|
export type AddonLayout = "inline" | "block";
|
|
126
|
-
export declare function InputGroup({ className, children, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement>
|
|
170
|
+
export declare function InputGroup({ className, children, width, style, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
171
|
+
width?: string;
|
|
172
|
+
}): React.JSX.Element;
|
|
127
173
|
export declare function InputGroupAddon({ side, layout, className, children, ...props }: HTMLAttributes<HTMLSpanElement> & RefAttributes<HTMLSpanElement> & {
|
|
128
174
|
side?: AddonSide;
|
|
129
175
|
layout?: Responsive<AddonLayout>;
|
package/dist/markup.js
CHANGED
|
@@ -37,39 +37,23 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
37
37
|
// tocar motor. Na dúvida, ele NÃO entra — cliente a mais é lento, servidor a mais é quebrado.
|
|
38
38
|
import React, { forwardRef } from "react";
|
|
39
39
|
import { cx, fundirRender, peleDoEixo } from "./pure.js";
|
|
40
|
-
export function Card({ variant = "base", className, render, ...props }) {
|
|
41
|
-
return fundirRender(render, { className: cx("card", variant !== "base" && `card-${variant}`, className), ...props });
|
|
40
|
+
export function Card({ variant = "base", padding = "normal", orientation = "vertical", className, render, ...props }) {
|
|
41
|
+
return fundirRender(render, { className: cx("card", variant !== "base" && `card-${variant}`, padding === "none" && "card-flush", orientation === "horizontal" && "card-horizontal", className), ...props });
|
|
42
|
+
}
|
|
43
|
+
/** A mídia do cartão — a primeira das partes da especificação do `Card` (A-14). No vertical,
|
|
44
|
+
* primeira filha, ela SANGRA até a borda de cima e dos lados; no horizontal, fica à esquerda com a
|
|
45
|
+
* largura de miniatura, dentro do respiro, com o raio que sai da conta da casa (ADR-0033: raio do
|
|
46
|
+
* cartão menos o respiro dele). O que vai dentro — `Image`, vídeo — é do app. */
|
|
47
|
+
function CardMedia({ className, ...props }) { return _jsx("div", { className: cx("card-media", className), ...props }); }
|
|
48
|
+
Card.Media = CardMedia;
|
|
49
|
+
export function Stack({ gap, align, className, ...props }) { return _jsx("div", { className: cx("stack", gap && gap !== "normal" && `stack-gap-${gap}`, align && align !== "stretch" && `stack-align-${align}`, className), ...props }); }
|
|
50
|
+
export function Cluster({ gap, align, justify, wrap, className, ...props }) { return _jsx("div", { className: cx("cluster", gap && gap !== "normal" && `cluster-gap-${gap}`, align && align !== "center" && `cluster-align-${align}`, justify && justify !== "start" && `cluster-justify-${justify}`, wrap === false && "cluster-nowrap", className), ...props }); }
|
|
51
|
+
export function Grid({ gap, min, columns, className, style, ...props }) {
|
|
52
|
+
const vars = min != null || columns != null
|
|
53
|
+
? { ...(min != null ? { "--grid-min": min } : {}), ...(columns != null ? { "--grid-cols": String(columns) } : {}), ...style }
|
|
54
|
+
: style;
|
|
55
|
+
return _jsx("div", { className: cx("grid", gap && gap !== "normal" && `grid-gap-${gap}`, columns != null && "grid-fixed", className), style: vars, ...props });
|
|
42
56
|
}
|
|
43
|
-
export function Stack({ className, ...props }) { return _jsx("div", { className: cx("stack", className), ...props }); }
|
|
44
|
-
// SEPARATOR — a régua entre coisas. Faltava: a Aurea só tinha `.prose hr` (preso à prosa) e o
|
|
45
|
-
// `ToolbarSeparator` (preso ao Toolbar). Untitled UI precisa dela para a variante de seções da
|
|
46
|
-
// lateral, e ela serve em todo lugar.
|
|
47
|
-
//
|
|
48
|
-
// É `<hr>`, e isso é decisão medida em 18/08/2026. O motor que já usamos ENTREGA um `Separator` —
|
|
49
|
-
// mas ele é `'use client'`, usa hook (`useRenderElement`) e o que produz são DOIS atributos:
|
|
50
|
-
// `role="separator"` e `aria-orientation`. Importá-lo arrastaria este módulo para o lado cliente,
|
|
51
|
-
// que é o defeito da ADR-0026 (o `Card` custou 118,5 KB atravessando essa fronteira). Aqui a regra
|
|
52
|
-
// "se o motor entrega, não escrevemos" (BUILDING.md passo 2) PERDE para a fronteira — e o registro
|
|
53
|
-
// existe para a próxima sessão não "corrigir" isto de volta.
|
|
54
|
-
//
|
|
55
|
-
// `<hr>` nativo JÁ TEM `role="separator"` implícito, então escrever o papel seria ARIA redundante —
|
|
56
|
-
// e o APG avisa que ARIA a mais é pior que ARIA nenhuma. O papel `separator` também tem orientação
|
|
57
|
-
// HORIZONTAL por padrão: por isso `aria-orientation` só aparece quando é vertical.
|
|
58
|
-
//
|
|
59
|
-
// O que NÃO entrou, pelo passo 5: as três tonalidades do HeroUI (`secondary`/`tertiary`) — a Aurea
|
|
60
|
-
// tem um `--border` e inventar escala de tom aqui seria copiar o sistema de token deles. E o
|
|
61
|
-
// separador COM RÓTULO no meio ("or", uma data numa conversa), que eles têm em
|
|
62
|
-
// `separator__container` + `__line` + `__content`: é outra estrutura (o `<hr>` não carrega texto),
|
|
63
|
-
// ninguém pediu ainda, e fica registrado aqui como o próximo degrau se alguém precisar.
|
|
64
|
-
// O `Separator` SAIU daqui em 29/08/2026, e a razão é o gate que provou a decisão errada.
|
|
65
|
-
// Ele era um <hr> com orientação estática, e o `comportamental.multi-motor.spec.ts` — a prova
|
|
66
|
-
// das cinco capacidades que o Victor especificou no G-AXIS-06 — cobra dele `data-orientation`
|
|
67
|
-
// e `aria-orientation` RESOLVIDOS por largura de contêiner. Isso é eixo COMPORTAMENTAL: não
|
|
68
|
-
// sai de classe CSS, precisa de runtime, e runtime precisa de hook. Um componente que precisa
|
|
69
|
-
// de hook é de cliente, e é isso que a ADR-0026 manda — ela separa quem PRECISA do cliente de
|
|
70
|
-
// quem só caiu num módulo com a diretiva. Mora no `layout-client.tsx`.
|
|
71
|
-
export function Cluster({ className, ...props }) { return _jsx("div", { className: cx("cluster", className), ...props }); }
|
|
72
|
-
export function Grid({ className, ...props }) { return _jsx("div", { className: cx("grid", className), ...props }); }
|
|
73
57
|
// ── Data Display ─────────────────────────────────────────────────────────────────────────────
|
|
74
58
|
export function KPI({ label, value, trend, className, ...props }) { return _jsxs(Card, { className: cx("kpi", className), ...props, children: [_jsx("span", { className: "muted", children: label }), _jsx("strong", { children: value }), trend && _jsx("small", { children: trend })] }); }
|
|
75
59
|
export function DataList({ items }) { return _jsx("dl", { className: "data-list", children: items.map((i, n) => _jsxs(React.Fragment, { children: [_jsx("dt", { children: i.term }), _jsx("dd", { children: i.value })] }, n)) }); }
|
|
@@ -121,7 +105,10 @@ export function LogStream({ lines }) { return _jsx("div", { className: "log-stre
|
|
|
121
105
|
// ── Media ────────────────────────────────────────────────────────────────────────────────────
|
|
122
106
|
export function MediaPlayerShell({ children, className, ...props }) { return _jsx("div", { className: cx("media-player", className), ...props, children: children }); }
|
|
123
107
|
// ── Navigation ───────────────────────────────────────────────────────────────────────────────
|
|
124
|
-
|
|
108
|
+
// B-07 (24/09/2026): `divider` põe a linha de baixo na `flush`. Ela é fundo igual ao da página e
|
|
109
|
+
// gruda no topo; sem linha, o conteúdo passa por baixo dela e nada diz onde a barra acaba. Só na
|
|
110
|
+
// `flush`: a `floating` e a `pill` são caixas com borda própria.
|
|
111
|
+
export function Topbar({ variant = "floating", divider, brand, children, className, ...props }) { return _jsxs("header", { className: cx("topbar", `topbar-${variant}`, divider && variant === "flush" && "topbar-divider", className), ...props, children: [brand != null && _jsx("div", { className: "brand", children: brand }), children] }); }
|
|
125
112
|
// ── System / interno ─────────────────────────────────────────────────────────────────────────
|
|
126
113
|
// Kbd — representação de tecla/atalho. <kbd> é o elemento HTML certo; a pele é nossa. Ele já
|
|
127
114
|
// morava fora da casa dele (no `internal.tsx`, por causa do `Button`); agora mora aqui, pelo
|
|
@@ -148,12 +135,15 @@ function ladoDoAdorno(no) {
|
|
|
148
135
|
const p = no.props;
|
|
149
136
|
return no.type === InputGroupAddon ? (p.side ?? "start") : null;
|
|
150
137
|
}
|
|
151
|
-
|
|
138
|
+
// A-08 (24/09/2026): `width` tira o grupo dos 100% — `"20rem"` para uma medida, `"auto"` para o
|
|
139
|
+
// tamanho do conteúdo. Sem ela, 100% como sempre. Com ela, o grupo também deixa de crescer numa
|
|
140
|
+
// fila (`flex:none`): o `flex:1` que as barras dão a ele desfaria a medida pedida.
|
|
141
|
+
export function InputGroup({ className, children, width, style, ...props }) {
|
|
152
142
|
const filhos = React.Children.toArray(children);
|
|
153
143
|
const inicio = filhos.filter(f => ladoDoAdorno(f) === "start");
|
|
154
144
|
const fim = filhos.filter(f => ladoDoAdorno(f) === "end");
|
|
155
145
|
const meio = filhos.filter(f => ladoDoAdorno(f) === null);
|
|
156
|
-
return _jsx("div", { className: cx("input-group", className), ...props, children: [...inicio, ...meio, ...fim] });
|
|
146
|
+
return _jsx("div", { className: cx("input-group", className), style: width != null ? { inlineSize: width, flex: "none", ...style } : style, ...props, children: [...inicio, ...meio, ...fim] });
|
|
157
147
|
}
|
|
158
148
|
// `layout` é responsivo, e a triagem que o autorizou está no `G-AXIS-07`: com o adorno em linha,
|
|
159
149
|
// a 200px de caixa sobram 48% da largura para o campo; com ele em faixa, 99%. Não é preferência
|
package/dist/overlays.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import React, { type ReactNode, type ReactElement } from "react";
|
|
2
2
|
import { type Responsive } from "./pure.js";
|
|
3
3
|
import { type IconName } from "./system.js";
|
|
4
|
-
export
|
|
4
|
+
export type DialogSize = "xs" | "sm" | "md" | "lg" | "xl" | "full";
|
|
5
|
+
export declare function Dialog({ open, title, children, footer, onClose, size, dismissible }: {
|
|
5
6
|
open: boolean;
|
|
6
7
|
title: ReactNode;
|
|
7
8
|
children: ReactNode;
|
|
8
9
|
footer?: ReactNode;
|
|
9
10
|
onClose: () => void;
|
|
11
|
+
size?: DialogSize;
|
|
12
|
+
dismissible?: boolean;
|
|
10
13
|
}): React.JSX.Element;
|
|
11
14
|
export declare function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, destructive, onConfirm, onCancel }: {
|
|
12
15
|
open: boolean;
|
package/dist/overlays.js
CHANGED
|
@@ -16,8 +16,12 @@ import { cx, useAureaStrings, usePortalContainer } from "./internal.js";
|
|
|
16
16
|
import { useValorResponsivo } from "./responsivo-runtime.js";
|
|
17
17
|
import { Icon } from "./system.js";
|
|
18
18
|
import { Button } from "./actions.js";
|
|
19
|
-
export function Dialog({ open, title, children, footer, onClose
|
|
20
|
-
|
|
19
|
+
export function Dialog({ open, title, children, footer, onClose, size = "md", dismissible = true }) {
|
|
20
|
+
const s = useAureaStrings();
|
|
21
|
+
const portal = usePortalContainer();
|
|
22
|
+
return _jsx(BaseDialog.Root, { open: open, disablePointerDismissal: !dismissible, onOpenChange: o => { if (!o && dismissible)
|
|
23
|
+
onClose(); }, children: _jsxs(BaseDialog.Portal, { container: portal, children: [_jsx(BaseDialog.Backdrop, { className: "dialog-backdrop" }), _jsxs(BaseDialog.Popup, { className: cx("dialog", size !== "md" && `dialog-${size}`), children: [_jsxs("header", { children: [_jsx(BaseDialog.Title, { render: _jsx("h2", {}), children: title }), _jsx(BaseDialog.Close, { className: "btn btn-ghost btn-icon", "aria-label": s.close, disabled: !dismissible, children: _jsx(Icon, { name: "close" }) })] }), _jsx("div", { className: "dialog-body", children: children }), footer && _jsx("footer", { children: footer })] })] }) });
|
|
24
|
+
}
|
|
21
25
|
// ConfirmDialog (M5): a decisão que não se fecha por engano. NÃO é um Dialog com dois botões —
|
|
22
26
|
// é `role="alertdialog"`, e a diferença é de comportamento, não de aparência: o Base UI tira do
|
|
23
27
|
// AlertDialog.Root as props `modal` e `disablePointerDismissal` (medido no d.ts de 1.6.0), ou
|