@aurea-uds/react 0.42.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.
- package/dist/code-client.d.ts +11 -2
- package/dist/code-client.js +24 -1
- package/dist/feedback-client.d.ts +1 -1
- package/dist/inputs-client.d.ts +4 -2
- package/dist/inputs-client.js +8 -2
- package/dist/inputs.d.ts +1 -0
- package/dist/layout-client.d.ts +22 -6
- package/dist/layout-client.js +30 -15
- package/dist/markup.d.ts +4 -1
- package/dist/markup.js +10 -6
- package/dist/navigation-client.d.ts +65 -6
- package/dist/navigation-client.js +159 -36
- package/package.json +1 -1
package/dist/code-client.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
/** Uma aba do `CodeBlock` em abas: o nome (o "npm"), o código e, se for outra, a língua dele. */
|
|
3
|
+
export interface CodeBlockTab {
|
|
4
|
+
label: string;
|
|
5
|
+
code: string;
|
|
6
|
+
language?: string;
|
|
7
|
+
}
|
|
2
8
|
/** Um pedaço de uma linha de código, com a classe da cor (`tok-keyword`, `tok-string`…) quando tem cor. */
|
|
3
9
|
export interface CodeToken {
|
|
4
10
|
text: string;
|
|
@@ -9,8 +15,8 @@ export type CodeLine = CodeToken[];
|
|
|
9
15
|
/** Quem colore: recebe o código e a língua e devolve as linhas, ou `null` quando não conhece a língua. O da Aurea é o
|
|
10
16
|
* `highlightCode` de `@aurea-uds/react/code-highlight`. */
|
|
11
17
|
export type CodeHighlighter = (code: string, language: string) => CodeLine[] | null;
|
|
12
|
-
export declare function CodeBlock({ children, language, copyable, preview, lineNumbers, highlight, className }: {
|
|
13
|
-
children
|
|
18
|
+
export declare function CodeBlock({ children, language, copyable, preview, lineNumbers, highlight, tabs, className }: {
|
|
19
|
+
children?: string;
|
|
14
20
|
language?: string;
|
|
15
21
|
copyable?: boolean;
|
|
16
22
|
/** A prévia viva do código: com ela, o bloco vira a caixa de exemplo, com as abas Prévia | Código. */
|
|
@@ -19,5 +25,8 @@ export declare function CodeBlock({ children, language, copyable, preview, lineN
|
|
|
19
25
|
lineNumbers?: boolean;
|
|
20
26
|
/** Colore o código. Passe o `highlightCode` de `@aurea-uds/react/code-highlight` (os analisadores são peer opcional). */
|
|
21
27
|
highlight?: CodeHighlighter;
|
|
28
|
+
/** As alternativas do mesmo passo, em abas (o comando de instalar em npm, pnpm, yarn e bun): a fileira em cima, dentro
|
|
29
|
+
* da caixa, e um código por aba. Com `tabs`, o `children` não é lido. */
|
|
30
|
+
tabs?: CodeBlockTab[];
|
|
22
31
|
className?: string;
|
|
23
32
|
}): React.JSX.Element;
|
package/dist/code-client.js
CHANGED
|
@@ -29,6 +29,26 @@ function CaixaDeExemplo({ preview, codigo, className }) {
|
|
|
29
29
|
const botao = (a, rotulo) => _jsx("button", { type: "button", role: "tab", id: `${id}-${a}`, ref: a === "preview" ? refPrevia : refCodigo, className: aba === a ? "active" : undefined, "aria-selected": aba === a, "aria-controls": `${id}-${a}-panel`, tabIndex: aba === a ? 0 : -1, onClick: () => setAba(a), onKeyDown: tecla, children: rotulo });
|
|
30
30
|
return _jsxs("div", { className: cx("demo code-preview", className), children: [_jsx("div", { className: "demo-tabs", children: _jsxs("div", { className: "segmented", role: "tablist", children: [botao("preview", s.codeBlockPreview), botao("code", s.codeBlockCode)] }) }), _jsx("div", { className: "demo-panel", "data-panel": "preview", role: "tabpanel", id: `${id}-preview-panel`, "aria-labelledby": `${id}-preview`, tabIndex: 0, hidden: aba !== "preview", children: preview }), _jsx("div", { className: "demo-panel demo-code", "data-panel": "code", role: "tabpanel", id: `${id}-code-panel`, "aria-labelledby": `${id}-code`, tabIndex: 0, hidden: aba !== "code", children: codigo })] });
|
|
31
31
|
}
|
|
32
|
+
// O CÓDIGO EM ABAS (bloco 1, o 3-A — 23/10/2026): as alternativas do MESMO passo, uma de cada vez — o comando de instalar
|
|
33
|
+
// em npm, pnpm, yarn e bun, como na documentação da referência (a fileira em cima, dentro da caixa do código). O estado é
|
|
34
|
+
// do React; os painéis levam `data-aurea-tabpanel` para o `aurea.js` do core trocar também na página que não acende (o
|
|
35
|
+
// site estático). A tecla para aqui (`stopPropagation`): com os dois na página, a seta andaria duas abas.
|
|
36
|
+
function CodigoEmAbas({ tabs, language, copyable, highlight, className }) {
|
|
37
|
+
const s = useAureaStrings();
|
|
38
|
+
const id = React.useId();
|
|
39
|
+
const [aba, setAba] = React.useState(0);
|
|
40
|
+
const refs = React.useRef([]);
|
|
41
|
+
const ir = (i) => { setAba(i); refs.current[i]?.focus(); };
|
|
42
|
+
const tecla = (e) => {
|
|
43
|
+
const n = tabs.length;
|
|
44
|
+
if (!["ArrowRight", "ArrowLeft", "Home", "End"].includes(e.key))
|
|
45
|
+
return;
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
ir(e.key === "Home" ? 0 : e.key === "End" ? n - 1 : e.key === "ArrowRight" ? (aba + 1) % n : (aba - 1 + n) % n);
|
|
49
|
+
};
|
|
50
|
+
return _jsxs("div", { className: cx("code-tabs", className), children: [_jsx("div", { className: "code-tabs-list", role: "tablist", "aria-label": s.tabsLabel, children: tabs.map((t, i) => _jsx("button", { type: "button", role: "tab", id: `${id}-${i}`, ref: el => { refs.current[i] = el; }, className: cx("code-tab", aba === i && "active"), "aria-selected": aba === i, "aria-controls": `${id}-${i}-panel`, tabIndex: aba === i ? 0 : -1, onClick: () => setAba(i), onKeyDown: tecla, children: t.label }, t.label)) }), tabs.map((t, i) => _jsx("div", { role: "tabpanel", id: `${id}-${i}-panel`, "aria-labelledby": `${id}-${i}`, "data-aurea-tabpanel": "", hidden: aba !== i, children: _jsx(CodeBlock, { language: t.language ?? language, copyable: copyable, highlight: highlight, children: t.code }) }, t.label))] });
|
|
51
|
+
}
|
|
32
52
|
// lineNumbers e highlight (lote V, 20/10/2026): as linhas viram um <span class="code-line"> cada, com o "\n" entre
|
|
33
53
|
// elas — o texto do bloco continua IGUAL ao código (copiar com o mouse traz o mesmo texto), e o número é desenhado pelo
|
|
34
54
|
// CSS, sem entrar no texto nem no leitor de tela. Sem as duas, a marcação é a de antes, sem mudar nada.
|
|
@@ -37,7 +57,9 @@ function linhasDoCodigo(codigo, language, highlight) {
|
|
|
37
57
|
const linhas = highlight?.(codigo, language) ?? codigo.split("\n").map(l => l === "" ? [] : [{ text: l }]);
|
|
38
58
|
return codigo.endsWith("\n") && linhas.length > 1 && linhas[linhas.length - 1].length === 0 ? linhas.slice(0, -1) : linhas;
|
|
39
59
|
}
|
|
40
|
-
export function CodeBlock({ children, language = "text", copyable, preview, lineNumbers, highlight, className }) {
|
|
60
|
+
export function CodeBlock({ children, language = "text", copyable, preview, lineNumbers, highlight, tabs, className }) {
|
|
61
|
+
if (tabs && tabs.length > 0)
|
|
62
|
+
return _jsx(CodigoEmAbas, { tabs: tabs, language: language, copyable: copyable, highlight: highlight, className: className });
|
|
41
63
|
if (preview !== undefined)
|
|
42
64
|
return _jsx(CaixaDeExemplo, { preview: preview, className: className, codigo: _jsx(CodeBlock, { language: language, copyable: copyable, lineNumbers: lineNumbers, highlight: highlight, children: children }) });
|
|
43
65
|
const s = useAureaStrings();
|
|
@@ -47,6 +69,7 @@ export function CodeBlock({ children, language = "text", copyable, preview, line
|
|
|
47
69
|
// demo do catálogo já tinha corrigido em 30/07/2026 no lado dele; aqui, na biblioteca, ele
|
|
48
70
|
// seguia aberto e só não aparecia porque nenhuma linha era comprida o bastante. Quem o achou
|
|
49
71
|
// foi o `catalog-sweep` em 10/08/2026, quando o bloco do I1 fez a linha de import crescer.
|
|
72
|
+
children ??= "";
|
|
50
73
|
const linhas = lineNumbers || highlight ? linhasDoCodigo(children, language, highlight) : null;
|
|
51
74
|
const colorido = linhas != null && highlight != null && linhas.some(l => l.some(p => p.className));
|
|
52
75
|
// Os algarismos da última linha: a coluna do número tem a largura deles (99 → 2, 100 → 3).
|
|
@@ -55,7 +55,7 @@ export declare function Spinner({ size, label, decorative, className, ...props }
|
|
|
55
55
|
decorative?: boolean;
|
|
56
56
|
}): React.JSX.Element;
|
|
57
57
|
export type DataStateValue = "loading" | "error" | "empty" | UniversalState;
|
|
58
|
-
export type DataStateProps = HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
58
|
+
export type DataStateProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & RefAttributes<HTMLDivElement> & {
|
|
59
59
|
state?: DataStateValue;
|
|
60
60
|
message?: ReactNode;
|
|
61
61
|
skeleton?: ReactNode;
|
package/dist/inputs-client.d.ts
CHANGED
|
@@ -310,15 +310,17 @@ export declare function OTPField({ length, value, defaultValue, onValueChange, m
|
|
|
310
310
|
/** `secondary`: o fundo neutro do `Input` secundário, para o campo dentro de um cartão. */
|
|
311
311
|
variant?: "primary" | "secondary";
|
|
312
312
|
}): React.JSX.Element;
|
|
313
|
-
export declare function SegmentedControl({ items, value, onChange, label, fullWidth }: {
|
|
313
|
+
export declare function SegmentedControl({ items, value, onChange, label, fullWidth, size }: {
|
|
314
314
|
items: Array<{
|
|
315
315
|
value: string;
|
|
316
316
|
label: ReactNode;
|
|
317
|
+
href?: string;
|
|
317
318
|
}>;
|
|
318
319
|
value: string;
|
|
319
|
-
onChange
|
|
320
|
+
onChange?: (v: string) => void;
|
|
320
321
|
label?: string;
|
|
321
322
|
fullWidth?: boolean;
|
|
323
|
+
size?: "sm" | "md";
|
|
322
324
|
}): React.JSX.Element;
|
|
323
325
|
export interface ComboboxOption {
|
|
324
326
|
value: string;
|
package/dist/inputs-client.js
CHANGED
|
@@ -763,9 +763,15 @@ export function OTPField({ length, value, defaultValue, onValueChange, mask, dis
|
|
|
763
763
|
// `fullWidth` (A5, 06/10/2026): o mesmo nome e o mesmo desenho do nativo — o controle ocupa a
|
|
764
764
|
// linha e cada segmento CRESCE a partir do rótulo, sem encolher abaixo dele. É como o grupo
|
|
765
765
|
// de botões alternáveis da referência ocupa a linha.
|
|
766
|
-
|
|
766
|
+
// NAVEGAÇÃO (bloco 1, o 5-A — 23/10/2026): com `href` em TODOS os itens, a cápsula é um <nav> de links — o atual leva
|
|
767
|
+
// `aria-current="page"` —, e não um grupo de escolha: ir para outra página é navegação, e o leitor de tela tem de ouvir
|
|
768
|
+
// "link", não "opção". É a chave Web | Native do site. `size="sm"`: a cápsula baixa da referência (abas de 24).
|
|
769
|
+
export function SegmentedControl({ items, value, onChange, label, fullWidth, size = "md" }) {
|
|
767
770
|
const s = useAureaStrings();
|
|
768
|
-
|
|
771
|
+
const classe = cx("segmented", fullWidth && "segmented-full", size === "sm" && "segmented-sm");
|
|
772
|
+
if (items.length > 0 && items.every(i => i.href != null))
|
|
773
|
+
return _jsx("nav", { className: classe, "aria-label": label ?? s.optionsLabel, children: items.map(i => _jsx("a", { href: i.href, className: i.value === value ? "active" : undefined, "aria-current": i.value === value ? "page" : undefined, children: i.label }, i.value)) });
|
|
774
|
+
return _jsx(BaseRadioGroup, { className: classe, "aria-label": label ?? s.optionsLabel, value: value, onValueChange: v => onChange?.(String(v)), children: items.map(i => _jsx(BaseRadio.Root, { value: i.value, className: i.value === value ? "active" : undefined, nativeButton: true, render: _jsx("button", { type: "button" }), children: i.label }, i.value)) });
|
|
769
775
|
}
|
|
770
776
|
const ehAgrupado = (items) => items != null && items.length > 0 && typeof items[0] === "object" && items[0] != null && "items" in items[0];
|
|
771
777
|
// UM renderizador e UMA lista para os dois combobox: duas cópias da mesma árvore é como a
|
package/dist/inputs.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export * from "./inputs-client.js";
|
|
2
2
|
export { Textarea, Checkbox, Radio, Switch, Range } from "./markup.js";
|
|
3
3
|
export { Label, InputGroup, InputGroupAddon, type AddonSide, type AddonLayout, type FieldSize, type FieldVariant } from "./markup.js";
|
|
4
|
+
export type { ColorSpace, ColorChannel } from "./color.js";
|
package/dist/layout-client.d.ts
CHANGED
|
@@ -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
|
|
5
|
-
declare function AppShellSidebarToggle(
|
|
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> & {
|
|
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?:
|
|
9
|
+
navItems?: SidebarEntry[];
|
|
10
10
|
currentNavId?: string;
|
|
11
11
|
navLabel?: string;
|
|
12
12
|
topbar?: ReactNode;
|
|
@@ -28,6 +28,8 @@ export declare function AppShell({ brand, navigation, navItems, currentNavId, na
|
|
|
28
28
|
topbarCurrentTab?: string;
|
|
29
29
|
/** O nome da segunda linha para o leitor de tela. Padrão: `"Sections"`. */
|
|
30
30
|
topbarTabsLabel?: string;
|
|
31
|
+
/** A ponta da linha das áreas (o `tabsEnd` do `Header`): a chave Web | Native da documentação. */
|
|
32
|
+
topbarTabsEnd?: ReactNode;
|
|
31
33
|
/** 0.32.0: a barra de rolagem da lateral da esquerda — o `scrollbar` da `Sidebar`. Padrão `hover` (clara, só com o
|
|
32
34
|
* ponteiro em cima); `visible` é a barra sempre à vista. */
|
|
33
35
|
sidebarScrollbar?: SidebarScrollbar;
|
|
@@ -42,8 +44,22 @@ export declare function AppShell({ brand, navigation, navItems, currentNavId, na
|
|
|
42
44
|
asideVariant?: SidebarVariant;
|
|
43
45
|
/** A lateral em trilha de ícones. Controlado: quem passa decide (e o `onSidebarCollapsedChange` avisa). */
|
|
44
46
|
sidebarCollapsed?: boolean;
|
|
45
|
-
/** 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.
|
|
46
|
-
|
|
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";
|
|
47
63
|
/** AN-01: começa recolhida, sem controlar. A escolha vale até a janela cruzar 1280. */
|
|
48
64
|
defaultSidebarCollapsed?: boolean;
|
|
49
65
|
/** AN-01: avisa cada troca — pelo botão, ou pela largura cruzando 1280. Guardar a preferência é do app. */
|
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
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
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 ?? (
|
|
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 (!
|
|
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
|
-
}, [
|
|
196
|
-
|
|
197
|
-
|
|
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",
|
|
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
|
}
|
package/dist/markup.d.ts
CHANGED
|
@@ -375,6 +375,9 @@ export interface HeaderProps extends HTMLAttributes<HTMLElement>, RefAttributes<
|
|
|
375
375
|
currentTab?: string;
|
|
376
376
|
/** O nome da segunda linha para o leitor de tela. Padrão: `"Sections"`. */
|
|
377
377
|
tabsLabel?: string;
|
|
378
|
+
/** O que fica na PONTA da segunda linha, do lado oposto das áreas (bloco 1, o 5-A — 23/10/2026): a chave Web | Native
|
|
379
|
+
* da documentação da referência. Some abaixo de 768, como lá. Sem `tabs`, não aparece. */
|
|
380
|
+
tabsEnd?: ReactNode;
|
|
378
381
|
}
|
|
379
382
|
/** Uma área da segunda linha do `Header`: o nome, o endereço e, se quiser, o ícone (o desenho que o app passa). */
|
|
380
383
|
export interface HeaderTab {
|
|
@@ -384,7 +387,7 @@ export interface HeaderTab {
|
|
|
384
387
|
icon?: ReactNode;
|
|
385
388
|
render?: SidebarItem["render"];
|
|
386
389
|
}
|
|
387
|
-
export declare function Header({ variant, divider, brand, items, current, actions, maxWidth, itemsJustify, size, blurred, menuActions, navLabel, menuLabel, menuId, tabs, currentTab, tabsLabel, children, className, ...props }: HeaderProps): React.JSX.Element;
|
|
390
|
+
export declare function Header({ variant, divider, brand, items, current, actions, maxWidth, itemsJustify, size, blurred, menuActions, navLabel, menuLabel, menuId, tabs, currentTab, tabsLabel, tabsEnd, children, className, ...props }: HeaderProps): React.JSX.Element;
|
|
388
391
|
/** @deprecated `Topbar` é o nome antigo do `Header` (07/10/2026). Continua funcionando, igual; use `Header`. */
|
|
389
392
|
export declare function Topbar(props: HeaderProps): React.JSX.Element;
|
|
390
393
|
export declare function Kbd({ children, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement>): React.JSX.Element;
|
package/dist/markup.js
CHANGED
|
@@ -206,13 +206,17 @@ function linksDoHeader(items, current) {
|
|
|
206
206
|
return _jsx("li", { children: it.render ? fundirRender(it.render, p, "a") : _jsx("a", { href: it.href, ...p }) }, it.id);
|
|
207
207
|
}) });
|
|
208
208
|
}
|
|
209
|
-
export function Header({ variant = "floating", divider, brand, items, current, actions, maxWidth, itemsJustify = "end", size = "md", blurred, menuActions, navLabel = "Main", menuLabel = "Menu", menuId = "aurea-header-menu", tabs, currentTab, tabsLabel = "Sections", children, className, ...props }) {
|
|
209
|
+
export function Header({ variant = "floating", divider, brand, items, current, actions, maxWidth, itemsJustify = "end", size = "md", blurred, menuActions, navLabel = "Main", menuLabel = "Menu", menuId = "aurea-header-menu", tabs, currentTab, tabsLabel = "Sections", tabsEnd, children, className, ...props }) {
|
|
210
210
|
const site = !!items && items.length > 0, comAbas = !!tabs && tabs.length > 0;
|
|
211
|
-
const miolo = _jsxs(_Fragment, { children: [brand != null && _jsx("div", { className: "brand", children: brand }), site && _jsx("nav", { className: "topbar-nav", "aria-label": navLabel, children: linksDoHeader(items, current) }), children, actions != null && _jsx("div", { className: "topbar-actions", children: actions }), site && _jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "btn btn-ghost btn-icon topbar-menu-toggle", popoverTarget: menuId, "aria-label": menuLabel, children: _jsx("span", { className: "topbar-menu-icon", "aria-hidden": "true" }) }), _jsxs("nav", { id: menuId, popover: "auto", className: "topbar-menu-panel", "aria-label": navLabel, children: [linksDoHeader(items, current), menuActions != null && _jsx("div", { className: "topbar-menu-actions", children: menuActions })] })] }), comAbas &&
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
211
|
+
const miolo = _jsxs(_Fragment, { children: [brand != null && _jsx("div", { className: "brand", children: brand }), site && _jsx("nav", { className: "topbar-nav", "aria-label": navLabel, children: linksDoHeader(items, current) }), children, actions != null && _jsx("div", { className: "topbar-actions", children: actions }), site && _jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "btn btn-ghost btn-icon topbar-menu-toggle", popoverTarget: menuId, "aria-label": menuLabel, children: _jsx("span", { className: "topbar-menu-icon", "aria-hidden": "true" }) }), _jsxs("nav", { id: menuId, popover: "auto", className: "topbar-menu-panel", "aria-label": navLabel, children: [linksDoHeader(items, current), menuActions != null && _jsx("div", { className: "topbar-menu-actions", children: menuActions })] })] }), comAbas && (() => {
|
|
212
|
+
const abas = _jsx("nav", { className: "topbar-tabs", "aria-label": tabsLabel, children: tabs.map(t => {
|
|
213
|
+
const p = { className: "topbar-tab", "aria-current": t.id === currentTab ? "page" : undefined,
|
|
214
|
+
children: _jsxs(_Fragment, { children: [t.icon != null && _jsx("span", { className: "topbar-tab-icon", "aria-hidden": "true", children: t.icon }), _jsx("span", { children: t.label })] }) };
|
|
215
|
+
return _jsx(React.Fragment, { children: t.render ? fundirRender(t.render, p, "a") : _jsx("a", { href: t.href, ...p }) }, t.id);
|
|
216
|
+
}) });
|
|
217
|
+
// Sem o encaixe, a marcação de sempre; com ele, a linha das áreas e a ponta numa mesma faixa.
|
|
218
|
+
return tabsEnd == null ? abas : _jsxs("div", { className: "topbar-tabs-row", children: [abas, _jsx("div", { className: "topbar-tabs-end", children: tabsEnd })] });
|
|
219
|
+
})()] });
|
|
216
220
|
return _jsx("header", { className: cx("topbar", `topbar-${variant}`, divider && variant === "flush" && "topbar-divider", site && "topbar-site", site && itemsJustify === "start" && "topbar-items-start", size === "sm" && "topbar-sm", blurred && variant === "flush" && "topbar-blurred", maxWidth && "topbar-contained", comAbas && "topbar-with-tabs", className), ...props, children: maxWidth ? _jsx("div", { className: cx("container", maxWidth !== "xl" && `container-${maxWidth}`, "topbar-inner"), children: miolo }) : miolo });
|
|
217
221
|
}
|
|
218
222
|
/** @deprecated `Topbar` é o nome antigo do `Header` (07/10/2026). Continua funcionando, igual; use `Header`. */
|
|
@@ -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?:
|
|
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
|
|
102
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
280
|
-
|
|
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
|
-
|
|
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
|