@aurea-uds/react 0.31.0 → 0.33.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/inputs.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from "./inputs-client.js";
2
2
  export { Textarea, Checkbox, Radio, Switch, Range } from "./markup.js";
3
- export { Label, InputGroup, InputGroupAddon, type AddonSide, type AddonLayout, type FieldSize } from "./markup.js";
3
+ export { Label, InputGroup, InputGroupAddon, type AddonSide, type AddonLayout, type FieldSize, type FieldVariant } from "./markup.js";
@@ -1,20 +1,23 @@
1
1
  import React from "react";
2
- import { type AureaStrings, type AureaTheme, type AureaDensity } from "./pure.js";
3
- export { cx, fundirRender, defaultStrings, ptBR, defaultSpriteUrl, universalStates, stateSeverity, type AureaStrings, type UniversalState, type AureaTheme, type AureaDensity } from "./pure.js";
2
+ import { type AureaStrings, type AureaTheme, type AureaThemePreference, type AureaDensity } from "./pure.js";
3
+ export { cx, fundirRender, defaultStrings, ptBR, defaultSpriteUrl, universalStates, stateSeverity, type AureaStrings, type UniversalState, type AureaTheme, type AureaThemePreference, type AureaDensity } from "./pure.js";
4
+ export declare const controlesRotulaveis: WeakSet<object>;
4
5
  export declare const StringsContext: React.Context<AureaStrings>;
5
6
  export declare const useAureaStrings: () => AureaStrings;
6
7
  export declare const SpriteContext: React.Context<string>;
7
8
  export declare const useSpriteUrl: () => string;
8
9
  export declare const ThemeContext: React.Context<{
9
10
  theme?: AureaTheme;
10
- setTheme: (t: AureaTheme) => void;
11
+ preference?: AureaThemePreference;
12
+ setTheme: (t: AureaThemePreference) => void;
11
13
  toggleTheme: () => void;
12
14
  }>;
13
15
  /** Tema atual e como trocá-lo. Fora de um `AureaProvider`, devolve `undefined` e no-ops — não
14
16
  * lança: um componente isolado num teste não deve morrer por falta de provider. */
15
17
  export declare const useTheme: () => {
16
18
  theme?: AureaTheme;
17
- setTheme: (t: AureaTheme) => void;
19
+ preference?: AureaThemePreference;
20
+ setTheme: (t: AureaThemePreference) => void;
18
21
  toggleTheme: () => void;
19
22
  };
20
23
  export declare const DensityContext: React.Context<{
package/dist/internal.js CHANGED
@@ -18,6 +18,10 @@ import { createContext, useContext, useEffect, useRef, useState } from "react";
18
18
  import { Toast as BaseToast } from "@base-ui/react/toast";
19
19
  import { defaultStrings, defaultSpriteUrl } from "./pure.js";
20
20
  export { cx, fundirRender, defaultStrings, ptBR, defaultSpriteUrl, universalStates, stateSeverity } from "./pure.js";
21
+ // Os controles da Aurea que moram FORA do pacote principal (o `DatePicker`, em `./calendar`, 0.32.0) e
22
+ // entregam o `id` ao nó focal. O `Field` os nomeia com `<label for>`, como os da lista dele; eles se
23
+ // registram aqui ao carregar, porque importar cada um no `Field` puxaria o motor deles para todo app.
24
+ export const controlesRotulaveis = new WeakSet();
21
25
  export const StringsContext = createContext(defaultStrings);
22
26
  export const useAureaStrings = () => useContext(StringsContext);
23
27
  export const SpriteContext = createContext(defaultSpriteUrl);
@@ -31,7 +35,8 @@ export const useSpriteUrl = () => useContext(SpriteContext);
31
35
  // diferente de "escuro". Um default concreto aqui faria o provider sobrescrever, na primeira
32
36
  // pintura, o `data-theme` que o documento já traz no markup — e esse atributo existe justamente
33
37
  // para não haver piscada de tema ao carregar.
34
- export const ThemeContext = createContext({ theme: undefined, setTheme: () => { }, toggleTheme: () => { } });
38
+ // `preference` (15/10/2026): o que foi ESCOLHIDO, que pode ser `"system"`; `theme` é o que está na tela.
39
+ export const ThemeContext = createContext({ theme: undefined, preference: undefined, setTheme: () => { }, toggleTheme: () => { } });
35
40
  /** Tema atual e como trocá-lo. Fora de um `AureaProvider`, devolve `undefined` e no-ops — não
36
41
  * lança: um componente isolado num teste não deve morrer por falta de provider. */
37
42
  export const useTheme = () => useContext(ThemeContext);
@@ -1,7 +1,7 @@
1
1
  import { type HTMLAttributes, type RefAttributes, type ReactNode } from "react";
2
2
  import { type Orientation, type Responsive } from "./pure.js";
3
- import { type HeaderVariant, type SidebarVariant, type SidebarItem } from "./navigation.js";
4
- export declare function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant, topbarDivider, sidebarVariant, sidebarCollapsed, sidebarCollapsible, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
3
+ import { type HeaderVariant, type SidebarVariant, type SidebarScrollbar, type SidebarItem } from "./navigation.js";
4
+ export declare function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant, topbarDivider, sidebarVariant, sidebarScrollbar, sidebarCollapsed, sidebarCollapsible, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant, aside, asideLabel, asideVariant, children, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
5
5
  brand: ReactNode;
6
6
  navigation?: ReactNode;
7
7
  navItems?: SidebarItem[];
@@ -11,6 +11,18 @@ export declare function AppShell({ brand, navigation, navItems, currentNavId, na
11
11
  topbarVariant?: Exclude<HeaderVariant, "pill">;
12
12
  topbarDivider?: boolean;
13
13
  sidebarVariant?: SidebarVariant;
14
+ /** 0.32.0: a barra de rolagem da lateral da esquerda — o `scrollbar` da `Sidebar`. Padrão `hover` (clara, só com o
15
+ * ponteiro em cima); `visible` é a barra sempre à vista. */
16
+ sidebarScrollbar?: SidebarScrollbar;
17
+ /** 0.32.0 (DOC-01): a coluna da DIREITA — o "Nesta página" de uma documentação (um `TableOfContents`).
18
+ * Mora numa `Sidebar placement="right"` do mesmo desenho da da esquerda. De 1280 para cima é a
19
+ * terceira coluna; abaixo, desce para depois do conteúdo. */
20
+ aside?: ReactNode;
21
+ /** O nome da coluna da direita para o leitor de tela. Padrão: a frase `tocLabel` ("On this page"). */
22
+ asideLabel?: string;
23
+ /** 0.32.0: a variante da coluna da direita. Padrão: a mesma da esquerda (`sidebarVariant`). `plain`
24
+ * tira a caixa — os itens soltos na página, como no "On this page" da documentação da referência. */
25
+ asideVariant?: SidebarVariant;
14
26
  /** A lateral em trilha de ícones. Controlado: quem passa decide (e o `onSidebarCollapsedChange` avisa). */
15
27
  sidebarCollapsed?: boolean;
16
28
  /** 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. */
@@ -146,7 +146,7 @@ function useLargura(query) {
146
146
  return () => mq.removeEventListener?.("change", avisar);
147
147
  }, () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(query).matches, () => false);
148
148
  }
149
- export function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant = "floating", topbarDivider, sidebarVariant, sidebarCollapsed, sidebarCollapsible, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant = "surface", children, className, ...props }) {
149
+ export function AppShell({ brand, navigation, navItems, currentNavId, navLabel, topbar, topbarVariant = "floating", topbarDivider, sidebarVariant, sidebarScrollbar, sidebarCollapsed, sidebarCollapsible, defaultSidebarCollapsed, onSidebarCollapsedChange, contentVariant = "surface", aside, asideLabel, asideVariant, children, className, ...props }) {
150
150
  const s = useAureaStrings();
151
151
  useGavetaFechaNoDesktop();
152
152
  const controlado = sidebarCollapsed !== undefined;
@@ -180,7 +180,7 @@ export function AppShell({ brand, navigation, navItems, currentNavId, navLabel,
180
180
  // A condição vai escrita no `icon=` do botão, e não numa variável: é ali que o check 46 lê os
181
181
  // ícones que o shell desenha.
182
182
  const paraOComeco = !efetiva, direita = useDirection() === "rtl";
183
- return _jsxs("div", { className: cx("app-shell", topbarVariant === "flush" && "app-shell-flush", sidebarCollapsible && "app-shell-collapsible", className), ...props, children: [_jsx("a", { className: "skip-link", href: `#${SHELL_MAIN_ID}`, children: s.skipToContent }), _jsx(Header, { variant: topbarVariant, divider: topbarDivider, brand: _jsxs(_Fragment, { children: [_jsx(IconButton, { className: "nav-toggle", icon: "list", label: s.navigationToggle, popoverTarget: SHELL_NAV_ID }), brand] }), children: topbar }), sidebarCollapsible && _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, collapsed: efetiva, items: navItems, current: currentNavId, label: navLabel, onToggle: focoDaGaveta, children: navigation }), _jsx("main", { id: SHELL_MAIN_ID, tabIndex: -1, className: cx("content", contentVariant === "plain" && "content-plain"), children: children })] });
183
+ return _jsxs("div", { className: cx("app-shell", topbarVariant === "flush" && "app-shell-flush", sidebarCollapsible && "app-shell-collapsible", aside != null && "app-shell-with-aside", className), ...props, children: [_jsx("a", { className: "skip-link", href: `#${SHELL_MAIN_ID}`, children: s.skipToContent }), _jsx(Header, { variant: topbarVariant, divider: topbarDivider, brand: _jsxs(_Fragment, { children: [_jsx(IconButton, { className: "nav-toggle", icon: "list", label: s.navigationToggle, popoverTarget: SHELL_NAV_ID }), brand] }), children: topbar }), sidebarCollapsible && _jsx("div", { className: "sidebar-toggle-slot", children: _jsx(Tooltip, { content: rotulo, side: "right", children: _jsx(IconButton, { className: "sidebar-toggle", size: "xs", icon: paraOComeco === direita ? "caret-right" : "caret-left", label: rotulo, "aria-expanded": !efetiva, "aria-controls": SHELL_NAV_ID, onClick: alternar }) }) }), _jsx(Sidebar, { id: SHELL_NAV_ID, popover: "auto", variant: sidebarVariant, scrollbar: sidebarScrollbar, collapsed: efetiva, items: navItems, current: currentNavId, label: navLabel, onToggle: focoDaGaveta, children: navigation }), _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, children: aside })] });
184
184
  }
185
185
  export function Separator({ orientation, spacing = "none", className, ...props }) {
186
186
  const ancora = useRef(null);
package/dist/markup.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import React, { type HTMLAttributes, type InputHTMLAttributes, type ReactElement, type ReactNode, type RefAttributes, type TextareaHTMLAttributes } from "react";
1
+ import React, { type AnchorHTMLAttributes, type HTMLAttributes, type InputHTMLAttributes, type ReactElement, type ReactNode, type RefAttributes, type TextareaHTMLAttributes } from "react";
2
2
  import { type Responsive } from "./pure.js";
3
3
  import type { ComponentSize } from "./actions.js";
4
4
  import type { SidebarItem } from "./navigation-client.js";
@@ -15,7 +15,7 @@ type CardBase = HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> &
15
15
  accent?: CardAccent;
16
16
  };
17
17
  export type CardProps = CardBase & ({
18
- variant?: "base" | "raised" | "inset" | "selected" | "danger" | "contrast";
18
+ variant?: "base" | "raised" | "inset" | "outline" | "selected" | "danger" | "contrast";
19
19
  render?: ReactElement;
20
20
  } | {
21
21
  variant: "interactive";
@@ -24,12 +24,22 @@ export type CardProps = CardBase & ({
24
24
  export declare function Card({ variant, padding, orientation, accent, className, render, ...props }: CardProps): ReactElement<unknown, string | React.JSXElementConstructor<any>>;
25
25
  export declare namespace Card {
26
26
  export { CardMedia as Media };
27
+ export { CardHeader as Header };
28
+ export { CardTitle as Title };
29
+ export { CardDescription as Description };
30
+ export { CardContent as Content };
31
+ export { CardFooter as Footer };
27
32
  }
28
33
  /** A mídia do cartão — a primeira das partes da especificação do `Card` (A-14). No vertical,
29
34
  * primeira filha, ela SANGRA até a borda de cima e dos lados; no horizontal, fica à esquerda com a
30
35
  * largura de miniatura, dentro do respiro, com o raio que sai da conta da casa (ADR-0033: raio do
31
36
  * cartão menos o respiro dele). O que vai dentro — `Image`, vídeo — é do app. */
32
37
  declare function CardMedia({ className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement>): React.JSX.Element;
38
+ declare function CardHeader({ className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement>): React.JSX.Element;
39
+ declare function CardTitle({ className, ...props }: HTMLAttributes<HTMLHeadingElement> & RefAttributes<HTMLHeadingElement>): React.JSX.Element;
40
+ declare function CardDescription({ className, ...props }: HTMLAttributes<HTMLParagraphElement> & RefAttributes<HTMLParagraphElement>): React.JSX.Element;
41
+ declare function CardContent({ className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement>): React.JSX.Element;
42
+ declare function CardFooter({ className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement>): React.JSX.Element;
33
43
  export type LayoutGap = "tight" | "normal" | "loose";
34
44
  export type StackAlign = "start" | "center" | "end" | "stretch";
35
45
  export type ClusterAlign = "start" | "center" | "end" | "baseline";
@@ -132,6 +142,10 @@ export interface SectionProps extends HTMLAttributes<HTMLElement>, RefAttributes
132
142
  /** Só no `footer`: as colunas de links, cada uma com título. Os itens são `SidebarItem` (`id`, `label`, `href`, `render`). */
133
143
  links?: SectionFooterGroup[];
134
144
  /** Só no `footer`: a linha de baixo — direitos, termos, privacidade. */
145
+ /** Só no `footer` (15/10/2026): `"columns"` (o padrão, o rodapé de site grande) ou `"inline"` — UMA linha centrada, como
146
+ * o rodapé da página inicial da referência: a frase legal, os links (sem os títulos das colunas) e o que vier dentro
147
+ * (os ícones sociais). A marca não entra. */
148
+ layout?: "columns" | "inline";
135
149
  legal?: ReactNode;
136
150
  /** Só no `footer`: até onde o miolo cresce, pela escala do `Container`. Padrão: `xl`. */
137
151
  maxWidth?: ContainerSize;
@@ -143,7 +157,7 @@ export interface SectionProps extends HTMLAttributes<HTMLElement>, RefAttributes
143
157
  * O conteúdo vai dentro de um `Container`. Dê um nome à faixa (`aria-labelledby` no título dela)
144
158
  * quando ela for uma região que o leitor de tela deva listar.
145
159
  */
146
- export declare function Section({ surface, spacing, theme, variant, brand, links, legal, maxWidth, navLabel, children, className, ...props }: SectionProps): React.JSX.Element;
160
+ export declare function Section({ surface, spacing, theme, variant, brand, links, legal, layout, maxWidth, navLabel, children, className, ...props }: SectionProps): React.JSX.Element;
147
161
  export type KPIDirection = "up" | "down" | "flat";
148
162
  export type KPITone = "success" | "danger" | "neutral";
149
163
  export type KPIVariant = "card" | "plain";
@@ -182,9 +196,14 @@ export type TypographyWeight = "normal" | "medium" | "semibold" | "bold" | "extr
182
196
  export type TypographyAlign = "start" | "center" | "end" | "justify";
183
197
  export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
184
198
  export type ParagraphSize = "base" | "sm" | "xs";
199
+ /** A cor do texto com o NOME do nativo (DOC-11, os mesmos nomes na web e no nativo). `link` é o amarelo
200
+ * de ESCREVER (legível nos dois temas); `primary` é o de PREENCHER, e no tema claro quase some — como no
201
+ * nativo. As cores de estado são o par `-400` (ADR-0061). Vence o `color` quando os dois vêm. */
202
+ export type TypographyTone = "default" | "muted" | "subtle" | "primary" | "link" | "danger" | "success" | "warning" | "info";
185
203
  interface TypographyBase {
186
204
  align?: TypographyAlign;
187
205
  color?: TypographyColor;
206
+ tone?: TypographyTone;
188
207
  weight?: TypographyWeight;
189
208
  truncate?: boolean;
190
209
  /** GAR-16 (0.28.0): algarismos da mesma largura — para número que alinha em coluna (preço, ano,
@@ -194,26 +213,30 @@ interface TypographyBase {
194
213
  export interface TextProps extends Omit<HTMLAttributes<HTMLSpanElement>, "color">, RefAttributes<HTMLSpanElement>, TypographyBase {
195
214
  type?: TypographyType;
196
215
  }
197
- export declare function Text({ type, align, color, weight, truncate, numeric, className, ...props }: TextProps): React.JSX.Element;
216
+ export declare function Text({ type, align, color, tone, weight, truncate, numeric, className, ...props }: TextProps): React.JSX.Element;
198
217
  export interface HeadingProps extends Omit<HTMLAttributes<HTMLHeadingElement>, "color">, RefAttributes<HTMLHeadingElement>, TypographyBase {
199
218
  level?: HeadingLevel;
200
219
  }
201
- export declare function Heading({ level, align, color, weight, truncate, numeric, className, ...props }: HeadingProps): React.JSX.Element;
220
+ export declare function Heading({ level, align, color, tone, weight, truncate, numeric, className, ...props }: HeadingProps): React.JSX.Element;
202
221
  export interface ParagraphProps extends Omit<HTMLAttributes<HTMLParagraphElement>, "color">, RefAttributes<HTMLParagraphElement>, TypographyBase {
203
222
  size?: ParagraphSize;
204
223
  }
205
- export declare function Paragraph({ size, align, color, weight, truncate, numeric, className, ...props }: ParagraphProps): React.JSX.Element;
224
+ export declare function Paragraph({ size, align, color, tone, weight, truncate, numeric, className, ...props }: ParagraphProps): React.JSX.Element;
206
225
  export interface CodeProps extends Omit<HTMLAttributes<HTMLElement>, "color">, RefAttributes<HTMLElement>, TypographyBase {
207
226
  }
208
- export declare function Code({ align, color, weight, truncate, className, ...props }: CodeProps): React.JSX.Element;
209
- export type BadgeEmphasis = "soft" | "solid" | "outline";
227
+ export declare function Code({ align, color, tone, weight, truncate, className, ...props }: CodeProps): React.JSX.Element;
228
+ export type BadgeEmphasis = "soft" | "solid" | "outline" | "flat";
210
229
  export type BadgeSize = "xs" | "sm" | "md" | "lg";
211
230
  export type BadgePlacement = "top-end" | "top-start" | "bottom-end" | "bottom-start";
212
231
  export type BadgeFit = "auto" | "content";
213
232
  export declare function formatBadgeCount(count: number, max?: number): string;
214
233
  export interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, RefAttributes<HTMLSpanElement> {
215
234
  variant?: BadgeVariant;
216
- /** `soft` é o tom de sempre; `solid` preenche com o acento; `outline` é só contorno. */
235
+ /** A cor, com o NOME do nativo (DOC-11, 0.32.0: os mesmos nomes na web e no nativo). É o mesmo
236
+ * eixo do `variant`, e vence quando os dois vêm. */
237
+ tone?: BadgeVariant;
238
+ /** `soft` é o tom de sempre; `solid` preenche com o acento; `outline` é só contorno; `flat` (15/10/2026) é o tom de
239
+ * sempre SEM a linha em volta, como o selo da referência (que chamava essa forma de `flat`). */
217
240
  emphasis?: BadgeEmphasis;
218
241
  size?: BadgeSize;
219
242
  /** Ponto de estado antes do texto. Sozinho num `anchor`, ele É o badge. */
@@ -239,7 +262,7 @@ export interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, RefAttribut
239
262
  * Chama-se assim, e não `content`, porque este colide com o atributo HTML de mesmo nome. */
240
263
  badgeContent?: ReactNode;
241
264
  }
242
- export declare function Badge({ variant, emphasis, size, dot, leading, trailing, image, imageAlt, count, max, showZero, fit, anchor, anchorShape, invisible, badgeContent, children, className, ...props }: BadgeProps): React.JSX.Element;
265
+ export declare function Badge({ variant: variantProp, tone, emphasis, size, dot, leading, trailing, image, imageAlt, count, max, showZero, fit, anchor, anchorShape, invisible, badgeContent, children, className, ...props }: BadgeProps): React.JSX.Element;
243
266
  /** O tom da barra: a mesma lista fechada do `ButtonTone`. Pausado é `neutral`; falha é `danger`. */
244
267
  export type ProgressTone = "brand" | "neutral" | "success" | "warning" | "danger" | "info";
245
268
  export interface ProgressProps {
@@ -252,10 +275,21 @@ export interface ProgressProps {
252
275
  * que falta, bytes. Em texto, vai junto no `aria-valuetext`. */
253
276
  detail?: ReactNode;
254
277
  tone?: ProgressTone;
278
+ /** 0.32.0: o rótulo À MOSTRA, no alto à esquerda (o da barra da referência). Sem ele, o `label` só
279
+ * nomeia a barra para o leitor de tela, como sempre. */
280
+ showLabel?: boolean;
281
+ /** 0.32.0: o valor ("60%") no alto à direita, quando não há `detail`. */
282
+ showValue?: boolean;
283
+ /** A espessura do trilho: sm 4, md 8, lg 12 — os da referência. */
284
+ size?: ProgressSize;
255
285
  className?: string;
256
286
  }
257
- export declare function Progress({ value, label, detail, tone, className }: ProgressProps): React.JSX.Element;
258
- export declare function Skeleton({ className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement>): React.JSX.Element;
287
+ export type ProgressSize = "sm" | "md" | "lg";
288
+ export declare function Progress({ value, label, detail, tone, showLabel, showValue, size, className }: ProgressProps): React.JSX.Element;
289
+ export type SkeletonAnimation = "pulse" | "none";
290
+ export declare function Skeleton({ animation, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
291
+ animation?: SkeletonAnimation;
292
+ }): React.JSX.Element;
259
293
  export declare function AvatarGroup({ children, max, total, label, size, className }: {
260
294
  children: ReactNode;
261
295
  max?: number;
@@ -290,6 +324,24 @@ export interface HeaderProps extends HTMLAttributes<HTMLElement>, RefAttributes<
290
324
  actions?: ReactNode;
291
325
  /** Até onde o miolo da barra cresce, pela escala do `Container` (`sm` 640 … `2xl` 1536, `full`). */
292
326
  maxWidth?: ContainerSize;
327
+ /**
328
+ * Onde ficam os links (14/10/2026): `"end"` (o padrão) logo antes das ações, na outra ponta da marca; `"start"`
329
+ * colados na marca, com as ações na outra ponta — a página inicial da referência. O nome é o `justify` do
330
+ * conteúdo da barra dela.
331
+ */
332
+ itemsJustify?: "start" | "end";
333
+ /**
334
+ * A altura (15/10/2026): `"md"` (o padrão, 64 — a do guia de barra da referência) ou `"sm"` (56, a do topo da página
335
+ * inicial dela), com 6 entre as ações em vez de 8.
336
+ */
337
+ size?: "md" | "sm";
338
+ /**
339
+ * Só na `flush` (15/10/2026): o fundo transparente que EMBAÇA o que passa por baixo, como o topo da página inicial
340
+ * da referência. Quem pede menos transparência no sistema, ou o navegador sem desfoque, recebe o fundo cheio.
341
+ */
342
+ blurred?: boolean;
343
+ /** O que entra no MENU DO CELULAR, embaixo dos links (15/10/2026): o GitHub, a conta. Na barra larga não aparece. */
344
+ menuActions?: ReactNode;
293
345
  /** O nome da navegação para o leitor de tela. Padrão: `"Main"`. */
294
346
  navLabel?: string;
295
347
  /** O nome do botão de menu do celular. Padrão: `"Menu"`. */
@@ -297,12 +349,14 @@ export interface HeaderProps extends HTMLAttributes<HTMLElement>, RefAttributes<
297
349
  /** O `id` do painel do celular. Padrão: `"aurea-header-menu"`. Troque só se a página tiver dois cabeçalhos de site. */
298
350
  menuId?: string;
299
351
  }
300
- export declare function Header({ variant, divider, brand, items, current, actions, maxWidth, navLabel, menuLabel, menuId, children, className, ...props }: HeaderProps): React.JSX.Element;
352
+ export declare function Header({ variant, divider, brand, items, current, actions, maxWidth, itemsJustify, size, blurred, menuActions, navLabel, menuLabel, menuId, children, className, ...props }: HeaderProps): React.JSX.Element;
301
353
  /** @deprecated `Topbar` é o nome antigo do `Header` (07/10/2026). Continua funcionando, igual; use `Header`. */
302
354
  export declare function Topbar(props: HeaderProps): React.JSX.Element;
303
355
  export declare function Kbd({ children, className, ...props }: HTMLAttributes<HTMLElement> & RefAttributes<HTMLElement>): React.JSX.Element;
304
356
  export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, RefAttributes<HTMLTextAreaElement> {
305
357
  size?: Responsive<FieldSize>;
358
+ /** 0.32.0, a da referência: `secondary` é o fundo neutro, para o campo dentro de um cartão. */
359
+ variant?: FieldVariant;
306
360
  }
307
361
  export declare const Textarea: React.ForwardRefExoticComponent<Omit<TextareaProps, "ref"> & RefAttributes<HTMLTextAreaElement>>;
308
362
  export declare function Checkbox({ label, labelHidden, description, size, className, ...props }: Omit<InputHTMLAttributes<HTMLInputElement>, "size"> & RefAttributes<HTMLInputElement> & {
@@ -311,12 +365,17 @@ export declare function Checkbox({ label, labelHidden, description, size, classN
311
365
  description?: ReactNode;
312
366
  size?: Responsive<FieldSize>;
313
367
  }): React.JSX.Element;
314
- export declare function Radio({ label, size, className, ...props }: Omit<InputHTMLAttributes<HTMLInputElement>, "size"> & RefAttributes<HTMLInputElement> & {
368
+ export declare function Radio({ label, labelHidden, description, size, className, ...props }: Omit<InputHTMLAttributes<HTMLInputElement>, "size"> & RefAttributes<HTMLInputElement> & {
315
369
  label: ReactNode;
370
+ labelHidden?: boolean;
371
+ description?: ReactNode;
316
372
  size?: Responsive<FieldSize>;
317
373
  }): React.JSX.Element;
318
- export declare function Switch({ label, size, className, ...props }: Omit<InputHTMLAttributes<HTMLInputElement>, "size"> & RefAttributes<HTMLInputElement> & {
374
+ export declare function Switch({ label, labelHidden, description, indicatorPlacement, size, className, ...props }: Omit<InputHTMLAttributes<HTMLInputElement>, "size"> & RefAttributes<HTMLInputElement> & {
319
375
  label: ReactNode;
376
+ labelHidden?: boolean;
377
+ description?: ReactNode;
378
+ indicatorPlacement?: "start" | "end";
320
379
  size?: Responsive<FieldSize>;
321
380
  }): React.JSX.Element;
322
381
  export type RangeOrientation = "horizontal" | "vertical";
@@ -324,6 +383,7 @@ export declare function Range({ orientation, className, ...props }: InputHTMLAtt
324
383
  orientation?: Responsive<RangeOrientation>;
325
384
  }): React.JSX.Element;
326
385
  export type FieldSize = Extract<ComponentSize, "sm" | "md" | "lg">;
386
+ export type FieldVariant = "primary" | "secondary";
327
387
  export declare function Label({ htmlFor, className, children, ...props }: HTMLAttributes<HTMLLabelElement> & RefAttributes<HTMLLabelElement> & {
328
388
  htmlFor?: string;
329
389
  }): React.JSX.Element;
@@ -339,4 +399,64 @@ export declare function InputGroupAddon({ side, layout, className, children, ...
339
399
  export declare function AspectRatio({ ratio, className, style, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
340
400
  ratio?: number;
341
401
  }): React.JSX.Element;
402
+ export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement>, RefAttributes<HTMLAnchorElement> {
403
+ /** Abre noutra aba e mostra a seta. */
404
+ external?: boolean;
405
+ /** Não navega: sai sem `href` e com `aria-disabled`. */
406
+ disabled?: boolean;
407
+ }
408
+ export declare function Link({ external, disabled, href, target, rel, className, children, ...props }: LinkProps): React.JSX.Element;
409
+ export type ColorSwatchSize = "xs" | "sm" | "md" | "lg" | "xl";
410
+ export interface ColorSwatchProps extends HTMLAttributes<HTMLSpanElement>, RefAttributes<HTMLSpanElement> {
411
+ /** Qualquer cor do CSS: `#f0c200`, `oklch(…)`, `var(--primary)`. */
412
+ color: string;
413
+ size?: ColorSwatchSize;
414
+ /** O nome que o leitor de tela anuncia ("Amarelo Aurea"). Sem ele, o valor da cor. */
415
+ label?: string;
416
+ }
417
+ export interface ColorSwatchOption {
418
+ color: string;
419
+ label?: string;
420
+ /** Esta cor não se escolhe (as outras sim). */
421
+ disabled?: boolean;
422
+ }
423
+ /** O que as duas formas têm em comum: a escala. (É a base que o leitor da API segue em `base & (a | b)`.) */
424
+ export interface ColorSwatchBase {
425
+ size?: ColorSwatchSize;
426
+ }
427
+ export interface ColorSwatchPickerProps {
428
+ /** As cores para escolher — `"#0485f7"` ou `{color, label}`. É o que faz da amostra um grupo de escolha. */
429
+ options: readonly (string | ColorSwatchOption)[];
430
+ /** O nome do grupo no formulário, e o que faz das amostras UM grupo (as setas andam entre elas). */
431
+ name: string;
432
+ /** O nome do grupo para o leitor de tela ("Cor de destaque"). */
433
+ label: string;
434
+ value?: string;
435
+ defaultValue?: string;
436
+ /** O evento do navegador, como no `Radio`: `event.target.value` é a cor escolhida. */
437
+ onChange?: React.ChangeEventHandler<HTMLInputElement>;
438
+ /** `"grid"` (o padrão: em linha, quebrando) ou `"stack"` (em coluna), como na referência. */
439
+ layout?: "grid" | "stack";
440
+ /** A marca da escolhida, no lugar do "visto" (um `<Icon>`, por exemplo). Ela ganha a tinta que contrasta. */
441
+ indicator?: ReactNode;
442
+ /** O nome de cada cor embaixo dela (o `label` da opção; sem ele, o código), como a escolha de tema da referência. */
443
+ showLabels?: boolean;
444
+ size?: ColorSwatchSize;
445
+ disabled?: boolean;
446
+ id?: string;
447
+ className?: string;
448
+ }
449
+ export declare function ColorSwatch(props: ColorSwatchBase & (ColorSwatchProps | ColorSwatchPickerProps)): React.JSX.Element;
450
+ export type ProgressCircleSize = "sm" | "md" | "lg";
451
+ export interface ProgressCircleProps extends HTMLAttributes<HTMLDivElement>, RefAttributes<HTMLDivElement> {
452
+ /** De `min` a `max`. Sem ele, o círculo gira. */
453
+ value?: number;
454
+ min?: number;
455
+ max?: number;
456
+ size?: ProgressCircleSize;
457
+ tone?: ProgressTone;
458
+ /** O nome que o leitor de tela anuncia ("Enviando o arquivo"). */
459
+ label: string;
460
+ }
461
+ export declare function ProgressCircle({ value, min, max, size, tone, label, className, ...props }: ProgressCircleProps): React.JSX.Element;
342
462
  export {};
package/dist/markup.js CHANGED
@@ -37,6 +37,8 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
37
37
  // tocar motor. Na dúvida, ele NÃO entra — cliente a mais é lento, servidor a mais é quebrado.
38
38
  import React, { forwardRef } from "react";
39
39
  import { cx, fundirRender, peleDoEixo } from "./pure.js";
40
+ // As contas de cor são funções puras, sem estado e sem navegador (ADR-0069): o `ColorSwatch` usa a do contraste.
41
+ import { contrastingInk, hsbToRgb, parseColor } from "./color.js";
40
42
  export function Card({ variant = "base", padding = "normal", orientation = "vertical", accent, className, render, ...props }) {
41
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
44
  }
@@ -46,6 +48,19 @@ export function Card({ variant = "base", padding = "normal", orientation = "vert
46
48
  * cartão menos o respiro dele). O que vai dentro — `Image`, vídeo — é do app. */
47
49
  function CardMedia({ className, ...props }) { return _jsx("div", { className: cx("card-media", className), ...props }); }
48
50
  Card.Media = CardMedia;
51
+ // AS PARTES DO CARTÃO (15/10/2026, o Victor: "A, B, C, pode"), como as da referência: o cabeçalho (o título e a
52
+ // descrição, colados), o conteúdo (4 entre os itens) e o rodapé (em linha). 12 entre as partes, o vão dela — por margem,
53
+ // porque o `Card` da Aurea é um bloco e virar coluna mudaria quem já o usa. O título é um `h3`, como lá.
54
+ function CardHeader({ className, ...props }) { return _jsx("div", { className: cx("card-header", className), ...props }); }
55
+ function CardTitle({ className, ...props }) { return _jsx("h3", { className: cx("card-title", className), ...props }); }
56
+ function CardDescription({ className, ...props }) { return _jsx("p", { className: cx("card-description", className), ...props }); }
57
+ function CardContent({ className, ...props }) { return _jsx("div", { className: cx("card-content", className), ...props }); }
58
+ function CardFooter({ className, ...props }) { return _jsx("div", { className: cx("card-footer", className), ...props }); }
59
+ Card.Header = CardHeader;
60
+ Card.Title = CardTitle;
61
+ Card.Description = CardDescription;
62
+ Card.Content = CardContent;
63
+ Card.Footer = CardFooter;
49
64
  export function Stack({ gap, align, className, ...props }) { return _jsx("div", { className: cx("stack", gap && gap !== "normal" && `stack-gap-${gap}`, align && align !== "stretch" && `stack-align-${align}`, className), ...props }); }
50
65
  export function Cluster({ gap, align, justify, wrap, className, ...props }) { return _jsx("div", { className: cx("cluster", gap && gap !== "normal" && `cluster-gap-${gap}`, align && align !== "center" && `cluster-align-${align}`, justify && justify !== "start" && `cluster-justify-${justify}`, wrap === false && "cluster-nowrap", className), ...props }); }
51
66
  const GRID_MIN = new Set(["xs", "sm", "md", "lg"]);
@@ -80,10 +95,16 @@ export function Container({ size = "xl", className, ...props }) {
80
95
  // (`spacing`) e o tema próprio (`theme` — rodapé escuro numa página clara). Nenhuma referência da
81
96
  // fila tem um rodapé aberto; o desenho é da Aurea, com tokens que já existem. Os links de cada
82
97
  // coluna são `SidebarItem`, a mesma forma dos menus, e o `render` leva o link do roteador.
83
- export function Section({ surface = "background", spacing = "md", theme, variant = "base", brand, links, legal, maxWidth = "xl", navLabel = "Footer", children, className, ...props }) {
98
+ export function Section({ surface = "background", spacing = "md", theme, variant = "base", brand, links, legal, layout = "columns", maxWidth = "xl", navLabel = "Footer", children, className, ...props }) {
84
99
  const pele = cx("section", surface !== "background" && `section-${surface}`, spacing !== "md" && `section-spacing-${spacing}`);
85
100
  if (variant !== "footer")
86
101
  return _jsx("section", { "data-theme": theme, className: cx(pele, className), ...props, children: children });
102
+ if (layout === "inline") {
103
+ const itens = (links ?? []).flatMap((g) => g.items);
104
+ return _jsx("footer", { "data-theme": theme, className: cx(pele, "section-footer", "section-footer-inline", className), ...props, children: _jsxs("div", { className: cx("container", maxWidth !== "xl" && `container-${maxWidth}`, "section-footer-line"), children: [legal != null && _jsx("p", { className: "section-footer-inline-legal", children: legal }), itens.length > 0 && _jsx("nav", { "aria-label": navLabel, children: _jsx("ul", { className: "section-footer-inline-links", children: itens.map(it => _jsx("li", { children: it.render
105
+ ? fundirRender(it.render, { className: "section-footer-link", children: it.label }, "a")
106
+ : _jsx("a", { className: "section-footer-link", href: it.href, children: it.label }) }, it.id)) }) }), children] }) });
107
+ }
87
108
  return _jsx("footer", { "data-theme": theme, className: cx(pele, "section-footer", className), ...props, children: _jsxs("div", { className: cx("container", maxWidth !== "xl" && `container-${maxWidth}`), children: [_jsxs("div", { className: "section-footer-top", children: [brand != null && _jsx("div", { className: "section-footer-brand", children: brand }), links && links.length > 0 && _jsx("nav", { className: "section-footer-nav", "aria-label": navLabel, children: links.map((g, n) => _jsxs("div", { className: "section-footer-group", children: [_jsx("h2", { className: "section-footer-title", children: g.title }), _jsx("ul", { className: "section-footer-links", children: g.items.map(it => _jsx("li", { children: it.render
88
109
  ? fundirRender(it.render, { className: "section-footer-link", children: it.label }, "a")
89
110
  : _jsx("a", { className: "section-footer-link", href: it.href, children: it.label }) }, it.id)) })] }, n)) }), children] }), legal != null && _jsx("div", { className: "section-footer-legal", children: legal })] }) });
@@ -104,16 +125,17 @@ export function Timeline({ items }) { return _jsx("ol", { className: "timeline",
104
125
  // `dangerouslySetInnerHTML` tem de SANITIZAR antes. A Aurea desenha o texto; ela não pode decidir
105
126
  // o que é seguro renderizar. Está dito na ficha, em voz alta.
106
127
  export function Prose({ className, ...props }) { return _jsx("div", { className: cx("prose", className), ...props }); }
107
- const tipografia = (tipo, { align, color, weight, truncate, numeric }, className) => cx("typography", `typography-${tipo}`, color === "muted" && "typography-muted", weight && `typography-weight-${weight}`, align && `typography-align-${align}`, truncate && "typography-truncate", numeric && "typography-numeric", className);
108
- export function Text({ type = "body", align, color, weight, truncate, numeric, className, ...props }) { return _jsx("span", { className: tipografia(type, { align, color, weight, truncate, numeric }, className), ...props }); }
128
+ const tipografia = (tipo, { align, color, tone, weight, truncate, numeric }, className) => cx("typography", `typography-${tipo}`, (tone ?? color) === "muted" && "typography-muted", tone && tone !== "default" && tone !== "muted" && `typography-tone-${tone}`, weight && `typography-weight-${weight}`, align && `typography-align-${align}`, truncate && "typography-truncate", numeric && "typography-numeric", className);
129
+ export function Text({ type = "body", align, color, tone, weight, truncate, numeric, className, ...props }) { return _jsx("span", { className: tipografia(type, { align, color, tone, weight, truncate, numeric }, className), ...props }); }
109
130
  // O nível decide o elemento E o tamanho, como na referência: um `h2` tem a cara de título 2.
110
- export function Heading({ level = 1, align, color, weight, truncate, numeric, className, ...props }) { const Tag = `h${level}`; return _jsx(Tag, { className: tipografia(`h${level}`, { align, color, weight, truncate, numeric }, className), ...props }); }
111
- export function Paragraph({ size = "base", align, color, weight, truncate, numeric, className, ...props }) { return _jsx("p", { className: tipografia(size === "base" ? "body" : `body-${size}`, { align, color, weight, truncate, numeric }, className), ...props }); }
112
- export function Code({ align, color, weight, truncate, className, ...props }) { return _jsx("code", { className: tipografia("code", { align, color, weight, truncate }, className), ...props }); }
131
+ export function Heading({ level = 1, align, color, tone, weight, truncate, numeric, className, ...props }) { const Tag = `h${level}`; return _jsx(Tag, { className: tipografia(`h${level}`, { align, color, tone, weight, truncate, numeric }, className), ...props }); }
132
+ export function Paragraph({ size = "base", align, color, tone, weight, truncate, numeric, className, ...props }) { return _jsx("p", { className: tipografia(size === "base" ? "body" : `body-${size}`, { align, color, tone, weight, truncate, numeric }, className), ...props }); }
133
+ export function Code({ align, color, tone, weight, truncate, className, ...props }) { return _jsx("code", { className: tipografia("code", { align, color, tone, weight, truncate }, className), ...props }); }
113
134
  // `max` com `+` é o idioma universal do contador (três das referências o usam). Exportada porque quem
114
135
  // escreve o nome acessível precisa do MESMO texto — "99+ unread" tem de bater com o que se vê.
115
136
  export function formatBadgeCount(count, max = 99) { return count > max ? `${max}+` : String(count); }
116
- export function Badge({ variant = "neutral", emphasis = "soft", size = "md", dot, leading, trailing, image, imageAlt, count, max = 99, showZero, fit = "auto", anchor, anchorShape = "square", invisible, badgeContent, children, className, ...props }) {
137
+ export function Badge({ variant: variantProp = "neutral", tone, emphasis = "soft", size = "md", dot, leading, trailing, image, imageAlt, count, max = 99, showZero, fit = "auto", anchor, anchorShape = "square", invisible, badgeContent, children, className, ...props }) {
138
+ const variant = tone ?? variantProp;
117
139
  const numero = count != null ? formatBadgeCount(count, max) : undefined;
118
140
  const miolo = anchor ? (numero ?? badgeContent) : (numero ?? children);
119
141
  // Ponto puro: `dot` sem nada para mostrar. Aí o badge não tem conteúdo, e ganha medida própria.
@@ -131,7 +153,7 @@ export function Badge({ variant = "neutral", emphasis = "soft", size = "md", dot
131
153
  // AN-07 (03/10/2026). Tudo novo é acréscimo: com `value` e sem `detail` nem `tone`, a marcação é a
132
154
  // de antes, mais a classe da caixa de fora. A anatomia é a da barra de progresso da referência: a
133
155
  // saída no alto à direita, o trilho embaixo, e sem `aria-valuenow` quando não há total.
134
- export function Progress({ value, label, detail, tone = "brand", className }) {
156
+ export function Progress({ value, label, detail, tone = "brand", showLabel, showValue, size = "md", className }) {
135
157
  const semTotal = value == null || Number.isNaN(value);
136
158
  const pct = semTotal ? undefined : Math.max(0, Math.min(100, value));
137
159
  const temApoio = detail != null && detail !== false && detail !== "";
@@ -139,9 +161,14 @@ export function Progress({ value, label, detail, tone = "brand", className }) {
139
161
  // vezes. Apoio que não é texto (um ícone, um link) fica onde está, para o leitor achar sozinho.
140
162
  const emTexto = temApoio && (typeof detail === "string" || typeof detail === "number") ? String(detail) : undefined;
141
163
  const valuetext = emTexto == null ? undefined : pct == null ? emTexto : `${pct}%, ${emTexto}`;
142
- return _jsxs("div", { className: cx("progress-field", className), children: [temApoio && _jsx("div", { className: "progress-detail", "aria-hidden": emTexto != null || undefined, children: detail }), _jsx("div", { className: cx("progress", semTotal && "progress-indeterminate", tone !== "brand" && `progress-tone-${tone}`), role: "progressbar", "aria-label": label, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": pct, "aria-valuetext": valuetext, children: _jsx("span", { style: pct == null ? undefined : { width: `${pct}%` } }) })] });
164
+ // O rótulo à mostra sai do leitor de tela (`aria-hidden`): quem nomeia a barra continua o `aria-label`,
165
+ // com o mesmo texto — sem isso, o leitor o leria duas vezes. (Este arquivo não usa hook, então nada de
166
+ // id gerado para `aria-labelledby`.)
167
+ const rotuloVisivel = !!showLabel && !!label;
168
+ const valor = !temApoio && showValue && pct != null ? `${Math.round(pct)}%` : undefined;
169
+ return _jsxs("div", { className: cx("progress-field", className), children: [rotuloVisivel && _jsx("span", { className: "progress-label", "aria-hidden": "true", children: label }), temApoio && _jsx("div", { className: "progress-detail", "aria-hidden": emTexto != null || undefined, children: detail }), valor && _jsx("div", { className: "progress-detail", "aria-hidden": "true", children: valor }), _jsx("div", { className: cx("progress", semTotal && "progress-indeterminate", tone !== "brand" && `progress-tone-${tone}`, size !== "md" && `progress-${size}`), role: "progressbar", "aria-label": label, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": pct, "aria-valuetext": valuetext, children: _jsx("span", { style: pct == null ? undefined : { width: `${pct}%` } }) })] });
143
170
  }
144
- export function Skeleton({ className, ...props }) { return _jsx("div", { className: cx("skeleton", className), "aria-hidden": "true", ...props }); }
171
+ export function Skeleton({ animation = "pulse", className, ...props }) { return _jsx("div", { className: cx("skeleton", animation === "none" && "skeleton-static", className), "aria-hidden": "true", ...props }); }
145
172
  // ── Identity ─────────────────────────────────────────────────────────────────────────────────
146
173
  // `React.Children` não é hook — é utilitário de leitura de `children`, e roda no servidor.
147
174
  export function AvatarGroup({ children, max, total, label, size, className }) {
@@ -169,10 +196,10 @@ function linksDoHeader(items, current) {
169
196
  return _jsx("li", { children: it.render ? fundirRender(it.render, p, "a") : _jsx("a", { href: it.href, ...p }) }, it.id);
170
197
  }) });
171
198
  }
172
- export function Header({ variant = "floating", divider, brand, items, current, actions, maxWidth, navLabel = "Main", menuLabel = "Menu", menuId = "aurea-header-menu", children, className, ...props }) {
199
+ 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", children, className, ...props }) {
173
200
  const site = !!items && items.length > 0;
174
- 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" }) }), _jsx("nav", { id: menuId, popover: "auto", className: "topbar-menu-panel", "aria-label": navLabel, children: linksDoHeader(items, current) })] })] });
175
- return _jsx("header", { className: cx("topbar", `topbar-${variant}`, divider && variant === "flush" && "topbar-divider", site && "topbar-site", maxWidth && "topbar-contained", className), ...props, children: maxWidth ? _jsx("div", { className: cx("container", maxWidth !== "xl" && `container-${maxWidth}`, "topbar-inner"), children: miolo }) : miolo });
201
+ 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 })] })] })] });
202
+ 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", className), ...props, children: maxWidth ? _jsx("div", { className: cx("container", maxWidth !== "xl" && `container-${maxWidth}`, "topbar-inner"), children: miolo }) : miolo });
176
203
  }
177
204
  /** @deprecated `Topbar` é o nome antigo do `Header` (07/10/2026). Continua funcionando, igual; use `Header`. */
178
205
  export function Topbar(props) { return _jsx(Header, { ...props }); }
@@ -180,13 +207,25 @@ export function Topbar(props) { return _jsx(Header, { ...props }); }
180
207
  // Kbd — representação de tecla/atalho. <kbd> é o elemento HTML certo; a pele é nossa. Ele já
181
208
  // morava fora da casa dele (no `internal.tsx`, por causa do `Button`); agora mora aqui, pelo
182
209
  // mesmo motivo elevado a regra.
183
- export function Kbd({ children, className, ...props }) { return _jsx("kbd", { className: cx("kbd", className), ...props, children: children }); }
184
- export const Textarea = forwardRef(function Textarea({ className, size, ...props }, ref) { return _jsx("textarea", { ref: ref, className: cx("textarea", peleDoEixo("textarea", size), className), ...props }); });
210
+ // 0.32.0: uma tecla de UM caractere ("K", "⌘", "/") sai redonda (`kbd-single`), e uma palavra
211
+ // ("Esc", "Enter") em cápsula — o canto da Aurea sobre a medida da referência. Conta-se o que a
212
+ // pessoa vê (`Array.from` não parte um emoji ao meio); conteúdo que não é texto fica em cápsula.
213
+ const umCaractere = (c) => (typeof c === "string" || typeof c === "number") && Array.from(String(c).trim()).length === 1;
214
+ export function Kbd({ children, className, ...props }) { return _jsx("kbd", { className: cx("kbd", umCaractere(children) && "kbd-single", className), ...props, children: children }); }
215
+ 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 }); });
185
216
  // `size` nos três marcáveis pela mesma razão do campo: uma linha de formulário com um campo `sm`
186
217
  // e um checkbox de tamanho fixo ao lado desalinha. O degrau vai na MARCA, não no rótulo.
187
218
  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 })] })] })] }); }
188
- export function Radio({ label, size, className, ...props }) { return _jsxs("label", { className: cx("radio", className), children: [_jsx("input", { type: "radio", ...props }), _jsx("span", { className: cx("control-mark", peleDoEixo("control-mark", size)) }), label] }); }
189
- export function Switch({ label, size, className, ...props }) { return _jsxs("label", { className: cx("switch", className), children: [_jsx("input", { type: "checkbox", role: "switch", ...props }), _jsx("span", { className: cx("switch-track", peleDoEixo("switch-track", size)) }), _jsx("span", { children: label })] }); }
219
+ // `description` no `Radio` e no `Switch` (15/10/2026, a referência tem nos dois): a linha apagada embaixo do nome, do
220
+ // mesmo jeito do `Checkbox`. Sem ela, a marcação é a de sempre.
221
+ const comDescricao = (label, description) => description ? _jsxs("span", { children: [_jsx("strong", { children: label }), _jsx("br", {}), _jsx("span", { className: "muted", children: description })] }) : label;
222
+ // `labelHidden` (15/10/2026) no `Radio` e no `Switch`, o mesmo do `Checkbox`: o nome sai da tela e fica para o leitor
223
+ // de tela — a fileira de controles sem rótulo da vitrine da referência.
224
+ export function Radio({ label, labelHidden, description, size, className, ...props }) { return _jsxs("label", { className: cx("radio", labelHidden && "radio-bare", className), children: [_jsx("input", { type: "radio", ...props }), _jsx("span", { className: cx("control-mark", peleDoEixo("control-mark", size)) }), labelHidden ? _jsx("span", { className: "sr-only", children: comDescricao(label, description) }) : comDescricao(label, description)] }); }
225
+ // `indicatorPlacement` (15/10/2026, o Victor: "A sim"): a chave no FIM, como o "Allow notifications" da vitrine da
226
+ // referência — o nome e a descrição à esquerda. O mesmo nome do `RadioGroup` do nativo. Muda só a ordem do DESENHO: o
227
+ // campo escondido continua logo antes da chave (o CSS do estado depende disso), e o rótulo é um só para o leitor.
228
+ export function Switch({ label, labelHidden, description, indicatorPlacement = "start", size, className, ...props }) { return _jsxs("label", { className: cx("switch", labelHidden && "switch-bare", indicatorPlacement === "end" && "switch-end", className), children: [_jsx("input", { type: "checkbox", role: "switch", ...props }), _jsx("span", { className: cx("switch-track", peleDoEixo("switch-track", size)) }), _jsx("span", { className: labelHidden ? "sr-only" : undefined, children: comDescricao(label, description) })] }); }
190
229
  export function Range({ orientation, className, ...props }) { return _jsx("input", { className: cx("range", peleDoEixo("range", orientation, "horizontal", "range"), className), type: "range", ...props }); }
191
230
  // `md` é a classe base — não existe `.input-md`, como não existe `.btn-md`. O prefixo é escrito
192
231
  // literal em cada chamada (`input-${size}`, e não `${base}-${size}`) porque é assim que o check 15
@@ -228,3 +267,34 @@ export function InputGroupAddon({ side = "start", layout = "inline", className,
228
267
  // escreve o `padding-top: 56.25%` de 2015, ou esquece o `min-width: 0` que impede a caixa de
229
268
  // estourar dentro de um grid.
230
269
  export function AspectRatio({ ratio = 1, className, style, ...props }) { return _jsx("div", { className: cx("aspect-ratio", className), style: { aspectRatio: ratio, ...style }, ...props }); }
270
+ export function Link({ external, disabled, href, target, rel, className, children, ...props }) {
271
+ return _jsxs("a", { className: cx("link", className), href: disabled ? undefined : href, "aria-disabled": disabled || undefined, target: external ? target ?? "_blank" : target, rel: external ? rel ?? "noopener noreferrer" : rel, ...props, children: [children, external && _jsx("span", { className: "link-external", "aria-hidden": "true" })] });
272
+ }
273
+ // Transparente quando o texto diz alfa abaixo de 1 (hex de 4 ou 8 dígitos, `rgba()`, `hsla()`…). Cor de token ou
274
+ // `oklch()` a marcação não lê: fica sem xadrez.
275
+ const transparente = (cor) => { const c = parseColor(cor); return c !== null && c.a < 1; };
276
+ export function ColorSwatch(props) {
277
+ if ("options" in props) {
278
+ const { options, name, label, value, defaultValue, onChange, layout = "grid", indicator, showLabels, size = "md", disabled, id, className } = props;
279
+ // O `onChange` é o do CONSUMIDOR, repassado, como no `Checkbox` e no `Radio` desta casa: nenhum manipulador nosso
280
+ // é escrito aqui (a marcação continua de servidor). Vai por espalhamento, como lá.
281
+ // `showLabels` (14/10/2026): o rótulo passa a ser a amostra E o nome embaixo — o círculo continua o mesmo
282
+ // (`.color-swatch-option`, agora um `span`), e clicar no nome também escolhe. O nome é só para os olhos: o leitor
283
+ // de tela já ouve o `aria-label` do botão de opção.
284
+ 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) => {
285
+ const op = typeof o === "string" ? { color: o } : o;
286
+ const cor = parseColor(op.color), rgb = cor && hsbToRgb(cor);
287
+ 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);
288
+ return showLabels
289
+ ? _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)
290
+ : circulo("label", op.color);
291
+ }) });
292
+ }
293
+ const { color, size = "md", label, className, style, ...resto } = props;
294
+ 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 });
295
+ }
296
+ export function ProgressCircle({ value, min = 0, max = 100, size = "md", tone = "brand", label, className, ...props }) {
297
+ const semTotal = value == null || Number.isNaN(value);
298
+ const pct = semTotal ? 25 : Math.max(0, Math.min(100, (value - min) / (max - min) * 100));
299
+ return _jsx("div", { role: "progressbar", "aria-label": label, "aria-valuemin": semTotal ? undefined : min, "aria-valuemax": semTotal ? undefined : max, "aria-valuenow": semTotal ? undefined : value, className: cx("progress-circle", size !== "md" && `progress-circle-${size}`, tone !== "brand" && `progress-circle-${tone}`, semTotal && "progress-circle-indeterminate", className), ...props, children: _jsxs("svg", { viewBox: "0 0 36 36", "aria-hidden": "true", children: [_jsx("circle", { className: "progress-circle-track", cx: "18", cy: "18", r: "16" }), _jsx("circle", { className: "progress-circle-fill", cx: "18", cy: "18", r: "16", pathLength: 100, strokeDasharray: "100", strokeDashoffset: 100 - pct })] }) });
300
+ }