@aurea-uds/react 0.40.1 → 0.42.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 +17 -6
- package/dist/layout-client.js +21 -4
- package/dist/navigation-client.d.ts +39 -1
- package/dist/navigation-client.js +40 -2
- package/package.json +1 -1
package/dist/layout-client.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { type HTMLAttributes, type RefAttributes, type ReactNode } from "react";
|
|
1
|
+
import React, { type HTMLAttributes, type RefAttributes, type ReactNode } from "react";
|
|
2
2
|
import { type Orientation, type Responsive } from "./pure.js";
|
|
3
|
+
import { type IconButtonProps } from "./actions.js";
|
|
3
4
|
import { type HeaderVariant, type HeaderTab, type SidebarVariant, type SidebarScrollbar, type SidebarItem } from "./navigation.js";
|
|
4
|
-
|
|
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, layout, sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant, aside, asideLabel, asideVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
5
7
|
brand: ReactNode;
|
|
6
8
|
navigation?: ReactNode;
|
|
7
9
|
navItems?: SidebarItem[];
|
|
@@ -13,8 +15,13 @@ export declare function AppShell({ brand, navigation, navItems, currentNavId, na
|
|
|
13
15
|
sidebarVariant?: SidebarVariant;
|
|
14
16
|
/** O arranjo (lote T, 17/10/2026): `"app"` (o padrão, o de sempre) ou `"docs"`, o da documentação da referência — um
|
|
15
17
|
* bloco CENTRALIZADO de 1400 com a lateral de 220, o texto e o índice de 268 (de 1280 para cima), a barra de cima de 56
|
|
16
|
-
* com a linha das áreas (`topbarTabs`) embaixo. A lateral fica onde a variante dela mandar (`plain`: sem caixa).
|
|
17
|
-
|
|
18
|
+
* com a linha das áreas (`topbarTabs`) embaixo. A lateral fica onde a variante dela mandar (`plain`: sem caixa).
|
|
19
|
+
* `"sidebar"` (MNT-34, 0.42.0): a lateral até o topo, com a marca (`brand`) no topo dela; a barra de cima só existe se o
|
|
20
|
+
* app passar `topbar`, e fica só em cima do conteúdo. Com `sidebarVariant` (flutuante ou de canto), as quatro formas da
|
|
21
|
+
* bancada; sem `layout`, a de sempre. */
|
|
22
|
+
layout?: "app" | "docs" | "sidebar";
|
|
23
|
+
/** O pé fixo da lateral (4-C): a pessoa e o sair (`Sidebar.User`), a lista curta (`Sidebar.Nav`). Só o meio rola. */
|
|
24
|
+
sidebarFooter?: ReactNode;
|
|
18
25
|
/** A segunda linha da barra de cima: as áreas do site, com ícone (o `tabs` do `Header`). */
|
|
19
26
|
topbarTabs?: HeaderTab[];
|
|
20
27
|
/** O `id` da área atual da segunda linha. */
|
|
@@ -42,9 +49,13 @@ export declare function AppShell({ brand, navigation, navItems, currentNavId, na
|
|
|
42
49
|
/** AN-01: avisa cada troca — pelo botão, ou pela largura cruzando 1280. Guardar a preferência é do app. */
|
|
43
50
|
onSidebarCollapsedChange?: (collapsed: boolean) => void;
|
|
44
51
|
contentVariant?: "surface" | "plain";
|
|
45
|
-
}):
|
|
52
|
+
}): React.JSX.Element;
|
|
53
|
+
export declare namespace AppShell {
|
|
54
|
+
export { AppShellSidebarToggle as SidebarToggle };
|
|
55
|
+
}
|
|
46
56
|
export type SeparatorSpacing = "none" | "tight" | "normal" | "loose";
|
|
47
57
|
export declare function Separator({ orientation, spacing, className, ...props }: HTMLAttributes<HTMLHRElement> & RefAttributes<HTMLHRElement> & {
|
|
48
58
|
orientation?: Responsive<Orientation>;
|
|
49
59
|
spacing?: SeparatorSpacing;
|
|
50
|
-
}):
|
|
60
|
+
}): React.JSX.Element;
|
|
61
|
+
export {};
|
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";
|
|
@@ -155,9 +155,21 @@ function useLargura(query) {
|
|
|
155
155
|
return () => mq.removeEventListener?.("change", avisar);
|
|
156
156
|
}, () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(query).matches, () => false);
|
|
157
157
|
}
|
|
158
|
-
|
|
158
|
+
// O BOTÃO DE RECOLHER AO LADO DO TÍTULO (MNT-34, 0.42.0) — o desenho das quinze laterais que o Victor aprovou (o botão
|
|
159
|
+
// de ícone, sem fundo, com o desenho de lateral, a 12 do título da página; *"quero o botão de recolher conforme eu tinha
|
|
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
|
+
// 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
|
+
// 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 });
|
|
169
|
+
}
|
|
170
|
+
export function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant = "floating", topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, layout = "app", sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant = "surface", aside, asideLabel, asideVariant, children, className, ...props }) {
|
|
159
171
|
const s = useAureaStrings();
|
|
160
|
-
const docs = layout === "docs";
|
|
172
|
+
const docs = layout === "docs", lateral = layout === "sidebar";
|
|
161
173
|
useGavetaFechaNoDesktop(docs);
|
|
162
174
|
const controlado = sidebarCollapsed !== undefined;
|
|
163
175
|
// `null` = ninguém escolheu, e vale a largura.
|
|
@@ -196,8 +208,13 @@ export function AppShell({ brand, navigation, navItems, currentNavId, navLabel,
|
|
|
196
208
|
// 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
|
|
197
209
|
// vizinhos e fora da linha deles (medido a 375, sem toque; com toque, todos sobem para 44).
|
|
198
210
|
const botaoDaGaveta = _jsx(IconButton, { className: "nav-toggle", icon: "list", label: s.navigationToggle, popoverTarget: SHELL_NAV_ID, ...(docs ? { size: "sm" } : {}) });
|
|
199
|
-
return
|
|
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, ...(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
|
|
212
|
+
? _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 })
|
|
214
|
+
: _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
|
+
: _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 })] }) });
|
|
200
216
|
}
|
|
217
|
+
AppShell.SidebarToggle = AppShellSidebarToggle;
|
|
201
218
|
export function Separator({ orientation, spacing = "none", className, ...props }) {
|
|
202
219
|
const ancora = useRef(null);
|
|
203
220
|
const resolvida = useValorResponsivo(orientation, "horizontal", ancora);
|
|
@@ -98,7 +98,7 @@ export interface SidebarItem {
|
|
|
98
98
|
export type SidebarVariant = "floating" | "flush" | "plain";
|
|
99
99
|
export type SidebarScrollbar = "hover" | "visible";
|
|
100
100
|
export type SidebarPlacement = "left" | "right";
|
|
101
|
-
export declare function Sidebar({ items, current, collapsed, variant, placement, scrollbar, label, children, className, onClick, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
|
|
101
|
+
export declare function Sidebar({ items, current, collapsed, variant, placement, scrollbar, label, header, footer, children, className, onClick, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
|
|
102
102
|
items?: SidebarItem[];
|
|
103
103
|
current?: string;
|
|
104
104
|
collapsed?: boolean;
|
|
@@ -106,7 +106,44 @@ export declare function Sidebar({ items, current, collapsed, variant, placement,
|
|
|
106
106
|
placement?: SidebarPlacement;
|
|
107
107
|
scrollbar?: SidebarScrollbar;
|
|
108
108
|
label?: string;
|
|
109
|
+
/** O topo fixo (4-C): a marca do app (`Sidebar.Brand`), a busca. Não rola com a lista. */
|
|
110
|
+
header?: ReactNode;
|
|
111
|
+
/** 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. */
|
|
112
|
+
footer?: ReactNode;
|
|
109
113
|
}): React.JSX.Element;
|
|
114
|
+
export declare namespace Sidebar {
|
|
115
|
+
export { SidebarBrand as Brand };
|
|
116
|
+
export { SidebarUser as User };
|
|
117
|
+
export { SidebarNav as Nav };
|
|
118
|
+
export { SidebarShow as Show };
|
|
119
|
+
}
|
|
120
|
+
/** 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
|
+
* 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
|
+
* grande. Recolhida, fica só o logo. */
|
|
123
|
+
declare function SidebarBrand({ logo, name, description, variant, className, ...props }: Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
124
|
+
logo: ReactNode;
|
|
125
|
+
name: ReactNode;
|
|
126
|
+
description?: ReactNode;
|
|
127
|
+
variant?: "tile" | "plain";
|
|
128
|
+
}): React.JSX.Element;
|
|
129
|
+
/** 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
|
+
declare function SidebarUser({ avatar, name, description, action, className, ...props }: Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
131
|
+
avatar: ReactNode;
|
|
132
|
+
name: ReactNode;
|
|
133
|
+
description?: ReactNode;
|
|
134
|
+
action?: ReactNode;
|
|
135
|
+
}): React.JSX.Element;
|
|
136
|
+
/** 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
|
+
declare function SidebarNav({ items, current, label, className, ...props }: Omit<HTMLAttributes<HTMLElement>, "children"> & {
|
|
138
|
+
items: SidebarItem[];
|
|
139
|
+
current?: string;
|
|
140
|
+
label: string;
|
|
141
|
+
}): React.JSX.Element;
|
|
142
|
+
/** O que só aparece com a lateral aberta (`when="expanded"`: a busca, o cartão de destaque) ou só recolhida (`when="collapsed"`: o botão da lupa). */
|
|
143
|
+
declare function SidebarShow({ when, children }: {
|
|
144
|
+
when: "expanded" | "collapsed";
|
|
145
|
+
children?: ReactNode;
|
|
146
|
+
}): React.JSX.Element | null;
|
|
110
147
|
export type BottomNavVariant = "floating" | "edge";
|
|
111
148
|
export type BottomNavIndicator = "none" | "subtle" | "pill" | "circle" | "circle-raised" | "circle-bold" | "circle-outline" | "capsule" | "expand";
|
|
112
149
|
export type BottomNavWidth = "full" | "content";
|
|
@@ -177,3 +214,4 @@ export declare function CommandPaletteShell({ open, query, onQueryChange, onClos
|
|
|
177
214
|
label?: string;
|
|
178
215
|
children?: ReactNode;
|
|
179
216
|
}): React.JSX.Element;
|
|
217
|
+
export {};
|
|
@@ -265,11 +265,49 @@ function fecharGavetaAoEscolher(e) {
|
|
|
265
265
|
}
|
|
266
266
|
catch { /* motor sem popover: não há gaveta */ }
|
|
267
267
|
}
|
|
268
|
-
|
|
268
|
+
// O TOPO E O PÉ FIXOS (4-C, o item 107 — as quinze laterais aprovadas pelo Victor em 21/10/2026, e o PV-15 de um
|
|
269
|
+
// segundo app). `header` e `footer` ficam presos; só o meio (a lista e o que vier em `children`) rola. Sem eles, a
|
|
270
|
+
// lateral continua a caixa de sempre — o mesmo HTML. As partes que moram neles (`Sidebar.Brand`, `Sidebar.User`,
|
|
271
|
+
// `Sidebar.Nav`, `Sidebar.Show`) sabem se a lateral está recolhida por este contexto, interno: o estado de recolher
|
|
272
|
+
// com gancho, para o app, é o 4-B.
|
|
273
|
+
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 }) {
|
|
269
275
|
const s = useAureaStrings();
|
|
270
276
|
const baseId = React.useId();
|
|
271
|
-
|
|
277
|
+
const lista = items && items.length > 0 && _jsx("nav", { className: "sidebar-nav", "aria-label": label ?? s.sidebarLabel, children: sidebarList(items, { baseId, current, collapsed }) });
|
|
278
|
+
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
|
|
281
|
+
? _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
|
+
: _jsxs(_Fragment, { children: [lista, children] }) }) });
|
|
272
283
|
}
|
|
284
|
+
/** 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
|
+
* 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
|
+
* grande. Recolhida, fica só o logo. */
|
|
287
|
+
function SidebarBrand({ logo, name, description, variant = "tile", className, ...props }) {
|
|
288
|
+
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 })] })] });
|
|
290
|
+
}
|
|
291
|
+
/** 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
|
+
function SidebarUser({ avatar, name, description, action, className, ...props }) {
|
|
293
|
+
const { collapsed } = React.useContext(SidebarContext);
|
|
294
|
+
return _jsxs("div", { className: cx("sidebar-user", className), ...props, children: [avatar, _jsxs("span", { className: cx("sidebar-user-text", collapsed && "sr-only"), children: [_jsx("strong", { className: "sidebar-user-name", children: name }), description != null && _jsx("span", { className: "sidebar-user-description", children: description })] }), action] });
|
|
295
|
+
}
|
|
296
|
+
/** 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. */
|
|
297
|
+
function SidebarNav({ items, current, label, className, ...props }) {
|
|
298
|
+
const ctx = React.useContext(SidebarContext);
|
|
299
|
+
const baseId = React.useId();
|
|
300
|
+
return _jsx("nav", { className: cx("sidebar-nav", className), "aria-label": label, ...props, children: sidebarList(items, { baseId, current: current ?? ctx.current, collapsed: ctx.collapsed }) });
|
|
301
|
+
}
|
|
302
|
+
/** O que só aparece com a lateral aberta (`when="expanded"`: a busca, o cartão de destaque) ou só recolhida (`when="collapsed"`: o botão da lupa). */
|
|
303
|
+
function SidebarShow({ when, children }) {
|
|
304
|
+
const { collapsed } = React.useContext(SidebarContext);
|
|
305
|
+
return (when === "collapsed") === collapsed ? _jsx(_Fragment, { children: children }) : null;
|
|
306
|
+
}
|
|
307
|
+
Sidebar.Brand = SidebarBrand;
|
|
308
|
+
Sidebar.User = SidebarUser;
|
|
309
|
+
Sidebar.Nav = SidebarNav;
|
|
310
|
+
Sidebar.Show = SidebarShow;
|
|
273
311
|
const LEGADO = {
|
|
274
312
|
flat: ["edge", "none"], surface: ["floating", "circle"], pill: ["floating", "pill"], dock: ["floating", "circle"]
|
|
275
313
|
};
|