@aurea-uds/react 0.31.0 → 0.33.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.
@@ -24,7 +24,8 @@ export declare function Breadcrumb({ items, label }: {
24
24
  }): React.JSX.Element;
25
25
  export type TabsOrientation = "horizontal" | "vertical";
26
26
  export type TabsPanel = "card" | "plain";
27
- export declare function Tabs({ tabs, value, onChange, label, orientation, activateOnFocus, loopFocus, panel }: {
27
+ export type TabsVariant = "primary" | "secondary";
28
+ export declare function Tabs({ tabs, value, onChange, label, orientation, activateOnFocus, loopFocus, panel, variant }: {
28
29
  tabs: Array<{
29
30
  id: string;
30
31
  label: ReactNode;
@@ -37,12 +38,26 @@ export declare function Tabs({ tabs, value, onChange, label, orientation, activa
37
38
  activateOnFocus?: boolean;
38
39
  loopFocus?: boolean;
39
40
  panel?: TabsPanel;
41
+ variant?: TabsVariant;
40
42
  }): React.JSX.Element;
41
- export declare function Pagination({ page, total, onPageChange }: {
43
+ export type PaginationVariant = "numbers" | "simple" | "compact";
44
+ export interface PaginationProps {
42
45
  page: number;
43
46
  total: number;
44
- onPageChange: (p: number) => void;
45
- }): React.JSX.Element;
47
+ onPageChange?: (p: number) => void;
48
+ variant?: PaginationVariant;
49
+ /** O resumo à esquerda — "1 a 5 de 50 pedidos". */
50
+ summary?: ReactNode;
51
+ /** O endereço de cada página. Com ele, as páginas são links. */
52
+ href?: (page: number) => string;
53
+ /** Quantas páginas aparecem de cada lado da atual. Padrão: 1. */
54
+ siblings?: number;
55
+ /** O nome do marco de navegação. Padrão: a frase `paginationLabel`. Com duas paginações na mesma
56
+ * página, cada uma diz de quê ("Páginas dos pedidos"), senão o leitor de tela ouve dois marcos iguais. */
57
+ label?: string;
58
+ className?: string;
59
+ }
60
+ export declare function Pagination({ page, total, onPageChange, variant, summary, href, siblings, label, className }: PaginationProps): React.JSX.Element;
46
61
  export interface TocItem {
47
62
  id: string;
48
63
  label: string;
@@ -80,12 +95,16 @@ export interface SidebarItem {
80
95
  /** O link do roteador do app (M-01): `<Link href="/relatorios" />`. Recebe a pele, o estado de página atual e o conteúdo do item. */
81
96
  render?: ReactElement;
82
97
  }
83
- export type SidebarVariant = "floating" | "flush";
84
- export declare function Sidebar({ items, current, collapsed, variant, label, children, className, onClick, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
98
+ export type SidebarVariant = "floating" | "flush" | "plain";
99
+ export type SidebarScrollbar = "hover" | "visible";
100
+ export type SidebarPlacement = "left" | "right";
101
+ export declare function Sidebar({ items, current, collapsed, variant, placement, scrollbar, label, children, className, onClick, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
85
102
  items?: SidebarItem[];
86
103
  current?: string;
87
104
  collapsed?: boolean;
88
105
  variant?: SidebarVariant;
106
+ placement?: SidebarPlacement;
107
+ scrollbar?: SidebarScrollbar;
89
108
  label?: string;
90
109
  }): React.JSX.Element;
91
110
  export type BottomNavVariant = "floating" | "edge";
@@ -135,17 +154,26 @@ export interface CommandItem {
135
154
  icon?: IconName;
136
155
  kbd?: string;
137
156
  run: () => void;
157
+ /** 0.32.0 (DOC-06): o grupo do item ("Componentes", "Páginas"). Itens com o mesmo grupo saem juntos,
158
+ * sob o título dele, na ordem em que o grupo aparece primeiro. */
159
+ group?: string;
138
160
  }
139
- export declare function CommandPalette({ open, onClose, items, placeholder, label }: {
161
+ export declare function CommandPalette({ open, onClose, items, placeholder, label, shortcuts }: {
140
162
  open: boolean;
141
163
  onClose: () => void;
142
164
  items: CommandItem[];
143
165
  placeholder?: string;
144
166
  label?: string;
145
- }): React.JSX.Element | null;
146
- export declare function CommandPaletteShell({ open, query, onQueryChange, children }: {
167
+ /** 0.32.0 (DOC-07): a linha que ensina as teclas, embaixo — ↑ ↓ mover, Enter abrir, Esc fechar. */
168
+ shortcuts?: boolean;
169
+ }): React.JSX.Element;
170
+ export declare function CommandPaletteShell({ open, query, onQueryChange, onClose, label, children }: {
147
171
  open: boolean;
148
172
  query: string;
149
173
  onQueryChange: (v: string) => void;
174
+ /** Quem fecha: a janela avisa pelo Esc e pelo clique fora. */
175
+ onClose?: () => void;
176
+ /** O nome da janela (o padrão é o da paleta, "Command palette"). */
177
+ label?: string;
150
178
  children?: ReactNode;
151
- }): React.JSX.Element | null;
179
+ }): React.JSX.Element;
@@ -7,6 +7,7 @@ import React, { useRef } from "react";
7
7
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
8
8
  import { useDirection } from "@base-ui/react/direction-provider";
9
9
  import { Autocomplete as BaseAutocomplete } from "@base-ui/react/autocomplete";
10
+ import { Dialog as BaseDialog } from "@base-ui/react/dialog";
10
11
  import { useValorResponsivo } from "./responsivo-runtime.js";
11
12
  import { cx, fundirRender, useAureaStrings, usePortalContainer } from "./internal.js";
12
13
  import { Kbd } from "./markup.js";
@@ -29,8 +30,37 @@ export function Stepper({ items, label, className }) {
29
30
  }) });
30
31
  }
31
32
  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: "caret-right", size: "sm" }), " ", i.render ? fundirRender(i.render, { children: i.label }, "a") : i.href ? _jsx("a", { href: i.href, children: i.label }) : _jsx("strong", { "aria-current": "page", children: i.label })] }, n)) }); }
32
- export function Tabs({ tabs, value, onChange, label, orientation, activateOnFocus = true, loopFocus, panel = "card" }) { const s = useAureaStrings(); const ancora = useRef(null); const resolvida = useValorResponsivo(orientation, "horizontal", ancora); return _jsxs(BaseTabs.Root, { ref: ancora, value: value, onValueChange: v => onChange(String(v)), orientation: resolvida, className: "tabs-root", children: [_jsx(BaseTabs.List, { className: "tabs", "aria-label": label ?? s.tabsLabel, activateOnFocus: activateOnFocus, loopFocus: loopFocus, 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: panel === "plain" ? "tabs-panel" : "card card-inset", tabIndex: 0, children: t.content }, t.id))] }); }
33
- 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 })] }); }
33
+ export function Tabs({ tabs, value, onChange, label, orientation, activateOnFocus = true, loopFocus, panel = "card", variant = "primary" }) { const s = useAureaStrings(); const ancora = useRef(null); const resolvida = useValorResponsivo(orientation, "horizontal", ancora); return _jsxs(BaseTabs.Root, { ref: ancora, value: value, onValueChange: v => onChange(String(v)), orientation: resolvida, className: "tabs-root", children: [_jsx(BaseTabs.List, { className: cx("tabs", variant === "secondary" && "tabs-secondary"), "aria-label": label ?? s.tabsLabel, activateOnFocus: activateOnFocus, loopFocus: loopFocus, 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: panel === "plain" ? "tabs-panel" : "card card-inset", tabIndex: 0, children: t.content }, t.id))] }); }
34
+ function paginasVisiveis(page, total, siblings) {
35
+ if (total <= 5 + siblings * 2)
36
+ return Array.from({ length: total }, (_, i) => i + 1);
37
+ const ini = Math.max(2, page - siblings), fim = Math.min(total - 1, page + siblings);
38
+ const meio = Array.from({ length: fim - ini + 1 }, (_, i) => ini + i);
39
+ return [1, ...(ini > 2 ? ["..."] : []), ...meio, ...(fim < total - 1 ? ["..."] : []), total];
40
+ }
41
+ export function Pagination({ page, total, onPageChange, variant = "numbers", summary, href, siblings = 1, label, className }) {
42
+ const s = useAureaStrings();
43
+ if (variant === "compact")
44
+ return _jsxs("nav", { className: cx("pagination", className), "aria-label": 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 })] });
45
+ // Um item: link (com `href`) ou botão. Desligado (a primeira página no "anterior"), sem endereço.
46
+ const item = (alvo, conteudo, { atual = false, nav, rotulo } = {}) => {
47
+ const fora = alvo < 1 || alvo > total;
48
+ const cls = cx("pagination-link", nav && "pagination-link-nav", atual && "active");
49
+ const comuns = { className: cls, "aria-label": rotulo, "aria-current": atual ? "page" : undefined };
50
+ if (href)
51
+ return fora ? _jsx("a", { ...comuns, "aria-disabled": "true", children: conteudo })
52
+ : _jsx("a", { ...comuns, href: href(alvo), onClick: onPageChange ? (e) => { if (!e.metaKey && !e.ctrlKey && !e.shiftKey && e.button === 0) {
53
+ e.preventDefault();
54
+ onPageChange(alvo);
55
+ } } : undefined, children: conteudo });
56
+ return _jsx("button", { type: "button", ...comuns, disabled: fora, onClick: () => onPageChange?.(alvo), children: conteudo });
57
+ };
58
+ const anterior = item(page - 1, _jsxs(_Fragment, { children: [_jsx(Icon, { name: "caret-left", className: "pagination-nav-icon" }), _jsx("span", { children: s.previous })] }), { nav: "prev" });
59
+ const proxima = item(page + 1, _jsxs(_Fragment, { children: [_jsx("span", { children: s.next }), _jsx(Icon, { name: "caret-right", className: "pagination-nav-icon" })] }), { nav: "next" });
60
+ return _jsxs("nav", { className: cx("pagination", className), "aria-label": label ?? s.paginationLabel, children: [summary != null && _jsx("span", { className: "pagination-summary", children: summary }), _jsxs("ul", { className: "pagination-content", children: [_jsx("li", { children: anterior }), variant === "numbers" && paginasVisiveis(page, total, siblings).map((p, i) => p === "..."
61
+ ? _jsx("li", { children: _jsx("span", { className: "pagination-ellipsis", "aria-hidden": "true", children: "\u2026" }) }, `e${i}`)
62
+ : _jsx("li", { children: item(p, p, { atual: p === page, rotulo: `${s.paginationPage} ${p}` }) }, p)), _jsx("li", { children: proxima })] })] });
63
+ }
34
64
  export function TableOfContents({ items, current, label, className, ...props }) {
35
65
  const s = useAureaStrings();
36
66
  const meu = React.useRef(null);
@@ -43,7 +73,7 @@ export function TableOfContents({ items, current, label, className, ...props })
43
73
  return _jsxs("nav", { ref: n => { meu.current = n; if (typeof refDele === "function")
44
74
  refDele(n);
45
75
  else if (refDele)
46
- refDele.current = n; }, className: cx("toc", className), "aria-label": label ?? s.tocLabel, ...resto, 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 === atual ? { "aria-current": "true" } : {}), children: i.label }, i.id))] });
76
+ refDele.current = n; }, className: cx("toc", className), "aria-label": label ?? s.tocLabel, ...resto, children: [_jsxs("p", { className: "toc-label", children: [_jsx("span", { className: "toc-label-icon", "aria-hidden": "true" }), label ?? s.tocLabel] }), items.map(i => _jsx("a", { href: `#${i.id}`, className: cx(i.sub && "toc-sub"), ...(i.id === atual ? { "aria-current": "true" } : {}), children: i.label }, i.id))] });
47
77
  }
48
78
  /** Qual dos `items` está na faixa de leitura, observando o documento. Devolve `undefined` até o
49
79
  * primeiro cálculo — e em SSR, onde não há documento para observar.
@@ -235,10 +265,10 @@ function fecharGavetaAoEscolher(e) {
235
265
  }
236
266
  catch { /* motor sem popover: não há gaveta */ }
237
267
  }
238
- export function Sidebar({ items, current, collapsed, variant = "floating", label, children, className, onClick, ...props }) {
268
+ export function Sidebar({ items, current, collapsed, variant = "floating", placement = "left", scrollbar = "hover", label, children, className, onClick, ...props }) {
239
269
  const s = useAureaStrings();
240
270
  const baseId = React.useId();
241
- return _jsxs("aside", { className: cx("sidebar", variant !== "floating" && `sidebar-${variant}`, collapsed && "sidebar-collapsed", className), onClick: e => { onClick?.(e); fecharGavetaAoEscolher(e); }, ...props, children: [items && items.length > 0 && _jsx("nav", { className: "sidebar-nav", "aria-label": label ?? s.sidebarLabel, children: sidebarList(items, { baseId, current, collapsed }) }), children] });
271
+ return _jsxs("aside", { className: cx("sidebar", variant !== "floating" && `sidebar-${variant}`, collapsed && "sidebar-collapsed", placement === "right" && "sidebar-right", scrollbar === "visible" && "sidebar-scrollbar-visible", className), "data-placement": placement, onClick: e => { onClick?.(e); fecharGavetaAoEscolher(e); }, ...props, children: [items && items.length > 0 && _jsx("nav", { className: "sidebar-nav", "aria-label": label ?? s.sidebarLabel, children: sidebarList(items, { baseId, current, collapsed }) }), children] });
242
272
  }
243
273
  const LEGADO = {
244
274
  flat: ["edge", "none"], surface: ["floating", "circle"], pill: ["floating", "pill"], dock: ["floating", "circle"]
@@ -282,24 +312,50 @@ export function NavList({ items, className, ...props }) {
282
312
  : _jsx("button", { type: "button", className: "nav-list-row", "aria-disabled": it.disabled || undefined, onClick: it.disabled ? undefined : it.onClick, children: miolo }) }, it.id);
283
313
  }) });
284
314
  }
285
- export function CommandPalette({ open, onClose, items, placeholder, label }) {
315
+ export function CommandPalette({ open, onClose, items, placeholder, label, shortcuts = true }) {
286
316
  const s = useAureaStrings();
317
+ const idAtalhos = React.useId();
318
+ // GRUPOS (0.32.0, DOC-06). Em 13/08/2026 a Aurea ficou SEM grupo, e a medição decidiu: dar a cada
319
+ // `Group` a sua fatia de itens passava POR CIMA do filtro do motor (digitar "the" devolvia os três).
320
+ // O caminho certo é o da documentação do motor (1.6.0, a paleta de exemplo dele): `items` agrupados
321
+ // (`{value, items}`), e a lista recebe os grupos JÁ FILTRADOS. Sem `group` em nenhum item, a lista é
322
+ // a de sempre.
323
+ const grupos = React.useMemo(() => {
324
+ if (!items.some(i => i.group))
325
+ return null;
326
+ const mapa = new Map();
327
+ for (const i of items) {
328
+ const g = i.group ?? "";
329
+ if (!mapa.has(g))
330
+ mapa.set(g, []);
331
+ mapa.get(g).push(i);
332
+ }
333
+ return [...mapa].map(([value, itens]) => ({ value, items: itens }));
334
+ }, [items]);
287
335
  const portal = usePortalContainer();
288
- if (!open)
289
- return null;
290
- // SEM AGRUPAMENTO na v1, e a medição é que decidiu (13/08/2026). O `Autocomplete.Root` não
291
- // consome a estrutura agrupada como o `Combobox.Root` consome — e o caminho alternativo, dar a
292
- // cada `Group` a sua fatia de itens, PASSA POR CIMA do filtro do motor: digitar "the" devolvia
293
- // os três comandos. Entre agrupar e filtrar, filtrar é o ponto de uma paleta de comandos.
294
- // Fica registrado como limite, não como esquecimento: quando alguém precisar de grupo aqui, o
295
- // caminho é o `Combobox.Root`, e isso é troca de motor, não ajuste.
336
+ const campo = useRef(null);
296
337
  const executa = (item) => { onClose(); item.run(); };
297
338
  const linha = (item) => _jsxs(BaseAutocomplete.Item, { value: item, className: "menu-item command-item", onClick: () => executa(item), children: [item.icon && _jsx(Icon, { name: item.icon }), _jsx("span", { className: "command-item-label", children: item.label }), item.kbd && _jsx(Kbd, { children: item.kbd })] }, item.id);
298
- // Escape fecha, e é o teclado que a pessoa tenta primeiro. O motor não fecha sozinho porque
299
- // quem é dono do `open` é o consumidor — mesma regra do Dialog e do Drawer daqui.
300
- return _jsx("div", { className: "command-overlay", onKeyDown: e => { if (e.key === "Escape")
301
- onClose(); }, children: _jsx("div", { className: "command-palette", role: "dialog", "aria-label": label ?? s.commandLabel, children: _jsxs(BaseAutocomplete.Root, { items: items, itemToStringValue: (i) => i.label, mode: "list", open: true, children: [_jsx(BaseAutocomplete.Input, { autoFocus: true, className: "input", onKeyDown: e => { if (e.key === "Escape")
302
- onClose(); }, "aria-label": placeholder ?? s.commandPlaceholder, placeholder: placeholder ?? s.commandPlaceholder }), _jsx(BaseAutocomplete.Portal, { container: portal, children: _jsx(BaseAutocomplete.Positioner, { sideOffset: 6, className: "command-positioner", children: _jsxs(BaseAutocomplete.Popup, { className: "menu command-list", children: [_jsx(BaseAutocomplete.Empty, { className: "combobox-empty", children: s.comboboxEmpty }), _jsx(BaseAutocomplete.List, { children: _jsx(BaseAutocomplete.Collection, { children: linha }) })] }) }) })] }) }) });
339
+ // A JANELA É A DO MOTOR (14/10/2026), como na paleta de exemplo dele (1.6.0): `Dialog` por fora,
340
+ // `Autocomplete` `inline` por dentro. Até aqui a moldura era uma `div` feita à mão, e o Victor achou no site
341
+ // publicado: o clique no fundo não fechava, e depois dele o foco ia para a página — o Esc, que era escutado
342
+ // dentro da caixa, não chegava mais. A janela do motor fecha pelos dois caminhos, prende o Tab, trava a
343
+ // rolagem de trás e devolve o foco a quem abriu. O `open` continua do consumidor: o motor só AVISA
344
+ // (`onOpenChange`), e quem fecha é o `onClose` — mesma regra do Dialog e do Drawer daqui. Os nomes de classe
345
+ // ficaram: a moldura (`Viewport`) é a `.command-overlay`, a caixa (`Popup`) é a `.command-palette`.
346
+ return _jsx(BaseDialog.Root, { open: open, onOpenChange: o => { if (!o)
347
+ onClose(); }, children: _jsx(BaseDialog.Portal, { container: portal, children: _jsx(BaseDialog.Viewport, { className: "command-overlay", children: _jsxs(BaseDialog.Popup, { className: "command-palette", "aria-label": label ?? s.commandLabel, initialFocus: campo, children: [_jsxs(BaseAutocomplete.Root, { items: (grupos ?? items), itemToStringValue: (i) => i.label, mode: "list", open: true, inline: true, autoHighlight: "always", keepHighlight: true, children: [_jsx(BaseAutocomplete.Input, { ref: campo, className: "input", "aria-label": placeholder ?? s.commandPlaceholder, placeholder: placeholder ?? s.commandPlaceholder, "aria-expanded": true, "aria-describedby": shortcuts ? idAtalhos : undefined }), _jsxs("div", { className: "menu command-list", children: [_jsx(BaseAutocomplete.Empty, { className: "combobox-empty", children: s.comboboxEmpty }), _jsx(BaseAutocomplete.List, { children: grupos
348
+ ? (g) => _jsxs(BaseAutocomplete.Group, { items: g.items, className: "command-group", children: [g.value && _jsx(BaseAutocomplete.GroupLabel, { className: "command-group-label", children: g.value }), _jsx(BaseAutocomplete.Collection, { children: linha })] }, g.value)
349
+ : _jsx(BaseAutocomplete.Collection, { children: linha }) })] })] }), shortcuts && _jsxs("p", { className: "command-shortcuts", id: idAtalhos, children: [_jsxs("span", { children: [_jsx(Kbd, { children: "\u2191" }), _jsx(Kbd, { children: "\u2193" }), " ", s.commandHintMove] }), _jsxs("span", { children: [_jsx(Kbd, { children: "Enter" }), " ", s.commandHintSelect] }), _jsxs("span", { children: [_jsx(Kbd, { children: "Esc" }), " ", s.commandHintClose] })] })] }) }) }) });
350
+ }
351
+ // A CASCA (15/10/2026, o Victor: "C sim"): a mesma janela do motor da `CommandPalette` acima. Até aqui era uma `div`
352
+ // feita à mão — o mesmo defeito que a busca do site teve: o clique fora e o Esc não fechavam, e o Tab saía da caixa.
353
+ // Agora o motor avisa pelos dois caminhos (`onClose`, novo), prende o Tab e devolve o foco a quem abriu. Sem `onClose`,
354
+ // a janela fica aberta até o `open` do consumidor mudar — como antes. O campo recebe o foco pelo `initialFocus`.
355
+ export function CommandPaletteShell({ open, query, onQueryChange, onClose, label, children }) {
356
+ const s = useAureaStrings();
357
+ const portal = usePortalContainer();
358
+ const campo = useRef(null);
359
+ return _jsx(BaseDialog.Root, { open: open, onOpenChange: o => { if (!o)
360
+ onClose?.(); }, children: _jsx(BaseDialog.Portal, { container: portal, children: _jsx(BaseDialog.Viewport, { className: "command-overlay", children: _jsxs(BaseDialog.Popup, { className: "command-palette", "aria-label": label ?? s.commandLabel, initialFocus: campo, children: [_jsx(SearchField, { ref: campo, "aria-label": s.commandPlaceholder, value: query, onChange: e => onQueryChange(e.target.value), placeholder: s.commandPlaceholder }), children] }) }) }) });
303
361
  }
304
- export function CommandPaletteShell({ open, query, onQueryChange, children }) { const s = useAureaStrings(); if (!open)
305
- 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] }) }); }
@@ -2,7 +2,9 @@ import React, { type ReactNode, type ReactElement } from "react";
2
2
  import { type Responsive } from "./pure.js";
3
3
  import { type IconName } from "./system.js";
4
4
  export type DialogSize = "xs" | "sm" | "md" | "lg" | "xl" | "full";
5
- export declare function Dialog({ open, title, children, footer, onClose, size, dismissible }: {
5
+ export type DialogPlacement = "auto" | "center" | "top" | "bottom";
6
+ export type DialogIconTone = "neutral" | "brand" | "info" | "success" | "warning" | "danger";
7
+ export declare function Dialog({ open, title, children, footer, onClose, size, dismissible, icon, iconTone, placement }: {
6
8
  open: boolean;
7
9
  title: ReactNode;
8
10
  children: ReactNode;
@@ -10,8 +12,11 @@ export declare function Dialog({ open, title, children, footer, onClose, size, d
10
12
  onClose: () => void;
11
13
  size?: DialogSize;
12
14
  dismissible?: boolean;
15
+ icon?: IconName;
16
+ iconTone?: DialogIconTone;
17
+ placement?: DialogPlacement;
13
18
  }): React.JSX.Element;
14
- export declare function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, destructive, onConfirm, onCancel }: {
19
+ export declare function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, destructive, onConfirm, onCancel, icon, iconTone, placement }: {
15
20
  open: boolean;
16
21
  title: ReactNode;
17
22
  description: ReactNode;
@@ -20,13 +25,18 @@ export declare function ConfirmDialog({ open, title, description, confirmLabel,
20
25
  destructive?: boolean;
21
26
  onConfirm: () => void;
22
27
  onCancel: () => void;
28
+ icon?: IconName;
29
+ iconTone?: DialogIconTone;
30
+ placement?: DialogPlacement;
23
31
  }): React.JSX.Element;
24
- export declare function Drawer({ open, title, children, onClose, side }: {
32
+ export type DrawerSide = "left" | "right" | "top" | "bottom";
33
+ export declare function Drawer({ open, title, children, footer, onClose, side }: {
25
34
  open: boolean;
26
35
  title: ReactNode;
27
36
  children: ReactNode;
37
+ footer?: ReactNode;
28
38
  onClose: () => void;
29
- side?: "left" | "right";
39
+ side?: DrawerSide;
30
40
  }): React.JSX.Element;
31
41
  export type AccessGateProps = {
32
42
  allowed: boolean;
@@ -42,16 +52,20 @@ export type AccessGateProps = {
42
52
  });
43
53
  export declare function AccessGate({ allowed, children, ...resto }: AccessGateProps): React.JSX.Element;
44
54
  export type OverlaySide = "top" | "right" | "bottom" | "left";
45
- export declare function Tooltip({ children, content, side }: {
55
+ export declare function Tooltip({ children, content, side, arrow, delay, closeDelay }: {
46
56
  children: ReactElement;
47
57
  content: ReactNode;
48
58
  side?: OverlaySide;
59
+ arrow?: boolean;
60
+ delay?: number;
61
+ closeDelay?: number;
49
62
  }): React.JSX.Element;
50
- export declare function Popover({ trigger, title, children, side }: {
63
+ export declare function Popover({ trigger, title, children, side, arrow }: {
51
64
  trigger: ReactElement;
52
65
  title?: ReactNode;
53
66
  children: ReactNode;
54
67
  side?: OverlaySide;
68
+ arrow?: boolean;
55
69
  }): React.JSX.Element;
56
70
  export declare function HoverCard({ trigger, children, side }: {
57
71
  trigger: ReactElement;
package/dist/overlays.js CHANGED
@@ -5,6 +5,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
5
5
  // internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
6
6
  import React, { useRef } from "react";
7
7
  import { Dialog as BaseDialog } from "@base-ui/react/dialog";
8
+ import { Drawer as BaseDrawer } from "@base-ui/react/drawer";
8
9
  import { AlertDialog as BaseAlertDialog } from "@base-ui/react/alert-dialog";
9
10
  import { Popover as BasePopover } from "@base-ui/react/popover";
10
11
  import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
@@ -15,12 +16,17 @@ import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
15
16
  import { cx, useAureaStrings, usePortalContainer } from "./internal.js";
16
17
  import { useValorResponsivo } from "./responsivo-runtime.js";
17
18
  import { Icon } from "./system.js";
18
- import { Button } from "./actions.js";
19
- export function Dialog({ open, title, children, footer, onClose, size = "md", dismissible = true }) {
20
- const s = useAureaStrings();
19
+ import { Button, CloseButton } from "./actions.js";
20
+ function IconeDaJanela({ icon, tone }) {
21
+ return _jsx("span", { className: cx("dialog-icon", `dialog-icon-${tone}`), "aria-hidden": "true", children: _jsx(Icon, { name: icon }) });
22
+ }
23
+ export function Dialog({ open, title, children, footer, onClose, size = "md", dismissible = true, icon, iconTone = "neutral", placement = "auto" }) {
21
24
  const portal = usePortalContainer();
25
+ // O X vem PRIMEIRO na ordem do documento, como o gatilho de fechar da referência: o motor foca o
26
+ // primeiro focável ao abrir, e era o X também quando ele morava no fim do cabeçalho (o título não é
27
+ // focável) — a ordem do Tab não muda.
22
28
  return _jsx(BaseDialog.Root, { open: open, disablePointerDismissal: !dismissible, onOpenChange: o => { if (!o && dismissible)
23
- onClose(); }, children: _jsxs(BaseDialog.Portal, { container: portal, children: [_jsx(BaseDialog.Backdrop, { className: "dialog-backdrop" }), _jsxs(BaseDialog.Popup, { className: cx("dialog", size !== "md" && `dialog-${size}`), children: [_jsxs("header", { children: [_jsx(BaseDialog.Title, { render: _jsx("h2", {}), children: title }), _jsx(BaseDialog.Close, { className: "btn btn-ghost btn-icon", "aria-label": s.close, disabled: !dismissible, children: _jsx(Icon, { name: "x" }) })] }), _jsx("div", { className: "dialog-body", children: children }), footer && _jsx("footer", { children: footer })] })] }) });
29
+ onClose(); }, children: _jsxs(BaseDialog.Portal, { container: portal, children: [_jsx(BaseDialog.Backdrop, { className: "dialog-backdrop" }), _jsxs(BaseDialog.Popup, { className: cx("dialog", size !== "md" && `dialog-${size}`), "data-placement": placement, children: [_jsx(BaseDialog.Close, { render: _jsx(CloseButton, { className: "dialog-close", disabled: !dismissible }) }), _jsxs("header", { className: "dialog-header", children: [icon && _jsx(IconeDaJanela, { icon: icon, tone: iconTone }), _jsx(BaseDialog.Title, { render: _jsx("h2", {}), className: "dialog-heading", children: title })] }), _jsx("div", { className: "dialog-body", children: children }), footer && _jsx("footer", { className: "dialog-footer", children: footer })] })] }) });
24
30
  }
25
31
  // ConfirmDialog (M5): a decisão que não se fecha por engano. NÃO é um Dialog com dois botões —
26
32
  // é `role="alertdialog"`, e a diferença é de comportamento, não de aparência: o Base UI tira do
@@ -50,15 +56,23 @@ export function Dialog({ open, title, children, footer, onClose, size = "md", di
50
56
  // `description` é prop e não `children` porque ela é o nó de `aria-describedby`: o AlertDialog
51
57
  // só anuncia o que passa pelo `Description`. Como `children`, um consumidor poria um <div> no
52
58
  // meio e o leitor de tela perderia a frase que diz o que se perde.
53
- export function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, destructive, onConfirm, onCancel }) {
59
+ //
60
+ // 0.32.0: a anatomia do `Dialog` (a da referência), sem o X — a decisão não se fecha por engano. O
61
+ // ícone é o círculo de 40 de lá; a cor dele segue o `destructive` quando quem usa não escolhe.
62
+ export function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, destructive, onConfirm, onCancel, icon, iconTone, placement = "auto" }) {
54
63
  const s = useAureaStrings();
55
64
  const portal = usePortalContainer();
56
65
  const seguro = React.useRef(null);
57
66
  return _jsx(BaseAlertDialog.Root, { open: open, onOpenChange: o => { if (!o)
58
- 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 })] })] })] }) });
67
+ onCancel(); }, children: _jsxs(BaseAlertDialog.Portal, { container: portal, children: [_jsx(BaseAlertDialog.Backdrop, { className: "dialog-backdrop" }), _jsxs(BaseAlertDialog.Popup, { className: "dialog dialog-confirm", initialFocus: seguro, "data-placement": placement, children: [_jsxs("header", { className: "dialog-header", children: [icon && _jsx(IconeDaJanela, { icon: icon, tone: iconTone ?? (destructive ? "danger" : "neutral") }), _jsx(BaseAlertDialog.Title, { render: _jsx("h2", {}), className: "dialog-heading", children: title })] }), _jsx(BaseAlertDialog.Description, { className: "dialog-body", children: description }), _jsxs("footer", { className: "dialog-footer", children: [_jsx(Button, { ref: seguro, variant: "tertiary", onClick: onCancel, children: cancelLabel ?? s.confirmCancel }), _jsx(Button, { variant: destructive ? "danger" : "primary", onClick: onConfirm, children: confirmLabel ?? s.confirmProceed })] })] })] }) });
68
+ }
69
+ const ARRASTO_DO_LADO = { left: "left", right: "right", top: "up", bottom: "down" };
70
+ export function Drawer({ open, title, children, footer, onClose, side = "right" }) {
71
+ const portal = usePortalContainer();
72
+ const alca = _jsx("div", { className: "drawer-handle", "aria-hidden": "true" });
73
+ return _jsx(BaseDrawer.Root, { open: open, onOpenChange: o => { if (!o)
74
+ onClose(); }, swipeDirection: ARRASTO_DO_LADO[side], children: _jsxs(BaseDrawer.Portal, { container: portal, children: [_jsx(BaseDrawer.Backdrop, { className: "drawer-backdrop" }), _jsx(BaseDrawer.Viewport, { className: "drawer-viewport", children: _jsxs(BaseDrawer.Popup, { className: cx("drawer", `drawer-${side}`), children: [_jsx(BaseDrawer.Close, { render: _jsx(CloseButton, { className: "dialog-close" }) }), side === "bottom" && alca, _jsx("header", { className: "dialog-header", children: _jsx(BaseDrawer.Title, { render: _jsx("h2", {}), className: "dialog-heading", children: title }) }), _jsx(BaseDrawer.Content, { className: "dialog-body", children: children }), footer && _jsx("footer", { className: "dialog-footer", children: footer }), side === "top" && alca] }) })] }) });
59
75
  }
60
- 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)
61
- 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: "x" }) })] }), children] })] }) }); }
62
76
  export function AccessGate({ allowed, children, ...resto }) {
63
77
  if (allowed)
64
78
  return children;
@@ -72,8 +86,49 @@ export function AccessGate({ allowed, children, ...resto }) {
72
86
  // conteúdo da dica. Era tooltip visual, não acessível (padrão APG Tooltip).
73
87
  // O id aponta para um elemento que só existe quando aberto; referência pendente é ignorada
74
88
  // pela tecnologia assistiva, então não precisa acompanhar o estado.
75
- export function Tooltip({ children, content, side = "top" }) { const id = React.useId(); const triggerId = children.props.id; const portal = usePortalContainer(); return _jsxs(BaseTooltip.Root, { children: [_jsx(BaseTooltip.Trigger, { id: triggerId, render: children, "aria-describedby": id }), _jsx(BaseTooltip.Portal, { container: portal, children: _jsx(BaseTooltip.Positioner, { side: side, sideOffset: 8, children: _jsx(BaseTooltip.Popup, { id: id, role: "tooltip", className: "tooltip", children: content }) }) })] }); }
76
- export function Popover({ trigger, title, children, side = "bottom" }) { const portal = usePortalContainer(); return _jsxs(BasePopover.Root, { children: [_jsx(BasePopover.Trigger, { render: trigger }), _jsx(BasePopover.Portal, { container: portal, children: _jsx(BasePopover.Positioner, { side: side, sideOffset: 8, children: _jsxs(BasePopover.Popup, { className: "popover", children: [title && _jsx(BasePopover.Title, { render: _jsx("strong", {}), children: title }), children] }) }) })] }); }
89
+ //
90
+ // 0.32.0, a dica e o popover da referência:
91
+ // • A SETA (`arrow`), desligada por padrão como lá. O desenho é nosso (uma curva de 12 × 6, sem a
92
+ // ponta afiada); ela tem o fundo da janela e a linha da borda, então a borda dá a volta nela.
93
+ // A dica com seta se afasta 8 do gatilho (`--space-2`: os 6 da seta e 2 de folga); sem
94
+ // seta, 4 (`--space-1`) — a referência usa 7 e 3, que não são da nossa escala. O popover fica
95
+ // sempre a 8, com ou sem seta, como o dela.
96
+ // • O ATRASO da dica é o dela: 1,5 s para abrir e 0,5 s para fechar (o motor abre em 0,6 s e
97
+ // fecha na hora). Pelo teclado ela abre já, e depois da primeira as vizinhas abrem sem esperar
98
+ // — é o grupo do `Tooltip.Provider` do `AureaProvider`.
99
+ // • O GATILHO FOCÁVEL (C-11): a dica em cima de um texto só abria pelo teclado se o app pusesse
100
+ // `tabIndex`. A referência resolve no gatilho, que sai focável como botão; aqui também — o que
101
+ // não é focável sozinho (um `<span>`, um selo) ganha `tabIndex=0` e `role="button"`. Na
102
+ // marcação, quando o filho é uma tag; e, quando é um componente, no nó de verdade, depois de
103
+ // montado, porque só o DOM sabe o que o componente desenhou.
104
+ const ATRASO_DA_DICA = 1500, ATRASO_PARA_FECHAR_A_DICA = 500;
105
+ function Seta() { return _jsxs("svg", { viewBox: "0 0 12 12", "aria-hidden": "true", children: [_jsx("path", { className: "overlay-arrow-fill", d: "M0 0Q6 12 12 0Z" }), _jsx("path", { className: "overlay-arrow-line", d: "M0 0Q6 12 12 0", fill: "none" })] }); }
106
+ const FOCAVEIS_POR_NATUREZA = new Set(["button", "input", "select", "textarea", "summary", "iframe", "audio", "video"]);
107
+ function focavelNaMarcacao(el) {
108
+ if (typeof el.type !== "string")
109
+ return undefined;
110
+ const p = el.props;
111
+ if (p.tabIndex !== undefined)
112
+ return true;
113
+ if (el.type === "a" || el.type === "area")
114
+ return p.href !== undefined;
115
+ return FOCAVEIS_POR_NATUREZA.has(el.type);
116
+ }
117
+ function garantirFoco(no) {
118
+ if (!no || no.tabIndex >= 0 || no.hasAttribute("tabindex"))
119
+ return;
120
+ no.tabIndex = 0;
121
+ if (!no.hasAttribute("role"))
122
+ no.setAttribute("role", "button");
123
+ }
124
+ export function Tooltip({ children, content, side = "top", arrow = false, delay = ATRASO_DA_DICA, closeDelay = ATRASO_PARA_FECHAR_A_DICA }) {
125
+ const id = React.useId();
126
+ const triggerId = children.props.id;
127
+ const portal = usePortalContainer();
128
+ const foco = focavelNaMarcacao(children) === false ? { tabIndex: 0, role: "button" } : {};
129
+ return _jsxs(BaseTooltip.Root, { children: [_jsx(BaseTooltip.Trigger, { ref: garantirFoco, id: triggerId, render: children, "aria-describedby": id, delay: delay, closeDelay: closeDelay, ...foco }), _jsx(BaseTooltip.Portal, { container: portal, children: _jsx(BaseTooltip.Positioner, { className: "positioner", side: side, sideOffset: arrow ? 8 : 4, children: _jsxs(BaseTooltip.Popup, { id: id, role: "tooltip", className: "tooltip", children: [arrow && _jsx(BaseTooltip.Arrow, { className: "overlay-arrow", children: _jsx(Seta, {}) }), content] }) }) })] });
130
+ }
131
+ export function Popover({ trigger, title, children, side = "bottom", arrow = false }) { const portal = usePortalContainer(); return _jsxs(BasePopover.Root, { children: [_jsx(BasePopover.Trigger, { render: trigger }), _jsx(BasePopover.Portal, { container: portal, children: _jsx(BasePopover.Positioner, { className: "positioner", side: side, sideOffset: 8, children: _jsxs(BasePopover.Popup, { className: "popover", children: [arrow && _jsx(BasePopover.Arrow, { className: "overlay-arrow", children: _jsx(Seta, {}) }), title && _jsx(BasePopover.Title, { render: _jsx("strong", {}), className: "popover-title", children: title }), children] }) }) })] }); }
77
132
  // HoverCard (Lote 1 do BUILDING.md). Não é Tooltip nem Popover, e a diferença é de propósito,
78
133
  // não de aparência: a Tooltip é um RÓTULO curto (`role="tooltip"`, some ao mover o mouse); o
79
134
  // Popover abre por CLIQUE e pode conter foco; este é uma PRÉVIA rica que aparece ao repousar o
@@ -83,7 +138,7 @@ export function Popover({ trigger, title, children, side = "bottom" }) { const p
83
138
  // um segundo nome criaria duas peles para a mesma coisa.
84
139
  // Por depender de repouso do ponteiro, NÃO serve para informação essencial — quem navega só por
85
140
  // teclado ou toque não abre um hover card. Conteúdo obrigatório vai em Popover.
86
- export function HoverCard({ trigger, children, side = "bottom" }) { const portal = usePortalContainer(); return _jsxs(BasePreviewCard.Root, { children: [_jsx(BasePreviewCard.Trigger, { render: trigger }), _jsx(BasePreviewCard.Portal, { container: portal, children: _jsx(BasePreviewCard.Positioner, { side: side, sideOffset: 8, children: _jsx(BasePreviewCard.Popup, { className: "popover hover-card", children: children }) }) })] }); }
141
+ export function HoverCard({ trigger, children, side = "bottom" }) { const portal = usePortalContainer(); return _jsxs(BasePreviewCard.Root, { children: [_jsx(BasePreviewCard.Trigger, { render: trigger }), _jsx(BasePreviewCard.Portal, { container: portal, children: _jsx(BasePreviewCard.Positioner, { className: "positioner", side: side, sideOffset: 8, children: _jsx(BasePreviewCard.Popup, { className: "popover hover-card", children: children }) }) })] }); }
87
142
  // A MARCA de um item que alterna fica num slot de largura FIXA, e não condicional: sem ele, um
88
143
  // menu com um item marcado e outro não desalinharia os rótulos a cada clique — o texto andaria
89
144
  // para o lado sozinho. É a mesma razão de o `leadingIcon` ter lugar próprio.
@@ -114,7 +169,7 @@ function renderMenuItems(items, portal) {
114
169
  const sm = it;
115
170
  // O submenu é uma RAIZ própria com gatilho próprio — não é um item que "abre outro menu".
116
171
  // É o que dá `aria-haspopup`, a seta para a direita e o fechamento em cascata de graça.
117
- return _jsxs(BaseMenu.SubmenuRoot, { children: [_jsxs(BaseMenu.SubmenuTrigger, { className: "menu-item", disabled: sm.disabled, children: [dentro(sm), _jsx(Icon, { name: "caret-right", size: "sm", className: "menu-seta" })] }), _jsx(BaseMenu.Portal, { container: portal, children: _jsx(BaseMenu.Positioner, { side: "inline-end", sideOffset: 4, children: _jsx(BaseMenu.Popup, { className: "menu", children: renderMenuItems(sm.items, portal) }) }) })] }, i);
172
+ return _jsxs(BaseMenu.SubmenuRoot, { children: [_jsxs(BaseMenu.SubmenuTrigger, { className: "menu-item", disabled: sm.disabled, children: [dentro(sm), _jsx(Icon, { name: "caret-right", size: "sm", className: "menu-seta" })] }), _jsx(BaseMenu.Portal, { container: portal, children: _jsx(BaseMenu.Positioner, { className: "positioner", side: "inline-end", sideOffset: 4, children: _jsx(BaseMenu.Popup, { className: "menu", children: renderMenuItems(sm.items, portal) }) }) })] }, i);
118
173
  }
119
174
  case "checkbox": {
120
175
  const c = it;
@@ -136,13 +191,13 @@ function renderMenuItems(items, portal) {
136
191
  }
137
192
  });
138
193
  }
139
- export function DropdownMenu({ trigger, items, side = "bottom", label }) { const portal = usePortalContainer(); return _jsxs(BaseMenu.Root, { children: [_jsx(BaseMenu.Trigger, { render: trigger }), _jsx(BaseMenu.Portal, { container: portal, children: _jsx(BaseMenu.Positioner, { side: side, sideOffset: 6, children: _jsx(BaseMenu.Popup, { className: "menu", "aria-label": label, children: renderMenuItems(items, portal) }) }) })] }); }
194
+ export function DropdownMenu({ trigger, items, side = "bottom", label }) { const portal = usePortalContainer(); return _jsxs(BaseMenu.Root, { children: [_jsx(BaseMenu.Trigger, { render: trigger }), _jsx(BaseMenu.Portal, { container: portal, children: _jsx(BaseMenu.Positioner, { className: "positioner", side: side, sideOffset: 6, children: _jsx(BaseMenu.Popup, { className: "menu", "aria-label": label, children: renderMenuItems(items, portal) }) }) })] }); }
140
195
  // ContextMenu: abre no botão direito e — por teclado — em Shift+F10 / tecla Menu,
141
196
  // que o browser só dispara (como evento contextmenu) sobre um elemento FOCADO. Por
142
197
  // isso o gatilho é focável (tabIndex 0) e tem nome acessível (auditoria 18/07/2026,
143
198
  // MÉDIO 3); sem isso o teclado não alcança o menu. Consumidor pode sobrescrever
144
199
  // tabIndex via children se o próprio já for focável.
145
- export function ContextMenu({ children, items, label, className }) { const portal = usePortalContainer(); return _jsxs(BaseContextMenu.Root, { children: [_jsx(BaseContextMenu.Trigger, { className: className, tabIndex: 0, "aria-label": label, "aria-haspopup": "menu", children: children }), _jsx(BaseContextMenu.Portal, { container: portal, children: _jsx(BaseContextMenu.Positioner, { children: _jsx(BaseContextMenu.Popup, { className: "menu", "aria-label": label, children: renderMenuItems(items, portal) }) }) })] }); }
200
+ export function ContextMenu({ children, items, label, className }) { const portal = usePortalContainer(); return _jsxs(BaseContextMenu.Root, { children: [_jsx(BaseContextMenu.Trigger, { className: className, tabIndex: 0, "aria-label": label, "aria-haspopup": "menu", children: children }), _jsx(BaseContextMenu.Portal, { container: portal, children: _jsx(BaseContextMenu.Positioner, { className: "positioner", children: _jsx(BaseContextMenu.Popup, { className: "menu", "aria-label": label, children: renderMenuItems(items, portal) }) }) })] }); }
146
201
  // G-AXIS-06 — o valor responsivo RESOLVIDO é a única fonte de verdade: ele vai para o motor, o
147
202
  // motor publica `data-orientation`/`aria-orientation` e ajusta o teclado, e a pele reage ao
148
203
  // atributo publicado. Ver `decisions/0047-css-first-para-apresentacao-runtime-para-semantica.md`.
@@ -151,5 +206,5 @@ export function Menubar({ menus, label, modal, disabled, loopFocus, orientation,
151
206
  const ancora = useRef(null);
152
207
  const resolvida = useValorResponsivo(orientation, "horizontal", ancora);
153
208
  const vertical = resolvida === "vertical";
154
- return _jsx(BaseMenubar, { ref: ancora, modal: modal, disabled: disabled, loopFocus: loopFocus, orientation: resolvida, "aria-label": label, className: cx("menubar", className), children: menus.map((m, i) => _jsxs(BaseMenu.Root, { disabled: m.disabled, children: [_jsx(BaseMenu.Trigger, { className: "menubar-trigger", children: m.label }), _jsx(BaseMenu.Portal, { container: portal, children: _jsx(BaseMenu.Positioner, { side: vertical ? "inline-end" : "bottom", align: "start", sideOffset: 4, children: _jsx(BaseMenu.Popup, { className: "menu", children: renderMenuItems(m.items) }) }) })] }, i)) });
209
+ return _jsx(BaseMenubar, { ref: ancora, modal: modal, disabled: disabled, loopFocus: loopFocus, orientation: resolvida, "aria-label": label, className: cx("menubar", className), children: menus.map((m, i) => _jsxs(BaseMenu.Root, { disabled: m.disabled, children: [_jsx(BaseMenu.Trigger, { className: "menubar-trigger", children: m.label }), _jsx(BaseMenu.Portal, { container: portal, children: _jsx(BaseMenu.Positioner, { className: "positioner", side: vertical ? "inline-end" : "bottom", align: "start", sideOffset: 4, children: _jsx(BaseMenu.Popup, { className: "menu", children: renderMenuItems(m.items) }) }) })] }, i)) });
155
210
  }
package/dist/pure.d.ts CHANGED
@@ -4,6 +4,9 @@ export declare function fundirRender(render: ReactElement | undefined, props: {
4
4
  className?: string;
5
5
  } & Record<string, unknown>, padrao?: string): ReactElement;
6
6
  export type AureaTheme = "dark" | "light";
7
+ /** O que se ESCOLHE (15/10/2026): um tema, ou `"system"` — seguir o claro/escuro do sistema, e mudar junto com ele.
8
+ * O tema na tela continua sendo `AureaTheme`; a preferência é o que a chave de três posições guarda. */
9
+ export type AureaThemePreference = AureaTheme | "system";
7
10
  export type AureaDensity = "compact" | "comfortable" | "spacious";
8
11
  export type UniversalState = "waiting_user" | "waiting_approval" | "waiting_dependency" | "offline" | "stale" | "partial" | "degraded";
9
12
  export declare const universalStates: readonly UniversalState[];
@@ -15,9 +18,12 @@ export interface AureaStrings {
15
18
  close: string;
16
19
  confirmCancel: string;
17
20
  dataError: string;
21
+ dataCrashed: string;
22
+ dataRetry: string;
18
23
  dataEmpty: string;
19
24
  confirmProceed: string;
20
25
  paginationLabel: string;
26
+ paginationPage: string;
21
27
  previous: string;
22
28
  next: string;
23
29
  breadcrumbLabel: string;
@@ -26,6 +32,9 @@ export interface AureaStrings {
26
32
  tableLabel: string;
27
33
  commandLabel: string;
28
34
  commandPlaceholder: string;
35
+ commandHintMove: string;
36
+ commandHintSelect: string;
37
+ commandHintClose: string;
29
38
  dismissNotification: string;
30
39
  toolbarLabel: string;
31
40
  loading: string;
@@ -166,6 +175,8 @@ export interface AureaStrings {
166
175
  graphZoomOut: string;
167
176
  graphFit: string;
168
177
  graphLegend: string;
178
+ graphLegendKind: string;
179
+ graphLegendStatus: string;
169
180
  graphOverview: string;
170
181
  graphConnections: string;
171
182
  graphShow: string;
@@ -209,6 +220,8 @@ export interface AureaStrings {
209
220
  qrCode: string;
210
221
  chartLabel: string;
211
222
  copyCode: string;
223
+ codeBlockPreview: string;
224
+ codeBlockCode: string;
212
225
  copied: string;
213
226
  linkCopied: string;
214
227
  linkCopyFailed: string;
@@ -219,7 +232,21 @@ export interface AureaStrings {
219
232
  sidebarExpand: string;
220
233
  bottomNavLabel: string;
221
234
  themeToDark: string;
235
+ themeChoice: string;
236
+ themeLight: string;
237
+ themeDark: string;
238
+ themeSystem: string;
222
239
  themeToLight: string;
240
+ datePlaceholder: string;
241
+ dateRangePlaceholder: string;
242
+ colorPicker: string;
243
+ colorArea2D: string;
244
+ colorChannel: Record<"hue" | "saturation" | "brightness" | "lightness" | "red" | "green" | "blue" | "alpha", string>;
245
+ colorHue: Record<"red" | "orange" | "yellow" | "green" | "cyan" | "blue" | "purple" | "magenta" | "pink" | "brown" | "gray" | "white" | "black", string>;
246
+ colorTone: Record<"veryDark" | "dark" | "light" | "veryLight" | "vivid" | "pale" | "grayish", string>;
247
+ colorNameFormat: string;
248
+ colorHex: string;
249
+ colorSwatches: string;
223
250
  universalState: Record<UniversalState, string>;
224
251
  }
225
252
  export declare const defaultStrings: AureaStrings;