synthesisui 0.16.403 → 0.16.405
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/sheet-needed.js +157 -3
- package/package.json +1 -1
package/dist/sheet-needed.js
CHANGED
|
@@ -9,18 +9,172 @@ function themeNames(themeCss) {
|
|
|
9
9
|
out.add(m[2]);
|
|
10
10
|
return [...out];
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* O VALOR DE UM ATRIBUTO DE CLASSE, QUANDO ELE É UMA EXPRESSÃO - e a regra é o ATRIBUTO, não a
|
|
14
|
+
* função.
|
|
15
|
+
*
|
|
16
|
+
* O DEFEITO, medido em 08/09 nas duas árvores do `frontend-hub`: o leitor via `className="…"` e o
|
|
17
|
+
* template direto, e não via `className={cn("…")}`.
|
|
18
|
+
*
|
|
19
|
+
* ```
|
|
20
|
+
* packages/ui/src apps/web-dashboard
|
|
21
|
+
* className=" literal 346 2639
|
|
22
|
+
* className={cn( ou {clsx( 66 239 <- invisíveis
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* São **305 sítios** onde o projeto dele escreve classe e a pergunta *"algo aqui precisa da nossa
|
|
26
|
+
* folha?"* era respondida sobre um texto que não continha a resposta. E o erro caía para o lado
|
|
27
|
+
* ERRADO: o cabeçalho deste módulo declara que *"o lado seguro do erro é PRECISA"*, porque um falso
|
|
28
|
+
* positivo mantém o setup sendo pedido e um falso NEGATIVO entrega um componente sem a animação que
|
|
29
|
+
* ele veste. `cn()` é o idioma de quem parte do shadcn, então a metade que faltava era a maior parte
|
|
30
|
+
* de quem chega.
|
|
31
|
+
*
|
|
32
|
+
* POR QUE A REGRA NÃO É O NOME DA FUNÇÃO. Casar `cn|clsx|twMerge` seria a lista dos casos de hoje: o
|
|
33
|
+
* próximo cliente chama a dele de `classes`, `cx` ou nada - passa um ternário direto. O que é
|
|
34
|
+
* estrutural é o ATRIBUTO: dentro do valor de um `class`/`className`, toda string literal é
|
|
35
|
+
* candidata a classe, seja ela argumento de função, ramo de ternário ou pedaço de template.
|
|
36
|
+
*
|
|
37
|
+
* O QUE ISTO NÃO ALCANÇA, e está declarado com o número: a tabela de variantes que mora numa const
|
|
38
|
+
* separada - `cva(...)` e `tv(...)`, medidos em 08/09 como **4 + 41 e 0 + 85** nas duas árvores. Ali
|
|
39
|
+
* as classes chegam ao atributo por VARIÁVEL, e cobri-las exige seguir a variável até a declaração:
|
|
40
|
+
* é outra frente, e o erro dela continua caindo para o lado de cobrar.
|
|
41
|
+
*/
|
|
42
|
+
function attributeExpressions(source) {
|
|
43
|
+
const out = [];
|
|
44
|
+
const ATTR = /class(?:Name)?=\{/g;
|
|
45
|
+
for (const m of source.matchAll(ATTR)) {
|
|
46
|
+
let depth = 0;
|
|
47
|
+
let i = (m.index ?? 0) + m[0].length - 1;
|
|
48
|
+
const start = i;
|
|
49
|
+
/** Aspas contam para NÃO deixar uma chave dentro de string fechar a expressão cedo. */
|
|
50
|
+
let quote = null;
|
|
51
|
+
for (; i < source.length; i += 1) {
|
|
52
|
+
const c = source[i];
|
|
53
|
+
if (quote) {
|
|
54
|
+
if (c === "\\")
|
|
55
|
+
i += 1;
|
|
56
|
+
else if (c === quote)
|
|
57
|
+
quote = null;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (c === '"' || c === "'" || c === "`")
|
|
61
|
+
quote = c;
|
|
62
|
+
else if (c === "{")
|
|
63
|
+
depth += 1;
|
|
64
|
+
else if (c === "}") {
|
|
65
|
+
depth -= 1;
|
|
66
|
+
if (depth === 0)
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (depth === 0)
|
|
71
|
+
out.push(source.slice(start + 1, i));
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A DECLARAÇÃO DE UMA CONST QUE O ATRIBUTO USA - o salto que faltava, e a mesma regra do atributo.
|
|
77
|
+
*
|
|
78
|
+
* O QUE FICAVA DE FORA, e estava declarado no contrato com o número: a tabela de variantes mora
|
|
79
|
+
* numa const separada e chega ao atributo por VARIÁVEL. O caso real, medido no `frontend-hub`:
|
|
80
|
+
*
|
|
81
|
+
* ```
|
|
82
|
+
* const buttonVariants = cva("… rounded-[var(--radius-md)] …", { variants: { … } });
|
|
83
|
+
* …
|
|
84
|
+
* className={twUtils.cn(buttonVariants({ variant, size, className }))}
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* As classes estão na declaração, não no atributo - então o leitor de 08/09, que já colhia toda
|
|
88
|
+
* string DENTRO da expressão, via `buttonVariants(...)` e não via nenhuma classe. Medido nas duas
|
|
89
|
+
* árvores: **4 + 41** declarações `cva(` e **0 + 85** `tv(`.
|
|
90
|
+
*
|
|
91
|
+
* A REGRA CONTINUA SENDO A MESMA, um salto adiante: o atributo diz quais identificadores importam,
|
|
92
|
+
* e a declaração daqueles identificadores é lida no mesmo arquivo. Nada aqui conhece `cva`, `tv` ou
|
|
93
|
+
* `cn` - o próximo cliente escreve a tabela dele num objeto pelado, e cai na mesma regra.
|
|
94
|
+
*
|
|
95
|
+
* E O ERRO CONTINUA CAINDO PARA O LADO SEGURO: uma const que não é classe - um rótulo, uma
|
|
96
|
+
* mensagem - entrega palavras que o `@theme` não declara, então elas somem na peneira final. O
|
|
97
|
+
* cabeçalho deste módulo diz que entre errar cobrando e errar calando, cobrar é o erro que a pessoa
|
|
98
|
+
* percebe.
|
|
99
|
+
*/
|
|
100
|
+
function declarationsBehind(source, exprs) {
|
|
101
|
+
/**
|
|
102
|
+
* TODO IDENTIFICADOR DA EXPRESSÃO, e não só os que ela CHAMA.
|
|
103
|
+
*
|
|
104
|
+
* A primeira versão pegava `nome(`, e o objeto pelado - `pick(byTone, tone)` - passa a tabela
|
|
105
|
+
* como ARGUMENTO. O que decide é o atributo mencionar o identificador; se ele é chamado ou
|
|
106
|
+
* passado é sintaxe, e sintaxe é o que muda de projeto para projeto.
|
|
107
|
+
*/
|
|
108
|
+
const names = new Set();
|
|
109
|
+
for (const expr of exprs)
|
|
110
|
+
for (const m of expr.matchAll(/\b([A-Za-z_$][\w$]*)\b/g))
|
|
111
|
+
names.add(m[1]);
|
|
112
|
+
if (names.size === 0)
|
|
113
|
+
return [];
|
|
114
|
+
const out = [];
|
|
115
|
+
for (const name of names) {
|
|
116
|
+
/** `const <nome> = ` - e o valor vai até a linha que fecha no MESMO nível de indentação. */
|
|
117
|
+
const at = source.search(new RegExp(`\\b(?:const|let|var)\\s+${name}\\s*=`));
|
|
118
|
+
if (at < 0)
|
|
119
|
+
continue;
|
|
120
|
+
let depth = 0;
|
|
121
|
+
let i = source.indexOf("=", at);
|
|
122
|
+
let quote = null;
|
|
123
|
+
let started = false;
|
|
124
|
+
for (; i < source.length; i += 1) {
|
|
125
|
+
const c = source[i];
|
|
126
|
+
if (quote) {
|
|
127
|
+
if (c === "\\")
|
|
128
|
+
i += 1;
|
|
129
|
+
else if (c === quote)
|
|
130
|
+
quote = null;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (c === '"' || c === "'" || c === "`")
|
|
134
|
+
quote = c;
|
|
135
|
+
else if (c === "(" || c === "{" || c === "[") {
|
|
136
|
+
depth += 1;
|
|
137
|
+
started = true;
|
|
138
|
+
}
|
|
139
|
+
else if (c === ")" || c === "}" || c === "]") {
|
|
140
|
+
depth -= 1;
|
|
141
|
+
if (started && depth <= 0)
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
else if (c === ";" && !started)
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
out.push(source.slice(at, i + 1));
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
12
151
|
/** As classes escritas no código - `hover:animate-shimmer` conta como `animate-shimmer`. */
|
|
13
152
|
function classesIn(source) {
|
|
14
153
|
const out = new Set();
|
|
15
|
-
|
|
16
|
-
const body = m[1] ?? m[2] ?? m[3] ?? m[4] ?? "";
|
|
154
|
+
const collect = (body) => {
|
|
17
155
|
for (const raw of body.split(/\s+/)) {
|
|
18
156
|
if (!raw)
|
|
19
157
|
continue;
|
|
20
158
|
const bare = raw.split(":").pop() ?? raw;
|
|
21
159
|
out.add(bare.replace(/^[!-]/, ""));
|
|
22
160
|
}
|
|
23
|
-
}
|
|
161
|
+
};
|
|
162
|
+
for (const m of source.matchAll(/class(?:Name)?=(?:"([^"]*)"|'([^']*)'|\{`([^`]*)`\}|\{"([^"]*)"\})/g))
|
|
163
|
+
collect(m[1] ?? m[2] ?? m[3] ?? m[4] ?? "");
|
|
164
|
+
/**
|
|
165
|
+
* E TODA STRING DENTRO DA EXPRESSÃO - ver `attributeExpressions`. As três formas de escrever uma
|
|
166
|
+
* string em JS/TS, porque quem escolhe a aspa é o formatador dele, não a gente.
|
|
167
|
+
*/
|
|
168
|
+
const exprs = attributeExpressions(source);
|
|
169
|
+
const strings = (text) => {
|
|
170
|
+
for (const lit of text.matchAll(/"([^"]*)"|'([^']*)'|`([^`]*)`/g))
|
|
171
|
+
collect(lit[1] ?? lit[2] ?? lit[3] ?? "");
|
|
172
|
+
};
|
|
173
|
+
for (const expr of exprs)
|
|
174
|
+
strings(expr);
|
|
175
|
+
/** E a declaração de quem o atributo chama - ver `declarationsBehind`. */
|
|
176
|
+
for (const decl of declarationsBehind(source, exprs))
|
|
177
|
+
strings(decl);
|
|
24
178
|
return out;
|
|
25
179
|
}
|
|
26
180
|
/**
|
package/package.json
CHANGED