@aurea-uds/react 0.1.0 → 0.3.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/README.md +34 -2
- package/dist/actions.d.ts +20 -0
- package/dist/actions.js +59 -5
- package/dist/agents.d.ts +209 -0
- package/dist/agents.js +302 -0
- package/dist/calendar.d.ts +6 -0
- package/dist/calendar.js +27 -0
- package/dist/chart.d.ts +10 -0
- package/dist/chart.js +53 -0
- package/dist/code-client.d.ts +6 -0
- package/dist/code-client.js +24 -0
- package/dist/code-editor.js +1 -0
- package/dist/code.d.ts +2 -13
- package/dist/code.js +5 -18
- package/dist/communication.js +1 -0
- package/dist/data-display-client.d.ts +14 -0
- package/dist/data-display-client.js +22 -0
- package/dist/data-display.d.ts +2 -23
- package/dist/data-display.js +5 -13
- package/dist/data-grid.d.ts +52 -3
- package/dist/data-grid.js +205 -25
- package/dist/feedback-client.d.ts +64 -0
- package/dist/feedback-client.js +110 -0
- package/dist/feedback.d.ts +2 -53
- package/dist/feedback.js +5 -71
- package/dist/file-input.d.ts +21 -2
- package/dist/file-input.js +202 -21
- package/dist/graph.d.ts +33 -0
- package/dist/graph.js +178 -0
- package/dist/identity-client.d.ts +9 -0
- package/dist/identity-client.js +12 -0
- package/dist/identity.d.ts +2 -8
- package/dist/identity.js +5 -3
- package/dist/index.d.ts +4 -1
- package/dist/index.js +33 -3
- package/dist/inputs-client.d.ts +105 -0
- package/dist/inputs-client.js +264 -0
- package/dist/inputs.d.ts +2 -65
- package/dist/inputs.js +9 -61
- package/dist/internal.d.ts +23 -70
- package/dist/internal.js +115 -23
- package/dist/layout-client.d.ts +9 -0
- package/dist/layout-client.js +72 -0
- package/dist/layout.d.ts +2 -14
- package/dist/layout.js +5 -22
- package/dist/markup.d.ts +72 -0
- package/dist/markup.js +87 -0
- package/dist/media-client.d.ts +36 -0
- package/dist/media-client.js +239 -0
- package/dist/media.d.ts +2 -9
- package/dist/media.js +5 -98
- package/dist/navigation-client.d.ts +94 -0
- package/dist/navigation-client.js +154 -0
- package/dist/navigation.d.ts +2 -59
- package/dist/navigation.js +5 -113
- package/dist/overlays.d.ts +28 -0
- package/dist/overlays.js +66 -10
- package/dist/pure.d.ts +196 -0
- package/dist/pure.js +111 -0
- package/dist/qrcode.d.ts +2 -1
- package/dist/qrcode.js +3 -2
- package/dist/system.d.ts +11 -1
- package/dist/system.js +59 -4
- package/package.json +40 -4
package/dist/agents.js
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// A camada operacional — PLANO-1.0, Parte H (09/08/2026).
|
|
4
|
+
//
|
|
5
|
+
// Um módulo por categoria do registry, como os outros (Fase 9, achado A5). A categoria
|
|
6
|
+
// é NOVA: "AI & Agents", da macroárea 18 do `DIRECTION.md`. Ela não estava na lista
|
|
7
|
+
// travada dos 13, e a decisão de acrescentá-la está na
|
|
8
|
+
// [ADR-0017](../../../decisions/0017-categoria-ai-agents.md) — porque o §2 do
|
|
9
|
+
// `DIRECTION.md` se declara "ilustrativo, não-vinculante", então tirar dali uma
|
|
10
|
+
// categoria é decisão, não dedução.
|
|
11
|
+
//
|
|
12
|
+
// PROCEDÊNCIA (BUILDING.md passo 2): estes três saem de `agents-kit-main`
|
|
13
|
+
// (`components/agents-ui/agent-card.tsx`, `agent-status-panel.tsx`) e do `DetailsView/`
|
|
14
|
+
// do `agent-prism-main`. As sete referências antigas NÃO têm esta família — foi por
|
|
15
|
+
// isso que a Parte H ficou bloqueada até 08/08/2026.
|
|
16
|
+
//
|
|
17
|
+
// Escopo menor que o da referência (passo 5): o `AgentCard` de lá despacha ações por
|
|
18
|
+
// STRING (`onAction: (action: string) => void`), o que troca o compilador por um acordo
|
|
19
|
+
// verbal. Aqui as ações entram como nó, e quem monta o botão sabe o que ele faz.
|
|
20
|
+
import React from "react";
|
|
21
|
+
import { cx, useAureaStrings } from "./internal.js";
|
|
22
|
+
import { Icon } from "./system.js";
|
|
23
|
+
import { Status, Badge, Progress, Alert } from "./feedback.js";
|
|
24
|
+
import { Avatar } from "./identity.js";
|
|
25
|
+
import { DataList } from "./data-display.js";
|
|
26
|
+
import { SegmentedControl, Switch } from "./inputs.js";
|
|
27
|
+
import { Button, IconButton } from "./actions.js";
|
|
28
|
+
// Só a variante: o `Status` já desenha o ponto, e um ícone ao lado dele seria a mesma
|
|
29
|
+
// informação duas vezes. A primeira versão deste mapa tinha um ícone por estado e
|
|
30
|
+
// nenhum era renderizado — código morto nascendo junto com o componente.
|
|
31
|
+
const ESTADO = {
|
|
32
|
+
idle: "neutral", thinking: "info", running: "info", paused: "warning", error: "danger", completed: "success",
|
|
33
|
+
};
|
|
34
|
+
// AgentStatus — o estado, e nada além dele.
|
|
35
|
+
// É `Status` com o vocabulário fixo desta família. Não vale um componente novo pela
|
|
36
|
+
// aparência; vale por CONTRATO: sem ele cada aplicação escreveria o seu par
|
|
37
|
+
// estado→variante, e a mesma condição apareceria de seis jeitos na mesma tela — que é
|
|
38
|
+
// exatamente o que a Parte J existe para impedir, um nível acima.
|
|
39
|
+
export function AgentStatus({ state = "idle", label, className, ...props }) {
|
|
40
|
+
const s = useAureaStrings();
|
|
41
|
+
return _jsx(Status, { variant: ESTADO[state], className: className, "data-state": state, ...props, children: label ?? s.agentState[state] });
|
|
42
|
+
}
|
|
43
|
+
// AgentCard — a identidade do agente: quem é, em que estado está, o que sabe fazer.
|
|
44
|
+
export function AgentCard({ name, description, avatarSrc, model, state, capabilities, actions, className, ...props }) {
|
|
45
|
+
return _jsxs("article", { className: cx("card", "agent-card", className), ...props, children: [_jsxs("header", { className: "agent-card-head", children: [_jsx(Avatar, { src: avatarSrc, alt: name, fallback: name.slice(0, 2), size: "md" }), _jsxs("div", { className: "agent-card-id", children: [_jsx("strong", { children: name }), model && _jsx("span", { className: "hint", children: model })] }), state && _jsx(AgentStatus, { state: state })] }), description && _jsx("p", { className: "agent-card-desc", children: description }), !!capabilities?.length && _jsx("ul", { className: "agent-caps", children: capabilities.map(c => _jsxs("li", { className: "agent-cap", title: c.description, children: [c.icon && _jsx(Icon, { name: c.icon, size: "sm" }), _jsx("span", { children: c.name })] }, c.name)) }), actions && _jsx("footer", { className: "agent-card-actions", children: actions })] });
|
|
46
|
+
}
|
|
47
|
+
// AgentInspector — o detalhe: configuração, ferramentas, instruções.
|
|
48
|
+
// A anatomia é a do `DetailsView/` do `agent-prism`: cabeçalho + seções rotuladas, com
|
|
49
|
+
// o valor cru disponível. Aqui as seções são `DataList`, que já existe e já tem pele —
|
|
50
|
+
// e o corpo livre entra como filho, para inspecionar o que a ficha não previu.
|
|
51
|
+
//
|
|
52
|
+
// O rótulo de seção NÃO é `<h3>`, e isso foi corrigido em 09/08/2026 por defeito medido: um
|
|
53
|
+
// componente não sabe a que profundidade está na página, e fixar um nível produz salto de
|
|
54
|
+
// hierarquia assim que ele entra sob um `<h1>` — foi o que a varredura do catálogo acusou
|
|
55
|
+
// (`salto h1 → h3`) no minuto em que a prévia dele passou a renderizar. Cada seção vira um
|
|
56
|
+
// `group` NOMEADO pelo próprio rótulo: o leitor de tela continua sabendo onde começa cada
|
|
57
|
+
// bloco, e ninguém precisa adivinhar o nível certo.
|
|
58
|
+
export function AgentInspector({ title, sections, children, className, ...props }) {
|
|
59
|
+
const s = useAureaStrings();
|
|
60
|
+
const uid = React.useId();
|
|
61
|
+
return _jsxs("section", { className: cx("card", "agent-inspector", className), "aria-label": typeof title === "string" ? title : s.agentInspector, ...props, children: [_jsx("header", { className: "agent-inspector-head", children: _jsx("strong", { children: title }) }), sections?.map((sec, i) => _jsxs("div", { className: "agent-inspector-section", role: "group", "aria-labelledby": `${uid}-${i}`, children: [_jsx("p", { id: `${uid}-${i}`, className: "agent-inspector-label", children: sec.label }), _jsx(DataList, { items: sec.items })] }, sec.label)), children] });
|
|
62
|
+
}
|
|
63
|
+
// InvocationPanel — UMA execução: o que foi pedido, os passos, o que saiu.
|
|
64
|
+
//
|
|
65
|
+
// O passo que tem corpo é um `<details>` nativo, o mesmo idioma do `Accordion`: dobrar
|
|
66
|
+
// e desdobrar já é comportamento de plataforma, com teclado e ARIA, e a referência
|
|
67
|
+
// gasta um `Collapsible` de biblioteca para chegar no mesmo lugar.
|
|
68
|
+
//
|
|
69
|
+
// `running` marca `aria-busy` na região INTEIRA em vez de animar o texto. A referência
|
|
70
|
+
// usa um `TextShimmer` — animação em cima do rótulo — e isso é decoração que um leitor
|
|
71
|
+
// de tela não alcança e que `prefers-reduced-motion` teria de desfazer.
|
|
72
|
+
//
|
|
73
|
+
// Entrada e saída são `group` NOMEADO, e não `<h3>` — mesmo defeito e mesma correção do
|
|
74
|
+
// `AgentInspector` (09/08/2026): nível de título fixo dentro de um componente vira salto de
|
|
75
|
+
// hierarquia na página que o hospeda.
|
|
76
|
+
export function InvocationPanel({ title, input, steps, output, running, className, ...props }) {
|
|
77
|
+
const s = useAureaStrings();
|
|
78
|
+
const uid = React.useId();
|
|
79
|
+
return _jsxs("section", { className: cx("card", "invocation", className), "aria-label": typeof title === "string" ? title : s.invocationLabel, "aria-busy": running || undefined, ...props, children: [title && _jsxs("header", { className: "invocation-head", children: [_jsx("strong", { children: title }), running && _jsx(AgentStatus, { state: "running" })] }), input && _jsxs("div", { className: "invocation-io", role: "group", "aria-labelledby": `${uid}-in`, children: [_jsx("p", { id: `${uid}-in`, className: "invocation-label", children: s.invocationInput }), _jsx("div", { children: input })] }), !!steps?.length && _jsx("ol", { className: "invocation-steps", children: steps.map(st => _jsx("li", { className: "invocation-step", "data-state": st.state ?? "done", children: st.content
|
|
80
|
+
? _jsxs("details", { children: [_jsxs("summary", { children: [st.label, st.detail && _jsxs("span", { className: "hint", children: [" \u00B7 ", st.detail] })] }), _jsx("div", { className: "invocation-step-body", children: st.content })] })
|
|
81
|
+
: _jsxs("span", { children: [st.label, st.detail && _jsxs("span", { className: "hint", children: [" \u00B7 ", st.detail] })] }) }, st.id)) }), output && _jsxs("div", { className: "invocation-io", role: "group", "aria-labelledby": `${uid}-out`, children: [_jsx("p", { id: `${uid}-out`, className: "invocation-label", children: s.invocationOutput }), _jsx("div", { children: output })] })] });
|
|
82
|
+
}
|
|
83
|
+
// Os seis estados e os três degraus de prioridade são os da referência, medidos.
|
|
84
|
+
const TAREFA = {
|
|
85
|
+
queued: "neutral", running: "info", completed: "success", failed: "danger", blocked: "warning", paused: "warning",
|
|
86
|
+
};
|
|
87
|
+
// TaskQueue — a fila de trabalho.
|
|
88
|
+
//
|
|
89
|
+
// ESCOPO MENOR QUE O DA REFERÊNCIA, e por fronteira, não por preguiça: o `AgentTask` de
|
|
90
|
+
// lá tem 15 campos, e cinco deles pertencem a OUTROS componentes desta mesma parte —
|
|
91
|
+
// `metrics.tokens` e `metrics.cost` são o `ModelUsage` (H11) e o `CostMeter` (H12),
|
|
92
|
+
// `checkpoints` é o `TraceTimeline` (H9), `assignee` é o `AgentCard` (H1). Absorvê-los
|
|
93
|
+
// aqui faria a fila responder por quatro contratos e nenhum deles direito.
|
|
94
|
+
export function TaskQueue({ tasks, label, onRetry, className, ...props }) {
|
|
95
|
+
const s = useAureaStrings();
|
|
96
|
+
return _jsx("ol", { className: cx("task-queue", className), "aria-label": label ?? s.taskQueueLabel, ...props, children: tasks.map(t => _jsxs("li", { className: "task-item", "data-state": t.state, children: [_jsxs("div", { className: "task-line", children: [_jsx("span", { className: "task-title", children: t.title }), t.priority && _jsx(Badge, { variant: t.priority === "high" ? "warning" : "neutral", children: s.taskPriority[t.priority] }), _jsx(Status, { variant: TAREFA[t.state], children: s.taskState[t.state] }), t.state === "failed" && onRetry && _jsx(IconButton, { variant: "ghost", size: "sm", icon: "restart", label: `${s.uploadRetry} ${t.title}`, onClick: () => onRetry(t) })] }), t.description && _jsx("p", { className: "task-desc", children: t.description }), t.state === "running" && t.progress != null && _jsx(Progress, { value: Math.round(t.progress * 100), label: t.title })] }, t.id)) });
|
|
97
|
+
}
|
|
98
|
+
// HumanApproval — o portão: o que vai acontecer, e a decisão de uma pessoa.
|
|
99
|
+
export function HumanApproval({ title, description, details, risk, reasoning, deadline, decision, onApprove, onDeny, className, ...props }) {
|
|
100
|
+
const s = useAureaStrings();
|
|
101
|
+
return _jsxs("section", { className: cx("card", "approval", className), "aria-label": typeof title === "string" ? title : s.approvalLabel, ...props, children: [_jsxs("header", { className: "approval-head", children: [_jsx("strong", { children: title }), risk && _jsx(Badge, { variant: risk === "high" ? "danger" : risk === "medium" ? "warning" : "neutral", children: s.approvalRisk[risk] })] }), description && _jsx("p", { className: "approval-desc", children: description }), !!details?.length && _jsx(DataList, { items: details }), reasoning && _jsx("p", { className: "approval-reason", children: reasoning }), deadline && _jsxs("p", { className: "hint", children: [s.approvalDeadline, ": ", deadline] }), decision
|
|
102
|
+
? _jsx(Alert, { variant: decision === "approved" ? "success" : "warning", children: decision === "approved" ? s.approvalApproved : s.approvalDenied })
|
|
103
|
+
: _jsxs("footer", { className: "approval-actions", children: [_jsx(Button, { variant: "secondary", onClick: onDeny, children: s.approvalDeny }), _jsx(Button, { variant: "primary", onClick: onApprove, children: s.approvalApprove })] })] });
|
|
104
|
+
}
|
|
105
|
+
// ToolPermission — o que cada ferramenta pode, sem perguntar de novo.
|
|
106
|
+
//
|
|
107
|
+
// A escolha de três vias é um `SegmentedControl`, que já é `radiogroup` do Base UI
|
|
108
|
+
// (ADR-0016): setas que movem E selecionam, `Home`/`End`, roving tabindex. Escrever
|
|
109
|
+
// três botões alternáveis aqui repetiria à mão o padrão que aquela ADR rejeitou.
|
|
110
|
+
export function ToolPermission({ tools, onChange, label, className, ...props }) {
|
|
111
|
+
const s = useAureaStrings();
|
|
112
|
+
const opcoes = [{ value: "ask", label: s.permissionAsk }, { value: "always", label: s.permissionAlways }, { value: "never", label: s.permissionNever }];
|
|
113
|
+
return _jsx("section", { className: cx("card", "tool-permission", className), "aria-label": label ?? s.permissionLabel, ...props, children: _jsx("ul", { className: "tool-permission-list", children: tools.map(t => _jsxs("li", { className: "tool-permission-item", children: [_jsxs("div", { className: "tool-permission-id", children: [_jsx("strong", { children: t.name }), t.scope && _jsx("code", { className: "tool-permission-scope", children: t.scope }), t.description && _jsx("span", { className: "hint", children: t.description })] }), _jsx(SegmentedControl, { items: opcoes, value: t.permission, label: `${t.name}${t.scope ? " " + t.scope : ""}`, onChange: v => onChange?.(t.id, v) })] }, t.id)) }) });
|
|
114
|
+
}
|
|
115
|
+
// EventStream — o que aconteceu, em ordem, ao vivo.
|
|
116
|
+
//
|
|
117
|
+
// NÃO é o `LogStream`, e a diferença é de PAPEL, não de aparência: `role="log"` é para
|
|
118
|
+
// saída de texto que se acumula; isto é `role="feed"` do APG — uma lista de artigos que
|
|
119
|
+
// a pessoa percorre, cada um com título, hora e gravidade próprios. Um evento tem
|
|
120
|
+
// estrutura; uma linha de log é texto.
|
|
121
|
+
export function EventStream({ events, label, follow, className, ...props }) {
|
|
122
|
+
const s = useAureaStrings();
|
|
123
|
+
const fim = React.useRef(null);
|
|
124
|
+
// "Seguir o fim" é o comportamento que distingue um fluxo ao vivo de uma lista: sem
|
|
125
|
+
// ele, quem está lendo o topo perde o que chega. Com ele E sem controle, quem está
|
|
126
|
+
// lendo o MEIO é arrastado para baixo — por isso é uma prop, e não o default.
|
|
127
|
+
React.useEffect(() => { if (follow)
|
|
128
|
+
fim.current?.scrollIntoView({ block: "end" }); }, [events.length, follow]);
|
|
129
|
+
const grupos = events.reduce((acc, e) => {
|
|
130
|
+
const ultimo = acc[acc.length - 1];
|
|
131
|
+
if (ultimo && ultimo.nome === e.group)
|
|
132
|
+
ultimo.itens.push(e);
|
|
133
|
+
else
|
|
134
|
+
acc.push({ nome: e.group, itens: [e] });
|
|
135
|
+
return acc;
|
|
136
|
+
}, []);
|
|
137
|
+
// O `feed` fica NO GRUPO, e não por fora, e isso é correção medida de 09/08/2026: `feed` só
|
|
138
|
+
// aceita `article` como filho, e o cabeçalho de grupo — que era um `<h3>` — reprovava em
|
|
139
|
+
// `aria-required-children` E em ordem de título, os dois achados pela varredura assim que a
|
|
140
|
+
// prévia do catálogo parou de sair vazia. Agora cada grupo é um feed com NOME próprio (a data),
|
|
141
|
+
// o rótulo deixou de ser título de nível fixo, e sem agrupamento nenhum o feed único continua
|
|
142
|
+
// se chamando como o componente todo.
|
|
143
|
+
return _jsxs("section", { className: cx("event-stream", className), "aria-label": label ?? s.eventStreamLabel, "aria-busy": follow || undefined, ...props, children: [grupos.map((g, gi) => _jsxs(React.Fragment, { children: [g.nome && _jsx("p", { className: "event-group", children: g.nome }), _jsx("div", { className: "event-group-feed", role: "feed", "aria-label": g.nome ?? label ?? s.eventStreamLabel, children: g.itens.map(e => _jsxs("article", { className: "event-item", "data-severity": e.severity ?? "info", "aria-labelledby": `ev-${e.id}`, children: [_jsx("span", { className: "event-dot", "aria-hidden": "true" }), _jsxs("div", { className: "event-body", children: [_jsx("span", { id: `ev-${e.id}`, children: e.title }), e.detail && _jsx("span", { className: "hint", children: e.detail })] }), e.time && _jsx("time", { className: "event-time", children: e.time })] }, e.id)) })] }, g.nome ?? gi)), _jsx("div", { ref: fim })] });
|
|
144
|
+
}
|
|
145
|
+
// TraceTimeline — quanto cada passo demorou, em cascata.
|
|
146
|
+
//
|
|
147
|
+
// NÃO é o `Timeline` que já existe: aquele é uma coluna de momentos (ponto, título,
|
|
148
|
+
// hora); este é uma cascata de DURAÇÕES, onde a posição e a largura da barra são o dado.
|
|
149
|
+
// A matemática é a da referência: cada barra é (start-min)/(max-min) de deslocamento e
|
|
150
|
+
// (end-start)/(max-min) de largura.
|
|
151
|
+
//
|
|
152
|
+
// O que NÃO entrou: as ONZE cores por categoria de span da referência
|
|
153
|
+
// (`llm_call`, `tool_execution`, `retrieval`…). Cor por categoria numa paleta travada é
|
|
154
|
+
// o mesmo defeito que o H.a recusou; `kind` entra como TEXTO, que é legível também por
|
|
155
|
+
// quem não distingue as cores.
|
|
156
|
+
export function TraceTimeline({ spans, label, className, ...props }) {
|
|
157
|
+
const s = useAureaStrings();
|
|
158
|
+
const min = Math.min(...spans.map(x => x.start), 0);
|
|
159
|
+
const max = Math.max(...spans.map(x => x.end), min + 1);
|
|
160
|
+
const janela = max - min || 1;
|
|
161
|
+
return _jsx("ol", { className: cx("trace", className), "aria-label": label ?? s.traceLabel, ...props, children: spans.map(sp => {
|
|
162
|
+
const off = ((sp.start - min) / janela) * 100, larg = Math.max(((sp.end - sp.start) / janela) * 100, 1);
|
|
163
|
+
return _jsxs("li", { className: "trace-span", "data-error": sp.error || undefined, style: { ["--trace-depth"]: String(sp.depth ?? 0) }, children: [_jsxs("span", { className: "trace-label", children: [sp.label, sp.kind && _jsxs("span", { className: "hint", children: [" \u00B7 ", sp.kind] })] }), _jsx("span", { className: "trace-track", role: "meter", "aria-label": typeof sp.label === "string" ? sp.label : s.traceLabel, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": sp.end - sp.start, "aria-valuetext": `${sp.end - sp.start}`, children: _jsx("span", { className: "trace-bar", style: { insetInlineStart: `${off}%`, inlineSize: `${larg}%` } }) })] }, sp.id);
|
|
164
|
+
}) });
|
|
165
|
+
}
|
|
166
|
+
const SAUDE = {
|
|
167
|
+
operational: "success", degraded: "warning", down: "danger", maintenance: "info", unknown: "neutral",
|
|
168
|
+
};
|
|
169
|
+
// HealthMatrix — o que está de pé, numa grade.
|
|
170
|
+
export function HealthMatrix({ entries, label, className, ...props }) {
|
|
171
|
+
const s = useAureaStrings();
|
|
172
|
+
return _jsx("ul", { className: cx("health-matrix", className), "aria-label": label ?? s.healthLabel, ...props, children: entries.map(e => _jsxs("li", { className: "health-cell", "data-state": e.state, children: [_jsx("span", { className: "health-name", children: e.name }), _jsx(Status, { variant: SAUDE[e.state], children: s.healthState[e.state] }), e.detail && _jsx("span", { className: "hint", children: e.detail })] }, e.id)) });
|
|
173
|
+
}
|
|
174
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
175
|
+
// H.e — custo e memória: quanto se consumiu, contra que teto, e o que ficou guardado.
|
|
176
|
+
//
|
|
177
|
+
// PROCEDÊNCIA: `langfuse-main/web/src/features/dashboard/components/` — o
|
|
178
|
+
// `ModelUsageChart.tsx` (a métrica total no topo e a quebra por modelo), o
|
|
179
|
+
// `ModelCostTable.tsx` (as colunas modelo × tokens × custo, com o número à direita), o
|
|
180
|
+
// `TotalMetric.tsx` (número grande + descrição, e é UMA linha de arranjo) e o
|
|
181
|
+
// `cards/BarListChartArea.tsx` (a lista de barras horizontais com rótulo de valor).
|
|
182
|
+
// Mais `agent-prism-main/packages/ui/src/components/{TokensBadge,PriceBadge}.tsx` — o par
|
|
183
|
+
// de unidades desta família, contagem e preço — e `agents-kit-main/components/agents-ui/
|
|
184
|
+
// agent-status-panel.tsx`, que traz a tarifa por 1k tokens com entrada e saída separadas.
|
|
185
|
+
//
|
|
186
|
+
// O `MemoryLedger` NÃO TEM REFERÊNCIA, e é o caso declarado no `BUILDING.md` §1: nasce de
|
|
187
|
+
// pesquisa registrada no `REFERENCES.md` e de composição. A pesquisa está lá com data.
|
|
188
|
+
// Formatação de número: `Intl` é a plataforma, e o locale entra como prop com default
|
|
189
|
+
// FIXO. O default fixo é o que mantém a saída determinística no SSR do catálogo e no gate
|
|
190
|
+
// de pixel — locale do ambiente mudaria o texto entre a máquina e a CI. A referência faz
|
|
191
|
+
// igual: o `costFormatter` do langfuse é `Intl.NumberFormat("en-US")` pregado, medido em
|
|
192
|
+
// `web/src/utils/numbers.ts`.
|
|
193
|
+
const compacto = (n, locale) => new Intl.NumberFormat(locale, { notation: "compact", maximumFractionDigits: 2 }).format(n);
|
|
194
|
+
// Duas casas fixas é o que o `costFormatter` da referência usa, e aqui isso MENTE: custo de
|
|
195
|
+
// modelo cai em fração de centavo o tempo todo, e "$0.00" para um gasto real de US$ 0,004
|
|
196
|
+
// apaga o número justamente no componente que existe para vigiá-lo.
|
|
197
|
+
const dinheiro = (n, currency, locale) => new Intl.NumberFormat(locale, { style: "currency", currency, minimumFractionDigits: 2, maximumFractionDigits: n !== 0 && Math.abs(n) < 0.01 ? 6 : 2 }).format(n);
|
|
198
|
+
// ModelUsage — o consumo repartido POR MODELO.
|
|
199
|
+
//
|
|
200
|
+
// NÃO é o `CostMeter`, e a diferença é de PAPEL, como a do `EventStream` para o `LogStream`:
|
|
201
|
+
// aqui a barra é FATIA DE UMA SOMA — o teto é o próprio total, e a pergunta é "qual modelo
|
|
202
|
+
// levou quanto". No `CostMeter` o teto vem de fora, e a pergunta é "quanto ainda cabe".
|
|
203
|
+
// Trocar um pelo outro é mostrar orçamento onde não existe orçamento nenhum.
|
|
204
|
+
//
|
|
205
|
+
// ESCOPO MENOR QUE O DA REFERÊNCIA (passo 5): as quatro abas de lá (`Cost by model`,
|
|
206
|
+
// `Cost by type`, `Usage by model`, `Usage by type`) existem porque são quatro CONSULTAS
|
|
207
|
+
// diferentes no produto dela. Aqui a dimensão é uma prop e os dados chegam prontos. Também
|
|
208
|
+
// ficaram fora o seletor de modelos em popover e a série temporal — a série é o `Chart`,
|
|
209
|
+
// que já existe, e embutir um segundo gráfico aqui duplicaria aquele contrato.
|
|
210
|
+
export function ModelUsage({ entries, metric = "tokens", label, currency = "USD", locale = "en-US", className, ...props }) {
|
|
211
|
+
const s = useAureaStrings();
|
|
212
|
+
const valor = (e) => (metric === "cost" ? e.cost : metric === "requests" ? e.requests : e.tokens) ?? 0;
|
|
213
|
+
const fmt = (n) => metric === "cost" ? dinheiro(n, currency, locale) : compacto(n, locale);
|
|
214
|
+
const total = entries.reduce((a, e) => a + valor(e), 0);
|
|
215
|
+
// Ordem decrescente pela métrica, como a referência (`orderBy` em `ModelCostTable`): uma
|
|
216
|
+
// lista de barras fora de ordem obriga a varrer tudo para achar o maior, que é a única
|
|
217
|
+
// coisa que ela existe para responder de relance. Cópia, não `sort` no array de quem chamou.
|
|
218
|
+
const linhas = [...entries].sort((a, b) => valor(b) - valor(a));
|
|
219
|
+
return _jsxs("section", { className: cx("card", "model-usage", className), "aria-label": label ?? s.modelUsageLabel, ...props, children: [_jsxs("header", { className: "metric-total", children: [_jsx("strong", { children: fmt(total) }), _jsx("span", { className: "hint", children: s.usageMetric[metric] })] }), _jsx("ul", { className: "model-usage-list", children: linhas.map(e => {
|
|
220
|
+
const v = valor(e), pct = total > 0 ? (v / total) * 100 : 0;
|
|
221
|
+
return _jsxs("li", { className: "model-usage-row", children: [_jsxs("span", { className: "model-usage-name", children: [e.model, e.provider && _jsxs("span", { className: "hint", children: [" \u00B7 ", e.provider] })] }), _jsx("span", { className: "model-usage-track", role: "meter", "aria-label": e.model, "aria-valuemin": 0, "aria-valuemax": total || 1, "aria-valuenow": v, "aria-valuetext": fmt(v), children: _jsx("span", { className: "model-usage-bar", style: { inlineSize: `${pct}%` } }) }), _jsx("span", { className: "model-usage-value", children: fmt(v) })] }, e.id);
|
|
222
|
+
}) })] });
|
|
223
|
+
}
|
|
224
|
+
// CostMeter — o gasto contra um TETO.
|
|
225
|
+
//
|
|
226
|
+
// Os dois limites são os do LiteLLM, que é o padrão de mercado de controle de custo de LLM
|
|
227
|
+
// medido em 09/08/2026 (pesquisa registrada no `REFERENCES.md`): o limite RÍGIDO bloqueia,
|
|
228
|
+
// o limite BRANDO só avisa. Nenhuma das nove referências locais tem orçamento — o langfuse
|
|
229
|
+
// OSS mostra custo e não teto —, então isto veio pelo passo 4 do `BUILDING.md`, pesquisado
|
|
230
|
+
// antes de escrever, e não de memória.
|
|
231
|
+
//
|
|
232
|
+
// Sem `softLimit` NÃO EXISTE estado de aviso. A tentação era derivar um em 80% do teto;
|
|
233
|
+
// 80% é um número inventado, e um alerta que aparece sozinho num limiar que ninguém
|
|
234
|
+
// configurou é ruído com aparência de política.
|
|
235
|
+
export function CostMeter({ spent, limit, softLimit, currency = "USD", locale = "en-US", period, segments, label, className, ...props }) {
|
|
236
|
+
const s = useAureaStrings();
|
|
237
|
+
const fmt = (n) => dinheiro(n, currency, locale);
|
|
238
|
+
const estado = limit != null && spent >= limit ? "over" : softLimit != null && spent >= softLimit ? "near" : "under";
|
|
239
|
+
const temTeto = limit != null && limit > 0;
|
|
240
|
+
return _jsxs("section", { className: cx("card", "cost-meter", className), "data-state": estado, "aria-label": label ?? s.costMeterLabel, ...props, children: [_jsxs("header", { className: "metric-total", children: [_jsx("strong", { children: fmt(spent) }), _jsx("span", { className: "hint", children: period ?? s.costMeterSpent })] }), temTeto && _jsxs(_Fragment, { children: [_jsx("span", { className: "cost-meter-track", role: "meter", "aria-label": typeof label === "string" ? label : s.costMeterLabel, "aria-valuemin": 0, "aria-valuemax": limit, "aria-valuenow": Math.min(spent, limit), "aria-valuetext": `${fmt(spent)} / ${fmt(limit)}`, children: _jsx("span", { className: "cost-meter-bar", style: { inlineSize: `${Math.min((spent / limit) * 100, 100)}%` } }) }), _jsxs("p", { className: "hint", children: [spent < limit ? `${fmt(limit - spent)} ${s.costMeterRemaining}` : s.costMeterExceeded, " \u00B7 ", fmt(limit)] })] }), !!segments?.length && _jsx(DataList, { items: segments.map(g => ({ term: g.label, value: fmt(g.amount) })) }), estado !== "under" && _jsx(Alert, { variant: estado === "over" ? "danger" : "warning", children: estado === "over" ? s.costMeterOver : s.costMeterNear })] });
|
|
241
|
+
}
|
|
242
|
+
const LANCAMENTO = {
|
|
243
|
+
added: "success", updated: "info", recalled: "neutral", forgotten: "warning",
|
|
244
|
+
};
|
|
245
|
+
// MemoryLedger — o que o agente guardou, esqueceu ou lembrou, e DE ONDE veio.
|
|
246
|
+
//
|
|
247
|
+
// É o único da Parte H sem referência no mundo aberto: o ADE do Letta só abre o servidor, o
|
|
248
|
+
// OpenMemory do mem0 está sendo descontinuado e o painel do mem0 é só na nuvem. Medido em
|
|
249
|
+
// 08/08/2026 e reconfirmado em 09/08.
|
|
250
|
+
//
|
|
251
|
+
// Livro-razão é APENDE-SÓ, e é isso que o separa de uma lista de memórias: `forgotten` não
|
|
252
|
+
// tira a linha, registra o esquecimento. Uma tela que apaga a linha ao esquecer perde
|
|
253
|
+
// exatamente a informação que se procura quando o agente para de saber uma coisa.
|
|
254
|
+
//
|
|
255
|
+
// NÃO usa o `DataGrid`, e a razão é medida: `data-grid.tsx` mora em subpath próprio porque
|
|
256
|
+
// carrega o `@tanstack/react-table` como peer OPCIONAL (check 19), e este módulo sai pelo
|
|
257
|
+
// barril leve. Importá-lo aqui faria quem instala a biblioteca pelo Button passar a precisar
|
|
258
|
+
// da tabela. O plano previa o contrário; a fronteira do pacote vence o plano. Quem quiser
|
|
259
|
+
// ordenar e filtrar o razão compõe as duas coisas na aplicação — o exemplo do catálogo mostra.
|
|
260
|
+
export function MemoryLedger({ records, label, className, ...props }) {
|
|
261
|
+
const s = useAureaStrings();
|
|
262
|
+
return _jsx("ol", { className: cx("memory-ledger", className), "aria-label": label ?? s.memoryLabel, ...props, children: records.map(r => _jsxs("li", { className: "memory-entry", "data-operation": r.operation, "data-scope": r.scope, children: [_jsxs("div", { className: "memory-line", children: [_jsx(Badge, { variant: LANCAMENTO[r.operation], children: s.memoryOperation[r.operation] }), _jsx(Badge, { children: s.memoryScope[r.scope] }), _jsx("span", { className: "memory-content", children: r.content }), r.time && _jsx("time", { className: "memory-time", children: r.time })] }), (r.source || r.details?.length) && _jsxs("details", { className: "memory-provenance", children: [_jsx("summary", { children: s.memoryProvenance }), r.source && _jsx("p", { className: "memory-source", children: r.source }), !!r.details?.length && _jsx(DataList, { items: r.details })] })] }, r.id)) });
|
|
263
|
+
}
|
|
264
|
+
const RECADO = {
|
|
265
|
+
request: "info", response: "success", handoff: "primary", broadcast: "neutral", error: "danger",
|
|
266
|
+
};
|
|
267
|
+
// InterAgentMessage — o recado de um agente para outro.
|
|
268
|
+
//
|
|
269
|
+
// NÃO é o `MessageList`, e a diferença é de PAPEL, como todas as desta parte: aquele é uma
|
|
270
|
+
// conversa com uma PESSOA — autor, corpo, hora, recibo de leitura. Aqui a DIREÇÃO é o dado:
|
|
271
|
+
// tem um remetente e um destinatário, e é a passagem entre os dois que se está lendo. Um
|
|
272
|
+
// `MessageList` com dois autores não diz quem entregou o quê a quem.
|
|
273
|
+
//
|
|
274
|
+
// O que NÃO entrou: as seis cores por intenção do `agent-routing-hub` (`technical` ciano,
|
|
275
|
+
// `billing` âmbar, `sales` ardósia…). É a TERCEIRA vez que esta parte recusa a mesma coisa —
|
|
276
|
+
// depois das onze de span no H.d e das seis de estado no H.a. Cor por categoria numa paleta
|
|
277
|
+
// travada não é legível para quem não separa as cores. A `kind` entra como palavra, num selo.
|
|
278
|
+
export function InterAgentMessage({ messages, label, className, ...props }) {
|
|
279
|
+
const s = useAureaStrings();
|
|
280
|
+
return _jsx("ol", { className: cx("agent-messages", className), "aria-label": label ?? s.agentMessageLabel, ...props, children: messages.map(m => {
|
|
281
|
+
const destino = m.to ?? s.agentMessageBroadcast;
|
|
282
|
+
return _jsxs("li", { className: "agent-message", "data-kind": m.kind ?? "handoff", children: [_jsxs("div", { className: "agent-message-line", children: [_jsxs("span", { className: "agent-message-route", role: "group", "aria-label": `${m.from} ${s.agentMessageTo} ${destino}`, children: [_jsx("strong", { children: m.from }), _jsx(Icon, { name: "arrow--right", size: "sm", className: "agent-message-arrow" }), m.to ? _jsx("strong", { children: m.to }) : _jsx("span", { className: "hint", children: destino })] }), _jsx(Badge, { variant: RECADO[m.kind ?? "handoff"], children: s.agentMessageKind[m.kind ?? "handoff"] }), m.time && _jsx("time", { className: "agent-message-time", children: m.time })] }), _jsx("p", { className: "agent-message-body", children: m.body }), (m.reason || m.details?.length) && _jsxs("details", { className: "agent-message-why", children: [_jsx("summary", { children: s.agentMessageReason }), m.reason && _jsx("p", { className: "agent-message-reason", children: m.reason }), !!m.details?.length && _jsx(DataList, { items: m.details })] })] }, m.id);
|
|
283
|
+
}) });
|
|
284
|
+
}
|
|
285
|
+
// AutomationCard — a regra que roda sozinha: QUANDO isto, ENTÃO aquilo.
|
|
286
|
+
//
|
|
287
|
+
// A anatomia é a do `AutomationSidebar` do langfuse, medida: nome, gatilho (fonte de evento) e
|
|
288
|
+
// ação (tipo), mais o estado ativo/inativo. É isso que separa este cartão do `AgentCard`, que é
|
|
289
|
+
// identidade, e da `TaskQueue`, que é trabalho enfileirado: uma automação é uma REGRA, e regra
|
|
290
|
+
// é uma condição e uma consequência.
|
|
291
|
+
//
|
|
292
|
+
// O par QUANDO/ENTÃO entra em `DataList`, que já existe e já é o par termo/valor da casa — a
|
|
293
|
+
// mesma escolha do `HumanApproval` para os parâmetros, e pelo mesmo motivo: quem lê precisa
|
|
294
|
+
// achar a condição sem varrer um parágrafo.
|
|
295
|
+
//
|
|
296
|
+
// O que NÃO entrou: o histórico de execuções. Na referência ele é uma aba com tabela dentro do
|
|
297
|
+
// mesmo componente; aqui já existem `DataGrid` e `EventStream` para isso, e absorvê-lo faria o
|
|
298
|
+
// cartão responder por dois contratos — o erro que o `TaskQueue` recusou no H.b.
|
|
299
|
+
export function AutomationCard({ name, description, trigger, action, enabled, onToggle, lastRun, lastResult, details, actions, className, ...props }) {
|
|
300
|
+
const s = useAureaStrings();
|
|
301
|
+
return _jsxs("article", { className: cx("card", "automation", className), "data-enabled": enabled ?? undefined, ...props, children: [_jsxs("header", { className: "automation-head", children: [_jsxs("div", { className: "automation-id", children: [_jsx("strong", { children: name }), description && _jsx("span", { className: "hint", children: description })] }), onToggle && _jsx(Switch, { checked: !!enabled, onChange: e => onToggle(e.target.checked), label: s.automationEnabled })] }), _jsx(DataList, { items: [{ term: s.automationWhen, value: trigger }, { term: s.automationThen, value: action }, ...(details ?? [])] }), (lastRun || lastResult) && _jsxs("footer", { className: "automation-foot", children: [lastResult && _jsx(Status, { variant: lastResult === "success" ? "success" : "danger", children: s.automationResult[lastResult] }), lastRun && _jsxs("span", { className: "hint", children: [s.automationLastRun, ": ", lastRun] }), actions] }), !lastRun && !lastResult && actions && _jsx("footer", { className: "automation-foot", children: actions })] });
|
|
302
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DayPicker } from "react-day-picker";
|
|
3
|
+
export type CalendarProps = React.ComponentProps<typeof DayPicker> & {
|
|
4
|
+
label?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function Calendar({ label, className, classNames, ...props }: CalendarProps): React.JSX.Element;
|
package/dist/calendar.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { DayPicker } from "react-day-picker";
|
|
4
|
+
import { cx } from "./internal.js";
|
|
5
|
+
// Só TRÊS nomes são renomeados, e é de propósito. Todo o resto da pele é escrito contra ELEMENTO
|
|
6
|
+
// (`.calendar table`, `.calendar th`, `.calendar td button`) e contra os `data-*` que o motor já
|
|
7
|
+
// emite (`data-selected`, `data-today`, `data-outside`, `data-disabled`, `data-hidden`) — e
|
|
8
|
+
// atributo não é classe, então o check 15 nem os vê. Renomear os 21 nomes do motor encheria o
|
|
9
|
+
// core de superfície que ninguém usa.
|
|
10
|
+
// Os três que sobram são os que não dão para alcançar por elemento: a raiz (é o escopo de tudo),
|
|
11
|
+
// o embrulho dos meses (é o `position:relative` que a navegação usa de âncora) e o rótulo do mês
|
|
12
|
+
// (um <span> solto no meio de <div>s).
|
|
13
|
+
const NOMES = { months: "calendar-months", month_caption: "calendar-caption" };
|
|
14
|
+
export function Calendar({ label, className, classNames, ...props }) {
|
|
15
|
+
const grade = _jsx(DayPicker
|
|
16
|
+
// Grade cheia por padrão, como o shadcn: mês com buraco nas pontas treme ao trocar de mês.
|
|
17
|
+
, {
|
|
18
|
+
// Grade cheia por padrão, como o shadcn: mês com buraco nas pontas treme ao trocar de mês.
|
|
19
|
+
showOutsideDays: true, ...props, classNames: { ...NOMES, root: cx("calendar", className), ...classNames } });
|
|
20
|
+
// O motor já nomeia a GRADE com o mês ("August 2026"). O que ele não sabe é para que serve
|
|
21
|
+
// ESTE calendário — "de" e "até" lado a lado soariam os dois "August 2026". É o que `label`
|
|
22
|
+
// resolve, e só quando é preciso: dentro de um Popover quem diz o assunto é o gatilho, e um
|
|
23
|
+
// grupo a mais só acrescentaria ruído.
|
|
24
|
+
// O invólucro existe porque o `role` do DayPicker é tipado como "application" | "dialog" — o
|
|
25
|
+
// motor não deixa a raiz dele ser um `group`, e nenhum dos dois papéis dele serve aqui.
|
|
26
|
+
return label ? _jsx("div", { role: "group", "aria-label": label, children: grade }) : grade;
|
|
27
|
+
}
|
package/dist/chart.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React, { type ReactElement } from "react";
|
|
2
|
+
import { Tooltip, type LegendProps } from "recharts";
|
|
3
|
+
export interface ChartProps {
|
|
4
|
+
children: ReactElement;
|
|
5
|
+
label?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function Chart({ children, label, className }: ChartProps): React.JSX.Element;
|
|
9
|
+
export declare function ChartTooltip(props: React.ComponentProps<typeof Tooltip>): React.JSX.Element;
|
|
10
|
+
export declare function ChartLegend(props: LegendProps): React.JSX.Element;
|
package/dist/chart.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// Lote 3 do BUILDING.md (01/08/2026). SUBPATH PRÓPRIO, como ./data-grid e ./qrcode: o único
|
|
4
|
+
// componente que precisa do `recharts`, que é peer OPCIONAL. Se morasse em data-display.tsx,
|
|
5
|
+
// quem importa Table baixaria um motor de gráfico inteiro — que é o achado A5 visto de perto.
|
|
6
|
+
//
|
|
7
|
+
// NÃO ESCREVEMOS MOTOR DE GRÁFICO. Duas das quatro referências (shadcn/ui e Untitled UI React)
|
|
8
|
+
// envelopam o MESMO motor, o Recharts, e nenhuma das quatro desenha eixo à mão. O que é nosso
|
|
9
|
+
// aqui é só a pele: a caixa, o tooltip e a legenda. Escala, eixo, curva e interação são dele.
|
|
10
|
+
//
|
|
11
|
+
// O QUE FICOU DE FORA, e por quê (BUILDING.md passo 5 — escopo menor que o da referência):
|
|
12
|
+
// • o `ChartConfig` do shadcn (mapa dataKey → {label, color, theme}). MEDIDO em 01/08/2026: o
|
|
13
|
+
// payload que o Recharts entrega ao `content` já traz `name` (do prop `name` da série) e
|
|
14
|
+
// `color` resolvido. O objeto de configuração é indireção para reconstruir o que já chega.
|
|
15
|
+
// E o eixo `theme:{light,dark}` não existe aqui: `var(--chart-2)` já troca com o data-theme.
|
|
16
|
+
// • o par `ChartTooltip`/`ChartTooltipContent`. No Recharts 2 o filho tinha de ser o
|
|
17
|
+
// componente DELES, o que forçava o shadcn a reexportar o primitivo e pôr a pele no
|
|
18
|
+
// `content`. MEDIDO no 3.10.1: um componente NOSSO como filho é reconhecido. Então é uma
|
|
19
|
+
// peça só, não duas.
|
|
20
|
+
// • prop de altura. Dimensão não é número (check 23): a caixa mede pelo CSS (`.chart`), e
|
|
21
|
+
// quem quer outra altura escreve uma classe. Sem prop, sem pixel cru no consumidor.
|
|
22
|
+
import React from "react";
|
|
23
|
+
import { ResponsiveContainer, Tooltip, Legend } from "recharts";
|
|
24
|
+
import { cx, useAureaStrings } from "./internal.js";
|
|
25
|
+
export function Chart({ children, label, className }) {
|
|
26
|
+
const s = useAureaStrings();
|
|
27
|
+
const nome = label ?? s.chartLabel;
|
|
28
|
+
// O nome vai para os DOIS: o grupo (que também abriga legenda e tooltip, que ficam FORA do
|
|
29
|
+
// <svg>) e o desenho. Medido em 01/08/2026: o motor emite `<title></title>` vazio, e o <svg>
|
|
30
|
+
// é role="application" com tabindex=0 — quem chega nele pelo Tab ouviria "application" e mais
|
|
31
|
+
// nada. `title` é prop do gráfico do motor, não da caixa, então o repasse é aqui. Se o
|
|
32
|
+
// consumidor já passou o seu, o dele vence.
|
|
33
|
+
const desenho = React.isValidElement(children) && children.props.title == null
|
|
34
|
+
? React.cloneElement(children, { title: nome }) : children;
|
|
35
|
+
return _jsx("div", { className: cx("chart", className), role: "group", "aria-label": nome, children: _jsx(ResponsiveContainer, { width: "100%", height: "100%", children: desenho }) });
|
|
36
|
+
}
|
|
37
|
+
// ChartTooltip: reusa `.tooltip`, a mesma superfície do Tooltip da Aurea — o valor sob o cursor
|
|
38
|
+
// é um rótulo, não um card. O quadradinho de cor vem do `color` do payload (é DADO: a cor da
|
|
39
|
+
// série), então é o único `style` inline do arquivo.
|
|
40
|
+
// ponytail: sem formatador de valor. `tickFormatter` do eixo já é do motor, e nenhum consumidor
|
|
41
|
+
// pediu o do tooltip — entra quando pedir.
|
|
42
|
+
export function ChartTooltip(props) {
|
|
43
|
+
return _jsx(Tooltip, { cursor: { className: "chart-cursor" }, ...props, content: ({ active, payload, label }) => {
|
|
44
|
+
if (!active || !payload?.length)
|
|
45
|
+
return null;
|
|
46
|
+
return _jsxs("div", { className: "tooltip chart-tooltip", children: [label != null && label !== "" && _jsx("strong", { children: String(label) }), payload.map((p, i) => _jsxs("span", { className: "chart-key", children: [_jsx("i", { style: { background: p.color } }), p.name, _jsx("b", { children: String(p.value) })] }, p.dataKey ?? i))] });
|
|
47
|
+
} });
|
|
48
|
+
}
|
|
49
|
+
// ChartLegend: lista de séries. `value` do payload é o nome legível da série (o prop `name`),
|
|
50
|
+
// não o valor do dado — é o nome do campo no Recharts e não dá para renomear.
|
|
51
|
+
export function ChartLegend(props) {
|
|
52
|
+
return _jsx(Legend, { verticalAlign: "bottom", ...props, content: ({ payload }) => _jsx("ul", { className: "chart-legend", children: (payload ?? []).map((p, i) => _jsxs("li", { className: "chart-key", children: [_jsx("i", { style: { background: p.color } }), p.value] }, p.value ?? i)) }) });
|
|
53
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// Fase 9 (achado A5): este arquivo saiu do index.tsx de 970 linhas. Um módulo por categoria
|
|
4
|
+
// do registry — a taxonomia já existia e é gateada. A ordem de import entre eles é um DAG:
|
|
5
|
+
// internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
6
|
+
import { cx, useAureaStrings } from "./internal.js";
|
|
7
|
+
import { Icon } from "./system.js";
|
|
8
|
+
// copyable: o gatilho é marcado com data-aurea-copy e o COMPORTAMENTO mora no aurea.js do
|
|
9
|
+
// core (uma implementação para React e para HTML puro). O onClick daqui atende quem só
|
|
10
|
+
// carrega o pacote React; ele para a propagação pro core não copiar duas vezes.
|
|
11
|
+
export function CodeBlock({ children, language = "text", copyable, className }) {
|
|
12
|
+
const s = useAureaStrings();
|
|
13
|
+
// tabIndex no <pre>: `.code-block` é `overflow:auto` por construção, então é REGIÃO ROLÁVEL
|
|
14
|
+
// e não tem nada focável dentro — quem navega por teclado não alcança o código que passa da
|
|
15
|
+
// largura. É a regra `scrollable-region-focusable` do axe, e o mesmo defeito que o painel de
|
|
16
|
+
// demo do catálogo já tinha corrigido em 30/07/2026 no lado dele; aqui, na biblioteca, ele
|
|
17
|
+
// seguia aberto e só não aparecia porque nenhuma linha era comprida o bastante. Quem o achou
|
|
18
|
+
// foi o `catalog-sweep` em 10/08/2026, quando o bloco do I1 fez a linha de import crescer.
|
|
19
|
+
const pre = _jsx("pre", { className: cx("code-block", !copyable && className), "data-language": language, tabIndex: 0, children: _jsx("code", { children: children }) });
|
|
20
|
+
if (!copyable)
|
|
21
|
+
return pre;
|
|
22
|
+
const onCopy = (e) => { e.stopPropagation(); window.Aurea?.copy?.(e.currentTarget) ?? navigator.clipboard?.writeText(children); };
|
|
23
|
+
return _jsxs("div", { className: cx("code-block-wrap", className), "data-aurea-copy-scope": true, children: [_jsxs("button", { type: "button", className: "btn btn-icon btn-ghost copy-code", "data-aurea-copy": true, "aria-label": s.copyCode, onClick: onCopy, children: [_jsx(Icon, { name: "copy", size: "sm", className: "c-copy" }), _jsx(Icon, { name: "checkmark", size: "sm", className: "c-done" })] }), pre] });
|
|
24
|
+
}
|
package/dist/code-editor.js
CHANGED
package/dist/code.d.ts
CHANGED
|
@@ -1,13 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
language?: string;
|
|
4
|
-
copyable?: boolean;
|
|
5
|
-
className?: string;
|
|
6
|
-
}): import("react").JSX.Element;
|
|
7
|
-
export declare function LogStream({ lines }: {
|
|
8
|
-
lines: Array<{
|
|
9
|
-
time?: string;
|
|
10
|
-
level?: string;
|
|
11
|
-
text: string;
|
|
12
|
-
}>;
|
|
13
|
-
}): import("react").JSX.Element;
|
|
1
|
+
export * from "./code-client.js";
|
|
2
|
+
export { LogStream } from "./markup.js";
|
package/dist/code.js
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { Icon } from "./system.js";
|
|
7
|
-
// copyable: o gatilho é marcado com data-aurea-copy e o COMPORTAMENTO mora no aurea.js do
|
|
8
|
-
// core (uma implementação para React e para HTML puro). O onClick daqui atende quem só
|
|
9
|
-
// carrega o pacote React; ele para a propagação pro core não copiar duas vezes.
|
|
10
|
-
export function CodeBlock({ children, language = "text", copyable, className }) {
|
|
11
|
-
const s = useAureaStrings();
|
|
12
|
-
const pre = _jsx("pre", { className: cx("code-block", !copyable && className), "data-language": language, children: _jsx("code", { children: children }) });
|
|
13
|
-
if (!copyable)
|
|
14
|
-
return pre;
|
|
15
|
-
const onCopy = (e) => { e.stopPropagation(); window.Aurea?.copy?.(e.currentTarget) ?? navigator.clipboard?.writeText(children); };
|
|
16
|
-
return _jsxs("div", { className: cx("code-block-wrap", className), "data-aurea-copy-scope": true, children: [_jsxs("button", { type: "button", className: "btn btn-icon btn-ghost copy-code", "data-aurea-copy": true, "aria-label": s.copyCode, onClick: onCopy, children: [_jsx(Icon, { name: "copy", size: "sm", className: "c-copy" }), _jsx(Icon, { name: "checkmark", size: "sm", className: "c-done" })] }), pre] });
|
|
17
|
-
}
|
|
18
|
-
export function LogStream({ lines }) { return _jsx("div", { className: "log-stream", role: "log", "aria-live": "polite", children: lines.map((l, n) => _jsxs("div", { className: cx("log-line", l.level && `log-${l.level}`), children: [_jsx("time", { children: l.time }), _jsx("span", { children: l.text })] }, n)) }); }
|
|
1
|
+
// VITRINE da categoria — é este arquivo que `@aurea-uds/react/code` resolve. Sem `"use client"`
|
|
2
|
+
// de propósito: a diretiva contamina o módulo inteiro e faria a marcação pura chegar como cliente
|
|
3
|
+
// por vizinhança (ADR-0026; o check 26b reprova quem a puser de volta aqui).
|
|
4
|
+
export * from "./code-client.js";
|
|
5
|
+
export { LogStream } from "./markup.js";
|
package/dist/communication.js
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React, { type HTMLAttributes, type RefAttributes, type ReactNode } from "react";
|
|
2
|
+
export declare function Table({ caption, children, className, ...props }: HTMLAttributes<HTMLTableElement> & RefAttributes<HTMLTableElement> & {
|
|
3
|
+
caption?: ReactNode;
|
|
4
|
+
}): React.JSX.Element;
|
|
5
|
+
export interface SortableItem {
|
|
6
|
+
id: string;
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export interface SortableListProps extends Omit<HTMLAttributes<HTMLUListElement>, "onReorder">, RefAttributes<HTMLUListElement> {
|
|
10
|
+
items: SortableItem[];
|
|
11
|
+
onReorder: (from: number, to: number) => void;
|
|
12
|
+
label?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function SortableList({ items, onReorder, label, className, ...props }: SortableListProps): React.JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// Fase 9 (achado A5): este arquivo saiu do index.tsx de 970 linhas. Um módulo por categoria
|
|
4
|
+
// do registry — a taxonomia já existia e é gateada. A ordem de import entre eles é um DAG:
|
|
5
|
+
// internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { cx, useAureaStrings, useReorder } from "./internal.js";
|
|
8
|
+
import { Icon } from "./system.js";
|
|
9
|
+
export function Table({ caption, children, className, ...props }) { const s = useAureaStrings(); return _jsx("div", { className: "table-region", role: "region", "aria-label": typeof caption === "string" ? caption : s.tableLabel, tabIndex: 0, children: _jsxs("table", { className: cx("table", className), ...props, children: [caption && _jsx("caption", { children: caption }), children] }) }); }
|
|
10
|
+
// O protocolo de teclado e de ponteiro saiu daqui para o `useReorder` do `internal` no item N1,
|
|
11
|
+
// quando o `BlockEditor` virou o segundo dono dele. A DOM abaixo não mudou uma vírgula na
|
|
12
|
+
// extração — é o que o gate de pixel e o `skin.spec` continuam medindo.
|
|
13
|
+
export function SortableList({ items, onReorder, label, className, ...props }) {
|
|
14
|
+
const s = useAureaStrings();
|
|
15
|
+
const bid = React.useId();
|
|
16
|
+
const r = useReorder({ count: items.length, order: items, onReorder,
|
|
17
|
+
rowSelector: ".sortable-item", handleSelector: ".sortable-handle" });
|
|
18
|
+
return _jsxs(_Fragment, { children: [_jsx("ul", { ref: r.ref, className: cx("sortable-list", className), "aria-label": label ?? s.sortableLabel, ...props, children: items.map((it, i) => {
|
|
19
|
+
const lid = `${bid}l${i}`, hid = `${bid}h${i}`;
|
|
20
|
+
return _jsxs("li", { className: "sortable-item", "data-grabbed": r.pego === i || undefined, children: [_jsxs("button", { type: "button", id: hid, className: "sortable-handle", "aria-labelledby": `${hid} ${lid}`, "aria-describedby": `${bid}ajuda`, "aria-pressed": r.pego === i, onKeyDown: e => r.teclado(e, i), onPointerDown: e => r.ponteiroBaixo(e, i), onPointerMove: r.ponteiroMove, onPointerUp: r.ponteiroSolta, onPointerCancel: r.ponteiroSolta, children: [_jsx(Icon, { name: "drag--horizontal" }), _jsx("span", { className: "sr-only", children: s.sortableHandle })] }), _jsx("span", { id: lid, className: "sortable-label", children: it.label })] }, it.id);
|
|
21
|
+
}) }), _jsx("span", { id: `${bid}ajuda`, className: "sr-only", children: s.sortableHelp }), _jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", children: r.aviso })] });
|
|
22
|
+
}
|
package/dist/data-display.d.ts
CHANGED
|
@@ -1,23 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export { Kbd } from "./
|
|
3
|
-
export declare function KPI({ label, value, trend, className, ...props }: HTMLAttributes<HTMLDivElement> & RefAttributes<HTMLDivElement> & {
|
|
4
|
-
label: ReactNode;
|
|
5
|
-
value: ReactNode;
|
|
6
|
-
trend?: ReactNode;
|
|
7
|
-
}): React.JSX.Element;
|
|
8
|
-
export declare function DataList({ items }: {
|
|
9
|
-
items: Array<{
|
|
10
|
-
term: ReactNode;
|
|
11
|
-
value: ReactNode;
|
|
12
|
-
}>;
|
|
13
|
-
}): React.JSX.Element;
|
|
14
|
-
export declare function Timeline({ items }: {
|
|
15
|
-
items: Array<{
|
|
16
|
-
title: ReactNode;
|
|
17
|
-
description?: ReactNode;
|
|
18
|
-
time?: ReactNode;
|
|
19
|
-
}>;
|
|
20
|
-
}): React.JSX.Element;
|
|
21
|
-
export declare function Table({ caption, children, className, ...props }: HTMLAttributes<HTMLTableElement> & RefAttributes<HTMLTableElement> & {
|
|
22
|
-
caption?: ReactNode;
|
|
23
|
-
}): React.JSX.Element;
|
|
1
|
+
export * from "./data-display-client.js";
|
|
2
|
+
export { Kbd, KPI, DataList, Timeline, Prose } from "./markup.js";
|
package/dist/data-display.js
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { cx, useAureaStrings } from "./internal.js";
|
|
7
|
-
import { Card } from "./layout.js";
|
|
8
|
-
// Kbd é implementado em ./internal (o Button depende dele); a casa PÚBLICA dele é esta.
|
|
9
|
-
export { Kbd } from "./internal.js";
|
|
10
|
-
export function KPI({ label, value, trend, className, ...props }) { return _jsxs(Card, { className: cx("kpi", className), ...props, children: [_jsx("span", { className: "muted", children: label }), _jsx("strong", { children: value }), trend && _jsx("small", { children: trend })] }); }
|
|
11
|
-
export function DataList({ items }) { return _jsx("dl", { className: "data-list", children: items.map((i, n) => _jsxs(React.Fragment, { children: [_jsx("dt", { children: i.term }), _jsx("dd", { children: i.value })] }, n)) }); }
|
|
12
|
-
export function Timeline({ items }) { return _jsx("ol", { className: "timeline", children: items.map((i, n) => _jsxs("li", { children: [_jsx("span", { className: "timeline-dot" }), _jsxs("div", { children: [_jsx("strong", { children: i.title }), i.description && _jsx("p", { children: i.description }), i.time && _jsx("small", { className: "muted", children: i.time })] })] }, n)) }); }
|
|
13
|
-
export function Table({ caption, children, className, ...props }) { const s = useAureaStrings(); return _jsx("div", { className: "table-region", role: "region", "aria-label": typeof caption === "string" ? caption : s.tableLabel, tabIndex: 0, children: _jsxs("table", { className: cx("table", className), ...props, children: [caption && _jsx("caption", { children: caption }), children] }) }); }
|
|
1
|
+
// VITRINE da categoria — é este arquivo que `@aurea-uds/react/data-display` resolve. Sem
|
|
2
|
+
// `"use client"` de propósito: a diretiva contamina o módulo inteiro e faria a marcação pura
|
|
3
|
+
// chegar como cliente por vizinhança (ADR-0026; o check 26b reprova quem a puser de volta aqui).
|
|
4
|
+
export * from "./data-display-client.js";
|
|
5
|
+
export { Kbd, KPI, DataList, Timeline, Prose } from "./markup.js";
|