synthesisui 0.16.351 → 0.16.354

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.
@@ -677,6 +677,24 @@ export function readUtility(raw, declared) {
677
677
  if (property)
678
678
  return { property, value: `${Number(pct.toFixed(4))}%` };
679
679
  }
680
+ /**
681
+ * `-translate-x-1/2` TAMBÉM É UMA FRAÇÃO, e ela tem que ser lida AQUI pelo motivo exato que o
682
+ * comentário acima já dava: depois do split de alpha ela chega como `translate-x-1` e volta
683
+ * `0.25rem` - *silently wrong, which is worse than unread*.
684
+ *
685
+ * E isto não é hipótese: o primeiro rascunho do leitor de `translate` (02/09) tratava a fração
686
+ * dentro de `readUtilityCore`, depois do split, e produziu `translateX(-0.25rem)` para o
687
+ * `-translate-x-1/2` com que ele centra elementos. O spec pegou. É a mesma armadilha, uma função
688
+ * de transform depois.
689
+ */
690
+ const shift = /^(-?)translate-([xy])-(\d+)\/(\d+)$/.exec(utility);
691
+ if (shift) {
692
+ const pct = (Number(shift[3]) / Number(shift[4])) * 100;
693
+ return {
694
+ property: "transform",
695
+ value: `translate${shift[2] === "x" ? "X" : "Y"}(${shift[1]}${Number(pct.toFixed(4))}%)`,
696
+ };
697
+ }
680
698
  const read = readUtilityCore(utility, declared);
681
699
  return read ? withAlpha(read, utility.split("/")[1]) : read;
682
700
  }
@@ -1139,6 +1157,63 @@ function readUtilityCore(utility, declared) {
1139
1157
  * so two on the same element would overwrite - none of their 3 co-occur, and saying
1140
1158
  * one of them is better than saying neither.
1141
1159
  */
1160
+ /**
1161
+ * O EIXO FAZ PARTE DA FUNÇÃO, e não do argumento - `rotate-x-45` é `rotateX(45deg)`.
1162
+ *
1163
+ * O QUE ISTO CONSERTA, e é pior que não-lido: o teste abaixo é `^-?rotate-(.+)$`, que capturava
1164
+ * `x-45` e montava **`rotate(x-45deg)`** - uma declaração que o navegador descarta inteira,
1165
+ * gravada na receita como se fosse a decisão dele. `skew-x-6` e `scale-x-95` caíam fora de
1166
+ * qualquer leitor e viravam lacuna, que é o lado seguro de errar; `rotate-x` era o inseguro.
1167
+ *
1168
+ * MEDIDO EM 02/09 COM A RÉGUA DO PRODUTO - as classes que o censo realmente carrega, e não um
1169
+ * grep: **0 usos nas duas populações** para as seis formas por eixo. E o grep ingênuo mentia
1170
+ * feio: ele dava 114 e 16 para `perspective-` e 60 e 78 para `origin-`, e NENHUM era classe de
1171
+ * componente - era o CSS `perspective:` e `transform-origin:` dentro das `@utility` dele.
1172
+ *
1173
+ * ENTÃO POR QUE LER, com N=0? Pelo mesmo motivo que `peer-<estado>/<nome>:` entrou no
1174
+ * `INV-INTERP-17`: isto não é forma de repositório nenhum, é a GRAMÁTICA que o Tailwind declara,
1175
+ * e nela o eixo é sufixo da função. Derivar da gramática cobre o cliente que a gente nunca viu -
1176
+ * e o que decide o caso é que a alternativa aqui não era silêncio, era CSS inválido.
1177
+ *
1178
+ * O QUE NÃO ENTROU, declarado: `origin-*`, `perspective-*`, `transform-gpu` e `translate-z-*`.
1179
+ * Os três primeiros são propriedades PRÓPRIAS (`transformOrigin`, `perspective`, `willChange`) e
1180
+ * não funções de `transform`, então não são sufixo desta família: entram como leitor novo, com
1181
+ * medição própria, no dia em que uma população as escrever como classe.
1182
+ */
1183
+ const axial = /^(-?)(rotate|skew|scale)-([xyz])-(.+)$/.exec(core);
1184
+ if (axial) {
1185
+ /**
1186
+ * QUANDO ESTE PADRÃO CASA, ELE DECIDE - e nunca deixa cair no leitor genérico abaixo.
1187
+ *
1188
+ * É a metade que fecha a porta de verdade. O primeiro rascunho só ACRESCENTAVA a leitura por
1189
+ * eixo, e `rotate-x-banana` continuava passando para `^-?rotate-(.+)$` e voltando
1190
+ * `rotate(x-bananadeg)` - o mesmo CSS inválido, agora por um caminho a mais. Um `return null`
1191
+ * aqui manda a classe para a lista de não lidas, que é a resposta certa: nunca inventamos, e
1192
+ * uma lacuna dita vale mais que um valor que o navegador descarta.
1193
+ *
1194
+ * E O SINAL SÓ EXISTE ONDE O TAILWIND O DEFINE: `-rotate-y-90` e `-skew-y-3` são válidos;
1195
+ * `-scale-x-95` não é, e aceitá-lo seria ler uma decisão que ele não tem como ter escrito.
1196
+ */
1197
+ const [, sign, kind, ax, arg] = axial;
1198
+ const fn = `${kind}${ax.toUpperCase()}`;
1199
+ const arbitrary = /^\[(.+)\]$/.exec(arg);
1200
+ if (kind === "scale") {
1201
+ if (sign)
1202
+ return null;
1203
+ const factor = arbitrary
1204
+ ? arbitrary[1]
1205
+ : /^\d+$/.test(arg)
1206
+ ? String(Number(arg) / 100)
1207
+ : null;
1208
+ return factor
1209
+ ? { property: "transform", value: `${fn}(${factor})` }
1210
+ : null;
1211
+ }
1212
+ if (!arbitrary && !/^\d+(\.\d+)?$/.test(arg))
1213
+ return null;
1214
+ const deg = arbitrary ? arbitrary[1] : `${arg}deg`;
1215
+ return { property: "transform", value: `${fn}(${sign}${deg})` };
1216
+ }
1142
1217
  const rotate = /^-?rotate-(.+)$/.exec(core);
1143
1218
  if (rotate) {
1144
1219
  const arbitrary = /^\[(.+)\]$/.exec(rotate[1]);
@@ -1148,6 +1223,57 @@ function readUtilityCore(utility, declared) {
1148
1223
  value: `rotate(${core.startsWith("-") ? `-${deg}` : deg})`,
1149
1224
  };
1150
1225
  }
1226
+ /**
1227
+ * `-translate-y-px`, `translate-x-1/2`, `translate-y-[140%]` - o deslocamento estático.
1228
+ *
1229
+ * A MESMA FAMÍLIA DE `rotate` E `scale`, e era a única das três sem leitor. Medido em 02/09, por
1230
+ * CAMADA e com a régua do produto:
1231
+ *
1232
+ * codelevel 22 camadas com classe de transform · 5 chegavam (23%) · 17 perdidas
1233
+ * frontend-hub 2 camadas · 2 chegavam (100%) · 0 perdidas
1234
+ *
1235
+ * As duas populações discordam porque escrevem coisas diferentes: o `frontend-hub` usa
1236
+ * `scale-95` e `rotate-180`, que já eram lidos; o `codelevel` usa `translate`, e nele as formas
1237
+ * perdidas eram `-translate-y-px` (6), `-translate-x-1/2` (3), `-translate-y-0.5` (2),
1238
+ * `-translate-y-1/2` (2), `translate-y-0`, `translate-y-[140%]` e as duas do grupo nomeado.
1239
+ *
1240
+ * O QUE ELE VÊ SEM ISTO: o card dele sobe 1px no hover no navegador e não sobe no Canvas, e o
1241
+ * elemento que ele centrou com `-translate-x-1/2` aparece deslocado meia largura.
1242
+ *
1243
+ * A ESCALA É A DELE PRIMEIRO, exatamente como em `gap-sm`: `--spacing-<passo>` declarado vence a
1244
+ * fórmula numérica. A FRAÇÃO é percentual por definição do Tailwind (`1/2` = 50%), e não passo de
1245
+ * escala - convertê-la pela escala daria um valor que nada no CSS dele significa.
1246
+ *
1247
+ * DUAS NA MESMA CAMADA AINDA SE SOBRESCREVEM, e isso não é novo nem calado: as três funções
1248
+ * pousam em `transform` inteiro, o comentário de `rotate` já declarava isso, e medido em 02/09 é
1249
+ * **1 de 18** camadas no `codelevel` e 0 no `frontend-hub`. Dizer uma continua sendo melhor que
1250
+ * dizer nenhuma.
1251
+ */
1252
+ const translate = /^-?translate-([xy])-(.+)$/.exec(core);
1253
+ if (translate) {
1254
+ const axis = translate[1] === "x" ? "X" : "Y";
1255
+ const arg = translate[2];
1256
+ const neg = core.startsWith("-");
1257
+ const own = `--spacing-${arg}`;
1258
+ const arbitrary = /^\[(.+)\]$/.exec(arg);
1259
+ /** A FRAÇÃO NÃO CHEGA AQUI - `readUtility` a lê antes do split de alpha, e o comentário lá
1260
+ * explica por que ela não pode esperar por este ponto. */
1261
+ const size = arbitrary
1262
+ ? arbitrary[1]
1263
+ : arg === "full"
1264
+ ? "100%"
1265
+ : declared.has(own)
1266
+ ? `{spacing.${arg}}`
1267
+ : (SPACING[arg] ?? numericSpacing(arg));
1268
+ if (size)
1269
+ return {
1270
+ property: "transform",
1271
+ value: `translate${axis}(${neg ? `-${size}` : size})`,
1272
+ ...(!arbitrary && arg !== "full" && declared.has(own)
1273
+ ? { token: own }
1274
+ : {}),
1275
+ };
1276
+ }
1151
1277
  const scale = /^scale-(.+)$/.exec(core);
1152
1278
  if (scale) {
1153
1279
  const arbitrary = /^\[(.+)\]$/.exec(scale[1]);
@@ -1648,8 +1774,12 @@ function slotFor(out, modifiers) {
1648
1774
  let at;
1649
1775
  let unslotted = false;
1650
1776
  for (const mod of rest) {
1651
- /** `group-hover:`, `group-data-[checked]:` - the PARENT's state. */
1652
- const group = /^group-(.+)$/.exec(mod);
1777
+ /**
1778
+ * `group-hover:`, `group-data-[checked]:` - the PARENT's state. E o NOME do grupo depois da
1779
+ * barra não é parte do estado: ver a régua gêmea em `variant-read.ts`, com a medição das duas
1780
+ * populações e a prova de que descartar o nome não junta nada.
1781
+ */
1782
+ const group = /^group-(.+?)(?:\/[A-Za-z0-9_-]+)?$/.exec(mod);
1653
1783
  const bare = group ? group[1] : mod;
1654
1784
  const state = STATE_SPELLING[bare] ?? dataState(bare);
1655
1785
  if (state) {
@@ -73,8 +73,34 @@ const MODIFIER_STATE = {
73
73
  "aria-invalid": "invalid",
74
74
  "aria-busy": "loading",
75
75
  };
76
- /** `group-hover`, `group-focus`, `peer-checked` - the state of something ELSE. */
77
- const RELATIONAL = /^(?:group|peer)-(.+)$/;
76
+ /**
77
+ * O NOME DO GRUPO NÃO É PARTE DO ESTADO - `group-hover/tt:` é "quando o grupo chamado `tt` está em
78
+ * hover", e o estado ali é `hover`.
79
+ *
80
+ * O TAILWIND NOMEIA GRUPOS desde a v3, e é o que se escreve quando dois grupos se aninham: o pai
81
+ * declara `group/tt` e o filho reage com `group-hover/tt:`. A régua capturava `(.+)` depois do
82
+ * `group-`, então ela procurava o estado `hover/tt` na tabela e não achava - e o estilo inteiro
83
+ * daquela condição era declarado perdido.
84
+ *
85
+ * MEDIDO EM 02/09, e AS DUAS POPULAÇÕES SÃO OPOSTAS (`INV-GERAL-07`):
86
+ *
87
+ * codelevel 138 usos NOMEADOS em 39 arquivos · 0 anônimos
88
+ * frontend-hub 0 nomeados · 192 anônimos
89
+ *
90
+ * Uma régua escrita para qualquer uma das duas quebraria na outra por inteiro. O que decide não é
91
+ * a população: é a gramática que o Tailwind declara, e nela o nome é um IDENTIFICADOR opcional
92
+ * depois de uma barra. `peer-<estado>/<nome>:` tem a mesma forma e entra pela mesma porta - 0 usos
93
+ * nas duas populações hoje, e cobrir os dois é derivar da gramática em vez de fixar o que um
94
+ * repositório escreve.
95
+ *
96
+ * DESCARTAR O NOME É SEGURO, e isto foi medido antes de ser decidido: o nome só distinguiria algo
97
+ * se dois grupos diferentes aparecessem na MESMA lista de classes. No `codelevel` são 2 nomes no
98
+ * repositório inteiro (`tt` 96, `btn` 42), 7 arquivos usam os dois, e **em 0 dos 10 atributos
99
+ * `className` medidos eles coexistem**. Cada lista de classes pertence a um elemento, e ali o nome
100
+ * é derivável do contexto. Se um dia coexistirem, as duas condições produzem o MESMO `within` e
101
+ * viram duas camadas distinguíveis pelas outras classes - nada é somado em silêncio.
102
+ */
103
+ const RELATIONAL = /^(?:group|peer)-(.+?)(?:\/[A-Za-z0-9_-]+)?$/;
78
104
  /**
79
105
  * `data-[state=open]:`, `data-[checked]:`, `data-[side=top]:` - como @base-ui e Radix escrevem uma
80
106
  * condição.
@@ -567,7 +567,56 @@ export const CHECKER_SINCE = "0.16.308";
567
567
  * QUEM NÃO É AFETADO: quem não escreve `@keyframes`. E quem escreve um que a captura NÃO alcançou -
568
568
  * ali o frame continua sendo lacuna, porque ali a perda é real.
569
569
  */
570
- export const READER_SINCE = "0.16.351";
570
+ /**
571
+ * 0.16.351 -> 0.16.352 em 02/09 (`INV-INTERP-17`): o GRUPO NOMEADO do Tailwind passa a ser lido.
572
+ *
573
+ * O QUE ELE GANHA COM O `sync`: a condição que só existe quando o grupo em volta reage. `group/tt`
574
+ * no pai e `group-hover/tt:` no filho é como se escreve isso desde a v3 do Tailwind, e a régua
575
+ * procurava o estado `hover/tt` na tabela - não achava, e declarava PERDIDA a condição inteira.
576
+ *
577
+ * MEDIDO NO `codelevel`: 4 classes em `unplaced` viram 2 camadas condicionais com `opacity: 1` na
578
+ * receita do `TooltipContent`. O tooltip dele aparece no hover no navegador e não aparecia na
579
+ * nossa.
580
+ *
581
+ * codelevel 138 usos NOMEADOS · 0 anônimos · unplaced 4 -> 0
582
+ * frontend-hub 0 nomeados · 192 anônimos · unplaced 0 -> 0 (a forma anônima não regride)
583
+ *
584
+ * QUEM NÃO É AFETADO: quem escreve só a forma anônima (`group-hover:`), que já era lida. O nome do
585
+ * grupo é descartado com prova: em 0 dos 10 atributos `className` medidos dois grupos coexistem.
586
+ */
587
+ /**
588
+ * 0.16.352 -> 0.16.353 em 02/09 (`INV-INTERP-18`): `translate` passa a ser lido.
589
+ *
590
+ * O QUE ELE GANHA COM O `sync`: o deslocamento estático que ele declara. `rotate` e `scale` já
591
+ * eram lidos; `translate` era a única das três funções de transform sem leitor, e a camada inteira
592
+ * que dependia dela era descartada.
593
+ *
594
+ * codelevel 5 de 22 camadas chegavam (23%) -> 30 de 30
595
+ * frontend-hub 2 de 2 (100%) -> 2 de 2 · ele escreve `scale`/`rotate`, que já eram lidos
596
+ *
597
+ * E UM CASO PIOR QUE NÃO-LIDO: `-translate-x-1/2`, com que ele centra elementos, chegava ao leitor
598
+ * de tamanho como `translate-x-1` e voltava `0.25rem`. Quem já importou tem essa receita gravada -
599
+ * o elemento aparece deslocado meia largura em vez de centrado.
600
+ *
601
+ * QUEM NÃO É AFETADO: quem não escreve `translate-*`.
602
+ */
603
+ /**
604
+ * 0.16.353 -> 0.16.354 em 02/09 (`INV-INTERP-19`): o EIXO passa a fazer parte da função, e a régua
605
+ * para de emitir CSS inválido.
606
+ *
607
+ * O QUE ELE GANHA COM O `sync`: `rotate-x-45` virava **`rotate(x-45deg)`**, uma declaração que o
608
+ * navegador descarta inteira e que ficava GRAVADA na receita como se fosse a decisão dele. Agora é
609
+ * `rotateX(45deg)`, e o que não é ângulo vira lacuna em vez de valor inventado.
610
+ *
611
+ * A MARCA SOBE APESAR DE N=0 nas duas populações, e é uma escolha declarada: quem TEM a forma tem
612
+ * um valor inválido gravado, e é a marca que faz o `align` chamá-lo a re-medir. Errar para o lado
613
+ * de subir custa um `sync` que não precisava; errar para o outro deixa o valor inválido para
614
+ * sempre, e "0 nas duas que eu medi" não é "0 no mundo" (`INV-GERAL-07`).
615
+ *
616
+ * QUEM NÃO É AFETADO: quem não escreve `rotate-x`, `skew-x/y` ou `scale-x/y`. As formas SEM eixo -
617
+ * `rotate-180`, `scale-95` - não se movem, e há asserção disso.
618
+ */
619
+ export const READER_SINCE = "0.16.354";
571
620
  /**
572
621
  * O QUE ESTÁ INSTALADO AQUI FICOU PARA TRÁS - e as DUAS condições que fazem isso ser verdade.
573
622
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.351",
3
+ "version": "0.16.354",
4
4
  "description": "Bring SynthesisUI design systems into any project - tokens, typed components, whole pages and an agent-ready CLAUDE.md manifest.",
5
5
  "type": "module",
6
6
  "bin": {