@aurea-uds/react 0.4.0 → 0.6.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 +35 -7
- package/dist/actions.js +76 -7
- package/dist/communication.js +3 -2
- package/dist/data-grid.js +149 -9
- package/dist/disclosure.d.ts +9 -0
- package/dist/disclosure.js +19 -0
- package/dist/escala.d.ts +26 -0
- package/dist/escala.js +17 -0
- package/dist/feedback-client.d.ts +5 -2
- package/dist/feedback-client.js +28 -2
- package/dist/file-input.js +2 -2
- package/dist/graph.js +8 -3
- package/dist/identity-client.d.ts +2 -1
- package/dist/identity-client.js +6 -2
- package/dist/index.d.ts +5 -3
- package/dist/index.js +11 -2
- package/dist/inputs-client.d.ts +28 -11
- package/dist/inputs-client.js +46 -18
- package/dist/inputs.d.ts +1 -0
- package/dist/inputs.js +4 -0
- package/dist/internal.d.ts +23 -2
- package/dist/internal.js +19 -1
- package/dist/layout-client.d.ts +4 -0
- package/dist/layout-client.js +41 -1
- package/dist/layout.d.ts +2 -1
- package/dist/layout.js +3 -1
- package/dist/markup.d.ts +46 -14
- package/dist/markup.js +67 -17
- package/dist/navigation-client.d.ts +8 -2
- package/dist/navigation-client.js +60 -3
- package/dist/overlays.d.ts +79 -4
- package/dist/overlays.js +65 -6
- package/dist/pure.d.ts +98 -0
- package/dist/pure.js +120 -2
- package/dist/qrcode.d.ts +2 -1
- package/dist/qrcode.js +3 -2
- package/dist/responsivo-runtime.d.ts +20 -0
- package/dist/responsivo-runtime.js +201 -0
- package/dist/system.d.ts +12 -4
- package/dist/system.js +46 -4
- package/package.json +1 -1
package/dist/file-input.js
CHANGED
|
@@ -274,7 +274,7 @@ export function FileInput({ accept, maxSize, multiple, onFilesChange, upload, la
|
|
|
274
274
|
const recibo = files.filter(f => f.status === "done" || f.status === "error" || f.status === "canceled");
|
|
275
275
|
const reciboTexto = recibo.map(r => [r.name, r.status, r.finishedAt ?? ""].join(TAB)).join(NL);
|
|
276
276
|
return _jsxs("div", { className: cx("field", className), children: [label && _jsx("label", { className: "label", htmlFor: inputId, children: label }), _jsxs("label", { className: "dropzone", "data-dragging": dragging || undefined, onDragOver: e => { e.preventDefault(); setDragging(true); }, onDragLeave: e => { if (!e.currentTarget.contains(e.relatedTarget))
|
|
277
|
-
setDragging(false); }, onDrop: e => { e.preventDefault(); setDragging(false); add(e.dataTransfer.files); }, children: [_jsx("input", { id: inputId, type: "file", className: "sr-only", accept: accept, multiple: multiple, onChange: e => { add(e.target.files); e.target.value = ""; } }), _jsx(Icon, { name: "cloud--upload", size: "xl", className: "dropzone-icon" }), _jsx("strong", { children: s.fileDropPrompt }), hint && _jsx("span", { className: "dropzone-hint", children: hint })] }), upload && (enviando || pausados) && _jsx("div", { className: "file-queue-actions", children: enviando ? _jsx(Button, { variant: "secondary", size: "sm", leadingIcon: "pause", onClick: pausarTudo, children: s.uploadPause })
|
|
277
|
+
setDragging(false); }, onDrop: e => { e.preventDefault(); setDragging(false); add(e.dataTransfer.files); }, children: [_jsx("input", { id: inputId, type: "file", className: "sr-only", accept: accept, multiple: multiple, "aria-invalid": rejected.length > 0 || undefined, "aria-describedby": rejected.length > 0 ? rejected.map((_, n) => `${inputId}-rejeitado-${n}`).join(" ") : undefined, onChange: e => { add(e.target.files); e.target.value = ""; } }), _jsx(Icon, { name: "cloud--upload", size: "xl", className: "dropzone-icon" }), _jsx("strong", { children: s.fileDropPrompt }), hint && _jsx("span", { className: "dropzone-hint", children: hint })] }), upload && (enviando || pausados) && _jsx("div", { className: "file-queue-actions", children: enviando ? _jsx(Button, { variant: "secondary", size: "sm", leadingIcon: "pause", onClick: pausarTudo, children: s.uploadPause })
|
|
278
278
|
: _jsx(Button, { variant: "secondary", size: "sm", leadingIcon: "play", onClick: retomarTudo, children: s.uploadResume }) }), files.length > 0 && _jsx("ul", { className: "file-list", children: files.map(({ id, file, name, bytes, status, progress = 0, restored, checksum: soma, preview: previa, erro }) => {
|
|
279
279
|
// A barra reusa .progress + .file-progress (largura fixa em classe); só o
|
|
280
280
|
// preenchimento (width %) fica inline, por ser data-driven. Erro reusa
|
|
@@ -283,5 +283,5 @@ export function FileInput({ accept, maxSize, multiple, onFilesChange, upload, la
|
|
|
283
283
|
// pelos docs não altera baseline — a justificativa antiga estava invertida).
|
|
284
284
|
const pct = Math.round(progress * 100);
|
|
285
285
|
return _jsxs("li", { className: "file-item", children: [previa ? _jsx("img", { className: "file-thumb", src: previa, alt: "" }) : _jsx(Icon, { name: "document" }), _jsx("span", { className: "file-name", children: name }), status === "uploading" ? _jsxs(_Fragment, { children: [_jsx("div", { className: "progress file-progress", role: "progressbar", "aria-label": `${s.uploadSending} ${name}`, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": pct, children: _jsx("span", { style: { width: `${pct}%` } }) }), _jsx(IconButton, { variant: "ghost", size: "sm", icon: "pause", label: `${s.uploadPause} ${name}`, onClick: () => pausar(id) }), _jsx(IconButton, { variant: "ghost", size: "sm", icon: "close", label: `${s.uploadCancel} ${name}`, onClick: () => abortId(id) })] }) : status === "paused" ? _jsxs(_Fragment, { children: [_jsxs("span", { className: "file-size", children: [s.uploadPaused, " \u00B7 ", Math.round(progress * 100), "%"] }), _jsx(IconButton, { variant: "ghost", size: "sm", icon: "play", label: `${s.uploadResume} ${name}`, onClick: () => retomar({ id, file, name, bytes, status, progress, restored }) }), _jsx(IconButton, { variant: "ghost", size: "sm", icon: "close", label: `${s.fileRemove} ${name}`, onClick: () => remove(id) })] }) : (status === "error" || status === "canceled") ? _jsxs(_Fragment, { children: [_jsx("span", { className: "field-error", children: erro ?? (status === "error" ? s.uploadError : s.uploadCanceled) }), file && _jsx(IconButton, { variant: "ghost", size: "sm", icon: "restart", label: `${s.uploadRetry} ${name}`, onClick: () => startUpload(id, file) }), _jsx(IconButton, { variant: "ghost", size: "sm", icon: "close", label: `${s.fileRemove} ${name}`, onClick: () => remove(id) })] }) : _jsxs(_Fragment, { children: [status === "done" && _jsx(Icon, { name: "checkmark--filled" }), _jsx("span", { className: "file-size", children: formatSize(bytes) }), soma && _jsx("span", { className: "file-checksum", title: `${s.uploadChecksum}: ${soma}`, children: soma.slice(0, 8) }), _jsx(IconButton, { variant: "ghost", size: "sm", icon: "close", label: `${s.fileRemove} ${name}`, onClick: () => remove(id) })] })] }, id);
|
|
286
|
-
}) }), conflitos.map((c, i) => _jsxs("div", { className: "file-conflict", role: "alert", children: [_jsxs("span", { children: [s.fileConflict, ": ", _jsx("strong", { children: c.file.name })] }), _jsx(Button, { size: "sm", variant: "secondary", onClick: () => resolverConflito(i, "replace"), children: s.fileReplace }), _jsx(Button, { size: "sm", variant: "secondary", onClick: () => resolverConflito(i, "both"), children: s.fileKeepBoth }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => resolverConflito(i, "skip"), children: s.fileSkip })] }, `c${i}`)), recibo.length > 0 && !emVoo && _jsxs("div", { className: "file-receipt", children: [_jsxs("div", { className: "file-receipt-head", children: [_jsx("strong", { children: s.uploadReceipt }), _jsx(Button, { size: "sm", variant: "ghost", leadingIcon: "copy", onClick: () => void navigator.clipboard?.writeText(reciboTexto), children: s.uploadReceiptCopy })] }), _jsx("ul", { children: recibo.map(r => _jsxs("li", { children: [r.name, " \u00B7 ", r.status === "done" ? s.uploadComplete : r.status === "canceled" ? s.uploadCanceled : s.uploadError, r.finishedAt ? ` · ${r.finishedAt}` : ""] }, r.id)) })] }), rejected.map((r, n) => _jsxs("span", { className: "field-error", children: [r.reason, ": ", r.file.name] }, n)), _jsx("span", { className: "sr-only", role: "status", "aria-live": "polite", children: announce })] });
|
|
286
|
+
}) }), conflitos.map((c, i) => _jsxs("div", { className: "file-conflict", role: "alert", children: [_jsxs("span", { children: [s.fileConflict, ": ", _jsx("strong", { children: c.file.name })] }), _jsx(Button, { size: "sm", variant: "secondary", onClick: () => resolverConflito(i, "replace"), children: s.fileReplace }), _jsx(Button, { size: "sm", variant: "secondary", onClick: () => resolverConflito(i, "both"), children: s.fileKeepBoth }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => resolverConflito(i, "skip"), children: s.fileSkip })] }, `c${i}`)), recibo.length > 0 && !emVoo && _jsxs("div", { className: "file-receipt", children: [_jsxs("div", { className: "file-receipt-head", children: [_jsx("strong", { children: s.uploadReceipt }), _jsx(Button, { size: "sm", variant: "ghost", leadingIcon: "copy", onClick: () => void navigator.clipboard?.writeText(reciboTexto), children: s.uploadReceiptCopy })] }), _jsx("ul", { children: recibo.map(r => _jsxs("li", { children: [r.name, " \u00B7 ", r.status === "done" ? s.uploadComplete : r.status === "canceled" ? s.uploadCanceled : s.uploadError, r.finishedAt ? ` · ${r.finishedAt}` : ""] }, r.id)) })] }), rejected.map((r, n) => _jsxs("span", { id: `${inputId}-rejeitado-${n}`, className: "field-error", children: [r.reason, ": ", r.file.name] }, n)), _jsx("span", { className: "sr-only", role: "status", "aria-live": "polite", children: announce })] });
|
|
287
287
|
}
|
package/dist/graph.js
CHANGED
|
@@ -110,9 +110,9 @@ function dispor(nodes, edges) {
|
|
|
110
110
|
function NoAurea({ data }) {
|
|
111
111
|
const d = data;
|
|
112
112
|
const corpo = _jsxs(_Fragment, { children: [_jsx("span", { className: "graph-node-label", children: d.label }), d.kind && _jsx("span", { className: "graph-node-kind", children: d.kind }), d.detail && _jsx("span", { className: "hint", children: d.detail })] });
|
|
113
|
-
return _jsxs("div", { className: "graph-node", "data-selected": d.selecionado || undefined, children: [_jsx(Handle, { type: "target", position: Position.Left, isConnectable:
|
|
113
|
+
return _jsxs("div", { className: "graph-node", "data-selected": d.selecionado || undefined, children: [d.conectavel && _jsx(Handle, { type: "target", position: Position.Left, isConnectable: true, className: "graph-handle" }), d.aoSelecionar
|
|
114
114
|
? _jsx("button", { type: "button", className: "graph-node-body", "aria-pressed": !!d.selecionado, onClick: d.aoSelecionar, children: corpo })
|
|
115
|
-
: _jsx("span", { className: "graph-node-body", children: corpo }), _jsx(Handle, { type: "source", position: Position.Right, isConnectable:
|
|
115
|
+
: _jsx("span", { className: "graph-node-body", children: corpo }), d.conectavel && _jsx(Handle, { type: "source", position: Position.Right, isConnectable: true, className: "graph-handle" })] });
|
|
116
116
|
}
|
|
117
117
|
const TIPOS = { aurea: NoAurea };
|
|
118
118
|
// DependencyGraph — quem depende de quem.
|
|
@@ -146,8 +146,13 @@ export function DependencyGraph({ nodes, edges, label, selectedId, onSelect, con
|
|
|
146
146
|
data: { label: n.label, kind: n.kind, detail: n.detail, selecionado: selectedId === n.id,
|
|
147
147
|
conectavel: !!connectable, aoSelecionar: onSelect ? () => onSelect(n.id) : undefined },
|
|
148
148
|
})), [nodes, automatico, selectedId, onSelect, connectable, onNodeMove]);
|
|
149
|
+
// `selectable:false` na PRÓPRIA aresta, e não só no `elementsSelectable` do `<ReactFlow>`:
|
|
150
|
+
// medido em 29/08/2026, a prop do fluxo não tira a classe `.selectable` da aresta, que é onde
|
|
151
|
+
// o `base.css` do motor põe `cursor:pointer`. A mão de ponteiro prometia um clique que a API
|
|
152
|
+
// da Aurea não atende — `onSelect` é do NÓ, e quem o atende é o <button> do corpo dele.
|
|
149
153
|
const arestasDoMotor = React.useMemo(() => edges.map(e => ({
|
|
150
154
|
id: `${e.from}->${e.to}`, source: e.from, target: e.to, label: e.label, animated: e.animated,
|
|
155
|
+
selectable: false,
|
|
151
156
|
})), [edges]);
|
|
152
157
|
// ── A MEDIDA TEM DE PODER VOLTAR, e isto foi achado NO NAVEGADOR ───────────────────────
|
|
153
158
|
// A primeira versão passava `nodes` e nenhum `onNodesChange`. O motor aceita calado e o
|
|
@@ -173,6 +178,6 @@ export function DependencyGraph({ nodes, edges, label, selectedId, onSelect, con
|
|
|
173
178
|
// que o `fitView` usa ENQUANTO ninguém mediu. Com o prefixo `initial`, o navegador sobrescreve
|
|
174
179
|
// na primeira medição — passar `width`/`height` direto no ReactFlow fixaria o tamanho e mataria
|
|
175
180
|
// a fluidez. O valor é a extensão do próprio layout, então no servidor o grafo cabe exato.
|
|
176
|
-
return _jsx("div", { className: cx("dependency-graph", className), style: height ? { blockSize: height } : undefined, role: "group", "aria-label": label ?? s.graphLabel, ...props, children: _jsx(ReactFlowProvider, { initialNodes: nosDoMotor, initialEdges: arestasDoMotor, fitView: true, initialWidth: automatico.extensao.larg, initialHeight: automatico.extensao.alt, children: _jsx(ReactFlow, { nodes: nosVivos, onNodesChange: aoMudarNos, edges: arestasDoMotor, nodeTypes: TIPOS, fitView: true, proOptions: { hideAttribution: false }, nodesDraggable: !!onNodeMove, nodesConnectable: !!connectable, elementsSelectable:
|
|
181
|
+
return _jsx("div", { className: cx("dependency-graph", className), style: height ? { blockSize: height } : undefined, role: "group", "aria-label": label ?? s.graphLabel, ...props, children: _jsx(ReactFlowProvider, { initialNodes: nosDoMotor, initialEdges: arestasDoMotor, fitView: true, initialWidth: automatico.extensao.larg, initialHeight: automatico.extensao.alt, children: _jsx(ReactFlow, { nodes: nosVivos, onNodesChange: aoMudarNos, edges: arestasDoMotor, nodeTypes: TIPOS, fitView: true, proOptions: { hideAttribution: false }, nodesDraggable: !!onNodeMove, nodesConnectable: !!connectable, elementsSelectable: false, onNodeDragStop: onNodeMove ? (_, no) => onNodeMove(no.id, no.position) : undefined, onConnect: onConnect ? c => { if (c.source && c.target)
|
|
177
182
|
onConnect({ from: c.source, to: c.target }); } : undefined, children: _jsx(Background, {}) }) }) });
|
|
178
183
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { type Responsive } from "./pure.js";
|
|
1
2
|
import React, { type ReactNode } from "react";
|
|
2
3
|
import type { AvatarSize } from "./markup.js";
|
|
3
4
|
export declare function Avatar({ src, alt, fallback, size, className }: {
|
|
4
5
|
src?: string;
|
|
5
6
|
alt?: string;
|
|
6
7
|
fallback?: ReactNode;
|
|
7
|
-
size?: AvatarSize
|
|
8
|
+
size?: Responsive<AvatarSize>;
|
|
8
9
|
className?: string;
|
|
9
10
|
}): React.JSX.Element;
|
package/dist/identity-client.js
CHANGED
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
// Fase 9 (achado A5): este arquivo saiu do index.tsx de 970 linhas. Um módulo por categoria
|
|
4
4
|
// do registry — a taxonomia já existia e é gateada. A ordem de import entre eles é um DAG:
|
|
5
|
+
import { peleDoEixo } from "./pure.js";
|
|
5
6
|
// internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
6
7
|
import React from "react";
|
|
7
8
|
import { cx } from "./internal.js";
|
|
8
|
-
|
|
9
|
+
// O DEGRAU RESPONSIVO volta (merge de 28/08/2026): a ficha declara `responsive.size` e o
|
|
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
13
|
const [falhou, setFalhou] = React.useState(false);
|
|
10
14
|
React.useEffect(() => { setFalhou(false); }, [src]);
|
|
11
|
-
return _jsx("span", { className: cx("avatar",
|
|
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
16
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
export { cx, defaultStrings, ptBR, defaultSpriteUrl, gridStateToParams, gridStateFromParams, screenStateToParams, screenStateFromParams, universalStates, stateSeverity, type AureaStrings, type GridState, type ScreenState, type UniversalState } from "./pure.js";
|
|
2
|
-
export { useAureaStrings, useSpriteUrl } from "./internal.js";
|
|
3
|
-
export {
|
|
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";
|
|
2
|
+
export { useAureaStrings, useSpriteUrl, useTheme, useDensity } from "./internal.js";
|
|
3
|
+
export { type Responsive, type Breakpoint, type ContainerBreakpoint, type Orientation, ESCALA, ESCALA_CONTAINER } from "./pure.js";
|
|
4
|
+
export { ContainerScope, useValorResponsivo } from "./responsivo-runtime.js";
|
|
5
|
+
export { AspectRatio, InputGroup, InputGroupAddon, Label, Card, Stack, Cluster, Grid, KPI, DataList, Timeline, Prose, Badge, Progress, Skeleton, AvatarGroup, LogStream, MediaPlayerShell, Topbar, Kbd, Select, Textarea, Checkbox, Radio, Switch, Range, formatBadgeCount, type BadgeVariant, type BadgeEmphasis, type BadgeSize, type BadgePlacement, type BadgeProps, type AvatarSize, type TopbarVariant } from "./markup.js";
|
|
4
6
|
export * from "./system.js";
|
|
5
7
|
export * from "./actions.js";
|
|
6
8
|
export * from "./feedback.js";
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,16 @@
|
|
|
29
29
|
// subpath tem a diretiva. Vindo daqui — via `pure.js`, que não tem — a função é
|
|
30
30
|
// chamável dos dois lados. É a mesma razão do `cx`, uma camada acima.
|
|
31
31
|
export { cx, defaultStrings, ptBR, defaultSpriteUrl, gridStateToParams, gridStateFromParams, screenStateToParams, screenStateFromParams, universalStates, stateSeverity } from "./pure.js";
|
|
32
|
-
export { useAureaStrings, useSpriteUrl } from "./internal.js";
|
|
32
|
+
export { useAureaStrings, useSpriteUrl, useTheme, useDensity } from "./internal.js";
|
|
33
|
+
// O EIXO RESPONSIVO (G-AXIS-04/06) — os tipos e a escala saem do `pure.js`, que não tem a
|
|
34
|
+
// diretiva, pela mesma razão do `gridStateToParams` logo acima: resolver um valor responsivo é
|
|
35
|
+
// computação de string, e o servidor precisa dela para emitir a classe certa no HTML.
|
|
36
|
+
export { ESCALA, ESCALA_CONTAINER } from "./pure.js";
|
|
37
|
+
// O contêiner Aurea como PRIMITIVE, e o resolvedor genérico. `ContainerScope` é público porque
|
|
38
|
+
// quem monta o layout precisa declarar o contêiner; `useValorResponsivo` é público porque o
|
|
39
|
+
// eixo comportamental é reutilizável fora dos cinco componentes que o estrearam. Estes DOIS têm
|
|
40
|
+
// a diretiva de propósito: observam o documento.
|
|
41
|
+
export { ContainerScope, useValorResponsivo } from "./responsivo-runtime.js";
|
|
33
42
|
// ── A LINHA DO ITEM O1, e ela é o item inteiro ───────────────────────────────────────────────
|
|
34
43
|
// Estes 22 vêm do `markup.js`, que NÃO tem a diretiva, e por isso chegam como componentes de
|
|
35
44
|
// SERVIDOR. Vinham dos módulos de categoria abaixo, e de lá chegavam como cliente: `Card` é uma
|
|
@@ -42,7 +51,7 @@ export { useAureaStrings, useSpriteUrl } from "./internal.js";
|
|
|
42
51
|
// inteiro). O que muda é de ONDE ele vem — do módulo com a diretiva —, e aí ele volta a chegar
|
|
43
52
|
// como referência de CLIENTE e os 118,5 KB voltam com ele. Não é um erro: é o ganho do item O1
|
|
44
53
|
// se desfazendo em silêncio. É isso, exatamente isso, que o check 35 pega.
|
|
45
|
-
export { Card, Stack, Cluster, Grid,
|
|
54
|
+
export { AspectRatio, InputGroup, InputGroupAddon, Label, Card, Stack, Cluster, Grid, KPI, DataList, Timeline, Prose, Badge, Progress, Skeleton, AvatarGroup, LogStream, MediaPlayerShell, Topbar, Kbd, Select, Textarea, Checkbox, Radio, Switch, Range, formatBadgeCount } from "./markup.js";
|
|
46
55
|
export * from "./system.js";
|
|
47
56
|
export * from "./actions.js";
|
|
48
57
|
export * from "./feedback.js";
|
package/dist/inputs-client.d.ts
CHANGED
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
import React, { type HTMLAttributes, type InputHTMLAttributes, type RefAttributes, type ReactNode } from "react";
|
|
2
|
+
import { type Responsive } from "./pure.js";
|
|
3
|
+
import { type FieldSize } from "./markup.js";
|
|
2
4
|
import { type IconName } from "./system.js";
|
|
3
5
|
export { FileInput, matchesAccept, type FileRejection, type UploadContext, type UploadFn } from "./file-input.js";
|
|
6
|
+
export type FieldOrientation = "vertical" | "horizontal";
|
|
4
7
|
export interface FieldProps extends HTMLAttributes<HTMLDivElement>, RefAttributes<HTMLDivElement> {
|
|
5
8
|
label: string;
|
|
6
9
|
hint?: ReactNode;
|
|
7
10
|
error?: ReactNode;
|
|
8
11
|
name?: string;
|
|
12
|
+
orientation?: Responsive<FieldOrientation>;
|
|
9
13
|
}
|
|
10
|
-
export declare function Field({ label, hint, error, children, className, id, name, ...props }: FieldProps): React.JSX.Element;
|
|
14
|
+
export declare function Field({ label, hint, error, children, className, id, name, orientation, ...props }: FieldProps): React.JSX.Element;
|
|
11
15
|
export declare function Form({ errors, onSubmit, children, className, ...props }: Omit<React.FormHTMLAttributes<HTMLFormElement>, "onSubmit"> & RefAttributes<HTMLFormElement> & {
|
|
12
16
|
errors?: Record<string, string | string[]>;
|
|
13
17
|
onSubmit?: (values: Record<string, unknown>) => void;
|
|
14
18
|
}): React.JSX.Element;
|
|
15
|
-
export interface InputProps extends InputHTMLAttributes<HTMLInputElement>, RefAttributes<HTMLInputElement> {
|
|
19
|
+
export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size">, RefAttributes<HTMLInputElement> {
|
|
16
20
|
formatOnBlur?: (value: string) => string;
|
|
21
|
+
size?: Responsive<FieldSize>;
|
|
17
22
|
}
|
|
18
23
|
export declare const Input: React.ForwardRefExoticComponent<Omit<InputProps, "ref"> & RefAttributes<HTMLInputElement>>;
|
|
19
|
-
export
|
|
24
|
+
export interface SearchFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size">, RefAttributes<HTMLInputElement> {
|
|
20
25
|
icon?: IconName;
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
size?: Responsive<FieldSize>;
|
|
27
|
+
}
|
|
28
|
+
export declare function SearchField({ icon, className, size, ...props }: SearchFieldProps): React.JSX.Element;
|
|
29
|
+
export declare function NumberField({ value, defaultValue, onValueChange, min, max, step, disabled, readOnly, required, label, id, name, format, locale, className, scrubbable, scrubDirection }: {
|
|
23
30
|
value?: number | null;
|
|
24
31
|
defaultValue?: number;
|
|
25
32
|
onValueChange?: (v: number | null) => void;
|
|
@@ -35,6 +42,8 @@ export declare function NumberField({ value, defaultValue, onValueChange, min, m
|
|
|
35
42
|
format?: Intl.NumberFormatOptions;
|
|
36
43
|
locale?: string;
|
|
37
44
|
className?: string;
|
|
45
|
+
scrubbable?: boolean;
|
|
46
|
+
scrubDirection?: "horizontal" | "vertical";
|
|
38
47
|
}): React.JSX.Element;
|
|
39
48
|
export declare function OTPField({ length, value, defaultValue, onValueChange, mask, disabled, required, label, id, className }: {
|
|
40
49
|
length: number;
|
|
@@ -61,24 +70,27 @@ export interface ComboboxOption {
|
|
|
61
70
|
value: string;
|
|
62
71
|
label: string;
|
|
63
72
|
}
|
|
64
|
-
export
|
|
73
|
+
export interface ComboboxOptGroup {
|
|
74
|
+
label: string;
|
|
65
75
|
items: ComboboxOption[];
|
|
76
|
+
}
|
|
77
|
+
export declare function Combobox({ items, value, onValueChange, placeholder, label, empty, disabled, size, id, className, "aria-describedby": descrito, "aria-invalid": invalido }: {
|
|
78
|
+
items: ComboboxOption[] | ComboboxOptGroup[];
|
|
79
|
+
empty?: ReactNode;
|
|
66
80
|
value?: ComboboxOption | null;
|
|
67
81
|
onValueChange?: (v: ComboboxOption | null) => void;
|
|
68
82
|
placeholder?: string;
|
|
69
83
|
label?: ReactNode;
|
|
70
84
|
disabled?: boolean;
|
|
85
|
+
size?: Responsive<FieldSize>;
|
|
71
86
|
id?: string;
|
|
72
87
|
className?: string;
|
|
73
88
|
"aria-describedby"?: string;
|
|
74
89
|
"aria-invalid"?: boolean | "true" | "false";
|
|
75
90
|
}): React.JSX.Element;
|
|
76
|
-
export
|
|
77
|
-
label: string;
|
|
78
|
-
items: ComboboxOption[];
|
|
79
|
-
}
|
|
80
|
-
export declare function MultiCombobox({ items, value, onValueChange, onInputChange, loading, placeholder, label, disabled, id, className, "aria-describedby": descrito, "aria-invalid": invalido }: {
|
|
91
|
+
export declare function MultiCombobox({ items, value, onValueChange, onInputChange, loading, placeholder, label, empty, disabled, id, className, "aria-describedby": descrito, "aria-invalid": invalido }: {
|
|
81
92
|
items: ComboboxOption[] | ComboboxOptGroup[];
|
|
93
|
+
empty?: ReactNode;
|
|
82
94
|
value?: ComboboxOption[];
|
|
83
95
|
onValueChange?: (v: ComboboxOption[]) => void;
|
|
84
96
|
onInputChange?: (query: string) => void;
|
|
@@ -103,3 +115,8 @@ export interface BlockEditorProps extends Omit<HTMLAttributes<HTMLOListElement>,
|
|
|
103
115
|
label?: string;
|
|
104
116
|
}
|
|
105
117
|
export declare function BlockEditor({ blocks, onReorder, onRemove, label, className, ...props }: BlockEditorProps): React.JSX.Element;
|
|
118
|
+
export interface PasswordFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type">, RefAttributes<HTMLInputElement> {
|
|
119
|
+
size?: Responsive<FieldSize>;
|
|
120
|
+
defaultVisible?: boolean;
|
|
121
|
+
}
|
|
122
|
+
export declare function PasswordField({ className, size, defaultVisible, id, ...props }: PasswordFieldProps): React.JSX.Element;
|
package/dist/inputs-client.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
4
4
|
// do registry — a taxonomia já existia e é gateada. A ordem de import entre eles é um DAG:
|
|
5
5
|
// internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
6
6
|
import React, { forwardRef } from "react";
|
|
7
|
+
import { valorBase, peleDoEixo, soOValor } from "./pure.js";
|
|
7
8
|
import { Combobox as BaseCombobox } from "@base-ui/react/combobox";
|
|
8
9
|
import { Form as BaseForm } from "@base-ui/react/form";
|
|
9
10
|
import { Field as BaseField } from "@base-ui/react/field";
|
|
@@ -16,7 +17,7 @@ import { cx, useAureaStrings, usePortalContainer, useReorder } from "./internal.
|
|
|
16
17
|
// diretiva — são marcação, e quem escuta `onChange` é o consumidor. Voltam IMPORTADOS e não só
|
|
17
18
|
// reexportados porque o `ehControle` do `Field` compara por IDENTIDADE de referência: dois
|
|
18
19
|
// objetos diferentes com o mesmo nome quebrariam o rótulo do campo em silêncio.
|
|
19
|
-
import { Select, Textarea, Checkbox, Radio, Switch, Range } from "./markup.js";
|
|
20
|
+
import { Select, Textarea, Checkbox, Radio, Switch, Range, InputGroup, InputGroupAddon } from "./markup.js";
|
|
20
21
|
import { Icon } from "./system.js";
|
|
21
22
|
import { IconButton } from "./actions.js";
|
|
22
23
|
// FileInput mora em arquivo próprio (132 linhas — upload real, aborto, progresso) e é público
|
|
@@ -71,9 +72,13 @@ function elementoRotulavel(tipo) {
|
|
|
71
72
|
return TAGS_ROTULAVEIS.has(tipo);
|
|
72
73
|
// Componente React arbitrário pode consumir as props no wrapper e nunca entregá-las ao nó
|
|
73
74
|
// focal. Só os controles Aurea cujo encaminhamento é parte do contrato entram aqui.
|
|
74
|
-
|
|
75
|
+
// `PasswordField` entrou em 29/08/2026, e entrou medido: `<Field label="Senha"><PasswordField/></Field>`
|
|
76
|
+
// reprovava no axe com "Form elements must have labels". Fora desta lista o Field vira GRUPO e
|
|
77
|
+
// não pendura `htmlFor`, então o <input> de dentro ficava sem nome. Ele qualifica pela mesma
|
|
78
|
+
// regra que os outros: recebe `id` e espalha `...props` no `Input`, que é o nó focal.
|
|
79
|
+
return [Input, Select, Textarea, SearchField, PasswordField, Checkbox, Radio, Switch, Range, Combobox, MultiCombobox].includes(tipo);
|
|
75
80
|
}
|
|
76
|
-
export function Field({ label, hint, error, children, className, id, name, ...props }) {
|
|
81
|
+
export function Field({ label, hint, error, children, className, id, name, orientation, ...props }) {
|
|
77
82
|
const auto = React.useId();
|
|
78
83
|
// Fragment não cria nó no DOM. Um Fragment com um só controle é só sintaxe; com vários,
|
|
79
84
|
// Field precisa voltar para grupo em vez de pendurar `htmlFor` num id que nunca existirá.
|
|
@@ -117,7 +122,7 @@ export function Field({ label, hint, error, children, className, id, name, ...pr
|
|
|
117
122
|
// embrulho o `Field.Root` recebe o erro e não tem a quem entregá-lo, e o campo fica válido na
|
|
118
123
|
// árvore de acessibilidade enquanto a frase de erro aparece na tela. Pior que não mostrar.
|
|
119
124
|
const controleFinal = name ? _jsx(BaseField.Control, { render: controle }) : controle;
|
|
120
|
-
const corpo = _jsxs("div", { className: cx("field", className), ...(nomeAqui ? {} : { role: "group", "aria-labelledby": idRotulo, ...(rotulavel ? {} : { "aria-describedby": descrito }) }), ...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" })] });
|
|
125
|
+
const corpo = _jsxs("div", { className: cx("field", peleDoEixo("field", orientation, "vertical", "field"), className), ...(nomeAqui ? {} : { role: "group", "aria-labelledby": idRotulo, ...(rotulavel ? {} : { "aria-describedby": descrito }) }), ...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" })] });
|
|
121
126
|
// `Field.Root` do motor entra SÓ quando há `name`: é ele que liga o campo à chave de `errors`
|
|
122
127
|
// do formulário. Ele não desenha nada — é contexto — então a pele não muda.
|
|
123
128
|
return name ? _jsx(BaseField.Root, { name: name, invalid: error ? true : undefined, render: corpo }) : corpo;
|
|
@@ -138,8 +143,8 @@ export function Field({ label, hint, error, children, className, id, name, ...pr
|
|
|
138
143
|
export function Form({ errors, onSubmit, children, className, ...props }) {
|
|
139
144
|
return _jsx(BaseForm, { errors: errors, onFormSubmit: onSubmit ? (v) => onSubmit(v) : undefined, className: cx("form", className), ...props, children: children });
|
|
140
145
|
}
|
|
141
|
-
export const Input = forwardRef(function Input({ className, formatOnBlur, onBlur, onChange, ...props }, ref) {
|
|
142
|
-
return _jsx("input", { ref: ref, className: cx("input", className), onChange: onChange, onBlur: e => {
|
|
146
|
+
export const Input = forwardRef(function Input({ className, formatOnBlur, size, onBlur, onChange, ...props }, ref) {
|
|
147
|
+
return _jsx("input", { ref: ref, className: cx("input", peleDoEixo("input", size), className), onChange: onChange, onBlur: e => {
|
|
143
148
|
if (formatOnBlur) {
|
|
144
149
|
const formatado = formatOnBlur(e.currentTarget.value);
|
|
145
150
|
if (formatado !== e.currentTarget.value) {
|
|
@@ -150,7 +155,12 @@ export const Input = forwardRef(function Input({ className, formatOnBlur, onBlur
|
|
|
150
155
|
onBlur?.(e);
|
|
151
156
|
}, ...props });
|
|
152
157
|
});
|
|
153
|
-
|
|
158
|
+
// O glifo entra por `InputGroup`/`InputGroupAddon`, e não pelo `.input-wrap`: o mesmo problema
|
|
159
|
+
// tinha sido resolvido DUAS vezes localmente aqui — `.input-wrap` para o glifo do SearchField e
|
|
160
|
+
// `.input-wrap-end` para o botão do PasswordField —, e o grupo é a terceira vez virando uma. O
|
|
161
|
+
// merge das duas linhagens tinha trazido de volta a versão com `.input-wrap`, contra um core
|
|
162
|
+
// que já não a pinta.
|
|
163
|
+
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 })] }); }
|
|
154
164
|
// labelHidden: coluna de seleção de tabela precisa do rótulo POR LINHA para o leitor de
|
|
155
165
|
// tela ("Select Analyst"), mas mostrá-lo engorda a coluna. O rótulo continua no DOM, só
|
|
156
166
|
// sai da tela (.sr-only) — nunca trocar por aria-label solto num <label> visível vazio.
|
|
@@ -171,9 +181,9 @@ export function SearchField({ icon = "search", className, ...props }) { return _
|
|
|
171
181
|
// plataforma; a Aurea não escreve formatador de dinheiro, e nem deveria.
|
|
172
182
|
// `name` entra junto porque é ele que faz o motor renderizar o input escondido com o valor CRU —
|
|
173
183
|
// é a trava do item ("o valor mascarado continua no DOM") entregue pelo motor, e o teste a cobra.
|
|
174
|
-
export function NumberField({ value, defaultValue, onValueChange, min, max, step, disabled, readOnly, required, label, id, name, format, locale, className }) {
|
|
184
|
+
export function NumberField({ value, defaultValue, onValueChange, min, max, step, disabled, readOnly, required, label, id, name, format, locale, className, scrubbable, scrubDirection }) {
|
|
175
185
|
const s = useAureaStrings();
|
|
176
|
-
return _jsx(BaseNumberField.Root, { id: id, name: name, value: value, defaultValue: defaultValue, onValueChange: onValueChange, min: min, max: max, step: step, format: format, locale: locale, disabled: disabled, readOnly: readOnly, required: required, className: cx("number-field", className), children: _jsxs(BaseNumberField.Group, { className: "number-field-group", children: [_jsx(BaseNumberField.Decrement, { className: "btn btn-ghost btn-icon", "aria-label": s.decrement, children: _jsx(Icon, { name: "subtract" }) }), _jsx(BaseNumberField.Input, { className: "input number-field-input", "aria-label": label }), _jsx(BaseNumberField.Increment, { className: "btn btn-ghost btn-icon", "aria-label": s.increment, children: _jsx(Icon, { name: "add" }) })] }) });
|
|
186
|
+
return _jsx(BaseNumberField.Root, { id: id, name: name, value: value, defaultValue: defaultValue, onValueChange: soOValor(onValueChange), min: min, max: max, step: step, format: format, locale: locale, disabled: disabled, readOnly: readOnly, required: required, className: cx("number-field", className), children: _jsxs(BaseNumberField.Group, { className: "number-field-group", children: [scrubbable && _jsxs(BaseNumberField.ScrubArea, { className: cx("number-field-scrub", scrubDirection === "vertical" && "number-field-scrub-vertical"), direction: scrubDirection, "aria-hidden": "true", children: [_jsx(Icon, { name: "draggable", "aria-hidden": true }), _jsx(BaseNumberField.ScrubAreaCursor, { className: "number-field-scrub-cursor", children: _jsx(Icon, { name: "draggable", "aria-hidden": true }) })] }), _jsx(BaseNumberField.Decrement, { className: "btn btn-ghost btn-icon", "aria-label": s.decrement, children: _jsx(Icon, { name: "subtract" }) }), _jsx(BaseNumberField.Input, { className: "input number-field-input", "aria-label": label }), _jsx(BaseNumberField.Increment, { className: "btn btn-ghost btn-icon", "aria-label": s.increment, children: _jsx(Icon, { name: "add" }) })] }) });
|
|
177
187
|
}
|
|
178
188
|
// OTPField (Lote 1 do BUILDING.md). Um campo por dígito, com o comportamento que ninguém acerta
|
|
179
189
|
// à mão: colar o código inteiro distribui pelos campos, Backspace volta um, e o
|
|
@@ -188,7 +198,7 @@ export function NumberField({ value, defaultValue, onValueChange, min, max, step
|
|
|
188
198
|
// o código; o nome de cada caixa é o que diz onde você está.
|
|
189
199
|
export function OTPField({ length, value, defaultValue, onValueChange, mask, disabled, required, label, id, className }) {
|
|
190
200
|
const s = useAureaStrings();
|
|
191
|
-
return _jsx(BaseOTPField.Root, { id: id, length: length, value: value, defaultValue: defaultValue, onValueChange: 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)) });
|
|
201
|
+
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)) });
|
|
192
202
|
}
|
|
193
203
|
// SegmentedControl — achado M20, fechado na Parte C do PLANO-1.0 em 07/08/2026.
|
|
194
204
|
//
|
|
@@ -223,6 +233,13 @@ export function SegmentedControl({ items, value, onChange, label }) {
|
|
|
223
233
|
const s = useAureaStrings();
|
|
224
234
|
return _jsx(BaseRadioGroup, { className: "segmented", "aria-label": label ?? s.optionsLabel, value: value, onValueChange: v => onChange(String(v)), children: items.map(i => _jsx(BaseRadio.Root, { value: i.value, className: i.value === value ? "active" : undefined, nativeButton: true, render: _jsx("button", { type: "button" }), children: i.label }, i.value)) });
|
|
225
235
|
}
|
|
236
|
+
const ehAgrupado = (items) => items != null && items.length > 0 && typeof items[0] === "object" && items[0] != null && "items" in items[0];
|
|
237
|
+
// UM renderizador e UMA lista para os dois combobox: duas cópias da mesma árvore é como a
|
|
238
|
+
// segunda fica para trás na mudança seguinte.
|
|
239
|
+
const renderComboboxItem = (item) => _jsxs(BaseCombobox.Item, { value: item, className: "menu-item combobox-item", children: [_jsx(BaseCombobox.ItemIndicator, { className: "combobox-check", children: _jsx(Icon, { name: "checkmark", size: "sm" }) }), _jsx("span", { children: item.label })] }, item.value);
|
|
240
|
+
const listaCombobox = (items) => _jsx(BaseCombobox.List, { children: ehAgrupado(items)
|
|
241
|
+
? (group) => _jsxs(BaseCombobox.Group, { items: group.items, className: "combobox-section", children: [_jsx(BaseCombobox.GroupLabel, { className: "combobox-group-label", children: group.label }), _jsx(BaseCombobox.Collection, { children: renderComboboxItem })] }, group.label)
|
|
242
|
+
: renderComboboxItem });
|
|
226
243
|
// `aria-describedby` e `aria-invalid` são explícitos e não caem em `...props` por acidente: este
|
|
227
244
|
// componente destrincha uma lista fixa, então o que não está aqui é DESCARTADO em silêncio — e era
|
|
228
245
|
// exatamente isso que fazia o `Field` não alcançar o input do Combobox (AUD-0001, 12/08/2026).
|
|
@@ -230,24 +247,28 @@ export function SegmentedControl({ items, value, onChange, label }) {
|
|
|
230
247
|
// `disabled` vai na ROOT, não no Input: `Input`, `Trigger`, `Clear` e `ChipRemove` leem todos o
|
|
231
248
|
// mesmo `selectors.disabled` do store do Base UI (@base-ui/react 1.6.0). Desabilitar o Input
|
|
232
249
|
// deixaria os dois botões vivos — abrir a lista de um campo desabilitado é o defeito, não o texto.
|
|
233
|
-
export function Combobox({ items, value, onValueChange, placeholder, label, disabled, id, className, "aria-describedby": descrito, "aria-invalid": invalido }) {
|
|
250
|
+
export function Combobox({ items, value, onValueChange, placeholder, label, empty, disabled, size, id, className, "aria-describedby": descrito, "aria-invalid": invalido }) {
|
|
234
251
|
const s = useAureaStrings();
|
|
235
252
|
const portal = usePortalContainer();
|
|
236
253
|
const autoId = React.useId();
|
|
237
254
|
const inputId = id ?? autoId;
|
|
238
|
-
return _jsxs(BaseCombobox.Root, { items: items, value: value, onValueChange: 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: "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: s.comboboxEmpty }),
|
|
255
|
+
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)] }) }) })] });
|
|
239
256
|
}
|
|
240
|
-
|
|
241
|
-
|
|
257
|
+
// MultiCombobox (Fase 4): multi-seleção com chips, opções agrupadas e filtro
|
|
258
|
+
// externo (async). Reusa .combobox-popup/-item/-empty do básico.
|
|
259
|
+
// - Agrupar: passar ComboboxOptGroup[] em items (label + items). Detecção pela
|
|
260
|
+
// presença de .items no 1º elemento — não misturar plano com agrupado.
|
|
261
|
+
// - Async: passar onInputChange; o filtro interno do Base UI desliga
|
|
262
|
+
// (filter={null}) e o consumidor troca os items conforme a busca retorna.
|
|
263
|
+
// loading só troca o texto do vazio para não piscar "Nenhum resultado".
|
|
264
|
+
export function MultiCombobox({ items, value, onValueChange, onInputChange, loading, placeholder, label, empty, disabled, id, className, "aria-describedby": descrito, "aria-invalid": invalido }) {
|
|
242
265
|
const s = useAureaStrings();
|
|
243
266
|
const portal = usePortalContainer();
|
|
244
267
|
const autoId = React.useId();
|
|
245
268
|
const inputId = id ?? autoId;
|
|
246
269
|
const renderItem = (item) => _jsxs(BaseCombobox.Item, { value: item, className: "menu-item combobox-item", children: [_jsx(BaseCombobox.ItemIndicator, { className: "combobox-check", children: _jsx(Icon, { name: "checkmark", size: "sm" }) }), _jsx("span", { children: item.label })] }, item.value);
|
|
247
|
-
return _jsxs(BaseCombobox.Root, { multiple: true, items: items, value: value, onValueChange: onValueChange, disabled: disabled, itemToStringLabel: (i) => i.label, filter: onInputChange ? null : undefined, onInputValueChange: onInputChange ? ((v, d) => { if (d.reason !== "item-press")
|
|
248
|
-
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 : s.comboboxEmpty }),
|
|
249
|
-
? (group) => _jsxs(BaseCombobox.Group, { items: group.items, className: "combobox-section", children: [_jsx(BaseCombobox.GroupLabel, { className: "combobox-group-label", children: group.label }), _jsx(BaseCombobox.Collection, { children: renderItem })] }, group.label)
|
|
250
|
-
: renderItem })] }) }) })] });
|
|
270
|
+
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")
|
|
271
|
+
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)] }) }) })] });
|
|
251
272
|
}
|
|
252
273
|
export function BlockEditor({ blocks, onReorder, onRemove, label, className, ...props }) {
|
|
253
274
|
const s = useAureaStrings();
|
|
@@ -262,3 +283,10 @@ export function BlockEditor({ blocks, onReorder, onRemove, label, className, ...
|
|
|
262
283
|
return _jsxs("li", { className: "block-item", "data-grabbed": r.pego === i || undefined, children: [_jsxs("div", { className: "block-rail", children: [_jsxs("button", { type: "button", id: hid, className: "block-handle", "aria-labelledby": `${hid} ${kid}`, "aria-describedby": `${bid}ajuda`, "aria-pressed": r.pego === i, onKeyDown: e => r.teclado(e, i), onPointerDown: e => r.ponteiroBaixo(e, i), onPointerMove: r.ponteiroMove, onPointerUp: r.ponteiroSolta, onPointerCancel: r.ponteiroSolta, children: [_jsx(Icon, { name: "drag--horizontal" }), _jsx("span", { className: "sr-only", children: s.sortableHandle })] }), onRemove && _jsxs("button", { type: "button", id: rid, className: "block-remove", "aria-labelledby": `${rid} ${kid}`, onClick: () => onRemove(i), children: [_jsx(Icon, { name: "trash-can" }), _jsx("span", { className: "sr-only", children: s.blockRemove })] })] }), _jsx("div", { className: "block-body", children: b.children }), _jsxs("span", { id: kid, className: "sr-only", children: [b.kind ?? s.blockLabel, " ", i + 1, " ", s.positionOf, " ", n] })] }, b.id);
|
|
263
284
|
}) }), _jsx("span", { id: `${bid}ajuda`, className: "sr-only", children: s.sortableHelp }), _jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", children: r.aviso })] });
|
|
264
285
|
}
|
|
286
|
+
export function PasswordField({ className, size, defaultVisible = false, id, ...props }) {
|
|
287
|
+
const s = useAureaStrings();
|
|
288
|
+
const [visivel, setVisivel] = React.useState(defaultVisible);
|
|
289
|
+
const auto = React.useId();
|
|
290
|
+
const campoId = id ?? auto;
|
|
291
|
+
return _jsxs(InputGroup, { className: className, children: [_jsx(Input, { id: campoId, type: visivel ? "text" : "password", className: peleDoEixo("input", size) || undefined, autoComplete: "current-password", ...props }), _jsx(InputGroupAddon, { side: "end", layout: "inline", children: _jsx(IconButton, { variant: "ghost", size: valorBase(size) === "lg" ? "md" : "sm", icon: visivel ? "view--off" : "view", label: visivel ? s.passwordHide : s.passwordShow, "aria-controls": campoId, onClick: () => setVisivel(v => !v) }) })] });
|
|
292
|
+
}
|
package/dist/inputs.d.ts
CHANGED
package/dist/inputs.js
CHANGED
|
@@ -7,3 +7,7 @@
|
|
|
7
7
|
// quebrariam o rótulo do campo em silêncio. Um caminho de import, um objeto.
|
|
8
8
|
export * from "./inputs-client.js";
|
|
9
9
|
export { Select, Textarea, Checkbox, Radio, Switch, Range } from "./markup.js";
|
|
10
|
+
// PORTADOS no merge de 28/08/2026, da linhagem da ATIVIDADE-2 — não existiam na `main`.
|
|
11
|
+
// Saem do `markup` pela mesma razão dos seis acima: nenhum usa hook, então chegam como
|
|
12
|
+
// componente de SERVIDOR e não arrastam a fronteira de cliente com eles.
|
|
13
|
+
export { Label, InputGroup, InputGroupAddon } from "./markup.js";
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { type AureaStrings } from "./pure.js";
|
|
3
|
-
export { cx, defaultStrings, ptBR, defaultSpriteUrl, universalStates, stateSeverity, type AureaStrings, type UniversalState } from "./pure.js";
|
|
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";
|
|
4
4
|
export declare const StringsContext: React.Context<AureaStrings>;
|
|
5
5
|
export declare const useAureaStrings: () => AureaStrings;
|
|
6
6
|
export declare const SpriteContext: React.Context<string>;
|
|
7
7
|
export declare const useSpriteUrl: () => string;
|
|
8
|
+
export declare const ThemeContext: React.Context<{
|
|
9
|
+
theme?: AureaTheme;
|
|
10
|
+
setTheme: (t: AureaTheme) => void;
|
|
11
|
+
toggleTheme: () => void;
|
|
12
|
+
}>;
|
|
13
|
+
/** Tema atual e como trocá-lo. Fora de um `AureaProvider`, devolve `undefined` e no-ops — não
|
|
14
|
+
* lança: um componente isolado num teste não deve morrer por falta de provider. */
|
|
15
|
+
export declare const useTheme: () => {
|
|
16
|
+
theme?: AureaTheme;
|
|
17
|
+
setTheme: (t: AureaTheme) => void;
|
|
18
|
+
toggleTheme: () => void;
|
|
19
|
+
};
|
|
20
|
+
export declare const DensityContext: React.Context<{
|
|
21
|
+
density?: AureaDensity;
|
|
22
|
+
setDensity: (d: AureaDensity) => void;
|
|
23
|
+
}>;
|
|
24
|
+
/** Densidade atual e como trocá-la. Mesma regra do `useTheme`. */
|
|
25
|
+
export declare const useDensity: () => {
|
|
26
|
+
density?: AureaDensity;
|
|
27
|
+
setDensity: (d: AureaDensity) => void;
|
|
28
|
+
};
|
|
8
29
|
export declare const PortalContext: React.Context<HTMLElement | null | undefined>;
|
|
9
30
|
export declare const usePortalContainer: () => HTMLElement | null | undefined;
|
|
10
31
|
export interface Reordenavel<E extends HTMLElement> {
|
package/dist/internal.js
CHANGED
|
@@ -12,13 +12,31 @@
|
|
|
12
12
|
// pure → internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
13
13
|
// INTERNO: o que todo módulo precisa e ninguém publica como componente próprio.
|
|
14
14
|
// NÃO é subpath — `@aurea-uds/react/internal` não existe, de propósito.
|
|
15
|
+
// Kbd mora aqui por dependência, não por categoria: o Button precisa dele e ele não precisa de
|
|
16
|
+
// ninguém. A casa pública dele continua sendo `/data-display`, que o reexporta.
|
|
15
17
|
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
16
18
|
import { defaultStrings, defaultSpriteUrl } from "./pure.js";
|
|
17
|
-
export { cx, defaultStrings, ptBR, defaultSpriteUrl, universalStates, stateSeverity } from "./pure.js";
|
|
19
|
+
export { cx, fundirRender, defaultStrings, ptBR, defaultSpriteUrl, universalStates, stateSeverity } from "./pure.js";
|
|
18
20
|
export const StringsContext = createContext(defaultStrings);
|
|
19
21
|
export const useAureaStrings = () => useContext(StringsContext);
|
|
20
22
|
export const SpriteContext = createContext(defaultSpriteUrl);
|
|
21
23
|
export const useSpriteUrl = () => useContext(SpriteContext);
|
|
24
|
+
// Tema e densidade viajam por contexto, e não por leitura do DOM, por um motivo que já custou
|
|
25
|
+
// caro em outro lugar deste repositório: quem lê o DOM não é notificado quando ele muda. O
|
|
26
|
+
// `TableOfContents` é presentacional pelo mesmo desenho e por isso NÃO marca a seção em vista
|
|
27
|
+
// (`G-CAP-25`). Aqui o provider é o dono do valor, escreve no `<html>` e avisa quem depende.
|
|
28
|
+
//
|
|
29
|
+
// O valor inicial é `undefined` de propósito: significa "ninguém decidiu ainda", que é
|
|
30
|
+
// diferente de "escuro". Um default concreto aqui faria o provider sobrescrever, na primeira
|
|
31
|
+
// pintura, o `data-theme` que o documento já traz no markup — e esse atributo existe justamente
|
|
32
|
+
// para não haver piscada de tema ao carregar.
|
|
33
|
+
export const ThemeContext = createContext({ theme: undefined, setTheme: () => { }, toggleTheme: () => { } });
|
|
34
|
+
/** Tema atual e como trocá-lo. Fora de um `AureaProvider`, devolve `undefined` e no-ops — não
|
|
35
|
+
* lança: um componente isolado num teste não deve morrer por falta de provider. */
|
|
36
|
+
export const useTheme = () => useContext(ThemeContext);
|
|
37
|
+
export const DensityContext = createContext({ density: undefined, setDensity: () => { } });
|
|
38
|
+
/** Densidade atual e como trocá-la. Mesma regra do `useTheme`. */
|
|
39
|
+
export const useDensity = () => useContext(DensityContext);
|
|
22
40
|
// ONDE OS POPUPS SÃO MONTADOS — achado B7, fechado na Parte C do PLANO-1.0 (07/08/2026).
|
|
23
41
|
// O DEFEITO não era o portal: era o consumidor não ter como mexer nele. Todo popup da Aurea
|
|
24
42
|
// (diálogo, gaveta, dica, popover, os dois menus, notificação, combobox, toast) monta num
|
package/dist/layout-client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type HTMLAttributes, type RefAttributes, type ReactNode } from "react";
|
|
2
|
+
import { type Orientation, type Responsive } from "./pure.js";
|
|
2
3
|
import { type TopbarVariant, type SidebarVariant } from "./navigation.js";
|
|
3
4
|
export declare function AppShell({ brand, navigation, topbar, topbarVariant, sidebarVariant, sidebarCollapsed, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
4
5
|
brand: ReactNode;
|
|
@@ -8,3 +9,6 @@ export declare function AppShell({ brand, navigation, topbar, topbarVariant, sid
|
|
|
8
9
|
sidebarVariant?: SidebarVariant;
|
|
9
10
|
sidebarCollapsed?: boolean;
|
|
10
11
|
}): import("react").JSX.Element;
|
|
12
|
+
export declare function Separator({ orientation, className, ...props }: HTMLAttributes<HTMLHRElement> & RefAttributes<HTMLHRElement> & {
|
|
13
|
+
orientation?: Responsive<Orientation>;
|
|
14
|
+
}): import("react").JSX.Element;
|
package/dist/layout-client.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// Fase 9 (achado A5): este arquivo saiu do index.tsx de 970 linhas. Um módulo por categoria
|
|
4
|
+
// do registry — a taxonomia já existia e é gateada. A ordem de import entre eles é um DAG:
|
|
5
|
+
// internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
6
|
+
import { useRef } from "react";
|
|
7
|
+
import { Separator as BaseSeparator } from "@base-ui/react/separator";
|
|
3
8
|
import { cx, useAureaStrings } from "./internal.js";
|
|
9
|
+
import { useValorResponsivo } from "./responsivo-runtime.js";
|
|
4
10
|
import { IconButton } from "./actions.js";
|
|
5
11
|
import { Sidebar, Topbar } from "./navigation.js";
|
|
6
12
|
// ── Auxiliar de topo: mora ANTES do primeiro export, e a posição é obrigatória ───────────────
|
|
@@ -73,5 +79,39 @@ function focoDaGaveta(e) {
|
|
|
73
79
|
// normal, e é como as 106 páginas do catálogo são montadas — recebia o padrão e ponto. A variante
|
|
74
80
|
// estava documentada no CHANGELOG como saída para quem instalou a `0.3.0`, e a porta estava
|
|
75
81
|
// trancada. É o par do `topbarVariant`, que já existia logo acima. Ver ADR-0034.
|
|
82
|
+
// O alvo do link de pular. Mesmo raciocínio do id da navegação: um documento tem UM AppShell,
|
|
83
|
+
// então id fixo é estável e não colide. Sem alvo estável não há como o link existir.
|
|
84
|
+
const SHELL_MAIN_ID = "aurea-shell-main";
|
|
76
85
|
const SHELL_NAV_ID = "aurea-shell-nav";
|
|
77
|
-
export function AppShell({ brand, navigation, topbar, topbarVariant = "floating", sidebarVariant, sidebarCollapsed, children, className, ...props }) {
|
|
86
|
+
export function AppShell({ brand, navigation, topbar, topbarVariant = "floating", sidebarVariant, sidebarCollapsed, children, className, ...props }) {
|
|
87
|
+
const s = useAureaStrings();
|
|
88
|
+
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, onToggle: focoDaGaveta, children: navigation }), _jsx("main", { id: SHELL_MAIN_ID, tabIndex: -1, className: "content", children: children })] });
|
|
89
|
+
}
|
|
90
|
+
// ── Separator ────────────────────────────────────────────────────────────────────────────────
|
|
91
|
+
// A LINHA DO SISTEMA, e ela é de CLIENTE por necessidade, não por vizinhança.
|
|
92
|
+
//
|
|
93
|
+
// Ela já foi um <hr> com orientação estática, no `markup.tsx`. O merge das duas linhagens ficou
|
|
94
|
+
// com essa versão, e o gate `comportamental.multi-motor.spec.ts` reprovou: a prova das cinco
|
|
95
|
+
// capacidades do `G-AXIS-06` — a lista que o Victor especificou — cobra do separador
|
|
96
|
+
// `data-orientation` E `aria-orientation` resolvidos pela largura do CONTÊINER, e os dois são
|
|
97
|
+
// atributo. Atributo não sai de classe CSS. Eixo comportamental precisa de runtime.
|
|
98
|
+
//
|
|
99
|
+
// E O ELEMENTO CONTINUA SENDO UM <hr>. As duas exigências pareciam brigar — a suíte de unidade
|
|
100
|
+
// cobra `<hr>` sem `role` escrito ("ARIA redundante é pior que ARIA nenhuma", aviso do próprio
|
|
101
|
+
// APG), e a prova de contêiner cobra atributo resolvido em runtime. `render` resolve as duas:
|
|
102
|
+
// o motor calcula e publica sobre o elemento que a Aurea escolhe.
|
|
103
|
+
//
|
|
104
|
+
// `role={undefined}` e o `aria-orientation` explícito são o acerto fino, e foram MEDIDOS antes
|
|
105
|
+
// de escrever: por padrão o motor escreve `role="separator"` no <hr> (redundante — o <hr> já É
|
|
106
|
+
// separator) e escreve `aria-orientation` também no HORIZONTAL, que é o default implícito do
|
|
107
|
+
// papel. As duas props passadas aqui vencem as do motor, e sobra exatamente o que se quer:
|
|
108
|
+
// vertical → <hr data-orientation="vertical" aria-orientation="vertical" class="separator separator-vertical">
|
|
109
|
+
// horizontal → <hr data-orientation="horizontal" class="separator">
|
|
110
|
+
export function Separator({ orientation, className, ...props }) {
|
|
111
|
+
const ancora = useRef(null);
|
|
112
|
+
const resolvida = useValorResponsivo(orientation, "horizontal", ancora);
|
|
113
|
+
// O elenco existe porque o tipo do motor descreve os manipuladores sobre `HTMLDivElement` — ele
|
|
114
|
+
// não sabe que o `render` troca o elemento. O tipo PÚBLICO desta função é o certo: quem passar um
|
|
115
|
+
// `ref` recebe o <hr> que está de fato no DOM.
|
|
116
|
+
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 });
|
|
117
|
+
}
|
package/dist/layout.d.ts
CHANGED
package/dist/layout.js
CHANGED
|
@@ -2,4 +2,6 @@
|
|
|
2
2
|
// de propósito: a diretiva contamina o módulo inteiro e faria a marcação pura chegar como cliente
|
|
3
3
|
// por vizinhança (ADR-0026; o check 26b reprova quem a puser de volta aqui).
|
|
4
4
|
export * from "./layout-client.js";
|
|
5
|
-
export { Card, Stack, Cluster, Grid
|
|
5
|
+
export { Card, Stack, Cluster, Grid } from "./markup.js";
|
|
6
|
+
// PORTADO no merge de 28/08/2026 — sai do markup (servidor), como os demais de marcação.
|
|
7
|
+
export { AspectRatio } from "./markup.js";
|