silvery 0.17.3 → 0.18.0
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/README.md +7 -13
- package/dist/{UPNG-AVSMjiFE.mjs → UPNG-DvKjM6wE.mjs} +1 -1
- package/dist/{UPNG-AVSMjiFE.mjs.map → UPNG-DvKjM6wE.mjs.map} +1 -1
- package/dist/{__vite-browser-external-2447137e-D3GdsvS_.mjs → __vite-browser-external-2447137e-DPKHHqQK.mjs} +1 -1
- package/dist/{__vite-browser-external-2447137e-D3GdsvS_.mjs.map → __vite-browser-external-2447137e-DPKHHqQK.mjs.map} +1 -1
- package/dist/{animation-C_PTO0uH.mjs → animation-DhINOJk8.mjs} +1 -1
- package/dist/{animation-C_PTO0uH.mjs.map → animation-DhINOJk8.mjs.map} +1 -1
- package/dist/{ansi-CXLE_pt1.mjs → ansi-C6Qs1Wn2.mjs} +1 -1
- package/dist/{ansi-CXLE_pt1.mjs.map → ansi-C6Qs1Wn2.mjs.map} +1 -1
- package/dist/{ansi-zmNzgkPB.d.mts → ansi-CsjnZtAw.d.mts} +1 -1
- package/dist/{ansi-zmNzgkPB.d.mts.map → ansi-CsjnZtAw.d.mts.map} +1 -1
- package/dist/apng-CvSlLBtc.mjs +3 -0
- package/dist/{apng-ENBAJk-H.mjs → apng-DFFVOItr.mjs} +3 -3
- package/dist/{apng-ENBAJk-H.mjs.map → apng-DFFVOItr.mjs.map} +1 -1
- package/dist/{backend-CkIkIHR-.mjs → backend-DU0Y938U.mjs} +1 -1
- package/dist/{backend-CkIkIHR-.mjs.map → backend-DU0Y938U.mjs.map} +1 -1
- package/dist/{backends-CkvbG3js.mjs → backends-BihMKFY_.mjs} +3 -3
- package/dist/{backends-CkvbG3js.mjs.map → backends-BihMKFY_.mjs.map} +1 -1
- package/dist/backends-Dk_5G_gC.mjs +3 -0
- package/dist/cli-GwJ0S2In.mjs +4 -0
- package/dist/{context-QreF3UHr.mjs → context-BjWgrikx.mjs} +1 -1
- package/dist/{context-QreF3UHr.mjs.map → context-BjWgrikx.mjs.map} +1 -1
- package/dist/{derive-D7bFJdfU.d.mts → derive-O_Kb1Bk_.d.mts} +3 -3
- package/dist/derive-O_Kb1Bk_.d.mts.map +1 -0
- package/dist/{devtools-owvUPfBi.mjs → devtools-CeO9X_uv.mjs} +4 -4
- package/dist/{devtools-owvUPfBi.mjs.map → devtools-CeO9X_uv.mjs.map} +1 -1
- package/dist/devtools-nX4tj6OH.mjs +2 -0
- package/dist/{eta-DLiVPaSD.mjs → eta-BnQSZcWf.mjs} +1 -1
- package/dist/{eta-DLiVPaSD.mjs.map → eta-BnQSZcWf.mjs.map} +1 -1
- package/dist/{flexily-zero-adapter-DmG4Ge8t.mjs → flexily-zero-adapter-BOM0cl8R.mjs} +61 -9
- package/dist/flexily-zero-adapter-BOM0cl8R.mjs.map +1 -0
- package/dist/{flexily-zero-adapter-GHwEW11s.mjs → flexily-zero-adapter-V8R3HQtK.mjs} +1 -1
- package/dist/{gif-Bp6fIyN3.mjs → gif-B9Uq4qZA.mjs} +3 -3
- package/dist/{gif-Bp6fIyN3.mjs.map → gif-B9Uq4qZA.mjs.map} +1 -1
- package/dist/gif-BdrLRBmM.mjs +3 -0
- package/dist/{gifenc-GiVCZ9-3.mjs → gifenc-DfhOb4xr.mjs} +1 -1
- package/dist/{gifenc-GiVCZ9-3.mjs.map → gifenc-DfhOb4xr.mjs.map} +1 -1
- package/dist/{image-Dx7gYjkq.mjs → image-B0zMbVUr.mjs} +136 -5
- package/dist/image-B0zMbVUr.mjs.map +1 -0
- package/dist/index-Bh3U1K09.d.mts +10823 -0
- package/dist/index-Bh3U1K09.d.mts.map +1 -0
- package/dist/{index-p-wBs_wH.d.mts → index-C4vrhbud.d.mts} +1 -1
- package/dist/{index-p-wBs_wH.d.mts.map → index-C4vrhbud.d.mts.map} +1 -1
- package/dist/{index-DCVL3jHo.d.mts → index-dehZ18K-.d.mts} +144 -99
- package/dist/index-dehZ18K-.d.mts.map +1 -0
- package/dist/index.d.mts +7 -7219
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +13 -9343
- package/dist/index.mjs.map +1 -1
- package/dist/{key-mapping-BsUHe_nk.mjs → key-mapping-7k2ufK2b.mjs} +1 -1
- package/dist/{key-mapping-DsyfLEdC.mjs → key-mapping-WLUmxjx1.mjs} +1 -1
- package/dist/{key-mapping-DsyfLEdC.mjs.map → key-mapping-WLUmxjx1.mjs.map} +1 -1
- package/dist/{layout-engine-D_lSR4i9.mjs → layout-engine--drvrWjD.mjs} +1 -1
- package/dist/{layout-engine-B3dsnVLU.mjs → layout-engine-Dr3cY5U4.mjs} +3 -3
- package/dist/{layout-engine-B3dsnVLU.mjs.map → layout-engine-Dr3cY5U4.mjs.map} +1 -1
- package/dist/{multi-progress-CQVB9lES.mjs → multi-progress-CcdqJFlf.mjs} +3 -3
- package/dist/{multi-progress-CQVB9lES.mjs.map → multi-progress-CcdqJFlf.mjs.map} +1 -1
- package/dist/{multi-progress-C0-rkn86.d.mts → multi-progress-DQ-uUzLf.d.mts} +2 -2
- package/dist/{multi-progress-C0-rkn86.d.mts.map → multi-progress-DQ-uUzLf.d.mts.map} +1 -1
- package/dist/{node-Dedx-6xF.mjs → node-CP5WChgr.mjs} +1 -1
- package/dist/{node-Dedx-6xF.mjs.map → node-CP5WChgr.mjs.map} +1 -1
- package/dist/{progress-bar-COPSBlT9.mjs → progress-bar-IrUjkLfU.mjs} +4 -4
- package/dist/{progress-bar-COPSBlT9.mjs.map → progress-bar-IrUjkLfU.mjs.map} +1 -1
- package/dist/{reconciler-B-NaZvbO.mjs → reconciler-B8uxQxaU.mjs} +57 -81
- package/dist/reconciler-B8uxQxaU.mjs.map +1 -0
- package/dist/{render-string-CZKpuKXo.mjs → render-string-BwLG7rIX.mjs} +1 -1
- package/dist/{pipeline-BmfaZb1O.mjs → render-string-DVfgc8xr.mjs} +836 -508
- package/dist/render-string-DVfgc8xr.mjs.map +1 -0
- package/dist/{resvg-js-V6oMi8CY.mjs → resvg-js-Cwipz-_J.mjs} +1 -1
- package/dist/{resvg-js-V6oMi8CY.mjs.map → resvg-js-Cwipz-_J.mjs.map} +1 -1
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.mjs +3 -3
- package/dist/{spinner-Cgej6Vnb.d.mts → spinner-BRkaJI0N.d.mts} +2 -2
- package/dist/{spinner-Cgej6Vnb.d.mts.map → spinner-BRkaJI0N.d.mts.map} +1 -1
- package/dist/{spinner-DSByknyx.mjs → spinner-BmldKx0M.mjs} +3 -3
- package/dist/{spinner-DSByknyx.mjs.map → spinner-BmldKx0M.mjs.map} +1 -1
- package/dist/{src-C9f3hiVG.mjs → src-C0sOQW-t.mjs} +402 -156
- package/dist/src-C0sOQW-t.mjs.map +1 -0
- package/dist/src-CJPXf3fC.mjs +18348 -0
- package/dist/src-CJPXf3fC.mjs.map +1 -0
- package/dist/{src-fJVbhdn-.mjs → src-D8kLrQBT.mjs} +1 -1
- package/dist/{src-fJVbhdn-.mjs.map → src-D8kLrQBT.mjs.map} +1 -1
- package/dist/{src-9B5k0JmY.mjs → src-D_BS-as7.mjs} +1130 -100
- package/dist/src-D_BS-as7.mjs.map +1 -0
- package/dist/theme.d.mts +45 -30
- package/dist/theme.d.mts.map +1 -1
- package/dist/theme.mjs +3 -3
- package/dist/{types-CDgkE-Rw.d.mts → types-B4A8Ebba.d.mts} +1 -1
- package/dist/{types-CDgkE-Rw.d.mts.map → types-B4A8Ebba.d.mts.map} +1 -1
- package/dist/types-e4dpfbSa.mjs +468 -0
- package/dist/types-e4dpfbSa.mjs.map +1 -0
- package/dist/ui/animation.d.mts +1 -1
- package/dist/ui/animation.mjs +1 -1
- package/dist/ui/ansi.d.mts +1 -1
- package/dist/ui/ansi.mjs +1 -1
- package/dist/ui/cli.d.mts +3 -3
- package/dist/ui/cli.mjs +5 -5
- package/dist/ui/display.d.mts +2 -2
- package/dist/ui/display.mjs +1 -1
- package/dist/ui/display.mjs.map +1 -1
- package/dist/ui/image.d.mts +1 -1
- package/dist/ui/image.mjs +1 -1
- package/dist/ui/input.d.mts +3 -3
- package/dist/ui/input.mjs +2 -2
- package/dist/ui/input.mjs.map +1 -1
- package/dist/ui/progress.d.mts +3 -3
- package/dist/ui/progress.mjs +4 -4
- package/dist/ui/progress.mjs.map +1 -1
- package/dist/ui/react.d.mts +3 -3
- package/dist/ui/react.mjs +4 -4
- package/dist/ui/react.mjs.map +1 -1
- package/dist/ui/utils.mjs +1 -1
- package/dist/ui/wrappers.d.mts +2 -2
- package/dist/ui/wrappers.mjs +1 -1
- package/dist/ui.d.mts +5 -5
- package/dist/ui.mjs +6 -6
- package/dist/{useLatest-BMIYXd6e.d.mts → useLatest-6xqnGIU6.d.mts} +1 -1
- package/dist/{useLatest-BMIYXd6e.d.mts.map → useLatest-6xqnGIU6.d.mts.map} +1 -1
- package/dist/{with-text-input-CmHf_9d6.d.mts → with-text-input-lUh9gYAG.d.mts} +3 -3
- package/dist/{with-text-input-CmHf_9d6.d.mts.map → with-text-input-lUh9gYAG.d.mts.map} +1 -1
- package/dist/{wrapper-Dqh0zi2W.mjs → wrapper-CE6GQ27z.mjs} +1 -1
- package/dist/{wrapper-Dqh0zi2W.mjs.map → wrapper-CE6GQ27z.mjs.map} +1 -1
- package/dist/{wrappers-hhL8EQ_n.mjs → wrappers-JrEYTuKA.mjs} +4 -4
- package/dist/wrappers-JrEYTuKA.mjs.map +1 -0
- package/dist/yoga-adapter-B8LZpQcE.mjs +2 -0
- package/dist/{yoga-adapter-BJ9SOhTY.mjs → yoga-adapter-Bc8XT9cN.mjs} +11 -2
- package/dist/yoga-adapter-Bc8XT9cN.mjs.map +1 -0
- package/package.json +20 -17
- package/dist/apng-DCWY913R.mjs +0 -3
- package/dist/backends-CyJqNLeK.mjs +0 -3
- package/dist/cli-B-k7Bm56.mjs +0 -4
- package/dist/derive-D7bFJdfU.d.mts.map +0 -1
- package/dist/devtools-DS9NseGT.mjs +0 -2
- package/dist/flexily-zero-adapter-DmG4Ge8t.mjs.map +0 -1
- package/dist/gif-BaJNREpP.mjs +0 -3
- package/dist/image-Dx7gYjkq.mjs.map +0 -1
- package/dist/index-CBcSpGSM.d.mts +0 -3416
- package/dist/index-CBcSpGSM.d.mts.map +0 -1
- package/dist/index-DCVL3jHo.d.mts.map +0 -1
- package/dist/pipeline-BmfaZb1O.mjs.map +0 -1
- package/dist/reconciler-B-NaZvbO.mjs.map +0 -1
- package/dist/render-string-Bvh1XzBv.mjs +0 -201
- package/dist/render-string-Bvh1XzBv.mjs.map +0 -1
- package/dist/runtime-PH2xY1DM.mjs +0 -8723
- package/dist/runtime-PH2xY1DM.mjs.map +0 -1
- package/dist/src-9B5k0JmY.mjs.map +0 -1
- package/dist/src-C9f3hiVG.mjs.map +0 -1
- package/dist/types-Bhj5QkIQ.mjs +0 -13
- package/dist/types-Bhj5QkIQ.mjs.map +0 -1
- package/dist/useLayout-BG2cGl15.mjs +0 -139
- package/dist/useLayout-BG2cGl15.mjs.map +0 -1
- package/dist/wrappers-hhL8EQ_n.mjs.map +0 -1
- package/dist/yoga-adapter-BJ9SOhTY.mjs.map +0 -1
- package/dist/yoga-adapter-Daq6-dw1.mjs +0 -2
|
@@ -486,6 +486,169 @@ var init_terminal_control = __esmMin((() => {
|
|
|
486
486
|
`${ESC$3}`;
|
|
487
487
|
}));
|
|
488
488
|
//#endregion
|
|
489
|
+
//#region packages/color/src/oklch.ts
|
|
490
|
+
function parseHex(hex) {
|
|
491
|
+
if (hex[0] !== "#") return null;
|
|
492
|
+
const h = hex.slice(1);
|
|
493
|
+
if (h.length === 3) {
|
|
494
|
+
const r = parseInt(h[0] + h[0], 16);
|
|
495
|
+
const g = parseInt(h[1] + h[1], 16);
|
|
496
|
+
const b = parseInt(h[2] + h[2], 16);
|
|
497
|
+
if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return null;
|
|
498
|
+
return [
|
|
499
|
+
r,
|
|
500
|
+
g,
|
|
501
|
+
b
|
|
502
|
+
];
|
|
503
|
+
}
|
|
504
|
+
if (h.length === 6) {
|
|
505
|
+
const r = parseInt(h.slice(0, 2), 16);
|
|
506
|
+
const g = parseInt(h.slice(2, 4), 16);
|
|
507
|
+
const b = parseInt(h.slice(4, 6), 16);
|
|
508
|
+
if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return null;
|
|
509
|
+
return [
|
|
510
|
+
r,
|
|
511
|
+
g,
|
|
512
|
+
b
|
|
513
|
+
];
|
|
514
|
+
}
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
/** sRGB channel (0–255) → linear RGB (0–1). Inverse gamma. */
|
|
518
|
+
function srgbToLinear(c) {
|
|
519
|
+
const s = c / 255;
|
|
520
|
+
return s <= .04045 ? s / 12.92 : ((s + .055) / 1.055) ** 2.4;
|
|
521
|
+
}
|
|
522
|
+
/** Linear RGB (0–1) → sRGB channel (0–255). Forward gamma. */
|
|
523
|
+
function linearToSrgb(c) {
|
|
524
|
+
const clamped = Math.max(0, Math.min(1, c));
|
|
525
|
+
return clamped <= .0031308 ? 12.92 * clamped * 255 : (1.055 * clamped ** (1 / 2.4) - .055) * 255;
|
|
526
|
+
}
|
|
527
|
+
/** Linear RGB → OKLab (Ottosson 2020 matrix). */
|
|
528
|
+
function linearRgbToOklab(r, g, b) {
|
|
529
|
+
const l = .4122214708 * r + .5363325363 * g + .0514459929 * b;
|
|
530
|
+
const m = .2119034982 * r + .6806995451 * g + .1073969566 * b;
|
|
531
|
+
const s = .0883024619 * r + .2817188376 * g + .6299787005 * b;
|
|
532
|
+
const lCbrt = Math.cbrt(l);
|
|
533
|
+
const mCbrt = Math.cbrt(m);
|
|
534
|
+
const sCbrt = Math.cbrt(s);
|
|
535
|
+
return [
|
|
536
|
+
.2104542553 * lCbrt + .793617785 * mCbrt - .0040720468 * sCbrt,
|
|
537
|
+
1.9779984951 * lCbrt - 2.428592205 * mCbrt + .4505937099 * sCbrt,
|
|
538
|
+
.0259040371 * lCbrt + .7827717662 * mCbrt - .808675766 * sCbrt
|
|
539
|
+
];
|
|
540
|
+
}
|
|
541
|
+
/** OKLab → linear RGB (inverse of the above). */
|
|
542
|
+
function oklabToLinearRgb(L, a, bb) {
|
|
543
|
+
const lCbrt = L + .3963377774 * a + .2158037573 * bb;
|
|
544
|
+
const mCbrt = L - .1055613458 * a - .0638541728 * bb;
|
|
545
|
+
const sCbrt = L - .0894841775 * a - 1.291485548 * bb;
|
|
546
|
+
const l = lCbrt ** 3;
|
|
547
|
+
const m = mCbrt ** 3;
|
|
548
|
+
const s = sCbrt ** 3;
|
|
549
|
+
return [
|
|
550
|
+
4.0767416621 * l - 3.3077115913 * m + .2309699292 * s,
|
|
551
|
+
-1.2684380046 * l + 2.6097574011 * m - .3413193965 * s,
|
|
552
|
+
-.0041960863 * l - .7034186147 * m + 1.707614701 * s
|
|
553
|
+
];
|
|
554
|
+
}
|
|
555
|
+
/** Hex (`#RRGGBB`) → OKLCH. Returns `null` for invalid hex. */
|
|
556
|
+
function hexToOklch(hex) {
|
|
557
|
+
const rgb = parseHex(hex);
|
|
558
|
+
if (!rgb) return null;
|
|
559
|
+
const [r, g, b] = rgb;
|
|
560
|
+
const [lr, lg, lb] = [
|
|
561
|
+
srgbToLinear(r),
|
|
562
|
+
srgbToLinear(g),
|
|
563
|
+
srgbToLinear(b)
|
|
564
|
+
];
|
|
565
|
+
const [L, a, bb] = linearRgbToOklab(lr, lg, lb);
|
|
566
|
+
const C = Math.sqrt(a * a + bb * bb);
|
|
567
|
+
let H = Math.atan2(bb, a) * 180 / Math.PI;
|
|
568
|
+
if (H < 0) H += 360;
|
|
569
|
+
return {
|
|
570
|
+
L,
|
|
571
|
+
C,
|
|
572
|
+
H
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
/** Check whether linear RGB is inside sRGB gamut (each channel in [0, 1]). */
|
|
576
|
+
function inGamut(r, g, b) {
|
|
577
|
+
const e = 1e-5;
|
|
578
|
+
return r >= -e && r <= 1 + e && g >= -e && g <= 1 + e && b >= -e && b <= 1 + e;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* OKLCH → hex. Gamut-maps out-of-sRGB colors by reducing chroma until in-gamut
|
|
582
|
+
* (preserves L and H — the perceptual anchors). This is the CSS Color 4
|
|
583
|
+
* recommended approach for rendering OKLCH on sRGB displays.
|
|
584
|
+
*/
|
|
585
|
+
function oklchToHex(c) {
|
|
586
|
+
const L = Math.max(0, Math.min(1, c.L));
|
|
587
|
+
const Crad = (c.H % 360 + 360) % 360 * Math.PI / 180;
|
|
588
|
+
let lo = 0;
|
|
589
|
+
let hi = Math.max(0, c.C);
|
|
590
|
+
let [rHi, gHi, bHi] = oklabToLinearRgb(L, hi * Math.cos(Crad), hi * Math.sin(Crad));
|
|
591
|
+
if (inGamut(rHi, gHi, bHi)) return rgbToHexInternal(linearToSrgb(rHi), linearToSrgb(gHi), linearToSrgb(bHi));
|
|
592
|
+
for (let i = 0; i < 20; i++) {
|
|
593
|
+
const mid = (lo + hi) / 2;
|
|
594
|
+
const [rr, gg, bbLin] = oklabToLinearRgb(L, mid * Math.cos(Crad), mid * Math.sin(Crad));
|
|
595
|
+
if (inGamut(rr, gg, bbLin)) lo = mid;
|
|
596
|
+
else hi = mid;
|
|
597
|
+
}
|
|
598
|
+
const a = lo * Math.cos(Crad);
|
|
599
|
+
const bb = lo * Math.sin(Crad);
|
|
600
|
+
[rHi, gHi, bHi] = oklabToLinearRgb(L, a, bb);
|
|
601
|
+
return rgbToHexInternal(linearToSrgb(rHi), linearToSrgb(gHi), linearToSrgb(bHi));
|
|
602
|
+
}
|
|
603
|
+
function rgbToHexInternal(r, g, b) {
|
|
604
|
+
const clamp = (n) => Math.max(0, Math.min(255, Math.round(n)));
|
|
605
|
+
return `#${clamp(r).toString(16).padStart(2, "0")}${clamp(g).toString(16).padStart(2, "0")}${clamp(b).toString(16).padStart(2, "0")}`.toUpperCase();
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Linear interpolate in OKLab (rectangular — a, b, L interpolated directly).
|
|
609
|
+
*
|
|
610
|
+
* CSS Color Module 4's default interpolation space. Avoids the hue-arc
|
|
611
|
+
* weirdness of `lerpOklch` when one endpoint is near-neutral (its H is
|
|
612
|
+
* effectively undefined). Produces the expected "tinted surface" when blending
|
|
613
|
+
* `bg` with an accent color.
|
|
614
|
+
*/
|
|
615
|
+
function lerpOklabHex(aHex, bHex, t) {
|
|
616
|
+
const aOk = hexToOklch(aHex);
|
|
617
|
+
const bOk = hexToOklch(bHex);
|
|
618
|
+
if (!aOk || !bOk) return null;
|
|
619
|
+
const aRad = aOk.H * Math.PI / 180;
|
|
620
|
+
const bRad = bOk.H * Math.PI / 180;
|
|
621
|
+
const aA = aOk.C * Math.cos(aRad);
|
|
622
|
+
const aB = aOk.C * Math.sin(aRad);
|
|
623
|
+
const bA = bOk.C * Math.cos(bRad);
|
|
624
|
+
const bB = bOk.C * Math.sin(bRad);
|
|
625
|
+
const L = aOk.L + (bOk.L - aOk.L) * t;
|
|
626
|
+
const A = aA + (bA - aA) * t;
|
|
627
|
+
const B = aB + (bB - aB) * t;
|
|
628
|
+
const C = Math.sqrt(A * A + B * B);
|
|
629
|
+
let H = Math.atan2(B, A) * 180 / Math.PI;
|
|
630
|
+
if (H < 0) H += 360;
|
|
631
|
+
return oklchToHex({
|
|
632
|
+
L,
|
|
633
|
+
C,
|
|
634
|
+
H
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* ΔE in OKLCH (≈ ΔE₀₀ quality in practice — OKLCH was designed to make Euclidean
|
|
639
|
+
* distance perceptually meaningful). Hue is weighted by chroma so near-neutral
|
|
640
|
+
* colors don't produce spurious large ΔH contributions.
|
|
641
|
+
*/
|
|
642
|
+
function deltaE(a, b) {
|
|
643
|
+
const dL = a.L - b.L;
|
|
644
|
+
const dC = a.C - b.C;
|
|
645
|
+
const dh = ((a.H - b.H + 540) % 360 - 180) * (Math.PI / 180);
|
|
646
|
+
(a.C + b.C) / 2;
|
|
647
|
+
const dH = 2 * Math.sqrt(a.C * b.C) * Math.sin(dh / 2);
|
|
648
|
+
return Math.sqrt(dL * dL + dC * dC + dH * dH);
|
|
649
|
+
}
|
|
650
|
+
var init_oklch = __esmMin((() => {}));
|
|
651
|
+
//#endregion
|
|
489
652
|
//#region packages/color/src/color.ts
|
|
490
653
|
/** Parse #rrggbb or #rgb to [r, g, b]. Returns null for invalid input. */
|
|
491
654
|
function hexToRgb(hex) {
|
|
@@ -509,33 +672,90 @@ function rgbToHex(r, g, b) {
|
|
|
509
672
|
return `#${clamp(r).toString(16).padStart(2, "0")}${clamp(g).toString(16).padStart(2, "0")}${clamp(b).toString(16).padStart(2, "0")}`.toUpperCase();
|
|
510
673
|
}
|
|
511
674
|
/**
|
|
512
|
-
* Blend two hex colors. t=0 returns a, t=1 returns b.
|
|
675
|
+
* Blend two hex colors in OKLab space. t=0 returns a, t=1 returns b.
|
|
676
|
+
* Perceptually-uniform midpoints (unlike naive RGB blending which produces
|
|
677
|
+
* muddy halfway colors).
|
|
678
|
+
*
|
|
679
|
+
* Interpolation is done in OKLab (rectangular a/b), not OKLCH (polar). This
|
|
680
|
+
* matches CSS Color Module 4's default interpolation space and avoids hue-arc
|
|
681
|
+
* weirdness when one endpoint is near-neutral (its hue is effectively
|
|
682
|
+
* undefined). For explicit hue-rotation blending, use `lerpOklch` directly.
|
|
683
|
+
*
|
|
513
684
|
* For non-hex inputs (ANSI names), returns `a` unchanged.
|
|
514
685
|
*/
|
|
515
686
|
function blend(a, b, t) {
|
|
516
|
-
|
|
517
|
-
const rgbB = hexToRgb(b);
|
|
518
|
-
if (!rgbA || !rgbB) return a;
|
|
519
|
-
return rgbToHex(rgbA[0] + (rgbB[0] - rgbA[0]) * t, rgbA[1] + (rgbB[1] - rgbA[1]) * t, rgbA[2] + (rgbB[2] - rgbA[2]) * t);
|
|
687
|
+
return lerpOklabHex(a, b, t) ?? a;
|
|
520
688
|
}
|
|
521
689
|
/**
|
|
522
|
-
* Brighten a hex color. amount=0.1 adds
|
|
523
|
-
*
|
|
690
|
+
* Brighten a hex color by raising OKLCH lightness. amount=0.1 adds 0.1 to L
|
|
691
|
+
* (perceptually linear — 10% brighter looks 10% brighter regardless of hue).
|
|
692
|
+
*
|
|
693
|
+
* For non-hex inputs, returns the color unchanged.
|
|
524
694
|
*/
|
|
525
695
|
function brighten(color, amount) {
|
|
526
|
-
|
|
696
|
+
const o = hexToOklch(color);
|
|
697
|
+
if (!o) return color;
|
|
698
|
+
return oklchToHex({
|
|
699
|
+
L: Math.min(1, o.L + amount),
|
|
700
|
+
C: o.C,
|
|
701
|
+
H: o.H
|
|
702
|
+
});
|
|
527
703
|
}
|
|
528
704
|
/**
|
|
529
|
-
* Darken a hex color. amount=0.1
|
|
530
|
-
*
|
|
705
|
+
* Darken a hex color by lowering OKLCH lightness. amount=0.1 subtracts 0.1 from L.
|
|
706
|
+
*
|
|
707
|
+
* For non-hex inputs, returns the color unchanged.
|
|
531
708
|
*/
|
|
532
709
|
function darken(color, amount) {
|
|
533
|
-
|
|
710
|
+
const o = hexToOklch(color);
|
|
711
|
+
if (!o) return color;
|
|
712
|
+
return oklchToHex({
|
|
713
|
+
L: Math.max(0, o.L - amount),
|
|
714
|
+
C: o.C,
|
|
715
|
+
H: o.H
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Desaturate a hex color by lowering OKLCH chroma. amount=0.4 reduces C by 40%
|
|
720
|
+
* (relative — consistent with the original HSL-based contract). For a flat
|
|
721
|
+
* subtraction, use `saturate(color, -amount)`.
|
|
722
|
+
*
|
|
723
|
+
* For non-hex inputs, returns the color unchanged.
|
|
724
|
+
*/
|
|
725
|
+
function desaturate(color, amount) {
|
|
726
|
+
const o = hexToOklch(color);
|
|
727
|
+
if (!o) return color;
|
|
728
|
+
return oklchToHex({
|
|
729
|
+
L: o.L,
|
|
730
|
+
C: Math.max(0, o.C * (1 - amount)),
|
|
731
|
+
H: o.H
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Get the complementary color (180° hue rotation) in OKLCH. Preserves L + C,
|
|
736
|
+
* so the complement has the same perceived brightness and colorfulness.
|
|
737
|
+
*
|
|
738
|
+
* For non-hex inputs, returns the color unchanged.
|
|
739
|
+
*/
|
|
740
|
+
function complement(color) {
|
|
741
|
+
const o = hexToOklch(color);
|
|
742
|
+
if (!o) return color;
|
|
743
|
+
return oklchToHex({
|
|
744
|
+
L: o.L,
|
|
745
|
+
C: o.C,
|
|
746
|
+
H: (o.H + 180) % 360
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
/** Perceptual color distance (ΔE) between two hex colors, in OKLCH. */
|
|
750
|
+
function colorDistance(a, b) {
|
|
751
|
+
const oa = hexToOklch(a);
|
|
752
|
+
const ob = hexToOklch(b);
|
|
753
|
+
if (!oa || !ob) return null;
|
|
754
|
+
return deltaE(oa, ob);
|
|
534
755
|
}
|
|
535
756
|
/**
|
|
536
|
-
* Linearize an sRGB channel value (0-255) for
|
|
537
|
-
*
|
|
538
|
-
* above use the gamma-corrected formula.
|
|
757
|
+
* Linearize an sRGB channel value (0-255) for WCAG 2.1 luminance.
|
|
758
|
+
* Kept for WCAG contrast checking — OKLCH uses its own linearization.
|
|
539
759
|
*/
|
|
540
760
|
function channelLuminance(c) {
|
|
541
761
|
const s = c / 255;
|
|
@@ -552,7 +772,7 @@ function relativeLuminance(hex) {
|
|
|
552
772
|
}
|
|
553
773
|
/**
|
|
554
774
|
* Pick black or white text for readability on the given background.
|
|
555
|
-
* Uses relative luminance
|
|
775
|
+
* Uses WCAG 2.1 relative luminance.
|
|
556
776
|
*/
|
|
557
777
|
function contrastFg(bg) {
|
|
558
778
|
const luminance = relativeLuminance(bg);
|
|
@@ -596,28 +816,9 @@ function hexToHsl(hex) {
|
|
|
596
816
|
if (!rgb) return null;
|
|
597
817
|
return rgbToHsl(rgb[0], rgb[1], rgb[2]);
|
|
598
818
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
* For non-hex inputs, returns the color unchanged.
|
|
603
|
-
*/
|
|
604
|
-
function desaturate(color, amount) {
|
|
605
|
-
const hsl = hexToHsl(color);
|
|
606
|
-
if (!hsl) return color;
|
|
607
|
-
const [h, s, l] = hsl;
|
|
608
|
-
return hslToHex(h, s * (1 - amount), l);
|
|
609
|
-
}
|
|
610
|
-
/**
|
|
611
|
-
* Get the complementary color (180° hue rotation).
|
|
612
|
-
* For non-hex inputs, returns the color unchanged.
|
|
613
|
-
*/
|
|
614
|
-
function complement(color) {
|
|
615
|
-
const hsl = hexToHsl(color);
|
|
616
|
-
if (!hsl) return color;
|
|
617
|
-
const [h, s, l] = hsl;
|
|
618
|
-
return hslToHex(h + 180, s, l);
|
|
619
|
-
}
|
|
620
|
-
var init_color = __esmMin((() => {}));
|
|
819
|
+
var init_color = __esmMin((() => {
|
|
820
|
+
init_oklch();
|
|
821
|
+
}));
|
|
621
822
|
//#endregion
|
|
622
823
|
//#region packages/color/src/contrast.ts
|
|
623
824
|
/**
|
|
@@ -653,24 +854,24 @@ function checkContrast(fg, bg) {
|
|
|
653
854
|
};
|
|
654
855
|
}
|
|
655
856
|
/**
|
|
656
|
-
* Adjust a color's lightness until it meets a minimum contrast ratio
|
|
657
|
-
* against a reference color. Preserves hue and
|
|
658
|
-
*
|
|
857
|
+
* Adjust a color's OKLCH lightness until it meets a minimum WCAG contrast ratio
|
|
858
|
+
* against a reference color. Preserves hue and chroma — only lightness shifts,
|
|
859
|
+
* and only as much as needed.
|
|
659
860
|
*
|
|
660
861
|
* Returns the original color unchanged if it already meets the target.
|
|
661
862
|
*
|
|
863
|
+
* For impossible targets (e.g. 21:1 against mid-gray), returns the
|
|
864
|
+
* best achievable color (near-black or near-white in the same hue).
|
|
865
|
+
*
|
|
662
866
|
* @param color - The color to adjust (hex)
|
|
663
867
|
* @param against - The reference background color (hex)
|
|
664
868
|
* @param minRatio - Minimum contrast ratio to achieve (e.g. 4.5 for AA)
|
|
665
869
|
* @returns Adjusted hex color meeting the target, or original if already OK
|
|
666
870
|
*
|
|
667
|
-
* For impossible targets (e.g. 21:1 against mid-gray), returns the
|
|
668
|
-
* best achievable color (near-black or near-white in the same hue).
|
|
669
|
-
*
|
|
670
871
|
* @example
|
|
671
872
|
* ```typescript
|
|
672
|
-
* // Yellow on white — too low contrast, gets darkened
|
|
673
|
-
* ensureContrast("#FFAB91", "#FFFFFF", 4.5)
|
|
873
|
+
* // Yellow on white — too low contrast, gets darkened (perceptually; same hue preserved)
|
|
874
|
+
* ensureContrast("#FFAB91", "#FFFFFF", 4.5)
|
|
674
875
|
*
|
|
675
876
|
* // Blue on dark bg — already fine, returned unchanged
|
|
676
877
|
* ensureContrast("#5C9FFF", "#1A1A2E", 4.5) // → "#5C9FFF"
|
|
@@ -680,36 +881,45 @@ function ensureContrast(color, against, minRatio) {
|
|
|
680
881
|
const current = checkContrast(color, against);
|
|
681
882
|
if (!current) return color;
|
|
682
883
|
if (current.ratio >= minRatio) return color;
|
|
683
|
-
const
|
|
684
|
-
if (!
|
|
685
|
-
const [h, s] = hsl;
|
|
884
|
+
const o = hexToOklch(color);
|
|
885
|
+
if (!o) return color;
|
|
686
886
|
const lightBg = contrastFg(against) === "#000000";
|
|
687
887
|
let lo, hi;
|
|
688
888
|
if (lightBg) {
|
|
689
889
|
lo = 0;
|
|
690
|
-
hi =
|
|
890
|
+
hi = o.L;
|
|
691
891
|
} else {
|
|
692
|
-
lo =
|
|
892
|
+
lo = o.L;
|
|
693
893
|
hi = 1;
|
|
694
894
|
}
|
|
695
|
-
for (let i = 0; i <
|
|
895
|
+
for (let i = 0; i < 24; i++) {
|
|
696
896
|
const mid = (lo + hi) / 2;
|
|
697
|
-
const r = checkContrast(
|
|
897
|
+
const r = checkContrast(oklchToHex({
|
|
898
|
+
L: mid,
|
|
899
|
+
C: o.C,
|
|
900
|
+
H: o.H
|
|
901
|
+
}), against);
|
|
698
902
|
if (!r) break;
|
|
699
903
|
if (lightBg) if (r.ratio >= minRatio) lo = mid;
|
|
700
904
|
else hi = mid;
|
|
701
905
|
else if (r.ratio >= minRatio) hi = mid;
|
|
702
906
|
else lo = mid;
|
|
703
907
|
}
|
|
704
|
-
return
|
|
908
|
+
return oklchToHex({
|
|
909
|
+
L: lightBg ? lo : hi,
|
|
910
|
+
C: o.C,
|
|
911
|
+
H: o.H
|
|
912
|
+
});
|
|
705
913
|
}
|
|
706
914
|
var init_contrast = __esmMin((() => {
|
|
915
|
+
init_oklch();
|
|
707
916
|
init_color();
|
|
708
917
|
}));
|
|
709
918
|
//#endregion
|
|
710
919
|
//#region packages/color/src/index.ts
|
|
711
920
|
var init_src$1 = __esmMin((() => {
|
|
712
921
|
init_color();
|
|
922
|
+
init_oklch();
|
|
713
923
|
init_contrast();
|
|
714
924
|
}));
|
|
715
925
|
//#endregion
|
|
@@ -757,8 +967,15 @@ function resolveToken(name, theme) {
|
|
|
757
967
|
const idx = parseInt(token.slice(5), 10);
|
|
758
968
|
if (idx >= 0 && idx < 16 && theme.palette && idx < theme.palette.length) return theme.palette[idx];
|
|
759
969
|
}
|
|
760
|
-
const
|
|
761
|
-
|
|
970
|
+
const key = token.replace(/-/g, "");
|
|
971
|
+
const themeObj = theme;
|
|
972
|
+
const direct = themeObj[key];
|
|
973
|
+
if (typeof direct === "string") return direct;
|
|
974
|
+
const aliased = PRIMER_ALIASES[key];
|
|
975
|
+
if (aliased) {
|
|
976
|
+
const val = themeObj[aliased];
|
|
977
|
+
if (typeof val === "string") return val;
|
|
978
|
+
}
|
|
762
979
|
}
|
|
763
980
|
/** Convert chalk numeric level (0-3) to ColorLevel. */
|
|
764
981
|
function fromChalkLevel(n) {
|
|
@@ -971,10 +1188,44 @@ function createChainWithRef(state, ref) {
|
|
|
971
1188
|
proxyRef.proxy = proxy;
|
|
972
1189
|
return proxy;
|
|
973
1190
|
}
|
|
974
|
-
var ESC$2, KNOWN_METHODS, THEME_TOKENS;
|
|
1191
|
+
var PRIMER_ALIASES, ESC$2, KNOWN_METHODS, THEME_TOKENS;
|
|
975
1192
|
var init_style = __esmMin((() => {
|
|
976
1193
|
init_detection();
|
|
977
1194
|
init_colors();
|
|
1195
|
+
PRIMER_ALIASES = {
|
|
1196
|
+
fgmuted: "muted",
|
|
1197
|
+
fgdisabled: "disabledfg",
|
|
1198
|
+
fgcursor: "cursor",
|
|
1199
|
+
fgselected: "selection",
|
|
1200
|
+
fginverse: "inverse",
|
|
1201
|
+
fgonsurface: "surface",
|
|
1202
|
+
fgonpopover: "popover",
|
|
1203
|
+
fgonprimary: "primaryfg",
|
|
1204
|
+
fgonsecondary: "secondaryfg",
|
|
1205
|
+
fgonaccent: "accentfg",
|
|
1206
|
+
fgonerror: "errorfg",
|
|
1207
|
+
fgonwarning: "warningfg",
|
|
1208
|
+
fgonsuccess: "successfg",
|
|
1209
|
+
fgoninfo: "infofg",
|
|
1210
|
+
bgmuted: "mutedbg",
|
|
1211
|
+
bgsurface: "surfacebg",
|
|
1212
|
+
bgpopover: "popoverbg",
|
|
1213
|
+
bginverse: "inversebg",
|
|
1214
|
+
bgselected: "selectionbg",
|
|
1215
|
+
bgcursor: "cursorbg",
|
|
1216
|
+
borderfocus: "focusborder",
|
|
1217
|
+
borderinput: "inputborder",
|
|
1218
|
+
brandhover: "brandHover",
|
|
1219
|
+
brandactive: "brandActive",
|
|
1220
|
+
brandred: "brandRed",
|
|
1221
|
+
brandorange: "brandOrange",
|
|
1222
|
+
brandyellow: "brandYellow",
|
|
1223
|
+
brandgreen: "brandGreen",
|
|
1224
|
+
brandteal: "brandTeal",
|
|
1225
|
+
brandblue: "brandBlue",
|
|
1226
|
+
brandpurple: "brandPurple",
|
|
1227
|
+
brandpink: "brandPink"
|
|
1228
|
+
};
|
|
978
1229
|
ESC$2 = "\x1B[";
|
|
979
1230
|
KNOWN_METHODS = new Set([
|
|
980
1231
|
"hex",
|
|
@@ -1074,11 +1325,302 @@ var init_mixed_proxy = __esmMin((() => {
|
|
|
1074
1325
|
]);
|
|
1075
1326
|
}));
|
|
1076
1327
|
//#endregion
|
|
1328
|
+
//#region packages/ansi/src/theme/invariants.ts
|
|
1329
|
+
function lightness(hex) {
|
|
1330
|
+
const o = hexToOklch(hex);
|
|
1331
|
+
return o ? o.L : null;
|
|
1332
|
+
}
|
|
1333
|
+
/**
|
|
1334
|
+
* Validate post-derivation invariants on a Theme.
|
|
1335
|
+
*
|
|
1336
|
+
* Default: visibility checks only (selection ΔL, cursor ΔE). These are
|
|
1337
|
+
* invariants that `deriveTheme` doesn't enforce and that matter for every
|
|
1338
|
+
* theme regardless of authoring pedigree.
|
|
1339
|
+
*
|
|
1340
|
+
* Opt into WCAG contrast checks via `{ wcag: true }`. Use at build-time to
|
|
1341
|
+
* verify bundled themes, or when loading hand-authored Theme objects that
|
|
1342
|
+
* didn't flow through `deriveTheme`'s `ensureContrast` pass.
|
|
1343
|
+
*
|
|
1344
|
+
* Non-hex values (ANSI names from `ansi16` mode) are skipped with no
|
|
1345
|
+
* violation — ANSI 16 themes can't be contrast-checked in hex space.
|
|
1346
|
+
*
|
|
1347
|
+
* @example
|
|
1348
|
+
* ```ts
|
|
1349
|
+
* // Default — visibility only, fast
|
|
1350
|
+
* const { ok, violations } = validateThemeInvariants(theme)
|
|
1351
|
+
*
|
|
1352
|
+
* // Build-time audit — full WCAG check
|
|
1353
|
+
* const audit = validateThemeInvariants(theme, { wcag: true })
|
|
1354
|
+
* ```
|
|
1355
|
+
*/
|
|
1356
|
+
function validateThemeInvariants(theme, opts = {}) {
|
|
1357
|
+
const checkWcag = opts.wcag ?? false;
|
|
1358
|
+
const checkVisibility = opts.visibility ?? true;
|
|
1359
|
+
const violations = [];
|
|
1360
|
+
if (checkWcag) for (const pair of CONTRAST_PAIRS) {
|
|
1361
|
+
const fg = theme[pair.fg];
|
|
1362
|
+
const bg = theme[pair.bg];
|
|
1363
|
+
if (typeof fg !== "string" || typeof bg !== "string") continue;
|
|
1364
|
+
const r = checkContrast(fg, bg);
|
|
1365
|
+
if (r === null) continue;
|
|
1366
|
+
if (r.ratio < pair.min) violations.push({
|
|
1367
|
+
rule: pair.rule,
|
|
1368
|
+
tokens: [String(pair.fg), String(pair.bg)],
|
|
1369
|
+
actual: r.ratio,
|
|
1370
|
+
required: pair.min,
|
|
1371
|
+
message: `${pair.fg} (${fg}) on ${pair.bg} (${bg}) is ${r.ratio.toFixed(2)}:1, needs ${pair.min.toFixed(1)}:1`
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
if (checkVisibility) {
|
|
1375
|
+
const lBg = lightness(theme.bg);
|
|
1376
|
+
const lSelBg = lightness(theme.selectionbg);
|
|
1377
|
+
if (lBg !== null && lSelBg !== null) {
|
|
1378
|
+
const dL = Math.abs(lSelBg - lBg);
|
|
1379
|
+
if (dL < .08) violations.push({
|
|
1380
|
+
rule: "visibility:selection",
|
|
1381
|
+
tokens: ["selectionbg", "bg"],
|
|
1382
|
+
actual: dL,
|
|
1383
|
+
required: SELECTION_DELTA_L,
|
|
1384
|
+
message: `selectionbg (${theme.selectionbg}) differs from bg (${theme.bg}) by ΔL=${dL.toFixed(3)}, needs ≥ ${SELECTION_DELTA_L.toFixed(2)}`
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
const oBg = hexToOklch(theme.bg);
|
|
1388
|
+
const oCursorBg = hexToOklch(theme.cursorbg);
|
|
1389
|
+
if (oBg && oCursorBg) {
|
|
1390
|
+
const de = deltaE(oBg, oCursorBg);
|
|
1391
|
+
if (de < .15) violations.push({
|
|
1392
|
+
rule: "visibility:cursor",
|
|
1393
|
+
tokens: ["cursorbg", "bg"],
|
|
1394
|
+
actual: de,
|
|
1395
|
+
required: CURSOR_DELTA_E,
|
|
1396
|
+
message: `cursorbg (${theme.cursorbg}) differs from bg (${theme.bg}) by ΔE=${de.toFixed(3)}, needs ≥ ${CURSOR_DELTA_E.toFixed(2)}`
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return {
|
|
1401
|
+
ok: violations.length === 0,
|
|
1402
|
+
violations
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Format violations as a multiline error message for throws/logs.
|
|
1407
|
+
*/
|
|
1408
|
+
function formatViolations(violations) {
|
|
1409
|
+
if (violations.length === 0) return "";
|
|
1410
|
+
return violations.map((v) => ` - [${v.rule}] ${v.message}`).join("\n");
|
|
1411
|
+
}
|
|
1412
|
+
var AA_RATIO, FAINT_RATIO, SELECTION_DELTA_L, CURSOR_DELTA_E, CONTRAST_PAIRS, ThemeInvariantError;
|
|
1413
|
+
var init_invariants = __esmMin((() => {
|
|
1414
|
+
init_src$1();
|
|
1415
|
+
AA_RATIO = 4.5;
|
|
1416
|
+
FAINT_RATIO = 1.5;
|
|
1417
|
+
SELECTION_DELTA_L = .08;
|
|
1418
|
+
CURSOR_DELTA_E = .15;
|
|
1419
|
+
CONTRAST_PAIRS = [
|
|
1420
|
+
{
|
|
1421
|
+
rule: "contrast:fg/bg",
|
|
1422
|
+
fg: "fg",
|
|
1423
|
+
bg: "bg",
|
|
1424
|
+
min: AA_RATIO
|
|
1425
|
+
},
|
|
1426
|
+
{
|
|
1427
|
+
rule: "contrast:fg/surfacebg",
|
|
1428
|
+
fg: "fg",
|
|
1429
|
+
bg: "surfacebg",
|
|
1430
|
+
min: AA_RATIO
|
|
1431
|
+
},
|
|
1432
|
+
{
|
|
1433
|
+
rule: "contrast:fg/popoverbg",
|
|
1434
|
+
fg: "fg",
|
|
1435
|
+
bg: "popoverbg",
|
|
1436
|
+
min: AA_RATIO
|
|
1437
|
+
},
|
|
1438
|
+
{
|
|
1439
|
+
rule: "contrast:muted/mutedbg",
|
|
1440
|
+
fg: "muted",
|
|
1441
|
+
bg: "mutedbg",
|
|
1442
|
+
min: 3
|
|
1443
|
+
},
|
|
1444
|
+
{
|
|
1445
|
+
rule: "contrast:primary/bg",
|
|
1446
|
+
fg: "primary",
|
|
1447
|
+
bg: "bg",
|
|
1448
|
+
min: AA_RATIO
|
|
1449
|
+
},
|
|
1450
|
+
{
|
|
1451
|
+
rule: "contrast:secondary/bg",
|
|
1452
|
+
fg: "secondary",
|
|
1453
|
+
bg: "bg",
|
|
1454
|
+
min: AA_RATIO
|
|
1455
|
+
},
|
|
1456
|
+
{
|
|
1457
|
+
rule: "contrast:accent/bg",
|
|
1458
|
+
fg: "accent",
|
|
1459
|
+
bg: "bg",
|
|
1460
|
+
min: AA_RATIO
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
rule: "contrast:error/bg",
|
|
1464
|
+
fg: "error",
|
|
1465
|
+
bg: "bg",
|
|
1466
|
+
min: AA_RATIO
|
|
1467
|
+
},
|
|
1468
|
+
{
|
|
1469
|
+
rule: "contrast:warning/bg",
|
|
1470
|
+
fg: "warning",
|
|
1471
|
+
bg: "bg",
|
|
1472
|
+
min: AA_RATIO
|
|
1473
|
+
},
|
|
1474
|
+
{
|
|
1475
|
+
rule: "contrast:success/bg",
|
|
1476
|
+
fg: "success",
|
|
1477
|
+
bg: "bg",
|
|
1478
|
+
min: AA_RATIO
|
|
1479
|
+
},
|
|
1480
|
+
{
|
|
1481
|
+
rule: "contrast:info/bg",
|
|
1482
|
+
fg: "info",
|
|
1483
|
+
bg: "bg",
|
|
1484
|
+
min: AA_RATIO
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
rule: "contrast:link/bg",
|
|
1488
|
+
fg: "link",
|
|
1489
|
+
bg: "bg",
|
|
1490
|
+
min: AA_RATIO
|
|
1491
|
+
},
|
|
1492
|
+
{
|
|
1493
|
+
rule: "contrast:inverse/inversebg",
|
|
1494
|
+
fg: "inverse",
|
|
1495
|
+
bg: "inversebg",
|
|
1496
|
+
min: AA_RATIO
|
|
1497
|
+
},
|
|
1498
|
+
{
|
|
1499
|
+
rule: "contrast:selection/selectionbg",
|
|
1500
|
+
fg: "selection",
|
|
1501
|
+
bg: "selectionbg",
|
|
1502
|
+
min: AA_RATIO
|
|
1503
|
+
},
|
|
1504
|
+
{
|
|
1505
|
+
rule: "contrast:cursor/cursorbg",
|
|
1506
|
+
fg: "cursor",
|
|
1507
|
+
bg: "cursorbg",
|
|
1508
|
+
min: AA_RATIO
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
rule: "contrast:primaryfg/primary",
|
|
1512
|
+
fg: "primaryfg",
|
|
1513
|
+
bg: "primary",
|
|
1514
|
+
min: AA_RATIO
|
|
1515
|
+
},
|
|
1516
|
+
{
|
|
1517
|
+
rule: "contrast:secondaryfg/secondary",
|
|
1518
|
+
fg: "secondaryfg",
|
|
1519
|
+
bg: "secondary",
|
|
1520
|
+
min: AA_RATIO
|
|
1521
|
+
},
|
|
1522
|
+
{
|
|
1523
|
+
rule: "contrast:accentfg/accent",
|
|
1524
|
+
fg: "accentfg",
|
|
1525
|
+
bg: "accent",
|
|
1526
|
+
min: AA_RATIO
|
|
1527
|
+
},
|
|
1528
|
+
{
|
|
1529
|
+
rule: "contrast:errorfg/error",
|
|
1530
|
+
fg: "errorfg",
|
|
1531
|
+
bg: "error",
|
|
1532
|
+
min: AA_RATIO
|
|
1533
|
+
},
|
|
1534
|
+
{
|
|
1535
|
+
rule: "contrast:warningfg/warning",
|
|
1536
|
+
fg: "warningfg",
|
|
1537
|
+
bg: "warning",
|
|
1538
|
+
min: AA_RATIO
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
rule: "contrast:successfg/success",
|
|
1542
|
+
fg: "successfg",
|
|
1543
|
+
bg: "success",
|
|
1544
|
+
min: AA_RATIO
|
|
1545
|
+
},
|
|
1546
|
+
{
|
|
1547
|
+
rule: "contrast:infofg/info",
|
|
1548
|
+
fg: "infofg",
|
|
1549
|
+
bg: "info",
|
|
1550
|
+
min: AA_RATIO
|
|
1551
|
+
},
|
|
1552
|
+
{
|
|
1553
|
+
rule: "contrast:inputborder/bg",
|
|
1554
|
+
fg: "inputborder",
|
|
1555
|
+
bg: "bg",
|
|
1556
|
+
min: 3
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
rule: "contrast:focusborder/bg",
|
|
1560
|
+
fg: "focusborder",
|
|
1561
|
+
bg: "bg",
|
|
1562
|
+
min: 3
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
rule: "contrast:disabledfg/bg",
|
|
1566
|
+
fg: "disabledfg",
|
|
1567
|
+
bg: "bg",
|
|
1568
|
+
min: 3
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
rule: "contrast:border/bg",
|
|
1572
|
+
fg: "border",
|
|
1573
|
+
bg: "bg",
|
|
1574
|
+
min: FAINT_RATIO
|
|
1575
|
+
}
|
|
1576
|
+
];
|
|
1577
|
+
ThemeInvariantError = class extends Error {
|
|
1578
|
+
violations;
|
|
1579
|
+
constructor(violations) {
|
|
1580
|
+
super(`Theme invariants failed (${violations.length} violation${violations.length === 1 ? "" : "s"}):\n${formatViolations(violations)}`);
|
|
1581
|
+
this.name = "ThemeInvariantError";
|
|
1582
|
+
this.violations = violations;
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
}));
|
|
1586
|
+
//#endregion
|
|
1077
1587
|
//#region packages/ansi/src/theme/derive.ts
|
|
1078
1588
|
function deriveTheme(palette, mode = "truecolor", adjustments) {
|
|
1079
1589
|
if (mode === "ansi16") return deriveAnsi16Theme(palette);
|
|
1080
1590
|
return deriveTruecolorTheme(palette, adjustments);
|
|
1081
1591
|
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Load and validate a theme from a ColorScheme.
|
|
1594
|
+
*
|
|
1595
|
+
* Combines `deriveTheme()` (auto-adjust via ensureContrast with project-tuned
|
|
1596
|
+
* thresholds) with `validateThemeInvariants()` (post-derivation visibility +
|
|
1597
|
+
* optional WCAG).
|
|
1598
|
+
*
|
|
1599
|
+
* We don't re-impose WCAG on top of derive's tweaked thresholds — default
|
|
1600
|
+
* validation checks visibility invariants only (selection/cursor vs bg) that
|
|
1601
|
+
* derive doesn't handle.
|
|
1602
|
+
*
|
|
1603
|
+
* @example
|
|
1604
|
+
* ```ts
|
|
1605
|
+
* // Default: lenient + visibility-only (derive already handled contrast)
|
|
1606
|
+
* const theme = loadTheme(myScheme)
|
|
1607
|
+
*
|
|
1608
|
+
* // Build-time audit: strict + full WCAG
|
|
1609
|
+
* const theme = loadTheme(myScheme, { enforce: "strict", wcag: true })
|
|
1610
|
+
* ```
|
|
1611
|
+
*/
|
|
1612
|
+
function loadTheme(palette, opts = {}) {
|
|
1613
|
+
const mode = opts.mode ?? "truecolor";
|
|
1614
|
+
const enforce = opts.enforce ?? "lenient";
|
|
1615
|
+
const theme = deriveTheme(palette, mode, opts.adjustments);
|
|
1616
|
+
if (enforce === "off") return theme;
|
|
1617
|
+
const { ok, violations } = validateThemeInvariants(theme, { wcag: opts.wcag });
|
|
1618
|
+
if (!ok) {
|
|
1619
|
+
if (enforce === "strict") throw new ThemeInvariantError(violations);
|
|
1620
|
+
if (opts.violations) opts.violations.push(...violations);
|
|
1621
|
+
}
|
|
1622
|
+
return theme;
|
|
1623
|
+
}
|
|
1082
1624
|
function deriveTruecolorTheme(p, adjustments) {
|
|
1083
1625
|
const dark = p.dark ?? true;
|
|
1084
1626
|
const bg = p.background;
|
|
@@ -1110,13 +1652,26 @@ function deriveTruecolorTheme(p, adjustments) {
|
|
|
1110
1652
|
const success = ensure("success", p.green, bg, AA);
|
|
1111
1653
|
const info = ensure("info", blend(fg, accent, .5), bg, AA);
|
|
1112
1654
|
const link = ensure("link", dark ? p.brightBlue : p.blue, bg, AA);
|
|
1655
|
+
const brand = primary;
|
|
1656
|
+
const brandHover = dark ? brighten(primary, .04) : darken(primary, .04);
|
|
1657
|
+
const brandActive = dark ? brighten(primary, .08) : darken(primary, .08);
|
|
1658
|
+
const red = ensure("red", p.red, bg, AA);
|
|
1659
|
+
const orange = ensure("orange", blend(p.red, p.yellow, .5), bg, AA);
|
|
1660
|
+
const yellow = ensure("yellow", p.yellow, bg, AA);
|
|
1661
|
+
const green = ensure("green", p.green, bg, AA);
|
|
1662
|
+
const teal = ensure("teal", blend(p.green, p.cyan, .5), bg, AA);
|
|
1663
|
+
const blue = ensure("blue", dark ? p.brightBlue : p.blue, bg, AA);
|
|
1664
|
+
const purple = ensure("purple", p.magenta, bg, AA);
|
|
1665
|
+
const pink = ensure("pink", blend(p.magenta, p.red, .5), bg, AA);
|
|
1113
1666
|
const mutedbg = blend(bg, p.foreground, .04);
|
|
1114
1667
|
const muted = ensure("muted", blend(fg, bg, .4), mutedbg, AA);
|
|
1115
1668
|
const disabledfg = ensure("disabledfg", blend(fg, bg, .5), bg, DIM);
|
|
1116
1669
|
const border = ensure("border", blend(bg, p.foreground, .15), bg, FAINT);
|
|
1117
1670
|
const inputborder = ensure("inputborder", blend(bg, p.foreground, .25), bg, CONTROL);
|
|
1118
|
-
const
|
|
1119
|
-
const
|
|
1671
|
+
const selectionBg = repairSelectionBg(p.selectionBackground, bg);
|
|
1672
|
+
const selection = ensure("selection", p.selectionForeground, selectionBg, AA);
|
|
1673
|
+
const cursorBgRepaired = repairCursorBg(p.cursorColor, bg);
|
|
1674
|
+
const cursor = ensure("cursor", p.cursorText, cursorBgRepaired, AA);
|
|
1120
1675
|
return {
|
|
1121
1676
|
name: p.name ?? (dark ? "derived-dark" : "derived-light"),
|
|
1122
1677
|
bg,
|
|
@@ -1130,9 +1685,9 @@ function deriveTruecolorTheme(p, adjustments) {
|
|
|
1130
1685
|
inverse: contrastFg(blend(fg, bg, .1)),
|
|
1131
1686
|
inversebg: blend(fg, bg, .1),
|
|
1132
1687
|
cursor,
|
|
1133
|
-
cursorbg:
|
|
1688
|
+
cursorbg: cursorBgRepaired,
|
|
1134
1689
|
selection,
|
|
1135
|
-
selectionbg:
|
|
1690
|
+
selectionbg: selectionBg,
|
|
1136
1691
|
primary,
|
|
1137
1692
|
primaryfg: contrastFg(primary),
|
|
1138
1693
|
secondary,
|
|
@@ -1169,7 +1724,26 @@ function deriveTruecolorTheme(p, adjustments) {
|
|
|
1169
1724
|
p.brightMagenta,
|
|
1170
1725
|
p.brightCyan,
|
|
1171
1726
|
p.brightWhite
|
|
1172
|
-
]
|
|
1727
|
+
],
|
|
1728
|
+
brand,
|
|
1729
|
+
brandHover,
|
|
1730
|
+
brandActive,
|
|
1731
|
+
red,
|
|
1732
|
+
orange,
|
|
1733
|
+
yellow,
|
|
1734
|
+
green,
|
|
1735
|
+
teal,
|
|
1736
|
+
blue,
|
|
1737
|
+
purple,
|
|
1738
|
+
pink,
|
|
1739
|
+
brandRed: red,
|
|
1740
|
+
brandOrange: orange,
|
|
1741
|
+
brandYellow: yellow,
|
|
1742
|
+
brandGreen: green,
|
|
1743
|
+
brandTeal: teal,
|
|
1744
|
+
brandBlue: blue,
|
|
1745
|
+
brandPurple: purple,
|
|
1746
|
+
brandPink: pink
|
|
1173
1747
|
};
|
|
1174
1748
|
}
|
|
1175
1749
|
function deriveAnsi16Theme(p) {
|
|
@@ -1227,21 +1801,281 @@ function deriveAnsi16Theme(p) {
|
|
|
1227
1801
|
p.brightMagenta,
|
|
1228
1802
|
p.brightCyan,
|
|
1229
1803
|
p.brightWhite
|
|
1230
|
-
]
|
|
1804
|
+
],
|
|
1805
|
+
brand: primaryColor,
|
|
1806
|
+
brandHover: primaryColor,
|
|
1807
|
+
brandActive: primaryColor,
|
|
1808
|
+
brandRed: dark ? p.brightRed : p.red,
|
|
1809
|
+
brandOrange: dark ? p.brightRed : p.red,
|
|
1810
|
+
brandYellow: p.yellow,
|
|
1811
|
+
brandGreen: dark ? p.brightGreen : p.green,
|
|
1812
|
+
brandTeal: p.cyan,
|
|
1813
|
+
brandBlue: dark ? p.brightBlue : p.blue,
|
|
1814
|
+
brandPurple: p.magenta,
|
|
1815
|
+
brandPink: dark ? p.brightMagenta : p.magenta
|
|
1231
1816
|
};
|
|
1232
1817
|
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Nudge `selectionBg`'s OKLCH lightness until it differs from `bg` by at least
|
|
1820
|
+
* `SELECTION_DELTA_L`. Preserves hue + chroma. Non-hex input returns unchanged.
|
|
1821
|
+
*
|
|
1822
|
+
* Direction: shift away from bg — if bg is dark, lift L; if bg is light, drop L.
|
|
1823
|
+
* If the input already meets the threshold, it's returned unchanged.
|
|
1824
|
+
*/
|
|
1825
|
+
function repairSelectionBg(selectionBg, bg) {
|
|
1826
|
+
const oSel = hexToOklch(selectionBg);
|
|
1827
|
+
const oBg = hexToOklch(bg);
|
|
1828
|
+
if (!oSel || !oBg) return selectionBg;
|
|
1829
|
+
const dL = Math.abs(oSel.L - oBg.L);
|
|
1830
|
+
if (dL >= .08) return selectionBg;
|
|
1831
|
+
const needed = SELECTION_DELTA_L - dL + .005;
|
|
1832
|
+
const direction = oSel.L >= oBg.L ? 1 : -1;
|
|
1833
|
+
return oklchToHex({
|
|
1834
|
+
L: Math.max(0, Math.min(1, oSel.L + direction * needed)),
|
|
1835
|
+
C: oSel.C,
|
|
1836
|
+
H: oSel.H
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
/**
|
|
1840
|
+
* Nudge `cursorBg`'s OKLCH values until it differs from `bg` by at least
|
|
1841
|
+
* `CURSOR_DELTA_E`. Shifts lightness first (preserves hue/chroma aesthetics).
|
|
1842
|
+
* Non-hex input returns unchanged.
|
|
1843
|
+
*/
|
|
1844
|
+
function repairCursorBg(cursorBg, bg) {
|
|
1845
|
+
const d = colorDistance(cursorBg, bg);
|
|
1846
|
+
if (d === null || d >= .15) return cursorBg;
|
|
1847
|
+
const oCur = hexToOklch(cursorBg);
|
|
1848
|
+
const oBg = hexToOklch(bg);
|
|
1849
|
+
const lGap = SELECTION_DELTA_L + .02;
|
|
1850
|
+
const direction = oCur.L >= oBg.L ? 1 : -1;
|
|
1851
|
+
const candidate = oklchToHex({
|
|
1852
|
+
L: Math.max(0, Math.min(1, oCur.L + direction * lGap)),
|
|
1853
|
+
C: oCur.C,
|
|
1854
|
+
H: oCur.H
|
|
1855
|
+
});
|
|
1856
|
+
const d2 = colorDistance(candidate, bg);
|
|
1857
|
+
if (d2 !== null && d2 >= .15) return candidate;
|
|
1858
|
+
return oBg.L > .5 ? "#000000" : "#FFFFFF";
|
|
1859
|
+
}
|
|
1233
1860
|
var AA, DIM, FAINT, CONTROL;
|
|
1234
1861
|
var init_derive = __esmMin((() => {
|
|
1235
1862
|
init_src$1();
|
|
1863
|
+
init_invariants();
|
|
1236
1864
|
AA = 4.5;
|
|
1237
1865
|
DIM = 3;
|
|
1238
1866
|
FAINT = 1.5;
|
|
1239
1867
|
CONTROL = 3;
|
|
1240
1868
|
}));
|
|
1241
1869
|
//#endregion
|
|
1242
|
-
//#region packages/ansi/src/theme/
|
|
1243
|
-
|
|
1244
|
-
|
|
1870
|
+
//#region packages/ansi/src/theme/monochrome.ts
|
|
1871
|
+
/**
|
|
1872
|
+
* Produce per-token monochrome attrs from a base Theme.
|
|
1873
|
+
*
|
|
1874
|
+
* Currently returns `DEFAULT_MONO_ATTRS` — a canonical mapping. Passed the
|
|
1875
|
+
* theme to allow per-theme overrides in the future (e.g., a palette that
|
|
1876
|
+
* prefers `underline` for accents over `italic`). The argument is reserved.
|
|
1877
|
+
*/
|
|
1878
|
+
function deriveMonochromeTheme(theme) {
|
|
1879
|
+
return DEFAULT_MONO_ATTRS;
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1882
|
+
* Resolve mono-attrs from a color *string* — the high-level entry point
|
|
1883
|
+
* consumed by the render pipeline.
|
|
1884
|
+
*
|
|
1885
|
+
* Accepts strings like `"$primary"`, `"$fg-muted"`, `"$border-focus"`. Strips
|
|
1886
|
+
* the `$` prefix and hyphens, tries direct Theme key lookup, then falls back
|
|
1887
|
+
* to the Primer alias table. Returns `undefined` for non-token strings (hex,
|
|
1888
|
+
* rgb(), named ANSI colors) — callers should treat this as "no attrs".
|
|
1889
|
+
*
|
|
1890
|
+
* @param color The color string (e.g. `"$primary"`, `"#ff0000"`, `"red"`)
|
|
1891
|
+
* @param theme Active theme (reserved for per-theme overrides)
|
|
1892
|
+
* @returns Array of mono-attrs for the token, or `undefined` if not a
|
|
1893
|
+
* recognized token.
|
|
1894
|
+
*/
|
|
1895
|
+
function monoAttrsForColorString(color, theme) {
|
|
1896
|
+
if (!color.startsWith("$")) return void 0;
|
|
1897
|
+
const raw = color.slice(1).replace(/-/g, "");
|
|
1898
|
+
const attrs = deriveMonochromeTheme(theme);
|
|
1899
|
+
const direct = attrs[raw];
|
|
1900
|
+
if (direct !== void 0) return direct;
|
|
1901
|
+
const aliased = PRIMER_ALIASES_FOR_MONO[raw];
|
|
1902
|
+
if (aliased) {
|
|
1903
|
+
const v = attrs[aliased];
|
|
1904
|
+
if (v !== void 0) return v;
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
var DEFAULT_MONO_ATTRS, PRIMER_ALIASES_FOR_MONO;
|
|
1908
|
+
var init_monochrome = __esmMin((() => {
|
|
1909
|
+
DEFAULT_MONO_ATTRS = {
|
|
1910
|
+
bg: [],
|
|
1911
|
+
mutedbg: [],
|
|
1912
|
+
surfacebg: [],
|
|
1913
|
+
popoverbg: [],
|
|
1914
|
+
border: [],
|
|
1915
|
+
cursorbg: [],
|
|
1916
|
+
fg: [],
|
|
1917
|
+
muted: ["dim"],
|
|
1918
|
+
disabledfg: ["dim"],
|
|
1919
|
+
surface: [],
|
|
1920
|
+
popover: [],
|
|
1921
|
+
inverse: ["inverse"],
|
|
1922
|
+
primary: ["bold"],
|
|
1923
|
+
secondary: ["bold"],
|
|
1924
|
+
accent: ["italic", "bold"],
|
|
1925
|
+
error: ["bold", "inverse"],
|
|
1926
|
+
warning: ["bold"],
|
|
1927
|
+
success: ["bold"],
|
|
1928
|
+
info: ["italic"],
|
|
1929
|
+
primaryfg: [],
|
|
1930
|
+
secondaryfg: [],
|
|
1931
|
+
accentfg: [],
|
|
1932
|
+
errorfg: ["inverse"],
|
|
1933
|
+
warningfg: [],
|
|
1934
|
+
successfg: [],
|
|
1935
|
+
infofg: [],
|
|
1936
|
+
link: ["underline"],
|
|
1937
|
+
focusborder: ["bold"],
|
|
1938
|
+
inputborder: [],
|
|
1939
|
+
selection: [],
|
|
1940
|
+
selectionbg: ["inverse"],
|
|
1941
|
+
cursor: []
|
|
1942
|
+
};
|
|
1943
|
+
PRIMER_ALIASES_FOR_MONO = {
|
|
1944
|
+
fgmuted: "muted",
|
|
1945
|
+
fgdisabled: "disabledfg",
|
|
1946
|
+
fgcursor: "cursor",
|
|
1947
|
+
fgselected: "selection",
|
|
1948
|
+
fginverse: "inverse",
|
|
1949
|
+
fgonsurface: "surface",
|
|
1950
|
+
fgonpopover: "popover",
|
|
1951
|
+
fgonprimary: "primaryfg",
|
|
1952
|
+
fgonsecondary: "secondaryfg",
|
|
1953
|
+
fgonaccent: "accentfg",
|
|
1954
|
+
fgonerror: "errorfg",
|
|
1955
|
+
fgonwarning: "warningfg",
|
|
1956
|
+
fgonsuccess: "successfg",
|
|
1957
|
+
fgoninfo: "infofg",
|
|
1958
|
+
bgmuted: "mutedbg",
|
|
1959
|
+
bgsurface: "surfacebg",
|
|
1960
|
+
bgpopover: "popoverbg",
|
|
1961
|
+
bginverse: "inversebg",
|
|
1962
|
+
bgselected: "selectionbg",
|
|
1963
|
+
bgcursor: "cursorbg",
|
|
1964
|
+
borderfocus: "focusborder",
|
|
1965
|
+
borderinput: "inputborder"
|
|
1966
|
+
};
|
|
1967
|
+
}));
|
|
1968
|
+
//#endregion
|
|
1969
|
+
//#region packages/ansi/src/theme/fingerprint.ts
|
|
1970
|
+
/**
|
|
1971
|
+
* Map ΔE thresholds into a 0–1 confidence.
|
|
1972
|
+
*
|
|
1973
|
+
* sumΔE=0 + maxΔE=0 → 1.0 (perfect match)
|
|
1974
|
+
* sumΔE=30 (threshold) → ~0.5
|
|
1975
|
+
* sumΔE≥60 → ~0.0
|
|
1976
|
+
*/
|
|
1977
|
+
function computeConfidence(sumDE, maxDE, sumThreshold) {
|
|
1978
|
+
const sumScore = Math.max(0, 1 - sumDE / (sumThreshold * 2));
|
|
1979
|
+
const maxScore = Math.max(0, 1 - maxDE / 16);
|
|
1980
|
+
return Math.max(0, Math.min(1, .7 * sumScore + .3 * maxScore));
|
|
1981
|
+
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Match probed slots against a catalog, returning the best candidate if it
|
|
1984
|
+
* satisfies both sum and per-slot thresholds. Returns `null` if nothing matches.
|
|
1985
|
+
*
|
|
1986
|
+
* `probed` is a partial ColorScheme — whatever slots OSC queries returned. Missing
|
|
1987
|
+
* slots are skipped (still counted as "not compared"). Non-hex values are
|
|
1988
|
+
* ignored (ΔE can't be computed).
|
|
1989
|
+
*/
|
|
1990
|
+
function fingerprintMatch(probed, catalog, opts = {}) {
|
|
1991
|
+
const sumThreshold = opts.sumThreshold ?? 30;
|
|
1992
|
+
const perSlotThreshold = opts.perSlotThreshold ?? 8;
|
|
1993
|
+
let best = null;
|
|
1994
|
+
for (const scheme of catalog) {
|
|
1995
|
+
let sumDE = 0;
|
|
1996
|
+
let maxDE = 0;
|
|
1997
|
+
let slotsCompared = 0;
|
|
1998
|
+
for (const field of FINGERPRINT_FIELDS) {
|
|
1999
|
+
const probedVal = probed[field];
|
|
2000
|
+
const catalogVal = scheme[field];
|
|
2001
|
+
if (typeof probedVal !== "string" || typeof catalogVal !== "string") continue;
|
|
2002
|
+
const de = colorDistance(probedVal, catalogVal);
|
|
2003
|
+
if (de === null) continue;
|
|
2004
|
+
const scaled = de * 100;
|
|
2005
|
+
sumDE += scaled;
|
|
2006
|
+
if (scaled > maxDE) maxDE = scaled;
|
|
2007
|
+
slotsCompared++;
|
|
2008
|
+
}
|
|
2009
|
+
if (slotsCompared === 0) continue;
|
|
2010
|
+
if (maxDE > perSlotThreshold) continue;
|
|
2011
|
+
if (sumDE > sumThreshold) continue;
|
|
2012
|
+
if (best === null || sumDE < best.sumDeltaE) best = {
|
|
2013
|
+
scheme,
|
|
2014
|
+
sumDeltaE: sumDE,
|
|
2015
|
+
maxDeltaE: maxDE,
|
|
2016
|
+
slotsCompared,
|
|
2017
|
+
confidence: computeConfidence(sumDE, maxDE, sumThreshold)
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
return best;
|
|
2021
|
+
}
|
|
2022
|
+
var FINGERPRINT_FIELDS;
|
|
2023
|
+
var init_fingerprint = __esmMin((() => {
|
|
2024
|
+
init_src$1();
|
|
2025
|
+
FINGERPRINT_FIELDS = [
|
|
2026
|
+
"foreground",
|
|
2027
|
+
"background",
|
|
2028
|
+
"black",
|
|
2029
|
+
"red",
|
|
2030
|
+
"green",
|
|
2031
|
+
"yellow",
|
|
2032
|
+
"blue",
|
|
2033
|
+
"magenta",
|
|
2034
|
+
"cyan",
|
|
2035
|
+
"white",
|
|
2036
|
+
"brightBlack",
|
|
2037
|
+
"brightRed",
|
|
2038
|
+
"brightGreen",
|
|
2039
|
+
"brightYellow",
|
|
2040
|
+
"brightBlue",
|
|
2041
|
+
"brightMagenta",
|
|
2042
|
+
"brightCyan",
|
|
2043
|
+
"brightWhite"
|
|
2044
|
+
];
|
|
2045
|
+
}));
|
|
2046
|
+
//#endregion
|
|
2047
|
+
//#region packages/ansi/src/theme/types.ts
|
|
2048
|
+
var COLOR_SCHEME_FIELDS;
|
|
2049
|
+
var init_types = __esmMin((() => {
|
|
2050
|
+
COLOR_SCHEME_FIELDS = [
|
|
2051
|
+
"black",
|
|
2052
|
+
"red",
|
|
2053
|
+
"green",
|
|
2054
|
+
"yellow",
|
|
2055
|
+
"blue",
|
|
2056
|
+
"magenta",
|
|
2057
|
+
"cyan",
|
|
2058
|
+
"white",
|
|
2059
|
+
"brightBlack",
|
|
2060
|
+
"brightRed",
|
|
2061
|
+
"brightGreen",
|
|
2062
|
+
"brightYellow",
|
|
2063
|
+
"brightBlue",
|
|
2064
|
+
"brightMagenta",
|
|
2065
|
+
"brightCyan",
|
|
2066
|
+
"brightWhite",
|
|
2067
|
+
"foreground",
|
|
2068
|
+
"background",
|
|
2069
|
+
"cursorColor",
|
|
2070
|
+
"cursorText",
|
|
2071
|
+
"selectionBackground",
|
|
2072
|
+
"selectionForeground"
|
|
2073
|
+
];
|
|
2074
|
+
}));
|
|
2075
|
+
//#endregion
|
|
2076
|
+
//#region packages/ansi/src/theme/default-schemes.ts
|
|
2077
|
+
var ansi16DarkTheme, ansi16LightTheme, defaultDarkScheme, defaultLightScheme;
|
|
2078
|
+
var init_default_schemes = __esmMin((() => {
|
|
1245
2079
|
ansi16DarkTheme = {
|
|
1246
2080
|
name: "dark-ansi16",
|
|
1247
2081
|
bg: "",
|
|
@@ -1294,7 +2128,26 @@ var init_default_palettes = __esmMin((() => {
|
|
|
1294
2128
|
"magentaBright",
|
|
1295
2129
|
"cyanBright",
|
|
1296
2130
|
"whiteBright"
|
|
1297
|
-
]
|
|
2131
|
+
],
|
|
2132
|
+
brand: "yellow",
|
|
2133
|
+
brandHover: "yellow",
|
|
2134
|
+
brandActive: "yellow",
|
|
2135
|
+
red: "redBright",
|
|
2136
|
+
orange: "redBright",
|
|
2137
|
+
yellow: "yellow",
|
|
2138
|
+
green: "greenBright",
|
|
2139
|
+
teal: "cyan",
|
|
2140
|
+
blue: "blueBright",
|
|
2141
|
+
purple: "magenta",
|
|
2142
|
+
pink: "magentaBright",
|
|
2143
|
+
brandRed: "redBright",
|
|
2144
|
+
brandOrange: "redBright",
|
|
2145
|
+
brandYellow: "yellow",
|
|
2146
|
+
brandGreen: "greenBright",
|
|
2147
|
+
brandTeal: "cyan",
|
|
2148
|
+
brandBlue: "blueBright",
|
|
2149
|
+
brandPurple: "magenta",
|
|
2150
|
+
brandPink: "magentaBright"
|
|
1298
2151
|
};
|
|
1299
2152
|
ansi16LightTheme = {
|
|
1300
2153
|
name: "light-ansi16",
|
|
@@ -1348,37 +2201,79 @@ var init_default_palettes = __esmMin((() => {
|
|
|
1348
2201
|
"magentaBright",
|
|
1349
2202
|
"cyanBright",
|
|
1350
2203
|
"whiteBright"
|
|
1351
|
-
]
|
|
2204
|
+
],
|
|
2205
|
+
brand: "blue",
|
|
2206
|
+
brandHover: "blue",
|
|
2207
|
+
brandActive: "blue",
|
|
2208
|
+
red: "red",
|
|
2209
|
+
orange: "red",
|
|
2210
|
+
yellow: "yellow",
|
|
2211
|
+
green: "green",
|
|
2212
|
+
teal: "cyan",
|
|
2213
|
+
blue: "blue",
|
|
2214
|
+
purple: "magenta",
|
|
2215
|
+
pink: "magenta",
|
|
2216
|
+
brandRed: "red",
|
|
2217
|
+
brandOrange: "red",
|
|
2218
|
+
brandYellow: "yellow",
|
|
2219
|
+
brandGreen: "green",
|
|
2220
|
+
brandTeal: "cyan",
|
|
2221
|
+
brandBlue: "blue",
|
|
2222
|
+
brandPurple: "magenta",
|
|
2223
|
+
brandPink: "magenta"
|
|
2224
|
+
};
|
|
2225
|
+
defaultDarkScheme = {
|
|
2226
|
+
name: "default-dark",
|
|
2227
|
+
dark: true,
|
|
2228
|
+
black: "#2e3440",
|
|
2229
|
+
red: "#bf616a",
|
|
2230
|
+
green: "#a3be8c",
|
|
2231
|
+
yellow: "#ebcb8b",
|
|
2232
|
+
blue: "#81a1c1",
|
|
2233
|
+
magenta: "#b48ead",
|
|
2234
|
+
cyan: "#88c0d0",
|
|
2235
|
+
white: "#d8dee9",
|
|
2236
|
+
brightBlack: "#4c566a",
|
|
2237
|
+
brightRed: "#bf616a",
|
|
2238
|
+
brightGreen: "#a3be8c",
|
|
2239
|
+
brightYellow: "#ebcb8b",
|
|
2240
|
+
brightBlue: "#81a1c1",
|
|
2241
|
+
brightMagenta: "#b48ead",
|
|
2242
|
+
brightCyan: "#8fbcbb",
|
|
2243
|
+
brightWhite: "#eceff4",
|
|
2244
|
+
foreground: "#d8dee9",
|
|
2245
|
+
background: "#2e3440",
|
|
2246
|
+
cursorColor: "#d8dee9",
|
|
2247
|
+
cursorText: "#2e3440",
|
|
2248
|
+
selectionBackground: "#434c5e",
|
|
2249
|
+
selectionForeground: "#d8dee9"
|
|
2250
|
+
};
|
|
2251
|
+
defaultLightScheme = {
|
|
2252
|
+
name: "default-light",
|
|
2253
|
+
dark: false,
|
|
2254
|
+
black: "#5c6370",
|
|
2255
|
+
red: "#d20f39",
|
|
2256
|
+
green: "#40a02b",
|
|
2257
|
+
yellow: "#df8e1d",
|
|
2258
|
+
blue: "#1e66f5",
|
|
2259
|
+
magenta: "#8839ef",
|
|
2260
|
+
cyan: "#179299",
|
|
2261
|
+
white: "#dce0e8",
|
|
2262
|
+
brightBlack: "#6c7086",
|
|
2263
|
+
brightRed: "#d20f39",
|
|
2264
|
+
brightGreen: "#40a02b",
|
|
2265
|
+
brightYellow: "#df8e1d",
|
|
2266
|
+
brightBlue: "#1e66f5",
|
|
2267
|
+
brightMagenta: "#8839ef",
|
|
2268
|
+
brightCyan: "#179299",
|
|
2269
|
+
brightWhite: "#eff1f5",
|
|
2270
|
+
foreground: "#4c4f69",
|
|
2271
|
+
background: "#eff1f5",
|
|
2272
|
+
cursorColor: "#dc8a78",
|
|
2273
|
+
cursorText: "#eff1f5",
|
|
2274
|
+
selectionBackground: "#ccd0da",
|
|
2275
|
+
selectionForeground: "#4c4f69"
|
|
1352
2276
|
};
|
|
1353
|
-
}));
|
|
1354
|
-
//#endregion
|
|
1355
|
-
//#region packages/ansi/src/theme/types.ts
|
|
1356
|
-
var COLOR_PALETTE_FIELDS;
|
|
1357
|
-
var init_types = __esmMin((() => {
|
|
1358
|
-
COLOR_PALETTE_FIELDS = [
|
|
1359
|
-
"black",
|
|
1360
|
-
"red",
|
|
1361
|
-
"green",
|
|
1362
|
-
"yellow",
|
|
1363
|
-
"blue",
|
|
1364
|
-
"magenta",
|
|
1365
|
-
"cyan",
|
|
1366
|
-
"white",
|
|
1367
|
-
"brightBlack",
|
|
1368
|
-
"brightRed",
|
|
1369
|
-
"brightGreen",
|
|
1370
|
-
"brightYellow",
|
|
1371
|
-
"brightBlue",
|
|
1372
|
-
"brightMagenta",
|
|
1373
|
-
"brightCyan",
|
|
1374
|
-
"brightWhite",
|
|
1375
|
-
"foreground",
|
|
1376
|
-
"background",
|
|
1377
|
-
"cursorColor",
|
|
1378
|
-
"cursorText",
|
|
1379
|
-
"selectionBackground",
|
|
1380
|
-
"selectionForeground"
|
|
1381
|
-
];
|
|
1382
2277
|
}));
|
|
1383
2278
|
//#endregion
|
|
1384
2279
|
//#region packages/ansi/src/osc-palette.ts
|
|
@@ -1495,7 +2390,7 @@ var init_osc_colors = __esmMin((() => {
|
|
|
1495
2390
|
}));
|
|
1496
2391
|
//#endregion
|
|
1497
2392
|
//#region packages/ansi/src/theme/detect.ts
|
|
1498
|
-
async function
|
|
2393
|
+
async function detectTerminalScheme(timeoutMs = 150) {
|
|
1499
2394
|
const stdin = process.stdin;
|
|
1500
2395
|
const stdout = process.stdout;
|
|
1501
2396
|
if (!stdin.isTTY || !stdout.isTTY) return null;
|
|
@@ -1601,6 +2496,139 @@ function isDarkColor(hex) {
|
|
|
1601
2496
|
var init_detect = __esmMin((() => {
|
|
1602
2497
|
init_osc_palette();
|
|
1603
2498
|
init_osc_colors();
|
|
2499
|
+
}));
|
|
2500
|
+
//#endregion
|
|
2501
|
+
//#region packages/ansi/src/theme/orchestrator.ts
|
|
2502
|
+
function envOverride() {
|
|
2503
|
+
const v = process.env.SILVERY_COLOR;
|
|
2504
|
+
if (!v) return null;
|
|
2505
|
+
if (v === "truecolor" || v === "256" || v === "ansi16" || v === "scheme" || v === "mono" || v === "auto") return v;
|
|
2506
|
+
return null;
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Detect the terminal's color scheme + derive a theme in one call.
|
|
2510
|
+
*
|
|
2511
|
+
* Runs the 4-layer detection cascade (override → probe → fingerprint →
|
|
2512
|
+
* fallback) and returns a fully-resolved Theme along with provenance metadata
|
|
2513
|
+
* so callers can log how the scheme was determined.
|
|
2514
|
+
*
|
|
2515
|
+
* This is the recommended entry point for apps — it handles all the gotchas
|
|
2516
|
+
* (non-TTY environments, failed probes, partial OSC responses, catalog matches,
|
|
2517
|
+
* bg-mode inference) and returns something you can hand to `ThemeProvider`.
|
|
2518
|
+
*
|
|
2519
|
+
* @example
|
|
2520
|
+
* ```ts
|
|
2521
|
+
* import { detectScheme } from "@silvery/ansi"
|
|
2522
|
+
* import { builtinPalettes } from "@silvery/theme/schemes"
|
|
2523
|
+
*
|
|
2524
|
+
* const { scheme, theme, source, matchedName, confidence } = await detectScheme({
|
|
2525
|
+
* catalog: Object.values(builtinPalettes),
|
|
2526
|
+
* enforce: "lenient",
|
|
2527
|
+
* })
|
|
2528
|
+
* console.log(`${source === "fingerprint" ? `detected ${matchedName}` : source} (${(confidence * 100).toFixed(0)}%)`)
|
|
2529
|
+
* ```
|
|
2530
|
+
*/
|
|
2531
|
+
async function detectScheme(opts = {}) {
|
|
2532
|
+
const enforce = opts.enforce ?? "lenient";
|
|
2533
|
+
const wcag = opts.wcag ?? false;
|
|
2534
|
+
if (opts.override) {
|
|
2535
|
+
const theme = loadTheme(opts.override, {
|
|
2536
|
+
enforce,
|
|
2537
|
+
wcag
|
|
2538
|
+
});
|
|
2539
|
+
return {
|
|
2540
|
+
scheme: opts.override,
|
|
2541
|
+
theme,
|
|
2542
|
+
source: "override",
|
|
2543
|
+
confidence: 1,
|
|
2544
|
+
slotSources: allSlotsFrom("fallback"),
|
|
2545
|
+
matchedName: opts.override.name
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2548
|
+
const envMode = envOverride();
|
|
2549
|
+
if (envMode === "mono" || envMode === "ansi16") {
|
|
2550
|
+
const fallback = opts.darkFallback !== false ? defaultDarkScheme : defaultLightScheme;
|
|
2551
|
+
return {
|
|
2552
|
+
scheme: fallback,
|
|
2553
|
+
theme: loadTheme(fallback, {
|
|
2554
|
+
enforce,
|
|
2555
|
+
wcag
|
|
2556
|
+
}),
|
|
2557
|
+
source: "override",
|
|
2558
|
+
confidence: 1,
|
|
2559
|
+
slotSources: allSlotsFrom("fallback"),
|
|
2560
|
+
matchedName: fallback.name
|
|
2561
|
+
};
|
|
2562
|
+
}
|
|
2563
|
+
const detected = await detectTerminalScheme(opts.timeoutMs);
|
|
2564
|
+
if (!detected) {
|
|
2565
|
+
const fallback = opts.darkFallback !== false ? defaultDarkScheme : defaultLightScheme;
|
|
2566
|
+
return {
|
|
2567
|
+
scheme: fallback,
|
|
2568
|
+
theme: loadTheme(fallback, {
|
|
2569
|
+
enforce,
|
|
2570
|
+
wcag
|
|
2571
|
+
}),
|
|
2572
|
+
source: "fallback",
|
|
2573
|
+
confidence: 0,
|
|
2574
|
+
slotSources: allSlotsFrom("fallback"),
|
|
2575
|
+
matchedName: fallback.name
|
|
2576
|
+
};
|
|
2577
|
+
}
|
|
2578
|
+
const catalog = opts.catalog ?? [];
|
|
2579
|
+
if (catalog.length > 0) {
|
|
2580
|
+
const match = fingerprintMatch(detected.palette, catalog);
|
|
2581
|
+
if (match) {
|
|
2582
|
+
const theme = loadTheme(match.scheme, {
|
|
2583
|
+
enforce,
|
|
2584
|
+
wcag
|
|
2585
|
+
});
|
|
2586
|
+
return {
|
|
2587
|
+
scheme: match.scheme,
|
|
2588
|
+
theme,
|
|
2589
|
+
source: "fingerprint",
|
|
2590
|
+
confidence: match.confidence,
|
|
2591
|
+
slotSources: allSlotsFrom("catalog"),
|
|
2592
|
+
matchedName: match.scheme.name
|
|
2593
|
+
};
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
const merged = {
|
|
2597
|
+
...detected.dark ? defaultDarkScheme : defaultLightScheme,
|
|
2598
|
+
...stripNulls(detected.palette)
|
|
2599
|
+
};
|
|
2600
|
+
const theme = loadTheme(merged, {
|
|
2601
|
+
enforce,
|
|
2602
|
+
wcag
|
|
2603
|
+
});
|
|
2604
|
+
const slotSources = {};
|
|
2605
|
+
for (const field of COLOR_SCHEME_FIELDS) slotSources[field] = typeof detected.palette[field] === "string" ? "probed" : "fallback";
|
|
2606
|
+
const probedCount = Object.values(slotSources).filter((s) => s === "probed").length;
|
|
2607
|
+
return {
|
|
2608
|
+
scheme: merged,
|
|
2609
|
+
theme,
|
|
2610
|
+
source: "probed",
|
|
2611
|
+
confidence: Math.min(1, probedCount / 18),
|
|
2612
|
+
slotSources,
|
|
2613
|
+
matchedName: void 0
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2616
|
+
function stripNulls(partial) {
|
|
2617
|
+
const result = {};
|
|
2618
|
+
for (const [k, v] of Object.entries(partial)) if (v != null) result[k] = v;
|
|
2619
|
+
return result;
|
|
2620
|
+
}
|
|
2621
|
+
function allSlotsFrom(src) {
|
|
2622
|
+
const out = {};
|
|
2623
|
+
for (const field of COLOR_SCHEME_FIELDS) out[field] = src;
|
|
2624
|
+
return out;
|
|
2625
|
+
}
|
|
2626
|
+
var init_orchestrator = __esmMin((() => {
|
|
2627
|
+
init_types();
|
|
2628
|
+
init_derive();
|
|
2629
|
+
init_detect();
|
|
2630
|
+
init_fingerprint();
|
|
2631
|
+
init_default_schemes();
|
|
1604
2632
|
})), CSI;
|
|
1605
2633
|
var init_color_scheme = __esmMin((() => {
|
|
1606
2634
|
CSI = `[`;
|
|
@@ -1617,13 +2645,15 @@ var init_src = __esmMin((() => {
|
|
|
1617
2645
|
init_style();
|
|
1618
2646
|
init_mixed_proxy();
|
|
1619
2647
|
init_derive();
|
|
1620
|
-
|
|
2648
|
+
init_monochrome();
|
|
2649
|
+
init_orchestrator();
|
|
2650
|
+
init_default_schemes();
|
|
1621
2651
|
init_types();
|
|
1622
2652
|
init_detect();
|
|
1623
2653
|
init_osc_palette();
|
|
1624
2654
|
init_color_scheme();
|
|
1625
2655
|
}));
|
|
1626
2656
|
//#endregion
|
|
1627
|
-
export {
|
|
2657
|
+
export { detectTerminalCaps as $, brighten as A, rgbToHsl as B, createMixedStyle as C, checkContrast as D, init_src$1 as E, hexToHsl as F, enableKittyKeyboard as G, oklchToHex as H, hexToRgb as I, fgColorCode as J, enableMouse as K, hslToHex as L, contrastFg as M, darken as N, ensureContrast as O, desaturate as P, detectInput as Q, relativeLuminance as R, deriveTheme as S, resolveThemeColor as T, disableKittyKeyboard as U, hexToOklch as V, disableMouse as W, detectColor as X, defaultCaps as Y, detectCursor as Z, setPaletteColor as _, queryBackgroundColor as a, COLOR_SCHEME_FIELDS as b, resetBackgroundColor as c, setBackgroundColor as d, detectUnicode as et, setCursorColor as f, queryPaletteColor as g, queryMultiplePaletteColors as h, detectColorScheme as i, complement as j, blend as k, resetCursorColor as l, parsePaletteResponse as m, detectScheme as n, queryCursorColor as o, setForegroundColor as p, bgColorCode as q, detectTerminalScheme as r, queryForegroundColor as s, init_src as t, resetForegroundColor as u, ansi16DarkTheme as v, createStyle as w, monoAttrsForColorString as x, ansi16LightTheme as y, rgbToHex as z };
|
|
1628
2658
|
|
|
1629
|
-
//# sourceMappingURL=src-
|
|
2659
|
+
//# sourceMappingURL=src-D_BS-as7.mjs.map
|