synthesisui 0.16.409 → 0.16.411
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/anatomy-from-sketch.js +16 -4
- package/dist/commands/doctor.js +71 -23
- package/dist/display-from-class.js +68 -0
- package/dist/doctor/transcribe.js +26 -9
- package/package.json +1 -1
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
* retyped ten-class string is where a `hover:` goes missing, and six components
|
|
28
28
|
* lost their states to exactly that (audit, dono, 01/08).
|
|
29
29
|
*/
|
|
30
|
+
import { displayFromClasses } from "./display-from-class.js";
|
|
30
31
|
import { frontierOf, rendersNothing, } from "./frontier-kind.js";
|
|
31
32
|
/** An svg's insides are geometry, not anatomy: the glyph is the node. */
|
|
32
33
|
const SVG_INTERNALS = new Set([
|
|
@@ -182,12 +183,23 @@ const NEUTRAL = new Set([
|
|
|
182
183
|
"nav",
|
|
183
184
|
"details",
|
|
184
185
|
]);
|
|
185
|
-
/**
|
|
186
|
+
/**
|
|
187
|
+
* `flex-col`, `grid` and `block` arrange DOWN; a bare `flex` arranges ACROSS.
|
|
188
|
+
*
|
|
189
|
+
* ONE READING OF THE BOX, not two. This used to run its own regex over the class string
|
|
190
|
+
* while `transcribe` ran another, and the two answers disagreed by construction: the form
|
|
191
|
+
* is a lossy reduction of `display` - it says "across or down" and drops the difference
|
|
192
|
+
* between a grid and a column. Both now come off the same table, so the form is DERIVED
|
|
193
|
+
* from the declaration instead of being a second opinion about it.
|
|
194
|
+
*/
|
|
186
195
|
function arrangement(classes) {
|
|
187
|
-
const
|
|
188
|
-
|
|
196
|
+
const box = displayFromClasses(classes);
|
|
197
|
+
const direction = box.flexDirection;
|
|
198
|
+
if (direction === "column" || direction === "column-reverse")
|
|
189
199
|
return "stack";
|
|
190
|
-
if (
|
|
200
|
+
if (direction === "row" || direction === "row-reverse")
|
|
201
|
+
return "row";
|
|
202
|
+
if (box.display === "flex" || box.display === "inline-flex")
|
|
191
203
|
return "row";
|
|
192
204
|
return "stack";
|
|
193
205
|
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -1090,42 +1090,90 @@ export async function doctor(opts) {
|
|
|
1090
1090
|
*/
|
|
1091
1091
|
const perApp = await readWiringPerApp(root, table.slug, config.pagesDir);
|
|
1092
1092
|
const targets = perApp.length > 0 ? perApp : [{ app: null, wiring }];
|
|
1093
|
-
|
|
1094
|
-
|
|
1093
|
+
/**
|
|
1094
|
+
* OS APPS QUE PEDEM A MESMA COISA VIRAM UM BLOCO SÓ, nomeando os dois.
|
|
1095
|
+
*
|
|
1096
|
+
* O DEFEITO, e ele é meu, do PR de algumas horas atrás: no `codelevel-monorepo` os DOIS apps
|
|
1097
|
+
* resolvem para a MESMA folha (`packages/ui/src/styles/globals.css`, o pacote compartilhado),
|
|
1098
|
+
* então o comando imprimiu a mesma instrução de 40 linhas DUAS VEZES, com o mesmo caminho e o
|
|
1099
|
+
* mesmo prefixo. O dono leu a parede duas vezes (medido no repositório dele, 09/09).
|
|
1100
|
+
*
|
|
1101
|
+
* Eu tinha escrito o aviso no comentário abaixo - *"num monorepo ele apareceria em escala:
|
|
1102
|
+
* dois blocos idênticos"* - sobre o caso do app JÁ FIADO, e entreguei a duplicata no caso do
|
|
1103
|
+
* que ainda falta. Nomear cada app foi o conserto certo; repetir a instrução não.
|
|
1104
|
+
*
|
|
1105
|
+
* A CHAVE É A INSTRUÇÃO, não o app: dois apps com a mesma folha, o mesmo prefixo e os mesmos
|
|
1106
|
+
* passos pendentes recebem uma instrução só. Um monorepo onde cada app tem folha própria volta
|
|
1107
|
+
* a receber uma por app, porque ali as instruções DIFEREM - é a resposta derivada, e não uma
|
|
1108
|
+
* regra sobre quantos apps existem.
|
|
1109
|
+
*/
|
|
1110
|
+
const blocks = new Map();
|
|
1095
1111
|
for (const { app, wiring: w } of targets) {
|
|
1096
1112
|
const sheet = app
|
|
1097
1113
|
? await globalSheetOf(root, `${app}/globals.css`)
|
|
1098
1114
|
: null;
|
|
1099
1115
|
/**
|
|
1100
1116
|
* O APP QUE JÁ ESTÁ FIADO SAI DA LISTA, nomeado. Repetir o setup para quem já o fez é o
|
|
1101
|
-
* defeito de 08/09 outra vez
|
|
1102
|
-
* idênticos, um deles cobrando o que já está colado.
|
|
1117
|
+
* defeito de 08/09 outra vez.
|
|
1103
1118
|
*/
|
|
1104
1119
|
const pending = !w.imported || !w.scoped || (w.fontsWritten && !w.fontsMapped);
|
|
1105
|
-
|
|
1120
|
+
const text = pending
|
|
1121
|
+
? setupPrompt(table.slug, {
|
|
1122
|
+
tokens: !w.imported,
|
|
1123
|
+
scope: !w.scoped,
|
|
1124
|
+
/** Só é passo quando o projeto TEM o arquivo de fontes - ver `readWiring`. */
|
|
1125
|
+
type: w.fontsWritten && !w.fontsMapped,
|
|
1126
|
+
...(sheet
|
|
1127
|
+
? { sheet: { path: sheet, prefix: prefixFrom(sheet) } }
|
|
1128
|
+
: {}),
|
|
1129
|
+
/**
|
|
1130
|
+
* DUAS LINHAS COM TAILWIND, UMA SEM - a mesma decisão que o `add` já toma pelo
|
|
1131
|
+
* projeto. Dizer "as duas linhas" a um projeto que precisa de uma manda o agente
|
|
1132
|
+
* procurar o que não existe.
|
|
1133
|
+
*/
|
|
1134
|
+
imports: config.styles === "css" ? 1 : 2,
|
|
1135
|
+
}).split("\n")
|
|
1136
|
+
: [];
|
|
1137
|
+
const key = `${pending ? "p" : "ok"}|${text.join("\n")}`;
|
|
1138
|
+
const found = blocks.get(key);
|
|
1139
|
+
if (found)
|
|
1140
|
+
found.apps.push(app ?? "");
|
|
1141
|
+
else
|
|
1142
|
+
blocks.set(key, { apps: [app ?? ""], text, pending });
|
|
1143
|
+
}
|
|
1144
|
+
const anyPending = [...blocks.values()].some((b) => b.pending);
|
|
1145
|
+
if (anyPending) {
|
|
1146
|
+
console.log("");
|
|
1147
|
+
console.log(body("Paste this into your agent - it does the setup for you:"));
|
|
1148
|
+
}
|
|
1149
|
+
for (const { apps, text, pending } of blocks.values()) {
|
|
1150
|
+
const named = apps.filter(Boolean);
|
|
1151
|
+
/**
|
|
1152
|
+
* O CABEÇALHO SÓ APARECE QUANDO HÁ MAIS DE UM APP no projeto - com um só ele seria cerimônia
|
|
1153
|
+
* sobre uma lista de um, e a maioria dos projetos é assim. Com vários, ele diz de QUEM é a
|
|
1154
|
+
* instrução, e o plural sai naturalmente: "apps/landing/app and apps/web/app".
|
|
1155
|
+
*/
|
|
1156
|
+
if (targets.length > 1 && named.length > 0) {
|
|
1157
|
+
/**
|
|
1158
|
+
* A LISTA SE LÊ EM VOZ ALTA, e o número dela não é fixo: "A and B" com dois,
|
|
1159
|
+
* "A, B and C" com três. `join(" and ")` daria "A and B and C", e `"both"` mentiria
|
|
1160
|
+
* no dia em que o monorepo tiver três apps na mesma folha - o mesmo erro de
|
|
1161
|
+
* dimensionar pela amostra, na escala de uma palavra.
|
|
1162
|
+
*/
|
|
1163
|
+
const lista = named.length > 1
|
|
1164
|
+
? `${named.slice(0, -1).join(", ")} and ${named[named.length - 1]}`
|
|
1165
|
+
: named[0];
|
|
1106
1166
|
console.log("");
|
|
1107
|
-
console.log(body(pending
|
|
1108
|
-
?
|
|
1109
|
-
|
|
1167
|
+
console.log(body(` ${lista} - ${pending
|
|
1168
|
+
? named.length > 1
|
|
1169
|
+
? "need it, and the steps are the same"
|
|
1170
|
+
: "still needs it"
|
|
1171
|
+
: "already wired, nothing to paste"}`));
|
|
1110
1172
|
}
|
|
1111
1173
|
if (!pending)
|
|
1112
1174
|
continue;
|
|
1113
1175
|
console.log("");
|
|
1114
|
-
console.log(snippet(
|
|
1115
|
-
tokens: !w.imported,
|
|
1116
|
-
scope: !w.scoped,
|
|
1117
|
-
/** Só é passo quando o projeto TEM o arquivo de fontes - ver `readWiring`. */
|
|
1118
|
-
type: w.fontsWritten && !w.fontsMapped,
|
|
1119
|
-
...(sheet
|
|
1120
|
-
? { sheet: { path: sheet, prefix: prefixFrom(sheet) } }
|
|
1121
|
-
: {}),
|
|
1122
|
-
/**
|
|
1123
|
-
* DUAS LINHAS COM TAILWIND, UMA SEM - a mesma decisão que o `add` já toma pelo
|
|
1124
|
-
* projeto. Dizer "as duas linhas" a um projeto que precisa de uma manda o agente
|
|
1125
|
-
* procurar o que não existe.
|
|
1126
|
-
*/
|
|
1127
|
-
imports: config.styles === "css" ? 1 : 2,
|
|
1128
|
-
}).split("\n")));
|
|
1176
|
+
console.log(snippet(text));
|
|
1129
1177
|
}
|
|
1130
1178
|
}
|
|
1131
1179
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O DISPLAY QUE O CLIENTE ESCREVEU, LIDO DE UM CLASS STRING - a tabela, num lugar só.
|
|
3
|
+
*
|
|
4
|
+
* O QUE O CLIENTE GANHA: o preview desenha a caixa que ele declarou, e não a que a
|
|
5
|
+
* plataforma teria adivinhado. `display` é a declaração que decide se o componente dele é
|
|
6
|
+
* uma linha, uma coluna, uma grade ou uma caixa em linha - e o desenho pergunta por ela
|
|
7
|
+
* para saber se o layout daquele nó é DELE. Sem ela, a forma inferida por nós vence a que
|
|
8
|
+
* ele escreveu, que é o inverso exato da lei de prioridade de layout.
|
|
9
|
+
*
|
|
10
|
+
* MEDIDO em 09/09 sobre três sistemas - dos componentes cuja raiz é estilizada por
|
|
11
|
+
* utilitário, quantos tinham `display` na receita: 2 de 58, 9 de 20 e 0 de 32; pela via de
|
|
12
|
+
* CSS Module, 48 de 196. A sintaxe que ele escolheu estava decidindo se a declaração dele
|
|
13
|
+
* sobrevivia, e ninguém escolhe uma sintaxe por esse motivo.
|
|
14
|
+
*
|
|
15
|
+
* A DIREÇÃO VIAJA JUNTO, ou `flex flex-col` vira uma linha: `display:flex` é `row` por
|
|
16
|
+
* padrão, e emitir o display sem a direção troca em silêncio toda coluna dele por uma
|
|
17
|
+
* linha - uma leitura pior que a anterior, porque parece deliberada.
|
|
18
|
+
*
|
|
19
|
+
* ESTE ARQUIVO TEM UM GÊMEO BYTE-IDÊNTICO em `libs/ds-contracts/src/display-from-class.ts`,
|
|
20
|
+
* garantido por spec. O CLI é publicado standalone e não pode importar os contratos; a
|
|
21
|
+
* plataforma precisa da mesma tabela para alcançar quem já importou sem pedir re-import.
|
|
22
|
+
* Editar um exige copiar para o outro.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Os valores de `display` do CSS, na grafia utilitária que os frameworks convergiram em
|
|
26
|
+
* usar para cada um. A tabela é sobre CSS: a chave é só como aquele valor costuma ser
|
|
27
|
+
* escrito quando não é escrito por CSS.
|
|
28
|
+
*/
|
|
29
|
+
export const DISPLAY_UTILITIES = {
|
|
30
|
+
flex: { property: "display", value: "flex" },
|
|
31
|
+
grid: { property: "display", value: "grid" },
|
|
32
|
+
"inline-flex": { property: "display", value: "inline-flex" },
|
|
33
|
+
"inline-grid": { property: "display", value: "inline-grid" },
|
|
34
|
+
"inline-block": { property: "display", value: "inline-block" },
|
|
35
|
+
inline: { property: "display", value: "inline" },
|
|
36
|
+
block: { property: "display", value: "block" },
|
|
37
|
+
"flow-root": { property: "display", value: "flow-root" },
|
|
38
|
+
contents: { property: "display", value: "contents" },
|
|
39
|
+
table: { property: "display", value: "table" },
|
|
40
|
+
"inline-table": { property: "display", value: "inline-table" },
|
|
41
|
+
"list-item": { property: "display", value: "list-item" },
|
|
42
|
+
hidden: { property: "display", value: "none" },
|
|
43
|
+
"flex-col": { property: "flexDirection", value: "column" },
|
|
44
|
+
"flex-col-reverse": { property: "flexDirection", value: "column-reverse" },
|
|
45
|
+
"flex-row": { property: "flexDirection", value: "row" },
|
|
46
|
+
"flex-row-reverse": { property: "flexDirection", value: "row-reverse" },
|
|
47
|
+
"flex-wrap": { property: "flexWrap", value: "wrap" },
|
|
48
|
+
"flex-wrap-reverse": { property: "flexWrap", value: "wrap-reverse" },
|
|
49
|
+
"flex-nowrap": { property: "flexWrap", value: "nowrap" },
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* As declarações de caixa que um class string carrega, na ordem em que ele as escreveu.
|
|
53
|
+
*
|
|
54
|
+
* SÓ A CLASSE NUA CONTA. Um utilitário com condição na frente - `md:flex`, `hover:grid`,
|
|
55
|
+
* `dark:hidden` - descreve a caixa em OUTRO estado, e escrevê-lo na base afirmaria que
|
|
56
|
+
* aquele estado é o de repouso. Quem lê estado é quem lê estado.
|
|
57
|
+
*/
|
|
58
|
+
export function displayFromClasses(classes) {
|
|
59
|
+
const out = {};
|
|
60
|
+
for (const raw of (classes ?? "").split(/\s+/)) {
|
|
61
|
+
if (!raw || raw.includes(":"))
|
|
62
|
+
continue;
|
|
63
|
+
const found = DISPLAY_UTILITIES[raw];
|
|
64
|
+
if (found)
|
|
65
|
+
out[found.property] = found.value;
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
* hover:shadow-md → states.hover
|
|
43
43
|
* data-[checked]:bg-ocean-50 → states.checked
|
|
44
44
|
*/
|
|
45
|
+
import { DISPLAY_UTILITIES } from "../display-from-class.js";
|
|
45
46
|
import { tokenRefFor } from "../token-ref.js";
|
|
46
47
|
import { frameworkDeclaration } from "./framework-palette.js";
|
|
47
48
|
/**
|
|
@@ -384,9 +385,10 @@ const TYPE_KEYWORD = {
|
|
|
384
385
|
* and without the position it stopped being a veil and became a block in the flow; the
|
|
385
386
|
* chevron's `justify-between` is what puts it at the far edge of the header.
|
|
386
387
|
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
388
|
+
* What comes in here is the DIMENSION (`flex-1`, `shrink-0`), the PLACE, and - since 09/09 -
|
|
389
|
+
* the DISPLAY in full. `flex` and `flex-col` used to be held out so the node's form
|
|
390
|
+
* (`row`/`stack`) would be the single carrier; the display block below says what that cost
|
|
391
|
+
* and why it was reversed.
|
|
390
392
|
*/
|
|
391
393
|
const PLACE_KEYWORD = {
|
|
392
394
|
// Position: what makes an overlay an overlay.
|
|
@@ -419,12 +421,27 @@ const PLACE_KEYWORD = {
|
|
|
419
421
|
"overflow-y-hidden": { property: "overflowY", value: "hidden" },
|
|
420
422
|
"overflow-x-scroll": { property: "overflowX", value: "scroll" },
|
|
421
423
|
"overflow-y-scroll": { property: "overflowY", value: "scroll" },
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
424
|
+
/**
|
|
425
|
+
* DISPLAY, ALL OF IT - and this reverses the decision written above.
|
|
426
|
+
*
|
|
427
|
+
* WHAT THE CLIENT SAW: their ThemeToggle is `relative grid place-items-center h-11 w-11
|
|
428
|
+
* rounded-full`. Everything survived except the word `grid`, and without it the preview
|
|
429
|
+
* drew a wide capsule with both icons stacked in the top-left corner instead of a round
|
|
430
|
+
* 2.75rem button - because `place-items-center` only does anything inside a grid or a
|
|
431
|
+
* flex box, and because `component-showcase.tsx` asks `base.display != null` to decide
|
|
432
|
+
* whether THEY declared the layout. With no display it answers no, and the shape WE infer
|
|
433
|
+
* beats the one they wrote - the exact inverse of the layout-priority law.
|
|
434
|
+
*
|
|
435
|
+
* `flex` and `flex-col` were held out on the reasoning that they already travel as the
|
|
436
|
+
* node's form (`row`/`stack`) and that declaring it twice starts a disagreement. The
|
|
437
|
+
* disagreement started anyway, because the form is a LOSSY reduction: it answers "across
|
|
438
|
+
* or down", so `grid` arrives as `stack` and `inline-grid` loses its inline-ness.
|
|
439
|
+
*
|
|
440
|
+
* The table itself lives in `display-from-class.ts` - ONE source, because the platform
|
|
441
|
+
* needs the same reading to reach whoever imported before this shipped, without asking
|
|
442
|
+
* them to re-import. The form stays derived from the same class string.
|
|
443
|
+
*/
|
|
444
|
+
...DISPLAY_UTILITIES,
|
|
428
445
|
// Focus and the pointer: real decisions, and `outline-none` is 21 of theirs.
|
|
429
446
|
"outline-none": { property: "outline", value: "none" },
|
|
430
447
|
"cursor-pointer": { property: "cursor", value: "pointer" },
|
package/package.json
CHANGED