@aurea-uds/react 0.54.0 → 0.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/layout-client.d.ts +8 -1
- package/dist/layout-client.js +20 -3
- package/dist/navigation-client.js +1 -1
- package/dist/overlays.d.ts +9 -1
- package/dist/overlays.js +17 -11
- package/package.json +1 -1
package/dist/layout-client.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type Orientation, type Responsive } from "./pure.js";
|
|
|
3
3
|
import { type IconButtonProps } from "./actions.js";
|
|
4
4
|
import { type HeaderVariant, type HeaderTab, type SidebarVariant, type SidebarScrollbar, type SidebarEntry, type SidebarCollapsible, type SidebarIndicator } from "./navigation.js";
|
|
5
5
|
declare function AppShellSidebarToggle(props: Omit<IconButtonProps, "icon" | "label" | "onClick" | "variant">): React.JSX.Element;
|
|
6
|
-
export declare function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant, topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, topbarTabsEnd, topbarActions, topbarBlurred, layout, sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, sidebarToggle, sidebarShortcut, sidebarIndicator, sidebarPanel, sidebarContrast, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant, aside, asideLabel, asideVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
6
|
+
export declare function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant, topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, topbarTabsEnd, topbarActions, topbarBlurred, layout, sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, sidebarToggle, sidebarShortcut, sidebarIndicator, sidebarPanel, sidebarContrast, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant, highContrast, textSize, aside, asideLabel, asideVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
7
7
|
brand: ReactNode;
|
|
8
8
|
navigation?: ReactNode;
|
|
9
9
|
navItems?: SidebarEntry[];
|
|
@@ -74,6 +74,13 @@ export declare function AppShell({ brand, navigation, navItems, currentNavId, na
|
|
|
74
74
|
/** AN-01: avisa cada troca — pelo botão, ou pela largura cruzando 1280. Guardar a preferência é do app. */
|
|
75
75
|
onSidebarCollapsedChange?: (collapsed: boolean) => void;
|
|
76
76
|
contentVariant?: "surface" | "plain";
|
|
77
|
+
/** O alto contraste no app inteiro (o MNT-30, ADR-0090): contorno nos campos, nos cartões e nos botões, o texto de apoio
|
|
78
|
+
* mais perto do texto e o link sempre sublinhado. Marca o `AppShell` e a raiz da página (`data-contrast="high"`), para
|
|
79
|
+
* os menus e as janelas, que abrem fora dele, saírem iguais. */
|
|
80
|
+
highContrast?: boolean;
|
|
81
|
+
/** O texto grande no app inteiro (o MNT-30, ADR-0090): cada letra 2 acima e o controle médio a 44. `data-text="lg"` no
|
|
82
|
+
* `AppShell` e na raiz da página, pela mesma razão do `highContrast`. */
|
|
83
|
+
textSize?: "md" | "lg";
|
|
77
84
|
}): React.JSX.Element;
|
|
78
85
|
export declare namespace AppShell {
|
|
79
86
|
export { AppShellSidebarToggle as SidebarToggle };
|
package/dist/layout-client.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
// Fase 9 (achado A5): este arquivo saiu do index.tsx de 970 linhas. Um módulo por categoria
|
|
4
4
|
// do registry — a taxonomia já existia e é gateada. A ordem de import entre eles é um DAG:
|
|
5
5
|
// internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
6
|
-
import { useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
6
|
+
import React, { useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
7
7
|
import { Separator as BaseSeparator } from "@base-ui/react/separator";
|
|
8
8
|
import { useDirection } from "@base-ui/react/direction-provider";
|
|
9
9
|
import { cx, useAureaStrings } from "./internal.js";
|
|
@@ -167,8 +167,25 @@ function ProvedorDaLateral({ ligado, children, ...p }) {
|
|
|
167
167
|
return ligado ? _jsx(Sidebar.Provider, { id: SHELL_NAV_ID, ...p, children: children }) : _jsx(_Fragment, { children: children });
|
|
168
168
|
}
|
|
169
169
|
function AppShellSidebarToggle(props) { return _jsx(Sidebar.Toggle, { ...props }); }
|
|
170
|
-
|
|
170
|
+
// O modo de leitura (o alto contraste, o texto grande) também na RAIZ da página (ADR-0090): menus, janelas e avisos abrem
|
|
171
|
+
// fora do `AppShell`, presos ao fim do documento, e sem isto sairiam sem o modo. Devolve a raiz como estava ao sair.
|
|
172
|
+
function useModoNaRaiz(atributo, valor) {
|
|
173
|
+
React.useEffect(() => {
|
|
174
|
+
if (valor === undefined || typeof document === "undefined")
|
|
175
|
+
return;
|
|
176
|
+
const raiz = document.documentElement;
|
|
177
|
+
const antes = raiz.getAttribute(atributo);
|
|
178
|
+
raiz.setAttribute(atributo, valor);
|
|
179
|
+
return () => { if (antes === null)
|
|
180
|
+
raiz.removeAttribute(atributo);
|
|
181
|
+
else
|
|
182
|
+
raiz.setAttribute(atributo, antes); };
|
|
183
|
+
}, [atributo, valor]);
|
|
184
|
+
}
|
|
185
|
+
export function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant = "floating", topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, topbarTabsEnd, topbarActions, topbarBlurred, layout = "app", sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, sidebarToggle = "edge", sidebarShortcut = true, sidebarIndicator, sidebarPanel, sidebarContrast, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant = "surface", highContrast, textSize, aside, asideLabel, asideVariant, children, className, ...props }) {
|
|
171
186
|
const s = useAureaStrings();
|
|
187
|
+
useModoNaRaiz("data-contrast", highContrast ? "high" : undefined);
|
|
188
|
+
useModoNaRaiz("data-text", textSize === "lg" ? "lg" : undefined);
|
|
172
189
|
const docs = layout === "docs", lateral = layout === "sidebar";
|
|
173
190
|
useGavetaFechaNoDesktop(docs);
|
|
174
191
|
const controlado = sidebarCollapsed !== undefined;
|
|
@@ -224,7 +241,7 @@ export function AppShell({ brand, navigation, navItems, currentNavId, navLabel,
|
|
|
224
241
|
// No arranjo, o topo é o pequeno (`size="sm"`), e o botão também: com o tamanho de sempre ele ficava 4 maior que os
|
|
225
242
|
// vizinhos e fora da linha deles (medido a 375, sem toque; com toque, todos sobem para 44).
|
|
226
243
|
const botaoDaGaveta = _jsx(IconButton, { className: "nav-toggle", icon: "list", label: s.navigationToggle, popoverTarget: SHELL_NAV_ID, ...(docs ? { size: "sm" } : {}) });
|
|
227
|
-
return _jsx("div", { className: cx("app-shell", layout === "docs" && "app-shell-docs", lateral && "app-shell-lateral", !lateral && topbarVariant === "flush" && "app-shell-flush", !lateral && topbarVariant === "pill" && "app-shell-pill", recolhe && "app-shell-collapsible", aside != null && "app-shell-with-aside", className), ...props, children: _jsxs(ProvedorDaLateral, { ligado: recolhe, collapsed: efetiva, onCollapsedChange: definir, collapsible: forma, shortcut: sidebarShortcut, children: [_jsx("a", { className: "skip-link", href: `#${SHELL_MAIN_ID}`, children: s.skipToContent }), !lateral && _jsxs(Header, { variant: topbarVariant, divider: topbarDivider, tabs: topbarTabs, currentTab: topbarCurrentTab, tabsLabel: topbarTabsLabel, tabsEnd: topbarTabsEnd, ...(docs ? { maxWidth: "docs", ...(topbarVariant === "pill" ? {} : { size: "sm" }) } : topbarVariant === "pill" ? { maxWidth: "full" } : {}), blurred: topbarBlurred, brand: docs ? brand : _jsxs(_Fragment, { children: [botaoDaGaveta, brand] }), actions: topbarActions != null ? _jsxs(_Fragment, { children: [topbarActions, docs && botaoDaGaveta] }) : undefined, children: [topbar, docs && topbarActions == null && botaoDaGaveta] }), recolhe && !lateral && sidebarToggle !== "none" && _jsx("div", { className: "sidebar-toggle-slot", children: _jsx(Tooltip, { content: rotulo, side: "right", children: _jsx(IconButton, { className: "sidebar-toggle", size: "xs", icon: paraOComeco === direita ? "caret-right" : "caret-left", label: rotulo, "aria-expanded": !efetiva, "aria-controls": SHELL_NAV_ID, onClick: alternar }) }) }), _jsx(Sidebar, { id: SHELL_NAV_ID, popover: "auto", variant: sidebarVariant, scrollbar: sidebarScrollbar, collapsed: efetiva, collapsible: forma, indicator: sidebarIndicator, panel: sidebarPanel, contrast: sidebarContrast, items: navItems, current: currentNavId, label: navLabel, onToggle: focoDaGaveta, header: lateral ? brand : undefined, footer: sidebarFooter, children: navigation }), docs && aside != null && _jsx("div", { className: "docs-toc-bar", children: _jsxs("button", { type: "button", className: "docs-toc-toggle", popoverTarget: SHELL_TOC_ID, children: [_jsx(Icon, { name: "list-bullets" }), _jsx("span", { className: "docs-toc-current", "data-toc-current": "", children: asideLabel ?? s.tocLabel }), _jsx(Icon, { name: "caret-down" })] }) }), lateral
|
|
244
|
+
return _jsx("div", { "data-contrast": highContrast ? "high" : undefined, "data-text": textSize === "lg" ? "lg" : undefined, className: cx("app-shell", layout === "docs" && "app-shell-docs", lateral && "app-shell-lateral", !lateral && topbarVariant === "flush" && "app-shell-flush", !lateral && topbarVariant === "pill" && "app-shell-pill", recolhe && "app-shell-collapsible", aside != null && "app-shell-with-aside", className), ...props, children: _jsxs(ProvedorDaLateral, { ligado: recolhe, collapsed: efetiva, onCollapsedChange: definir, collapsible: forma, shortcut: sidebarShortcut, children: [_jsx("a", { className: "skip-link", href: `#${SHELL_MAIN_ID}`, children: s.skipToContent }), !lateral && _jsxs(Header, { variant: topbarVariant, divider: topbarDivider, tabs: topbarTabs, currentTab: topbarCurrentTab, tabsLabel: topbarTabsLabel, tabsEnd: topbarTabsEnd, ...(docs ? { maxWidth: "docs", ...(topbarVariant === "pill" ? {} : { size: "sm" }) } : topbarVariant === "pill" ? { maxWidth: "full" } : {}), blurred: topbarBlurred, brand: docs ? brand : _jsxs(_Fragment, { children: [botaoDaGaveta, brand] }), actions: topbarActions != null ? _jsxs(_Fragment, { children: [topbarActions, docs && botaoDaGaveta] }) : undefined, children: [topbar, docs && topbarActions == null && botaoDaGaveta] }), recolhe && !lateral && sidebarToggle !== "none" && _jsx("div", { className: "sidebar-toggle-slot", children: _jsx(Tooltip, { content: rotulo, side: "right", children: _jsx(IconButton, { className: "sidebar-toggle", size: "xs", icon: paraOComeco === direita ? "caret-right" : "caret-left", label: rotulo, "aria-expanded": !efetiva, "aria-controls": SHELL_NAV_ID, onClick: alternar }) }) }), _jsx(Sidebar, { id: SHELL_NAV_ID, popover: "auto", variant: sidebarVariant, scrollbar: sidebarScrollbar, collapsed: efetiva, collapsible: forma, indicator: sidebarIndicator, panel: sidebarPanel, contrast: sidebarContrast, items: navItems, current: currentNavId, label: navLabel, onToggle: focoDaGaveta, header: lateral ? brand : undefined, footer: sidebarFooter, children: navigation }), docs && aside != null && _jsx("div", { className: "docs-toc-bar", children: _jsxs("button", { type: "button", className: "docs-toc-toggle", popoverTarget: SHELL_TOC_ID, children: [_jsx(Icon, { name: "list-bullets" }), _jsx("span", { className: "docs-toc-current", "data-toc-current": "", children: asideLabel ?? s.tocLabel }), _jsx(Icon, { name: "caret-down" })] }) }), lateral
|
|
228
245
|
? _jsxs("div", { className: "app-shell-column", children: [topbar != null || topbarActions != null
|
|
229
246
|
? _jsx(Header, { variant: "flush", size: "sm", divider: topbarDivider, brand: _jsxs(_Fragment, { children: [botaoDaGaveta, sidebarToggle !== "none" && _jsx(AppShellSidebarToggle, {})] }), actions: topbarActions, children: topbar })
|
|
230
247
|
: _jsxs("div", { className: "app-shell-narrow-bar", children: [botaoDaGaveta, brand] }), _jsx("main", { id: SHELL_MAIN_ID, tabIndex: -1, className: cx("content", contentVariant === "plain" && "content-plain"), children: children })] })
|
|
@@ -508,7 +508,7 @@ export function NavList({ items, size = "md", currentLabel, className, ...props
|
|
|
508
508
|
}) });
|
|
509
509
|
}
|
|
510
510
|
// `size="lg"` (o site B — a busca nova, aprovada pela bancada em 01/11/2026, o item 2 e o D-2): a janela da largura `lg`
|
|
511
|
-
// (1024), o campo de 64 com a lupa e o "Esc" dentro, o encaixe `filters` embaixo dele, o título do grupo em mono maiúsculo
|
|
511
|
+
// (1024), o campo de 52 (era 64 na 0.54.0; o Victor, 03/11/2026, como a referência) com a lupa e o "Esc" dentro, o encaixe `filters` embaixo dele, o título do grupo em mono maiúsculo
|
|
512
512
|
// com a contagem, o item de 50 com o ícone num círculo de 40 tingido (`tone`), o título e a descrição cortada, o "↵" na
|
|
513
513
|
// linha ativa, a prévia (`preview`) do item ativo ao lado da lista — some abaixo de 1240 — e o encaixe `footer` no pé,
|
|
514
514
|
// ao lado das teclas. Sem `size="lg"`, a paleta de sempre; os encaixes só valem no `lg`.
|
package/dist/overlays.d.ts
CHANGED
|
@@ -76,6 +76,10 @@ interface MenuItemBase {
|
|
|
76
76
|
label: ReactNode;
|
|
77
77
|
disabled?: boolean;
|
|
78
78
|
leadingIcon?: IconName;
|
|
79
|
+
/** 0.55.0: a explicação embaixo do nome, na letra pequena (a anatomia do item da referência). */
|
|
80
|
+
description?: ReactNode;
|
|
81
|
+
/** 0.55.0: o ícone na ponta do item — por exemplo, o "abre fora" de um link que abre outro site. */
|
|
82
|
+
trailingIcon?: IconName;
|
|
79
83
|
}
|
|
80
84
|
/** Item de ação — a forma de sempre. `kind` é opcional para não quebrar quem já usa. */
|
|
81
85
|
export interface MenuActionDef extends MenuItemBase {
|
|
@@ -93,6 +97,8 @@ export interface MenuLinkDef {
|
|
|
93
97
|
kind: "link";
|
|
94
98
|
label: ReactNode;
|
|
95
99
|
leadingIcon?: IconName;
|
|
100
|
+
description?: ReactNode;
|
|
101
|
+
trailingIcon?: IconName;
|
|
96
102
|
href: string;
|
|
97
103
|
target?: string;
|
|
98
104
|
rel?: string;
|
|
@@ -137,10 +143,12 @@ export type MenuEntry = MenuActionDef | MenuLinkDef | MenuCheckboxDef | MenuRadi
|
|
|
137
143
|
/** @deprecated desde 28/08/2026 — use `MenuEntry`. Mantido porque `MenuActionDef` É a forma
|
|
138
144
|
* antiga: quem tipava com `MenuItemDef` continua compilando. */
|
|
139
145
|
export type MenuItemDef = MenuActionDef;
|
|
140
|
-
export declare function DropdownMenu({ trigger, items, side, label }: {
|
|
146
|
+
export declare function DropdownMenu({ trigger, items, side, align, label }: {
|
|
141
147
|
trigger: ReactElement;
|
|
142
148
|
items: MenuEntry[];
|
|
143
149
|
side?: OverlaySide;
|
|
150
|
+
/** 0.55.0: por onde o menu se alinha ao gatilho — `"end"` encosta a ponta dele na ponta do botão (a referência, no botão dividido). */
|
|
151
|
+
align?: "start" | "center" | "end";
|
|
144
152
|
label?: string;
|
|
145
153
|
}): React.JSX.Element;
|
|
146
154
|
export declare function ContextMenu({ children, items, label, className }: {
|
package/dist/overlays.js
CHANGED
|
@@ -150,26 +150,31 @@ const marca = (children) => _jsx("span", { className: "menu-mark", "aria-hidden"
|
|
|
150
150
|
// container configurado pelo provider e o submenu escaparia para o `document.body`. Duas
|
|
151
151
|
// camadas do mesmo menu em containers diferentes é o tipo de divergência que só aparece quando
|
|
152
152
|
// alguém monta a Aurea dentro de um shadow root ou de um diálogo nativo.
|
|
153
|
-
|
|
153
|
+
// O item com `description` (0.55.0) se anuncia como o da referência: o NOME é só o rótulo e a explicação é a DESCRIÇÃO
|
|
154
|
+
// (`aria-labelledby` + `aria-describedby`). Sem isso o leitor de tela lia os dois colados ("View as MarkdownView page as…").
|
|
155
|
+
// `ids` é o `useId` de quem monta o menu, mais a posição do item: estável no servidor e no navegador.
|
|
156
|
+
const nomeDoItem = (x, id) => x.description != null ? { "aria-labelledby": `${id}-l`, "aria-describedby": `${id}-d` } : {};
|
|
157
|
+
function renderMenuItems(items, portal, ids = "") {
|
|
154
158
|
return items.map((it, i) => {
|
|
155
159
|
if (it === "separator")
|
|
156
160
|
return _jsx(BaseMenu.Separator, { className: "menu-sep" }, i);
|
|
157
161
|
const kind = it.kind ?? "item";
|
|
158
|
-
const
|
|
162
|
+
const id = `${ids}-${i}`;
|
|
163
|
+
const dentro = (x, xid = id) => _jsxs(_Fragment, { children: [x.leadingIcon && _jsx(Icon, { name: x.leadingIcon }), x.description != null ? _jsxs("span", { className: "menu-item-text", children: [_jsx("span", { id: `${xid}-l`, children: x.label }), _jsx("span", { id: `${xid}-d`, className: "menu-item-description", children: x.description })] }) : x.label, x.trailingIcon && _jsx(Icon, { name: x.trailingIcon, className: "menu-item-trailing" })] });
|
|
159
164
|
switch (kind) {
|
|
160
165
|
case "group": {
|
|
161
166
|
const g = it;
|
|
162
|
-
return _jsxs(BaseMenu.Group, { children: [g.label && _jsx(BaseMenu.GroupLabel, { className: "menu-label", children: g.label }), renderMenuItems(g.items, portal)] }, i);
|
|
167
|
+
return _jsxs(BaseMenu.Group, { children: [g.label && _jsx(BaseMenu.GroupLabel, { className: "menu-label", children: g.label }), renderMenuItems(g.items, portal, id)] }, i);
|
|
163
168
|
}
|
|
164
169
|
case "radiogroup": {
|
|
165
170
|
const g = it;
|
|
166
|
-
return _jsxs(BaseMenu.RadioGroup, { value: g.value, defaultValue: g.defaultValue, onValueChange: v => g.onValueChange?.(String(v)), children: [g.label && _jsx(BaseMenu.GroupLabel, { className: "menu-label", children: g.label }), g.items.map((r, j) => _jsxs(BaseMenu.RadioItem, { className: "menu-item", value: r.value, disabled: r.disabled, children: [marca(_jsx(BaseMenu.RadioItemIndicator, { className: "menu-ponto" })), dentro(r)] }, j))] }, i);
|
|
171
|
+
return _jsxs(BaseMenu.RadioGroup, { value: g.value, defaultValue: g.defaultValue, onValueChange: v => g.onValueChange?.(String(v)), children: [g.label && _jsx(BaseMenu.GroupLabel, { className: "menu-label", children: g.label }), g.items.map((r, j) => _jsxs(BaseMenu.RadioItem, { className: "menu-item", value: r.value, disabled: r.disabled, ...nomeDoItem(r, `${id}-${j}`), children: [marca(_jsx(BaseMenu.RadioItemIndicator, { className: "menu-ponto" })), dentro(r, `${id}-${j}`)] }, j))] }, i);
|
|
167
172
|
}
|
|
168
173
|
case "submenu": {
|
|
169
174
|
const sm = it;
|
|
170
175
|
// O submenu é uma RAIZ própria com gatilho próprio — não é um item que "abre outro menu".
|
|
171
176
|
// É o que dá `aria-haspopup`, a seta para a direita e o fechamento em cascata de graça.
|
|
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);
|
|
177
|
+
return _jsxs(BaseMenu.SubmenuRoot, { children: [_jsxs(BaseMenu.SubmenuTrigger, { className: "menu-item", disabled: sm.disabled, ...nomeDoItem(sm, id), 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, id) }) }) })] }, i);
|
|
173
178
|
}
|
|
174
179
|
case "checkbox": {
|
|
175
180
|
const c = it;
|
|
@@ -178,26 +183,26 @@ function renderMenuItems(items, portal) {
|
|
|
178
183
|
// assinatura pública da Aurea mudar junto com uma versão do motor. Mesma decisão do
|
|
179
184
|
// `onValueChange` do grupo de rádio. O teste pegou: sem o embrulho, o `vi.fn()` recebia um
|
|
180
185
|
// `PointerEvent` de brinde.
|
|
181
|
-
return _jsxs(BaseMenu.CheckboxItem, { className: "menu-item", disabled: c.disabled, checked: c.checked, defaultChecked: c.defaultChecked, onCheckedChange: v => c.onCheckedChange?.(v), children: [marca(_jsx(BaseMenu.CheckboxItemIndicator, { children: _jsx(Icon, { name: "check", size: "sm" }) })), dentro(c)] }, i);
|
|
186
|
+
return _jsxs(BaseMenu.CheckboxItem, { className: "menu-item", disabled: c.disabled, checked: c.checked, defaultChecked: c.defaultChecked, onCheckedChange: v => c.onCheckedChange?.(v), ...nomeDoItem(c, id), children: [marca(_jsx(BaseMenu.CheckboxItemIndicator, { children: _jsx(Icon, { name: "check", size: "sm" }) })), dentro(c)] }, i);
|
|
182
187
|
}
|
|
183
188
|
case "link": {
|
|
184
189
|
const l = it;
|
|
185
|
-
return _jsx(BaseMenu.LinkItem, { className: "menu-item", href: l.href, target: l.target, rel: l.rel, closeOnClick: l.closeOnClick ?? true, children: dentro(l) }, i);
|
|
190
|
+
return _jsx(BaseMenu.LinkItem, { className: "menu-item", href: l.href, target: l.target, rel: l.rel, closeOnClick: l.closeOnClick ?? true, ...nomeDoItem(l, id), children: dentro(l) }, i);
|
|
186
191
|
}
|
|
187
192
|
default: {
|
|
188
193
|
const a = it;
|
|
189
|
-
return _jsx(BaseMenu.Item, { className: "menu-item", disabled: a.disabled, onClick: a.onClick, render: a.render, children: dentro(a) }, i);
|
|
194
|
+
return _jsx(BaseMenu.Item, { className: "menu-item", disabled: a.disabled, onClick: a.onClick, render: a.render, ...nomeDoItem(a, id), children: dentro(a) }, i);
|
|
190
195
|
}
|
|
191
196
|
}
|
|
192
197
|
});
|
|
193
198
|
}
|
|
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) }) }) })] }); }
|
|
199
|
+
export function DropdownMenu({ trigger, items, side = "bottom", align = "center", label }) { const portal = usePortalContainer(); const ids = React.useId(); return _jsxs(BaseMenu.Root, { children: [_jsx(BaseMenu.Trigger, { render: trigger }), _jsx(BaseMenu.Portal, { container: portal, children: _jsx(BaseMenu.Positioner, { className: "positioner", side: side, align: align, sideOffset: 6, children: _jsx(BaseMenu.Popup, { className: "menu", "aria-label": label, children: renderMenuItems(items, portal, ids) }) }) })] }); }
|
|
195
200
|
// ContextMenu: abre no botão direito e — por teclado — em Shift+F10 / tecla Menu,
|
|
196
201
|
// que o browser só dispara (como evento contextmenu) sobre um elemento FOCADO. Por
|
|
197
202
|
// isso o gatilho é focável (tabIndex 0) e tem nome acessível (auditoria 18/07/2026,
|
|
198
203
|
// MÉDIO 3); sem isso o teclado não alcança o menu. Consumidor pode sobrescrever
|
|
199
204
|
// tabIndex via children se o próprio já for focável.
|
|
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) }) }) })] }); }
|
|
205
|
+
export function ContextMenu({ children, items, label, className }) { const portal = usePortalContainer(); const ids = React.useId(); 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, ids) }) }) })] }); }
|
|
201
206
|
// G-AXIS-06 — o valor responsivo RESOLVIDO é a única fonte de verdade: ele vai para o motor, o
|
|
202
207
|
// motor publica `data-orientation`/`aria-orientation` e ajusta o teclado, e a pele reage ao
|
|
203
208
|
// atributo publicado. Ver `decisions/0047-css-first-para-apresentacao-runtime-para-semantica.md`.
|
|
@@ -206,5 +211,6 @@ export function Menubar({ menus, label, modal, disabled, loopFocus, orientation,
|
|
|
206
211
|
const ancora = useRef(null);
|
|
207
212
|
const resolvida = useValorResponsivo(orientation, "horizontal", ancora);
|
|
208
213
|
const vertical = resolvida === "vertical";
|
|
209
|
-
|
|
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)) });
|
|
210
216
|
}
|