@aurea-uds/react 0.2.0 → 0.3.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/README.md +34 -2
- package/dist/actions.d.ts +10 -3
- package/dist/actions.js +55 -6
- package/dist/code-client.d.ts +6 -0
- package/dist/code-client.js +24 -0
- package/dist/code.d.ts +2 -13
- package/dist/code.js +5 -34
- package/dist/data-display-client.d.ts +14 -0
- package/dist/data-display-client.js +22 -0
- package/dist/data-display.d.ts +2 -23
- package/dist/data-display.js +5 -14
- package/dist/feedback-client.d.ts +64 -0
- package/dist/feedback-client.js +110 -0
- package/dist/feedback.d.ts +2 -63
- package/dist/feedback.js +5 -101
- package/dist/file-input.js +57 -9
- package/dist/identity-client.d.ts +9 -0
- package/dist/identity-client.js +12 -0
- package/dist/identity.d.ts +2 -17
- package/dist/identity.js +5 -25
- package/dist/index.d.ts +2 -1
- package/dist/index.js +19 -3
- package/dist/inputs-client.d.ts +105 -0
- package/dist/inputs-client.js +264 -0
- package/dist/inputs.d.ts +2 -91
- package/dist/inputs.js +9 -126
- package/dist/internal.d.ts +20 -5
- package/dist/internal.js +91 -10
- package/dist/layout-client.d.ts +9 -0
- package/dist/layout-client.js +72 -0
- package/dist/layout.d.ts +2 -15
- package/dist/layout.js +5 -76
- package/dist/markup.d.ts +72 -0
- package/dist/markup.js +87 -0
- package/dist/media-client.d.ts +36 -0
- package/dist/media-client.js +239 -0
- package/dist/media.d.ts +2 -9
- package/dist/media.js +5 -99
- package/dist/navigation-client.d.ts +94 -0
- package/dist/navigation-client.js +154 -0
- package/dist/navigation.d.ts +2 -85
- package/dist/navigation.js +5 -138
- package/dist/overlays.d.ts +23 -0
- package/dist/overlays.js +45 -1
- package/dist/pure.d.ts +30 -0
- package/dist/pure.js +26 -2
- package/dist/system.d.ts +9 -0
- package/dist/system.js +46 -0
- package/package.json +180 -176
package/dist/navigation.d.ts
CHANGED
|
@@ -1,85 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export type StepState = "default" | "active" | "done" | "error";
|
|
4
|
-
export interface StepItem {
|
|
5
|
-
label: ReactNode;
|
|
6
|
-
state?: StepState;
|
|
7
|
-
optional?: ReactNode;
|
|
8
|
-
onClick?: () => void;
|
|
9
|
-
}
|
|
10
|
-
export declare function Stepper({ items, label, className }: {
|
|
11
|
-
items: StepItem[];
|
|
12
|
-
label?: string;
|
|
13
|
-
className?: string;
|
|
14
|
-
}): React.JSX.Element;
|
|
15
|
-
export declare function Breadcrumb({ items, label }: {
|
|
16
|
-
items: Array<{
|
|
17
|
-
label: ReactNode;
|
|
18
|
-
href?: string;
|
|
19
|
-
}>;
|
|
20
|
-
label?: string;
|
|
21
|
-
}): React.JSX.Element;
|
|
22
|
-
export declare function Tabs({ tabs, value, onChange, label }: {
|
|
23
|
-
tabs: Array<{
|
|
24
|
-
id: string;
|
|
25
|
-
label: ReactNode;
|
|
26
|
-
content: ReactNode;
|
|
27
|
-
}>;
|
|
28
|
-
value: string;
|
|
29
|
-
onChange: (id: string) => void;
|
|
30
|
-
label?: string;
|
|
31
|
-
}): React.JSX.Element;
|
|
32
|
-
export declare function Pagination({ page, total, onPageChange }: {
|
|
33
|
-
page: number;
|
|
34
|
-
total: number;
|
|
35
|
-
onPageChange: (p: number) => void;
|
|
36
|
-
}): React.JSX.Element;
|
|
37
|
-
export interface TocItem {
|
|
38
|
-
id: string;
|
|
39
|
-
label: string;
|
|
40
|
-
sub?: boolean;
|
|
41
|
-
}
|
|
42
|
-
export declare function TableOfContents({ items, current, label, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
|
|
43
|
-
items: TocItem[];
|
|
44
|
-
current?: string;
|
|
45
|
-
label?: string;
|
|
46
|
-
}): React.JSX.Element;
|
|
47
|
-
export interface TreeNode {
|
|
48
|
-
id: string;
|
|
49
|
-
label: ReactNode;
|
|
50
|
-
icon?: IconName;
|
|
51
|
-
children?: TreeNode[];
|
|
52
|
-
}
|
|
53
|
-
export declare function TreeView({ items, defaultExpandedIds, onSelect, label, className }: {
|
|
54
|
-
items: TreeNode[];
|
|
55
|
-
defaultExpandedIds?: string[];
|
|
56
|
-
onSelect?: (node: TreeNode) => void;
|
|
57
|
-
label?: string;
|
|
58
|
-
className?: string;
|
|
59
|
-
}): ReactElement<unknown, string | React.JSXElementConstructor<any>>;
|
|
60
|
-
export interface SidebarItem {
|
|
61
|
-
id: string;
|
|
62
|
-
label: ReactNode;
|
|
63
|
-
href?: string;
|
|
64
|
-
icon?: IconName;
|
|
65
|
-
badge?: ReactNode;
|
|
66
|
-
onClick?: () => void;
|
|
67
|
-
items?: SidebarItem[];
|
|
68
|
-
}
|
|
69
|
-
export declare function Sidebar({ items, current, collapsed, label, children, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
|
|
70
|
-
items?: SidebarItem[];
|
|
71
|
-
current?: string;
|
|
72
|
-
collapsed?: boolean;
|
|
73
|
-
label?: string;
|
|
74
|
-
}): React.JSX.Element;
|
|
75
|
-
export type TopbarVariant = "floating" | "flush" | "pill";
|
|
76
|
-
export declare function Topbar({ variant, brand, children, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
|
|
77
|
-
variant?: TopbarVariant;
|
|
78
|
-
brand?: ReactNode;
|
|
79
|
-
}): React.JSX.Element;
|
|
80
|
-
export declare function CommandPaletteShell({ open, query, onQueryChange, children }: {
|
|
81
|
-
open: boolean;
|
|
82
|
-
query: string;
|
|
83
|
-
onQueryChange: (v: string) => void;
|
|
84
|
-
children?: ReactNode;
|
|
85
|
-
}): React.JSX.Element | null;
|
|
1
|
+
export * from "./navigation-client.js";
|
|
2
|
+
export { Topbar, type TopbarVariant } from "./markup.js";
|
package/dist/navigation.js
CHANGED
|
@@ -1,138 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import React from "react";
|
|
7
|
-
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
8
|
-
import { cx, useAureaStrings } from "./internal.js";
|
|
9
|
-
import { Icon } from "./system.js";
|
|
10
|
-
import { Button } from "./actions.js";
|
|
11
|
-
import { Badge } from "./feedback.js";
|
|
12
|
-
import { SearchField } from "./inputs.js";
|
|
13
|
-
export function Stepper({ items, label, className }) {
|
|
14
|
-
const s = useAureaStrings();
|
|
15
|
-
return _jsx("div", { role: "list", "aria-label": label ?? s.stepperLabel, className: cx("stepper", className), children: items.map((it, n) => {
|
|
16
|
-
const st = it.state ?? "default";
|
|
17
|
-
const marca = st === "done" ? _jsx(Icon, { name: "checkmark" }) : st === "error" ? _jsx(Icon, { name: "error" }) : n + 1;
|
|
18
|
-
const miolo = _jsxs(_Fragment, { children: [_jsx("span", { className: "step-dot", children: marca }), _jsx("strong", { children: it.label }), it.optional && _jsx("small", { className: "step-optional", children: it.optional })] });
|
|
19
|
-
return _jsx("div", { role: "listitem", className: cx("step", st !== "default" && `step-${st}`), "aria-current": st === "active" ? "step" : undefined, children: it.onClick ? _jsx("button", { type: "button", className: "step-trigger", onClick: it.onClick, children: miolo }) : miolo }, n);
|
|
20
|
-
}) });
|
|
21
|
-
}
|
|
22
|
-
export function Breadcrumb({ items, label }) { const s = useAureaStrings(); return _jsx("nav", { className: "breadcrumb", "aria-label": label ?? s.breadcrumbLabel, children: items.map((i, n) => _jsxs(React.Fragment, { children: [n > 0 && _jsx(Icon, { name: "chevron--right", size: "sm" }), " ", i.href ? _jsx("a", { href: i.href, children: i.label }) : _jsx("strong", { "aria-current": "page", children: i.label })] }, n)) }); }
|
|
23
|
-
export function Tabs({ tabs, value, onChange, label }) { const s = useAureaStrings(); return _jsxs(BaseTabs.Root, { value: value, onValueChange: v => onChange(String(v)), children: [_jsx(BaseTabs.List, { className: "tabs", "aria-label": label ?? s.tabsLabel, activateOnFocus: true, children: tabs.map(t => _jsx(BaseTabs.Tab, { value: t.id, className: "tab", children: t.label }, t.id)) }), tabs.map(t => _jsx(BaseTabs.Panel, { value: t.id, className: "card card-inset", tabIndex: 0, children: t.content }, t.id))] }); }
|
|
24
|
-
export function Pagination({ page, total, onPageChange }) { const s = useAureaStrings(); return _jsxs("nav", { className: "pagination", "aria-label": s.paginationLabel, children: [_jsx(Button, { variant: "ghost", size: "sm", disabled: page <= 1, onClick: () => onPageChange(page - 1), children: s.previous }), _jsxs(Badge, { variant: "primary", children: [page, " / ", total] }), _jsx(Button, { variant: "ghost", size: "sm", disabled: page >= total, onClick: () => onPageChange(page + 1), children: s.next })] }); }
|
|
25
|
-
export function TableOfContents({ items, current, label, className, ...props }) {
|
|
26
|
-
const s = useAureaStrings();
|
|
27
|
-
return _jsxs("nav", { className: cx("toc", className), "aria-label": label ?? s.tocLabel, ...props, children: [_jsx("p", { className: "toc-label", children: label ?? s.tocLabel }), items.map(i => _jsx("a", { href: `#${i.id}`, className: cx(i.sub && "toc-sub"), ...(i.id === current ? { "aria-current": "true" } : {}), children: i.label }, i.id))] });
|
|
28
|
-
}
|
|
29
|
-
function flattenVisible(nodes, expanded, level = 1, parentId, acc = []) {
|
|
30
|
-
for (const node of nodes) {
|
|
31
|
-
acc.push({ node, level, parentId });
|
|
32
|
-
if (node.children?.length && expanded.has(node.id))
|
|
33
|
-
flattenVisible(node.children, expanded, level + 1, node.id, acc);
|
|
34
|
-
}
|
|
35
|
-
return acc;
|
|
36
|
-
}
|
|
37
|
-
export function TreeView({ items, defaultExpandedIds, onSelect, label, className }) {
|
|
38
|
-
const s = useAureaStrings();
|
|
39
|
-
const baseId = React.useId();
|
|
40
|
-
const [expanded, setExpanded] = React.useState(() => new Set(defaultExpandedIds));
|
|
41
|
-
const [selected, setSelected] = React.useState();
|
|
42
|
-
const [active, setActive] = React.useState(() => items[0]?.id);
|
|
43
|
-
const rootRef = React.useRef(null);
|
|
44
|
-
const visible = flattenVisible(items, expanded);
|
|
45
|
-
// Roving tab stop derivado: se o nó ativo saiu do conjunto visível (dados
|
|
46
|
-
// trocados, nó removido), o primeiro visível volta a ser tabulável — senão a
|
|
47
|
-
// árvore inteira fica tabIndex=-1 e some da ordem do Tab (auditoria, MÉDIO 1).
|
|
48
|
-
const effectiveActive = active !== undefined && visible.some(v => v.node.id === active) ? active : visible[0]?.node.id;
|
|
49
|
-
const focusId = (id) => { setActive(id); rootRef.current?.querySelector(`[data-tree-id="${CSS.escape(id)}"]`)?.focus(); };
|
|
50
|
-
const toggle = (id, open) => setExpanded(prev => { const n = new Set(prev); if (open)
|
|
51
|
-
n.add(id);
|
|
52
|
-
else
|
|
53
|
-
n.delete(id); return n; });
|
|
54
|
-
const select = (node) => { setSelected(node.id); onSelect?.(node); };
|
|
55
|
-
const onKeyDown = (e) => {
|
|
56
|
-
const idx = visible.findIndex(v => v.node.id === effectiveActive);
|
|
57
|
-
if (idx < 0)
|
|
58
|
-
return;
|
|
59
|
-
const cur = visible[idx], hasChildren = !!cur.node.children?.length, isOpen = expanded.has(cur.node.id);
|
|
60
|
-
const rtl = getComputedStyle(e.currentTarget).direction === "rtl";
|
|
61
|
-
const expandKey = rtl ? "ArrowLeft" : "ArrowRight", collapseKey = rtl ? "ArrowRight" : "ArrowLeft";
|
|
62
|
-
switch (e.key) {
|
|
63
|
-
case "ArrowDown":
|
|
64
|
-
e.preventDefault();
|
|
65
|
-
if (idx < visible.length - 1)
|
|
66
|
-
focusId(visible[idx + 1].node.id);
|
|
67
|
-
break;
|
|
68
|
-
case "ArrowUp":
|
|
69
|
-
e.preventDefault();
|
|
70
|
-
if (idx > 0)
|
|
71
|
-
focusId(visible[idx - 1].node.id);
|
|
72
|
-
break;
|
|
73
|
-
case expandKey:
|
|
74
|
-
e.preventDefault();
|
|
75
|
-
if (hasChildren && !isOpen)
|
|
76
|
-
toggle(cur.node.id, true);
|
|
77
|
-
else if (hasChildren && isOpen)
|
|
78
|
-
focusId(cur.node.children[0].id);
|
|
79
|
-
break;
|
|
80
|
-
case collapseKey:
|
|
81
|
-
e.preventDefault();
|
|
82
|
-
if (hasChildren && isOpen)
|
|
83
|
-
toggle(cur.node.id, false);
|
|
84
|
-
else if (cur.parentId)
|
|
85
|
-
focusId(cur.parentId);
|
|
86
|
-
break;
|
|
87
|
-
case "Home":
|
|
88
|
-
e.preventDefault();
|
|
89
|
-
focusId(visible[0].node.id);
|
|
90
|
-
break;
|
|
91
|
-
case "End":
|
|
92
|
-
e.preventDefault();
|
|
93
|
-
focusId(visible[visible.length - 1].node.id);
|
|
94
|
-
break;
|
|
95
|
-
case "Enter":
|
|
96
|
-
case " ":
|
|
97
|
-
e.preventDefault();
|
|
98
|
-
select(cur.node);
|
|
99
|
-
if (hasChildren)
|
|
100
|
-
toggle(cur.node.id, !isOpen);
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
const renderNodes = (nodes, level) => (_jsx("ul", { ref: level === 1 ? rootRef : undefined, className: cx(level === 1 ? "tree" : "tree-group", level === 1 && className), role: level === 1 ? "tree" : "group", "aria-label": level === 1 ? (label ?? s.treeLabel) : undefined, onKeyDown: level === 1 ? onKeyDown : undefined, children: nodes.map(node => {
|
|
105
|
-
const hasChildren = !!node.children?.length, isOpen = expanded.has(node.id), isSelected = selected === node.id, labelId = baseId + node.id;
|
|
106
|
-
return _jsxs("li", { className: "tree-item", role: "treeitem", "data-tree-id": node.id, "aria-level": level, "aria-expanded": hasChildren ? isOpen : undefined, "aria-selected": isSelected, "aria-labelledby": labelId, tabIndex: node.id === effectiveActive ? 0 : -1, children: [_jsxs("span", { className: "tree-node", "data-selected": isSelected || undefined, style: { paddingInlineStart: `calc(var(--space-3) + ${level - 1} * var(--space-4))` }, onClick: () => { focusId(node.id); select(node); if (hasChildren)
|
|
107
|
-
toggle(node.id, !isOpen); }, children: [hasChildren ? _jsx(Icon, { name: "chevron--right", size: "sm", className: "tree-twist" }) : _jsx("span", { className: "tree-indent", "aria-hidden": "true" }), node.icon && _jsx(Icon, { name: node.icon, size: "sm" }), _jsx("span", { id: labelId, className: "tree-label", children: node.label })] }), hasChildren && isOpen && renderNodes(node.children, level + 1)] }, node.id);
|
|
108
|
-
}) }));
|
|
109
|
-
return renderNodes(items, 1);
|
|
110
|
-
}
|
|
111
|
-
function sidebarList(items, ctx, sub, labelledBy) {
|
|
112
|
-
return _jsx("ul", { className: cx("sidebar-list", sub && "sidebar-sub"), "aria-labelledby": labelledBy, children: items.map(it => {
|
|
113
|
-
const lid = ctx.baseId + it.id;
|
|
114
|
-
const filhos = it.items?.length ? it.items : undefined;
|
|
115
|
-
// Rótulo escondido vira `.sr-only` em vez de sumir do DOM: na lateral recolhida o item
|
|
116
|
-
// continua tendo nome para quem usa leitor de tela. Ícone sozinho não nomeia nada.
|
|
117
|
-
const oculto = (no) => ctx.collapsed ? _jsx("span", { className: "sr-only", children: no }) : no;
|
|
118
|
-
if (filhos && !it.href && !it.onClick)
|
|
119
|
-
return _jsxs("li", { children: [_jsx("p", { id: lid, className: cx("sidebar-group-label", ctx.collapsed && "sr-only"), children: it.label }), sidebarList(filhos, ctx, false, lid)] }, it.id);
|
|
120
|
-
const ativo = it.id === ctx.current;
|
|
121
|
-
const miolo = _jsxs(_Fragment, { children: [it.icon && _jsx(Icon, { name: it.icon, size: "sm" }), _jsx("span", { className: cx("sidebar-label", ctx.collapsed && "sr-only"), children: it.label }), it.badge != null && oculto(it.badge)] });
|
|
122
|
-
return _jsxs("li", { children: [it.href
|
|
123
|
-
? _jsx("a", { id: lid, href: it.href, className: "sidebar-item", "aria-current": ativo ? "page" : undefined, onClick: it.onClick, children: miolo })
|
|
124
|
-
: _jsx("button", { id: lid, type: "button", className: "sidebar-item", "aria-current": ativo ? "page" : undefined, onClick: it.onClick, children: miolo }), filhos && sidebarList(filhos, ctx, true, lid)] }, it.id);
|
|
125
|
-
}) });
|
|
126
|
-
}
|
|
127
|
-
export function Sidebar({ items, current, collapsed, label, children, className, ...props }) {
|
|
128
|
-
const s = useAureaStrings();
|
|
129
|
-
const baseId = React.useId();
|
|
130
|
-
return _jsxs("aside", { className: cx("sidebar", collapsed && "sidebar-collapsed", className), ...props, children: [items && items.length > 0 && _jsx("nav", { className: "sidebar-nav", "aria-label": label ?? s.sidebarLabel, children: sidebarList(items, { baseId, current, collapsed }) }), children] });
|
|
131
|
-
}
|
|
132
|
-
export function Topbar({ variant = "floating", brand, children, className, ...props }) { return _jsxs("header", { className: cx("topbar", `topbar-${variant}`, className), ...props, children: [brand != null && _jsx("div", { className: "brand", children: brand }), children] }); }
|
|
133
|
-
// Shell NÃO-modal de propósito: é presentational (o consumidor controla open) e não
|
|
134
|
-
// tem focus trap/inert/Escape — declarar aria-modal sem entregar a modalidade faria
|
|
135
|
-
// leitores ocultarem o resto da página com o teclado ainda alcançando tudo
|
|
136
|
-
// (auditoria 18/07/2026, ALTO 2; APG dialog-modal). Modal de verdade = BaseDialog.
|
|
137
|
-
export function CommandPaletteShell({ open, query, onQueryChange, children }) { const s = useAureaStrings(); if (!open)
|
|
138
|
-
return null; return _jsx("div", { className: "command-overlay", children: _jsxs("div", { className: "command-palette", role: "dialog", "aria-label": s.commandLabel, children: [_jsx(SearchField, { autoFocus: true, "aria-label": s.commandPlaceholder, value: query, onChange: e => onQueryChange(e.target.value), placeholder: s.commandPlaceholder }), children] }) }); }
|
|
1
|
+
// VITRINE da categoria — é este arquivo que `@aurea-uds/react/navigation` resolve. Sem
|
|
2
|
+
// `"use client"` de propósito: a diretiva contamina o módulo inteiro e faria a marcação pura
|
|
3
|
+
// chegar como cliente por vizinhança (ADR-0026; o check 26b reprova quem a puser de volta aqui).
|
|
4
|
+
export * from "./navigation-client.js";
|
|
5
|
+
export { Topbar } from "./markup.js";
|
package/dist/overlays.d.ts
CHANGED
|
@@ -7,6 +7,16 @@ export declare function Dialog({ open, title, children, footer, onClose }: {
|
|
|
7
7
|
footer?: ReactNode;
|
|
8
8
|
onClose: () => void;
|
|
9
9
|
}): React.JSX.Element;
|
|
10
|
+
export declare function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, destructive, onConfirm, onCancel }: {
|
|
11
|
+
open: boolean;
|
|
12
|
+
title: ReactNode;
|
|
13
|
+
description: ReactNode;
|
|
14
|
+
confirmLabel?: string;
|
|
15
|
+
cancelLabel?: string;
|
|
16
|
+
destructive?: boolean;
|
|
17
|
+
onConfirm: () => void;
|
|
18
|
+
onCancel: () => void;
|
|
19
|
+
}): React.JSX.Element;
|
|
10
20
|
export declare function Drawer({ open, title, children, onClose, side }: {
|
|
11
21
|
open: boolean;
|
|
12
22
|
title: ReactNode;
|
|
@@ -14,6 +24,19 @@ export declare function Drawer({ open, title, children, onClose, side }: {
|
|
|
14
24
|
onClose: () => void;
|
|
15
25
|
side?: "left" | "right";
|
|
16
26
|
}): React.JSX.Element;
|
|
27
|
+
export type AccessGateProps = {
|
|
28
|
+
allowed: boolean;
|
|
29
|
+
children: ReactElement;
|
|
30
|
+
} & ({
|
|
31
|
+
mode?: "hide";
|
|
32
|
+
fallback?: ReactNode;
|
|
33
|
+
reason?: never;
|
|
34
|
+
} | {
|
|
35
|
+
mode: "disable";
|
|
36
|
+
reason: ReactNode;
|
|
37
|
+
fallback?: never;
|
|
38
|
+
});
|
|
39
|
+
export declare function AccessGate({ allowed, children, ...resto }: AccessGateProps): React.JSX.Element;
|
|
17
40
|
export type OverlaySide = "top" | "right" | "bottom" | "left";
|
|
18
41
|
export declare function Tooltip({ children, content, side }: {
|
|
19
42
|
children: ReactElement;
|
package/dist/overlays.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } 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
5
|
// internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { Dialog as BaseDialog } from "@base-ui/react/dialog";
|
|
8
|
+
import { AlertDialog as BaseAlertDialog } from "@base-ui/react/alert-dialog";
|
|
8
9
|
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
9
10
|
import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
|
|
10
11
|
import { Menu as BaseMenu } from "@base-ui/react/menu";
|
|
@@ -12,10 +13,53 @@ import { ContextMenu as BaseContextMenu } from "@base-ui/react/context-menu";
|
|
|
12
13
|
import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
|
|
13
14
|
import { cx, useAureaStrings, usePortalContainer } from "./internal.js";
|
|
14
15
|
import { Icon } from "./system.js";
|
|
16
|
+
import { Button } from "./actions.js";
|
|
15
17
|
export function Dialog({ open, title, children, footer, onClose }) { const s = useAureaStrings(); const portal = usePortalContainer(); return _jsx(BaseDialog.Root, { open: open, onOpenChange: o => { if (!o)
|
|
16
18
|
onClose(); }, children: _jsxs(BaseDialog.Portal, { container: portal, children: [_jsx(BaseDialog.Backdrop, { className: "dialog-backdrop" }), _jsxs(BaseDialog.Popup, { className: "dialog", 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, children: _jsx(Icon, { name: "close" }) })] }), _jsx("div", { className: "dialog-body", children: children }), footer && _jsx("footer", { children: footer })] })] }) }); }
|
|
19
|
+
// ConfirmDialog (M5): a decisão que não se fecha por engano. NÃO é um Dialog com dois botões —
|
|
20
|
+
// é `role="alertdialog"`, e a diferença é de comportamento, não de aparência: o Base UI tira do
|
|
21
|
+
// AlertDialog.Root as props `modal` e `disablePointerDismissal` (medido no d.ts de 1.6.0), ou
|
|
22
|
+
// seja, clicar fora NÃO fecha. Num Dialog comum, clicar fora vira "cancelei" sem a pessoa ter
|
|
23
|
+
// decidido — que é exatamente o acidente que este componente existe para impedir.
|
|
24
|
+
//
|
|
25
|
+
// FOCO NO BOTÃO SEGURO: quem abre um "isto apaga" e aperta Enter por reflexo tem de cancelar,
|
|
26
|
+
// não apagar. As quatro referências convergem em cancelar-antes-de-agir na ORDEM visual, e
|
|
27
|
+
// nenhuma delas move o foco — este passo saiu de medir o teclado, não de ler.
|
|
28
|
+
//
|
|
29
|
+
// DUAS coisas garantem, e as duas foram medidas em 13/08/2026, uma de cada vez:
|
|
30
|
+
// • a ORDEM do DOM — o Cancelar vem primeiro, e o motor foca o primeiro focável. Sozinha, ela
|
|
31
|
+
// já faz o teste passar; tirar só o `initialFocus` NÃO reprova.
|
|
32
|
+
// • o `initialFocus`, que é o cinto: com a ordem dos dois botões INVERTIDA ele continua
|
|
33
|
+
// segurando o foco no Cancelar, e é aí que ele prova que não é enfeite. Sem ele e com a
|
|
34
|
+
// ordem invertida, o teste reprova — que é o defeito de verdade, porque inverter a ordem é
|
|
35
|
+
// uma mudança de aparência que alguém faz sem pensar no teclado.
|
|
36
|
+
// O teste cobra o EFEITO ("o foco nasce no seguro"), não o mecanismo. É por isso que ele
|
|
37
|
+
// sobrevive a trocar um dos dois — e reprova quando os dois somem.
|
|
38
|
+
//
|
|
39
|
+
// ESCOPO MENOR que a referência (BUILDING.md §5): lá são nove peças compostas
|
|
40
|
+
// (Root/Trigger/Content/Header/Title/Description/Footer/Cancel/Action). Aqui é uma prop `open`,
|
|
41
|
+
// como no `Dialog` e no `Drawer` — a composição não acrescenta escolha nenhuma num diálogo cujo
|
|
42
|
+
// corpo é uma frase e dois botões.
|
|
43
|
+
//
|
|
44
|
+
// `description` é prop e não `children` porque ela é o nó de `aria-describedby`: o AlertDialog
|
|
45
|
+
// só anuncia o que passa pelo `Description`. Como `children`, um consumidor poria um <div> no
|
|
46
|
+
// meio e o leitor de tela perderia a frase que diz o que se perde.
|
|
47
|
+
export function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, destructive, onConfirm, onCancel }) {
|
|
48
|
+
const s = useAureaStrings();
|
|
49
|
+
const portal = usePortalContainer();
|
|
50
|
+
const seguro = React.useRef(null);
|
|
51
|
+
return _jsx(BaseAlertDialog.Root, { open: open, onOpenChange: o => { if (!o)
|
|
52
|
+
onCancel(); }, children: _jsxs(BaseAlertDialog.Portal, { container: portal, children: [_jsx(BaseAlertDialog.Backdrop, { className: "dialog-backdrop" }), _jsxs(BaseAlertDialog.Popup, { className: "dialog dialog-confirm", initialFocus: seguro, children: [_jsx("header", { children: _jsx(BaseAlertDialog.Title, { render: _jsx("h2", {}), children: title }) }), _jsx(BaseAlertDialog.Description, { className: "dialog-body", children: description }), _jsxs("footer", { children: [_jsx(Button, { ref: seguro, variant: "secondary", onClick: onCancel, children: cancelLabel ?? s.confirmCancel }), _jsx(Button, { variant: destructive ? "danger" : "primary", onClick: onConfirm, children: confirmLabel ?? s.confirmProceed })] })] })] }) });
|
|
53
|
+
}
|
|
17
54
|
export function Drawer({ open, title, children, onClose, side = "right" }) { const s = useAureaStrings(); const portal = usePortalContainer(); return _jsx(BaseDialog.Root, { open: open, onOpenChange: o => { if (!o)
|
|
18
55
|
onClose(); }, children: _jsxs(BaseDialog.Portal, { container: portal, children: [_jsx(BaseDialog.Backdrop, { className: "drawer-backdrop" }), _jsxs(BaseDialog.Popup, { className: cx("drawer", `drawer-${side}`), 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, children: _jsx(Icon, { name: "close" }) })] }), children] })] }) }); }
|
|
56
|
+
export function AccessGate({ allowed, children, ...resto }) {
|
|
57
|
+
if (allowed)
|
|
58
|
+
return children;
|
|
59
|
+
if (resto.mode === "disable")
|
|
60
|
+
return _jsx(Tooltip, { content: resto.reason, children: React.cloneElement(children, { "aria-disabled": true }) });
|
|
61
|
+
return _jsx(_Fragment, { children: resto.fallback ?? null });
|
|
62
|
+
}
|
|
19
63
|
// `role="tooltip"` + `aria-describedby` no disparador é o que faz a dica EXISTIR para leitor
|
|
20
64
|
// de tela. Medido em 30/07/2026: sem isso, o popup saía sem role e sem id, e o disparador sem
|
|
21
65
|
// aria-describedby — quem navega por leitor de tela ouvia só o rótulo do botão e nunca o
|
package/dist/pure.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ export declare const universalStates: readonly UniversalState[];
|
|
|
4
4
|
export declare const stateSeverity: (state: UniversalState) => "info" | "warning";
|
|
5
5
|
export interface AureaStrings {
|
|
6
6
|
close: string;
|
|
7
|
+
confirmCancel: string;
|
|
8
|
+
dataError: string;
|
|
9
|
+
dataEmpty: string;
|
|
10
|
+
confirmProceed: string;
|
|
7
11
|
paginationLabel: string;
|
|
8
12
|
previous: string;
|
|
9
13
|
next: string;
|
|
@@ -68,6 +72,22 @@ export interface AureaStrings {
|
|
|
68
72
|
mediaSkipForward: string;
|
|
69
73
|
mediaFullscreenEnter: string;
|
|
70
74
|
mediaFullscreenExit: string;
|
|
75
|
+
carouselLabel: string;
|
|
76
|
+
carouselSlide: string;
|
|
77
|
+
positionOf: string;
|
|
78
|
+
carouselPrev: string;
|
|
79
|
+
carouselNext: string;
|
|
80
|
+
galleryLabel: string;
|
|
81
|
+
sortableLabel: string;
|
|
82
|
+
sortableHandle: string;
|
|
83
|
+
sortableHelp: string;
|
|
84
|
+
sortableGrabbed: string;
|
|
85
|
+
sortableDropped: string;
|
|
86
|
+
sortableMoved: string;
|
|
87
|
+
sortableCanceled: string;
|
|
88
|
+
blockEditorLabel: string;
|
|
89
|
+
blockLabel: string;
|
|
90
|
+
blockRemove: string;
|
|
71
91
|
uploadSending: string;
|
|
72
92
|
uploadCancel: string;
|
|
73
93
|
uploadRetry: string;
|
|
@@ -164,3 +184,13 @@ export declare function gridStateFromParams(params: URLSearchParams, filters?: A
|
|
|
164
184
|
column: string;
|
|
165
185
|
facet?: boolean;
|
|
166
186
|
}>): GridState;
|
|
187
|
+
export interface ScreenState extends GridState {
|
|
188
|
+
tab?: string;
|
|
189
|
+
view?: string;
|
|
190
|
+
detail?: string;
|
|
191
|
+
}
|
|
192
|
+
export declare function screenStateToParams(state: ScreenState, into?: URLSearchParams): URLSearchParams;
|
|
193
|
+
export declare function screenStateFromParams(params: URLSearchParams, filters?: Array<{
|
|
194
|
+
column: string;
|
|
195
|
+
facet?: boolean;
|
|
196
|
+
}>): ScreenState;
|
package/dist/pure.js
CHANGED
|
@@ -21,10 +21,10 @@ export const universalStates = ["waiting_user", "waiting_approval", "waiting_dep
|
|
|
21
21
|
// perdeu qualidade é avisado. Um `role="alert"` aqui interromperia o leitor de tela por uma
|
|
22
22
|
// condição que não pede ação imediata, que é o oposto do que o papel serve.
|
|
23
23
|
export const stateSeverity = (state) => state.startsWith("waiting_") ? "info" : "warning";
|
|
24
|
-
export const defaultStrings = { close: "Close", paginationLabel: "Pagination", previous: "Previous", next: "Next", breadcrumbLabel: "Breadcrumb", tabsLabel: "Tabs", optionsLabel: "Options", tableLabel: "Table", commandLabel: "Command palette", commandPlaceholder: "Type a command…", dismissNotification: "Dismiss notification", toolbarLabel: "Toolbar", loading: "Loading", otpDigit: "Digit", stepperLabel: "Steps", increment: "Increase", decrement: "Decrease", comboboxEmpty: "No results", comboboxClear: "Clear selection", comboboxOpen: "Open list", comboboxRemove: "Remove", comboboxLoading: "Loading…", fileDropPrompt: "Drag files here or click to select", fileAdded: "File added", fileRemoved: "File removed", fileRemove: "Remove", fileTooLarge: "File exceeds the size limit", fileWrongType: "File type not allowed", treeLabel: "Tree", notificationsLabel: "Notifications", notificationMarkAll: "Mark all as read", notificationEmpty: "No notifications", notificationUnread: "Unread", notificationNew: "new notifications", dataGridFilter: "Filter", dataGridEmpty: "No results", dataGridSelectAll: "Select all rows", dataGridSelectRow: "Select row", dataGridSelected: "selected", dataGridClearSelection: "Clear selection", dataGridBulkLabel: "Bulk actions", dataGridColumns: "Columns", dataGridResize: "Resize column", dataGridStale: "Showing data that may be out of date.", dataGridPartial: "Some rows could not be loaded. What you see is incomplete.", dataGridError: "The rows could not be loaded.", dataGridDetails: "Details", dataGridDetailPanel: "Row detail", dataGridExport: "Export", dataGridExportRows: "rows", dataGridExportFiltered: "filtered rows", dataGridExportSelected: "selected rows", mediaPlayer: "Media player", mediaPlay: "Play", mediaPause: "Pause", mediaMute: "Mute", mediaUnmute: "Unmute", mediaSeek: "Seek", mediaVolume: "Volume", mediaCaptionsShow: "Show captions", mediaCaptionsHide: "Hide captions", mediaSkipBack: "Skip back 10 seconds", mediaSkipForward: "Skip forward 10 seconds", mediaFullscreenEnter: "Enter full screen", mediaFullscreenExit: "Exit full screen", uploadSending: "Uploading", uploadCancel: "Cancel upload", uploadRetry: "Retry upload", uploadError: "Upload failed", uploadCanceled: "Upload canceled", uploadComplete: "Upload complete", uploadPause: "Pause upload", uploadResume: "Resume upload", uploadPaused: "Paused", uploadPending: "Waiting", uploadChecksum: "Checksum", uploadChecksumBad: "The server received different bytes than the ones sent.", fileConflict: "A file with this name is already in the queue", fileReplace: "Replace", fileKeepBoth: "Keep both", fileSkip: "Skip", uploadReceipt: "Receipt", uploadReceiptCopy: "Copy receipt", agentInspector: "Agent inspector", invocationLabel: "Invocation", invocationInput: "Input", invocationOutput: "Output", taskQueueLabel: "Task queue", taskState: { queued: "Queued", running: "Running", completed: "Completed", failed: "Failed", blocked: "Blocked", paused: "Paused" }, taskPriority: { low: "Low", medium: "Medium", high: "High" }, approvalLabel: "Approval", approvalApprove: "Approve", approvalDeny: "Deny", approvalApproved: "Approved", approvalDenied: "Denied", approvalDeadline: "Decide by", approvalRisk: { low: "Low risk", medium: "Medium risk", high: "High risk" }, permissionLabel: "Tool permissions", permissionAsk: "Ask", permissionAlways: "Always", permissionNever: "Never", eventStreamLabel: "Events", traceLabel: "Trace", healthLabel: "Health", healthState: { operational: "Operational", degraded: "Degraded", down: "Down", maintenance: "Maintenance", unknown: "Unknown" }, modelUsageLabel: "Model usage", usageMetric: { tokens: "Tokens", cost: "Cost", requests: "Requests" }, costMeterLabel: "Cost", costMeterSpent: "Spent", costMeterRemaining: "left", costMeterExceeded: "Over the limit", costMeterNear: "Spending is past the soft limit.", costMeterOver: "The limit has been reached. Further calls are blocked.", memoryLabel: "Memory ledger", memoryProvenance: "Where this came from", memoryOperation: { added: "Added", updated: "Updated", recalled: "Recalled", forgotten: "Forgotten" }, memoryScope: { episodic: "Episodic", semantic: "Semantic", procedural: "Procedural" }, agentMessageLabel: "Agent messages", agentMessageTo: "to", agentMessageBroadcast: "all agents", agentMessageReason: "Why it went this way", agentMessageKind: { request: "Request", response: "Response", handoff: "Handoff", broadcast: "Broadcast", error: "Error" }, automationWhen: "When", automationThen: "Then", automationEnabled: "Enabled", automationLastRun: "Last run", automationResult: { success: "Succeeded", failure: "Failed" }, graphLabel: "Dependency graph", agentState: { idle: "Idle", thinking: "Thinking", running: "Running", paused: "Paused", error: "Error", completed: "Completed" }, codeEditor: "Code editor", chatLabel: "Conversation", chatMessage: "Message", chatSend: "Send", qrCode: "QR code", chartLabel: "Chart", copyCode: "Copy code", tocLabel: "On this page", navigationToggle: "Navigation", sidebarLabel: "Sidebar", universalState: { waiting_user: "Waiting for someone to act.", waiting_approval: "Waiting for approval.", waiting_dependency: "Waiting for something else to finish.", offline: "No connection. This was loaded earlier.", stale: "This may be out of date.", partial: "Some of this could not be loaded.", degraded: "Working with reduced capability." } };
|
|
24
|
+
export const defaultStrings = { close: "Close", confirmCancel: "Cancel", dataError: "This could not be loaded.", dataEmpty: "Nothing here yet", confirmProceed: "Continue", paginationLabel: "Pagination", previous: "Previous", next: "Next", breadcrumbLabel: "Breadcrumb", tabsLabel: "Tabs", optionsLabel: "Options", tableLabel: "Table", commandLabel: "Command palette", commandPlaceholder: "Type a command…", dismissNotification: "Dismiss notification", toolbarLabel: "Toolbar", loading: "Loading", otpDigit: "Digit", stepperLabel: "Steps", increment: "Increase", decrement: "Decrease", comboboxEmpty: "No results", comboboxClear: "Clear selection", comboboxOpen: "Open list", comboboxRemove: "Remove", comboboxLoading: "Loading…", fileDropPrompt: "Drag files here or click to select", fileAdded: "File added", fileRemoved: "File removed", fileRemove: "Remove", fileTooLarge: "File exceeds the size limit", fileWrongType: "File type not allowed", treeLabel: "Tree", notificationsLabel: "Notifications", notificationMarkAll: "Mark all as read", notificationEmpty: "No notifications", notificationUnread: "Unread", notificationNew: "new notifications", dataGridFilter: "Filter", dataGridEmpty: "No results", dataGridSelectAll: "Select all rows", dataGridSelectRow: "Select row", dataGridSelected: "selected", dataGridClearSelection: "Clear selection", dataGridBulkLabel: "Bulk actions", dataGridColumns: "Columns", dataGridResize: "Resize column", dataGridStale: "Showing data that may be out of date.", dataGridPartial: "Some rows could not be loaded. What you see is incomplete.", dataGridError: "The rows could not be loaded.", dataGridDetails: "Details", dataGridDetailPanel: "Row detail", dataGridExport: "Export", dataGridExportRows: "rows", dataGridExportFiltered: "filtered rows", dataGridExportSelected: "selected rows", mediaPlayer: "Media player", mediaPlay: "Play", mediaPause: "Pause", mediaMute: "Mute", mediaUnmute: "Unmute", mediaSeek: "Seek", mediaVolume: "Volume", mediaCaptionsShow: "Show captions", mediaCaptionsHide: "Hide captions", mediaSkipBack: "Skip back 10 seconds", mediaSkipForward: "Skip forward 10 seconds", mediaFullscreenEnter: "Enter full screen", mediaFullscreenExit: "Exit full screen", carouselLabel: "Carousel", carouselSlide: "Slide", positionOf: "of", carouselPrev: "Previous slide", carouselNext: "Next slide", galleryLabel: "Gallery", sortableLabel: "Sortable list", sortableHandle: "Reorder", sortableHelp: "Press Space to pick this up, then Arrow Up and Arrow Down to move it. Space drops it, Escape puts it back.", sortableGrabbed: "Picked up", sortableDropped: "Dropped", sortableMoved: "Moved", sortableCanceled: "Put back", blockEditorLabel: "Content blocks", blockLabel: "Block", blockRemove: "Remove block", uploadSending: "Uploading", uploadCancel: "Cancel upload", uploadRetry: "Retry upload", uploadError: "Upload failed", uploadCanceled: "Upload canceled", uploadComplete: "Upload complete", uploadPause: "Pause upload", uploadResume: "Resume upload", uploadPaused: "Paused", uploadPending: "Waiting", uploadChecksum: "Checksum", uploadChecksumBad: "The server received different bytes than the ones sent.", fileConflict: "A file with this name is already in the queue", fileReplace: "Replace", fileKeepBoth: "Keep both", fileSkip: "Skip", uploadReceipt: "Receipt", uploadReceiptCopy: "Copy receipt", agentInspector: "Agent inspector", invocationLabel: "Invocation", invocationInput: "Input", invocationOutput: "Output", taskQueueLabel: "Task queue", taskState: { queued: "Queued", running: "Running", completed: "Completed", failed: "Failed", blocked: "Blocked", paused: "Paused" }, taskPriority: { low: "Low", medium: "Medium", high: "High" }, approvalLabel: "Approval", approvalApprove: "Approve", approvalDeny: "Deny", approvalApproved: "Approved", approvalDenied: "Denied", approvalDeadline: "Decide by", approvalRisk: { low: "Low risk", medium: "Medium risk", high: "High risk" }, permissionLabel: "Tool permissions", permissionAsk: "Ask", permissionAlways: "Always", permissionNever: "Never", eventStreamLabel: "Events", traceLabel: "Trace", healthLabel: "Health", healthState: { operational: "Operational", degraded: "Degraded", down: "Down", maintenance: "Maintenance", unknown: "Unknown" }, modelUsageLabel: "Model usage", usageMetric: { tokens: "Tokens", cost: "Cost", requests: "Requests" }, costMeterLabel: "Cost", costMeterSpent: "Spent", costMeterRemaining: "left", costMeterExceeded: "Over the limit", costMeterNear: "Spending is past the soft limit.", costMeterOver: "The limit has been reached. Further calls are blocked.", memoryLabel: "Memory ledger", memoryProvenance: "Where this came from", memoryOperation: { added: "Added", updated: "Updated", recalled: "Recalled", forgotten: "Forgotten" }, memoryScope: { episodic: "Episodic", semantic: "Semantic", procedural: "Procedural" }, agentMessageLabel: "Agent messages", agentMessageTo: "to", agentMessageBroadcast: "all agents", agentMessageReason: "Why it went this way", agentMessageKind: { request: "Request", response: "Response", handoff: "Handoff", broadcast: "Broadcast", error: "Error" }, automationWhen: "When", automationThen: "Then", automationEnabled: "Enabled", automationLastRun: "Last run", automationResult: { success: "Succeeded", failure: "Failed" }, graphLabel: "Dependency graph", agentState: { idle: "Idle", thinking: "Thinking", running: "Running", paused: "Paused", error: "Error", completed: "Completed" }, codeEditor: "Code editor", chatLabel: "Conversation", chatMessage: "Message", chatSend: "Send", qrCode: "QR code", chartLabel: "Chart", copyCode: "Copy code", tocLabel: "On this page", navigationToggle: "Navigation", sidebarLabel: "Sidebar", universalState: { waiting_user: "Waiting for someone to act.", waiting_approval: "Waiting for approval.", waiting_dependency: "Waiting for something else to finish.", offline: "No connection. This was loaded earlier.", stale: "This may be out of date.", partial: "Some of this could not be loaded.", degraded: "Working with reduced capability." } };
|
|
25
25
|
// pt-BR preservado como locale (mesmos valores que já eram o default): passe
|
|
26
26
|
// <AureaProvider strings={ptBR}> para restaurar português.
|
|
27
|
-
export const ptBR = { close: "Fechar", paginationLabel: "Paginação", previous: "Anterior", next: "Próxima", breadcrumbLabel: "Breadcrumb", tabsLabel: "Abas", optionsLabel: "Opções", tableLabel: "Tabela", commandLabel: "Paleta de comandos", commandPlaceholder: "Digite um comando…", dismissNotification: "Dispensar notificação", toolbarLabel: "Barra de ferramentas", loading: "Carregando", otpDigit: "Dígito", stepperLabel: "Etapas", increment: "Aumentar", decrement: "Diminuir", comboboxEmpty: "Nenhum resultado", comboboxClear: "Limpar seleção", comboboxOpen: "Abrir lista", comboboxRemove: "Remover", comboboxLoading: "Carregando…", fileDropPrompt: "Arraste arquivos aqui ou clique para selecionar", fileAdded: "Arquivo adicionado", fileRemoved: "Arquivo removido", fileRemove: "Remover", fileTooLarge: "Arquivo maior que o limite", fileWrongType: "Tipo de arquivo não aceito", treeLabel: "Árvore", notificationsLabel: "Notificações", notificationMarkAll: "Marcar todas como lidas", notificationEmpty: "Nenhuma notificação", notificationUnread: "Não lida", notificationNew: "novas notificações", dataGridFilter: "Filtrar", dataGridEmpty: "Nenhum resultado", dataGridSelectAll: "Selecionar todas as linhas", dataGridSelectRow: "Selecionar linha", dataGridSelected: "selecionadas", dataGridClearSelection: "Limpar seleção", dataGridBulkLabel: "Ações em lote", dataGridColumns: "Colunas", dataGridResize: "Redimensionar coluna", dataGridStale: "Mostrando dados que podem estar desatualizados.", dataGridPartial: "Algumas linhas não puderam ser carregadas. O que aparece está incompleto.", dataGridError: "Não foi possível carregar as linhas.", dataGridDetails: "Detalhes", dataGridDetailPanel: "Detalhe da linha", dataGridExport: "Exportar", dataGridExportRows: "linhas", dataGridExportFiltered: "linhas filtradas", dataGridExportSelected: "linhas selecionadas", mediaPlayer: "Reprodutor de mídia", mediaPlay: "Reproduzir", mediaPause: "Pausar", mediaMute: "Silenciar", mediaUnmute: "Ativar som", mediaSeek: "Posição da reprodução", mediaVolume: "Volume", mediaCaptionsShow: "Ativar legendas", mediaCaptionsHide: "Desativar legendas", mediaSkipBack: "Voltar 10 segundos", mediaSkipForward: "Avançar 10 segundos", mediaFullscreenEnter: "Tela cheia", mediaFullscreenExit: "Sair da tela cheia", uploadSending: "Enviando", uploadCancel: "Cancelar envio", uploadRetry: "Tentar envio novamente", uploadError: "Falha no envio", uploadCanceled: "Envio cancelado", uploadComplete: "Envio concluído", uploadPause: "Pausar envio", uploadResume: "Retomar envio", uploadPaused: "Pausado", uploadPending: "Aguardando", uploadChecksum: "Soma de verificação", uploadChecksumBad: "O servidor recebeu bytes diferentes dos enviados.", fileConflict: "Já existe um arquivo com este nome na fila", fileReplace: "Substituir", fileKeepBoth: "Manter os dois", fileSkip: "Pular", uploadReceipt: "Recibo", uploadReceiptCopy: "Copiar recibo", agentInspector: "Inspetor do agente", invocationLabel: "Invocação", invocationInput: "Entrada", invocationOutput: "Saída", taskQueueLabel: "Fila de tarefas", taskState: { queued: "Na fila", running: "Executando", completed: "Concluída", failed: "Falhou", blocked: "Bloqueada", paused: "Pausada" }, taskPriority: { low: "Baixa", medium: "Média", high: "Alta" }, approvalLabel: "Aprovação", approvalApprove: "Aprovar", approvalDeny: "Negar", approvalApproved: "Aprovado", approvalDenied: "Negado", approvalDeadline: "Decidir até", approvalRisk: { low: "Risco baixo", medium: "Risco médio", high: "Risco alto" }, permissionLabel: "Permissões de ferramenta", permissionAsk: "Perguntar", permissionAlways: "Sempre", permissionNever: "Nunca", eventStreamLabel: "Eventos", traceLabel: "Rastro", healthLabel: "Saúde", healthState: { operational: "Operando", degraded: "Degradado", down: "Fora do ar", maintenance: "Em manutenção", unknown: "Desconhecido" }, modelUsageLabel: "Consumo por modelo", usageMetric: { tokens: "Tokens", cost: "Custo", requests: "Chamadas" }, costMeterLabel: "Custo", costMeterSpent: "Gasto", costMeterRemaining: "restantes", costMeterExceeded: "Acima do limite", costMeterNear: "O gasto passou do limite brando.", costMeterOver: "O limite foi atingido. As próximas chamadas estão bloqueadas.", memoryLabel: "Livro-razão de memória", memoryProvenance: "De onde isto veio", memoryOperation: { added: "Guardada", updated: "Atualizada", recalled: "Lembrada", forgotten: "Esquecida" }, memoryScope: { episodic: "Episódica", semantic: "Semântica", procedural: "Procedural" }, agentMessageLabel: "Recados entre agentes", agentMessageTo: "para", agentMessageBroadcast: "todos os agentes", agentMessageReason: "Por que foi por aqui", agentMessageKind: { request: "Pedido", response: "Resposta", handoff: "Passagem", broadcast: "Difusão", error: "Erro" }, automationWhen: "Quando", automationThen: "Então", automationEnabled: "Ativa", automationLastRun: "Última execução", automationResult: { success: "Concluiu", failure: "Falhou" }, graphLabel: "Grafo de dependências", agentState: { idle: "Ocioso", thinking: "Pensando", running: "Executando", paused: "Pausado", error: "Erro", completed: "Concluído" }, codeEditor: "Editor de código", chatLabel: "Conversa", chatMessage: "Mensagem", chatSend: "Enviar", qrCode: "Código QR", chartLabel: "Gráfico", copyCode: "Copiar código", tocLabel: "Nesta página", navigationToggle: "Navegação", sidebarLabel: "Lateral", universalState: { waiting_user: "Esperando alguém agir.", waiting_approval: "Esperando aprovação.", waiting_dependency: "Esperando outra coisa terminar.", offline: "Sem conexão. Isto foi carregado antes.", stale: "Isto pode estar desatualizado.", partial: "Parte disto não pôde ser carregada.", degraded: "Funcionando com capacidade reduzida." } };
|
|
27
|
+
export const ptBR = { close: "Fechar", confirmCancel: "Cancelar", dataError: "Não foi possível carregar.", dataEmpty: "Ainda não há nada aqui", confirmProceed: "Continuar", paginationLabel: "Paginação", previous: "Anterior", next: "Próxima", breadcrumbLabel: "Breadcrumb", tabsLabel: "Abas", optionsLabel: "Opções", tableLabel: "Tabela", commandLabel: "Paleta de comandos", commandPlaceholder: "Digite um comando…", dismissNotification: "Dispensar notificação", toolbarLabel: "Barra de ferramentas", loading: "Carregando", otpDigit: "Dígito", stepperLabel: "Etapas", increment: "Aumentar", decrement: "Diminuir", comboboxEmpty: "Nenhum resultado", comboboxClear: "Limpar seleção", comboboxOpen: "Abrir lista", comboboxRemove: "Remover", comboboxLoading: "Carregando…", fileDropPrompt: "Arraste arquivos aqui ou clique para selecionar", fileAdded: "Arquivo adicionado", fileRemoved: "Arquivo removido", fileRemove: "Remover", fileTooLarge: "Arquivo maior que o limite", fileWrongType: "Tipo de arquivo não aceito", treeLabel: "Árvore", notificationsLabel: "Notificações", notificationMarkAll: "Marcar todas como lidas", notificationEmpty: "Nenhuma notificação", notificationUnread: "Não lida", notificationNew: "novas notificações", dataGridFilter: "Filtrar", dataGridEmpty: "Nenhum resultado", dataGridSelectAll: "Selecionar todas as linhas", dataGridSelectRow: "Selecionar linha", dataGridSelected: "selecionadas", dataGridClearSelection: "Limpar seleção", dataGridBulkLabel: "Ações em lote", dataGridColumns: "Colunas", dataGridResize: "Redimensionar coluna", dataGridStale: "Mostrando dados que podem estar desatualizados.", dataGridPartial: "Algumas linhas não puderam ser carregadas. O que aparece está incompleto.", dataGridError: "Não foi possível carregar as linhas.", dataGridDetails: "Detalhes", dataGridDetailPanel: "Detalhe da linha", dataGridExport: "Exportar", dataGridExportRows: "linhas", dataGridExportFiltered: "linhas filtradas", dataGridExportSelected: "linhas selecionadas", mediaPlayer: "Reprodutor de mídia", mediaPlay: "Reproduzir", mediaPause: "Pausar", mediaMute: "Silenciar", mediaUnmute: "Ativar som", mediaSeek: "Posição da reprodução", mediaVolume: "Volume", mediaCaptionsShow: "Ativar legendas", mediaCaptionsHide: "Desativar legendas", mediaSkipBack: "Voltar 10 segundos", mediaSkipForward: "Avançar 10 segundos", mediaFullscreenEnter: "Tela cheia", mediaFullscreenExit: "Sair da tela cheia", carouselLabel: "Carrossel", carouselSlide: "Slide", positionOf: "de", carouselPrev: "Slide anterior", carouselNext: "Próximo slide", galleryLabel: "Galeria", sortableLabel: "Lista ordenável", sortableHandle: "Reordenar", sortableHelp: "Aperte Espaço para pegar, e as setas para cima e para baixo para mover. Espaço solta, Esc devolve ao lugar.", sortableGrabbed: "Pego", sortableDropped: "Solto", sortableMoved: "Movido", sortableCanceled: "Devolvido", blockEditorLabel: "Blocos de conteúdo", blockLabel: "Bloco", blockRemove: "Remover bloco", uploadSending: "Enviando", uploadCancel: "Cancelar envio", uploadRetry: "Tentar envio novamente", uploadError: "Falha no envio", uploadCanceled: "Envio cancelado", uploadComplete: "Envio concluído", uploadPause: "Pausar envio", uploadResume: "Retomar envio", uploadPaused: "Pausado", uploadPending: "Aguardando", uploadChecksum: "Soma de verificação", uploadChecksumBad: "O servidor recebeu bytes diferentes dos enviados.", fileConflict: "Já existe um arquivo com este nome na fila", fileReplace: "Substituir", fileKeepBoth: "Manter os dois", fileSkip: "Pular", uploadReceipt: "Recibo", uploadReceiptCopy: "Copiar recibo", agentInspector: "Inspetor do agente", invocationLabel: "Invocação", invocationInput: "Entrada", invocationOutput: "Saída", taskQueueLabel: "Fila de tarefas", taskState: { queued: "Na fila", running: "Executando", completed: "Concluída", failed: "Falhou", blocked: "Bloqueada", paused: "Pausada" }, taskPriority: { low: "Baixa", medium: "Média", high: "Alta" }, approvalLabel: "Aprovação", approvalApprove: "Aprovar", approvalDeny: "Negar", approvalApproved: "Aprovado", approvalDenied: "Negado", approvalDeadline: "Decidir até", approvalRisk: { low: "Risco baixo", medium: "Risco médio", high: "Risco alto" }, permissionLabel: "Permissões de ferramenta", permissionAsk: "Perguntar", permissionAlways: "Sempre", permissionNever: "Nunca", eventStreamLabel: "Eventos", traceLabel: "Rastro", healthLabel: "Saúde", healthState: { operational: "Operando", degraded: "Degradado", down: "Fora do ar", maintenance: "Em manutenção", unknown: "Desconhecido" }, modelUsageLabel: "Consumo por modelo", usageMetric: { tokens: "Tokens", cost: "Custo", requests: "Chamadas" }, costMeterLabel: "Custo", costMeterSpent: "Gasto", costMeterRemaining: "restantes", costMeterExceeded: "Acima do limite", costMeterNear: "O gasto passou do limite brando.", costMeterOver: "O limite foi atingido. As próximas chamadas estão bloqueadas.", memoryLabel: "Livro-razão de memória", memoryProvenance: "De onde isto veio", memoryOperation: { added: "Guardada", updated: "Atualizada", recalled: "Lembrada", forgotten: "Esquecida" }, memoryScope: { episodic: "Episódica", semantic: "Semântica", procedural: "Procedural" }, agentMessageLabel: "Recados entre agentes", agentMessageTo: "para", agentMessageBroadcast: "todos os agentes", agentMessageReason: "Por que foi por aqui", agentMessageKind: { request: "Pedido", response: "Resposta", handoff: "Passagem", broadcast: "Difusão", error: "Erro" }, automationWhen: "Quando", automationThen: "Então", automationEnabled: "Ativa", automationLastRun: "Última execução", automationResult: { success: "Concluiu", failure: "Falhou" }, graphLabel: "Grafo de dependências", agentState: { idle: "Ocioso", thinking: "Pensando", running: "Executando", paused: "Pausado", error: "Erro", completed: "Concluído" }, codeEditor: "Editor de código", chatLabel: "Conversa", chatMessage: "Mensagem", chatSend: "Enviar", qrCode: "Código QR", chartLabel: "Gráfico", copyCode: "Copiar código", tocLabel: "Nesta página", navigationToggle: "Navegação", sidebarLabel: "Lateral", universalState: { waiting_user: "Esperando alguém agir.", waiting_approval: "Esperando aprovação.", waiting_dependency: "Esperando outra coisa terminar.", offline: "Sem conexão. Isto foi carregado antes.", stale: "Isto pode estar desatualizado.", partial: "Parte disto não pôde ser carregada.", degraded: "Funcionando com capacidade reduzida." } };
|
|
28
28
|
// Sprite de ícones: CONFIGURAÇÃO DE APLICAÇÃO, então entra pelo provider, uma vez.
|
|
29
29
|
// Antes o default absoluto "/aurea-icons.svg" vivia no Icon e 15 componentes declaravam
|
|
30
30
|
// e repassavam `spriteUrl` à mão — 52 sítios de código. Consequência: aplicação servida
|
|
@@ -85,3 +85,27 @@ export function gridStateFromParams(params, filters) {
|
|
|
85
85
|
state.columnFilters = colunas;
|
|
86
86
|
return state;
|
|
87
87
|
}
|
|
88
|
+
const CHAVES_TELA = ["tab", "view", "detail"];
|
|
89
|
+
// `into` preserva o que já estava, pelo mesmo motivo do `gridStateToParams`: uma aplicação real
|
|
90
|
+
// tem `ref=`, `utm_*` e companhia na mesma URL, e serializar a tela não pode apagá-los. O que se
|
|
91
|
+
// apaga é só o que ESTE formato escreve — senão um estado que saiu continuaria na URL.
|
|
92
|
+
export function screenStateToParams(state, into) {
|
|
93
|
+
const p = gridStateToParams(state, into);
|
|
94
|
+
for (const k of CHAVES_TELA)
|
|
95
|
+
p.delete(k);
|
|
96
|
+
for (const k of CHAVES_TELA) {
|
|
97
|
+
const v = state[k];
|
|
98
|
+
if (v)
|
|
99
|
+
p.set(k, v);
|
|
100
|
+
}
|
|
101
|
+
return p;
|
|
102
|
+
}
|
|
103
|
+
export function screenStateFromParams(params, filters) {
|
|
104
|
+
const state = gridStateFromParams(params, filters);
|
|
105
|
+
for (const k of CHAVES_TELA) {
|
|
106
|
+
const v = params.get(k);
|
|
107
|
+
if (v)
|
|
108
|
+
state[k] = v;
|
|
109
|
+
}
|
|
110
|
+
return state;
|
|
111
|
+
}
|
package/dist/system.d.ts
CHANGED
|
@@ -9,6 +9,15 @@ export declare function AureaProvider({ children, strings, direction, spriteUrl,
|
|
|
9
9
|
}): React.JSX.Element;
|
|
10
10
|
export type AureaToastType = "info" | "success" | "warning" | "danger";
|
|
11
11
|
export declare const useToast: () => import("@base-ui/react").UseToastManagerReturnValue<any>;
|
|
12
|
+
export type AureaThemeName = "dark" | "light";
|
|
13
|
+
export type AureaDensity = "compact" | "comfortable" | "spacious";
|
|
14
|
+
export declare function useAureaTheme(): {
|
|
15
|
+
theme: AureaThemeName | null;
|
|
16
|
+
density: AureaDensity | null;
|
|
17
|
+
setTheme: (t: AureaThemeName) => void;
|
|
18
|
+
setDensity: (d: AureaDensity) => void;
|
|
19
|
+
toggleTheme: () => void;
|
|
20
|
+
};
|
|
12
21
|
export type IconName = string;
|
|
13
22
|
export interface IconProps extends React.SVGAttributes<SVGSVGElement> {
|
|
14
23
|
name: IconName;
|
package/dist/system.js
CHANGED
|
@@ -20,6 +20,52 @@ export function AureaProvider({ children, strings, direction = "ltr", spriteUrl
|
|
|
20
20
|
return _jsx(StringsContext.Provider, { value: value, children: _jsx(SpriteContext.Provider, { value: spriteUrl, children: _jsx(PortalContext.Provider, { value: portalContainer, children: _jsx(DirectionProvider, { direction: direction, children: _jsx(BaseToast.Provider, { children: _jsxs(BaseTooltip.Provider, { children: [children, _jsx(AureaToastViewport, {})] }) }) }) }) }) });
|
|
21
21
|
}
|
|
22
22
|
export const useToast = () => BaseToast.useToastManager();
|
|
23
|
+
// useAureaTheme (M7): ler e trocar os DOIS eixos que a Aurea põe no <html> — `data-theme` e
|
|
24
|
+
// `data-density`. Até aqui só existia `window.Aurea.setTheme` no `aurea.js`, que é vanilla: em
|
|
25
|
+
// React não havia como saber o tema atual sem enfiar a mão no DOM, e um botão de tema não sabia
|
|
26
|
+
// que ícone desenhar.
|
|
27
|
+
//
|
|
28
|
+
// O QUE ESTE HOOK NÃO FAZ, e é a parte mais importante dele — pesquisado em 13/08/2026, não
|
|
29
|
+
// suposto. O `next-themes` já resolve persistência, preferência do sistema, sincronia entre abas
|
|
30
|
+
// e o script embutido que evita o flash, e ele escreve **`data-theme` no <html>**, que é
|
|
31
|
+
// exatamente o atributo que a Aurea lê. Ou seja: os dois já se encaixam sem código nosso.
|
|
32
|
+
// Reescrever isso aqui seria trocar uma biblioteca mantida por uma cópia pior — e guardar
|
|
33
|
+
// preferência de usuário é decisão da APLICAÇÃO, não da biblioteca de interface (é o mesmo
|
|
34
|
+
// motivo pelo qual a persistência de tema do catálogo mora no catálogo).
|
|
35
|
+
// O que ele faz é o que biblioteca nenhuma faz: **densidade**, que é eixo da Aurea e não existe
|
|
36
|
+
// no `next-themes` nem em ninguém.
|
|
37
|
+
//
|
|
38
|
+
// `useSyncExternalStore` e não `useState`: o valor mora no DOM, e quem o troca pode ser outro —
|
|
39
|
+
// o `next-themes`, um script no <head>, ou o `window.Aurea` de sempre. Assinar a mutação do
|
|
40
|
+
// atributo é o que mantém o React em dia com quem manda de verdade.
|
|
41
|
+
//
|
|
42
|
+
// E `getServerSnapshot` devolve `null` de propósito. A armadilha está documentada no próprio
|
|
43
|
+
// `next-themes`: no servidor o tema é **desconhecido**, e fingir um valor produz erro de
|
|
44
|
+
// hidratação. Por isso o retorno é `theme: string|null` — enquanto for `null`, não desenhe UI que
|
|
45
|
+
// dependa do tema. É a mesma regra do "delay rendering until mounted", só que sem um `mounted`
|
|
46
|
+
// solto para o consumidor esquecer de checar.
|
|
47
|
+
const assinaHtml = (cb) => {
|
|
48
|
+
if (typeof MutationObserver === "undefined")
|
|
49
|
+
return () => { };
|
|
50
|
+
const obs = new MutationObserver(cb);
|
|
51
|
+
obs.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme", "data-density"] });
|
|
52
|
+
return () => obs.disconnect();
|
|
53
|
+
};
|
|
54
|
+
const leAtributo = (nome) => () => typeof document === "undefined" ? null : document.documentElement.getAttribute(nome);
|
|
55
|
+
const semServidor = () => null;
|
|
56
|
+
export function useAureaTheme() {
|
|
57
|
+
const theme = React.useSyncExternalStore(assinaHtml, leAtributo("data-theme"), semServidor);
|
|
58
|
+
const density = React.useSyncExternalStore(assinaHtml, leAtributo("data-density"), semServidor);
|
|
59
|
+
return React.useMemo(() => ({
|
|
60
|
+
theme, density,
|
|
61
|
+
setTheme: (t) => { document.documentElement.dataset.theme = t; },
|
|
62
|
+
setDensity: (d) => { document.documentElement.dataset.density = d; },
|
|
63
|
+
// Alternar é sobre o que está NA TELA, então `null` (servidor, ou ninguém escolheu ainda)
|
|
64
|
+
// resolve para claro e vira escuro — e não o contrário, que deixaria o primeiro clique sem
|
|
65
|
+
// efeito visível em quem estava no claro do sistema.
|
|
66
|
+
toggleTheme: () => { document.documentElement.dataset.theme = theme === "dark" ? "light" : "dark"; },
|
|
67
|
+
}), [theme, density]);
|
|
68
|
+
}
|
|
23
69
|
function AureaToastList() {
|
|
24
70
|
const { toasts } = BaseToast.useToastManager();
|
|
25
71
|
const s = useAureaStrings();
|