@aurea-uds/react 0.43.0 → 0.44.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.
@@ -1,12 +1,12 @@
1
1
  import React, { type HTMLAttributes, type RefAttributes, type ReactNode } from "react";
2
2
  import { type Orientation, type Responsive } from "./pure.js";
3
3
  import { type IconButtonProps } from "./actions.js";
4
- import { type HeaderVariant, type HeaderTab, type SidebarVariant, type SidebarScrollbar, type SidebarItem } from "./navigation.js";
5
- declare function AppShellSidebarToggle({ className, ...props }: Omit<IconButtonProps, "icon" | "label" | "onClick">): React.JSX.Element | null;
6
- export declare function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant, topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, topbarTabsEnd, layout, sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant, aside, asideLabel, asideVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
4
+ import { type HeaderVariant, type HeaderTab, type SidebarVariant, type SidebarScrollbar, type SidebarEntry, type SidebarCollapsible, type SidebarIndicator } from "./navigation.js";
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, layout, sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, sidebarToggle, sidebarShortcut, sidebarIndicator, sidebarPanel, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant, aside, asideLabel, asideVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
7
7
  brand: ReactNode;
8
8
  navigation?: ReactNode;
9
- navItems?: SidebarItem[];
9
+ navItems?: SidebarEntry[];
10
10
  currentNavId?: string;
11
11
  navLabel?: string;
12
12
  topbar?: ReactNode;
@@ -44,8 +44,22 @@ export declare function AppShell({ brand, navigation, navItems, currentNavId, na
44
44
  asideVariant?: SidebarVariant;
45
45
  /** A lateral em trilha de ícones. Controlado: quem passa decide (e o `onSidebarCollapsedChange` avisa). */
46
46
  sidebarCollapsed?: boolean;
47
- /** AN-01: o botão de recolher na junção do menu com o conteúdo, e a trilha sozinha entre 1024 e 1279 de largura. */
48
- sidebarCollapsible?: boolean;
47
+ /** AN-01: o botão de recolher na junção do menu com o conteúdo, e a trilha sozinha entre 1024 e 1279 de largura.
48
+ * Desde o bloco 2 (4-A), também o JEITO de recolher: `true` ou `"icon"` (a trilha), `"capsule"` (a trilha em cápsula) ou
49
+ * `"offcanvas"` (a lateral sai da tela). */
50
+ sidebarCollapsible?: boolean | SidebarCollapsible;
51
+ /** 4-B: onde o shell põe o botão de recolher. `"edge"` (o padrão): na junção da lateral com o conteúdo (no
52
+ * `layout="sidebar"`, no começo da barra do conteúdo). `"none"`: o shell não põe nenhum, e o app põe o `Sidebar.Toggle`
53
+ * onde quiser — dentro da lateral, ao lado da marca, ou no pé, como linha (`variant="item"`). */
54
+ sidebarToggle?: "edge" | "none";
55
+ /** 4-B: o atalho Ctrl+B (Cmd+B no Mac), que recolhe e abre a lateral (abaixo de 1024, abre e fecha a gaveta). Padrão:
56
+ * ligado, com `sidebarCollapsible`. Não age quando a pessoa está digitando num campo. */
57
+ sidebarShortcut?: boolean;
58
+ /** 4-H: o desenho do item atual da lateral (o `indicator` da `Sidebar`). */
59
+ sidebarIndicator?: SidebarIndicator;
60
+ /** 4-F e 4-G: a trilha das seções com o painel (o `panel` da `Sidebar`) — os itens do primeiro nível de `navItems` viram
61
+ * seções. `docked`: o painel ao lado (recolher esconde o painel); `overlay`: o painel abre por cima. */
62
+ sidebarPanel?: "docked" | "overlay";
49
63
  /** AN-01: começa recolhida, sem controlar. A escolha vale até a janela cruzar 1280. */
50
64
  defaultSidebarCollapsed?: boolean;
51
65
  /** AN-01: avisa cada troca — pelo botão, ou pela largura cruzando 1280. Guardar a preferência é do app. */
@@ -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 React, { useEffect, useRef, useState, useSyncExternalStore } from "react";
6
+ import { 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";
@@ -160,22 +160,24 @@ function useLargura(query) {
160
160
  // aprovado"*). No `layout="sidebar"` ele substitui a bolinha da junção: com a barra no conteúdo, o shell o põe no começo
161
161
  // dela; sem barra, o app o põe ao lado do próprio título (`AppShell.SidebarToggle`). Abaixo de 1024 ele some — ali a
162
162
  // lateral é gaveta, e quem abre é o botão da gaveta.
163
- const ShellToggleContext = React.createContext(null);
164
- function AppShellSidebarToggle({ className, ...props }) {
165
- const c = React.useContext(ShellToggleContext);
166
- if (!c)
167
- return null;
168
- return _jsx(IconButton, { className: cx("sidebar-collapse-trigger", className), icon: "sidebar-simple", label: c.rotulo, "aria-expanded": !c.efetiva, "aria-controls": SHELL_NAV_ID, onClick: c.alternar, ...props });
163
+ // Desde o bloco 2 (4-B, 25/10/2026), é o `Sidebar.Toggle`: o shell põe a lateral num `Sidebar.Provider`, e o botão lê o estado
164
+ // dele — o mesmo botão serve ao lado do título, dentro da lateral (ao lado da marca) e no pé, como linha.
165
+ function ProvedorDaLateral({ ligado, children, ...p }) {
166
+ return ligado ? _jsx(Sidebar.Provider, { id: SHELL_NAV_ID, ...p, children: children }) : _jsx(_Fragment, { children: children });
169
167
  }
170
- export function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant = "floating", topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, topbarTabsEnd, layout = "app", sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant = "surface", aside, asideLabel, asideVariant, children, className, ...props }) {
168
+ function AppShellSidebarToggle(props) { return _jsx(Sidebar.Toggle, { ...props }); }
169
+ export function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant = "floating", topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, topbarTabsEnd, layout = "app", sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, sidebarToggle = "edge", sidebarShortcut = true, sidebarIndicator, sidebarPanel, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant = "surface", aside, asideLabel, asideVariant, children, className, ...props }) {
171
170
  const s = useAureaStrings();
172
171
  const docs = layout === "docs", lateral = layout === "sidebar";
173
172
  useGavetaFechaNoDesktop(docs);
174
173
  const controlado = sidebarCollapsed !== undefined;
174
+ // O jeito de recolher (4-A): `true` é a trilha de sempre.
175
+ const forma = sidebarCollapsible === true ? "icon" : sidebarCollapsible || undefined;
176
+ const recolhe = !!forma;
175
177
  // `null` = ninguém escolheu, e vale a largura.
176
178
  const [escolha, setEscolha] = useState(defaultSidebarCollapsed ?? null);
177
179
  const media = useLargura(MEDIA_MEDIA), estreita = useLargura(MEDIA_ESTREITA);
178
- const recolhida = controlado ? !!sidebarCollapsed : (escolha ?? (!!sidebarCollapsible && media));
180
+ const recolhida = controlado ? !!sidebarCollapsed : (escolha ?? (recolhe && media));
179
181
  // NA GAVETA A LATERAL NUNCA É TRILHA. Abaixo de 1024 ela abre por cima de tudo, com espaço para o
180
182
  // nome; recolhida ali, era uma gaveta de ícones sem nome — também para quem já passava
181
183
  // `sidebarCollapsed` (medido em 03/10/2026, na mesma conferência).
@@ -185,16 +187,29 @@ export function AppShell({ brand, navigation, navItems, currentNavId, navLabel,
185
187
  // Cruzar 1280 é mudar de contexto: a escolha da pessoa sai e a largura volta a mandar. Pelo
186
188
  // evento do navegador, e não comparando desenhos, para a hidratação não contar como cruzamento.
187
189
  useEffect(() => {
188
- if (!sidebarCollapsible || typeof window === "undefined" || typeof window.matchMedia !== "function")
190
+ if (!recolhe || typeof window === "undefined" || typeof window.matchMedia !== "function")
189
191
  return;
190
192
  const mq = window.matchMedia(MEDIA_MEDIA);
191
193
  const aoCruzar = (e) => { if (!controlado)
192
194
  setEscolha(null); aviso.current?.(e.matches); };
193
195
  mq.addEventListener?.("change", aoCruzar);
194
196
  return () => mq.removeEventListener?.("change", aoCruzar);
195
- }, [sidebarCollapsible, controlado]);
196
- const alternar = () => { const nova = !recolhida; if (!controlado)
197
- setEscolha(nova); onSidebarCollapsedChange?.(nova); };
197
+ }, [recolhe, controlado]);
198
+ // QUEM MUDA O ESTADO: o botão da junção, o `Sidebar.Toggle` em qualquer lugar e o Ctrl+B passam todos por aqui (4-B).
199
+ // Abaixo de 1024 a lateral é a gaveta: recolher ali é abrir ou fechar a gaveta, como o "mobile" da referência.
200
+ const definir = (nova) => {
201
+ if (estreita) {
202
+ try {
203
+ document.getElementById(SHELL_NAV_ID)?.togglePopover();
204
+ }
205
+ catch { /* motor sem popover */ }
206
+ return;
207
+ }
208
+ if (!controlado)
209
+ setEscolha(nova);
210
+ onSidebarCollapsedChange?.(nova);
211
+ };
212
+ const alternar = () => definir(!recolhida);
198
213
  const rotulo = efetiva ? s.sidebarExpand : s.sidebarCollapse;
199
214
  // A seta aponta para onde a lateral vai: recolher é para o começo da linha, abrir é para o fim. Na
200
215
  // escrita da direita para a esquerda o começo é a direita — pela direção do provedor, e não por
@@ -208,9 +223,9 @@ export function AppShell({ brand, navigation, navItems, currentNavId, navLabel,
208
223
  // 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
209
224
  // vizinhos e fora da linha deles (medido a 375, sem toque; com toque, todos sobem para 44).
210
225
  const botaoDaGaveta = _jsx(IconButton, { className: "nav-toggle", icon: "list", label: s.navigationToggle, popoverTarget: SHELL_NAV_ID, ...(docs ? { size: "sm" } : {}) });
211
- return _jsx("div", { className: cx("app-shell", layout === "docs" && "app-shell-docs", lateral && "app-shell-lateral", !lateral && topbarVariant === "flush" && "app-shell-flush", sidebarCollapsible && "app-shell-collapsible", aside != null && "app-shell-with-aside", className), ...props, children: _jsxs(ShellToggleContext.Provider, { value: sidebarCollapsible ? { alternar, efetiva, rotulo } : null, 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", size: "sm" } : {}), brand: docs ? brand : _jsxs(_Fragment, { children: [botaoDaGaveta, brand] }), children: [topbar, docs && botaoDaGaveta] }), sidebarCollapsible && !lateral && _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, 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
226
+ return _jsx("div", { className: cx("app-shell", layout === "docs" && "app-shell-docs", lateral && "app-shell-lateral", !lateral && topbarVariant === "flush" && "app-shell-flush", 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", size: "sm" } : {}), brand: docs ? brand : _jsxs(_Fragment, { children: [botaoDaGaveta, brand] }), children: [topbar, docs && 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, 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
212
227
  ? _jsxs("div", { className: "app-shell-column", children: [topbar != null
213
- ? _jsx(Header, { variant: "flush", size: "sm", divider: topbarDivider, brand: _jsxs(_Fragment, { children: [botaoDaGaveta, _jsx(AppShellSidebarToggle, {})] }), children: topbar })
228
+ ? _jsx(Header, { variant: "flush", size: "sm", divider: topbarDivider, brand: _jsxs(_Fragment, { children: [botaoDaGaveta, sidebarToggle !== "none" && _jsx(AppShellSidebarToggle, {})] }), children: topbar })
214
229
  : _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 })] })
215
230
  : _jsx("main", { id: SHELL_MAIN_ID, tabIndex: -1, className: cx("content", contentVariant === "plain" && "content-plain"), children: children }), aside != null && _jsx(Sidebar, { placement: "right", variant: asideVariant ?? sidebarVariant, className: "app-shell-aside", "aria-label": asideLabel ?? s.tocLabel, ...(docs ? { id: SHELL_TOC_ID, popover: "auto", onToggle: focoDaGaveta } : {}), children: aside })] }) });
216
231
  }
@@ -1,6 +1,7 @@
1
1
  import React, { type HTMLAttributes, type RefAttributes, type ReactNode, type ReactElement } from "react";
2
2
  import { type Responsive } from "./pure.js";
3
3
  import { type IconName } from "./system.js";
4
+ import { type IconButtonProps } from "./actions.js";
4
5
  export type StepState = "default" | "active" | "done" | "error";
5
6
  export interface StepItem {
6
7
  label: ReactNode;
@@ -91,21 +92,75 @@ export interface SidebarItem {
91
92
  icon?: IconName;
92
93
  badge?: ReactNode;
93
94
  onClick?: () => void;
94
- items?: SidebarItem[];
95
+ items?: SidebarEntry[];
95
96
  /** 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. */
96
97
  render?: ReactElement;
98
+ /** A foto ou o logotipo do item (4-E — o time, a pessoa): toma o lugar do `icon`, no mesmo formato da `NavList`. Recolhida, ele
99
+ * fica na trilha, e não um vão. */
100
+ avatar?: {
101
+ src?: string;
102
+ fallback?: ReactNode;
103
+ };
104
+ /** A ação do item ou do grupo (4-D — o "⋯", o "+"): um `IconButton` pequeno. Mora AO LADO do item, nunca dentro do link (botão
105
+ * dentro de link não é HTML válido, e o leitor de tela perde um dos dois). Recolhida, some, como na referência. */
106
+ action?: ReactNode;
107
+ /** Só no GRUPO (item com `items` e sem destino): o nome vira um botão que dobra a lista (4-D). */
108
+ collapsible?: boolean;
109
+ /** Com `collapsible`: o grupo começa aberto. Padrão: aberto. */
110
+ defaultOpen?: boolean;
97
111
  }
112
+ /** A lista da lateral: os itens e, entre eles, `"separator"` — a divisória entre seções (4-E). Sem linha (ADR-0072): é um vão.
113
+ * A lista se parte nela em duas, como os grupos da referência, que se separam fora da lista. */
114
+ export type SidebarEntry = SidebarItem | "separator";
98
115
  export type SidebarVariant = "floating" | "flush" | "plain";
99
116
  export type SidebarScrollbar = "hover" | "visible";
100
117
  export type SidebarPlacement = "left" | "right";
101
- export declare function Sidebar({ items, current, collapsed, variant, placement, scrollbar, label, header, footer, children, className, onClick, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
102
- items?: SidebarItem[];
118
+ export type SidebarCollapsible = "icon" | "capsule" | "offcanvas";
119
+ export type SidebarIndicator = "brand" | "segment" | "segment-dot" | "segment-line" | "subtle";
120
+ export interface SidebarState {
121
+ /** Recolhida agora. */
122
+ collapsed: boolean;
123
+ setCollapsed: (collapsed: boolean) => void;
124
+ toggle: () => void;
125
+ /** O jeito de recolher que o provedor passa à lateral. */
126
+ collapsible: SidebarCollapsible;
127
+ /** O `id` da lateral: o botão de recolher aponta para ela (`aria-controls`). */
128
+ id: string;
129
+ }
130
+ /** O estado da lateral: dentro de um `Sidebar.Provider` ou de um `AppShell` com `sidebarCollapsible`. Fora deles, `null`. */
131
+ export declare function useSidebar(): SidebarState | null;
132
+ declare function SidebarProvider({ collapsed, defaultCollapsed, onCollapsedChange, collapsible, shortcut, id, children }: {
133
+ /** Recolhida (controlado). */
134
+ collapsed?: boolean;
135
+ defaultCollapsed?: boolean;
136
+ onCollapsedChange?: (collapsed: boolean) => void;
137
+ /** O jeito de recolher (4-A). Padrão: `icon`, a trilha. */
138
+ collapsible?: SidebarCollapsible;
139
+ /** O atalho Ctrl+B (Cmd+B no Mac). Padrão: ligado, como na referência. */
140
+ shortcut?: boolean;
141
+ /** O `id` da lateral. Sem ele, um gerado. */
142
+ id?: string;
143
+ children?: ReactNode;
144
+ }): React.JSX.Element;
145
+ declare function SidebarToggle({ variant, className, onClick, ...props }: Omit<IconButtonProps, "icon" | "label" | "variant" | "children"> & {
146
+ variant?: "icon" | "item";
147
+ }): React.JSX.Element | null;
148
+ export declare function Sidebar({ items, current, collapsed, collapsible, indicator, panel, variant, placement, scrollbar, label, header, footer, children, className, onClick, id, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
149
+ items?: SidebarEntry[];
103
150
  current?: string;
104
151
  collapsed?: boolean;
105
152
  variant?: SidebarVariant;
106
153
  placement?: SidebarPlacement;
107
154
  scrollbar?: SidebarScrollbar;
108
155
  label?: string;
156
+ /** O jeito de recolher (4-A): `icon` (a trilha, o padrão), `capsule` (a trilha em cápsula) ou `offcanvas` (sai da tela).
157
+ * Dentro de um `Sidebar.Provider`, vem dele. */
158
+ collapsible?: SidebarCollapsible;
159
+ /** O desenho do item atual (4-H): `brand` (o de hoje), `segment`, `segment-dot`, `segment-line` ou `subtle`. */
160
+ indicator?: SidebarIndicator;
161
+ /** A trilha das seções com o painel (4-F e 4-G): os itens do primeiro nível viram seções, e a lista da seção mora num
162
+ * painel — `docked`, ao lado da trilha (recolher esconde só o painel), ou `overlay`, por cima, ao lado do ícone. */
163
+ panel?: "docked" | "overlay";
109
164
  /** O topo fixo (4-C): a marca do app (`Sidebar.Brand`), a busca. Não rola com a lista. */
110
165
  header?: ReactNode;
111
166
  /** O pé fixo (4-C): a pessoa e o sair (`Sidebar.User`), a lista curta (`Sidebar.Nav`), o cartão de destaque. Não rola com a lista. */
@@ -116,15 +171,19 @@ export declare namespace Sidebar {
116
171
  export { SidebarUser as User };
117
172
  export { SidebarNav as Nav };
118
173
  export { SidebarShow as Show };
174
+ export { SidebarProvider as Provider };
175
+ export { SidebarToggle as Toggle };
119
176
  }
120
177
  /** A marca do app no topo da lateral: o `logo` (a letra, o desenho, a imagem), o nome e o subtítulo. `variant="tile"` (o
121
178
  * padrão, a 11 das quinze) põe o logo num quadrinho na cor primária; `plain` (da 8 à 10) é o desenho solto e o nome
122
179
  * grande. Recolhida, fica só o logo. */
123
- declare function SidebarBrand({ logo, name, description, variant, className, ...props }: Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
180
+ declare function SidebarBrand({ logo, name, description, variant, action, className, ...props }: Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
124
181
  logo: ReactNode;
125
182
  name: ReactNode;
126
183
  description?: ReactNode;
127
184
  variant?: "tile" | "plain";
185
+ /** Uma ação ao lado da marca: o `Sidebar.Toggle`. Recolhida, ela desce para baixo do logo. */
186
+ action?: ReactNode;
128
187
  }): React.JSX.Element;
129
188
  /** A pessoa no pé da lateral, numa caixinha: a foto (`avatar`), o nome, o papel e a ação (o sair). Recolhida, a foto e a ação, empilhadas. */
130
189
  declare function SidebarUser({ avatar, name, description, action, className, ...props }: Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
@@ -135,7 +194,7 @@ declare function SidebarUser({ avatar, name, description, action, className, ...
135
194
  }): React.JSX.Element;
136
195
  /** Uma segunda lista com a pele da lateral (a do pé: Suporte, Ajustes). `label` é obrigatório: duas listas com o mesmo nome confundem o leitor de tela. */
137
196
  declare function SidebarNav({ items, current, label, className, ...props }: Omit<HTMLAttributes<HTMLElement>, "children"> & {
138
- items: SidebarItem[];
197
+ items: SidebarEntry[];
139
198
  current?: string;
140
199
  label: string;
141
200
  }): React.JSX.Element;
@@ -151,7 +210,7 @@ export type BottomNavWidth = "full" | "content";
151
210
  export type BottomNavVariantLegacy = "flat" | "surface" | "pill" | "dock";
152
211
  export type BottomNavVariantAny = BottomNavVariant | BottomNavVariantLegacy;
153
212
  export declare function BottomNav({ items, current, variant, indicator, width, label, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
154
- items: SidebarItem[];
213
+ items: SidebarEntry[];
155
214
  current?: string;
156
215
  variant?: BottomNavVariantAny;
157
216
  indicator?: BottomNavIndicator;
@@ -8,11 +8,12 @@ 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
10
  import { Dialog as BaseDialog } from "@base-ui/react/dialog";
11
+ import { Popover as BasePopover } from "@base-ui/react/popover";
11
12
  import { useValorResponsivo } from "./responsivo-runtime.js";
12
13
  import { cx, fundirRender, useAureaStrings, usePortalContainer } from "./internal.js";
13
14
  import { Kbd } from "./markup.js";
14
15
  import { Icon } from "./system.js";
15
- import { Button } from "./actions.js";
16
+ import { Button, IconButton } from "./actions.js";
16
17
  import { Badge, Spinner } from "./feedback.js";
17
18
  import { SearchField } from "./inputs.js";
18
19
  // `overlays` PASSOU A VIR ANTES de `navigation` no DAG (18/08/2026, MAP.md §DAG). Ele só
@@ -219,30 +220,57 @@ export function TreeView({ items, defaultExpandedIds, onSelect, onExpand, select
219
220
  }) }));
220
221
  return renderNodes(items, 1);
221
222
  }
222
- function sidebarList(items, ctx, sub, labelledBy) {
223
- return _jsx("ul", { className: cx("sidebar-list", sub && "sidebar-sub"), "aria-labelledby": labelledBy, children: items.map(it => {
224
- const lid = ctx.baseId + it.id;
225
- const filhos = it.items?.length ? it.items : undefined;
226
- // Rótulo escondido vira `.sr-only` em vez de sumir do DOM: na lateral recolhida o item
227
- // continua tendo nome para quem usa leitor de tela. Ícone sozinho não nomeia nada.
228
- const oculto = (no) => ctx.collapsed ? _jsx("span", { className: "sr-only", children: no }) : no;
229
- if (filhos && !it.href && !it.onClick && !it.render)
230
- return _jsxs("li", { children: [_jsx("p", { id: lid, className: cx("sidebar-group-label", ctx.collapsed && "sr-only"), children: it.label }), sidebarList(filhos, ctx, false, lid)] }, it.id);
231
- const ativo = it.id === ctx.current;
232
- // O item escolhido desenha o ícone CHEIO (ADR-0053).
233
- const miolo = _jsxs(_Fragment, { children: [it.icon && _jsx(Icon, { name: it.icon, weight: ativo ? "fill" : undefined }), _jsx("span", { className: cx("sidebar-label", ctx.collapsed && "sr-only"), children: it.label }), it.badge != null && oculto(it.badge)] });
234
- const alvo = it.render
235
- ? fundirRender(it.render, { id: lid, className: "sidebar-item", "aria-current": ativo ? "page" : undefined, onClick: it.onClick, children: miolo }, "a")
236
- : it.href
237
- ? _jsx("a", { id: lid, href: it.href, className: "sidebar-item", "aria-current": ativo ? "page" : undefined, onClick: it.onClick, children: miolo })
238
- : _jsx("button", { id: lid, type: "button", className: "sidebar-item", "aria-current": ativo ? "page" : undefined, onClick: it.onClick, children: miolo });
239
- // NO TRILHO O NOME SÓ EXISTE NO TOOLTIP. Recolhida, a lateral manda o rótulo para `.sr-only`: quem
240
- // usa leitor de tela continua ouvindo, e quem ENXERGA fica com um ícone mudo. A referência resolve
241
- // isso com tooltip no botão de navegação dela, e é o que falta para um trilho de ícone não virar adivinhação.
242
- // Só quando recolhida: com o rótulo visível ao lado, o tooltip repetiria o que já está na tela.
243
- // `side="right"` porque a lateral encosta na borda esquerda — para cima o balão sairia do trilho.
244
- return _jsxs("li", { children: [ctx.collapsed ? _jsx(Tooltip, { content: it.label, side: "right", children: alvo }) : alvo, filhos && sidebarList(filhos, ctx, true, lid)] }, it.id);
245
- }) });
223
+ // A DIVISÓRIA PARTE A LISTA (4-E, 25/10/2026). Na referência ela mora ENTRE grupos, fora das listas — então aqui cada trecho
224
+ // entre duas divisórias é uma lista própria, e a divisória é um vão entre elas. Um `<li>` vazio de papel apagado no meio da
225
+ // lista confundiria a conta de itens do leitor de tela ("3 de 9").
226
+ function sidebarList(entradas, ctx, sub, labelledBy) {
227
+ const trechos = [[]];
228
+ for (const e of entradas)
229
+ e === "separator" ? trechos.push([]) : trechos[trechos.length - 1].push(e);
230
+ const listas = trechos.filter(t => t.length > 0);
231
+ const ul = (itens, k) => _jsx("ul", { className: cx("sidebar-list", sub && "sidebar-sub"), "aria-labelledby": labelledBy, children: itens.map(it => sidebarEntry(it, ctx)) }, k);
232
+ return listas.length < 2 ? ul(listas[0] ?? [], 0) : _jsx(_Fragment, { children: listas.map((t, k) => _jsxs(React.Fragment, { children: [k > 0 && _jsx("div", { className: "sidebar-separator", "aria-hidden": "true" }), ul(t, k)] }, k)) });
233
+ }
234
+ function sidebarEntry(it, ctx) {
235
+ const lid = ctx.baseId + it.id;
236
+ const filhos = it.items?.length ? it.items : undefined;
237
+ // Rótulo escondido vira `.sr-only` em vez de sumir do DOM: na lateral recolhida o item
238
+ // continua tendo nome para quem usa leitor de tela. Ícone sozinho não nomeia nada.
239
+ const oculto = (no) => ctx.collapsed ? _jsx("span", { className: "sr-only", children: no }) : no;
240
+ if (filhos && !it.href && !it.onClick && !it.render)
241
+ return _jsx(SidebarGroup, { item: it, filhos: filhos, lid: lid, ctx: ctx }, it.id);
242
+ const ativo = it.id === ctx.current;
243
+ // O item escolhido desenha o ícone CHEIO (ADR-0053). Com `avatar`, a foto toma o lugar do ícone (4-E).
244
+ const miolo = _jsxs(_Fragment, { children: [it.avatar ? _jsx(Avatar, { src: it.avatar.src, fallback: it.avatar.fallback, className: "sidebar-avatar" }) : it.icon && _jsx(Icon, { name: it.icon, weight: ativo ? "fill" : undefined }), _jsx("span", { className: cx("sidebar-label", ctx.collapsed && "sr-only"), children: it.label }), it.badge != null && oculto(it.badge)] });
245
+ const alvo = it.render
246
+ ? fundirRender(it.render, { id: lid, className: "sidebar-item", "aria-current": ativo ? "page" : undefined, onClick: it.onClick, children: miolo }, "a")
247
+ : it.href
248
+ ? _jsx("a", { id: lid, href: it.href, className: "sidebar-item", "aria-current": ativo ? "page" : undefined, onClick: it.onClick, children: miolo })
249
+ : _jsx("button", { id: lid, type: "button", className: "sidebar-item", "aria-current": ativo ? "page" : undefined, onClick: it.onClick, children: miolo });
250
+ // NO TRILHO O NOME SÓ EXISTE NO TOOLTIP. Recolhida, a lateral manda o rótulo para `.sr-only`: quem
251
+ // usa leitor de tela continua ouvindo, e quem ENXERGA fica com um ícone mudo. A referência resolve
252
+ // isso com tooltip no botão de navegação dela, e é o que falta para um trilho de ícone não virar adivinhação.
253
+ // Só quando recolhida: com o rótulo visível ao lado, o tooltip repetiria o que já está na tela.
254
+ // `side="right"` porque a lateral encosta na borda esquerda — para cima o balão sairia do trilho.
255
+ // A SUBLISTA SOME NA TRILHA (2-A, o achado 13 do item 106): recolhido, o subitem sem ícone virava um botão vazio. A
256
+ // referência esconde a sublista quando a lateral recolhe; o item pai continua, com o nome na dica.
257
+ const acao = it.action != null && !ctx.collapsed;
258
+ return _jsxs("li", { className: cx(acao && "sidebar-item-with-action"), children: [ctx.collapsed ? _jsx(Tooltip, { content: it.label, side: "right", children: alvo }) : alvo, acao && _jsx("span", { className: "sidebar-item-action", children: it.action }), filhos && !ctx.collapsed && sidebarList(filhos, ctx, true, lid)] }, it.id);
259
+ }
260
+ // O GRUPO QUE DOBRA (4-D, 25/10/2026). O nome do grupo vira o botão de abrir e fechar — o padrão de divulgação (o mesmo
261
+ // do `Collapsible`): `aria-expanded` no botão e `aria-controls` na lista, que fica no DOM com `hidden` quando fechada. A
262
+ // seta aponta para baixo aberto e para o fim da linha fechado, como a do grupo que dobra da referência principal. A ação do grupo (o "+") fica ao lado do nome. Recolhida, o
263
+ // nome vai para o leitor de tela e a lista aparece inteira, como o grupo de sempre: na trilha não há onde dobrar.
264
+ function SidebarGroup({ item, filhos, lid, ctx }) {
265
+ const [aberto, setAberto] = React.useState(item.defaultOpen ?? true);
266
+ const direita = useDirection() === "rtl";
267
+ const dobra = !!item.collapsible && !ctx.collapsed;
268
+ const acao = item.action != null && !ctx.collapsed;
269
+ const nome = dobra
270
+ ? _jsxs("button", { id: lid, type: "button", className: "sidebar-group-label sidebar-group-toggle", "aria-expanded": aberto, "aria-controls": lid + "-lista", onClick: () => setAberto(v => !v), children: [_jsx("span", { children: item.label }), _jsx(Icon, { name: aberto ? "caret-down" : direita ? "caret-left" : "caret-right", size: "sm", className: "sidebar-group-caret" })] })
271
+ : _jsx("p", { id: lid, className: cx("sidebar-group-label", ctx.collapsed && "sr-only"), children: item.label });
272
+ const lista = sidebarList(filhos, ctx, false, lid);
273
+ return _jsxs("li", { children: [acao || dobra ? _jsxs("div", { className: "sidebar-group-head", children: [nome, acao && _jsx("span", { className: "sidebar-group-action", children: item.action })] }) : nome, dobra ? _jsx("div", { id: lid + "-lista", hidden: !aberto, children: lista }) : lista] });
246
274
  }
247
275
  // A GAVETA FECHA AO ESCOLHER (A-06, 23/09/2026). Abaixo de lg a lateral do `AppShell` é popover,
248
276
  // e a biblioteca a abria e NUNCA a fechava por código: `hidePopover` tinha zero ocorrências. O
@@ -271,22 +299,121 @@ function fecharGavetaAoEscolher(e) {
271
299
  // `Sidebar.Nav`, `Sidebar.Show`) sabem se a lateral está recolhida por este contexto, interno: o estado de recolher
272
300
  // com gancho, para o app, é o 4-B.
273
301
  const SidebarContext = React.createContext({ collapsed: false });
274
- export function Sidebar({ items, current, collapsed, variant = "floating", placement = "left", scrollbar = "hover", label, header, footer, children, className, onClick, ...props }) {
302
+ const SidebarStateContext = React.createContext(null);
303
+ /** O estado da lateral: dentro de um `Sidebar.Provider` ou de um `AppShell` com `sidebarCollapsible`. Fora deles, `null`. */
304
+ export function useSidebar() { return React.useContext(SidebarStateContext); }
305
+ // O ATALHO, como o da referência: Ctrl+B, e Cmd+B no Mac. A DIVERGÊNCIA, com o motivo: na referência ele vale até dentro de um
306
+ // campo, e rouba o negrito de quem escreve num editor; aqui ele não age onde se digita.
307
+ const ONDE_SE_DIGITA = "input,textarea,select,[contenteditable]:not([contenteditable=false])";
308
+ function SidebarProvider({ collapsed, defaultCollapsed = false, onCollapsedChange, collapsible = "icon", shortcut = true, id, children }) {
309
+ const [interno, setInterno] = React.useState(defaultCollapsed);
310
+ const controlado = collapsed !== undefined;
311
+ const valor = controlado ? !!collapsed : interno;
312
+ const gerado = React.useId();
313
+ const aviso = useRef(onCollapsedChange);
314
+ aviso.current = onCollapsedChange;
315
+ const setCollapsed = React.useCallback((v) => { if (!controlado)
316
+ setInterno(v); aviso.current?.(v); }, [controlado]);
317
+ const toggle = React.useCallback(() => setCollapsed(!valor), [setCollapsed, valor]);
318
+ const alternar = useRef(toggle);
319
+ alternar.current = toggle;
320
+ React.useEffect(() => {
321
+ if (!shortcut || typeof window === "undefined")
322
+ return;
323
+ const f = (e) => {
324
+ if (e.defaultPrevented || e.altKey || e.shiftKey || !(e.ctrlKey || e.metaKey) || e.key.toLowerCase() !== "b")
325
+ return;
326
+ if (e.target?.closest?.(ONDE_SE_DIGITA))
327
+ return;
328
+ e.preventDefault();
329
+ alternar.current();
330
+ };
331
+ window.addEventListener("keydown", f);
332
+ return () => window.removeEventListener("keydown", f);
333
+ }, [shortcut]);
334
+ const estado = React.useMemo(() => ({ collapsed: valor, setCollapsed, toggle, collapsible, id: id ?? "aurea-sidebar" + gerado.replace(/:/g, "") }), [valor, setCollapsed, toggle, collapsible, id, gerado]);
335
+ return _jsx(SidebarStateContext.Provider, { value: estado, children: children });
336
+ }
337
+ // O BOTÃO DE RECOLHER EM QUALQUER LUGAR (4-B). `icon`: o botão de ícone das quinze (o desenho de lateral, sem fundo) — ao lado
338
+ // do título (1 e 12) ou dentro da lateral, ao lado da marca (13 a 15). `item`: uma linha da lista, "Recolher o menu", no pé da
339
+ // lateral (a 11). Fora de um provedor, não desenha nada.
340
+ // O `variant` aqui é o jeito do botão ("icon" ou "item"); a aparência é sempre a do botão fantasma, como o das quinze.
341
+ function SidebarToggle({ variant = "icon", className, onClick, ...props }) {
342
+ const estado = React.useContext(SidebarStateContext);
343
+ const { collapsed } = React.useContext(SidebarContext);
344
+ const s = useAureaStrings();
345
+ if (!estado)
346
+ return null;
347
+ const rotulo = estado.collapsed ? s.sidebarExpand : s.sidebarCollapse;
348
+ const comum = { "aria-expanded": !estado.collapsed, "aria-controls": estado.id, onClick: (e) => { onClick?.(e); if (!e.defaultPrevented)
349
+ estado.toggle(); } };
350
+ if (variant === "item") {
351
+ // A linha é um botão do HTML: o que só o `IconButton` entende (tamanho, aparência, ocupado) não passa para ele.
352
+ const { size: _t, appearance: _a, tone: _o, loading: _l, leadingIcon: _li, trailingIcon: _ti, href: _h, fullWidth: _f, quiet: _q, grow: _g, render: _r, target: _tg, rel: _rl, download: _d, pressed: _p, share: _s, kbd: _k, ...html } = props;
353
+ const linha = _jsxs("button", { type: "button", ...html, ...comum, className: cx("sidebar-item", "sidebar-toggle-item", className), children: [_jsx(Icon, { name: "sidebar-simple" }), _jsx("span", { className: cx("sidebar-label", collapsed && "sr-only"), children: rotulo })] });
354
+ return collapsed ? _jsx(Tooltip, { content: rotulo, side: "right", children: linha }) : linha;
355
+ }
356
+ return _jsx(IconButton, { ...props, ...comum, className: cx("sidebar-collapse-trigger", className), icon: "sidebar-simple", label: rotulo });
357
+ }
358
+ // A TRILHA DAS SEÇÕES E O PAINEL (4-F e 4-G, 25/10/2026 — as 6 e 7 das quinze). Com `panel`, os itens do primeiro nível são
359
+ // SEÇÕES: a trilha mostra o ícone de cada uma, e a lista da seção mora num painel. `docked` (a 6): o painel fica ao lado da
360
+ // trilha, e recolher a lateral esconde só o painel. `overlay` (a 7): o painel abre POR CIMA, ao lado do ícone, numa janelinha
361
+ // que segura o foco e fecha com o Esc ou com um clique fora (a janelinha da Aurea, o motor dela). A referência faz a 6 com duas
362
+ // laterais lado a lado (a trilha que escolhe e a lista da escolhida); a 7 não tem nela — vem da bancada das quinze.
363
+ // A seção da página atual leva `aria-current="true"` (a "atual de um conjunto"), e não `page`: ela não é a página.
364
+ const contem = (it, id) => !!id && (it.id === id || !!it.items?.some(f => f !== "separator" && contem(f, id)));
365
+ function SidebarSectionButton({ sec, ctx, aberta, painelId, onEscolher, recolhida }) {
366
+ return _jsx(Tooltip, { content: sec.label, side: "right", children: _jsxs("button", { type: "button", className: "sidebar-item", "aria-current": contem(sec, ctx.current) ? "true" : undefined, "aria-expanded": !recolhida && aberta, "aria-controls": painelId, onClick: onEscolher, children: [sec.avatar ? _jsx(Avatar, { src: sec.avatar.src, fallback: sec.avatar.fallback, className: "sidebar-avatar" }) : sec.icon && _jsx(Icon, { name: sec.icon, weight: contem(sec, ctx.current) ? "fill" : undefined }), _jsx("span", { className: "sidebar-label sr-only", children: sec.label })] }) });
367
+ }
368
+ function SidebarSectionFlyout({ sec, ctx }) {
369
+ const portal = usePortalContainer();
370
+ const atual = contem(sec, ctx.current);
371
+ const tituloId = ctx.baseId + sec.id + "-titulo";
372
+ return _jsxs(BasePopover.Root, { children: [_jsx(Tooltip, { content: sec.label, side: "right", children: _jsxs(BasePopover.Trigger, { render: _jsx("button", { type: "button", className: "sidebar-item", "aria-current": atual ? "true" : undefined }), children: [sec.avatar ? _jsx(Avatar, { src: sec.avatar.src, fallback: sec.avatar.fallback, className: "sidebar-avatar" }) : sec.icon && _jsx(Icon, { name: sec.icon, weight: atual ? "fill" : undefined }), _jsx("span", { className: "sidebar-label sr-only", children: sec.label })] }) }), _jsx(BasePopover.Portal, { container: portal, children: _jsx(BasePopover.Positioner, { className: "positioner", side: "right", align: "start", sideOffset: 8, children: _jsxs(BasePopover.Popup, { className: "popover sidebar-flyout", "aria-labelledby": tituloId, children: [_jsx("p", { id: tituloId, className: "sidebar-panel-title", children: sec.label }), _jsx("nav", { className: "sidebar-nav", "aria-labelledby": tituloId, children: sidebarList(sec.items ?? [], { ...ctx, collapsed: false }) })] }) }) })] });
373
+ }
374
+ export function Sidebar({ items, current, collapsed, collapsible, indicator = "brand", panel, variant = "floating", placement = "left", scrollbar = "hover", label, header, footer, children, className, onClick, id, ...props }) {
275
375
  const s = useAureaStrings();
276
376
  const baseId = React.useId();
277
- const lista = items && items.length > 0 && _jsx("nav", { className: "sidebar-nav", "aria-label": label ?? s.sidebarLabel, children: sidebarList(items, { baseId, current, collapsed }) });
377
+ // Dentro de um provedor, a lateral segue o estado dele; a prop escrita ganha (quem escreveu as duas quis a prop).
378
+ const estado = React.useContext(SidebarStateContext);
379
+ const recolhida = collapsed ?? estado?.collapsed ?? false;
380
+ const forma = collapsible ?? estado?.collapsible ?? "icon";
381
+ const lista = items && items.length > 0 && _jsx("nav", { className: "sidebar-nav", "aria-label": label ?? s.sidebarLabel, children: sidebarList(items, { baseId, current, collapsed: recolhida }) });
278
382
  const partes = header != null || footer != null;
279
- const contexto = React.useMemo(() => ({ collapsed: !!collapsed, current }), [collapsed, current]);
280
- return _jsx("aside", { className: cx("sidebar", variant !== "floating" && `sidebar-${variant}`, collapsed && "sidebar-collapsed", placement === "right" && "sidebar-right", scrollbar === "visible" && "sidebar-scrollbar-visible", partes && "sidebar-with-parts", className), "data-placement": placement, onClick: e => { onClick?.(e); fecharGavetaAoEscolher(e); }, ...props, children: _jsx(SidebarContext.Provider, { value: contexto, children: partes
383
+ const contexto = React.useMemo(() => ({ collapsed: recolhida, current }), [recolhida, current]);
384
+ const secoes = panel ? (items ?? []).filter((it) => it !== "separator") : [];
385
+ const [escolhida, setEscolhida] = React.useState(() => secoes.find(x => contem(x, current))?.id ?? secoes[0]?.id);
386
+ const naTrilha = React.useMemo(() => ({ collapsed: true, current }), [current]);
387
+ if (panel) {
388
+ const secao = secoes.find(x => x.id === escolhida) ?? secoes[0];
389
+ const painelId = baseId.replace(/:/g, "") + "-painel";
390
+ const ctxTrilha = { baseId, current, collapsed: true };
391
+ const trilha = _jsx("nav", { className: "sidebar-nav", "aria-label": label ?? s.sidebarLabel, children: _jsx("ul", { className: "sidebar-list", children: secoes.map(sec => _jsx("li", { children: panel === "overlay"
392
+ ? _jsx(SidebarSectionFlyout, { sec: sec, ctx: ctxTrilha })
393
+ : _jsx(SidebarSectionButton, { sec: sec, ctx: ctxTrilha, aberta: sec.id === secao?.id, painelId: painelId, recolhida: recolhida, onEscolher: () => { setEscolhida(sec.id); if (recolhida)
394
+ estado?.setCollapsed(false); } }) }, sec.id)) }) });
395
+ return _jsxs("aside", { id: id ?? estado?.id, className: cx("sidebar", variant !== "floating" && `sidebar-${variant}`, `sidebar-panel-${panel}`, recolhida && "sidebar-collapsed", indicator !== "brand" && `sidebar-indicator-${indicator}`, placement === "right" && "sidebar-right", scrollbar === "visible" && "sidebar-scrollbar-visible", className), "data-placement": placement, onClick: e => { onClick?.(e); fecharGavetaAoEscolher(e); }, ...props, children: [_jsx("div", { className: "sidebar-rail-box", children: _jsxs(SidebarContext.Provider, { value: naTrilha, children: [header != null && _jsx("div", { className: "sidebar-header", children: header }), _jsxs("div", { className: "sidebar-body", children: [trilha, children] }), footer != null && _jsx("div", { className: "sidebar-footer", children: footer })] }) }), panel === "docked" && secao && _jsxs("div", { className: "sidebar-panel", id: painelId, hidden: recolhida, children: [_jsx("p", { className: "sidebar-panel-title", id: painelId + "-titulo", children: secao.label }), _jsx("nav", { className: "sidebar-nav", "aria-labelledby": painelId + "-titulo", children: sidebarList(secao.items ?? [], { baseId, current, collapsed: false }) })] })] });
396
+ }
397
+ return _jsx("aside", { id: id ?? estado?.id, className: cx("sidebar", variant !== "floating" && `sidebar-${variant}`, recolhida && "sidebar-collapsed", forma !== "icon" && `sidebar-collapse-${forma}`, indicator !== "brand" && `sidebar-indicator-${indicator}`, placement === "right" && "sidebar-right", scrollbar === "visible" && "sidebar-scrollbar-visible", partes && "sidebar-with-parts", className), "data-placement": placement, onClick: e => { onClick?.(e); fecharGavetaAoEscolher(e); }, ...props, children: _jsx(SidebarContext.Provider, { value: contexto, children: partes
281
398
  ? _jsxs(_Fragment, { children: [header != null && _jsx("div", { className: "sidebar-header", children: header }), _jsxs("div", { className: "sidebar-body", children: [lista, children] }), footer != null && _jsx("div", { className: "sidebar-footer", children: footer })] })
282
399
  : _jsxs(_Fragment, { children: [lista, children] }) }) });
283
400
  }
401
+ // As partes moram LOGO DEPOIS da lateral (as funções sobem no módulo): assim a leitura do check 46 alcança, a partir da
402
+ // `Sidebar`, os ícones fixos delas — o `sidebar-simple` do `Sidebar.Toggle` ficava sem ficha que o alcançasse.
403
+ Sidebar.Brand = SidebarBrand;
404
+ Sidebar.User = SidebarUser;
405
+ Sidebar.Nav = SidebarNav;
406
+ Sidebar.Show = SidebarShow;
407
+ Sidebar.Provider = SidebarProvider;
408
+ Sidebar.Toggle = SidebarToggle;
284
409
  /** A marca do app no topo da lateral: o `logo` (a letra, o desenho, a imagem), o nome e o subtítulo. `variant="tile"` (o
285
410
  * padrão, a 11 das quinze) põe o logo num quadrinho na cor primária; `plain` (da 8 à 10) é o desenho solto e o nome
286
411
  * grande. Recolhida, fica só o logo. */
287
- function SidebarBrand({ logo, name, description, variant = "tile", className, ...props }) {
412
+ // `action` (o bloco 2, 0.44.0): o botão de recolher ao lado da marca, dentro da lateral (as 13, 14 e 15 das quinze) — o mesmo
413
+ // lugar que a `Sidebar.User` dá ao "sair". Recolhida, ele desce para baixo do logo.
414
+ function SidebarBrand({ logo, name, description, variant = "tile", action, className, ...props }) {
288
415
  const { collapsed } = React.useContext(SidebarContext);
289
- return _jsxs("div", { className: cx("sidebar-brand", variant === "plain" && "sidebar-brand-plain", className), ...props, children: [_jsx("span", { className: "sidebar-brand-logo", "aria-hidden": "true", children: logo }), _jsxs("span", { className: cx("sidebar-brand-text", collapsed && "sr-only"), children: [_jsx("strong", { className: "sidebar-brand-name", children: name }), description != null && _jsx("span", { className: "sidebar-brand-description", children: description })] })] });
416
+ return _jsxs("div", { className: cx("sidebar-brand", variant === "plain" && "sidebar-brand-plain", action != null && "sidebar-brand-with-action", className), ...props, children: [_jsx("span", { className: "sidebar-brand-logo", "aria-hidden": "true", children: logo }), _jsxs("span", { className: cx("sidebar-brand-text", collapsed && "sr-only"), children: [_jsx("strong", { className: "sidebar-brand-name", children: name }), description != null && _jsx("span", { className: "sidebar-brand-description", children: description })] }), action] });
290
417
  }
291
418
  /** A pessoa no pé da lateral, numa caixinha: a foto (`avatar`), o nome, o papel e a ação (o sair). Recolhida, a foto e a ação, empilhadas. */
292
419
  function SidebarUser({ avatar, name, description, action, className, ...props }) {
@@ -304,10 +431,6 @@ function SidebarShow({ when, children }) {
304
431
  const { collapsed } = React.useContext(SidebarContext);
305
432
  return (when === "collapsed") === collapsed ? _jsx(_Fragment, { children: children }) : null;
306
433
  }
307
- Sidebar.Brand = SidebarBrand;
308
- Sidebar.User = SidebarUser;
309
- Sidebar.Nav = SidebarNav;
310
- Sidebar.Show = SidebarShow;
311
434
  const LEGADO = {
312
435
  flat: ["edge", "none"], surface: ["floating", "circle"], pill: ["floating", "pill"], dock: ["floating", "circle"]
313
436
  };
@@ -316,7 +439,7 @@ export function BottomNav({ items, current, variant = "floating", indicator = "n
316
439
  const [layout, marca0] = variant in LEGADO ? LEGADO[variant] : [variant, indicator];
317
440
  // O indicador explícito ganha do que o nome legado implica: quem escreveu os dois quis os dois.
318
441
  const ind = indicator !== "none" ? indicator : marca0;
319
- return _jsx("nav", { className: cx("bottom-nav", layout === "edge" && "bottom-nav-edge", layout !== "edge" && width === "content" && "bottom-nav-content", `bottom-nav-ind-${ind}`, className), "aria-label": label ?? s.bottomNavLabel, ...props, children: items.map(it => {
442
+ return _jsx("nav", { className: cx("bottom-nav", layout === "edge" && "bottom-nav-edge", layout !== "edge" && width === "content" && "bottom-nav-content", `bottom-nav-ind-${ind}`, className), "aria-label": label ?? s.bottomNavLabel, ...props, children: items.filter((it) => it !== "separator").map(it => {
320
443
  const ativo = it.id === current;
321
444
  // O CONTADOR PENDURA NO ÍCONE, e é por isso que existe esta caixa. Pendurado no ITEM (a
322
445
  // primeira versão), `50%` cai no meio do RÓTULO quando o item é linha — o Victor viu o número
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurea-uds/react",
3
- "version": "0.43.0",
3
+ "version": "0.44.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",