synthesisui 0.16.366 → 0.16.367
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/color-forms.js +94 -2
- package/dist/doctor/scan.js +16 -1
- package/dist/install-marks.js +16 -2
- package/package.json +1 -1
package/dist/color-forms.js
CHANGED
|
@@ -130,6 +130,98 @@ function fromHsl(raw) {
|
|
|
130
130
|
alpha: Number.isFinite(alpha) ? Math.max(0, Math.min(1, alpha)) : 1,
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* `oklch(69.6% 0.17 162.48)` - E ELE ERA 42% DOS LITERAIS DE COR DE UM SISTEMA REAL.
|
|
135
|
+
*
|
|
136
|
+
* O QUE O CLIENTE GANHA: a cor que o Tailwind 4 escreve por padrão passa a ser interpretada como
|
|
137
|
+
* cor. Antes ela chegava na receita (o coletor a lê) e morria aqui - `colorForm` devolvia `null` -,
|
|
138
|
+
* então `deltaE` não a comparava, `namedByValue` não a indexava, o v2 nunca propunha agrupá-la nem
|
|
139
|
+
* nomeá-la, e nada a declarava como lacuna. Ela era invisível nos dois sentidos.
|
|
140
|
+
*
|
|
141
|
+
* MEDIDO em 03/09, nos `looks` de duas populações: 94 usos no `codelevel-ui` e 23 no
|
|
142
|
+
* `frontend-hub`, 39 valores distintos - e ZERO deles no `observed` das três populações, que é a
|
|
143
|
+
* régua de valores. É a decisão 1 do dono (21/08): *"toda forma de cor entra - hex, rgb, rgba, hsl,
|
|
144
|
+
* color-mix, oklch"*.
|
|
145
|
+
*
|
|
146
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
147
|
+
* O GAMUT É MAPEADO POR CHROMA, E NÃO CLAMPADO - e essa é a decisão que impede a cor errada
|
|
148
|
+
*
|
|
149
|
+
* OKLCh descreve cores que o sRGB não alcança: 25 dos 39 valores medidos caem fora. A saída barata
|
|
150
|
+
* é clampar cada canal em 0-255; a certa é a do CSS Color 4, reduzir o CHROMA mantendo o L e o H até
|
|
151
|
+
* a cor caber. As duas DISCORDAM em 22 dos 25:
|
|
152
|
+
*
|
|
153
|
+
* oklch(69.6% 0.17 162.48) clamp #00bc7d chroma-map #00b981
|
|
154
|
+
* oklch(76.9% 0.188 70.08) clamp #fe9a00 chroma-map #f69e00
|
|
155
|
+
*
|
|
156
|
+
* `#00b981` é o emerald que o navegador pinta; `#00bc7d` é uma cor que ninguém vê. Um hex errado
|
|
157
|
+
* aqui não fica quieto: ele vira a chave que decide se duas cores são a mesma e se um token dele
|
|
158
|
+
* casa com um valor - as duas afirmações que este produto não pode errar. O laço binário custa 24
|
|
159
|
+
* iterações e só roda para quem está fora.
|
|
160
|
+
*/
|
|
161
|
+
function fromOklch(raw) {
|
|
162
|
+
const m = /^oklch\(([^)]*)\)$/i.exec(raw.trim());
|
|
163
|
+
if (!m)
|
|
164
|
+
return null;
|
|
165
|
+
const [body, alphaPart] = m[1].split("/");
|
|
166
|
+
const parts = body
|
|
167
|
+
.trim()
|
|
168
|
+
.split(/[\s,]+/)
|
|
169
|
+
.filter(Boolean);
|
|
170
|
+
if (parts.length < 3)
|
|
171
|
+
return null;
|
|
172
|
+
/** L aceita 0-1 e 0%-100%; C aceita o número e o percentual, cujo 100% é 0.4 por spec. */
|
|
173
|
+
const L = unit(parts[0]);
|
|
174
|
+
const C = parts[1].trim().endsWith("%")
|
|
175
|
+
? unit(parts[1], 0.4)
|
|
176
|
+
: Number.parseFloat(parts[1]);
|
|
177
|
+
/** `none` é um ângulo ausente, e ausente é zero - com C=0 o matiz não muda nada de qualquer forma. */
|
|
178
|
+
const H = /^none$/i.test(parts[2].trim()) ? 0 : Number.parseFloat(parts[2]);
|
|
179
|
+
if (![L, C, H].every(Number.isFinite))
|
|
180
|
+
return null;
|
|
181
|
+
const linear = (chroma) => {
|
|
182
|
+
const h = (H * Math.PI) / 180;
|
|
183
|
+
const a = chroma * Math.cos(h);
|
|
184
|
+
const b = chroma * Math.sin(h);
|
|
185
|
+
const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
|
|
186
|
+
const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
|
|
187
|
+
const s_ = L - 0.0894841775 * a - 1.291485548 * b;
|
|
188
|
+
const l3 = l_ ** 3;
|
|
189
|
+
const m3 = m_ ** 3;
|
|
190
|
+
const s3 = s_ ** 3;
|
|
191
|
+
return [
|
|
192
|
+
4.0767416621 * l3 - 3.3077115913 * m3 + 0.2309699292 * s3,
|
|
193
|
+
-1.2684380046 * l3 + 2.6097574011 * m3 - 0.3413193965 * s3,
|
|
194
|
+
-0.0041960863 * l3 - 0.7034186147 * m3 + 1.707614701 * s3,
|
|
195
|
+
];
|
|
196
|
+
};
|
|
197
|
+
/** A folga de 1e-4 é ruído de ponto flutuante, não cor fora do gamut. */
|
|
198
|
+
const fits = (c) => c.every((x) => x >= -0.0001 && x <= 1.0001);
|
|
199
|
+
let channels = linear(Math.max(0, C));
|
|
200
|
+
if (!fits(channels)) {
|
|
201
|
+
let lo = 0;
|
|
202
|
+
let hi = Math.max(0, C);
|
|
203
|
+
for (let i = 0; i < 24; i++) {
|
|
204
|
+
const mid = (lo + hi) / 2;
|
|
205
|
+
if (fits(linear(mid)))
|
|
206
|
+
lo = mid;
|
|
207
|
+
else
|
|
208
|
+
hi = mid;
|
|
209
|
+
}
|
|
210
|
+
channels = linear(lo);
|
|
211
|
+
}
|
|
212
|
+
/** sRGB transfer function - o mesmo expoente que o navegador usa. */
|
|
213
|
+
const gamma = (x) => {
|
|
214
|
+
const v = Math.max(0, Math.min(1, x));
|
|
215
|
+
return (v <= 0.0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055) * 255;
|
|
216
|
+
};
|
|
217
|
+
const [r, g, b] = channels.map(gamma);
|
|
218
|
+
const rawAlpha = alphaPart ?? parts[3];
|
|
219
|
+
const alpha = rawAlpha === undefined ? 1 : unit(rawAlpha);
|
|
220
|
+
return {
|
|
221
|
+
hex: `#${hex2(r)}${hex2(g)}${hex2(b)}`,
|
|
222
|
+
alpha: Number.isFinite(alpha) ? Math.max(0, Math.min(1, alpha)) : 1,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
133
225
|
/**
|
|
134
226
|
* QUALQUER FORMA -> a canônica. `null` para o que não é uma cor literal.
|
|
135
227
|
*
|
|
@@ -140,7 +232,7 @@ export function colorForm(value) {
|
|
|
140
232
|
const v = value.trim();
|
|
141
233
|
if (!v || /^(transparent|currentcolor|inherit|initial|unset|none)$/i.test(v))
|
|
142
234
|
return null;
|
|
143
|
-
return fromHex(v) ?? fromRgb(v) ?? fromHsl(v);
|
|
235
|
+
return fromHex(v) ?? fromRgb(v) ?? fromHsl(v) ?? fromOklch(v);
|
|
144
236
|
}
|
|
145
237
|
/**
|
|
146
238
|
* AS CORES LITERAIS DENTRO DE UM VALOR - inclusive as de dentro de uma função de composição.
|
|
@@ -163,7 +255,7 @@ export function colorsIn(value) {
|
|
|
163
255
|
seen.add(key);
|
|
164
256
|
out.push(c);
|
|
165
257
|
};
|
|
166
|
-
const rest = value.replace(/\b(?:rgba?|hsla
|
|
258
|
+
const rest = value.replace(/\b(?:rgba?|hsla?|oklch)\([^)]*\)/gi, (m) => (push(colorForm(m)), " "));
|
|
167
259
|
for (const m of rest.match(/#[0-9a-f]{3,8}\b/gi) ?? [])
|
|
168
260
|
push(colorForm(m));
|
|
169
261
|
return out;
|
package/dist/doctor/scan.js
CHANGED
|
@@ -38,8 +38,23 @@ const IGNORE_LINE = /^\s*(import|@import|\/\/|\*|\/\*)/;
|
|
|
38
38
|
* plain CSS values and Tailwind arbitrary values (`bg-[#2563eb]`).
|
|
39
39
|
* `#` inside a URL fragment or an id selector is excluded by requiring a full
|
|
40
40
|
* 3/6/8 digit run terminated by a non-hex character.
|
|
41
|
+
*
|
|
42
|
+
* `oklch()` ENTROU EM 03/09, e a ausência dela era a metade calada de uma lacuna maior.
|
|
43
|
+
*
|
|
44
|
+
* O QUE O CLIENTE GANHA: a cor que o Tailwind 4 escreve por padrão passa a ser contada como valor
|
|
45
|
+
* de design. Este regex alimenta TRÊS superfícies - o `observed` do censo, a lista "Values written
|
|
46
|
+
* by hand" do `doctor`, e o relatório do `hook` a cada escrita -, e as três eram cegas a ela.
|
|
47
|
+
*
|
|
48
|
+
* MEDIDO no menor caso possível, uma `@theme` com duas cores em oklch e uma em hex: o `declared`
|
|
49
|
+
* trazia as três, o `look` do componente trazia `background: oklch(...)`, e o `observed` trazia
|
|
50
|
+
* SÓ o `#ffffff` da mesma regra. Nas populações: 94 usos no `codelevel-ui`, 23 no `frontend-hub`,
|
|
51
|
+
* e zero no `observed` das três.
|
|
52
|
+
*
|
|
53
|
+
* Ler oklch aqui e não no motor de cor - ou o contrário - não entrega nada: o valor precisa ser
|
|
54
|
+
* VISTO pelo scanner e INTERPRETADO por `colorForm` para chegar a uma comparação. As duas metades
|
|
55
|
+
* entraram na mesma mudança porque meia jornada não é meio valor.
|
|
41
56
|
*/
|
|
42
|
-
const COLOR = /#[0-9a-fA-F]{8}\b|#[0-9a-fA-F]{6}\b|#[0-9a-fA-F]{3}\b|rgba?\([^)]*\)|hsla?\([^)]*\)/g;
|
|
57
|
+
const COLOR = /#[0-9a-fA-F]{8}\b|#[0-9a-fA-F]{6}\b|#[0-9a-fA-F]{3}\b|rgba?\([^)]*\)|hsla?\([^)]*\)|oklch\([^)]*\)/g;
|
|
43
58
|
/**
|
|
44
59
|
* THE QUOTE THAT MADE HALF THE DRIFT INVISIBLE.
|
|
45
60
|
*
|
package/dist/install-marks.js
CHANGED
|
@@ -235,7 +235,14 @@ export const MATERIALISER_SINCE = "0.16.362";
|
|
|
235
235
|
* "não lido" sobre um valor que o de hoje resolve - e o número é o que a pessoa lê para decidir
|
|
236
236
|
* se adotou. O `!` de important (0.16.306) já tinha mudado a mesma contagem.
|
|
237
237
|
*/
|
|
238
|
-
|
|
238
|
+
/**
|
|
239
|
+
* 0.16.308 -> 0.16.367 em 03/09: o hook passa a ver `oklch()`. O regex de cor do scanner era cego à
|
|
240
|
+
* forma, então um agente que escrevia `oklch(69.6% 0.17 162.48)` recebia SILÊNCIO mesmo com o
|
|
241
|
+
* `--color-mint-500` do próprio repositório nomeando aquele valor. Agora recebe a linha de sempre:
|
|
242
|
+
* `line 12 oklch(...) -> --color-mint-500`. Um hook pinado antes desta versão aconselha OUTRA
|
|
243
|
+
* coisa - nada -, que é a régua desta marca.
|
|
244
|
+
*/
|
|
245
|
+
export const CHECKER_SINCE = "0.16.367";
|
|
239
246
|
/**
|
|
240
247
|
* A ÚLTIMA VERSÃO EM QUE OS LEITORES PASSARAM A PRODUZIR UM CENSO DIFERENTE.
|
|
241
248
|
*
|
|
@@ -651,7 +658,14 @@ export const CHECKER_SINCE = "0.16.308";
|
|
|
651
658
|
* QUEM NÃO É AFETADO: quem tem menos de 4 096 formas em todo grupo - `web-onboarding` já chegava
|
|
652
659
|
* com 39 de 39. O `sync` daquele repositório não muda um byte.
|
|
653
660
|
*/
|
|
654
|
-
|
|
661
|
+
/**
|
|
662
|
+
* 0.16.366 -> 0.16.367 em 03/09: `oklch()` entra na leitura de cor. O regex do scanner passou a ver
|
|
663
|
+
* a forma (era cega no `observed`, no `doctor` e no `hook`) e `colorForm` passou a interpretá-la,
|
|
664
|
+
* mapeando o gamut por chroma em vez de clampar canal. Medido nos `looks`: 94 usos no
|
|
665
|
+
* `codelevel-ui` e 23 no `frontend-hub`, e ZERO no `observed` das três populações. Um censo tirado
|
|
666
|
+
* antes disto não tem aqueles valores na régua, e só um `sync` os traz.
|
|
667
|
+
*/
|
|
668
|
+
export const READER_SINCE = "0.16.367";
|
|
655
669
|
/**
|
|
656
670
|
* O QUE ESTÁ INSTALADO AQUI FICOU PARA TRÁS - e as DUAS condições que fazem isso ser verdade.
|
|
657
671
|
*
|
package/package.json
CHANGED