@aurea-uds/react 0.51.0 → 0.54.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.
@@ -433,7 +433,7 @@ export function CheckboxGroup({ label, description, error, value, defaultValue,
433
433
  });
434
434
  return _jsxs("div", { role: "group", "aria-labelledby": idRotulo, "aria-describedby": [idDescricao, idErro].filter(Boolean).join(" ") || undefined, className: cx("checkbox-group", className), ...props, children: [_jsx("span", { className: "label", id: idRotulo, children: _jsxs("span", { children: [label, required ? _jsx("span", { className: "label-required", "aria-hidden": "true", children: "*" }) : null] }) }), description && _jsx("span", { className: "field-description", id: idDescricao, children: description }), caixas, error && _jsx("span", { className: "field-error", id: idErro, children: error })] });
435
435
  }
436
- export function RadioGroup({ label, labelHidden, description, error, value, defaultValue, onValueChange, name, disabled, invalid, orientation = "vertical", required, children, className, ...props }) {
436
+ export function RadioGroup({ label, labelHidden, description, error, value, defaultValue, onValueChange, name, disabled, invalid, orientation = "vertical", required, variant = "list", indicatorPlacement = "start", children, className, ...props }) {
437
437
  const auto = React.useId();
438
438
  const [proprio, setProprio] = React.useState(defaultValue);
439
439
  const escolhido = value ?? proprio;
@@ -456,7 +456,7 @@ export function RadioGroup({ label, labelHidden, description, error, value, defa
456
456
  onValueChange?.(v);
457
457
  } });
458
458
  });
459
- return _jsxs("div", { role: "radiogroup", "aria-labelledby": idRotulo, "aria-describedby": [idDescricao, idErro].filter(Boolean).join(" ") || undefined, "aria-orientation": orientation, "aria-required": required || undefined, "aria-invalid": error || invalid ? true : undefined, className: cx("radio-group", orientation === "horizontal" && "radio-group-horizontal", labelHidden && "radio-group-bare", className), ...props, children: [_jsx("span", { className: cx("label", labelHidden && "sr-only"), id: idRotulo, children: _jsxs("span", { children: [label, required ? _jsx("span", { className: "label-required", "aria-hidden": "true", children: "*" }) : null] }) }), description && _jsx("span", { className: "field-description", id: idDescricao, children: description }), orientation === "horizontal" ? _jsx("div", { className: "radio-group-items", children: opcoes }) : opcoes, error && _jsx("span", { className: "field-error", id: idErro, children: error })] });
459
+ return _jsxs("div", { role: "radiogroup", "aria-labelledby": idRotulo, "aria-describedby": [idDescricao, idErro].filter(Boolean).join(" ") || undefined, "aria-orientation": orientation, "aria-required": required || undefined, "aria-invalid": error || invalid ? true : undefined, className: cx("radio-group", orientation === "horizontal" && "radio-group-horizontal", labelHidden && "radio-group-bare", variant === "card" && indicatorPlacement === "none" && "radio-group-indicator-none", className), ...props, children: [_jsx("span", { className: cx("label", labelHidden && "sr-only"), id: idRotulo, children: _jsxs("span", { children: [label, required ? _jsx("span", { className: "label-required", "aria-hidden": "true", children: "*" }) : null] }) }), description && _jsx("span", { className: "field-description", id: idDescricao, children: description }), variant === "card" ? _jsx("div", { className: "radio-group-cards", children: opcoes }) : orientation === "horizontal" ? _jsx("div", { className: "radio-group-items", children: opcoes }) : opcoes, error && _jsx("span", { className: "field-error", id: idErro, children: error })] });
460
460
  }
461
461
  /** A opção do grupo: o `Radio`, como o `RadioGroup.Item` do nativo. */
462
462
  RadioGroup.Item = Radio;
@@ -730,12 +730,15 @@ export function OTPField({ length, value, defaultValue, onValueChange, mask, dis
730
730
  const s = useAureaStrings();
731
731
  return _jsx(BaseOTPField.Root, { id: id, length: length, value: value, defaultValue: defaultValue, onValueChange: soOValor(onValueChange), mask: mask, disabled: disabled, required: required, role: "group", "aria-label": label, className: cx("otp-field", className), children: Array.from({ length }, (_, i) => _jsxs(React.Fragment, { children: [_jsx(BaseOTPField.Input, { render: _jsx("input", { "aria-label": `${s.otpDigit} ${i + 1}` }), className: cx("input otp-slot", variant === "secondary" && "input-secondary") }), groupSize && groupSize > 0 && (i + 1) % groupSize === 0 && i < length - 1 ? _jsx(BaseOTPField.Separator, { className: "otp-separator" }) : null] }, i)) });
732
732
  }
733
- export function SegmentedControl({ items, value, onChange, label, fullWidth, size = "md", selectedStyle }) {
733
+ // O SITE B (aprovado pela bancada em 01/11/2026, os itens 3 e 8): `items[].icon` (o escolhido troca sozinho para a forma
734
+ // cheia), `size="2xl"` (segmento de 48), `wrap` (quebra linha, o trilho com canto 22) e `orientation="vertical"` (em pé).
735
+ export function SegmentedControl({ items, value, onChange, label, fullWidth, size = "md", selectedStyle, wrap, orientation = "horizontal" }) {
734
736
  const s = useAureaStrings();
735
- const classe = cx("segmented", fullWidth && "segmented-full", size === "sm" && "segmented-sm");
737
+ const classe = cx("segmented", fullWidth && "segmented-full", size === "sm" && "segmented-sm", size === "lg" && "segmented-lg", size === "xl" && "segmented-xl", size === "2xl" && "segmented-2xl", wrap && orientation !== "vertical" && "segmented-wrap", orientation === "vertical" && "segmented-vertical");
738
+ const miolo = (i) => i.icon ? _jsxs(_Fragment, { children: [_jsx(Icon, { name: i.icon, weight: i.value === value ? "fill" : "regular" }), i.label] }) : i.label;
736
739
  if (items.length > 0 && items.every(i => i.href != null))
737
- return _jsx("nav", { className: classe, "data-segment-style": selectedStyle, "aria-label": label ?? s.optionsLabel, children: items.map(i => _jsx("a", { href: i.href, className: i.value === value ? "active" : undefined, "aria-current": i.value === value ? "page" : undefined, children: i.label }, i.value)) });
738
- return _jsx(BaseRadioGroup, { className: classe, "data-segment-style": selectedStyle, "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)) });
740
+ return _jsx("nav", { className: classe, "data-segment-style": selectedStyle, "aria-label": label ?? s.optionsLabel, children: items.map(i => _jsx("a", { href: i.href, className: i.value === value ? "active" : undefined, "aria-current": i.value === value ? "page" : undefined, children: miolo(i) }, i.value)) });
741
+ return _jsx(BaseRadioGroup, { className: classe, "data-segment-style": selectedStyle, "aria-label": label ?? s.optionsLabel, "aria-orientation": orientation === "vertical" ? "vertical" : undefined, value: value, onValueChange: v => onChange?.(String(v)), children: items.map(i => _jsx(BaseRadio.Root, { value: i.value, className: i.value === value ? "active" : undefined, nativeButton: true, render: _jsx("button", { type: "button" }), children: miolo(i) }, i.value)) });
739
742
  }
740
743
  const ehAgrupado = (items) => items != null && items.length > 0 && typeof items[0] === "object" && items[0] != null && "items" in items[0];
741
744
  // UM renderizador e UMA lista para os dois combobox: duas cópias da mesma árvore é como a
@@ -3,14 +3,14 @@ import { type Orientation, type Responsive } from "./pure.js";
3
3
  import { type IconButtonProps } from "./actions.js";
4
4
  import { type HeaderVariant, type HeaderTab, type SidebarVariant, type SidebarScrollbar, type SidebarEntry, type SidebarCollapsible, type SidebarIndicator } from "./navigation.js";
5
5
  declare function AppShellSidebarToggle(props: Omit<IconButtonProps, "icon" | "label" | "onClick" | "variant">): React.JSX.Element;
6
- export declare function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant, topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, topbarTabsEnd, topbarActions, layout, sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, sidebarToggle, sidebarShortcut, sidebarIndicator, sidebarPanel, sidebarContrast, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant, aside, asideLabel, asideVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
6
+ export declare function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant, topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, topbarTabsEnd, topbarActions, topbarBlurred, layout, sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, sidebarToggle, sidebarShortcut, sidebarIndicator, sidebarPanel, sidebarContrast, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant, aside, asideLabel, asideVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
7
7
  brand: ReactNode;
8
8
  navigation?: ReactNode;
9
9
  navItems?: SidebarEntry[];
10
10
  currentNavId?: string;
11
11
  navLabel?: string;
12
12
  topbar?: ReactNode;
13
- topbarVariant?: Exclude<HeaderVariant, "pill">;
13
+ topbarVariant?: HeaderVariant;
14
14
  topbarDivider?: boolean;
15
15
  sidebarVariant?: SidebarVariant;
16
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
@@ -34,6 +34,9 @@ export declare function AppShell({ brand, navigation, navItems, currentNavId, na
34
34
  * conta, o sino. É o `actions` do `Header`. No `layout="sidebar"` a barra do conteúdo passa a existir também quando o app
35
35
  * passa só isto; no `"docs"`, o botão da gaveta continua o último, depois delas. */
36
36
  topbarActions?: ReactNode;
37
+ /** O site B (30/10/2026): o fundo da barra de cima que EMBAÇA o que passa por baixo — o `blurred` do `Header`, na
38
+ * `flush` e na `pill`. */
39
+ topbarBlurred?: boolean;
37
40
  /** 0.32.0: a barra de rolagem da lateral da esquerda — o `scrollbar` da `Sidebar`. Padrão `hover` (clara, só com o
38
41
  * ponteiro em cima); `visible` é a barra sempre à vista. */
39
42
  sidebarScrollbar?: SidebarScrollbar;
@@ -59,7 +59,8 @@ function focoDaGaveta(e) {
59
59
  // API pública intacta: as props seguem brand/navigation/topbar. O que mudou é ONDE a
60
60
  // marca sai — no topo, não na lateral. `topbarVariant` escolhe a pele do topo; o shell
61
61
  // precisa saber porque a lateral se encaixa abaixo dele (o `flush` não tem folga em
62
- // cima, então ela sobe um --space-4). `pill` é cabeçalho de site — não é pra shell.
62
+ // cima, então ela sobe um --space-4). ~~`pill` é cabeçalho de site — não é pra shell.~~ Desde o site B (30/10/2026), a
63
+ // `pill` entra no shell: a cápsula da largura do bloco, que flutua a --space-4 do alto (o `maxWidth` do `Header`).
63
64
  // A lateral RECOLHE em tela estreita: o <aside> é um popover nativo e o botão é o invoker. O
64
65
  // navegador entrega Escape, clique fora e o `aria-expanded` no disparador. Era o achado A8: em
65
66
  // 375px o `h1` da página começava 4,6 telas abaixo, depois dos 65 itens da navegação.
@@ -166,7 +167,7 @@ function ProvedorDaLateral({ ligado, children, ...p }) {
166
167
  return ligado ? _jsx(Sidebar.Provider, { id: SHELL_NAV_ID, ...p, children: children }) : _jsx(_Fragment, { children: children });
167
168
  }
168
169
  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, topbarActions, layout = "app", sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, sidebarToggle = "edge", sidebarShortcut = true, sidebarIndicator, sidebarPanel, sidebarContrast, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant = "surface", aside, asideLabel, asideVariant, children, className, ...props }) {
170
+ export function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant = "floating", topbarDivider, topbarTabs, topbarCurrentTab, topbarTabsLabel, topbarTabsEnd, topbarActions, topbarBlurred, layout = "app", sidebarVariant, sidebarScrollbar, sidebarFooter, sidebarCollapsed, sidebarCollapsible, sidebarToggle = "edge", sidebarShortcut = true, sidebarIndicator, sidebarPanel, sidebarContrast, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant = "surface", aside, asideLabel, asideVariant, children, className, ...props }) {
170
171
  const s = useAureaStrings();
171
172
  const docs = layout === "docs", lateral = layout === "sidebar";
172
173
  useGavetaFechaNoDesktop(docs);
@@ -223,7 +224,7 @@ export function AppShell({ brand, navigation, navItems, currentNavId, navLabel,
223
224
  // 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
224
225
  // vizinhos e fora da linha deles (medido a 375, sem toque; com toque, todos sobem para 44).
225
226
  const botaoDaGaveta = _jsx(IconButton, { className: "nav-toggle", icon: "list", label: s.navigationToggle, popoverTarget: SHELL_NAV_ID, ...(docs ? { size: "sm" } : {}) });
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] }), actions: topbarActions != null ? _jsxs(_Fragment, { children: [topbarActions, docs && botaoDaGaveta] }) : undefined, children: [topbar, docs && topbarActions == null && botaoDaGaveta] }), recolhe && !lateral && sidebarToggle !== "none" && _jsx("div", { className: "sidebar-toggle-slot", children: _jsx(Tooltip, { content: rotulo, side: "right", children: _jsx(IconButton, { className: "sidebar-toggle", size: "xs", icon: paraOComeco === direita ? "caret-right" : "caret-left", label: rotulo, "aria-expanded": !efetiva, "aria-controls": SHELL_NAV_ID, onClick: alternar }) }) }), _jsx(Sidebar, { id: SHELL_NAV_ID, popover: "auto", variant: sidebarVariant, scrollbar: sidebarScrollbar, collapsed: efetiva, collapsible: forma, indicator: sidebarIndicator, panel: sidebarPanel, contrast: sidebarContrast, items: navItems, current: currentNavId, label: navLabel, onToggle: focoDaGaveta, header: lateral ? brand : undefined, footer: sidebarFooter, children: navigation }), docs && aside != null && _jsx("div", { className: "docs-toc-bar", children: _jsxs("button", { type: "button", className: "docs-toc-toggle", popoverTarget: SHELL_TOC_ID, children: [_jsx(Icon, { name: "list-bullets" }), _jsx("span", { className: "docs-toc-current", "data-toc-current": "", children: asideLabel ?? s.tocLabel }), _jsx(Icon, { name: "caret-down" })] }) }), lateral
227
+ return _jsx("div", { className: cx("app-shell", layout === "docs" && "app-shell-docs", lateral && "app-shell-lateral", !lateral && topbarVariant === "flush" && "app-shell-flush", !lateral && topbarVariant === "pill" && "app-shell-pill", recolhe && "app-shell-collapsible", aside != null && "app-shell-with-aside", className), ...props, children: _jsxs(ProvedorDaLateral, { ligado: recolhe, collapsed: efetiva, onCollapsedChange: definir, collapsible: forma, shortcut: sidebarShortcut, children: [_jsx("a", { className: "skip-link", href: `#${SHELL_MAIN_ID}`, children: s.skipToContent }), !lateral && _jsxs(Header, { variant: topbarVariant, divider: topbarDivider, tabs: topbarTabs, currentTab: topbarCurrentTab, tabsLabel: topbarTabsLabel, tabsEnd: topbarTabsEnd, ...(docs ? { maxWidth: "docs", ...(topbarVariant === "pill" ? {} : { size: "sm" }) } : topbarVariant === "pill" ? { maxWidth: "full" } : {}), blurred: topbarBlurred, brand: docs ? brand : _jsxs(_Fragment, { children: [botaoDaGaveta, brand] }), actions: topbarActions != null ? _jsxs(_Fragment, { children: [topbarActions, docs && botaoDaGaveta] }) : undefined, children: [topbar, docs && topbarActions == null && botaoDaGaveta] }), recolhe && !lateral && sidebarToggle !== "none" && _jsx("div", { className: "sidebar-toggle-slot", children: _jsx(Tooltip, { content: rotulo, side: "right", children: _jsx(IconButton, { className: "sidebar-toggle", size: "xs", icon: paraOComeco === direita ? "caret-right" : "caret-left", label: rotulo, "aria-expanded": !efetiva, "aria-controls": SHELL_NAV_ID, onClick: alternar }) }) }), _jsx(Sidebar, { id: SHELL_NAV_ID, popover: "auto", variant: sidebarVariant, scrollbar: sidebarScrollbar, collapsed: efetiva, collapsible: forma, indicator: sidebarIndicator, panel: sidebarPanel, contrast: sidebarContrast, items: navItems, current: currentNavId, label: navLabel, onToggle: focoDaGaveta, header: lateral ? brand : undefined, footer: sidebarFooter, children: navigation }), docs && aside != null && _jsx("div", { className: "docs-toc-bar", children: _jsxs("button", { type: "button", className: "docs-toc-toggle", popoverTarget: SHELL_TOC_ID, children: [_jsx(Icon, { name: "list-bullets" }), _jsx("span", { className: "docs-toc-current", "data-toc-current": "", children: asideLabel ?? s.tocLabel }), _jsx(Icon, { name: "caret-down" })] }) }), lateral
227
228
  ? _jsxs("div", { className: "app-shell-column", children: [topbar != null || topbarActions != null
228
229
  ? _jsx(Header, { variant: "flush", size: "sm", divider: topbarDivider, brand: _jsxs(_Fragment, { children: [botaoDaGaveta, sidebarToggle !== "none" && _jsx(AppShellSidebarToggle, {})] }), actions: topbarActions, children: topbar })
229
230
  : _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 })] })
package/dist/markup.d.ts CHANGED
@@ -13,6 +13,8 @@ type CardBase = HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> &
13
13
  padding?: "normal" | "none";
14
14
  orientation?: "vertical" | "horizontal";
15
15
  accent?: CardAccent;
16
+ lift?: boolean;
17
+ fill?: "brand";
16
18
  };
17
19
  export type CardProps = CardBase & ({
18
20
  variant?: "base" | "raised" | "inset" | "outline" | "selected" | "danger" | "contrast";
@@ -21,7 +23,7 @@ export type CardProps = CardBase & ({
21
23
  variant: "interactive";
22
24
  render: ReactElement;
23
25
  });
24
- export declare function Card({ variant, padding, orientation, accent, className, render, ...props }: CardProps): ReactElement<unknown, string | React.JSXElementConstructor<any>>;
26
+ export declare function Card({ variant, padding, orientation, accent, lift, fill, className, render, ...props }: CardProps): ReactElement<unknown, string | React.JSXElementConstructor<any>>;
25
27
  export declare namespace Card {
26
28
  export { CardMedia as Media };
27
29
  export { CardHeader as Header };
@@ -174,7 +176,13 @@ export interface SectionProps extends Omit<HTMLAttributes<HTMLElement>, "title">
174
176
  export declare function Section({ surface, spacing, theme, variant, brand, links, legal, layout, maxWidth, navLabel, title, titleAs: Titulo, eyebrow, description, actions, media, align, children, className, ...props }: SectionProps): React.JSX.Element;
175
177
  export type KPIDirection = "up" | "down" | "flat";
176
178
  export type KPITone = "success" | "danger" | "neutral";
177
- export type KPIVariant = "card" | "plain";
179
+ export type KPIVariant = "card" | "plain" | "brand";
180
+ /** Uma barra do `KPI` (o site B): o nome curto ("Jun"), o valor dito na leitura ("$48.2k") e o número que dá a altura. */
181
+ export interface KPIBar {
182
+ label: string;
183
+ value: ReactNode;
184
+ amount: number;
185
+ }
178
186
  export interface KPIProps extends HTMLAttributes<HTMLDivElement>, RefAttributes<HTMLDivElement> {
179
187
  label: ReactNode;
180
188
  value: ReactNode;
@@ -186,10 +194,16 @@ export interface KPIProps extends HTMLAttributes<HTMLDivElement>, RefAttributes<
186
194
  tone?: KPITone;
187
195
  /** A palavra que o leitor de tela ouve antes da tendência. Padrão em inglês: "Up", "Down", "No change". */
188
196
  directionLabel?: string;
189
- /** `plain` tira a caixa: o número dentro de um cartão que já existe. */
197
+ /** `plain` tira a caixa: o número dentro de um cartão que já existe. `brand` (o site B, 0.54.0) é o cartão AMARELO, com
198
+ * a tinta e a sombra média. */
190
199
  variant?: KPIVariant;
200
+ /** As barras embaixo do número (o site B, 0.54.0): cada uma é um botão de opção nativo; a escolhida fica branca no
201
+ * `brand` (na cor do texto, fora dele) e a leitura diz o nome e o valor dela. */
202
+ bars?: KPIBar[];
203
+ /** A barra que começa escolhida (o índice). Padrão: a última. */
204
+ defaultBar?: number;
191
205
  }
192
- export declare function KPI({ label, value, trend, direction, tone, directionLabel, variant, className, ...props }: KPIProps): React.JSX.Element;
206
+ export declare function KPI({ label, value, trend, direction, tone, directionLabel, variant, bars, defaultBar, className, ...props }: KPIProps): React.JSX.Element;
193
207
  export declare function DataList({ items }: {
194
208
  items: Array<{
195
209
  term: ReactNode;
@@ -346,7 +360,8 @@ export interface HeaderProps extends HTMLAttributes<HTMLElement>, RefAttributes<
346
360
  current?: string;
347
361
  /** O que fica do lado direito: busca, botão de ação, conta. Fica na barra também no celular. */
348
362
  actions?: ReactNode;
349
- /** Até onde o miolo da barra cresce, pela escala do `Container` (`sm` 640 … `2xl` 1536, `full`). */
363
+ /** Até onde o miolo da barra cresce, pela escala do `Container` (`sm` 640 … `2xl` 1536, `full`). Na `pill` (o site B,
364
+ * 30/10/2026), a cápsula passa a ser o miolo, da largura do `Container`, e não do conteúdo. */
350
365
  maxWidth?: ContainerSize;
351
366
  /**
352
367
  * Onde ficam os links (14/10/2026): `"end"` (o padrão) logo antes das ações, na outra ponta da marca; `"start"`
@@ -360,8 +375,9 @@ export interface HeaderProps extends HTMLAttributes<HTMLElement>, RefAttributes<
360
375
  */
361
376
  size?: "md" | "sm";
362
377
  /**
363
- * Só na `flush` (15/10/2026): o fundo transparente que EMBAÇA o que passa por baixo, como o topo da página inicial
364
- * da referência. Quem pede menos transparência no sistema, ou o navegador sem desfoque, recebe o fundo cheio.
378
+ * Na `flush` (15/10/2026) e na `pill` (o site B, 30/10/2026): o fundo transparente que EMBAÇA o que passa por baixo,
379
+ * como o topo da página inicial da referência. Quem pede menos transparência no sistema, ou o navegador sem desfoque,
380
+ * recebe o fundo cheio.
365
381
  */
366
382
  blurred?: boolean;
367
383
  /** O que entra no MENU DO CELULAR, embaixo dos links (15/10/2026): o GitHub, a conta. Na barra larga não aparece. */
@@ -403,11 +419,13 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
403
419
  variant?: FieldVariant;
404
420
  }
405
421
  export declare const Textarea: React.ForwardRefExoticComponent<Omit<TextareaProps, "ref"> & RefAttributes<HTMLTextAreaElement>>;
406
- export declare function Checkbox({ label, labelHidden, description, size, className, ...props }: Omit<InputHTMLAttributes<HTMLInputElement>, "size"> & RefAttributes<HTMLInputElement> & {
422
+ export declare function Checkbox({ label, labelHidden, description, size, variant, tone, className, ...props }: Omit<InputHTMLAttributes<HTMLInputElement>, "size"> & RefAttributes<HTMLInputElement> & {
407
423
  label: ReactNode;
408
424
  labelHidden?: boolean;
409
425
  description?: ReactNode;
410
426
  size?: Responsive<FieldSize>;
427
+ variant?: "default" | "pill";
428
+ tone?: "success";
411
429
  }): React.JSX.Element;
412
430
  export declare function Radio({ label, labelHidden, description, size, className, ...props }: Omit<InputHTMLAttributes<HTMLInputElement>, "size"> & RefAttributes<HTMLInputElement> & {
413
431
  label: ReactNode;
package/dist/markup.js CHANGED
@@ -39,8 +39,8 @@ import React, { forwardRef } from "react";
39
39
  import { cx, fundirRender, peleDoEixo } from "./pure.js";
40
40
  // As contas de cor são funções puras, sem estado e sem navegador (ADR-0069): o `ColorSwatch` usa a do contraste.
41
41
  import { contrastingInk, hsbToRgb, parseColor } from "./color.js";
42
- export function Card({ variant = "base", padding = "normal", orientation = "vertical", accent, className, render, ...props }) {
43
- return fundirRender(render, { className: cx("card", variant !== "base" && `card-${variant}`, accent && `card-accent card-accent-${accent}`, padding === "none" && "card-flush", orientation === "horizontal" && "card-horizontal", className), ...(variant === "contrast" ? { "data-theme": "dark" } : null), ...props });
42
+ export function Card({ variant = "base", padding = "normal", orientation = "vertical", accent, lift, fill, className, render, ...props }) {
43
+ return fundirRender(render, { className: cx("card", variant !== "base" && `card-${variant}`, lift && variant === "interactive" && "card-lift", accent && `card-accent card-accent-${accent}`, fill === "brand" && "card-fill-brand", padding === "none" && "card-flush", orientation === "horizontal" && "card-horizontal", className), ...(variant === "contrast" ? { "data-theme": "dark" } : null), ...props });
44
44
  }
45
45
  /** A mídia do cartão — a primeira das partes da especificação do `Card` (A-14). No vertical,
46
46
  * primeira filha, ela SANGRA até a borda de cima e dos lados; no horizontal, fica à esquerda com a
@@ -119,11 +119,19 @@ export function Section({ surface = "background", spacing = "md", theme, variant
119
119
  }
120
120
  const TOM_DA_DIRECAO = { up: "success", down: "danger", flat: "neutral" };
121
121
  const PALAVRA_DA_DIRECAO = { up: "Up", down: "Down", flat: "No change" };
122
- export function KPI({ label, value, trend, direction, tone, directionLabel, variant = "card", className, ...props }) {
122
+ export function KPI({ label, value, trend, direction, tone, directionLabel, variant = "card", bars, defaultBar, className, ...props }) {
123
123
  const tom = direction ? (tone ?? TOM_DA_DIRECAO[direction]) : undefined;
124
124
  const miolo = _jsxs(_Fragment, { children: [_jsx("span", { className: "muted", children: label }), _jsx("strong", { children: value }), (trend || trend === 0 || direction) && _jsxs("small", { className: direction ? cx("kpi-trend", `kpi-trend-${direction}`, `kpi-tone-${tom}`) : undefined, children: [direction && _jsx("span", { className: "kpi-trend-icon", "aria-hidden": "true" }), direction && _jsx("span", { className: "sr-only", children: directionLabel ?? PALAVRA_DA_DIRECAO[direction] }), trend] })] });
125
- return variant === "plain" ? _jsx("div", { className: cx("kpi", className), ...props, children: miolo })
126
- : _jsx(Card, { className: cx("kpi", className), ...props, children: miolo });
125
+ const maior = bars && bars.length > 0 ? Math.max(...bars.map(b => b.amount), 1) : 1;
126
+ const escolhida = bars && bars.length > 0 ? Math.min(Math.max(defaultBar ?? bars.length - 1, 0), bars.length - 1) : -1;
127
+ const leituraDe = (b) => `${b.label} · ${typeof b.value === "string" || typeof b.value === "number" ? b.value : ""}`;
128
+ // As barras são botões de opção NATIVOS (o KPI é marcação pura, roda no servidor): o grupo é um `fieldset` com o rótulo
129
+ // do KPI, cada barra o `label` de um rádio com a leitura dela; o CSS mostra a leitura da escolhida e a da que está sob o
130
+ // mouse. O `name` vem do rótulo quando é texto.
131
+ const nomeDoGrupo = `kpi-bars-${typeof label === "string" ? label.toLowerCase().replace(/[^a-z0-9]+/g, "-") : "x"}`;
132
+ const barras = bars && bars.length > 0 && _jsxs("fieldset", { className: "kpi-bars-wrap", children: [typeof label === "string" && _jsx("legend", { className: "sr-only", children: label }), _jsx("div", { className: "kpi-bars", style: { "--kpi-bars": bars.length }, children: bars.map((b, i) => _jsxs("label", { className: "kpi-bar", children: [_jsx("input", { type: "radio", className: "kpi-bar-input", name: nomeDoGrupo, value: String(i), defaultChecked: i === escolhida, "aria-label": leituraDe(b) }), _jsx("span", { className: "kpi-bar-fill", style: { "--kpi-bar-h": `${Math.round(b.amount / maior * 100)}%` } }), _jsx("span", { className: "kpi-bar-reading", "aria-hidden": "true", children: leituraDe(b) })] }, i)) }), _jsx("div", { className: "kpi-bars-x", "aria-hidden": "true", style: { "--kpi-bars": bars.length }, children: bars.map((b, i) => _jsx("span", { children: b.label }, i)) })] });
133
+ return variant === "plain" ? _jsxs("div", { className: cx("kpi", className), ...props, children: [miolo, barras] })
134
+ : _jsxs(Card, { className: cx("kpi", variant === "brand" && "kpi-brand", className), ...props, children: [miolo, barras] });
127
135
  }
128
136
  export function DataList({ items }) { return _jsx("dl", { className: "data-list", children: items.map((i, n) => _jsxs(React.Fragment, { children: [_jsx("dt", { children: i.term }), _jsx("dd", { children: i.value })] }, n)) }); }
129
137
  export function Timeline({ items, variant }) { return _jsx("ol", { className: "timeline", "data-timeline-style": variant, children: items.map((i, n) => _jsxs("li", { children: [_jsx("span", { className: "timeline-dot" }), _jsxs("div", { children: [_jsx("strong", { children: i.title }), i.description && _jsx("p", { children: i.description }), i.time && _jsx("small", { className: "muted", children: i.time })] })] }, n)) }); }
@@ -217,7 +225,7 @@ export function Header({ variant = "floating", divider, brand, items, current, a
217
225
  // Sem o encaixe, a marcação de sempre; com ele, a linha das áreas e a ponta numa mesma faixa.
218
226
  return tabsEnd == null ? abas : _jsxs("div", { className: "topbar-tabs-row", children: [abas, _jsx("div", { className: "topbar-tabs-end", children: tabsEnd })] });
219
227
  })()] });
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 });
228
+ 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" || variant === "pill") && "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 });
221
229
  }
222
230
  /** @deprecated `Topbar` é o nome antigo do `Header` (07/10/2026). Continua funcionando, igual; use `Header`. */
223
231
  export function Topbar(props) { return _jsx(Header, { ...props }); }
@@ -233,7 +241,14 @@ export function Kbd({ children, className, ...props }) { return _jsx("kbd", { cl
233
241
  export const Textarea = forwardRef(function Textarea({ className, size, variant, ...props }, ref) { return _jsx("textarea", { ref: ref, className: cx("textarea", peleDoEixo("textarea", size), variant === "secondary" && "textarea-secondary", className), ...props }); });
234
242
  // `size` nos três marcáveis pela mesma razão do campo: uma linha de formulário com um campo `sm`
235
243
  // e um checkbox de tamanho fixo ao lado desalinha. O degrau vai na MARCA, não no rótulo.
236
- export function Checkbox({ label, labelHidden, description, size, className, ...props }) { return _jsxs("label", { className: cx("checkbox", labelHidden && "checkbox-bare", className), children: [_jsx("input", { type: "checkbox", ...props }), _jsx("span", { className: cx("control-mark", peleDoEixo("control-mark", size)) }), _jsxs("span", { className: labelHidden ? "sr-only" : undefined, children: [_jsx("strong", { children: label }), description && _jsxs(_Fragment, { children: [_jsx("br", {}), _jsx("span", { className: "muted", children: description })] })] })] }); }
244
+ // `variant="pill"` (o site B, o "Mark as done" — aprovado pela bancada em 01/11/2026, o item 4): a cápsula em volta, o alvo
245
+ // inteiro, de 44 (`--target-min`, a caixa 24) ou, com `size` sm/md, de 36 (`--control-h-md`, a caixa 20). `tone="success"`
246
+ // pinta a marcada de "feito" (a cápsula no verde a 18%, a letra e a caixa no verde). Sem `pill`, a caixa de sempre.
247
+ export function Checkbox({ label, labelHidden, description, size, variant = "default", tone, className, ...props }) {
248
+ if (variant === "pill")
249
+ return _jsxs("label", { className: cx("checkbox", "checkbox-pill", (size === "sm" || size === "md") && "checkbox-pill-md", className), "data-tone": tone, children: [_jsx("input", { type: "checkbox", ...props }), _jsx("span", { className: "control-mark" }), _jsx("span", { className: labelHidden ? "sr-only" : undefined, children: label })] });
250
+ return _jsxs("label", { className: cx("checkbox", labelHidden && "checkbox-bare", className), children: [_jsx("input", { type: "checkbox", ...props }), _jsx("span", { className: cx("control-mark", peleDoEixo("control-mark", size)) }), _jsxs("span", { className: labelHidden ? "sr-only" : undefined, children: [_jsx("strong", { children: label }), description && _jsxs(_Fragment, { children: [_jsx("br", {}), _jsx("span", { className: "muted", children: description })] })] })] });
251
+ }
237
252
  // `description` no `Radio` e no `Switch` (15/10/2026, a referência tem nos dois): a linha apagada embaixo do nome, do
238
253
  // mesmo jeito do `Checkbox`. Sem ela, a marcação é a de sempre.
239
254
  const comDescricao = (label, description) => description ? _jsxs("span", { children: [_jsx("strong", { children: label }), _jsx("br", {}), _jsx("span", { className: "muted", children: description })] }) : label;
@@ -291,6 +306,13 @@ export function Link({ external, disabled, href, target, rel, className, childre
291
306
  // Transparente quando o texto diz alfa abaixo de 1 (hex de 4 ou 8 dígitos, `rgba()`, `hsla()`…). Cor de token ou
292
307
  // `oklch()` a marcação não lê: fica sem xadrez.
293
308
  const transparente = (cor) => { const c = parseColor(cor); return c !== null && c.a < 1; };
309
+ // A cor só entra no estilo quando É uma cor (31/10/2026, a auditoria de segurança): o texto ia cru para a variável, e
310
+ // no HTML do servidor um ";" abria regras novas (cobrir a tela, buscar imagem de outro endereço). Aceita o que a ficha
311
+ // promete — hex, nome, as funções de cor do CSS e `var(--token)` — e nada com ";", chaves, barra invertida, aspas,
312
+ // comentário ou outra função (`url(`). Recusada, a variável não se escreve: a amostra fica sem cor, e o nome continua.
313
+ // (O `parseColor` não serve de filtro: ele não lê `oklch()` nem `var()`, que a ficha promete.)
314
+ const COR_DE_CSS = /^(?:#[0-9a-f]{3,8}|[a-z]+|(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\([^;{}\\"'()]*\)|var\(--[\w-]+\))$/i;
315
+ const corDeCss = (cor) => { const c = cor.trim(); return COR_DE_CSS.test(c) && !c.includes("/*") ? c : undefined; };
294
316
  export function ColorSwatch(props) {
295
317
  if ("options" in props) {
296
318
  const { options, name, label, value, defaultValue, onChange, layout = "grid", indicator, showLabels, size = "md", disabled, id, className } = props;
@@ -302,14 +324,14 @@ export function ColorSwatch(props) {
302
324
  return _jsx("div", { role: "radiogroup", "aria-label": label, id: id, "aria-disabled": disabled || undefined, className: cx("color-swatch-picker", size !== "md" && `color-swatch-picker-${size}`, layout === "stack" && "color-swatch-picker-stack", showLabels && "color-swatch-picker-labels", className), children: options.map((o) => {
303
325
  const op = typeof o === "string" ? { color: o } : o;
304
326
  const cor = parseColor(op.color), rgb = cor && hsbToRgb(cor);
305
- const circulo = (Tag, key) => _jsxs(Tag, { className: cx("color-swatch-option", rgb && contrastingInk(rgb) === "dark" && "color-swatch-option-dark"), style: { ["--color-swatch-current"]: op.color }, children: [_jsx("input", { type: "radio", className: "color-swatch-input", name: name, value: op.color, "aria-label": op.label ?? op.color, checked: value === undefined ? undefined : value === op.color, defaultChecked: value === undefined ? defaultValue === op.color : undefined, disabled: disabled || op.disabled, ...(onChange ? { onChange } : {}) }), _jsx("span", { className: cx("color-swatch", cor && cor.a < 1 && "color-swatch-alpha"), "aria-hidden": "true" }), indicator != null && _jsx("span", { className: "color-swatch-indicator", "aria-hidden": "true", children: indicator })] }, key);
327
+ const circulo = (Tag, key) => _jsxs(Tag, { className: cx("color-swatch-option", rgb && contrastingInk(rgb) === "dark" && "color-swatch-option-dark"), style: { ["--color-swatch-current"]: corDeCss(op.color) }, children: [_jsx("input", { type: "radio", className: "color-swatch-input", name: name, value: op.color, "aria-label": op.label ?? op.color, checked: value === undefined ? undefined : value === op.color, defaultChecked: value === undefined ? defaultValue === op.color : undefined, disabled: disabled || op.disabled, ...(onChange ? { onChange } : {}) }), _jsx("span", { className: cx("color-swatch", cor && cor.a < 1 && "color-swatch-alpha"), "aria-hidden": "true" }), indicator != null && _jsx("span", { className: "color-swatch-indicator", "aria-hidden": "true", children: indicator })] }, key);
306
328
  return showLabels
307
329
  ? _jsxs("label", { className: "color-swatch-item", children: [circulo("span"), _jsx("span", { className: "color-swatch-name", "aria-hidden": "true", children: op.label ?? op.color })] }, op.color)
308
330
  : circulo("label", op.color);
309
331
  }) });
310
332
  }
311
333
  const { color, size = "md", label, className, style, ...resto } = props;
312
- return _jsx("span", { role: "img", "aria-label": label ?? color, className: cx("color-swatch", size !== "md" && `color-swatch-${size}`, transparente(color) && "color-swatch-alpha", className), style: { ...style, ["--color-swatch-current"]: color }, ...resto });
334
+ return _jsx("span", { role: "img", "aria-label": label ?? color, className: cx("color-swatch", size !== "md" && `color-swatch-${size}`, transparente(color) && "color-swatch-alpha", className), style: { ...style, ["--color-swatch-current"]: corDeCss(color) }, ...resto });
313
335
  }
314
336
  export function ProgressCircle({ value, min = 0, max = 100, size = "md", tone = "brand", label, className, ...props }) {
315
337
  const semTotal = value == null || Number.isNaN(value);
@@ -8,10 +8,15 @@ export interface StepItem {
8
8
  state?: StepState;
9
9
  optional?: ReactNode;
10
10
  onClick?: () => void;
11
+ href?: string;
11
12
  }
12
- export declare function Stepper({ items, label, className }: {
13
+ export type StepperVariant = "default" | "path" | "bar";
14
+ export declare function Stepper({ items, label, variant, startContent, endContent, className }: {
13
15
  items: StepItem[];
14
16
  label?: string;
17
+ variant?: StepperVariant;
18
+ startContent?: ReactNode;
19
+ endContent?: ReactNode;
15
20
  className?: string;
16
21
  }): React.JSX.Element;
17
22
  export interface BreadcrumbItem {
@@ -64,10 +69,14 @@ export interface TocItem {
64
69
  label: string;
65
70
  sub?: boolean;
66
71
  }
67
- export declare function TableOfContents({ items, current, label, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
72
+ export declare function TableOfContents({ items, current, label, progress, indicator, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement> & {
68
73
  items: TocItem[];
69
74
  current?: string;
70
75
  label?: string;
76
+ /** O anel de leitura no lugar do ícone do nome: quanto da página já rolou, em anel e em número. */
77
+ progress?: boolean;
78
+ /** O desenho do item atual: `"line"` (o padrão, o traço do lado) ou `"segment"` (a cápsula levantada, como a da `Sidebar`). */
79
+ indicator?: "line" | "segment";
71
80
  }): React.JSX.Element;
72
81
  export interface TreeNode {
73
82
  id: string;
@@ -245,10 +254,18 @@ export interface NavListItem {
245
254
  };
246
255
  /** Os sinais ao lado do `value` (AN-04): fixada, silenciada. Pequenos e apagados, cada um com nome. */
247
256
  indicators?: NavListIndicator[];
257
+ /** A cor de categoria do círculo do ícone, no `size="lg"` (as cores do `Badge`). */
258
+ tone?: BadgeCategory;
259
+ /** A linha da página em que se está: `aria-current="page"`, o fundo, e o selo `currentLabel` no lugar da seta. */
260
+ current?: boolean;
248
261
  }
249
- export declare function NavList({ items, className, ...props }: HTMLAttributes<HTMLUListElement> & RefAttributes<HTMLUListElement> & {
262
+ export declare function NavList({ items, size, currentLabel, className, ...props }: HTMLAttributes<HTMLUListElement> & RefAttributes<HTMLUListElement> & {
250
263
  items: NavListItem[];
264
+ size?: "md" | "lg";
265
+ /** O texto do selo da linha atual (só aparece com `current` num item). */
266
+ currentLabel?: ReactNode;
251
267
  }): React.JSX.Element;
268
+ import type { BadgeCategory } from "./markup.js";
252
269
  export interface CommandItem {
253
270
  id: string;
254
271
  label: string;
@@ -258,8 +275,12 @@ export interface CommandItem {
258
275
  /** 0.32.0 (DOC-06): o grupo do item ("Componentes", "Páginas"). Itens com o mesmo grupo saem juntos,
259
276
  * sob o título dele, na ordem em que o grupo aparece primeiro. */
260
277
  group?: string;
278
+ /** A linha de baixo do item, apagada e cortada (no `size="lg"`). */
279
+ description?: string;
280
+ /** A cor de categoria do círculo do ícone (no `size="lg"`), como as do `Badge`. Sem ela, o círculo neutro. */
281
+ tone?: BadgeCategory;
261
282
  }
262
- export declare function CommandPalette({ open, onClose, items, placeholder, label, shortcuts }: {
283
+ export declare function CommandPalette({ open, onClose, items, placeholder, label, shortcuts, size, filters, preview, footer }: {
263
284
  open: boolean;
264
285
  onClose: () => void;
265
286
  items: CommandItem[];
@@ -267,6 +288,13 @@ export declare function CommandPalette({ open, onClose, items, placeholder, labe
267
288
  label?: string;
268
289
  /** 0.32.0 (DOC-07): a linha que ensina as teclas, embaixo — ↑ ↓ mover, Enter abrir, Esc fechar. */
269
290
  shortcuts?: boolean;
291
+ size?: "md" | "lg";
292
+ /** No `lg`: o que vai embaixo do campo — os filtros que o app desenha (um `ToggleGroup`, por exemplo). */
293
+ filters?: ReactNode;
294
+ /** No `lg`: a prévia do item ativo, ao lado da lista. Some quando a janela é estreita. */
295
+ preview?: (item: CommandItem) => ReactNode;
296
+ /** No `lg`: o que vai no pé, ao lado da linha das teclas. */
297
+ footer?: ReactNode;
270
298
  }): React.JSX.Element;
271
299
  export declare function CommandPaletteShell({ open, query, onQueryChange, onClose, label, children }: {
272
300
  open: boolean;
@@ -11,7 +11,7 @@ import { Dialog as BaseDialog } from "@base-ui/react/dialog";
11
11
  import { Popover as BasePopover } from "@base-ui/react/popover";
12
12
  import { useValorResponsivo } from "./responsivo-runtime.js";
13
13
  import { cx, fundirRender, useAureaStrings, usePortalContainer } from "./internal.js";
14
- import { Kbd } from "./markup.js";
14
+ import { Kbd, ProgressCircle } from "./markup.js";
15
15
  import { Icon } from "./system.js";
16
16
  import { Button, IconButton } from "./actions.js";
17
17
  import { Badge, Spinner } from "./feedback.js";
@@ -21,14 +21,20 @@ import { SearchField } from "./inputs.js";
21
21
  // mudou foi a ORDEM documentada, que colocava overlays no "resto" sem motivo medido.
22
22
  import { Tooltip } from "./overlays.js";
23
23
  import { Avatar } from "./identity-client.js";
24
- export function Stepper({ items, label, className }) {
24
+ export function Stepper({ items, label, variant = "default", startContent, endContent, className }) {
25
25
  const s = useAureaStrings();
26
- return _jsx("div", { role: "list", "aria-label": label ?? s.stepperLabel, className: cx("stepper", className), children: items.map((it, n) => {
27
- const st = it.state ?? "default";
28
- const marca = st === "done" ? _jsx(Icon, { name: "check" }) : st === "error" ? _jsx(Icon, { name: "x-circle" }) : n + 1;
29
- const miolo = _jsxs(_Fragment, { children: [_jsx("span", { className: "step-dot", children: marca }), _jsx("strong", { children: it.label }), it.optional && _jsx("small", { className: "step-optional", children: it.optional })] });
30
- return _jsx("div", { role: "listitem", className: cx("step", st !== "default" && `step-${st}`), "aria-current": st === "active" ? "step" : undefined, children: it.onClick ? _jsx("button", { type: "button", className: "step-trigger", onClick: it.onClick, children: miolo }) : miolo }, n);
31
- }) });
26
+ const comPontas = variant === "path";
27
+ const lista = _jsxs("div", { role: "list", "aria-label": label ?? s.stepperLabel, className: cx("stepper", variant === "default" && className), style: comPontas ? { "--stepper-cols": items.length + (startContent != null ? 1 : 0) + (endContent != null ? 1 : 0) } : undefined, children: [comPontas && startContent != null && _jsx("div", { role: "listitem", className: "step-end step-end-start", children: startContent }), items.map((it, n) => {
28
+ const st = it.state ?? "default";
29
+ const marca = st === "done" && variant !== "path" ? _jsx(Icon, { name: "check" }) : st === "error" ? _jsx(Icon, { name: "x-circle" }) : n + 1;
30
+ const miolo = variant === "bar" ? _jsx("span", { className: "sr-only", children: it.label }) : _jsxs(_Fragment, { children: [_jsx("span", { className: "step-dot", children: marca }), _jsx("strong", { children: it.label }), it.optional && _jsx("small", { className: "step-optional", children: it.optional })] });
31
+ return _jsx("div", { role: "listitem", className: cx("step", st !== "default" && `step-${st}`), "aria-current": st === "active" ? "step" : undefined, children: it.href ? _jsx("a", { className: "step-trigger", href: it.href, onClick: it.onClick, children: miolo }) : it.onClick || variant === "bar" ? _jsx("button", { type: "button", className: "step-trigger", onClick: it.onClick, children: miolo }) : miolo }, n);
32
+ }), comPontas && endContent != null && _jsx("div", { role: "listitem", className: "step-end", children: endContent })] });
33
+ if (variant === "path")
34
+ return _jsx("div", { className: cx("stepper-path", className), children: lista });
35
+ if (variant === "bar")
36
+ return _jsxs("div", { className: cx("stepper-bar", className), children: [startContent != null && _jsx("span", { className: "stepper-bar-label", children: startContent }), lista, endContent != null && _jsx("span", { className: "stepper-bar-count", role: "status", children: endContent })] });
37
+ return lista;
32
38
  }
33
39
  export function Breadcrumb({ items, label }) { const s = useAureaStrings(); return _jsx("nav", { className: "breadcrumb", "aria-label": label ?? s.breadcrumbLabel, children: items.map((i, n) => _jsxs(React.Fragment, { children: [n > 0 && _jsx(Icon, { name: "caret-right", size: "sm" }), " ", i.render ? fundirRender(i.render, { children: i.label }, "a") : i.href ? _jsx("a", { href: i.href, children: i.label }) : _jsx("strong", { "aria-current": "page", children: i.label })] }, n)) }); }
34
40
  export function Tabs({ tabs, value, onChange, label, orientation, activateOnFocus = true, loopFocus, panel = "card", variant = "primary" }) { const s = useAureaStrings(); const ancora = useRef(null); const resolvida = useValorResponsivo(orientation, "horizontal", ancora); return _jsxs(BaseTabs.Root, { ref: ancora, value: value, onValueChange: v => onChange(String(v)), orientation: resolvida, className: "tabs-root", children: [_jsx(BaseTabs.List, { className: cx("tabs", variant === "secondary" && "tabs-secondary"), "aria-label": label ?? s.tabsLabel, activateOnFocus: activateOnFocus, loopFocus: loopFocus, children: tabs.map(t => _jsx(BaseTabs.Tab, { value: t.id, className: "tab", children: t.label }, t.id)) }), tabs.map(t => _jsx(BaseTabs.Panel, { value: t.id, className: panel === "plain" ? "tabs-panel" : "card card-inset", tabIndex: 0, children: t.content }, t.id))] }); }
@@ -62,11 +68,29 @@ export function Pagination({ page, total, onPageChange, variant = "numbers", sum
62
68
  ? _jsx("li", { children: _jsx("span", { className: "pagination-ellipsis", "aria-hidden": "true", children: "\u2026" }) }, `e${i}`)
63
69
  : _jsx("li", { children: item(p, p, { atual: p === page, rotulo: `${s.paginationPage} ${p}` }) }, p)), _jsx("li", { children: proxima })] })] });
64
70
  }
65
- export function TableOfContents({ items, current, label, className, ...props }) {
71
+ //
72
+ // O SITE B (30/10/2026, protótipo): `progress` troca o ícone do nome pelo ANEL DE LEITURA — quanto da página já rolou, no
73
+ // anel (o `ProgressCircle`) e em número, na ponta da linha. É enfeite de leitura: o anel e o número ficam fora do leitor
74
+ // de tela (o que importa a ele é a seção atual, que o `aria-current` já diz).
75
+ export function TableOfContents({ items, current, label, progress, indicator = "line", className, ...props }) {
66
76
  const s = useAureaStrings();
67
77
  const meu = React.useRef(null);
68
78
  const observado = useSecaoEmVista(items, current === undefined, meu);
69
79
  const atual = current ?? observado;
80
+ const [lido, setLido] = React.useState(0);
81
+ const Rotulo = progress ? "div" : "p";
82
+ React.useEffect(() => {
83
+ if (!progress || typeof window === "undefined")
84
+ return;
85
+ const ler = () => {
86
+ const alto = document.documentElement.scrollHeight - window.innerHeight;
87
+ setLido(alto > 0 ? Math.round(Math.min(1, Math.max(0, window.scrollY / alto)) * 100) : 100);
88
+ };
89
+ ler();
90
+ window.addEventListener("scroll", ler, { passive: true });
91
+ window.addEventListener("resize", ler);
92
+ return () => { window.removeEventListener("scroll", ler); window.removeEventListener("resize", ler); };
93
+ }, [progress]);
70
94
  // O `ref` do consumidor continua chegando: em React 19 ele é prop comum, então espalhá-lo por
71
95
  // `...props` depois do nosso o sobrescreveria em silêncio. Os dois são atendidos aqui.
72
96
  const refDele = props.ref;
@@ -74,7 +98,9 @@ export function TableOfContents({ items, current, label, className, ...props })
74
98
  return _jsxs("nav", { ref: n => { meu.current = n; if (typeof refDele === "function")
75
99
  refDele(n);
76
100
  else if (refDele)
77
- refDele.current = n; }, className: cx("toc", className), "aria-label": label ?? s.tocLabel, ...resto, children: [_jsxs("p", { className: "toc-label", children: [_jsx("span", { className: "toc-label-icon", "aria-hidden": "true" }), label ?? s.tocLabel] }), items.map(i => _jsx("a", { href: `#${i.id}`, className: cx(i.sub && "toc-sub"), ...(i.id === atual ? { "aria-current": "true" } : {}), children: i.label }, i.id))] });
101
+ refDele.current = n; }, className: cx("toc", indicator === "segment" && "toc-segment", className), "aria-label": label ?? s.tocLabel, ...resto, children: [_jsxs(Rotulo, { className: cx("toc-label", progress && "toc-label-progress"), children: [progress
102
+ ? _jsx("span", { className: "toc-progress", "aria-hidden": "true", children: _jsx(ProgressCircle, { value: lido, size: "lg", label: label ?? s.tocLabel }) })
103
+ : _jsx("span", { className: "toc-label-icon", "aria-hidden": "true" }), label ?? s.tocLabel, progress && _jsxs("span", { className: "toc-progress-value", "aria-hidden": "true", children: [lido, "%"] })] }), items.map(i => _jsx("a", { href: `#${i.id}`, className: cx(i.sub && "toc-sub"), ...(i.id === atual ? { "aria-current": "true" } : {}), children: i.label }, i.id))] });
78
104
  }
79
105
  /** Qual dos `items` está na faixa de leitura, observando o documento. Devolve `undefined` até o
80
106
  * primeiro cálculo — e em SSR, onde não há documento para observar.
@@ -270,7 +296,7 @@ function SidebarGroup({ item, filhos, lid, ctx }) {
270
296
  ? _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
297
  : _jsx("p", { id: lid, className: cx("sidebar-group-label", ctx.collapsed && "sr-only"), children: item.label });
272
298
  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] });
299
+ 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", className: "sidebar-group-list", hidden: !aberto, children: lista }) : lista] });
274
300
  }
275
301
  // A GAVETA FECHA AO ESCOLHER (A-06, 23/09/2026). Abaixo de lg a lateral do `AppShell` é popover,
276
302
  // e a biblioteca a abria e NUNCA a fechava por código: `hidePopover` tinha zero ocorrências. O
@@ -463,17 +489,32 @@ export function BottomNav({ items, current, variant = "floating", indicator = "n
463
489
  : _jsx("button", { type: "button", className: "bottom-nav-item", "aria-current": ativo ? "page" : undefined, onClick: it.onClick, children: miolo }, it.id);
464
490
  }) });
465
491
  }
466
- export function NavList({ items, className, ...props }) {
467
- return _jsx("ul", { className: cx("nav-list", className), ...props, children: items.map(it => {
468
- const miolo = _jsxs(_Fragment, { children: [it.avatar ? _jsx(Avatar, { src: it.avatar.src, fallback: it.avatar.fallback }) : it.icon && _jsx(Icon, { name: it.icon }), _jsxs("span", { className: "nav-list-text", children: [_jsx("span", { className: "nav-list-label", children: it.label }), it.description != null && _jsx("span", { className: "nav-list-description", children: it.description })] }), it.indicators && it.indicators.length > 0 && _jsx("span", { className: "nav-list-indicators", children: it.indicators.map(x => _jsxs("span", { children: [_jsx(Icon, { name: x.icon, size: "sm" }), _jsx("span", { className: "sr-only", children: x.label })] }, x.label)) }), it.value != null && _jsx("span", { className: "nav-list-value", children: it.value }), (it.href || it.render) && _jsx(Icon, { name: "caret-right", size: "sm", className: "nav-list-chevron" })] });
492
+ // `size="lg"` (o site B — o menu do celular, aprovado pela bancada em 01/11/2026, o item 10): a linha de 56 em cápsula (o
493
+ // ícone de 40 + 8 em cima e embaixo), o ícone num círculo de 40 tingido (`tone`), a letra 18 seminegrito. `current` marca a
494
+ // linha atual (o fundo `--fill-2`), e `currentLabel` é o selo que ela leva no lugar da seta ("You are here"). Sem `lg`, a
495
+ // lista de sempre; `current` vale nos dois tamanhos.
496
+ export function NavList({ items, size = "md", currentLabel, className, ...props }) {
497
+ const grande = size === "lg";
498
+ return _jsx("ul", { className: cx("nav-list", grande && "nav-list-lg", className), ...props, children: items.map(it => {
499
+ const icone = it.icon && (grande ? _jsx("span", { className: "nav-list-tile", "data-tone": it.tone, children: _jsx(Icon, { name: it.icon }) }) : _jsx(Icon, { name: it.icon }));
500
+ const miolo = _jsxs(_Fragment, { children: [it.avatar ? _jsx(Avatar, { src: it.avatar.src, fallback: it.avatar.fallback }) : icone, _jsxs("span", { className: "nav-list-text", children: [_jsx("span", { className: "nav-list-label", children: it.label }), it.description != null && _jsx("span", { className: "nav-list-description", children: it.description })] }), it.indicators && it.indicators.length > 0 && _jsx("span", { className: "nav-list-indicators", children: it.indicators.map(x => _jsxs("span", { children: [_jsx(Icon, { name: x.icon, size: "sm" }), _jsx("span", { className: "sr-only", children: x.label })] }, x.label)) }), it.value != null && _jsx("span", { className: "nav-list-value", children: it.value }), it.current && currentLabel != null ? _jsx(Badge, { variant: "primary", emphasis: "solid", className: "nav-list-here", children: currentLabel })
501
+ : (it.href || it.render) && _jsx(Icon, { name: "caret-right", size: "sm", className: "nav-list-chevron" })] });
502
+ const atual = it.current ? "page" : undefined;
469
503
  return _jsx("li", { children: it.render && !it.disabled
470
- ? fundirRender(it.render, { className: "nav-list-row", onClick: it.onClick, children: miolo }, "a")
504
+ ? fundirRender(it.render, { className: "nav-list-row", onClick: it.onClick, "aria-current": atual, children: miolo }, "a")
471
505
  : it.href && !it.disabled
472
- ? _jsx("a", { href: it.href, className: "nav-list-row", onClick: it.onClick, children: miolo })
473
- : _jsx("button", { type: "button", className: "nav-list-row", "aria-disabled": it.disabled || undefined, onClick: it.disabled ? undefined : it.onClick, children: miolo }) }, it.id);
506
+ ? _jsx("a", { href: it.href, className: "nav-list-row", "aria-current": atual, onClick: it.onClick, children: miolo })
507
+ : _jsx("button", { type: "button", className: "nav-list-row", "aria-current": atual, "aria-disabled": it.disabled || undefined, onClick: it.disabled ? undefined : it.onClick, children: miolo }) }, it.id);
474
508
  }) });
475
509
  }
476
- export function CommandPalette({ open, onClose, items, placeholder, label, shortcuts = true }) {
510
+ // `size="lg"` (o site B — a busca nova, aprovada pela bancada em 01/11/2026, o item 2 e o D-2): a janela da largura `lg`
511
+ // (1024), o campo de 64 com a lupa e o "Esc" dentro, o encaixe `filters` embaixo dele, o título do grupo em mono maiúsculo
512
+ // com a contagem, o item de 50 com o ícone num círculo de 40 tingido (`tone`), o título e a descrição cortada, o "↵" na
513
+ // linha ativa, a prévia (`preview`) do item ativo ao lado da lista — some abaixo de 1240 — e o encaixe `footer` no pé,
514
+ // ao lado das teclas. Sem `size="lg"`, a paleta de sempre; os encaixes só valem no `lg`.
515
+ export function CommandPalette({ open, onClose, items, placeholder, label, shortcuts = true, size = "md", filters, preview, footer }) {
516
+ const grande = size === "lg";
517
+ const [ativo, setAtivo] = React.useState(undefined);
477
518
  const s = useAureaStrings();
478
519
  const idAtalhos = React.useId();
479
520
  // GRUPOS (0.32.0, DOC-06). Em 13/08/2026 a Aurea ficou SEM grupo, e a medição decidiu: dar a cada
@@ -496,7 +537,9 @@ export function CommandPalette({ open, onClose, items, placeholder, label, short
496
537
  const portal = usePortalContainer();
497
538
  const campo = useRef(null);
498
539
  const executa = (item) => { onClose(); item.run(); };
499
- const linha = (item) => _jsxs(BaseAutocomplete.Item, { value: item, className: "menu-item command-item", onClick: () => executa(item), children: [item.icon && _jsx(Icon, { name: item.icon }), _jsx("span", { className: "command-item-label", children: item.label }), item.kbd && _jsx(Kbd, { children: item.kbd })] }, item.id);
540
+ const linha = (item) => grande
541
+ ? _jsxs(BaseAutocomplete.Item, { value: item, className: "menu-item command-item", onClick: () => executa(item), children: [_jsx("span", { className: "command-item-tile", "data-tone": item.tone, children: item.icon && _jsx(Icon, { name: item.icon }) }), _jsxs("span", { className: "command-item-text", children: [_jsx("span", { className: "command-item-label", children: item.label }), item.description && _jsx("span", { className: "command-item-description", children: item.description })] }), item.kbd ? _jsx(Kbd, { children: item.kbd }) : _jsx(Kbd, { className: "command-item-enter", "aria-hidden": "true", children: "\u21B5" })] }, item.id)
542
+ : _jsxs(BaseAutocomplete.Item, { value: item, className: "menu-item command-item", onClick: () => executa(item), children: [item.icon && _jsx(Icon, { name: item.icon }), _jsx("span", { className: "command-item-label", children: item.label }), item.kbd && _jsx(Kbd, { children: item.kbd })] }, item.id);
500
543
  // A JANELA É A DO MOTOR (14/10/2026), como na paleta de exemplo dele (1.6.0): `Dialog` por fora,
501
544
  // `Autocomplete` `inline` por dentro. Até aqui a moldura era uma `div` feita à mão, e o Victor achou no site
502
545
  // publicado: o clique no fundo não fechava, e depois dele o foco ia para a página — o Esc, que era escutado
@@ -505,9 +548,12 @@ export function CommandPalette({ open, onClose, items, placeholder, label, short
505
548
  // (`onOpenChange`), e quem fecha é o `onClose` — mesma regra do Dialog e do Drawer daqui. Os nomes de classe
506
549
  // ficaram: a moldura (`Viewport`) é a `.command-overlay`, a caixa (`Popup`) é a `.command-palette`.
507
550
  return _jsx(BaseDialog.Root, { open: open, onOpenChange: o => { if (!o)
508
- onClose(); }, children: _jsx(BaseDialog.Portal, { container: portal, children: _jsx(BaseDialog.Viewport, { className: "command-overlay", children: _jsxs(BaseDialog.Popup, { className: "command-palette", "aria-label": label ?? s.commandLabel, initialFocus: campo, children: [_jsxs(BaseAutocomplete.Root, { items: (grupos ?? items), itemToStringValue: (i) => i.label, mode: "list", open: true, inline: true, autoHighlight: "always", keepHighlight: true, children: [_jsx(BaseAutocomplete.Input, { ref: campo, className: "input", "aria-label": placeholder ?? s.commandPlaceholder, placeholder: placeholder ?? s.commandPlaceholder, "aria-expanded": true, "aria-describedby": shortcuts ? idAtalhos : undefined }), _jsxs("div", { className: "menu command-list", children: [_jsx(BaseAutocomplete.Empty, { className: "combobox-empty", children: s.comboboxEmpty }), _jsx(BaseAutocomplete.List, { children: grupos
509
- ? (g) => _jsxs(BaseAutocomplete.Group, { items: g.items, className: "command-group", children: [g.value && _jsx(BaseAutocomplete.GroupLabel, { className: "command-group-label", children: g.value }), _jsx(BaseAutocomplete.Collection, { children: linha })] }, g.value)
510
- : _jsx(BaseAutocomplete.Collection, { children: linha }) })] })] }), shortcuts && _jsxs("p", { className: "command-shortcuts", id: idAtalhos, children: [_jsxs("span", { children: [_jsx(Kbd, { children: "\u2191" }), _jsx(Kbd, { children: "\u2193" }), " ", s.commandHintMove] }), _jsxs("span", { children: [_jsx(Kbd, { children: "Enter" }), " ", s.commandHintSelect] }), _jsxs("span", { children: [_jsx(Kbd, { children: "Esc" }), " ", s.commandHintClose] })] })] }) }) }) });
551
+ onClose(); }, children: _jsx(BaseDialog.Portal, { container: portal, children: _jsx(BaseDialog.Viewport, { className: "command-overlay", children: _jsxs(BaseDialog.Popup, { className: cx("command-palette", grande && "command-palette-lg"), "aria-label": label ?? s.commandLabel, initialFocus: campo, children: [_jsxs(BaseAutocomplete.Root, { items: (grupos ?? items), itemToStringValue: (i) => i.label, mode: "list", open: true, inline: true, autoHighlight: "always", keepHighlight: true, onItemHighlighted: grande && preview ? (v) => { if (v)
552
+ setAtivo(v); } : undefined, children: [grande
553
+ ? _jsxs("div", { className: "command-field", children: [_jsx(Icon, { name: "magnifying-glass" }), _jsx(BaseAutocomplete.Input, { ref: campo, className: "command-input", "aria-label": placeholder ?? s.commandPlaceholder, placeholder: placeholder ?? s.commandPlaceholder, "aria-expanded": true, "aria-describedby": shortcuts ? idAtalhos : undefined }), _jsx(Kbd, { children: "Esc" })] })
554
+ : _jsx(BaseAutocomplete.Input, { ref: campo, className: "input", "aria-label": placeholder ?? s.commandPlaceholder, placeholder: placeholder ?? s.commandPlaceholder, "aria-expanded": true, "aria-describedby": shortcuts ? idAtalhos : undefined }), grande && filters != null && _jsx("div", { className: "command-filters", children: filters }), _jsxs("div", { className: grande && preview ? "command-body" : "command-body-plain", children: [_jsxs("div", { className: "menu command-list", children: [_jsx(BaseAutocomplete.Empty, { className: "combobox-empty", children: s.comboboxEmpty }), _jsx(BaseAutocomplete.List, { children: grupos
555
+ ? (g) => _jsxs(BaseAutocomplete.Group, { items: g.items, className: "command-group", children: [g.value && _jsxs(BaseAutocomplete.GroupLabel, { className: "command-group-label", children: [g.value, grande && _jsx("span", { className: "command-group-count", children: g.items.length })] }), _jsx(BaseAutocomplete.Collection, { children: linha })] }, g.value)
556
+ : _jsx(BaseAutocomplete.Collection, { children: linha }) })] }), grande && preview && ativo && _jsx("div", { className: "command-preview", children: preview(ativo) })] })] }), (shortcuts || (grande && footer != null)) && _jsxs("div", { className: grande ? "command-foot" : "command-foot-plain", children: [shortcuts && _jsxs("p", { className: "command-shortcuts", id: idAtalhos, children: [_jsxs("span", { children: [_jsx(Kbd, { children: "\u2191" }), _jsx(Kbd, { children: "\u2193" }), " ", s.commandHintMove] }), _jsxs("span", { children: [_jsx(Kbd, { children: "Enter" }), " ", s.commandHintSelect] }), _jsxs("span", { children: [_jsx(Kbd, { children: "Esc" }), " ", s.commandHintClose] })] }), grande && footer] })] }) }) }) });
511
557
  }
512
558
  // A CASCA (15/10/2026, o Victor: "C sim"): a mesma janela do motor da `CommandPalette` acima. Até aqui era uma `div`
513
559
  // feita à mão — o mesmo defeito que a busca do site teve: o clique fora e o Esc não fechavam, e o Tab saía da caixa.