synthesisui 0.16.441 → 0.16.443

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.
@@ -64,6 +64,17 @@ const COLOR_PROPERTY = {
64
64
  text: "color",
65
65
  border: "borderColor",
66
66
  ring: "outlineColor",
67
+ /**
68
+ * `outline-brand-blue` - a v4 escreve o contorno com o nome dela própria, e não só com `ring`.
69
+ *
70
+ * Medido no `codelevel` em 20/09: o `CommandBlock` usa `focus-visible:outline-brand-blue`, e
71
+ * `brand-blue` é a cor de AÇÃO que ele escolheu no import. Sem esta linha o leitor não sabia de
72
+ * que propriedade se tratava, e a nota dele caía por ele usar o próprio sistema.
73
+ *
74
+ * Um sufixo que não resolve para cor nenhuma - `outline-2`, que é largura - continua não lido,
75
+ * porque o leitor de cor devolve `null` e nenhum valor errado entra no lugar.
76
+ */
77
+ outline: "outlineColor",
67
78
  fill: "fill",
68
79
  stroke: "stroke",
69
80
  decoration: "textDecorationColor",
@@ -713,7 +724,69 @@ export function readUtility(raw, declared) {
713
724
  };
714
725
  }
715
726
  const read = readUtilityCore(utility, declared);
716
- return read ? withAlpha(read, utility.split("/")[1]) : read;
727
+ if (read)
728
+ return withAlpha(read, utility.split("/")[1]);
729
+ return readNegative(utility, declared);
730
+ }
731
+ /**
732
+ * O SINAL DE MENOS NÃO APAGA O DEGRAU - `-top-1` é o `top-1` dele, para o outro lado.
733
+ *
734
+ * Medido no `codelevel` em 20/09: `-top-1` e `-right-1` no `TierBadge` e `-top-5` no
735
+ * `ConfettiBurst` caíam em não lido, enquanto `top-1` seria lido. É o mesmo valor da escala dele,
736
+ * na direção oposta - e sobrepor ou pendurar um elemento é justamente o caso em que a distância é
737
+ * negativa por desenho.
738
+ *
739
+ * E ELE NÃO CRIA DEGRAU NOVO: o valor lido é o degrau que ele já tem, com o sinal. Tratar `-1`
740
+ * como um degrau próprio dobraria a escala dele e faria o sistema propor vocabulário que ele nunca
741
+ * escreveria.
742
+ *
743
+ * ─────────────────────────────────────────────────────────────────────────
744
+ * E POR QUE O `gap` FICA DE FORA, mesmo com `-space-x-2` sendo cinco dos oito casos dele.
745
+ *
746
+ * `space-x` é lido como `columnGap` - uma aproximação que o próprio comentário da tabela assume,
747
+ * e que é exata onde o pai arranja. Um `columnGap` NEGATIVO não é CSS válido: o que
748
+ * `-space-x-2` faz é margem negativa nos filhos, que é como a pilha de avatares dele se
749
+ * sobrepõe. Emitir `columnGap: -0.5rem` seria errado em silêncio, e a regra deste arquivo é que
750
+ * isso é pior que não lido.
751
+ *
752
+ * Então os cinco `-space-x-*` do `Avatar` continuam não lidos, agora por um motivo que se pode
753
+ * escrever - e resolvê-los é modelar margem negativa, não remendar o sinal.
754
+ */
755
+ const NAO_ACEITA_NEGATIVO = new Set([
756
+ "gap",
757
+ "columnGap",
758
+ "rowGap",
759
+ "width",
760
+ "height",
761
+ "padding",
762
+ "paddingInline",
763
+ "paddingBlock",
764
+ "paddingTop",
765
+ "paddingRight",
766
+ "paddingBottom",
767
+ "paddingLeft",
768
+ ]);
769
+ function readNegative(utility, declared) {
770
+ if (!utility.startsWith("-"))
771
+ return null;
772
+ const positivo = readUtilityCore(utility.slice(1), declared);
773
+ if (!positivo)
774
+ return null;
775
+ if (NAO_ACEITA_NEGATIVO.has(positivo.property))
776
+ return null;
777
+ /** Só um comprimento se nega. Uma palavra-chave com menos na frente não é valor nenhum. */
778
+ const m = /^(-?)([\d.]+)([a-z%]*)$/.exec(positivo.value.trim());
779
+ if (!m || !m[3])
780
+ return null;
781
+ const n = Number(m[2]);
782
+ if (!Number.isFinite(n) || n === 0)
783
+ return null;
784
+ return {
785
+ ...positivo,
786
+ value: `${m[1] ? "" : "-"}${m[2]}${m[3]}`,
787
+ /** O token dele some: `-1` não é o `--spacing-1` dele, é o negativo dele. */
788
+ ...(positivo.token ? { token: undefined } : {}),
789
+ };
717
790
  }
718
791
  function readUtilityCore(utility, declared) {
719
792
  /**
@@ -791,6 +864,68 @@ function readUtilityCore(utility, declared) {
791
864
  * nome do Tailwind é o valor CSS verbatim em toda a escala publicada. O gatilho do
792
865
  * MetricCard real diz "isto tem explicação" com ele (12/08).
793
866
  */
867
+ /**
868
+ * `will-change-transform` - DICA PARA O NAVEGADOR, e ela precisa ser LIDA para poder ser
869
+ * classificada como arranjo.
870
+ *
871
+ * Medido no `codelevel` em 20/09: `Aurora` e `Orb` a escrevem, e ela caía em valor não lido.
872
+ * Não pinta nada - diz ao compositor que a camada vai se mover, para promovê-la antes. Quem a
873
+ * tira do denominador é `STRUCTURAL_PROPERTIES`, pela propriedade; aqui ela só deixa de ser
874
+ * invisível.
875
+ */
876
+ /**
877
+ * AS QUATRO PROPRIEDADES QUE FALTAVAM NA TABELA - E05 da jornada `a-escala-e-do-usuario`.
878
+ *
879
+ * Medidas no `codelevel` em 20/09, dez dos valores que a conta dava como não lidos. Nenhuma
880
+ * delas é ambígua: `outline-2` é uma largura, `brightness-95` é um filtro de 95%. O leitor
881
+ * simplesmente não tinha a propriedade.
882
+ *
883
+ * Button active:brightness-95 filtro
884
+ * CommandBlock outline-2 · outline-offset-2 contorno: largura e distância
885
+ * Card·PillNav backdrop-saturate-140 filtro de fundo
886
+ * QuestItem line-through · underline-offset-4 · decoration-2
887
+ *
888
+ * A ORDEM IMPORTA: `outline` e `decoration` já são prefixos de COR, e a leitura de cor roda
889
+ * antes. `outline-brand-blue` continua indo por lá; só o que ela recusa - um número - chega
890
+ * aqui. Inverter isso leria a cor dele como largura, que é o errado-em-silêncio de sempre.
891
+ */
892
+ const contorno = /^outline-(\d+)$/.exec(core);
893
+ if (contorno)
894
+ return { property: "outlineWidth", value: `${contorno[1]}px` };
895
+ const contornoDist = /^outline-offset-(\d+)$/.exec(core);
896
+ if (contornoDist)
897
+ return { property: "outlineOffset", value: `${contornoDist[1]}px` };
898
+ const brilho = /^brightness-(\d+)$/.exec(core);
899
+ if (brilho)
900
+ return {
901
+ property: "filter",
902
+ value: `brightness(${Number(brilho[1]) / 100})`,
903
+ };
904
+ const satFundo = /^backdrop-saturate-(\d+)$/.exec(core);
905
+ if (satFundo)
906
+ return {
907
+ property: "backdropFilter",
908
+ value: `saturate(${Number(satFundo[1]) / 100})`,
909
+ };
910
+ /** A grafia entre colchetes carrega a unidade dele, e ela viaja como está. */
911
+ const satFundoCru = /^backdrop-saturate-\[([\d.]+%?)\]$/.exec(core);
912
+ if (satFundoCru)
913
+ return { property: "backdropFilter", value: `saturate(${satFundoCru[1]})` };
914
+ if (core === "line-through" || core === "underline" || core === "overline")
915
+ return { property: "textDecorationLine", value: core };
916
+ const sublinhado = /^underline-offset-(\d+)$/.exec(core);
917
+ if (sublinhado)
918
+ return { property: "textUnderlineOffset", value: `${sublinhado[1]}px` };
919
+ const espessura = /^decoration-(\d+)$/.exec(core);
920
+ if (espessura)
921
+ return {
922
+ property: "textDecorationThickness",
923
+ value: `${espessura[1]}px`,
924
+ };
925
+ const willChange = /^will-change-([a-z-]+)$/.exec(core);
926
+ if (willChange) {
927
+ return { property: "willChange", value: willChange[1] };
928
+ }
794
929
  const cursor = /^cursor-([a-z-]+)$/.exec(core);
795
930
  if (cursor)
796
931
  return { property: "cursor", value: cursor[1] };
@@ -1435,6 +1570,17 @@ const BRACKET_PROPERTY = {
1435
1570
  z: "zIndex",
1436
1571
  grid: "gridTemplateColumns",
1437
1572
  aspect: "aspectRatio",
1573
+ /**
1574
+ * `ease-[var(--ease-emphasis)]` - o caminho arbitrário já resolvia o `var()`; faltava dizer a
1575
+ * qual propriedade o `ease` pertence, e sem isso a leitura morria no último passo.
1576
+ *
1577
+ * Medido no `codelevel` em 20/09: `Card`, `Progress` e `Toast` escrevem essa classe, e
1578
+ * `--ease-emphasis` é o `motion.easings.emphasis` DELE, publicado na v1. Três dos 35 valores
1579
+ * "não lidos" eram ele apontando para o próprio vocabulário.
1580
+ *
1581
+ * O `ease-out` nomeado continua sendo lido pela tabela `EASING`, antes daqui.
1582
+ */
1583
+ ease: "transitionTimingFunction",
1438
1584
  };
1439
1585
  /**
1440
1586
  * What is inside the brackets, resolved.
@@ -1665,10 +1811,50 @@ const GRADIENT_DIRECTION = {
1665
1811
  };
1666
1812
  /** A colour stop's value: their token first, Tailwind's table second, a literal last. */
1667
1813
  function stopValue(raw, declared) {
1814
+ /**
1815
+ * A PARADA COM ALFA - `from-white/85`, e o resto do leitor já sabia ler isso.
1816
+ *
1817
+ * Medido no `codelevel` em 20/09: o `Card` escreve `bg-gradient-to-b from-white/85
1818
+ * to-white/60`, com as três cores declaradas no CSS dele, e o gradiente inteiro caía em
1819
+ * `unreadable`. O `SkillNode`, que escreve o mesmo sem alfa, compunha perfeitamente -
1820
+ * `linear-gradient(to bottom right, {color.white}, {color.amber.50})`. A diferença era a barra.
1821
+ *
1822
+ * `readUtility` já resolve alfa em toda cor, por `withAlpha`. Esta função era a única que via a
1823
+ * barra e devolvia `null` - e um gradiente com UMA parada ilegível não é meio lido: o
1824
+ * compositor descarta o gradiente inteiro, então a barra apagava a decisão toda.
1825
+ */
1826
+ const comAlfa = /^(.+)\/(\d{1,3})$/.exec(raw);
1827
+ if (comAlfa) {
1828
+ const base = stopValue(comAlfa[1], declared);
1829
+ if (!base)
1830
+ return null;
1831
+ const pct = Number(comAlfa[2]);
1832
+ if (!Number.isFinite(pct) || pct > 100)
1833
+ return null;
1834
+ /** A grafia do CSS moderno: `color-mix` não, `/ <alpha>` dentro do próprio valor. */
1835
+ return `color-mix(in oklab, ${base} ${pct}%, transparent)`;
1836
+ }
1668
1837
  if (declared.has(`--color-${raw}`))
1669
1838
  return refFor(raw);
1670
1839
  if (TAILWIND_COLOR[raw])
1671
1840
  return TAILWIND_COLOR[raw];
1841
+ /**
1842
+ * A PALETA DO FRAMEWORK TAMBÉM PINTA UMA PARADA - e o caminho normal de cor já a consulta.
1843
+ *
1844
+ * Medido no `codelevel` em 20/09, contra o censo de produção: o `SkillNode` escreve
1845
+ * `bg-gradient-to-br from-white to-amber-50`, e o gradiente inteiro era descartado porque
1846
+ * `amber-50` não resolvia aqui. Ninguém declara `--color-amber-50` no código dele: é a paleta
1847
+ * padrão do Tailwind, que `frameworkDeclaration` conhece e esta função não consultava.
1848
+ *
1849
+ * A assimetria era a falha: `bg-amber-50` sozinho era lido, e `to-amber-50` não. Uma parada
1850
+ * ilegível derruba o gradiente inteiro, então a cor da paleta apagava a decisão toda.
1851
+ *
1852
+ * O valor vem com o carimbo de framework do outro lado; aqui só o valor interessa, porque uma
1853
+ * parada é uma string dentro do `linear-gradient`.
1854
+ */
1855
+ const daPaleta = frameworkDeclaration("color", raw);
1856
+ if (daPaleta)
1857
+ return daPaleta.value;
1672
1858
  if (/^#[0-9a-fA-F]{3,8}$/.test(raw) ||
1673
1859
  raw === "transparent" ||
1674
1860
  raw === "white" ||
@@ -1689,7 +1875,7 @@ function stopValue(raw, declared) {
1689
1875
  * prefix, so stops only count when a `bg-gradient-to-*` sits in the SAME class list -
1690
1876
  * and a direction whose stops do not resolve is reported, never half-built.
1691
1877
  */
1692
- function composeGradient(utilities, declared) {
1878
+ export function composeGradient(utilities, declared) {
1693
1879
  const dir = utilities.find((u) => GRADIENT_DIRECTION[u.replace(/^bg-gradient-/, "")] &&
1694
1880
  u.startsWith("bg-gradient-"));
1695
1881
  if (!dir)
@@ -1,4 +1,4 @@
1
- import { parseClass, readUtility } from "./transcribe.js";
1
+ import { composeGradient, parseClass, readUtility } from "./transcribe.js";
2
2
  /**
3
3
  * AS PROPRIEDADES QUE SÃO ARRANJO - a definição de "estrutura", por propriedade resolvida.
4
4
  *
@@ -50,6 +50,15 @@ const STRUCTURAL_PROPERTIES = new Set([
50
50
  "isolation",
51
51
  "textOverflow",
52
52
  "borderCollapse",
53
+ /**
54
+ * `will-change` É DICA PARA O NAVEGADOR, nunca decisão de design - medido no `codelevel` em
55
+ * 20/09, onde `will-change-transform` no `Aurora` e no `Orb` contava como valor perdido.
56
+ *
57
+ * Ela não pinta nada: diz ao compositor do navegador que aquela camada vai se mover, para ele
58
+ * promovê-la antes. Trocá-la muda desempenho, não aparência - que é exatamente a linha que
59
+ * separa este conjunto do resto.
60
+ */
61
+ "willChange",
53
62
  ]);
54
63
  /**
55
64
  * TOKENS DE ARRANJO QUE O RESOLVEDOR NÃO DEVOLVE COMO DECLARAÇÃO - a metade utilitária da mesma
@@ -121,6 +130,14 @@ const ARRANJO_SEM_VALOR = [
121
130
  /^order-(\d+|first|last|none)$/,
122
131
  /** Margem `auto` é centralização - a única margem cujo valor não sai de escala nenhuma. */
123
132
  /^-?m[xytblrse]?-auto$/,
133
+ /**
134
+ * O GRUPO NOMEADO É O MESMO GRUPO - `group/tt`, e `group` já estava em `STRUCTURAL_TOKENS`.
135
+ *
136
+ * A v4 deixa nomear o grupo para que um filho alcance o ancestral certo quando há dois
137
+ * aninhados; o `Tooltip` dele usa `group/tt` por isso. É mecanismo de seletor, não aparência -
138
+ * e o conjunto exato não pegava porque a barra e o nome vêm colados.
139
+ */
140
+ /^(group|peer)\/[A-Za-z0-9_-]+$/,
124
141
  ];
125
142
  /** `mx-auto` e `col-span-6` nomeiam arranjo; `gap-6` nomeia uma escolha de escala. */
126
143
  export function arranjoSemValor(utility) {
@@ -177,8 +194,45 @@ defined) {
177
194
  answered: 0,
178
195
  unknown: 0,
179
196
  };
197
+ /**
198
+ * O GRADIENTE É UMA DECISÃO EM TRÊS CLASSES, E A CONTA VIA TRÊS PERDAS.
199
+ *
200
+ * Medido no `codelevel` em 20/09: o `SkillNode` escreve `bg-gradient-to-br from-white
201
+ * to-amber-50`, e o transcritor compõe isso perfeitamente -
202
+ * `linear-gradient(to bottom right, {color.white}, {color.amber.50})`. A receita dele tem o
203
+ * gradiente. E esta conta, que olha uma classe de cada vez, chamava as três de não lidas.
204
+ *
205
+ * O leitor entendeu e o contador não: dez dos 35 valores "não lidos" dele eram isso. Um número
206
+ * que contradiz a receita ao lado dele é o defeito que este arquivo mais evita.
207
+ *
208
+ * A composição roda por GRUPO DE MODIFICADOR, igual ao `transcribe` - é o que as três partes de
209
+ * um gradiente têm em comum. E o guarda dele continua de pé: uma parada sem direção no MESMO
210
+ * grupo não compõe, porque `slide-in-from-bottom-2` usa o mesmo prefixo `from-`. As paradas de
211
+ * dark do `Card`, que moram numa camada sem a direção, seguem não lidas - e é verdade que
212
+ * seguem: o gradiente escuro dele não está sendo lido.
213
+ */
214
+ const grupos = new Map();
215
+ for (const cls of tokens) {
216
+ const { modifiers, utility } = parseClass(cls);
217
+ const chave = modifiers.join(":");
218
+ grupos.set(chave, [...(grupos.get(chave) ?? []), utility]);
219
+ }
220
+ const compostas = new Set();
221
+ for (const [chave, utilidades] of grupos) {
222
+ const g = composeGradient(utilidades, declared);
223
+ /** Só o que COMPÔS conta: um gradiente quebrado continua sendo perda, e diz qual peça. */
224
+ if (!g.value)
225
+ continue;
226
+ const prefixo = chave ? `${chave}:` : "";
227
+ for (const u of g.consumed)
228
+ compostas.add(`${prefixo}${u}`);
229
+ }
180
230
  for (const cls of tokens) {
181
231
  account.seen += 1;
232
+ if (compostas.has(cls)) {
233
+ account.interpreted += 1;
234
+ continue;
235
+ }
182
236
  account[destinationOf(cls, declared, answered, defined)] += 1;
183
237
  }
184
238
  return account;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.441",
3
+ "version": "0.16.443",
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": {