@aurea-uds/react 0.36.0 → 0.37.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/agents.js +3 -1
- package/dist/code-client.d.ts +15 -1
- package/dist/code-client.js +18 -4
- package/dist/code-editor.js +4 -1
- package/dist/code-highlight.d.ts +14 -0
- package/dist/code-highlight.js +92 -0
- package/package.json +31 -2
package/dist/agents.js
CHANGED
|
@@ -298,5 +298,7 @@ export function InterAgentMessage({ messages, label, className, ...props }) {
|
|
|
298
298
|
// cartão responder por dois contratos — o erro que o `TaskQueue` recusou no H.b.
|
|
299
299
|
export function AutomationCard({ name, description, trigger, action, enabled, onToggle, lastRun, lastResult, details, actions, className, ...props }) {
|
|
300
300
|
const s = useAureaStrings();
|
|
301
|
-
|
|
301
|
+
// `data-enabled` só quando LIGADA: o `false` saía como `data-enabled="false"` e escapava da regra que faz a regra
|
|
302
|
+
// desligada recuar (`:not([data-enabled])`) — achado do check 49, lote 1, 20/10/2026.
|
|
303
|
+
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
304
|
}
|
package/dist/code-client.d.ts
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
|
|
2
|
+
/** Um pedaço de uma linha de código, com a classe da cor (`tok-keyword`, `tok-string`…) quando tem cor. */
|
|
3
|
+
export interface CodeToken {
|
|
4
|
+
text: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
/** Uma linha de código: os pedaços, na ordem. */
|
|
8
|
+
export type CodeLine = CodeToken[];
|
|
9
|
+
/** Quem colore: recebe o código e a língua e devolve as linhas, ou `null` quando não conhece a língua. O da Aurea é o
|
|
10
|
+
* `highlightCode` de `@aurea-uds/react/code-highlight`. */
|
|
11
|
+
export type CodeHighlighter = (code: string, language: string) => CodeLine[] | null;
|
|
12
|
+
export declare function CodeBlock({ children, language, copyable, preview, lineNumbers, highlight, className }: {
|
|
3
13
|
children: string;
|
|
4
14
|
language?: string;
|
|
5
15
|
copyable?: boolean;
|
|
6
16
|
/** A prévia viva do código: com ela, o bloco vira a caixa de exemplo, com as abas Prévia | Código. */
|
|
7
17
|
preview?: React.ReactNode;
|
|
18
|
+
/** Mostra o número de cada linha à esquerda. O número não entra no texto copiado nem é lido pelo leitor de tela. */
|
|
19
|
+
lineNumbers?: boolean;
|
|
20
|
+
/** Colore o código. Passe o `highlightCode` de `@aurea-uds/react/code-highlight` (os analisadores são peer opcional). */
|
|
21
|
+
highlight?: CodeHighlighter;
|
|
8
22
|
className?: string;
|
|
9
23
|
}): React.JSX.Element;
|
package/dist/code-client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
// Fase 9 (achado A5): este arquivo saiu do index.tsx de 970 linhas. Um módulo por categoria
|
|
4
4
|
// do registry — a taxonomia já existia e é gateada. A ordem de import entre eles é um DAG:
|
|
5
5
|
// internal → system → actions → feedback → inputs → navigation → layout → data-display → resto.
|
|
@@ -29,9 +29,17 @@ function CaixaDeExemplo({ preview, codigo, className }) {
|
|
|
29
29
|
const botao = (a, rotulo) => _jsx("button", { type: "button", role: "tab", id: `${id}-${a}`, ref: a === "preview" ? refPrevia : refCodigo, className: aba === a ? "active" : undefined, "aria-selected": aba === a, "aria-controls": `${id}-${a}-panel`, tabIndex: aba === a ? 0 : -1, onClick: () => setAba(a), onKeyDown: tecla, children: rotulo });
|
|
30
30
|
return _jsxs("div", { className: cx("demo code-preview", className), children: [_jsx("div", { className: "demo-tabs", children: _jsxs("div", { className: "segmented", role: "tablist", children: [botao("preview", s.codeBlockPreview), botao("code", s.codeBlockCode)] }) }), _jsx("div", { className: "demo-panel", "data-panel": "preview", role: "tabpanel", id: `${id}-preview-panel`, "aria-labelledby": `${id}-preview`, tabIndex: 0, hidden: aba !== "preview", children: preview }), _jsx("div", { className: "demo-panel demo-code", "data-panel": "code", role: "tabpanel", id: `${id}-code-panel`, "aria-labelledby": `${id}-code`, tabIndex: 0, hidden: aba !== "code", children: codigo })] });
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
// lineNumbers e highlight (lote V, 20/10/2026): as linhas viram um <span class="code-line"> cada, com o "\n" entre
|
|
33
|
+
// elas — o texto do bloco continua IGUAL ao código (copiar com o mouse traz o mesmo texto), e o número é desenhado pelo
|
|
34
|
+
// CSS, sem entrar no texto nem no leitor de tela. Sem as duas, a marcação é a de antes, sem mudar nada.
|
|
35
|
+
// O "\n" do fim (o código que termina em quebra de linha) não vira uma linha numerada e vazia: ele sai depois da última.
|
|
36
|
+
function linhasDoCodigo(codigo, language, highlight) {
|
|
37
|
+
const linhas = highlight?.(codigo, language) ?? codigo.split("\n").map(l => l === "" ? [] : [{ text: l }]);
|
|
38
|
+
return codigo.endsWith("\n") && linhas.length > 1 && linhas[linhas.length - 1].length === 0 ? linhas.slice(0, -1) : linhas;
|
|
39
|
+
}
|
|
40
|
+
export function CodeBlock({ children, language = "text", copyable, preview, lineNumbers, highlight, className }) {
|
|
33
41
|
if (preview !== undefined)
|
|
34
|
-
return _jsx(CaixaDeExemplo, { preview: preview, className: className, codigo: _jsx(CodeBlock, { language: language, copyable: copyable, children: children }) });
|
|
42
|
+
return _jsx(CaixaDeExemplo, { preview: preview, className: className, codigo: _jsx(CodeBlock, { language: language, copyable: copyable, lineNumbers: lineNumbers, highlight: highlight, children: children }) });
|
|
35
43
|
const s = useAureaStrings();
|
|
36
44
|
// tabIndex no <pre>: `.code-block` é `overflow:auto` por construção, então é REGIÃO ROLÁVEL
|
|
37
45
|
// e não tem nada focável dentro — quem navega por teclado não alcança o código que passa da
|
|
@@ -39,7 +47,13 @@ export function CodeBlock({ children, language = "text", copyable, preview, clas
|
|
|
39
47
|
// demo do catálogo já tinha corrigido em 30/07/2026 no lado dele; aqui, na biblioteca, ele
|
|
40
48
|
// seguia aberto e só não aparecia porque nenhuma linha era comprida o bastante. Quem o achou
|
|
41
49
|
// foi o `catalog-sweep` em 10/08/2026, quando o bloco do I1 fez a linha de import crescer.
|
|
42
|
-
const
|
|
50
|
+
const linhas = lineNumbers || highlight ? linhasDoCodigo(children, language, highlight) : null;
|
|
51
|
+
const colorido = linhas != null && highlight != null && linhas.some(l => l.some(p => p.className));
|
|
52
|
+
// Os algarismos da última linha: a coluna do número tem a largura deles (99 → 2, 100 → 3).
|
|
53
|
+
const digitos = lineNumbers && linhas ? { "--code-line-digits": String(linhas.length).length } : undefined;
|
|
54
|
+
const pre = _jsx("pre", { className: cx("code-block", lineNumbers && "code-block-numbered", colorido && "code-block-highlighted", !copyable && className), style: digitos, "data-language": language, tabIndex: 0, children: _jsx("code", { children: linhas
|
|
55
|
+
? _jsxs(_Fragment, { children: [linhas.map((l, i) => _jsxs(React.Fragment, { children: [_jsx("span", { className: "code-line", children: l.map((p, j) => p.className ? _jsx("span", { className: p.className, children: p.text }, j) : p.text) }), i < linhas.length - 1 ? "\n" : null] }, i)), children.endsWith("\n") ? "\n" : null] })
|
|
56
|
+
: children }) });
|
|
43
57
|
if (!copyable)
|
|
44
58
|
return pre;
|
|
45
59
|
// 0.28.0: o "copiado" é dito ao leitor de tela. Com o `aurea.js` na página, é ele quem diz (pelo
|
package/dist/code-editor.js
CHANGED
|
@@ -92,7 +92,10 @@ export function CodeEditor({ defaultValue = "", onChange, extensions, readOnly =
|
|
|
92
92
|
const dynExt = () => [
|
|
93
93
|
EditorState.readOnly.of(readOnly),
|
|
94
94
|
EditorView.editable.of(!readOnly),
|
|
95
|
-
|
|
95
|
+
// `tabindex="0"` (21/10/2026): o CodeMirror põe -1 na área de rolagem, e com o código mais alto que o editor o axe
|
|
96
|
+
// reprovava `scrollable-region-focusable` — a área rola e nada dentro DIZ que recebe o teclado. O conteúdo já era
|
|
97
|
+
// parada de Tab (contenteditable); no readOnly, é o que deixa o teclado chegar ao código para rolar.
|
|
98
|
+
EditorView.contentAttributes.of({ "aria-label": label, tabindex: "0" }),
|
|
96
99
|
...(extensions ?? []),
|
|
97
100
|
];
|
|
98
101
|
React.useEffect(() => {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CodeLine } from "./code-client.js";
|
|
2
|
+
/** As línguas que `highlightCode` colore. Com outra, ele devolve `null` e o `CodeBlock` mostra o texto puro. */
|
|
3
|
+
export declare const highlightLanguages: readonly string[];
|
|
4
|
+
/**
|
|
5
|
+
* Colore o código para o `CodeBlock` (a prop `highlight`): devolve as linhas, cada uma com os pedaços de texto e a
|
|
6
|
+
* classe da cor. Língua que não está em `highlightLanguages` devolve `null`, e o bloco sai sem cor.
|
|
7
|
+
*
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import {CodeBlock} from "@aurea-uds/react";
|
|
10
|
+
* import {highlightCode} from "@aurea-uds/react/code-highlight";
|
|
11
|
+
* <CodeBlock language="tsx" highlight={highlightCode} lineNumbers>{code}</CodeBlock>
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function highlightCode(code: string, language: string): CodeLine[] | null;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// AS CORES DO CÓDIGO (lote V, 20/10/2026). O Victor, comparando as caixas de código do site com as da referência:
|
|
2
|
+
// "não são como dos outros, com numero de linhas laterais e cores". A ficha do `CodeBlock` já prometia código com cores
|
|
3
|
+
// de sintaxe, e o código desenhava texto puro.
|
|
4
|
+
//
|
|
5
|
+
// O MOTOR é o mesmo do `CodeEditor` (decisão do Victor, "A: motor da Aurea"): o `@lezer/highlight`, com os
|
|
6
|
+
// analisadores do próprio Lezer. A função `highlightCode` dele colore código PARADO — sem editor, sem espera e sem
|
|
7
|
+
// navegador —, então serve ao site, montado no Node, e a quem usa o `CodeBlock` no servidor ou no cliente.
|
|
8
|
+
// As CORES são as do `aureaHighlightStyle` do `CodeEditor`, pelos mesmos grupos de etiquetas: o comentário apagado e
|
|
9
|
+
// em itálico, a palavra-chave e o nome de tipo em azul, o texto em verde, o número em amarelo, a função em 600. Lá elas
|
|
10
|
+
// são estilo de linha (o editor monta no navegador); aqui são CLASSES (`tok-*`), pintadas pelo `aurea.css` com os
|
|
11
|
+
// mesmos tokens, porque o HTML parado não carrega estilo calculado.
|
|
12
|
+
//
|
|
13
|
+
// Módulo próprio, como o `code-editor`: os analisadores são peer OPCIONAL, e quem não usa as cores não os instala
|
|
14
|
+
// (o check 19 do `validate.py` cobra que só este arquivo e o do editor importam o `@lezer/`).
|
|
15
|
+
import { highlightCode as colorirArvore, tagHighlighter, tags as t } from "@lezer/highlight";
|
|
16
|
+
import { parser as js } from "@lezer/javascript";
|
|
17
|
+
import { parser as css } from "@lezer/css";
|
|
18
|
+
import { parser as html } from "@lezer/html";
|
|
19
|
+
import { parser as json } from "@lezer/json";
|
|
20
|
+
import { StreamLanguage } from "@codemirror/language";
|
|
21
|
+
import { shell } from "@codemirror/legacy-modes/mode/shell";
|
|
22
|
+
// As etiquetas do Lezer → as classes que o `aurea.css` pinta. Os grupos são os do `aureaHighlightStyle`.
|
|
23
|
+
const destaque = tagHighlighter([
|
|
24
|
+
{ tag: [t.comment, t.lineComment, t.blockComment, t.docComment], class: "tok-comment" },
|
|
25
|
+
{ tag: [t.keyword, t.controlKeyword, t.moduleKeyword, t.operatorKeyword, t.definitionKeyword, t.modifier, t.self, t.atom, t.bool, t.null, t.typeName, t.className, t.namespace, t.tagName], class: "tok-keyword" },
|
|
26
|
+
{ tag: [t.string, t.character, t.docString, t.regexp, t.escape, t.special(t.string)], class: "tok-string" },
|
|
27
|
+
{ tag: [t.number, t.integer, t.float, t.unit], class: "tok-number" },
|
|
28
|
+
{ tag: [t.propertyName, t.attributeName, t.labelName], class: "tok-property" },
|
|
29
|
+
{ tag: t.function(t.variableName), class: "tok-function" },
|
|
30
|
+
{ tag: t.invalid, class: "tok-invalid" },
|
|
31
|
+
]);
|
|
32
|
+
// As línguas que a Aurea colore. Os nomes são os que o `CodeBlock` recebe em `language`; `sh` e `shell` são o bash.
|
|
33
|
+
const ANALISADORES = {
|
|
34
|
+
js, javascript: js,
|
|
35
|
+
jsx: js.configure({ dialect: "jsx" }),
|
|
36
|
+
ts: js.configure({ dialect: "ts" }), typescript: js.configure({ dialect: "ts" }),
|
|
37
|
+
tsx: js.configure({ dialect: "jsx ts" }),
|
|
38
|
+
css, html, json,
|
|
39
|
+
};
|
|
40
|
+
let bash;
|
|
41
|
+
// O bash vem do modo antigo do CodeMirror (o Lezer não tem gramática de shell); ele só é montado quando pedido.
|
|
42
|
+
function analisador(lingua) {
|
|
43
|
+
const l = lingua.toLowerCase();
|
|
44
|
+
if (l === "bash" || l === "sh" || l === "shell")
|
|
45
|
+
return bash ??= StreamLanguage.define(shell).parser;
|
|
46
|
+
return ANALISADORES[l];
|
|
47
|
+
}
|
|
48
|
+
/** As línguas que `highlightCode` colore. Com outra, ele devolve `null` e o `CodeBlock` mostra o texto puro. */
|
|
49
|
+
export const highlightLanguages = ["bash", "css", "html", "javascript", "js", "json", "jsx", "sh", "shell", "ts", "tsx", "typescript"];
|
|
50
|
+
/**
|
|
51
|
+
* Colore o código para o `CodeBlock` (a prop `highlight`): devolve as linhas, cada uma com os pedaços de texto e a
|
|
52
|
+
* classe da cor. Língua que não está em `highlightLanguages` devolve `null`, e o bloco sai sem cor.
|
|
53
|
+
*
|
|
54
|
+
* ```tsx
|
|
55
|
+
* import {CodeBlock} from "@aurea-uds/react";
|
|
56
|
+
* import {highlightCode} from "@aurea-uds/react/code-highlight";
|
|
57
|
+
* <CodeBlock language="tsx" highlight={highlightCode} lineNumbers>{code}</CodeBlock>
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function highlightCode(code, language) {
|
|
61
|
+
const p = analisador(language);
|
|
62
|
+
if (!p)
|
|
63
|
+
return null;
|
|
64
|
+
// O TRECHO DE JSX. O exemplo de documentação é um pedaço — várias linhas de JSX soltas, uma embaixo da outra —, e o
|
|
65
|
+
// analisador lê código de verdade: o `<` da segunda linha vira "menor que", e a partir dali as cores trocam de lugar
|
|
66
|
+
// (medido na página do Button, 20/10/2026: só a primeira linha saía certa). Quando a leitura direta tem erro, o
|
|
67
|
+
// trecho é lido de novo dentro de um fragmento (`<>…</>`), fica a leitura com menos erros, e só o trecho original é
|
|
68
|
+
// pintado — o fragmento não aparece.
|
|
69
|
+
let texto = code, arvore = p.parse(code), de = 0;
|
|
70
|
+
if (JSX.has(language.toLowerCase())) {
|
|
71
|
+
const direto = erros(arvore);
|
|
72
|
+
if (direto > 0) {
|
|
73
|
+
const embrulhado = `<>${code}</>`, outra = p.parse(embrulhado);
|
|
74
|
+
if (erros(outra) < direto) {
|
|
75
|
+
texto = embrulhado;
|
|
76
|
+
arvore = outra;
|
|
77
|
+
de = 2;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const linhas = [[]];
|
|
82
|
+
colorirArvore(texto, arvore, destaque, (pedaco, classes) => { linhas[linhas.length - 1].push(classes ? { text: pedaco, className: classes } : { text: pedaco }); }, () => { linhas.push([]); }, de, de + code.length);
|
|
83
|
+
return linhas;
|
|
84
|
+
}
|
|
85
|
+
const JSX = new Set(["jsx", "tsx"]);
|
|
86
|
+
// Quantos nós de erro a leitura deixou: é a régua para escolher entre a leitura direta e a do fragmento.
|
|
87
|
+
function erros(arvore) {
|
|
88
|
+
let n = 0;
|
|
89
|
+
arvore.iterate({ enter: (no) => { if (no.type.isError)
|
|
90
|
+
n++; } });
|
|
91
|
+
return n;
|
|
92
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurea-uds/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.37.0",
|
|
4
4
|
"description": "Os componentes React da Aurea UDS. Importe @aurea-uds/fonts/css e @aurea-uds/core/css junto.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aurea",
|
|
@@ -90,6 +90,10 @@
|
|
|
90
90
|
"types": "./dist/code-editor.d.ts",
|
|
91
91
|
"import": "./dist/code-editor.js"
|
|
92
92
|
},
|
|
93
|
+
"./code-highlight": {
|
|
94
|
+
"types": "./dist/code-highlight.d.ts",
|
|
95
|
+
"import": "./dist/code-highlight.js"
|
|
96
|
+
},
|
|
93
97
|
"./data-grid": {
|
|
94
98
|
"types": "./dist/data-grid.d.ts",
|
|
95
99
|
"import": "./dist/data-grid.js"
|
|
@@ -127,9 +131,14 @@
|
|
|
127
131
|
},
|
|
128
132
|
"peerDependencies": {
|
|
129
133
|
"@codemirror/language": "^6.12.4",
|
|
134
|
+
"@codemirror/legacy-modes": "^6.5.5",
|
|
130
135
|
"@codemirror/state": "^6.7.1",
|
|
131
136
|
"@codemirror/view": "^6.43.6",
|
|
137
|
+
"@lezer/css": "^1.3.9",
|
|
132
138
|
"@lezer/highlight": "^1.2.3",
|
|
139
|
+
"@lezer/html": "^1.3.13",
|
|
140
|
+
"@lezer/javascript": "^1.5.6",
|
|
141
|
+
"@lezer/json": "^1.0.3",
|
|
133
142
|
"@tanstack/react-table": "^8.21.3",
|
|
134
143
|
"@tisoap/react-flow-smart-edge": "^5.0.0",
|
|
135
144
|
"@xyflow/react": "^12.11.3",
|
|
@@ -181,13 +190,33 @@
|
|
|
181
190
|
},
|
|
182
191
|
"@tisoap/react-flow-smart-edge": {
|
|
183
192
|
"optional": true
|
|
193
|
+
},
|
|
194
|
+
"@lezer/javascript": {
|
|
195
|
+
"optional": true
|
|
196
|
+
},
|
|
197
|
+
"@lezer/css": {
|
|
198
|
+
"optional": true
|
|
199
|
+
},
|
|
200
|
+
"@lezer/html": {
|
|
201
|
+
"optional": true
|
|
202
|
+
},
|
|
203
|
+
"@lezer/json": {
|
|
204
|
+
"optional": true
|
|
205
|
+
},
|
|
206
|
+
"@codemirror/legacy-modes": {
|
|
207
|
+
"optional": true
|
|
184
208
|
}
|
|
185
209
|
},
|
|
186
210
|
"devDependencies": {
|
|
187
|
-
"@codemirror/language": "^6.
|
|
211
|
+
"@codemirror/language": "^6.13.1",
|
|
212
|
+
"@codemirror/legacy-modes": "^6.5.5",
|
|
188
213
|
"@codemirror/state": "^6.7.1",
|
|
189
214
|
"@codemirror/view": "^6.43.6",
|
|
215
|
+
"@lezer/css": "^1.3.9",
|
|
190
216
|
"@lezer/highlight": "^1.2.3",
|
|
217
|
+
"@lezer/html": "^1.3.13",
|
|
218
|
+
"@lezer/javascript": "^1.5.6",
|
|
219
|
+
"@lezer/json": "^1.0.3",
|
|
191
220
|
"@tanstack/react-table": "8.21.3",
|
|
192
221
|
"codemirror": "^6.0.2",
|
|
193
222
|
"qr": "^0.6.0",
|