@aurea-uds/react 0.5.0 → 0.6.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/pure.d.ts CHANGED
@@ -1,8 +1,17 @@
1
+ import { type ReactElement } from "react";
1
2
  export declare const cx: (...v: Array<string | false | null | undefined>) => string;
3
+ export declare function fundirRender(render: ReactElement | undefined, props: {
4
+ className?: string;
5
+ } & object, padrao?: string): ReactElement;
6
+ export type AureaTheme = "dark" | "light";
7
+ export type AureaDensity = "compact" | "comfortable" | "spacious";
2
8
  export type UniversalState = "waiting_user" | "waiting_approval" | "waiting_dependency" | "offline" | "stale" | "partial" | "degraded";
3
9
  export declare const universalStates: readonly UniversalState[];
4
10
  export declare const stateSeverity: (state: UniversalState) => "info" | "warning";
5
11
  export interface AureaStrings {
12
+ passwordShow: string;
13
+ passwordHide: string;
14
+ skipToContent: string;
6
15
  close: string;
7
16
  confirmCancel: string;
8
17
  dataError: string;
@@ -168,6 +177,95 @@ export interface AureaStrings {
168
177
  export declare const defaultStrings: AureaStrings;
169
178
  export declare const ptBR: AureaStrings;
170
179
  export declare const defaultSpriteUrl = "/aurea-icons.svg";
180
+ /** Os pontos da escala vêm de `escala.tsx`, que é GERADO da mesma leitura dos tokens que produz
181
+ * as `@media`/`@container` do core. Até 22/08/2026 eles eram escritos aqui à mão, e isso era
182
+ * seguro só enquanto ninguém comparava largura em JavaScript. Com o resolvedor de runtime do
183
+ * `G-AXIS-06` deixou de ser: número repetido em CSS, tipo, `matchMedia` e observer são quatro
184
+ * lugares para divergir. Agora há um. */
185
+ export type { Breakpoint, ContainerBreakpoint } from "./escala.js";
186
+ export { ESCALA, ESCALA_CONTAINER } from "./escala.js";
187
+ import type { Breakpoint, ContainerBreakpoint } from "./escala.js";
188
+ /** O valor, e SÓ o valor.
189
+ *
190
+ * Todo callback de mudança do Base UI é chamado com DOIS argumentos — `(valor, eventDetails)` —
191
+ * e a Aurea declara um só. Repassar o callback do consumidor cru ao motor entrega esse segundo
192
+ * argumento de brinde: um objeto de evento do motor vazando por uma API pública que promete não
193
+ * tê-lo. Em TypeScript isso é INVISÍVEL, porque argumento a mais nunca é erro de tipo — o que
194
+ * torna o defeito silencioso e a assinatura, mentirosa.
195
+ *
196
+ * O custo real é acoplamento: quem escrever `onValueChange={(v, e) => …}` passa a depender do
197
+ * formato do evento de UMA versão do Base UI, e a Aurea deixa de poder trocar de motor sem
198
+ * quebrar consumidor. O `G-API-02` já tinha corrigido isso UMA vez, no `onCheckedChange` do item
199
+ * de menu, sem perguntar quem mais tinha o mesmo problema. Tinham outros SETE — medidos com
200
+ * `grep -noE "on(Value|Pressed|Checked|Open|InputValue)Change=\{on[A-Za-z]+\}"` e conferidos um
201
+ * a um contra o `.d.ts` do motor, que declara `eventDetails` nos sete.
202
+ *
203
+ * Devolve `undefined` quando não há callback, para o motor continuar distinguindo "sem handler"
204
+ * de "handler que não faz nada". */
205
+ export declare function soOValor<T>(fn: ((v: T) => void) | undefined): ((v: T) => void) | undefined;
206
+ export type Orientation = "horizontal" | "vertical";
207
+ /** Um valor que pode ser simples, responsivo por VIEWPORT ou adaptativo por CONTAINER.
208
+ *
209
+ * Os dois últimos são MUTUAMENTE EXCLUSIVOS por tipo (`never` no ramo oposto), e é decisão: um
210
+ * valor que reage aos dois ao mesmo tempo teria precedência ambígua, e a API deixaria de dizer a
211
+ * que ele responde — que é exatamente o que não pode acontecer. Quem precisa dos dois tem uma
212
+ * pergunta de desenho para responder, não um default para herdar. */
213
+ export type Responsive<T extends string> = T | {
214
+ base: T;
215
+ viewport: Partial<Record<Breakpoint, T>>;
216
+ container?: never;
217
+ } | {
218
+ base: T;
219
+ container: Partial<Record<ContainerBreakpoint, T>>;
220
+ viewport?: never;
221
+ };
222
+ /** O valor BASE de um responsivo — o que vale antes de qualquer ponto da escala, e o que um
223
+ * ambiente sem suporte a `@container` continua mostrando. */
224
+ export declare function valorBase<T extends string>(v: Responsive<T> | undefined): T | undefined;
225
+ /** `true` quando o valor pede a camada genérica (`size-*`) em vez da classe do componente. */
226
+ export declare function ehResponsivo<T extends string>(v: Responsive<T> | undefined): boolean;
227
+ /** As classes de um valor responsivo, para um eixo da camada compartilhada.
228
+ *
229
+ * `eixo` é o nome da família de regras no core (hoje só `size`), e não o nome do componente: a
230
+ * camada é genérica de propósito — a explosão combinatória (passos × pontos) fica lá, uma vez,
231
+ * em vez de uma vez por peça.
232
+ *
233
+ * Devolve `""` para valor simples: nesse caso o componente segue emitindo a própria classe
234
+ * (`btn-sm`), que produz exatamente o mesmo computado. É o que mantém a mudança SOMATIVA — nenhum
235
+ * consumidor existente muda de classe, e nenhuma baseline de pixel se mexe. */
236
+ export declare function classesResponsivas<T extends string>(eixo: string, v: Responsive<T> | undefined): string;
237
+ /** A PELE DE UM VALOR DE EIXO, para qualquer família e qualquer eixo.
238
+ *
239
+ * Chamava-se `peleDeTamanho` até 22/08/2026, quando o eixo `orientation` entrou pela mesma
240
+ * camada e o nome passou a mentir: a regra sempre foi "valor simples devolve a classe do
241
+ * componente, valor responsivo devolve a camada genérica", e isso não tem nada de específico
242
+ * de tamanho. O check 15 do validate.py lê o PRIMEIRO argumento desta função para saber que
243
+ * classes o core pode legitimamente conter — se ela for renomeada de novo, ele muda junto.
244
+ *
245
+ * Estava em `inputs.tsx` como função de módulo e servia só à família de campo. Subiu para cá ao
246
+ * fechar as três famílias restantes do `G-AXIS-04` (marcação, identidade, glifo), porque a regra
247
+ * é uma só e escrevê-la de novo em cada módulo é o "47 adaptações manuais independentes" que o
248
+ * Victor proibiu.
249
+ *
250
+ * `padrao` existe porque o degrau BASE não é `md` em toda família: o do Spinner é `sm`, e o core
251
+ * reflete isso (`.spinner` já É o `sm`, e quem tem classe própria é o `md`). Presumir `md` como
252
+ * base universal é o erro que esta atividade já cometeu duas vezes — uma no padding do campo,
253
+ * outra na escala de glifo. Aqui ele é PARÂMETRO.
254
+ *
255
+ * Valor simples devolve a classe de sempre (`input-sm`, `icon-lg`), byte por byte; valor
256
+ * responsivo devolve a camada.
257
+ *
258
+ * `eixo` é a FAMÍLIA DE CLASSES da camada responsiva, e ela não é sempre a mesma que `base`.
259
+ * No `size` os degraus são valores compartilhados, então a família é uma só (`size-lg`) e o
260
+ * default serve. Em `orientation` as regras são de cada componente — um `btn-group` vertical
261
+ * não se parece com um `field` horizontal —, então a família é a do componente e a chamada
262
+ * passa `base` de novo.
263
+ *
264
+ * Consequência aceita: no eixo de orientação a classe do valor BASE (`btn-group-horizontal`)
265
+ * é emitida sem ter regra no core, porque horizontal é o desenho de partida. Classe sem regra
266
+ * não custa nada e mantém a forma da camada uniforme; o inverso — regra sem componente — é que
267
+ * seria defeito, e é o que o check 15 pega. */
268
+ export declare function peleDoEixo<T extends string>(base: string, valor: Responsive<T> | undefined, padrao?: string, eixo?: string): string | false;
171
269
  export interface GridState {
172
270
  sorting?: Array<{
173
271
  id: string;
package/dist/pure.js CHANGED
@@ -14,17 +14,49 @@
14
14
  //
15
15
  // `.tsx` sem JSX de propósito: os checks 11, 19 e 26 varrem `packages/react/src/*.tsx`, e um
16
16
  // `.ts` aqui seria um arquivo que gate nenhum enxerga.
17
+ import { cloneElement, createElement } from "react";
17
18
  export const cx = (...v) => v.filter(Boolean).join(" ");
19
+ // ── `render`: a superfície é da Aurea, o ELEMENTO é de quem consome ───────────────────────────
20
+ //
21
+ // Nasceu do `G-A11Y-11`. O `Card` oferecia `variant="interactive"` — ponteiro de mão, elevação
22
+ // no hover, e a descrição do próprio pattern dizendo *"carries the hover and the focus ring"* —
23
+ // sobre uma `<div>` que não recebe foco nenhum. Falha de WCAG 2.1.1, e a mesma forma do
24
+ // `G-A11Y-10`: a intenção estava escrita e a implementação a contradizia.
25
+ //
26
+ // A saída NÃO é `tabIndex={0}` na `<div>`. Uma superfície clicável pode prometer duas coisas
27
+ // diferentes, e elas exigem elementos diferentes:
28
+ //
29
+ // AÇÃO clicar faz algo aqui → <button>
30
+ // NAVEGAÇÃO clicar leva a outro lugar → <a href>
31
+ //
32
+ // O componente não pode adivinhar qual: escolher `<button>` sempre quebraria abrir-em-nova-aba
33
+ // num cartão-link, e `tabIndex` numa `<div>` daria foco sem papel, sem tecla e sem nome
34
+ // acessível — verde no gate e inútil para quem usa leitor de tela.
35
+ //
36
+ // Então quem sabe decide. `render` recebe o ELEMENTO e a Aurea funde a pele nele. É o idioma que
37
+ // o `DropdownMenu`, o `Popover` e o `Combobox` já usam com a Base UI (`render={<Button/>}`), e é
38
+ // a primeira parcela do `G-API-02` — o padrão "o motor entrega e a Aurea não passa adiante".
39
+ export function fundirRender(render, props, padrao = "div") {
40
+ if (!render)
41
+ return createElement(padrao, props);
42
+ // As props do elemento de quem chama vêm DEPOIS das nossas, para que ele possa sobrescrever
43
+ // qualquer uma — e a classe é concatenada em vez de substituída, na mesma ordem do `cx` em
44
+ // todo componente da casa: a pele primeiro, o ajuste de quem usa depois.
45
+ const dele = (render.props ?? {});
46
+ return cloneElement(render, {
47
+ ...props, ...dele, className: cx(props.className, dele.className),
48
+ });
49
+ }
18
50
  export const universalStates = ["waiting_user", "waiting_approval", "waiting_dependency", "offline", "stale", "partial", "degraded"];
19
51
  // Nenhum dos sete é FALHA: nos sete a tela AINDA SERVE, e é isso que os separa de `error`. Por
20
52
  // isso o teto de gravidade é `warning` e `danger` não aparece — quem espera é informado, quem
21
53
  // perdeu qualidade é avisado. Um `role="alert"` aqui interromperia o leitor de tela por uma
22
54
  // condição que não pede ação imediata, que é o oposto do que o papel serve.
23
55
  export const stateSeverity = (state) => state.startsWith("waiting_") ? "info" : "warning";
24
- export const defaultStrings = { close: "Close", confirmCancel: "Cancel", dataError: "This could not be loaded.", dataEmpty: "Nothing here yet", confirmProceed: "Continue", paginationLabel: "Pagination", previous: "Previous", next: "Next", breadcrumbLabel: "Breadcrumb", tabsLabel: "Tabs", optionsLabel: "Options", tableLabel: "Table", commandLabel: "Command palette", commandPlaceholder: "Type a command…", dismissNotification: "Dismiss notification", toolbarLabel: "Toolbar", loading: "Loading", otpDigit: "Digit", stepperLabel: "Steps", increment: "Increase", decrement: "Decrease", comboboxEmpty: "No results", comboboxClear: "Clear selection", comboboxOpen: "Open list", comboboxRemove: "Remove", comboboxLoading: "Loading…", fileDropPrompt: "Drag files here or click to select", fileAdded: "File added", fileRemoved: "File removed", fileRemove: "Remove", fileTooLarge: "File exceeds the size limit", fileWrongType: "File type not allowed", treeLabel: "Tree", notificationsLabel: "Notifications", notificationMarkAll: "Mark all as read", notificationEmpty: "No notifications", notificationUnread: "Unread", notificationNew: "new notifications", dataGridFilter: "Filter", dataGridEmpty: "No results", dataGridSelectAll: "Select all rows", dataGridSelectRow: "Select row", dataGridSelected: "selected", dataGridClearSelection: "Clear selection", dataGridBulkLabel: "Bulk actions", dataGridColumns: "Columns", dataGridResize: "Resize column", dataGridStale: "Showing data that may be out of date.", dataGridPartial: "Some rows could not be loaded. What you see is incomplete.", dataGridError: "The rows could not be loaded.", dataGridDetails: "Details", dataGridDetailPanel: "Row detail", dataGridExport: "Export", dataGridExportRows: "rows", dataGridExportFiltered: "filtered rows", dataGridExportSelected: "selected rows", mediaPlayer: "Media player", mediaPlay: "Play", mediaPause: "Pause", mediaMute: "Mute", mediaUnmute: "Unmute", mediaSeek: "Seek", mediaVolume: "Volume", mediaCaptionsShow: "Show captions", mediaCaptionsHide: "Hide captions", mediaSkipBack: "Skip back 10 seconds", mediaSkipForward: "Skip forward 10 seconds", mediaFullscreenEnter: "Enter full screen", mediaFullscreenExit: "Exit full screen", carouselLabel: "Carousel", carouselSlide: "Slide", positionOf: "of", carouselPrev: "Previous slide", carouselNext: "Next slide", galleryLabel: "Gallery", sortableLabel: "Sortable list", sortableHandle: "Reorder", sortableHelp: "Press Space to pick this up, then Arrow Up and Arrow Down to move it. Space drops it, Escape puts it back.", sortableGrabbed: "Picked up", sortableDropped: "Dropped", sortableMoved: "Moved", sortableCanceled: "Put back", blockEditorLabel: "Content blocks", blockLabel: "Block", blockRemove: "Remove block", uploadSending: "Uploading", uploadCancel: "Cancel upload", uploadRetry: "Retry upload", uploadError: "Upload failed", uploadCanceled: "Upload canceled", uploadComplete: "Upload complete", uploadPause: "Pause upload", uploadResume: "Resume upload", uploadPaused: "Paused", uploadPending: "Waiting", uploadChecksum: "Checksum", uploadChecksumBad: "The server received different bytes than the ones sent.", fileConflict: "A file with this name is already in the queue", fileReplace: "Replace", fileKeepBoth: "Keep both", fileSkip: "Skip", uploadReceipt: "Receipt", uploadReceiptCopy: "Copy receipt", agentInspector: "Agent inspector", invocationLabel: "Invocation", invocationInput: "Input", invocationOutput: "Output", taskQueueLabel: "Task queue", taskState: { queued: "Queued", running: "Running", completed: "Completed", failed: "Failed", blocked: "Blocked", paused: "Paused" }, taskPriority: { low: "Low", medium: "Medium", high: "High" }, approvalLabel: "Approval", approvalApprove: "Approve", approvalDeny: "Deny", approvalApproved: "Approved", approvalDenied: "Denied", approvalDeadline: "Decide by", approvalRisk: { low: "Low risk", medium: "Medium risk", high: "High risk" }, permissionLabel: "Tool permissions", permissionAsk: "Ask", permissionAlways: "Always", permissionNever: "Never", eventStreamLabel: "Events", traceLabel: "Trace", healthLabel: "Health", healthState: { operational: "Operational", degraded: "Degraded", down: "Down", maintenance: "Maintenance", unknown: "Unknown" }, modelUsageLabel: "Model usage", usageMetric: { tokens: "Tokens", cost: "Cost", requests: "Requests" }, costMeterLabel: "Cost", costMeterSpent: "Spent", costMeterRemaining: "left", costMeterExceeded: "Over the limit", costMeterNear: "Spending is past the soft limit.", costMeterOver: "The limit has been reached. Further calls are blocked.", memoryLabel: "Memory ledger", memoryProvenance: "Where this came from", memoryOperation: { added: "Added", updated: "Updated", recalled: "Recalled", forgotten: "Forgotten" }, memoryScope: { episodic: "Episodic", semantic: "Semantic", procedural: "Procedural" }, agentMessageLabel: "Agent messages", agentMessageTo: "to", agentMessageBroadcast: "all agents", agentMessageReason: "Why it went this way", agentMessageKind: { request: "Request", response: "Response", handoff: "Handoff", broadcast: "Broadcast", error: "Error" }, automationWhen: "When", automationThen: "Then", automationEnabled: "Enabled", automationLastRun: "Last run", automationResult: { success: "Succeeded", failure: "Failed" }, graphLabel: "Dependency graph", agentState: { idle: "Idle", thinking: "Thinking", running: "Running", paused: "Paused", error: "Error", completed: "Completed" }, codeEditor: "Code editor", chatLabel: "Conversation", chatMessage: "Message", chatSend: "Send", qrCode: "QR code", chartLabel: "Chart", copyCode: "Copy code", tocLabel: "On this page", navigationToggle: "Navigation", sidebarLabel: "Sidebar", bottomNavLabel: "Main", universalState: { waiting_user: "Waiting for someone to act.", waiting_approval: "Waiting for approval.", waiting_dependency: "Waiting for something else to finish.", offline: "No connection. This was loaded earlier.", stale: "This may be out of date.", partial: "Some of this could not be loaded.", degraded: "Working with reduced capability." } };
56
+ export const defaultStrings = { passwordShow: "Show password", passwordHide: "Hide password", skipToContent: "Skip to content", close: "Close", confirmCancel: "Cancel", dataError: "This could not be loaded.", dataEmpty: "Nothing here yet", confirmProceed: "Continue", paginationLabel: "Pagination", previous: "Previous", next: "Next", breadcrumbLabel: "Breadcrumb", tabsLabel: "Tabs", optionsLabel: "Options", tableLabel: "Table", commandLabel: "Command palette", commandPlaceholder: "Type a command…", dismissNotification: "Dismiss notification", toolbarLabel: "Toolbar", loading: "Loading", otpDigit: "Digit", stepperLabel: "Steps", increment: "Increase", decrement: "Decrease", comboboxEmpty: "No results", comboboxClear: "Clear selection", comboboxOpen: "Open list", comboboxRemove: "Remove", comboboxLoading: "Loading…", fileDropPrompt: "Drag files here or click to select", fileAdded: "File added", fileRemoved: "File removed", fileRemove: "Remove", fileTooLarge: "File exceeds the size limit", fileWrongType: "File type not allowed", treeLabel: "Tree", notificationsLabel: "Notifications", notificationMarkAll: "Mark all as read", notificationEmpty: "No notifications", notificationUnread: "Unread", notificationNew: "new notifications", dataGridFilter: "Filter", dataGridEmpty: "No results", dataGridSelectAll: "Select all rows", dataGridSelectRow: "Select row", dataGridSelected: "selected", dataGridClearSelection: "Clear selection", dataGridBulkLabel: "Bulk actions", dataGridColumns: "Columns", dataGridResize: "Resize column", dataGridStale: "Showing data that may be out of date.", dataGridPartial: "Some rows could not be loaded. What you see is incomplete.", dataGridError: "The rows could not be loaded.", dataGridDetails: "Details", dataGridDetailPanel: "Row detail", dataGridExport: "Export", dataGridExportRows: "rows", dataGridExportFiltered: "filtered rows", dataGridExportSelected: "selected rows", mediaPlayer: "Media player", mediaPlay: "Play", mediaPause: "Pause", mediaMute: "Mute", mediaUnmute: "Unmute", mediaSeek: "Seek", mediaVolume: "Volume", mediaCaptionsShow: "Show captions", mediaCaptionsHide: "Hide captions", mediaSkipBack: "Skip back 10 seconds", mediaSkipForward: "Skip forward 10 seconds", mediaFullscreenEnter: "Enter full screen", mediaFullscreenExit: "Exit full screen", carouselLabel: "Carousel", carouselSlide: "Slide", positionOf: "of", carouselPrev: "Previous slide", carouselNext: "Next slide", galleryLabel: "Gallery", sortableLabel: "Sortable list", sortableHandle: "Reorder", sortableHelp: "Press Space to pick this up, then Arrow Up and Arrow Down to move it. Space drops it, Escape puts it back.", sortableGrabbed: "Picked up", sortableDropped: "Dropped", sortableMoved: "Moved", sortableCanceled: "Put back", blockEditorLabel: "Content blocks", blockLabel: "Block", blockRemove: "Remove block", uploadSending: "Uploading", uploadCancel: "Cancel upload", uploadRetry: "Retry upload", uploadError: "Upload failed", uploadCanceled: "Upload canceled", uploadComplete: "Upload complete", uploadPause: "Pause upload", uploadResume: "Resume upload", uploadPaused: "Paused", uploadPending: "Waiting", uploadChecksum: "Checksum", uploadChecksumBad: "The server received different bytes than the ones sent.", fileConflict: "A file with this name is already in the queue", fileReplace: "Replace", fileKeepBoth: "Keep both", fileSkip: "Skip", uploadReceipt: "Receipt", uploadReceiptCopy: "Copy receipt", agentInspector: "Agent inspector", invocationLabel: "Invocation", invocationInput: "Input", invocationOutput: "Output", taskQueueLabel: "Task queue", taskState: { queued: "Queued", running: "Running", completed: "Completed", failed: "Failed", blocked: "Blocked", paused: "Paused" }, taskPriority: { low: "Low", medium: "Medium", high: "High" }, approvalLabel: "Approval", approvalApprove: "Approve", approvalDeny: "Deny", approvalApproved: "Approved", approvalDenied: "Denied", approvalDeadline: "Decide by", approvalRisk: { low: "Low risk", medium: "Medium risk", high: "High risk" }, permissionLabel: "Tool permissions", permissionAsk: "Ask", permissionAlways: "Always", permissionNever: "Never", eventStreamLabel: "Events", traceLabel: "Trace", healthLabel: "Health", healthState: { operational: "Operational", degraded: "Degraded", down: "Down", maintenance: "Maintenance", unknown: "Unknown" }, modelUsageLabel: "Model usage", usageMetric: { tokens: "Tokens", cost: "Cost", requests: "Requests" }, costMeterLabel: "Cost", costMeterSpent: "Spent", costMeterRemaining: "left", costMeterExceeded: "Over the limit", costMeterNear: "Spending is past the soft limit.", costMeterOver: "The limit has been reached. Further calls are blocked.", memoryLabel: "Memory ledger", memoryProvenance: "Where this came from", memoryOperation: { added: "Added", updated: "Updated", recalled: "Recalled", forgotten: "Forgotten" }, memoryScope: { episodic: "Episodic", semantic: "Semantic", procedural: "Procedural" }, agentMessageLabel: "Agent messages", agentMessageTo: "to", agentMessageBroadcast: "all agents", agentMessageReason: "Why it went this way", agentMessageKind: { request: "Request", response: "Response", handoff: "Handoff", broadcast: "Broadcast", error: "Error" }, automationWhen: "When", automationThen: "Then", automationEnabled: "Enabled", automationLastRun: "Last run", automationResult: { success: "Succeeded", failure: "Failed" }, graphLabel: "Dependency graph", agentState: { idle: "Idle", thinking: "Thinking", running: "Running", paused: "Paused", error: "Error", completed: "Completed" }, codeEditor: "Code editor", chatLabel: "Conversation", chatMessage: "Message", chatSend: "Send", qrCode: "QR code", chartLabel: "Chart", copyCode: "Copy code", tocLabel: "On this page", navigationToggle: "Navigation", sidebarLabel: "Sidebar", bottomNavLabel: "Main", universalState: { waiting_user: "Waiting for someone to act.", waiting_approval: "Waiting for approval.", waiting_dependency: "Waiting for something else to finish.", offline: "No connection. This was loaded earlier.", stale: "This may be out of date.", partial: "Some of this could not be loaded.", degraded: "Working with reduced capability." } };
25
57
  // pt-BR preservado como locale (mesmos valores que já eram o default): passe
26
58
  // <AureaProvider strings={ptBR}> para restaurar português.
27
- export const ptBR = { close: "Fechar", confirmCancel: "Cancelar", dataError: "Não foi possível carregar.", dataEmpty: "Ainda não há nada aqui", confirmProceed: "Continuar", paginationLabel: "Paginação", previous: "Anterior", next: "Próxima", breadcrumbLabel: "Breadcrumb", tabsLabel: "Abas", optionsLabel: "Opções", tableLabel: "Tabela", commandLabel: "Paleta de comandos", commandPlaceholder: "Digite um comando…", dismissNotification: "Dispensar notificação", toolbarLabel: "Barra de ferramentas", loading: "Carregando", otpDigit: "Dígito", stepperLabel: "Etapas", increment: "Aumentar", decrement: "Diminuir", comboboxEmpty: "Nenhum resultado", comboboxClear: "Limpar seleção", comboboxOpen: "Abrir lista", comboboxRemove: "Remover", comboboxLoading: "Carregando…", fileDropPrompt: "Arraste arquivos aqui ou clique para selecionar", fileAdded: "Arquivo adicionado", fileRemoved: "Arquivo removido", fileRemove: "Remover", fileTooLarge: "Arquivo maior que o limite", fileWrongType: "Tipo de arquivo não aceito", treeLabel: "Árvore", notificationsLabel: "Notificações", notificationMarkAll: "Marcar todas como lidas", notificationEmpty: "Nenhuma notificação", notificationUnread: "Não lida", notificationNew: "novas notificações", dataGridFilter: "Filtrar", dataGridEmpty: "Nenhum resultado", dataGridSelectAll: "Selecionar todas as linhas", dataGridSelectRow: "Selecionar linha", dataGridSelected: "selecionadas", dataGridClearSelection: "Limpar seleção", dataGridBulkLabel: "Ações em lote", dataGridColumns: "Colunas", dataGridResize: "Redimensionar coluna", dataGridStale: "Mostrando dados que podem estar desatualizados.", dataGridPartial: "Algumas linhas não puderam ser carregadas. O que aparece está incompleto.", dataGridError: "Não foi possível carregar as linhas.", dataGridDetails: "Detalhes", dataGridDetailPanel: "Detalhe da linha", dataGridExport: "Exportar", dataGridExportRows: "linhas", dataGridExportFiltered: "linhas filtradas", dataGridExportSelected: "linhas selecionadas", mediaPlayer: "Reprodutor de mídia", mediaPlay: "Reproduzir", mediaPause: "Pausar", mediaMute: "Silenciar", mediaUnmute: "Ativar som", mediaSeek: "Posição da reprodução", mediaVolume: "Volume", mediaCaptionsShow: "Ativar legendas", mediaCaptionsHide: "Desativar legendas", mediaSkipBack: "Voltar 10 segundos", mediaSkipForward: "Avançar 10 segundos", mediaFullscreenEnter: "Tela cheia", mediaFullscreenExit: "Sair da tela cheia", carouselLabel: "Carrossel", carouselSlide: "Slide", positionOf: "de", carouselPrev: "Slide anterior", carouselNext: "Próximo slide", galleryLabel: "Galeria", sortableLabel: "Lista ordenável", sortableHandle: "Reordenar", sortableHelp: "Aperte Espaço para pegar, e as setas para cima e para baixo para mover. Espaço solta, Esc devolve ao lugar.", sortableGrabbed: "Pego", sortableDropped: "Solto", sortableMoved: "Movido", sortableCanceled: "Devolvido", blockEditorLabel: "Blocos de conteúdo", blockLabel: "Bloco", blockRemove: "Remover bloco", uploadSending: "Enviando", uploadCancel: "Cancelar envio", uploadRetry: "Tentar envio novamente", uploadError: "Falha no envio", uploadCanceled: "Envio cancelado", uploadComplete: "Envio concluído", uploadPause: "Pausar envio", uploadResume: "Retomar envio", uploadPaused: "Pausado", uploadPending: "Aguardando", uploadChecksum: "Soma de verificação", uploadChecksumBad: "O servidor recebeu bytes diferentes dos enviados.", fileConflict: "Já existe um arquivo com este nome na fila", fileReplace: "Substituir", fileKeepBoth: "Manter os dois", fileSkip: "Pular", uploadReceipt: "Recibo", uploadReceiptCopy: "Copiar recibo", agentInspector: "Inspetor do agente", invocationLabel: "Invocação", invocationInput: "Entrada", invocationOutput: "Saída", taskQueueLabel: "Fila de tarefas", taskState: { queued: "Na fila", running: "Executando", completed: "Concluída", failed: "Falhou", blocked: "Bloqueada", paused: "Pausada" }, taskPriority: { low: "Baixa", medium: "Média", high: "Alta" }, approvalLabel: "Aprovação", approvalApprove: "Aprovar", approvalDeny: "Negar", approvalApproved: "Aprovado", approvalDenied: "Negado", approvalDeadline: "Decidir até", approvalRisk: { low: "Risco baixo", medium: "Risco médio", high: "Risco alto" }, permissionLabel: "Permissões de ferramenta", permissionAsk: "Perguntar", permissionAlways: "Sempre", permissionNever: "Nunca", eventStreamLabel: "Eventos", traceLabel: "Rastro", healthLabel: "Saúde", healthState: { operational: "Operando", degraded: "Degradado", down: "Fora do ar", maintenance: "Em manutenção", unknown: "Desconhecido" }, modelUsageLabel: "Consumo por modelo", usageMetric: { tokens: "Tokens", cost: "Custo", requests: "Chamadas" }, costMeterLabel: "Custo", costMeterSpent: "Gasto", costMeterRemaining: "restantes", costMeterExceeded: "Acima do limite", costMeterNear: "O gasto passou do limite brando.", costMeterOver: "O limite foi atingido. As próximas chamadas estão bloqueadas.", memoryLabel: "Livro-razão de memória", memoryProvenance: "De onde isto veio", memoryOperation: { added: "Guardada", updated: "Atualizada", recalled: "Lembrada", forgotten: "Esquecida" }, memoryScope: { episodic: "Episódica", semantic: "Semântica", procedural: "Procedural" }, agentMessageLabel: "Recados entre agentes", agentMessageTo: "para", agentMessageBroadcast: "todos os agentes", agentMessageReason: "Por que foi por aqui", agentMessageKind: { request: "Pedido", response: "Resposta", handoff: "Passagem", broadcast: "Difusão", error: "Erro" }, automationWhen: "Quando", automationThen: "Então", automationEnabled: "Ativa", automationLastRun: "Última execução", automationResult: { success: "Concluiu", failure: "Falhou" }, graphLabel: "Grafo de dependências", agentState: { idle: "Ocioso", thinking: "Pensando", running: "Executando", paused: "Pausado", error: "Erro", completed: "Concluído" }, codeEditor: "Editor de código", chatLabel: "Conversa", chatMessage: "Mensagem", chatSend: "Enviar", qrCode: "Código QR", chartLabel: "Gráfico", copyCode: "Copiar código", tocLabel: "Nesta página", navigationToggle: "Navegação", sidebarLabel: "Lateral", bottomNavLabel: "Principal", universalState: { waiting_user: "Esperando alguém agir.", waiting_approval: "Esperando aprovação.", waiting_dependency: "Esperando outra coisa terminar.", offline: "Sem conexão. Isto foi carregado antes.", stale: "Isto pode estar desatualizado.", partial: "Parte disto não pôde ser carregada.", degraded: "Funcionando com capacidade reduzida." } };
59
+ export const ptBR = { passwordShow: "Mostrar senha", passwordHide: "Ocultar senha", skipToContent: "Pular para o conteúdo", close: "Fechar", confirmCancel: "Cancelar", dataError: "Não foi possível carregar.", dataEmpty: "Ainda não há nada aqui", confirmProceed: "Continuar", paginationLabel: "Paginação", previous: "Anterior", next: "Próxima", breadcrumbLabel: "Breadcrumb", tabsLabel: "Abas", optionsLabel: "Opções", tableLabel: "Tabela", commandLabel: "Paleta de comandos", commandPlaceholder: "Digite um comando…", dismissNotification: "Dispensar notificação", toolbarLabel: "Barra de ferramentas", loading: "Carregando", otpDigit: "Dígito", stepperLabel: "Etapas", increment: "Aumentar", decrement: "Diminuir", comboboxEmpty: "Nenhum resultado", comboboxClear: "Limpar seleção", comboboxOpen: "Abrir lista", comboboxRemove: "Remover", comboboxLoading: "Carregando…", fileDropPrompt: "Arraste arquivos aqui ou clique para selecionar", fileAdded: "Arquivo adicionado", fileRemoved: "Arquivo removido", fileRemove: "Remover", fileTooLarge: "Arquivo maior que o limite", fileWrongType: "Tipo de arquivo não aceito", treeLabel: "Árvore", notificationsLabel: "Notificações", notificationMarkAll: "Marcar todas como lidas", notificationEmpty: "Nenhuma notificação", notificationUnread: "Não lida", notificationNew: "novas notificações", dataGridFilter: "Filtrar", dataGridEmpty: "Nenhum resultado", dataGridSelectAll: "Selecionar todas as linhas", dataGridSelectRow: "Selecionar linha", dataGridSelected: "selecionadas", dataGridClearSelection: "Limpar seleção", dataGridBulkLabel: "Ações em lote", dataGridColumns: "Colunas", dataGridResize: "Redimensionar coluna", dataGridStale: "Mostrando dados que podem estar desatualizados.", dataGridPartial: "Algumas linhas não puderam ser carregadas. O que aparece está incompleto.", dataGridError: "Não foi possível carregar as linhas.", dataGridDetails: "Detalhes", dataGridDetailPanel: "Detalhe da linha", dataGridExport: "Exportar", dataGridExportRows: "linhas", dataGridExportFiltered: "linhas filtradas", dataGridExportSelected: "linhas selecionadas", mediaPlayer: "Reprodutor de mídia", mediaPlay: "Reproduzir", mediaPause: "Pausar", mediaMute: "Silenciar", mediaUnmute: "Ativar som", mediaSeek: "Posição da reprodução", mediaVolume: "Volume", mediaCaptionsShow: "Ativar legendas", mediaCaptionsHide: "Desativar legendas", mediaSkipBack: "Voltar 10 segundos", mediaSkipForward: "Avançar 10 segundos", mediaFullscreenEnter: "Tela cheia", mediaFullscreenExit: "Sair da tela cheia", carouselLabel: "Carrossel", carouselSlide: "Slide", positionOf: "de", carouselPrev: "Slide anterior", carouselNext: "Próximo slide", galleryLabel: "Galeria", sortableLabel: "Lista ordenável", sortableHandle: "Reordenar", sortableHelp: "Aperte Espaço para pegar, e as setas para cima e para baixo para mover. Espaço solta, Esc devolve ao lugar.", sortableGrabbed: "Pego", sortableDropped: "Solto", sortableMoved: "Movido", sortableCanceled: "Devolvido", blockEditorLabel: "Blocos de conteúdo", blockLabel: "Bloco", blockRemove: "Remover bloco", uploadSending: "Enviando", uploadCancel: "Cancelar envio", uploadRetry: "Tentar envio novamente", uploadError: "Falha no envio", uploadCanceled: "Envio cancelado", uploadComplete: "Envio concluído", uploadPause: "Pausar envio", uploadResume: "Retomar envio", uploadPaused: "Pausado", uploadPending: "Aguardando", uploadChecksum: "Soma de verificação", uploadChecksumBad: "O servidor recebeu bytes diferentes dos enviados.", fileConflict: "Já existe um arquivo com este nome na fila", fileReplace: "Substituir", fileKeepBoth: "Manter os dois", fileSkip: "Pular", uploadReceipt: "Recibo", uploadReceiptCopy: "Copiar recibo", agentInspector: "Inspetor do agente", invocationLabel: "Invocação", invocationInput: "Entrada", invocationOutput: "Saída", taskQueueLabel: "Fila de tarefas", taskState: { queued: "Na fila", running: "Executando", completed: "Concluída", failed: "Falhou", blocked: "Bloqueada", paused: "Pausada" }, taskPriority: { low: "Baixa", medium: "Média", high: "Alta" }, approvalLabel: "Aprovação", approvalApprove: "Aprovar", approvalDeny: "Negar", approvalApproved: "Aprovado", approvalDenied: "Negado", approvalDeadline: "Decidir até", approvalRisk: { low: "Risco baixo", medium: "Risco médio", high: "Risco alto" }, permissionLabel: "Permissões de ferramenta", permissionAsk: "Perguntar", permissionAlways: "Sempre", permissionNever: "Nunca", eventStreamLabel: "Eventos", traceLabel: "Rastro", healthLabel: "Saúde", healthState: { operational: "Operando", degraded: "Degradado", down: "Fora do ar", maintenance: "Em manutenção", unknown: "Desconhecido" }, modelUsageLabel: "Consumo por modelo", usageMetric: { tokens: "Tokens", cost: "Custo", requests: "Chamadas" }, costMeterLabel: "Custo", costMeterSpent: "Gasto", costMeterRemaining: "restantes", costMeterExceeded: "Acima do limite", costMeterNear: "O gasto passou do limite brando.", costMeterOver: "O limite foi atingido. As próximas chamadas estão bloqueadas.", memoryLabel: "Livro-razão de memória", memoryProvenance: "De onde isto veio", memoryOperation: { added: "Guardada", updated: "Atualizada", recalled: "Lembrada", forgotten: "Esquecida" }, memoryScope: { episodic: "Episódica", semantic: "Semântica", procedural: "Procedural" }, agentMessageLabel: "Recados entre agentes", agentMessageTo: "para", agentMessageBroadcast: "todos os agentes", agentMessageReason: "Por que foi por aqui", agentMessageKind: { request: "Pedido", response: "Resposta", handoff: "Passagem", broadcast: "Difusão", error: "Erro" }, automationWhen: "Quando", automationThen: "Então", automationEnabled: "Ativa", automationLastRun: "Última execução", automationResult: { success: "Concluiu", failure: "Falhou" }, graphLabel: "Grafo de dependências", agentState: { idle: "Ocioso", thinking: "Pensando", running: "Executando", paused: "Pausado", error: "Erro", completed: "Concluído" }, codeEditor: "Editor de código", chatLabel: "Conversa", chatMessage: "Mensagem", chatSend: "Enviar", qrCode: "Código QR", chartLabel: "Gráfico", copyCode: "Copiar código", tocLabel: "Nesta página", navigationToggle: "Navegação", sidebarLabel: "Lateral", bottomNavLabel: "Principal", universalState: { waiting_user: "Esperando alguém agir.", waiting_approval: "Esperando aprovação.", waiting_dependency: "Esperando outra coisa terminar.", offline: "Sem conexão. Isto foi carregado antes.", stale: "Isto pode estar desatualizado.", partial: "Parte disto não pôde ser carregada.", degraded: "Funcionando com capacidade reduzida." } };
28
60
  // Sprite de ícones: CONFIGURAÇÃO DE APLICAÇÃO, então entra pelo provider, uma vez.
29
61
  // Antes o default absoluto "/aurea-icons.svg" vivia no Icon e 15 componentes declaravam
30
62
  // e repassavam `spriteUrl` à mão — 52 sítios de código. Consequência: aplicação servida
@@ -33,6 +65,92 @@ export const ptBR = { close: "Fechar", confirmCancel: "Cancelar", dataError: "N
33
65
  // foi corrigido nos fallbacks do catálogo e não aqui). O default segue o mesmo para quem
34
66
  // não configura nada; `Icon` aceita a prop como override local.
35
67
  export const defaultSpriteUrl = "/aurea-icons.svg";
68
+ export { ESCALA, ESCALA_CONTAINER } from "./escala.js";
69
+ /** O valor, e SÓ o valor.
70
+ *
71
+ * Todo callback de mudança do Base UI é chamado com DOIS argumentos — `(valor, eventDetails)` —
72
+ * e a Aurea declara um só. Repassar o callback do consumidor cru ao motor entrega esse segundo
73
+ * argumento de brinde: um objeto de evento do motor vazando por uma API pública que promete não
74
+ * tê-lo. Em TypeScript isso é INVISÍVEL, porque argumento a mais nunca é erro de tipo — o que
75
+ * torna o defeito silencioso e a assinatura, mentirosa.
76
+ *
77
+ * O custo real é acoplamento: quem escrever `onValueChange={(v, e) => …}` passa a depender do
78
+ * formato do evento de UMA versão do Base UI, e a Aurea deixa de poder trocar de motor sem
79
+ * quebrar consumidor. O `G-API-02` já tinha corrigido isso UMA vez, no `onCheckedChange` do item
80
+ * de menu, sem perguntar quem mais tinha o mesmo problema. Tinham outros SETE — medidos com
81
+ * `grep -noE "on(Value|Pressed|Checked|Open|InputValue)Change=\{on[A-Za-z]+\}"` e conferidos um
82
+ * a um contra o `.d.ts` do motor, que declara `eventDetails` nos sete.
83
+ *
84
+ * Devolve `undefined` quando não há callback, para o motor continuar distinguindo "sem handler"
85
+ * de "handler que não faz nada". */
86
+ export function soOValor(fn) {
87
+ return fn ? (v) => { fn(v); } : undefined;
88
+ }
89
+ /** O valor BASE de um responsivo — o que vale antes de qualquer ponto da escala, e o que um
90
+ * ambiente sem suporte a `@container` continua mostrando. */
91
+ export function valorBase(v) {
92
+ return v === undefined ? undefined : typeof v === "string" ? v : v.base;
93
+ }
94
+ /** `true` quando o valor pede a camada genérica (`size-*`) em vez da classe do componente. */
95
+ export function ehResponsivo(v) {
96
+ return typeof v === "object" && v !== null;
97
+ }
98
+ /** As classes de um valor responsivo, para um eixo da camada compartilhada.
99
+ *
100
+ * `eixo` é o nome da família de regras no core (hoje só `size`), e não o nome do componente: a
101
+ * camada é genérica de propósito — a explosão combinatória (passos × pontos) fica lá, uma vez,
102
+ * em vez de uma vez por peça.
103
+ *
104
+ * Devolve `""` para valor simples: nesse caso o componente segue emitindo a própria classe
105
+ * (`btn-sm`), que produz exatamente o mesmo computado. É o que mantém a mudança SOMATIVA — nenhum
106
+ * consumidor existente muda de classe, e nenhuma baseline de pixel se mexe. */
107
+ export function classesResponsivas(eixo, v) {
108
+ if (v === undefined || typeof v === "string")
109
+ return "";
110
+ const fora = [`${eixo}-${v.base}`];
111
+ const mapa = v.viewport ?? v.container;
112
+ const prefixo = v.viewport ? "vp" : "ct";
113
+ for (const [ponto, valor] of Object.entries(mapa ?? {})) {
114
+ if (valor)
115
+ fora.push(`${prefixo}-${ponto}:${eixo}-${valor}`);
116
+ }
117
+ return fora.join(" ");
118
+ }
119
+ /** A PELE DE UM VALOR DE EIXO, para qualquer família e qualquer eixo.
120
+ *
121
+ * Chamava-se `peleDeTamanho` até 22/08/2026, quando o eixo `orientation` entrou pela mesma
122
+ * camada e o nome passou a mentir: a regra sempre foi "valor simples devolve a classe do
123
+ * componente, valor responsivo devolve a camada genérica", e isso não tem nada de específico
124
+ * de tamanho. O check 15 do validate.py lê o PRIMEIRO argumento desta função para saber que
125
+ * classes o core pode legitimamente conter — se ela for renomeada de novo, ele muda junto.
126
+ *
127
+ * Estava em `inputs.tsx` como função de módulo e servia só à família de campo. Subiu para cá ao
128
+ * fechar as três famílias restantes do `G-AXIS-04` (marcação, identidade, glifo), porque a regra
129
+ * é uma só e escrevê-la de novo em cada módulo é o "47 adaptações manuais independentes" que o
130
+ * Victor proibiu.
131
+ *
132
+ * `padrao` existe porque o degrau BASE não é `md` em toda família: o do Spinner é `sm`, e o core
133
+ * reflete isso (`.spinner` já É o `sm`, e quem tem classe própria é o `md`). Presumir `md` como
134
+ * base universal é o erro que esta atividade já cometeu duas vezes — uma no padding do campo,
135
+ * outra na escala de glifo. Aqui ele é PARÂMETRO.
136
+ *
137
+ * Valor simples devolve a classe de sempre (`input-sm`, `icon-lg`), byte por byte; valor
138
+ * responsivo devolve a camada.
139
+ *
140
+ * `eixo` é a FAMÍLIA DE CLASSES da camada responsiva, e ela não é sempre a mesma que `base`.
141
+ * No `size` os degraus são valores compartilhados, então a família é uma só (`size-lg`) e o
142
+ * default serve. Em `orientation` as regras são de cada componente — um `btn-group` vertical
143
+ * não se parece com um `field` horizontal —, então a família é a do componente e a chamada
144
+ * passa `base` de novo.
145
+ *
146
+ * Consequência aceita: no eixo de orientação a classe do valor BASE (`btn-group-horizontal`)
147
+ * é emitida sem ter regra no core, porque horizontal é o desenho de partida. Classe sem regra
148
+ * não custa nada e mantém a forma da camada uniforme; o inverso — regra sem componente — é que
149
+ * seria defeito, e é o que o check 15 pega. */
150
+ export function peleDoEixo(base, valor, padrao = "md", eixo = "size") {
151
+ const v = valorBase(valor);
152
+ return ehResponsivo(valor) ? classesResponsivas(eixo, valor) : (!!v && v !== padrao && `${base}-${v}`);
153
+ }
36
154
  // Formato: `sort=-nome,execucoes` (o `-` é descendente) · `q=texto` · `page=2` ·
37
155
  // `f.<coluna>=valor`, repetido quando a coluna é faceta. Só entra o que está
38
156
  // ativo, então grade sem filtro nenhum deixa a URL limpa.
package/dist/qrcode.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import React from "react";
2
2
  import { type ErrorCorrection } from "qr";
3
+ import { type Responsive } from "./pure.js";
3
4
  export type QRCodeSize = "sm" | "md" | "lg";
4
5
  export interface QRCodeProps extends Omit<React.SVGAttributes<SVGSVGElement>, "children"> {
5
6
  value: string;
6
- size?: QRCodeSize;
7
+ size?: Responsive<QRCodeSize>;
7
8
  ecc?: ErrorCorrection;
8
9
  quietZone?: number;
9
10
  label?: string;
package/dist/qrcode.js CHANGED
@@ -8,6 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  // instalar um gerador de QR — que é exatamente o achado A5 visto de perto.
9
9
  import React from "react";
10
10
  import encodeQR from "qr";
11
+ import { peleDoEixo } from "./pure.js";
11
12
  import { cx, useAureaStrings } from "./internal.js";
12
13
  // QRCode: dado escaneável com a geometria suave da Aurea — módulos REDONDOS (dots) e
13
14
  // olhos circulares, não quadrados. Miolo de alto contraste FIXO (não segue o tema: dark
@@ -15,7 +16,7 @@ import { cx, useAureaStrings } from "./internal.js";
15
16
  // --qr-quiet no CSS. Matriz da lib `qr` (0-dep, Apache-2.0, Paul Miller); o desenho é
16
17
  // nosso. ecc default "quartile": dots cobrem menos área que quadrados, então mais
17
18
  // correção de erro preserva a escaneabilidade. ponytail: um estilo (dots) só.
18
- export function QRCode({ value, size = "md", ecc = "quartile", quietZone = 4, label, className, ...props }) {
19
+ export function QRCode({ value, size, ecc = "quartile", quietZone = 4, label, className, ...props }) {
19
20
  const s = useAureaStrings();
20
21
  const name = label ?? `${s.qrCode}: ${value}`;
21
22
  const m = encodeQR(value, "raw", { ecc, border: quietZone });
@@ -31,5 +32,5 @@ export function QRCode({ value, size = "md", ecc = "quartile", quietZone = 4, la
31
32
  // olho redondo: anel externo (raio 3.5) → furo (2.5, cor do fundo) → centro (1.5).
32
33
  // os raios preservam a proporção 7:5:3 do finder, então o leitor ainda o reconhece.
33
34
  const eyeShapes = eyes.map(([ex, ey], i) => { const cx = ex + 3.5, cy = ey + 3.5; return _jsxs(React.Fragment, { children: [_jsx("circle", { className: "qr-mod", cx: cx, cy: cy, r: 3.5 }), _jsx("circle", { className: "qr-eye-gap", cx: cx, cy: cy, r: 2.5 }), _jsx("circle", { className: "qr-mod", cx: cx, cy: cy, r: 1.5 })] }, `eye${i}`); });
34
- return _jsxs("svg", { className: cx("qrcode", size !== "md" && `qrcode-${size}`, className), role: "img", "aria-label": name, viewBox: `0 0 ${n} ${n}`, ...props, children: [_jsx("title", { children: name }), eyeShapes, dots] });
35
+ return _jsxs("svg", { className: cx("qrcode", peleDoEixo("qrcode", size), className), role: "img", "aria-label": name, viewBox: `0 0 ${n} ${n}`, ...props, children: [_jsx("title", { children: name }), eyeShapes, dots] });
35
36
  }
@@ -0,0 +1,20 @@
1
+ import { type ReactNode, type RefObject } from "react";
2
+ import { type Responsive } from "./pure.js";
3
+ /** O contêiner Aurea como PRIMITIVE. Declara o contêiner para o CSS (`container-scope`) e publica
4
+ * o elemento para quem precisar medi-lo — os dois pelo mesmo elemento, por construção. */
5
+ export declare function ContainerScope({ children, className, ...props }: {
6
+ children?: ReactNode;
7
+ className?: string;
8
+ } & React.HTMLAttributes<HTMLDivElement>): import("react").JSX.Element;
9
+ /** RESOLVE um `Responsive<T>` no valor único que vale agora.
10
+ *
11
+ * Genérico de propósito: o `G-AXIS-06` chegou por `orientation`, mas nada aqui sabe o que é
12
+ * orientação. Qualquer eixo COMPORTAMENTAL futuro usa este mesmo resolvedor — foi o que o Victor
13
+ * pediu ao recusar um `useResponsiveOrientation`.
14
+ *
15
+ * SSR/RSC: o servidor devolve sempre o valor BASE, deterministicamente. A hidratação casa com
16
+ * ele — `useSyncExternalStore` usa o snapshot de servidor durante a hidratação e só então
17
+ * re-renderiza com o do cliente —, e o contêiner só é medido depois da montagem, quando existe
18
+ * elemento para medir. Valor simples não assina nada: nem `matchMedia`, nem observer, nem
19
+ * estado que dependa de hidratação. */
20
+ export declare function useValorResponsivo<T extends string>(valor: Responsive<T> | undefined, padrao: T, ancora?: RefObject<HTMLElement | null>): T;
@@ -0,0 +1,201 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ // RESOLUÇÃO RESPONSIVA EM RUNTIME — a infraestrutura do `G-AXIS-06`.
4
+ //
5
+ // POR QUE ELA EXISTE. O eixo responsivo nasceu CSS-first, e para `size` isso está certo: mudar um
6
+ // degrau de escala não muda o que o componente FAZ. Para `orientation` em componente que navega
7
+ // por seta, muda: o `aria-orientation` decide que par de setas move o foco, e CSS não escreve
8
+ // atributo. Medido no banco de prova — no `Tabs` horizontal, ArrowDown/ArrowUp ficam PARADOS.
9
+ // Desenhar em coluna por CSS e continuar anunciando `horizontal` deixaria a interface visualmente
10
+ // vertical e semanticamente horizontal. A decisão do Victor (22/08/2026, ADR-0019) é que
11
+ // CSS-first vale para apresentação, e resolução em runtime é permitida — e necessária — quando o
12
+ // que está em jogo é semântica, teclado ou comportamento do motor.
13
+ //
14
+ // A REGRA QUE ESTE ARQUIVO OBEDECE: o valor responsivo RESOLVIDO é a única fonte de verdade. Ele
15
+ // vai para o motor; o motor publica `data-orientation` e `aria-orientation` e ajusta o teclado; a
16
+ // pele reage ao atributo publicado. Em nenhum momento o CSS decide a orientação por conta própria
17
+ // e o JavaScript corre atrás para consertar o atributo — isso seria duas fontes de verdade e uma
18
+ // janela em que visual e comportamento divergem.
19
+ //
20
+ // O MECANISMO MUDA COM A NATUREZA DO VALOR, e é de propósito:
21
+ //
22
+ // valor simples → nada. Nenhum listener, nenhum observer, nenhum estado.
23
+ // viewport → matchMedia (é o que a janela expõe, e é barato)
24
+ // container → ResizeObserver (não há outra forma de medir um elemento)
25
+ //
26
+ // A API pública não muda: continua `Responsive<T>` com os mesmos três formatos.
27
+ import { createContext, useContext, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
28
+ import { ESCALA, ESCALA_CONTAINER, PONTOS_DESC, PONTOS_CONTAINER_DESC } from "./escala.js";
29
+ import { cx, valorBase } from "./pure.js";
30
+ // ── o contêiner Aurea, identificado sem heurística ─────────────────────────────────────────────
31
+ //
32
+ // O Victor foi explícito: *"não quero heurística — vamos observar o parentElement e provavelmente
33
+ // é ele"*. O elemento que o observer mede tem de ser EXATAMENTE o que a API responsiva considera.
34
+ //
35
+ // Quem define o contêiner no CSS é `.container-scope { container:aurea / inline-size }`, e
36
+ // `@container aurea` casa com o ancestral mais próximo que tenha esse nome. Então a regra do JS é
37
+ // a MESMA REGRA, não uma parecida: `closest(".container-scope")`. Não é palpite sobre qual
38
+ // elemento seja — é o mesmo seletor que o navegador usa para responder a `@container`.
39
+ //
40
+ // O contexto existe por cima disso, para o caso explícito: quem monta um `<ContainerScope>` passa
41
+ // a referência adiante e nem precisa da busca. Os dois caminhos apontam para o mesmo elemento, e
42
+ // há teste cobrando isso.
43
+ const ContainerAurea = createContext(null);
44
+ /** O contêiner Aurea como PRIMITIVE. Declara o contêiner para o CSS (`container-scope`) e publica
45
+ * o elemento para quem precisar medi-lo — os dois pelo mesmo elemento, por construção. */
46
+ export function ContainerScope({ children, className, ...props }) {
47
+ const ref = useRef(null);
48
+ return _jsx(ContainerAurea.Provider, { value: ref, children: _jsx("div", { ref: ref, className: cx("container-scope", className), ...props, children: children }) });
49
+ }
50
+ // ── matchMedia compartilhado ───────────────────────────────────────────────────────────────────
51
+ // Um `MediaQueryList` por PONTO, não por componente. Sete pontos no total, para a aplicação
52
+ // inteira, e o navegador já avalia essas media queries de qualquer jeito por causa do CSS.
53
+ //
54
+ // AUSÊNCIA das APIs não pode quebrar: `jsdom` não implementa `matchMedia` nem `ResizeObserver`, e
55
+ // consumidor que testa em jsdom é caso comum, não exótico. Sem essas APIs o valor fica no BASE —
56
+ // que é o mesmo comportamento do servidor, e portanto o degradar correto: a interface aparece
57
+ // coerente, só não adapta. Quebrar seria transformar uma limitação de ambiente em erro de runtime.
58
+ const temMatchMedia = () => typeof window !== "undefined" && typeof window.matchMedia === "function";
59
+ const mqls = new Map();
60
+ const mql = (px) => {
61
+ const q = `(min-width:${px}px)`;
62
+ let m = mqls.get(q);
63
+ if (!m) {
64
+ m = window.matchMedia(q);
65
+ mqls.set(q, m);
66
+ }
67
+ return m;
68
+ };
69
+ // UM ouvinte real por ponto para a APLICAÇÃO INTEIRA, com um conjunto de interessados por cima.
70
+ // `useSyncExternalStore` chama `subscribe` por componente, então a versão ingênua registrava sete
71
+ // ouvintes por componente responsivo — linear no número de componentes, e medido: 7 para um,
72
+ // 70 para dez. Aqui é 7 para sempre, e o teste de escala cobra isso.
73
+ const interessadosVp = new Set();
74
+ let ouvindoVp = false;
75
+ const avisarTodos = () => { for (const f of interessadosVp)
76
+ f(); };
77
+ function assinarViewport(avisar) {
78
+ if (!temMatchMedia())
79
+ return () => { };
80
+ interessadosVp.add(avisar);
81
+ if (!ouvindoVp) {
82
+ for (const px of Object.values(ESCALA))
83
+ mql(px).addEventListener("change", avisarTodos);
84
+ ouvindoVp = true;
85
+ }
86
+ return () => { interessadosVp.delete(avisar); };
87
+ }
88
+ /** O ponto mais alto que a janela alcança, ou `null` abaixo do primeiro. `min-width` quer dizer
89
+ * que o ÚLTIMO ponto atingido vence, então a varredura é do maior para o menor. */
90
+ function pontoDaViewport() {
91
+ if (!temMatchMedia())
92
+ return null;
93
+ for (const p of PONTOS_DESC)
94
+ if (mql(ESCALA[p]).matches)
95
+ return p;
96
+ return null;
97
+ }
98
+ // ── ResizeObserver compartilhado ───────────────────────────────────────────────────────────────
99
+ // UM observer para o documento inteiro, com um registro de callbacks por elemento — e não um
100
+ // observer por componente. Não é infraestrutura especulativa: é a forma mais simples que não
101
+ // multiplica objetos, e o custo real está medido em `audit/activity-2/20-G-AXIS-06-CUSTO.md`.
102
+ const inscritos = new Map();
103
+ let observer = null;
104
+ function observarElemento(el, avisar) {
105
+ if (typeof ResizeObserver === "undefined")
106
+ return () => { };
107
+ if (!observer) {
108
+ observer = new ResizeObserver((entradas) => {
109
+ for (const e of entradas) {
110
+ // `borderBoxSize` é o que `@container ... (min-width)` consulta — a caixa de conteúdo
111
+ // daria outro número em qualquer elemento com padding, e as duas respostas divergiriam
112
+ // justamente onde o Victor exigiu que fossem a mesma.
113
+ const largura = e.borderBoxSize?.[0]?.inlineSize ?? e.contentRect.width;
114
+ for (const f of inscritos.get(e.target) ?? [])
115
+ f(largura);
116
+ }
117
+ });
118
+ }
119
+ let jogo = inscritos.get(el);
120
+ if (!jogo) {
121
+ jogo = new Set();
122
+ inscritos.set(el, jogo);
123
+ observer.observe(el);
124
+ }
125
+ jogo.add(avisar);
126
+ return () => {
127
+ jogo.delete(avisar);
128
+ if (jogo.size === 0) {
129
+ inscritos.delete(el);
130
+ observer.unobserve(el);
131
+ }
132
+ };
133
+ }
134
+ function pontoDaLargura(largura) {
135
+ for (const p of PONTOS_CONTAINER_DESC)
136
+ if (largura >= ESCALA_CONTAINER[p])
137
+ return p;
138
+ return null;
139
+ }
140
+ // ── a resolução ────────────────────────────────────────────────────────────────────────────────
141
+ /** O valor de um mapa de pontos, dado o ponto alcançado. Percorre do alcançado para baixo e
142
+ * devolve o primeiro que o mapa declara — um mapa esparso (`{md:"x"}`) continua valendo em `lg`,
143
+ * que é a semântica de `min-width` e a mesma da camada CSS. */
144
+ function doMapa(mapa, alcancado, ordemDesc, base) {
145
+ if (!alcancado)
146
+ return base;
147
+ let vendo = false;
148
+ for (const p of ordemDesc) {
149
+ if (p === alcancado)
150
+ vendo = true;
151
+ if (vendo && mapa[p] !== undefined)
152
+ return mapa[p];
153
+ }
154
+ return base;
155
+ }
156
+ const semAssinatura = () => () => { };
157
+ /** RESOLVE um `Responsive<T>` no valor único que vale agora.
158
+ *
159
+ * Genérico de propósito: o `G-AXIS-06` chegou por `orientation`, mas nada aqui sabe o que é
160
+ * orientação. Qualquer eixo COMPORTAMENTAL futuro usa este mesmo resolvedor — foi o que o Victor
161
+ * pediu ao recusar um `useResponsiveOrientation`.
162
+ *
163
+ * SSR/RSC: o servidor devolve sempre o valor BASE, deterministicamente. A hidratação casa com
164
+ * ele — `useSyncExternalStore` usa o snapshot de servidor durante a hidratação e só então
165
+ * re-renderiza com o do cliente —, e o contêiner só é medido depois da montagem, quando existe
166
+ * elemento para medir. Valor simples não assina nada: nem `matchMedia`, nem observer, nem
167
+ * estado que dependa de hidratação. */
168
+ export function useValorResponsivo(valor, padrao, ancora) {
169
+ const base = (valorBase(valor) ?? padrao);
170
+ const porViewport = typeof valor === "object" && valor !== null && valor.viewport ? valor.viewport : null;
171
+ const porContainer = typeof valor === "object" && valor !== null && valor.container ? valor.container : null;
172
+ // VIEWPORT — `useSyncExternalStore` porque a fonte é externa e síncrona, e porque ele é o único
173
+ // jeito de a hidratação usar o valor de servidor sem aviso e ainda assim corrigir no mesmo
174
+ // commit seguinte, em vez de esperar um efeito.
175
+ const pontoVp = useSyncExternalStore(porViewport ? assinarViewport : semAssinatura, () => (porViewport ? pontoDaViewport() : null), () => null);
176
+ // CONTAINER — o elemento só existe depois da montagem, então aqui é estado + efeito de layout.
177
+ // O primeiro render do cliente devolve o base, igual ao do servidor; a medição entra em
178
+ // seguida. Foi por isso que não usei `useSyncExternalStore` também aqui: não há snapshot
179
+ // síncrono antes de haver elemento.
180
+ const doContexto = useContext(ContainerAurea);
181
+ const [largura, setLargura] = useState(null);
182
+ useLayoutEffect(() => {
183
+ if (!porContainer)
184
+ return;
185
+ // A ÂNCORA é o elemento raiz do próprio componente, e ela é obrigatória para o caminho de
186
+ // busca: sem um nó no documento não há de onde subir. O contexto vem primeiro quando existe,
187
+ // porque aí o contêiner é explícito e não precisa ser procurado.
188
+ const el = doContexto?.current ?? ancora?.current?.closest(".container-scope") ?? null;
189
+ if (!el)
190
+ return;
191
+ setLargura(el.getBoundingClientRect().width);
192
+ return observarElemento(el, setLargura);
193
+ }, [porContainer, doContexto, ancora]);
194
+ return useMemo(() => {
195
+ if (porViewport)
196
+ return doMapa(porViewport, pontoVp, PONTOS_DESC, base);
197
+ if (porContainer)
198
+ return doMapa(porContainer, largura === null ? null : pontoDaLargura(largura), PONTOS_CONTAINER_DESC, base);
199
+ return base;
200
+ }, [porViewport, porContainer, pontoVp, largura, base]);
201
+ }
package/dist/system.d.ts CHANGED
@@ -1,16 +1,23 @@
1
1
  import React, { type ReactNode } from "react";
2
- import { type AureaStrings } from "./internal.js";
3
- export declare function AureaProvider({ children, strings, direction, spriteUrl, portalContainer }: {
2
+ import { type Responsive } from "./pure.js";
3
+ import { type AureaStrings, type AureaTheme, type AureaDensity } from "./internal.js";
4
+ export declare function AureaProvider({ children, strings, direction, spriteUrl, portalContainer, theme, defaultTheme, onThemeChange, density, defaultDensity, onDensityChange }: {
4
5
  children: ReactNode;
5
6
  strings?: Partial<AureaStrings>;
6
7
  direction?: "ltr" | "rtl";
7
8
  spriteUrl?: string;
8
9
  portalContainer?: HTMLElement | null;
10
+ theme?: AureaTheme;
11
+ defaultTheme?: AureaTheme;
12
+ onThemeChange?: (theme: AureaTheme) => void;
13
+ density?: AureaDensity;
14
+ defaultDensity?: AureaDensity;
15
+ onDensityChange?: (density: AureaDensity) => void;
9
16
  }): React.JSX.Element;
10
17
  export type AureaToastType = "info" | "success" | "warning" | "danger";
11
18
  export declare const useToast: () => import("@base-ui/react").UseToastManagerReturnValue<any>;
12
19
  export type AureaThemeName = "dark" | "light";
13
- export type AureaDensity = "compact" | "comfortable" | "spacious";
20
+ export type { AureaDensity };
14
21
  export declare function useAureaTheme(): {
15
22
  theme: AureaThemeName | null;
16
23
  density: AureaDensity | null;
@@ -19,9 +26,10 @@ export declare function useAureaTheme(): {
19
26
  toggleTheme: () => void;
20
27
  };
21
28
  export type IconName = string;
29
+ export type IconSize = "sm" | "md" | "lg" | "xl";
22
30
  export interface IconProps extends React.SVGAttributes<SVGSVGElement> {
23
31
  name: IconName;
24
32
  spriteUrl?: string;
25
- size?: "sm" | "md" | "lg" | "xl";
33
+ size?: Responsive<IconSize>;
26
34
  }
27
35
  export declare function Icon({ name, spriteUrl, size, className, ...props }: IconProps): React.JSX.Element;