@aurea-uds/react 0.56.0 → 0.59.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.
@@ -70,13 +70,17 @@ function linhasDoCodigo(codigo, language, highlight) {
70
70
  // arquivo à esquerda e, com `copyable`, o "Copy" ESCRITO (o botão secundário, com o ícone antes do nome; vira "Copied").
71
71
  // O bloco vira o cartão (canto 22, a cor do cartão) e a linha longa DESCE em vez de rolar. Sem `filename`, o de sempre.
72
72
  export function CodeBlock({ children, language = "text", copyable, preview, previewLayout = "tabs", lineNumbers, highlight, tabs, filename, className }) {
73
+ // Os hooks ANTES de todo `return` (auditoria externa, 05/11/2026): moravam depois dos três retornos da caixa e dos dois do
74
+ // bloco sem cópia, e trocar `copyable` entre renderizações mudava a ordem dos hooks — o React avisava e o "copiado" se
75
+ // perdia. Regra dos hooks do React: mesma ordem, em toda renderização.
76
+ const s = useAureaStrings();
77
+ const [copiado, setCopiado] = React.useState(false);
73
78
  if (tabs && tabs.length > 0)
74
79
  return _jsx(CodigoEmAbas, { tabs: tabs, language: language, copyable: copyable, highlight: highlight, className: className });
75
80
  if (preview !== undefined && previewLayout === "stacked")
76
81
  return _jsx(CaixaEmpilhada, { preview: preview, className: className, linhas: (children ?? "").split("\n").length, codigo: _jsx(CodeBlock, { language: language, copyable: copyable, lineNumbers: lineNumbers, highlight: highlight, children: children }) });
77
82
  if (preview !== undefined)
78
83
  return _jsx(CaixaDeExemplo, { preview: preview, className: className, codigo: _jsx(CodeBlock, { language: language, copyable: copyable, lineNumbers: lineNumbers, highlight: highlight, children: children }) });
79
- const s = useAureaStrings();
80
84
  // tabIndex no <pre>: `.code-block` é `overflow:auto` por construção, então é REGIÃO ROLÁVEL
81
85
  // e não tem nada focável dentro — quem navega por teclado não alcança o código que passa da
82
86
  // largura. É a regra `scrollable-region-focusable` do axe, e o mesmo defeito que o painel de
@@ -97,7 +101,6 @@ export function CodeBlock({ children, language = "text", copyable, preview, prev
97
101
  return _jsxs("div", { className: cx("code-block-wrap", "code-block-file", className), children: [_jsx("div", { className: "code-block-head", children: _jsx("span", { className: "code-block-title", children: filename }) }), pre] });
98
102
  // 0.28.0: o "copiado" é dito ao leitor de tela. Com o `aurea.js` na página, é ele quem diz (pelo
99
103
  // texto do `data-aurea-copy-done`, na língua do app); sem ele, a região de status daqui.
100
- const [copiado, setCopiado] = React.useState(false);
101
104
  const onCopy = (e) => {
102
105
  e.stopPropagation();
103
106
  const vanilla = window.Aurea;
@@ -17,8 +17,11 @@ export interface TableProps extends HTMLAttributes<HTMLTableElement>, RefAttribu
17
17
  /** As linhas ímpares do corpo com fundo (o site B, 02/11/2026, a "B" na imagem): a 1ª, a 3ª… — o olho segue a linha
18
18
  * numa tabela larga. Nos dois arranjos (`default` e `rows`). */
19
19
  striped?: boolean;
20
+ /** MNT-38: uma linha clara entre as fileiras do corpo, menos depois da última (a forma "A", aprovada em 05/11/2026). Uma
21
+ * exceção nomeada ao sem linha (ADR-0072): só aparece quando o app escolhe. Sem efeito no arranjo `rows` e na Ember. */
22
+ dividers?: boolean;
20
23
  }
21
- export declare function Table({ caption, stickyHeader, stickyFirstColumn, fit, differencesOnly, striped, variant, children, className, ...props }: TableProps): React.JSX.Element;
24
+ export declare function Table({ caption, stickyHeader, stickyFirstColumn, fit, differencesOnly, striped, dividers, variant, children, className, ...props }: TableProps): React.JSX.Element;
22
25
  export interface SortableItem {
23
26
  id: string;
24
27
  label: ReactNode;
@@ -6,7 +6,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
6
6
  import React from "react";
7
7
  import { cx, useAureaStrings, useReorder } from "./internal.js";
8
8
  import { Icon } from "./system.js";
9
- export function Table({ caption, stickyHeader, stickyFirstColumn, fit, differencesOnly, striped, variant = "default", children, className, ...props }) { const s = useAureaStrings(); return _jsx("div", { className: cx("table-region", stickyHeader && "table-sticky-header", stickyFirstColumn && "table-sticky-first", variant === "rows" && "table-region-rows"), role: "region", "aria-label": typeof caption === "string" ? caption : s.tableLabel, tabIndex: 0, children: _jsxs("table", { className: cx("table", fit && "table-fit", differencesOnly && "table-differences-only", variant === "rows" && "table-rows", striped && "table-striped", className), ...props, children: [caption && _jsx("caption", { children: caption }), children] }) }); }
9
+ export function Table({ caption, stickyHeader, stickyFirstColumn, fit, differencesOnly, striped, dividers, variant = "default", children, className, ...props }) { const s = useAureaStrings(); return _jsx("div", { className: cx("table-region", stickyHeader && "table-sticky-header", stickyFirstColumn && "table-sticky-first", variant === "rows" && "table-region-rows"), role: "region", "aria-label": typeof caption === "string" ? caption : s.tableLabel, tabIndex: 0, children: _jsxs("table", { className: cx("table", fit && "table-fit", differencesOnly && "table-differences-only", variant === "rows" && "table-rows", striped && "table-striped", dividers && "table-dividers", className), ...props, children: [caption && _jsx("caption", { children: caption }), children] }) }); }
10
10
  // O protocolo de teclado e de ponteiro saiu daqui para o `useReorder` do `internal` no item N1,
11
11
  // quando o `BlockEditor` virou o segundo dono dele. A DOM abaixo não mudou uma vírgula na
12
12
  // extração — é o que o gate de pixel e o `skin.spec` continuam medindo.
@@ -12,7 +12,7 @@ export interface GridFilterSpec {
12
12
  label: string;
13
13
  }>;
14
14
  }
15
- export declare function DataGrid<T>({ data, columns, label, filterable, pageSize, selectable, onSelectionChange, getRowId, className, sorting: sortingProp, onSortingChange, globalFilter: globalFilterProp, onGlobalFilterChange, page, onPageChange, rowSelection: rowSelectionProp, onRowSelectionChange, manualSorting, manualFiltering, manualPagination, rowCount, filters, columnFilters: columnFiltersProp, onColumnFiltersChange, bulkActions, stickyHeader, hideableColumns, columnVisibility: columnVisibilityProp, onColumnVisibilityChange, resizableColumns, columnSizing: columnSizingProp, onColumnSizingChange, state, stateMessage, renderDetail, detailRowId: detailRowIdProp, onDetailRowIdChange, onExport }: {
15
+ export declare function DataGrid<T>({ data, columns, label, filterable, pageSize, selectable, onSelectionChange, getRowId, className, sorting: sortingProp, onSortingChange, globalFilter: globalFilterProp, onGlobalFilterChange, page, onPageChange, rowSelection: rowSelectionProp, onRowSelectionChange, manualSorting, manualFiltering, manualPagination, rowCount, filters, columnFilters: columnFiltersProp, onColumnFiltersChange, bulkActions, stickyHeader, dividers, fit, hideableColumns, columnVisibility: columnVisibilityProp, onColumnVisibilityChange, resizableColumns, columnSizing: columnSizingProp, onColumnSizingChange, state, stateMessage, renderDetail, detailRowId: detailRowIdProp, onDetailRowIdChange, onExport }: {
16
16
  data: T[];
17
17
  columns: Array<ColumnDef<T, any>>;
18
18
  label?: string;
@@ -43,7 +43,9 @@ export declare function DataGrid<T>({ data, columns, label, filterable, pageSize
43
43
  icon?: IconName;
44
44
  onAction: (rows: T[], clear: () => void) => void;
45
45
  }>;
46
- stickyHeader?: boolean;
46
+ stickyHeader?: boolean | "page";
47
+ dividers?: boolean;
48
+ fit?: boolean;
47
49
  hideableColumns?: boolean;
48
50
  columnVisibility?: VisibilityState;
49
51
  onColumnVisibilityChange?: (v: VisibilityState) => void;
package/dist/data-grid.js CHANGED
@@ -95,7 +95,67 @@ function useMaybe(outer, onChange, initial) {
95
95
  return [value, u => { const next = typeof u === "function" ? u(value) : u; if (!controlled)
96
96
  setInner(next); onChange?.(next); }];
97
97
  }
98
- export function DataGrid({ data, columns, label, filterable, pageSize, selectable, onSelectionChange, getRowId, className, sorting: sortingProp, onSortingChange, globalFilter: globalFilterProp, onGlobalFilterChange, page, onPageChange, rowSelection: rowSelectionProp, onRowSelectionChange, manualSorting, manualFiltering, manualPagination, rowCount, filters, columnFilters: columnFiltersProp, onColumnFiltersChange, bulkActions, stickyHeader, hideableColumns, columnVisibility: columnVisibilityProp, onColumnVisibilityChange, resizableColumns, columnSizing: columnSizingProp, onColumnSizingChange, state, stateMessage, renderDetail, detailRowId: detailRowIdProp, onDetailRowIdChange, onExport }) {
98
+ /** O que fica parado no topo da página na coluna da grade: o fundo da pilha de elementos no alto da tela, subindo até o
99
+ * primeiro ancestral `fixed` ou `sticky` que não é da própria grade. Devolve onde ele termina (0 se não houver). */
100
+ function topoParado(caixa) {
101
+ const r = caixa.getBoundingClientRect();
102
+ const x = Math.min(Math.max(r.left + r.width / 2, 0), innerWidth - 1);
103
+ let fundo = 0;
104
+ // Sem `elementsFromPoint` (um ambiente sem desenho), não há o que medir: o cabeçalho fica onde está.
105
+ for (const el of document.elementsFromPoint?.(x, 0) ?? []) {
106
+ if (caixa.contains(el))
107
+ continue;
108
+ for (let a = el; a && a !== document.documentElement; a = a.parentElement) {
109
+ const pos = getComputedStyle(a).position;
110
+ if (pos === "fixed" || pos === "sticky") {
111
+ fundo = Math.max(fundo, a.getBoundingClientRect().bottom);
112
+ break;
113
+ }
114
+ }
115
+ }
116
+ return fundo;
117
+ }
118
+ /** S-10: o cabeçalho da grade anda com a página. Cada `th` do `thead` ganha um `translate` — a caixa continua rolando de
119
+ * lado, e o cabeçalho, que está dentro dela, vai junto. Para no fim da caixa, com a última fileira ainda à vista. */
120
+ function usePresoNaPagina(ligado, grade, montagem) {
121
+ React.useLayoutEffect(() => {
122
+ const tabela = grade.current;
123
+ if (!ligado || !tabela)
124
+ return;
125
+ const caixa = tabela.closest(".table-wrap");
126
+ if (!caixa)
127
+ return;
128
+ let quadro = 0;
129
+ const medir = () => {
130
+ quadro = 0;
131
+ const cab = tabela.tHead;
132
+ if (!cab)
133
+ return;
134
+ const r = caixa.getBoundingClientRect();
135
+ const ultima = tabela.tBodies[0]?.rows[tabela.tBodies[0].rows.length - 1]?.offsetHeight ?? 0;
136
+ const y = Math.round(Math.max(0, Math.min(topoParado(caixa) - r.top, r.height - cab.offsetHeight - ultima)));
137
+ for (const th of cab.querySelectorAll(":scope > tr > th"))
138
+ th.style.translate = y ? `0 ${y}px` : "";
139
+ };
140
+ const pedir = () => { if (!quadro)
141
+ quadro = requestAnimationFrame(medir); };
142
+ medir();
143
+ addEventListener("scroll", pedir, { passive: true, capture: true });
144
+ addEventListener("resize", pedir);
145
+ const vigia = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(pedir);
146
+ vigia?.observe(tabela);
147
+ return () => {
148
+ cancelAnimationFrame(quadro);
149
+ removeEventListener("scroll", pedir, { capture: true });
150
+ removeEventListener("resize", pedir);
151
+ vigia?.disconnect();
152
+ for (const th of tabela.querySelectorAll("thead th"))
153
+ th.style.translate = "";
154
+ };
155
+ // `montagem`: a linha aberta do painel de detalhe muda o lugar da tabela na árvore, e a tabela nasce de novo.
156
+ }, [ligado, grade, montagem]);
157
+ }
158
+ export function DataGrid({ data, columns, label, filterable, pageSize, selectable, onSelectionChange, getRowId, className, sorting: sortingProp, onSortingChange, globalFilter: globalFilterProp, onGlobalFilterChange, page, onPageChange, rowSelection: rowSelectionProp, onRowSelectionChange, manualSorting, manualFiltering, manualPagination, rowCount, filters, columnFilters: columnFiltersProp, onColumnFiltersChange, bulkActions, stickyHeader, dividers, fit, hideableColumns, columnVisibility: columnVisibilityProp, onColumnVisibilityChange, resizableColumns, columnSizing: columnSizingProp, onColumnSizingChange, state, stateMessage, renderDetail, detailRowId: detailRowIdProp, onDetailRowIdChange, onExport }) {
99
159
  const s = useAureaStrings();
100
160
  const [sorting, setSorting] = useMaybe(sortingProp, onSortingChange, []);
101
161
  const [globalFilter, setGlobalFilter] = useMaybe(globalFilterProp, onGlobalFilterChange, "");
@@ -400,7 +460,12 @@ export function DataGrid({ data, columns, label, filterable, pageSize, selectabl
400
460
  // O marcador vai na GRADE, não no recado: quem está obsoleto é a tabela, e o `Alert` é só
401
461
  // como ela conta isso. Achado pelo check 30 na primeira execução dele — eu tinha marcado o
402
462
  // recado, e com `state="loading"` não há recado nenhum, então o estado não chegava ao DOM.
403
- return _jsxs("div", { className: cx("datagrid", stickyHeader && "datagrid-sticky", className), "data-state": state, children: [emLote.length > 0 && _jsxs(Toolbar, { label: s.dataGridBulkLabel, children: [_jsxs("span", { className: "hint", children: [emLote.length, " ", s.dataGridSelected] }), _jsx(ToolbarSeparator, {}), bulkActions?.map(a => _jsx(ToolbarButton, { size: "sm", leadingIcon: a.icon, onClick: () => a.onAction(emLote, limparSelecao), children: a.label }, a.id)), _jsx(ToolbarButton, { size: "sm", onClick: limparSelecao, children: s.dataGridClearSelection })] }), controles.length > 1 ? _jsx(Cluster, { children: controles }) : controles[0] ?? null, recado && _jsx(Alert, { variant: state === "error" ? "danger" : universal ? stateSeverity(universal) : "warning", children: recado }), (() => {
463
+ // S-10 (o MNT-40, aprovado em 05/11/2026 como valor novo): com `stickyHeader="page"` a caixa não ganha teto nem rolagem
464
+ // de cima para baixo, e o cabeçalho anda com a PÁGINA até encostar embaixo do que fica parado no topo dela (a barra do
465
+ // `AppShell`, o cabeçalho do site). Só com CSS não dá: a caixa rola de lado, e um elemento grudento gruda no contêiner de
466
+ // rolagem mais próximo — a caixa, não a página. Então o deslocamento é medido aqui, a cada rolagem.
467
+ usePresoNaPagina(stickyHeader === "page", grade, detailRowId);
468
+ return _jsxs("div", { className: cx("datagrid", stickyHeader === true && "datagrid-sticky", stickyHeader === "page" && "datagrid-sticky-page", dividers && "datagrid-dividers", fit && "datagrid-fit", className), "data-state": state, children: [emLote.length > 0 && _jsxs(Toolbar, { label: s.dataGridBulkLabel, children: [_jsxs("span", { className: "hint", children: [emLote.length, " ", s.dataGridSelected] }), _jsx(ToolbarSeparator, {}), bulkActions?.map(a => _jsx(ToolbarButton, { size: "sm", leadingIcon: a.icon, onClick: () => a.onAction(emLote, limparSelecao), children: a.label }, a.id)), _jsx(ToolbarButton, { size: "sm", onClick: limparSelecao, children: s.dataGridClearSelection })] }), controles.length > 1 ? _jsx(Cluster, { children: controles }) : controles[0] ?? null, recado && _jsx(Alert, { variant: state === "error" ? "danger" : universal ? stateSeverity(universal) : "warning", children: recado }), (() => {
404
469
  // F9: o embrulho de duas colunas só existe COM o painel aberto — fechado, a
405
470
  // marcação é a de sempre. É a lição do F7: não mudar a estrutura de quem não
406
471
  // pediu nada. A largura do painel é `--datagrid-detail-w`, e quem decide se
@@ -59,10 +59,12 @@ const ICONE_DA_VARIANTE = { info: "info",
59
59
  // na cor do texto. Sem ele (`"card"`), o cartão de sempre.
60
60
  export function Alert({ variant, state, title, icon, onDismiss, action, appearance, children, className, ...props }) { const s = useAureaStrings(); const v = variant ?? (state ? stateSeverity(state) : "info"); return _jsxs("div", { className: cx("alert", `alert-${v}`, appearance === "soft" && "alert-soft", action != null && "alert-has-action", className), role: v === "danger" ? "alert" : "status", "data-state": state, ...props, children: [_jsx(Icon, { name: icon ?? proprio(ICONE_DA_VARIANTE, v) ?? "info", weight: icon ? undefined : "fill" }), _jsxs("div", { children: [title && _jsx("strong", { children: title }), children ?? (state ? proprio(s.universalState, state) : null)] }), action != null && _jsx("div", { className: "alert-action", children: action }), onDismiss ? _jsx(CloseButton, { onClick: onDismiss }) : _jsx("span", {})] }); }
61
61
  export function Banner(props) {
62
+ // O hook ANTES do `return` do `consent` (auditoria externa, 05/11/2026): trocar a variante entre renderizações mudava a
63
+ // ordem dos hooks.
64
+ const s = useAureaStrings();
62
65
  if (props.variant === "consent")
63
66
  return _jsx(BannerConsent, { ...props });
64
67
  const { variant, state, title, icon, onDismiss, children, className, categories: _c, value: _v, onConsent: _o, ...rest } = props;
65
- const s = useAureaStrings();
66
68
  const v = variant ?? (state ? stateSeverity(state) : "info");
67
69
  return _jsxs("div", { className: cx("banner", `banner-${v}`, className), role: v === "danger" ? "alert" : "status", "data-state": state, ...rest, children: [icon ? _jsx(Icon, { name: icon }) : _jsx("span", {}), _jsxs("div", { children: [title && _jsx("strong", { children: title }), children ?? (state ? proprio(s.universalState, state) : null)] }), onDismiss ? _jsx(IconButton, { variant: "ghost", size: "sm", icon: "x", label: s.close, onClick: onDismiss }) : _jsx("span", {})] });
68
70
  }
@@ -15,7 +15,7 @@ import { Slider as BaseSlider } from "@base-ui/react/slider";
15
15
  import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
16
16
  import { Radio as BaseRadio } from "@base-ui/react/radio";
17
17
  import { useDirection } from "@base-ui/react/direction-provider";
18
- import { cx, useAureaStrings, usePortalContainer, useReorder, controlesRotulaveis } from "./internal.js";
18
+ import { cx, useAureaStrings, usePortalContainer, useReorder, useDeslize, controlesRotulaveis } from "./internal.js";
19
19
  import { COLOR_CHANNELS, areaBackground, channelRange, colorName, corToHex, formatChannel, getChannel, hsbToRgb, parseColor, pureHue, setChannel, spaceOf, trackBackground } from "./color.js";
20
20
  import { Popover as BasePopover } from "@base-ui/react/popover";
21
21
  // Os seis controles abaixo saíram deste arquivo no item O1 e moram no `markup.tsx`, sem a
@@ -734,11 +734,15 @@ export function OTPField({ length, value, defaultValue, onValueChange, mask, dis
734
734
  // cheia), `size="2xl"` (segmento de 48), `wrap` (quebra linha, o trilho com canto 22) e `orientation="vertical"` (em pé).
735
735
  export function SegmentedControl({ items, value, onChange, label, fullWidth, size = "md", selectedStyle, wrap, orientation = "horizontal" }) {
736
736
  const s = useAureaStrings();
737
+ // S-04 (05/11/2026): o escolhido DESLIZA de um segmento ao outro, em vez de pular (`useDeslize`, no `internal`). Só na
738
+ // escolha: com `href` a troca é de página, e a página nova já nasce com o escolhido no lugar.
739
+ const fila = React.useRef(null);
740
+ useDeslize(fila, ".active", value);
737
741
  const classe = cx("segmented", fullWidth && "segmented-full", size === "sm" && "segmented-sm", size === "lg" && "segmented-lg", size === "xl" && "segmented-xl", size === "2xl" && "segmented-2xl", wrap && orientation !== "vertical" && "segmented-wrap", orientation === "vertical" && "segmented-vertical");
738
742
  const miolo = (i) => i.icon ? _jsxs(_Fragment, { children: [_jsx(Icon, { name: i.icon, weight: i.value === value ? "fill" : "regular" }), i.label] }) : i.label;
739
743
  if (items.length > 0 && items.every(i => i.href != null))
740
744
  return _jsx("nav", { className: classe, "data-segment-style": selectedStyle, "aria-label": label ?? s.optionsLabel, children: items.map(i => _jsx("a", { href: i.href, className: i.value === value ? "active" : undefined, "aria-current": i.value === value ? "page" : undefined, children: miolo(i) }, i.value)) });
741
- return _jsx(BaseRadioGroup, { className: classe, "data-segment-style": selectedStyle, "aria-label": label ?? s.optionsLabel, "aria-orientation": orientation === "vertical" ? "vertical" : undefined, value: value, onValueChange: v => onChange?.(String(v)), children: items.map(i => _jsx(BaseRadio.Root, { value: i.value, className: i.value === value ? "active" : undefined, nativeButton: true, render: _jsx("button", { type: "button" }), children: miolo(i) }, i.value)) });
745
+ return _jsx(BaseRadioGroup, { ref: fila, className: classe, "data-segment-style": selectedStyle, "aria-label": label ?? s.optionsLabel, "aria-orientation": orientation === "vertical" ? "vertical" : undefined, value: value, onValueChange: v => onChange?.(String(v)), children: items.map(i => _jsx(BaseRadio.Root, { value: i.value, className: i.value === value ? "active" : undefined, nativeButton: true, render: _jsx("button", { type: "button" }), children: miolo(i) }, i.value)) });
742
746
  }
743
747
  const ehAgrupado = (items) => items != null && items.length > 0 && typeof items[0] === "object" && items[0] != null && "items" in items[0];
744
748
  // UM renderizador e UMA lista para os dois combobox: duas cópias da mesma árvore é como a
@@ -33,6 +33,12 @@ export declare const DentroDoProviderContext: React.Context<boolean>;
33
33
  export declare const avisosAncorados: import("@base-ui/react").ToastManager<any>;
34
34
  export declare const PortalContext: React.Context<HTMLElement | null | undefined>;
35
35
  export declare const usePortalContainer: () => HTMLElement | null | undefined;
36
+ export declare const reduzMovimento: () => boolean;
37
+ export declare function tempoDoToken(el: Element, duracao: string, curva: string): {
38
+ duration: number;
39
+ easing: string;
40
+ } | null;
41
+ export declare function useDeslize(ref: React.RefObject<HTMLElement | null>, seletor: string, chave: unknown): void;
36
42
  export interface Reordenavel<E extends HTMLElement> {
37
43
  ref: React.RefObject<E | null>;
38
44
  pego: number | null;
package/dist/internal.js CHANGED
@@ -14,7 +14,7 @@
14
14
  // NÃO é subpath — `@aurea-uds/react/internal` não existe, de propósito.
15
15
  // Kbd mora aqui por dependência, não por categoria: o Button precisa dele e ele não precisa de
16
16
  // ninguém. A casa pública dele continua sendo `/data-display`, que o reexporta.
17
- import { createContext, useContext, useEffect, useRef, useState } from "react";
17
+ import React, { createContext, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
18
18
  import { Toast as BaseToast } from "@base-ui/react/toast";
19
19
  import { defaultStrings, defaultSpriteUrl } from "./pure.js";
20
20
  export { cx, fundirRender, defaultStrings, ptBR, defaultSpriteUrl, universalStates, stateSeverity } from "./pure.js";
@@ -71,6 +71,111 @@ export const DentroDoProviderContext = createContext(false);
71
71
  export const avisosAncorados = BaseToast.createToastManager();
72
72
  export const PortalContext = createContext(undefined);
73
73
  export const usePortalContainer = () => useContext(PortalContext);
74
+ // direction informa o Base UI (lado dos popovers, setas do teclado). O CSS
75
+ // espelha sozinho por propriedade lógica, mas depende do atributo dir no DOM:
76
+ // quem consome precisa pôr dir="rtl" no <html>. Este provider não mexe no DOM.
77
+ // ── O MOVIMENTO (S-04 e S-05, 05/11/2026) ─────────────────────────────────────────────────────
78
+ // O Victor achou a Aurea "estática": o escolhido do `SegmentedControl` e do `Tabs` PULAVA, e o arrasto do
79
+ // `SortableList` e do `BlockEditor` ia de casa em casa. Decidido por ele (05/11/2026, "Construir nós"): sem biblioteca
80
+ // nova, CSS e a animação do próprio navegador (`Element.animate`). O tempo e a curva NÃO se escrevem aqui: saem dos
81
+ // tokens da folha (`--duration-*`, `--ease-*`), lidos no elemento — o mesmo número que o CSS usa. Sem a folha, não há
82
+ // token, e não há animação: a troca acontece de uma vez, como antes. E quem pediu "reduzir movimento" também vê de
83
+ // uma vez — a regra global do CSS não alcança a animação feita por código, então quem pergunta é este arquivo.
84
+ export const reduzMovimento = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
85
+ export function tempoDoToken(el, duracao, curva) {
86
+ const cs = getComputedStyle(el);
87
+ const d = cs.getPropertyValue(duracao).trim(), easing = cs.getPropertyValue(curva).trim();
88
+ const duration = d.endsWith("ms") ? parseFloat(d) : d.endsWith("s") ? parseFloat(d) * 1000 : NaN;
89
+ return Number.isFinite(duration) && duration > 0 && easing ? { duration, easing } : null;
90
+ }
91
+ // O nome das animações deste arquivo: para cancelar só as nossas, e não a transição de CSS da mesma peça.
92
+ const ANIMACAO = "aurea-movimento";
93
+ // ── useDeslize (S-04) ─────────────────────────────────────────────────────────────────────────
94
+ // O ESCOLHIDO DESLIZA. A referência tem uma peça separada atrás dos itens. Aqui o escolhido continua se pintando — as
95
+ // sete cores do segmento, as treze marcas e os dois temas são regras de CSS que este gancho NÃO repete —, e só na troca
96
+ // entra uma peça de passagem: ela COPIA a pintura do novo escolhido (o fundo, a sombra, o aro e o fio de baixo, que na
97
+ // aba secundária é o único sinal), esconde a do item e anda da posição de antes até a nova. No fim, sai, e o item volta
98
+ // a se pintar. Copiar o que o navegador calculou, em vez de reescrever as cores, é o que garante que o escolhido em
99
+ // repouso fique IDÊNTICO ao de hoje. Troca no meio do caminho parte de onde a peça está, e não do item de antes.
100
+ // `seletor` acha o escolhido dentro de `ref`; `chave` é o valor escolhido.
101
+ export function useDeslize(ref, seletor, chave) {
102
+ const anterior = useRef(null);
103
+ const emCurso = useRef(null);
104
+ React.useLayoutEffect(() => () => { emCurso.current?.(); }, []);
105
+ React.useLayoutEffect(() => {
106
+ const raiz = ref.current;
107
+ if (!raiz)
108
+ return;
109
+ const novo = raiz.querySelector(seletor);
110
+ const velho = anterior.current;
111
+ anterior.current = novo;
112
+ const corrente = emCurso.current;
113
+ emCurso.current = null;
114
+ const de = corrente ? corrente() : velho && velho !== novo && velho.isConnected ? velho.getBoundingClientRect() : null;
115
+ if (!novo || !de || !de.width || reduzMovimento() || typeof novo.animate !== "function")
116
+ return;
117
+ const tempo = tempoDoToken(raiz, "--duration-slow", "--ease-emphasized");
118
+ if (!tempo)
119
+ return;
120
+ const para = novo.getBoundingClientRect();
121
+ if (!para.width)
122
+ return;
123
+ const cs = getComputedStyle(novo), fio = getComputedStyle(novo, "::after");
124
+ const passagem = document.createElement("span");
125
+ passagem.className = "selection-indicator";
126
+ passagem.setAttribute("aria-hidden", "true");
127
+ Object.assign(passagem.style, { left: "0px", top: "0px", borderRadius: cs.borderRadius, backgroundColor: cs.backgroundColor,
128
+ backgroundImage: cs.backgroundImage, boxShadow: cs.boxShadow });
129
+ if (fio.content && fio.content !== "none" && fio.content !== "normal" && fio.display !== "none") {
130
+ const linha = document.createElement("span");
131
+ Object.assign(linha.style, { left: fio.left, right: fio.right, bottom: fio.bottom, height: fio.height,
132
+ borderRadius: fio.borderRadius, backgroundColor: fio.backgroundColor });
133
+ passagem.append(linha);
134
+ }
135
+ // A peça mora DENTRO da fila, atrás dos itens (`z-index:-1` num contexto de empilhamento só dela), e a fila só
136
+ // ganha posição e contexto durante a passagem — em repouso, nada nela muda.
137
+ const antes = { position: raiz.style.position, isolation: raiz.style.isolation };
138
+ if (getComputedStyle(raiz).position === "static")
139
+ raiz.style.position = "relative";
140
+ raiz.style.isolation = "isolate";
141
+ const rr = raiz.getBoundingClientRect();
142
+ const quadro = (r) => ({ transform: `translate(${r.left - rr.left - raiz.clientLeft + raiz.scrollLeft}px,${r.top - rr.top - raiz.clientTop + raiz.scrollTop}px)`,
143
+ width: `${r.width}px`, height: `${r.height}px` });
144
+ const pintura = ["background-color", "background-image", "box-shadow"].map(p => [p, novo.style.getPropertyValue(p), novo.style.getPropertyPriority(p)]);
145
+ for (const [p] of pintura)
146
+ novo.style.setProperty(p, p === "background-color" ? "transparent" : "none", "important");
147
+ novo.setAttribute("data-sliding", "");
148
+ raiz.prepend(passagem);
149
+ const a = passagem.animate([quadro(de), quadro(para)], { ...tempo, fill: "forwards", id: ANIMACAO });
150
+ let feito = false;
151
+ const encerra = () => {
152
+ const onde = passagem.getBoundingClientRect();
153
+ if (feito)
154
+ return onde;
155
+ feito = true;
156
+ a.cancel();
157
+ passagem.remove();
158
+ for (const [p, v, pr] of pintura) {
159
+ if (v)
160
+ novo.style.setProperty(p, v, pr);
161
+ else
162
+ novo.style.removeProperty(p);
163
+ }
164
+ if (!novo.getAttribute("style"))
165
+ novo.removeAttribute("style");
166
+ novo.removeAttribute("data-sliding");
167
+ raiz.style.position = antes.position;
168
+ raiz.style.isolation = antes.isolation;
169
+ if (!raiz.getAttribute("style"))
170
+ raiz.removeAttribute("style");
171
+ if (emCurso.current === encerra)
172
+ emCurso.current = null;
173
+ return onde;
174
+ };
175
+ emCurso.current = encerra;
176
+ a.onfinish = () => { encerra(); };
177
+ }, [chave]);
178
+ }
74
179
  export function useReorder({ count, order, onReorder, rowSelector, handleSelector }) {
75
180
  const s = useAureaStrings();
76
181
  const ref = useRef(null);
@@ -79,16 +184,55 @@ export function useReorder({ count, order, onReorder, rowSelector, handleSelecto
79
184
  const [aviso, setAviso] = useState("");
80
185
  const origem = useRef(null);
81
186
  const arrasto = useRef(null);
187
+ // S-05: a MÃO — a linha que o ponteiro pegou, onde o ponteiro estava ao pegar e agora, e o topo dela ao pegar. Com isso a
188
+ // linha anda com o ponteiro (`translate`), e não só pula de casa em casa.
189
+ const mao = useRef(null);
190
+ // S-05: onde cada linha estava NA TELA antes da troca — a conta do "First, Last, Invert, Play": depois de a ordem nova
191
+ // entrar, cada vizinho parte de onde estava e desliza até o lugar novo.
192
+ const antes = useRef(null);
82
193
  const anuncia = (verbo, i) => setAviso(`${verbo}: ${i + 1} ${s.positionOf} ${count}`);
83
194
  const alcas = () => [...(ref.current?.querySelectorAll(handleSelector) ?? [])];
195
+ const linhas = () => [...(ref.current?.querySelectorAll(rowSelector) ?? [])];
196
+ // `offsetTop` não conta o `translate` nem a animação: é o lugar da linha na lista, e não onde ela aparece agora.
197
+ const seguir = (m) => { m.linha.style.translate = `0 ${m.y - m.y0 - (m.linha.offsetTop - m.topo0)}px`; };
84
198
  // Vai por efeito e não por `requestAnimationFrame`: o React precisa ter commitado a ordem nova
85
199
  // antes de procurar a alça.
86
200
  useEffect(() => { if (foco !== null) {
87
201
  alcas()[foco]?.focus();
88
202
  setFoco(null);
89
203
  } }, [foco, order]);
90
- const mover = (de, para) => { if (para >= 0 && para < count && de !== para)
91
- onReorder(de, para); };
204
+ // A ordem nova entrou: a linha pega volta para baixo do ponteiro, e os vizinhos deslizam de onde estavam.
205
+ useLayoutEffect(() => {
206
+ const m = mao.current;
207
+ if (m)
208
+ seguir(m);
209
+ const mapa = antes.current;
210
+ antes.current = null;
211
+ if (!mapa || !ref.current || reduzMovimento())
212
+ return;
213
+ const tempo = tempoDoToken(ref.current, "--duration-base", "--ease-emphasized");
214
+ if (!tempo)
215
+ return;
216
+ for (const l of linhas()) {
217
+ if (m && l === m.linha)
218
+ continue;
219
+ const de = mapa.get(l);
220
+ if (de == null || typeof l.animate !== "function")
221
+ continue;
222
+ for (const a of l.getAnimations?.() ?? [])
223
+ if (a.id === ANIMACAO)
224
+ a.cancel();
225
+ const d = de - l.getBoundingClientRect().top;
226
+ if (Math.abs(d) >= 1)
227
+ l.animate([{ transform: `translateY(${d}px)` }, { transform: "none" }], { ...tempo, id: ANIMACAO });
228
+ }
229
+ }, [order]);
230
+ const mover = (de, para) => {
231
+ if (para >= 0 && para < count && de !== para) {
232
+ antes.current = new Map(linhas().map(l => [l, l.getBoundingClientRect().top]));
233
+ onReorder(de, para);
234
+ }
235
+ };
92
236
  const teclado = (e, i) => {
93
237
  if (e.key === " " || e.key === "Enter") {
94
238
  e.preventDefault();
@@ -130,23 +274,56 @@ export function useReorder({ count, order, onReorder, rowSelector, handleSelecto
130
274
  }
131
275
  };
132
276
  // O alvo é a primeira linha cujo MEIO ainda está abaixo do ponteiro — a conta que faz o item
133
- // trocar de lugar ao passar da metade da linha vizinha, e não ao encostar nela.
277
+ // trocar de lugar ao passar da metade da linha vizinha, e não ao encostar nela. O meio é o do LUGAR da linha
278
+ // (`offsetTop`), e não o de onde ela aparece: a linha pega anda com o ponteiro e os vizinhos estão deslizando, e medir a
279
+ // caixa na tela faria o alvo tremer. A origem dos `offsetTop` na tela sai da própria lista.
134
280
  const ponteiroMove = (e) => {
135
281
  const de = arrasto.current;
136
282
  if (de === null)
137
283
  return;
138
- const linhas = [...(ref.current?.querySelectorAll(rowSelector) ?? [])];
139
- const achado = linhas.findIndex(l => { const r = l.getBoundingClientRect(); return e.clientY < r.top + r.height / 2; });
140
- const para = achado === -1 ? linhas.length - 1 : achado;
284
+ const m = mao.current;
285
+ if (m) {
286
+ m.y = e.clientY;
287
+ seguir(m);
288
+ }
289
+ const lista = ref.current;
290
+ if (!lista)
291
+ return;
292
+ const ls = linhas();
293
+ const caixa = lista.getBoundingClientRect();
294
+ const zero = ls[0]?.offsetParent === lista ? caixa.top + lista.clientTop - lista.scrollTop : caixa.top - lista.offsetTop;
295
+ const achado = ls.findIndex(l => e.clientY < zero + l.offsetTop + l.offsetHeight / 2);
296
+ const para = achado === -1 ? ls.length - 1 : achado;
141
297
  if (para !== de) {
142
298
  mover(de, para);
143
299
  arrasto.current = para;
144
300
  setPego(para);
145
301
  }
146
302
  };
303
+ // Ao soltar, a linha desliza do ponteiro até o lugar dela, e só então desce de volta para o nível das outras.
304
+ const pousa = () => {
305
+ const m = mao.current;
306
+ mao.current = null;
307
+ if (!m)
308
+ return;
309
+ const d = m.y - m.y0 - (m.linha.offsetTop - m.topo0);
310
+ m.linha.style.translate = "";
311
+ if (!m.linha.getAttribute("style"))
312
+ m.linha.removeAttribute("style");
313
+ const fim = () => m.linha.removeAttribute("data-dragging");
314
+ const tempo = ref.current && !reduzMovimento() && typeof m.linha.animate === "function" ? tempoDoToken(ref.current, "--duration-base", "--ease-emphasized") : null;
315
+ if (!tempo || Math.abs(d) < 1) {
316
+ fim();
317
+ return;
318
+ }
319
+ const a = m.linha.animate([{ transform: `translateY(${d}px)` }, { transform: "none" }], { ...tempo, id: ANIMACAO });
320
+ a.onfinish = fim;
321
+ a.oncancel = fim;
322
+ };
147
323
  const ponteiroSolta = () => {
148
324
  if (arrasto.current === null)
149
325
  return;
326
+ pousa();
150
327
  anuncia(s.sortableDropped, arrasto.current);
151
328
  arrasto.current = null;
152
329
  setPego(null);
@@ -157,6 +334,14 @@ export function useReorder({ count, order, onReorder, rowSelector, handleSelecto
157
334
  e.currentTarget.setPointerCapture(e.pointerId);
158
335
  arrasto.current = i;
159
336
  setPego(i);
337
+ const linha = e.currentTarget.closest(rowSelector);
338
+ if (linha) {
339
+ for (const a of linha.getAnimations?.() ?? [])
340
+ if (a.id === ANIMACAO)
341
+ a.finish();
342
+ linha.setAttribute("data-dragging", "");
343
+ mao.current = { linha, y0: e.clientY, topo0: linha.offsetTop, y: e.clientY };
344
+ }
160
345
  };
161
346
  return { ref, pego, aviso, teclado, ponteiroBaixo, ponteiroMove, ponteiroSolta };
162
347
  }
package/dist/markup.d.ts CHANGED
@@ -200,7 +200,8 @@ export interface KPIProps extends HTMLAttributes<HTMLDivElement>, RefAttributes<
200
200
  /** As barras embaixo do número (o site B, 0.54.0): cada uma é um botão de opção nativo; a escolhida fica branca no
201
201
  * `brand` (na cor do texto, fora dele) e a leitura diz o nome e o valor dela. */
202
202
  bars?: KPIBar[];
203
- /** A barra que começa escolhida (o índice). Padrão: a última. */
203
+ /** A barra que começa escolhida (o índice). Padrão: a última. Dois `KPI` com o mesmo título E as mesmas barras na
204
+ * mesma página precisam de `id` diferentes, para cada um guardar a sua barra. */
204
205
  defaultBar?: number;
205
206
  }
206
207
  export declare function KPI({ label, value, trend, direction, tone, directionLabel, variant, bars, defaultBar, className, ...props }: KPIProps): React.JSX.Element;
package/dist/markup.js CHANGED
@@ -119,6 +119,10 @@ export function Section({ surface = "background", spacing = "md", theme, variant
119
119
  }
120
120
  const TOM_DA_DIRECAO = { up: "success", down: "danger", flat: "neutral" };
121
121
  const PALAVRA_DA_DIRECAO = { up: "Up", down: "Down", flat: "No change" };
122
+ // Uma assinatura curta e determinística de um texto (djb2, em base 36): o mesmo texto dá o mesmo nome no servidor e no
123
+ // navegador, sem hook.
124
+ const assinatura = (texto) => { let h = 5381; for (let i = 0; i < texto.length; i++)
125
+ h = ((h << 5) + h + texto.charCodeAt(i)) | 0; return (h >>> 0).toString(36); };
122
126
  export function KPI({ label, value, trend, direction, tone, directionLabel, variant = "card", bars, defaultBar, className, ...props }) {
123
127
  const tom = direction ? (tone ?? TOM_DA_DIRECAO[direction]) : undefined;
124
128
  const miolo = _jsxs(_Fragment, { children: [_jsx("span", { className: "muted", children: label }), _jsx("strong", { children: value }), (trend || trend === 0 || direction) && _jsxs("small", { className: direction ? cx("kpi-trend", `kpi-trend-${direction}`, `kpi-tone-${tom}`) : undefined, children: [direction && _jsx("span", { className: "kpi-trend-icon", "aria-hidden": "true" }), direction && _jsx("span", { className: "sr-only", children: directionLabel ?? PALAVRA_DA_DIRECAO[direction] }), trend] })] });
@@ -127,8 +131,13 @@ export function KPI({ label, value, trend, direction, tone, directionLabel, vari
127
131
  const leituraDe = (b) => `${b.label} · ${typeof b.value === "string" || typeof b.value === "number" ? b.value : ""}`;
128
132
  // As barras são botões de opção NATIVOS (o KPI é marcação pura, roda no servidor): o grupo é um `fieldset` com o rótulo
129
133
  // do KPI, cada barra o `label` de um rádio com a leitura dela; o CSS mostra a leitura da escolhida e a da que está sob o
130
- // mouse. O `name` vem do rótulo quando é texto.
131
- const nomeDoGrupo = `kpi-bars-${typeof label === "string" ? label.toLowerCase().replace(/[^a-z0-9]+/g, "-") : "x"}`;
134
+ // mouse.
135
+ // O `name` do grupo (auditoria externa de 05/11/2026): vinha SÓ do rótulo, e dois KPI com o mesmo título — ou com o
136
+ // título em JSX, que virava "x" — caíam no mesmo grupo de rádios; medido no Chromium e no Firefox, o primeiro já
137
+ // perdia a barra escolhida ao carregar. Marcação pura não chama `useId` (a mesma regra do `menuId` do `Header`), então
138
+ // o nome junta o `id` do KPI, quando o app passa um, o rótulo e uma assinatura das próprias barras: dois KPI com dados
139
+ // diferentes nunca colidem, e dois idênticos se separam pelo `id`.
140
+ const nomeDoGrupo = bars && bars.length > 0 ? `kpi-bars-${props.id ? `${props.id}-` : ""}${typeof label === "string" ? label.toLowerCase().replace(/[^a-z0-9]+/g, "-") : "x"}-${assinatura(bars.map(b => `${b.label}:${b.amount}`).join("|"))}` : "";
132
141
  const barras = bars && bars.length > 0 && _jsxs("fieldset", { className: "kpi-bars-wrap", children: [typeof label === "string" && _jsx("legend", { className: "sr-only", children: label }), _jsx("div", { className: "kpi-bars", style: { "--kpi-bars": bars.length }, children: bars.map((b, i) => _jsxs("label", { className: "kpi-bar", children: [_jsx("input", { type: "radio", className: "kpi-bar-input", name: nomeDoGrupo, value: String(i), defaultChecked: i === escolhida, "aria-label": leituraDe(b) }), _jsx("span", { className: "kpi-bar-fill", style: { "--kpi-bar-h": `${Math.round(b.amount / maior * 100)}%` } }), _jsx("span", { className: "kpi-bar-reading", "aria-hidden": "true", children: leituraDe(b) })] }, i)) }), _jsx("div", { className: "kpi-bars-x", "aria-hidden": "true", style: { "--kpi-bars": bars.length }, children: bars.map((b, i) => _jsx("span", { children: b.label }, i)) })] });
133
142
  return variant === "plain" ? _jsxs("div", { className: cx("kpi", className), ...props, children: [miolo, barras] })
134
143
  : _jsxs(Card, { className: cx("kpi", variant === "brand" && "kpi-brand", className), ...props, children: [miolo, barras] });
@@ -10,7 +10,7 @@ import { Autocomplete as BaseAutocomplete } from "@base-ui/react/autocomplete";
10
10
  import { Dialog as BaseDialog } from "@base-ui/react/dialog";
11
11
  import { Popover as BasePopover } from "@base-ui/react/popover";
12
12
  import { useValorResponsivo } from "./responsivo-runtime.js";
13
- import { cx, fundirRender, useAureaStrings, usePortalContainer } from "./internal.js";
13
+ import { cx, fundirRender, useAureaStrings, usePortalContainer, useDeslize } from "./internal.js";
14
14
  import { Kbd, ProgressCircle } from "./markup.js";
15
15
  import { Icon } from "./system.js";
16
16
  import { Button, IconButton } from "./actions.js";
@@ -37,7 +37,7 @@ export function Stepper({ items, label, variant = "default", startContent, endCo
37
37
  return lista;
38
38
  }
39
39
  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)) }); }
40
- 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))] }); }
40
+ 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); const lista = useRef(null); useDeslize(lista, ".tab[data-active]", value); return _jsxs(BaseTabs.Root, { ref: ancora, value: value, onValueChange: v => onChange(String(v)), orientation: resolvida, className: "tabs-root", children: [_jsx(BaseTabs.List, { ref: lista, 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))] }); }
41
41
  function paginasVisiveis(page, total, siblings) {
42
42
  if (total <= 5 + siblings * 2)
43
43
  return Array.from({ length: total }, (_, i) => i + 1);
package/dist/overlays.js CHANGED
@@ -212,5 +212,5 @@ export function Menubar({ menus, label, modal, disabled, loopFocus, orientation,
212
212
  const resolvida = useValorResponsivo(orientation, "horizontal", ancora);
213
213
  const vertical = resolvida === "vertical";
214
214
  const ids = React.useId();
215
- 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, undefined, `${ids}-${i}`) }) }) })] }, i)) });
215
+ 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, portal, `${ids}-${i}`) }) }) })] }, i)) });
216
216
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurea-uds/react",
3
- "version": "0.56.0",
3
+ "version": "0.59.0",
4
4
  "description": "Os componentes React da Aurea UDS. Importe @aurea-uds/fonts/css e @aurea-uds/core/css junto.",
5
5
  "keywords": [
6
6
  "aurea",