@ngxsmk/theme 1.3.1 → 1.3.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ngxsmk/theme
2
2
 
3
- The design-token engine of the [NGXSMK UI kit](https://github.com/NGXSMK/ngxsmk-ui-kit). A `ThemeConfig` maps to a flat set of `--ngxsmk-*` CSS custom properties that every `@ngxsmk/core` component reads. Ships 4 presets, light/dark/system strategies, and runtime theme switching via `NgxsmkThemeService`.
3
+ The design-token engine of the [NGXSMK UI kit](https://ngxsmk.github.io/ngxsmk-ui-kit). A `ThemeConfig` maps to a flat set of `--ngxsmk-*` CSS custom properties that every `@ngxsmk/core` component reads. Ships 4 presets, light/dark/system strategies, and runtime theme switching via `NgxsmkThemeService`.
4
4
 
5
5
  ## Compatibility
6
6
 
@@ -1,4 +1,4 @@
1
- export function hexToHsl(hex) {
1
+ function hexToRgb(hex) {
2
2
  const value = hex.replace('#', '');
3
3
  const full = value.length === 3
4
4
  ? value
@@ -12,90 +12,80 @@ export function hexToHsl(hex) {
12
12
  const r = parseInt(full.slice(0, 2), 16) / 255;
13
13
  const g = parseInt(full.slice(2, 4), 16) / 255;
14
14
  const b = parseInt(full.slice(4, 6), 16) / 255;
15
- const max = Math.max(r, g, b);
16
- const min = Math.min(r, g, b);
17
- const delta = max - min;
18
- const l = (max + min) / 2;
19
- let h = 0;
20
- let s = 0;
21
- if (delta !== 0) {
22
- s = delta / (1 - Math.abs(2 * l - 1));
23
- switch (max) {
24
- case r:
25
- h = 60 * (((g - b) / delta) % 6);
26
- break;
27
- case g:
28
- h = 60 * ((b - r) / delta + 2);
29
- break;
30
- default:
31
- h = 60 * ((r - g) / delta + 4);
32
- }
33
- }
15
+ return { r, g, b };
16
+ }
17
+ function srgbToLinear(c) {
18
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
19
+ }
20
+ function linearToSrgb(c) {
21
+ return c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
22
+ }
23
+ export function hexToOklch(hex) {
24
+ const { r: sr, g: sg, b: sb } = hexToRgb(hex);
25
+ const r = srgbToLinear(sr);
26
+ const g = srgbToLinear(sg);
27
+ const b = srgbToLinear(sb);
28
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
29
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
30
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
31
+ const l_ = Math.cbrt(l);
32
+ const m_ = Math.cbrt(m);
33
+ const s_ = Math.cbrt(s);
34
+ const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
35
+ const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
36
+ const b_ = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
37
+ const C = Math.sqrt(a * a + b_ * b_);
38
+ let h = (Math.atan2(b_, a) * 180) / Math.PI;
34
39
  if (h < 0)
35
40
  h += 360;
36
- return { h, s: s * 100, l: l * 100 };
41
+ return { l: L, c: C, h };
37
42
  }
38
- export function hslToHex({ h, s, l }) {
39
- const sn = s / 100;
40
- const ln = l / 100;
41
- const c = (1 - Math.abs(2 * ln - 1)) * sn;
42
- const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
43
- const m = ln - c / 2;
44
- let rgb;
45
- if (h < 60)
46
- rgb = [c, x, 0];
47
- else if (h < 120)
48
- rgb = [x, c, 0];
49
- else if (h < 180)
50
- rgb = [0, c, x];
51
- else if (h < 240)
52
- rgb = [0, x, c];
53
- else if (h < 300)
54
- rgb = [x, 0, c];
55
- else
56
- rgb = [c, 0, x];
57
- const toHex = (v) => Math.round((v + m) * 255)
58
- .toString(16)
59
- .padStart(2, '0');
60
- return `#${toHex(rgb[0])}${toHex(rgb[1])}${toHex(rgb[2])}`.toUpperCase();
43
+ export function oklchToHex({ l: L, c: C, h }) {
44
+ const hRad = (h * Math.PI) / 180;
45
+ const a = C * Math.cos(hRad);
46
+ const b_ = C * Math.sin(hRad);
47
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * b_;
48
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * b_;
49
+ const s_ = L - 0.0894841775 * a - 1.291485548 * b_;
50
+ const l = l_ * l_ * l_;
51
+ const m = m_ * m_ * m_;
52
+ const s = s_ * s_ * s_;
53
+ const r = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
54
+ const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
55
+ const b = -0.0041960863 * l - 0.7034186148 * m + 1.707614701 * s;
56
+ const rClamped = Math.min(255, Math.max(0, Math.round(linearToSrgb(r) * 255)));
57
+ const gClamped = Math.min(255, Math.max(0, Math.round(linearToSrgb(g) * 255)));
58
+ const bClamped = Math.min(255, Math.max(0, Math.round(linearToSrgb(b) * 255)));
59
+ const toHex = (v) => v.toString(16).padStart(2, '0');
60
+ return `#${toHex(rClamped)}${toHex(gClamped)}${toHex(bClamped)}`.toUpperCase();
61
61
  }
62
- /** Shift a color's lightness by `delta` percentage points (clamped 0–100). */
62
+ /** Shift a color's lightness by `delta` (clamped 0–1). */
63
63
  export function shiftLightness(hex, delta) {
64
- const hsl = hexToHsl(hex);
65
- return hslToHex({ ...hsl, l: Math.min(100, Math.max(0, hsl.l + delta)) });
64
+ const oklch = hexToOklch(hex);
65
+ return oklchToHex({ ...oklch, l: Math.min(1.0, Math.max(0.0, oklch.l + delta)) });
66
66
  }
67
- /** Rotate a color's hue by `degrees`, keeping saturation and lightness. */
67
+ /** Rotate a color's hue by `degrees`, keeping chroma and lightness. */
68
68
  export function rotateHue(hex, degrees) {
69
- const hsl = hexToHsl(hex);
70
- return hslToHex({ ...hsl, h: (((hsl.h + degrees) % 360) + 360) % 360 });
69
+ const oklch = hexToOklch(hex);
70
+ return oklchToHex({ ...oklch, h: (((oklch.h + degrees) % 360) + 360) % 360 });
71
71
  }
72
- /**
73
- * Lightness stops for each scale step. Tuned so that step 500/600 stays close
74
- * to typical brand-color lightness and the extremes remain usable as tinted
75
- * backgrounds (50–100) and readable text (900–950).
76
- */
72
+ /** Lightness stops for each scale step in OKLCH (0–1). */
77
73
  const LIGHTNESS_STOPS = {
78
- 50: 97,
79
- 100: 94,
80
- 200: 87,
81
- 300: 78,
82
- 400: 66,
83
- 500: 56,
84
- 600: 48,
85
- 700: 40,
86
- 800: 32,
87
- 900: 25,
88
- 950: 16,
74
+ 50: 0.97,
75
+ 100: 0.94,
76
+ 200: 0.87,
77
+ 300: 0.78,
78
+ 400: 0.66,
79
+ 500: 0.56,
80
+ 600: 0.48,
81
+ 700: 0.4,
82
+ 800: 0.32,
83
+ 900: 0.25,
84
+ 950: 0.16,
89
85
  };
90
- /**
91
- * Derive a full 50–950 color scale from a single brand hex.
92
- *
93
- * The input color keeps its exact value at the step whose lightness stop is
94
- * nearest to the input's own lightness, so `scale[step]` round-trips brand
95
- * colors instead of shifting them.
96
- */
86
+ /** Derive a full 50–950 color scale from a single brand hex. */
97
87
  export function deriveScale(baseHex) {
98
- const base = hexToHsl(baseHex);
88
+ const base = hexToOklch(baseHex);
99
89
  let nearest = 500;
100
90
  let nearestDelta = Number.POSITIVE_INFINITY;
101
91
  for (const [step, stop] of Object.entries(LIGHTNESS_STOPS)) {
@@ -108,8 +98,15 @@ export function deriveScale(baseHex) {
108
98
  const scale = {};
109
99
  for (const [step, stop] of Object.entries(LIGHTNESS_STOPS)) {
110
100
  const key = Number(step);
111
- scale[key] = key === nearest ? hslToHex(base) : hslToHex({ h: base.h, s: base.s, l: stop });
101
+ if (key === nearest) {
102
+ scale[key] = oklchToHex(base);
103
+ }
104
+ else {
105
+ // Perceptually scale chroma using a sine taper so that extremes (50/950) don't clip/saturate unnaturally.
106
+ const scaleChroma = base.c * Math.sin(Math.PI * stop);
107
+ scale[key] = oklchToHex({ l: stop, c: scaleChroma, h: base.h });
108
+ }
112
109
  }
113
110
  return scale;
114
111
  }
115
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29sb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy90aGVtZS9zcmMvbGliL2NvbG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVNBLE1BQU0sVUFBVSxRQUFRLENBQUMsR0FBVztJQUNsQyxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNuQyxNQUFNLElBQUksR0FDUixLQUFLLENBQUMsTUFBTSxLQUFLLENBQUM7UUFDaEIsQ0FBQyxDQUFDLEtBQUs7YUFDRixLQUFLLENBQUMsRUFBRSxDQUFDO2FBQ1QsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQ2pCLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDYixDQUFDLENBQUMsS0FBSyxDQUFDO0lBQ1osSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ25DLE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLEdBQUcsR0FBRyxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVELE1BQU0sQ0FBQyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUM7SUFDL0MsTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUMvQyxNQUFNLENBQUMsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDO0lBRS9DLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUM5QixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDOUIsTUFBTSxLQUFLLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUN4QixNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFFMUIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ1YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ1YsSUFBSSxLQUFLLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDaEIsQ0FBQyxHQUFHLEtBQUssR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN0QyxRQUFRLEdBQUcsRUFBRSxDQUFDO1lBQ1osS0FBSyxDQUFDO2dCQUNKLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUNqQyxNQUFNO1lBQ1IsS0FBSyxDQUFDO2dCQUNKLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBQy9CLE1BQU07WUFDUjtnQkFDRSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ25DLENBQUM7SUFDSCxDQUFDO0lBQ0QsSUFBSSxDQUFDLEdBQUcsQ0FBQztRQUFFLENBQUMsSUFBSSxHQUFHLENBQUM7SUFFcEIsT0FBTyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDO0FBQ3ZDLENBQUM7QUFFRCxNQUFNLFVBQVUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQU87SUFDdkMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUNuQixNQUFNLEVBQUUsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDO0lBQ25CLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUMxQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakQsTUFBTSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFFckIsSUFBSSxHQUE2QixDQUFDO0lBQ2xDLElBQUksQ0FBQyxHQUFHLEVBQUU7UUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQ3ZCLElBQUksQ0FBQyxHQUFHLEdBQUc7UUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQzdCLElBQUksQ0FBQyxHQUFHLEdBQUc7UUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQzdCLElBQUksQ0FBQyxHQUFHLEdBQUc7UUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQzdCLElBQUksQ0FBQyxHQUFHLEdBQUc7UUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDOztRQUM3QixH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QUM7UUFDN0MsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsS0FBSyxPQUFPLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDOUYsQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbG9yU2NhbGUgfSBmcm9tICcuL3R5cGVzJztcblxuLyoqIEhTTCB0cmlwbGU6IGggaW4gWzAsMzYwKSwgcyBhbmQgbCBpbiBbMCwxMDBdLiAqL1xuZXhwb3J0IGludGVyZmFjZSBIc2wge1xuICBoOiBudW1iZXI7XG4gIHM6IG51bWJlcjtcbiAgbDogbnVtYmVyO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaGV4VG9Ic2woaGV4OiBzdHJpbmcpOiBIc2wge1xuICBjb25zdCB2YWx1ZSA9IGhleC5yZXBsYWNlKCcjJywgJycpO1xuICBjb25zdCBmdWxsID1cbiAgICB2YWx1ZS5sZW5ndGggPT09IDNcbiAgICAgID8gdmFsdWVcbiAgICAgICAgICAuc3BsaXQoJycpXG4gICAgICAgICAgLm1hcCgoYykgPT4gYyArIGMpXG4gICAgICAgICAgLmpvaW4oJycpXG4gICAgICA6IHZhbHVlO1xuICBpZiAoIS9eWzAtOWEtZkEtRl17Nn0kLy50ZXN0KGZ1bGwpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGhleCBjb2xvcjogXCIke2hleH1cImApO1xuICB9XG5cbiAgY29uc3QgciA9IHBhcnNlSW50KGZ1bGwuc2xpY2UoMCwgMiksIDE2KSAvIDI1NTtcbiAgY29uc3QgZyA9IHBhcnNlSW50KGZ1bGwuc2xpY2UoMiwgNCksIDE2KSAvIDI1NTtcbiAgY29uc3QgYiA9IHBhcnNlSW50KGZ1bGwuc2xpY2UoNCwgNiksIDE2KSAvIDI1NTtcblxuICBjb25zdCBtYXggPSBNYXRoLm1heChyLCBnLCBiKTtcbiAgY29uc3QgbWluID0gTWF0aC5taW4ociwgZywgYik7XG4gIGNvbnN0IGRlbHRhID0gbWF4IC0gbWluO1xuICBjb25zdCBsID0gKG1heCArIG1pbikgLyAyO1xuXG4gIGxldCBoID0gMDtcbiAgbGV0IHMgPSAwO1xuICBpZiAoZGVsdGEgIT09IDApIHtcbiAgICBzID0gZGVsdGEgLyAoMSAtIE1hdGguYWJzKDIgKiBsIC0gMSkpO1xuICAgIHN3aXRjaCAobWF4KSB7XG4gICAgICBjYXNlIHI6XG4gICAgICAgIGggPSA2MCAqICgoKGcgLSBiKSAvIGRlbHRhKSAlIDYpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgZzpcbiAgICAgICAgaCA9IDYwICogKChiIC0gcikgLyBkZWx0YSArIDIpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGggPSA2MCAqICgociAtIGcpIC8gZGVsdGEgKyA0KTtcbiAgICB9XG4gIH1cbiAgaWYgKGggPCAwKSBoICs9IDM2MDtcblxuICByZXR1cm4geyBoLCBzOiBzICogMTAwLCBsOiBsICogMTAwIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBoc2xUb0hleCh7IGgsIHMsIGwgfTogSHNsKTogc3RyaW5nIHtcbiAgY29uc3Qgc24gPSBzIC8gMTAwO1xuICBjb25zdCBsbiA9IGwgLyAxMDA7XG4gIGNvbnN0IGMgPSAoMSAtIE1hdGguYWJzKDIgKiBsbiAtIDEpKSAqIHNuO1xuICBjb25zdCB4ID0gYyAqICgxIC0gTWF0aC5hYnMoKChoIC8gNjApICUgMikgLSAxKSk7XG4gIGNvbnN0IG0gPSBsbiAtIGMgLyAyO1xuXG4gIGxldCByZ2I6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyXTtcbiAgaWYgKGggPCA2MCkgcmdiID0gW2MsIHgsIDBdO1xuICBlbHNlIGlmIChoIDwgMTIwKSByZ2IgPSBbeCwgYywgMF07XG4gIGVsc2UgaWYgKGggPCAxODApIHJnYiA9IFswLCBjLCB4XTtcbiAgZWxzZSBpZiAoaCA8IDI0MCkgcmdiID0gWzAsIHgsIGNdO1xuICBlbHNlIGlmIChoIDwgMzAwKSByZ2IgPSBbeCwgMCwgY107XG4gIGVsc2UgcmdiID0gW2MsIDAsIHhdO1xuXG4gIGNvbnN0IHRvSGV4ID0gKHY6IG51bWJlcikgPT5cbiAgICBNYXRoLnJvdW5kKCh2ICsgbSkgKiAyNTUpXG4gICAgICAudG9TdHJpbmcoMTYpXG4gICAgICAucGFkU3RhcnQoMiwgJzAnKTtcblxuICByZXR1cm4gYCMke3RvSGV4KHJnYlswXSl9JHt0b0hleChyZ2JbMV0pfSR7dG9IZXgocmdiWzJdKX1gLnRvVXBwZXJDYXNlKCk7XG59XG5cbi8qKiBTaGlmdCBhIGNvbG9yJ3MgbGlnaHRuZXNzIGJ5IGBkZWx0YWAgcGVyY2VudGFnZSBwb2ludHMgKGNsYW1wZWQgMOKAkzEwMCkuICovXG5leHBvcnQgZnVuY3Rpb24gc2hpZnRMaWdodG5lc3MoaGV4OiBzdHJpbmcsIGRlbHRhOiBudW1iZXIpOiBzdHJpbmcge1xuICBjb25zdCBoc2wgPSBoZXhUb0hzbChoZXgpO1xuICByZXR1cm4gaHNsVG9IZXgoeyAuLi5oc2wsIGw6IE1hdGgubWluKDEwMCwgTWF0aC5tYXgoMCwgaHNsLmwgKyBkZWx0YSkpIH0pO1xufVxuXG4vKiogUm90YXRlIGEgY29sb3IncyBodWUgYnkgYGRlZ3JlZXNgLCBrZWVwaW5nIHNhdHVyYXRpb24gYW5kIGxpZ2h0bmVzcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiByb3RhdGVIdWUoaGV4OiBzdHJpbmcsIGRlZ3JlZXM6IG51bWJlcik6IHN0cmluZyB7XG4gIGNvbnN0IGhzbCA9IGhleFRvSHNsKGhleCk7XG4gIHJldHVybiBoc2xUb0hleCh7IC4uLmhzbCwgaDogKCgoaHNsLmggKyBkZWdyZWVzKSAlIDM2MCkgKyAzNjApICUgMzYwIH0pO1xufVxuXG4vKipcbiAqIExpZ2h0bmVzcyBzdG9wcyBmb3IgZWFjaCBzY2FsZSBzdGVwLiBUdW5lZCBzbyB0aGF0IHN0ZXAgNTAwLzYwMCBzdGF5cyBjbG9zZVxuICogdG8gdHlwaWNhbCBicmFuZC1jb2xvciBsaWdodG5lc3MgYW5kIHRoZSBleHRyZW1lcyByZW1haW4gdXNhYmxlIGFzIHRpbnRlZFxuICogYmFja2dyb3VuZHMgKDUw4oCTMTAwKSBhbmQgcmVhZGFibGUgdGV4dCAoOTAw4oCTOTUwKS5cbiAqL1xuY29uc3QgTElHSFRORVNTX1NUT1BTOiBSZWNvcmQ8a2V5b2YgQ29sb3JTY2FsZSwgbnVtYmVyPiA9IHtcbiAgNTA6IDk3LFxuICAxMDA6IDk0LFxuICAyMDA6IDg3LFxuICAzMDA6IDc4LFxuICA0MDA6IDY2LFxuICA1MDA6IDU2LFxuICA2MDA6IDQ4LFxuICA3MDA6IDQwLFxuICA4MDA6IDMyLFxuICA5MDA6IDI1LFxuICA5NTA6IDE2LFxufTtcblxuLyoqXG4gKiBEZXJpdmUgYSBmdWxsIDUw4oCTOTUwIGNvbG9yIHNjYWxlIGZyb20gYSBzaW5nbGUgYnJhbmQgaGV4LlxuICpcbiAqIFRoZSBpbnB1dCBjb2xvciBrZWVwcyBpdHMgZXhhY3QgdmFsdWUgYXQgdGhlIHN0ZXAgd2hvc2UgbGlnaHRuZXNzIHN0b3AgaXNcbiAqIG5lYXJlc3QgdG8gdGhlIGlucHV0J3Mgb3duIGxpZ2h0bmVzcywgc28gYHNjYWxlW3N0ZXBdYCByb3VuZC10cmlwcyBicmFuZFxuICogY29sb3JzIGluc3RlYWQgb2Ygc2hpZnRpbmcgdGhlbS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlcml2ZVNjYWxlKGJhc2VIZXg6IHN0cmluZyk6IENvbG9yU2NhbGUge1xuICBjb25zdCBiYXNlID0gaGV4VG9Ic2woYmFzZUhleCk7XG5cbiAgbGV0IG5lYXJlc3Q6IGtleW9mIENvbG9yU2NhbGUgPSA1MDA7XG4gIGxldCBuZWFyZXN0RGVsdGEgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7XG4gIGZvciAoY29uc3QgW3N0ZXAsIHN0b3BdIG9mIE9iamVjdC5lbnRyaWVzKExJR0hUTkVTU19TVE9QUykpIHtcbiAgICBjb25zdCBkZWx0YSA9IE1hdGguYWJzKHN0b3AgLSBiYXNlLmwpO1xuICAgIGlmIChkZWx0YSA8IG5lYXJlc3REZWx0YSkge1xuICAgICAgbmVhcmVzdERlbHRhID0gZGVsdGE7XG4gICAgICBuZWFyZXN0ID0gTnVtYmVyKHN0ZXApIGFzIGtleW9mIENvbG9yU2NhbGU7XG4gICAgfVxuICB9XG5cbiAgY29uc3Qgc2NhbGUgPSB7fSBhcyBDb2xvclNjYWxlO1xuICBmb3IgKGNvbnN0IFtzdGVwLCBzdG9wXSBvZiBPYmplY3QuZW50cmllcyhMSUdIVE5FU1NfU1RPUFMpKSB7XG4gICAgY29uc3Qga2V5ID0gTnVtYmVyKHN0ZXApIGFzIGtleW9mIENvbG9yU2NhbGU7XG4gICAgc2NhbGVba2V5XSA9IGtleSA9PT0gbmVhcmVzdCA/IGhzbFRvSGV4KGJhc2UpIDogaHNsVG9IZXgoeyBoOiBiYXNlLmgsIHM6IGJhc2UucywgbDogc3RvcCB9KTtcbiAgfVxuICByZXR1cm4gc2NhbGU7XG59XG4iXX0=
112
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29sb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy90aGVtZS9zcmMvbGliL2NvbG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVNBLFNBQVMsUUFBUSxDQUFDLEdBQVc7SUFDM0IsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDbkMsTUFBTSxJQUFJLEdBQ1IsS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQ2hCLENBQUMsQ0FBQyxLQUFLO2FBQ0YsS0FBSyxDQUFDLEVBQUUsQ0FBQzthQUNULEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQzthQUNqQixJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ2IsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUNaLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUNuQyxNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixHQUFHLEdBQUcsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFFRCxNQUFNLENBQUMsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDO0lBQy9DLE1BQU0sQ0FBQyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUM7SUFDL0MsTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUMvQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztBQUNyQixDQUFDO0FBRUQsU0FBUyxZQUFZLENBQUMsQ0FBUztJQUM3QixPQUFPLENBQUMsSUFBSSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLEdBQUcsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQ3ZFLENBQUM7QUFFRCxTQUFTLFlBQVksQ0FBQyxDQUFTO0lBQzdCLE9BQU8sQ0FBQyxJQUFJLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUM7QUFDM0UsQ0FBQztBQUVELE1BQU0sVUFBVSxVQUFVLENBQUMsR0FBVztJQUNwQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDOUMsTUFBTSxDQUFDLEdBQUcsWUFBWSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzNCLE1BQU0sQ0FBQyxHQUFHLFlBQVksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMzQixNQUFNLENBQUMsR0FBRyxZQUFZLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFM0IsTUFBTSxDQUFDLEdBQUcsWUFBWSxHQUFHLENBQUMsR0FBRyxZQUFZLEdBQUcsQ0FBQyxHQUFHLFlBQVksR0FBRyxDQUFDLENBQUM7SUFDakUsTUFBTSxDQUFDLEdBQUcsWUFBWSxHQUFHLENBQUMsR0FBRyxZQUFZLEdBQUcsQ0FBQyxHQUFHLFlBQVksR0FBRyxDQUFDLENBQUM7SUFDakUsTUFBTSxDQUFDLEdBQUcsWUFBWSxHQUFHLENBQUMsR0FBRyxZQUFZLEdBQUcsQ0FBQyxHQUFHLFlBQVksR0FBRyxDQUFDLENBQUM7SUFFakUsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4QixNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFeEIsTUFBTSxDQUFDLEdBQUcsWUFBWSxHQUFHLEVBQUUsR0FBRyxXQUFXLEdBQUcsRUFBRSxHQUFHLFlBQVksR0FBRyxFQUFFLENBQUM7SUFDbkUsTUFBTSxDQUFDLEdBQUcsWUFBWSxHQUFHLEVBQUUsR0FBRyxXQUFXLEdBQUcsRUFBRSxHQUFHLFlBQVksR0FBRyxFQUFFLENBQUM7SUFDbkUsTUFBTSxFQUFFLEdBQUcsWUFBWSxHQUFHLEVBQUUsR0FBRyxZQUFZLEdBQUcsRUFBRSxHQUFHLFdBQVcsR0FBRyxFQUFFLENBQUM7SUFFcEUsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUNyQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDNUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztRQUFFLENBQUMsSUFBSSxHQUFHLENBQUM7SUFFcEIsT0FBTyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztBQUMzQixDQUFDO0FBRUQsTUFBTSxVQUFVLFVBQVUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQVM7SUFDakQsTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUNqQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM3QixNQUFNLEVBQUUsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUU5QixNQUFNLEVBQUUsR0FBRyxDQUFDLEdBQUcsWUFBWSxHQUFHLENBQUMsR0FBRyxZQUFZLEdBQUcsRUFBRSxDQUFDO0lBQ3BELE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxZQUFZLEdBQUcsQ0FBQyxHQUFHLFlBQVksR0FBRyxFQUFFLENBQUM7SUFDcEQsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLFlBQVksR0FBRyxDQUFDLEdBQUcsV0FBVyxHQUFHLEVBQUUsQ0FBQztJQUVuRCxNQUFNLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQztJQUN2QixNQUFNLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQztJQUN2QixNQUFNLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQztJQUV2QixNQUFNLENBQUMsR0FBRyxDQUFDLFlBQVksR0FBRyxDQUFDLEdBQUcsWUFBWSxHQUFHLENBQUMsR0FBRyxZQUFZLEdBQUcsQ0FBQyxDQUFDO0lBQ2xFLE1BQU0sQ0FBQyxHQUFHLENBQUMsWUFBWSxHQUFHLENBQUMsR0FBRyxZQUFZLEdBQUcsQ0FBQyxHQUFHLFlBQVksR0FBRyxDQUFDLENBQUM7SUFDbEUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEdBQUcsQ0FBQyxHQUFHLFlBQVksR0FBRyxDQUFDLEdBQUcsV0FBVyxHQUFHLENBQUMsQ0FBQztJQUVqRSxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0UsTUFBTSxRQUFR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QUFDO0lBQy9CLEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUM7UUFDM0QsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBcUIsQ0FBQztRQUM3QyxJQUFJLEdBQUcsS0FBSyxPQUFPLEVBQUUsQ0FBQztZQUNwQixLQUFLLENBQUMsR0FBRyxDQUFDLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hDLENBQUM7YUFBTSxDQUFDO1lBQ04sMEdBQTBHO1lBQzFHLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO1lBQ3RELEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxXQUFXLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2xFLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29sb3JTY2FsZSB9IGZyb20gJy4vdHlwZXMnO1xuXG4vKiogT0tMQ0ggY29sb3I6IGwgaW4gWzAsMV0sIGMgaW4gWzAsMC40XSwgaCBpbiBbMCwzNjApLiAqL1xuZXhwb3J0IGludGVyZmFjZSBPa2xjaCB7XG4gIGw6IG51bWJlcjtcbiAgYzogbnVtYmVyO1xuICBoOiBudW1iZXI7XG59XG5cbmZ1bmN0aW9uIGhleFRvUmdiKGhleDogc3RyaW5nKTogeyByOiBudW1iZXI7IGc6IG51bWJlcjsgYjogbnVtYmVyIH0ge1xuICBjb25zdCB2YWx1ZSA9IGhleC5yZXBsYWNlKCcjJywgJycpO1xuICBjb25zdCBmdWxsID1cbiAgICB2YWx1ZS5sZW5ndGggPT09IDNcbiAgICAgID8gdmFsdWVcbiAgICAgICAgICAuc3BsaXQoJycpXG4gICAgICAgICAgLm1hcCgoYykgPT4gYyArIGMpXG4gICAgICAgICAgLmpvaW4oJycpXG4gICAgICA6IHZhbHVlO1xuICBpZiAoIS9eWzAtOWEtZkEtRl17Nn0kLy50ZXN0KGZ1bGwpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGhleCBjb2xvcjogXCIke2hleH1cImApO1xuICB9XG5cbiAgY29uc3QgciA9IHBhcnNlSW50KGZ1bGwuc2xpY2UoMCwgMiksIDE2KSAvIDI1NTtcbiAgY29uc3QgZyA9IHBhcnNlSW50KGZ1bGwuc2xpY2UoMiwgNCksIDE2KSAvIDI1NTtcbiAgY29uc3QgYiA9IHBhcnNlSW50KGZ1bGwuc2xpY2UoNCwgNiksIDE2KSAvIDI1NTtcbiAgcmV0dXJuIHsgciwgZywgYiB9O1xufVxuXG5mdW5jdGlvbiBzcmdiVG9MaW5lYXIoYzogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIGMgPD0gMC4wNDA0NSA/IGMgLyAxMi45MiA6IE1hdGgucG93KChjICsgMC4wNTUpIC8gMS4wNTUsIDIuNCk7XG59XG5cbmZ1bmN0aW9uIGxpbmVhclRvU3JnYihjOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gYyA8PSAwLjAwMzEzMDggPyBjICogMTIuOTIgOiAxLjA1NSAqIE1hdGgucG93KGMsIDEgLyAyLjQpIC0gMC4wNTU7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBoZXhUb09rbGNoKGhleDogc3RyaW5nKTogT2tsY2gge1xuICBjb25zdCB7IHI6IHNyLCBnOiBzZywgYjogc2IgfSA9IGhleFRvUmdiKGhleCk7XG4gIGNvbnN0IHIgPSBzcmdiVG9MaW5lYXIoc3IpO1xuICBjb25zdCBnID0gc3JnYlRvTGluZWFyKHNnKTtcbiAgY29uc3QgYiA9IHNyZ2JUb0xpbmVhcihzYik7XG5cbiAgY29uc3QgbCA9IDAuNDEyMjIxNDcwOCAqIHIgKyAwLjUzNjMzMjUzNjMgKiBnICsgMC4wNTE0NDU5OTI5ICogYjtcbiAgY29uc3QgbSA9IDAuMjExOTAzNDk4MiAqIHIgKyAwLjY4MDY5OTU0NTEgKiBnICsgMC4xMDczOTY5NTY2ICogYjtcbiAgY29uc3QgcyA9IDAuMDg4MzAyNDYxOSAqIHIgKyAwLjI4MTcxODgzNzYgKiBnICsgMC42Mjk5Nzg3MDA1ICogYjtcblxuICBjb25zdCBsXyA9IE1hdGguY2JydChsKTtcbiAgY29uc3QgbV8gPSBNYXRoLmNicnQobSk7XG4gIGNvbnN0IHNfID0gTWF0aC5jYnJ0KHMpO1xuXG4gIGNvbnN0IEwgPSAwLjIxMDQ1NDI1NTMgKiBsXyArIDAuNzkzNjE3Nzg1ICogbV8gLSAwLjAwNDA3MjA0NjggKiBzXztcbiAgY29uc3QgYSA9IDEuOTc3OTk4NDk1MSAqIGxfIC0gMi40Mjg1OTIyMDUgKiBtXyArIDAuNDUwNTkzNzA5OSAqIHNfO1xuICBjb25zdCBiXyA9IDAuMDI1OTA0MDM3MSAqIGxfICsgMC43ODI3NzE3NjYyICogbV8gLSAwLjgwODY3NTc2NiAqIHNfO1xuXG4gIGNvbnN0IEMgPSBNYXRoLnNxcnQoYSAqIGEgKyBiXyAqIGJfKTtcbiAgbGV0IGggPSAoTWF0aC5hdGFuMihiXywgYSkgKiAxODApIC8gTWF0aC5QSTtcbiAgaWYgKGggPCAwKSBoICs9IDM2MDtcblxuICByZXR1cm4geyBsOiBMLCBjOiBDLCBoIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBva2xjaFRvSGV4KHsgbDogTCwgYzogQywgaCB9OiBPa2xjaCk6IHN0cmluZyB7XG4gIGNvbnN0IGhSYWQgPSAoaCAqIE1hdGguUEkpIC8gMTgwO1xuICBjb25zdCBhID0gQyAqIE1hdGguY29zKGhSYWQpO1xuICBjb25zdCBiXyA9IEMgKiBNYXRoLnNpbihoUmFkKTtcblxuICBjb25zdCBsXyA9IEwgKyAwLjM5NjMzNzc3NzQgKiBhICsgMC4yMTU4MDM3NTczICogYl87XG4gIGNvbnN0IG1fID0gTCAtIDAuMTA1NTYxMzQ1OCAqIGEgLSAwLjA2Mzg1NDE3MjggKiBiXztcbiAgY29uc3Qgc18gPSBMIC0gMC4wODk0ODQxNzc1ICogYSAtIDEuMjkxNDg1NTQ4ICogYl87XG5cbiAgY29uc3QgbCA9IGxfICogbF8gKiBsXztcbiAgY29uc3QgbSA9IG1fICogbV8gKiBtXztcbiAgY29uc3QgcyA9IHNfICogc18gKiBzXztcblxuICBjb25zdCByID0gKzQuMDc2NzQxNjYyMSAqIGwgLSAzLjMwNzcxMTU5MTMgKiBtICsgMC4yMzA5Njk5MjkyICogcztcbiAgY29uc3QgZyA9IC0xLjI2ODQzODAwNDYgKiBsICsgMi42MDk3NTc0MDExICogbSAtIDAuMzQxMzE5Mzk2NSAqIHM7XG4gIGNvbnN0IGIgPSAtMC4wMDQxOTYwODYzICogbCAtIDAuNzAzNDE4NjE0OCAqIG0gKyAxLjcwNzYxNDcwMSAqIHM7XG5cbiAgY29uc3QgckNsYW1wZWQgPSBNYXRoLm1pbigyNTUsIE1hdGgubWF4KDAsIE1hdGgucm91bmQobGluZWFyVG9TcmdiKHIpICogMjU1KSkpO1xuICBjb25zdCBnQ2xhbXBlZCA9IE1hdGgubWluKDI1NSwgTWF0aC5tYXgoMCwgTWF0aC5yb3VuZChsaW5lYXJUb1NyZ2IoZykgKiAyNTUpKSk7XG4gIGNvbnN0IGJDbGFtcGVkID0gTWF0aC5taW4oMjU1LCBNYXRoLm1heCgwLCBNYXRoLnJvdW5kKGxpbmVhclRvU3JnYihiKSAqIDI1NSkpKTtcblxuICBjb25zdCB0b0hleCA9ICh2OiBudW1iZXIpID0+IHYudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsICcwJyk7XG4gIHJldHVybiBgIyR7dG9IZXgockNsYW1wZWQpfSR7dG9IZXgoZ0NsYW1wZWQpfSR7dG9IZXgoYkNsYW1wZWQpfWAudG9VcHBlckNhc2UoKTtcbn1cblxuLyoqIFNoaWZ0IGEgY29sb3IncyBsaWdodG5lc3MgYnkgYGRlbHRhYCAoY2xhbXBlZCAw4oCTMSkuICovXG5leHBvcnQgZnVuY3Rpb24gc2hpZnRMaWdodG5lc3MoaGV4OiBzdHJpbmcsIGRlbHRhOiBudW1iZXIpOiBzdHJpbmcge1xuICBjb25zdCBva2xjaCA9IGhleFRvT2tsY2goaGV4KTtcbiAgcmV0dXJuIG9rbGNoVG9IZXgoeyAuLi5va2xjaCwgbDogTWF0aC5taW4oMS4wLCBNYXRoLm1heCgwLjAsIG9rbGNoLmwgKyBkZWx0YSkpIH0pO1xufVxuXG4vKiogUm90YXRlIGEgY29sb3IncyBodWUgYnkgYGRlZ3JlZXNgLCBrZWVwaW5nIGNocm9tYSBhbmQgbGlnaHRuZXNzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJvdGF0ZUh1ZShoZXg6IHN0cmluZywgZGVncmVlczogbnVtYmVyKTogc3RyaW5nIHtcbiAgY29uc3Qgb2tsY2ggPSBoZXhUb09rbGNoKGhleCk7XG4gIHJldHVybiBva2xjaFRvSGV4KHsgLi4ub2tsY2gsIGg6ICgoKG9rbGNoLmggKyBkZWdyZWVzKSAlIDM2MCkgKyAzNjApICUgMzYwIH0pO1xufVxuXG4vKiogTGlnaHRuZXNzIHN0b3BzIGZvciBlYWNoIHNjYWxlIHN0ZXAgaW4gT0tMQ0ggKDDigJMxKS4gKi9cbmNvbnN0IExJR0hUTkVTU19TVE9QUzogUmVjb3JkPGtleW9mIENvbG9yU2NhbGUsIG51bWJlcj4gPSB7XG4gIDUwOiAwLjk3LFxuICAxMDA6IDAuOTQsXG4gIDIwMDogMC44NyxcbiAgMzAwOiAwLjc4LFxuICA0MDA6IDAuNjYsXG4gIDUwMDogMC41NixcbiAgNjAwOiAwLjQ4LFxuICA3MDA6IDAuNCxcbiAgODAwOiAwLjMyLFxuICA5MDA6IDAuMjUsXG4gIDk1MDogMC4xNixcbn07XG5cbi8qKiBEZXJpdmUgYSBmdWxsIDUw4oCTOTUwIGNvbG9yIHNjYWxlIGZyb20gYSBzaW5nbGUgYnJhbmQgaGV4LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlcml2ZVNjYWxlKGJhc2VIZXg6IHN0cmluZyk6IENvbG9yU2NhbGUge1xuICBjb25zdCBiYXNlID0gaGV4VG9Pa2xjaChiYXNlSGV4KTtcblxuICBsZXQgbmVhcmVzdDoga2V5b2YgQ29sb3JTY2FsZSA9IDUwMDtcbiAgbGV0IG5lYXJlc3REZWx0YSA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTtcbiAgZm9yIChjb25zdCBbc3RlcCwgc3RvcF0gb2YgT2JqZWN0LmVudHJpZXMoTElHSFRORVNTX1NUT1BTKSkge1xuICAgIGNvbnN0IGRlbHRhID0gTWF0aC5hYnMoc3RvcCAtIGJhc2UubCk7XG4gICAgaWYgKGRlbHRhIDwgbmVhcmVzdERlbHRhKSB7XG4gICAgICBuZWFyZXN0RGVsdGEgPSBkZWx0YTtcbiAgICAgIG5lYXJlc3QgPSBOdW1iZXIoc3RlcCkgYXMga2V5b2YgQ29sb3JTY2FsZTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBzY2FsZSA9IHt9IGFzIENvbG9yU2NhbGU7XG4gIGZvciAoY29uc3QgW3N0ZXAsIHN0b3BdIG9mIE9iamVjdC5lbnRyaWVzKExJR0hUTkVTU19TVE9QUykpIHtcbiAgICBjb25zdCBrZXkgPSBOdW1iZXIoc3RlcCkgYXMga2V5b2YgQ29sb3JTY2FsZTtcbiAgICBpZiAoa2V5ID09PSBuZWFyZXN0KSB7XG4gICAgICBzY2FsZVtrZXldID0gb2tsY2hUb0hleChiYXNlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUGVyY2VwdHVhbGx5IHNjYWxlIGNocm9tYSB1c2luZyBhIHNpbmUgdGFwZXIgc28gdGhhdCBleHRyZW1lcyAoNTAvOTUwKSBkb24ndCBjbGlwL3NhdHVyYXRlIHVubmF0dXJhbGx5LlxuICAgICAgY29uc3Qgc2NhbGVDaHJvbWEgPSBiYXNlLmMgKiBNYXRoLnNpbihNYXRoLlBJICogc3RvcCk7XG4gICAgICBzY2FsZVtrZXldID0gb2tsY2hUb0hleCh7IGw6IHN0b3AsIGM6IHNjYWxlQ2hyb21hLCBoOiBiYXNlLmggfSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBzY2FsZTtcbn1cbiJdfQ==
@@ -10,7 +10,7 @@ import { inject, signal, computed, effect, Injectable } from '@angular/core';
10
10
  * SCSS/Tailwind/JSON exporters build on the same model).
11
11
  */
12
12
 
13
- function hexToHsl(hex) {
13
+ function hexToRgb(hex) {
14
14
  const value = hex.replace('#', '');
15
15
  const full = value.length === 3
16
16
  ? value
@@ -24,90 +24,80 @@ function hexToHsl(hex) {
24
24
  const r = parseInt(full.slice(0, 2), 16) / 255;
25
25
  const g = parseInt(full.slice(2, 4), 16) / 255;
26
26
  const b = parseInt(full.slice(4, 6), 16) / 255;
27
- const max = Math.max(r, g, b);
28
- const min = Math.min(r, g, b);
29
- const delta = max - min;
30
- const l = (max + min) / 2;
31
- let h = 0;
32
- let s = 0;
33
- if (delta !== 0) {
34
- s = delta / (1 - Math.abs(2 * l - 1));
35
- switch (max) {
36
- case r:
37
- h = 60 * (((g - b) / delta) % 6);
38
- break;
39
- case g:
40
- h = 60 * ((b - r) / delta + 2);
41
- break;
42
- default:
43
- h = 60 * ((r - g) / delta + 4);
44
- }
45
- }
27
+ return { r, g, b };
28
+ }
29
+ function srgbToLinear(c) {
30
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
31
+ }
32
+ function linearToSrgb(c) {
33
+ return c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
34
+ }
35
+ function hexToOklch(hex) {
36
+ const { r: sr, g: sg, b: sb } = hexToRgb(hex);
37
+ const r = srgbToLinear(sr);
38
+ const g = srgbToLinear(sg);
39
+ const b = srgbToLinear(sb);
40
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
41
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
42
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
43
+ const l_ = Math.cbrt(l);
44
+ const m_ = Math.cbrt(m);
45
+ const s_ = Math.cbrt(s);
46
+ const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
47
+ const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
48
+ const b_ = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
49
+ const C = Math.sqrt(a * a + b_ * b_);
50
+ let h = (Math.atan2(b_, a) * 180) / Math.PI;
46
51
  if (h < 0)
47
52
  h += 360;
48
- return { h, s: s * 100, l: l * 100 };
53
+ return { l: L, c: C, h };
49
54
  }
50
- function hslToHex({ h, s, l }) {
51
- const sn = s / 100;
52
- const ln = l / 100;
53
- const c = (1 - Math.abs(2 * ln - 1)) * sn;
54
- const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
55
- const m = ln - c / 2;
56
- let rgb;
57
- if (h < 60)
58
- rgb = [c, x, 0];
59
- else if (h < 120)
60
- rgb = [x, c, 0];
61
- else if (h < 180)
62
- rgb = [0, c, x];
63
- else if (h < 240)
64
- rgb = [0, x, c];
65
- else if (h < 300)
66
- rgb = [x, 0, c];
67
- else
68
- rgb = [c, 0, x];
69
- const toHex = (v) => Math.round((v + m) * 255)
70
- .toString(16)
71
- .padStart(2, '0');
72
- return `#${toHex(rgb[0])}${toHex(rgb[1])}${toHex(rgb[2])}`.toUpperCase();
55
+ function oklchToHex({ l: L, c: C, h }) {
56
+ const hRad = (h * Math.PI) / 180;
57
+ const a = C * Math.cos(hRad);
58
+ const b_ = C * Math.sin(hRad);
59
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * b_;
60
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * b_;
61
+ const s_ = L - 0.0894841775 * a - 1.291485548 * b_;
62
+ const l = l_ * l_ * l_;
63
+ const m = m_ * m_ * m_;
64
+ const s = s_ * s_ * s_;
65
+ const r = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
66
+ const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
67
+ const b = -0.0041960863 * l - 0.7034186148 * m + 1.707614701 * s;
68
+ const rClamped = Math.min(255, Math.max(0, Math.round(linearToSrgb(r) * 255)));
69
+ const gClamped = Math.min(255, Math.max(0, Math.round(linearToSrgb(g) * 255)));
70
+ const bClamped = Math.min(255, Math.max(0, Math.round(linearToSrgb(b) * 255)));
71
+ const toHex = (v) => v.toString(16).padStart(2, '0');
72
+ return `#${toHex(rClamped)}${toHex(gClamped)}${toHex(bClamped)}`.toUpperCase();
73
73
  }
74
- /** Shift a color's lightness by `delta` percentage points (clamped 0–100). */
74
+ /** Shift a color's lightness by `delta` (clamped 0–1). */
75
75
  function shiftLightness(hex, delta) {
76
- const hsl = hexToHsl(hex);
77
- return hslToHex({ ...hsl, l: Math.min(100, Math.max(0, hsl.l + delta)) });
76
+ const oklch = hexToOklch(hex);
77
+ return oklchToHex({ ...oklch, l: Math.min(1.0, Math.max(0.0, oklch.l + delta)) });
78
78
  }
79
- /** Rotate a color's hue by `degrees`, keeping saturation and lightness. */
79
+ /** Rotate a color's hue by `degrees`, keeping chroma and lightness. */
80
80
  function rotateHue(hex, degrees) {
81
- const hsl = hexToHsl(hex);
82
- return hslToHex({ ...hsl, h: (((hsl.h + degrees) % 360) + 360) % 360 });
81
+ const oklch = hexToOklch(hex);
82
+ return oklchToHex({ ...oklch, h: (((oklch.h + degrees) % 360) + 360) % 360 });
83
83
  }
84
- /**
85
- * Lightness stops for each scale step. Tuned so that step 500/600 stays close
86
- * to typical brand-color lightness and the extremes remain usable as tinted
87
- * backgrounds (50–100) and readable text (900–950).
88
- */
84
+ /** Lightness stops for each scale step in OKLCH (0–1). */
89
85
  const LIGHTNESS_STOPS = {
90
- 50: 97,
91
- 100: 94,
92
- 200: 87,
93
- 300: 78,
94
- 400: 66,
95
- 500: 56,
96
- 600: 48,
97
- 700: 40,
98
- 800: 32,
99
- 900: 25,
100
- 950: 16,
86
+ 50: 0.97,
87
+ 100: 0.94,
88
+ 200: 0.87,
89
+ 300: 0.78,
90
+ 400: 0.66,
91
+ 500: 0.56,
92
+ 600: 0.48,
93
+ 700: 0.4,
94
+ 800: 0.32,
95
+ 900: 0.25,
96
+ 950: 0.16,
101
97
  };
102
- /**
103
- * Derive a full 50–950 color scale from a single brand hex.
104
- *
105
- * The input color keeps its exact value at the step whose lightness stop is
106
- * nearest to the input's own lightness, so `scale[step]` round-trips brand
107
- * colors instead of shifting them.
108
- */
98
+ /** Derive a full 50–950 color scale from a single brand hex. */
109
99
  function deriveScale(baseHex) {
110
- const base = hexToHsl(baseHex);
100
+ const base = hexToOklch(baseHex);
111
101
  let nearest = 500;
112
102
  let nearestDelta = Number.POSITIVE_INFINITY;
113
103
  for (const [step, stop] of Object.entries(LIGHTNESS_STOPS)) {
@@ -120,7 +110,14 @@ function deriveScale(baseHex) {
120
110
  const scale = {};
121
111
  for (const [step, stop] of Object.entries(LIGHTNESS_STOPS)) {
122
112
  const key = Number(step);
123
- scale[key] = key === nearest ? hslToHex(base) : hslToHex({ h: base.h, s: base.s, l: stop });
113
+ if (key === nearest) {
114
+ scale[key] = oklchToHex(base);
115
+ }
116
+ else {
117
+ // Perceptually scale chroma using a sine taper so that extremes (50/950) don't clip/saturate unnaturally.
118
+ const scaleChroma = base.c * Math.sin(Math.PI * stop);
119
+ scale[key] = oklchToHex({ l: stop, c: scaleChroma, h: base.h });
120
+ }
124
121
  }
125
122
  return scale;
126
123
  }
@@ -745,5 +742,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.0", ngImpor
745
742
  * Generated bundle index. Do not edit.
746
743
  */
747
744
 
748
- export { CONTROL_HEIGHT, CONTROL_HEIGHTS, DEFAULT_FONT_FAMILY, DEFAULT_NEUTRAL, DEFAULT_SEMANTIC, DEFAULT_TYPOGRAPHY, DURATION, EASING, ICON_SIZE, NgxsmkThemeService, OPACITY, RADIUS, SHADOW, SPACING, TRACKING, Z_INDEX, buildThemeCss, defineConfig, deriveScale, emeraldPreset, hexToHsl, hslToHex, neutralPreset, presets, resolveTheme, rosePreset, rotateHue, shiftLightness, violetPreset };
745
+ export { CONTROL_HEIGHT, CONTROL_HEIGHTS, DEFAULT_FONT_FAMILY, DEFAULT_NEUTRAL, DEFAULT_SEMANTIC, DEFAULT_TYPOGRAPHY, DURATION, EASING, ICON_SIZE, NgxsmkThemeService, OPACITY, RADIUS, SHADOW, SPACING, TRACKING, Z_INDEX, buildThemeCss, defineConfig, deriveScale, emeraldPreset, hexToOklch, neutralPreset, oklchToHex, presets, resolveTheme, rosePreset, rotateHue, shiftLightness, violetPreset };
749
746
  //# sourceMappingURL=ngxsmk-theme.mjs.map