@tenphi/glaze 0.0.0-snapshot.e76f494 → 0.0.0-snapshot.e941371
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 +51 -19
- package/dist/index.cjs +76 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -21
- package/dist/index.d.mts +47 -21
- package/dist/index.mjs +76 -74
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,8 +71,8 @@ const success = primary.extend({ hue: 157 });
|
|
|
71
71
|
|
|
72
72
|
// Compose into a palette and export
|
|
73
73
|
const palette = glaze.palette({ primary, danger, success });
|
|
74
|
-
const tokens = palette.tokens({
|
|
75
|
-
// → { light: { 'primary-surface': 'okhsl(...)',
|
|
74
|
+
const tokens = palette.tokens({ primary: 'primary' });
|
|
75
|
+
// → { light: { 'primary-surface': 'okhsl(...)', 'surface': 'okhsl(...)', ... }, dark: { ... } }
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
## Core Concepts
|
|
@@ -618,7 +618,7 @@ Modes control how colors adapt across schemes:
|
|
|
618
618
|
|
|
619
619
|
### Lightness
|
|
620
620
|
|
|
621
|
-
|
|
621
|
+
Absolute lightness values (both root colors and dependent colors with absolute lightness) are mapped linearly within the configured `lightLightness` window:
|
|
622
622
|
|
|
623
623
|
```ts
|
|
624
624
|
const [lo, hi] = lightLightness; // default: [10, 100]
|
|
@@ -694,12 +694,12 @@ Combine multiple themes into a single palette:
|
|
|
694
694
|
const palette = glaze.palette({ primary, danger, success, warning });
|
|
695
695
|
```
|
|
696
696
|
|
|
697
|
-
###
|
|
697
|
+
### Prefix Behavior
|
|
698
698
|
|
|
699
|
-
|
|
699
|
+
Palette export methods (`tokens()`, `tasty()`, `css()`) default to `prefix: true` — all tokens are automatically prefixed with the theme name to avoid collisions:
|
|
700
700
|
|
|
701
701
|
```ts
|
|
702
|
-
const tokens = palette.tokens(
|
|
702
|
+
const tokens = palette.tokens();
|
|
703
703
|
// → {
|
|
704
704
|
// light: { 'primary-surface': 'okhsl(...)', 'danger-surface': 'okhsl(...)' },
|
|
705
705
|
// dark: { 'primary-surface': 'okhsl(...)', 'danger-surface': 'okhsl(...)' },
|
|
@@ -712,15 +712,44 @@ Custom prefix mapping:
|
|
|
712
712
|
palette.tokens({ prefix: { primary: 'brand-', danger: 'error-' } });
|
|
713
713
|
```
|
|
714
714
|
|
|
715
|
+
To disable prefixing entirely, pass `prefix: false` explicitly. Note that tokens with the same name will overwrite each other (last theme wins).
|
|
716
|
+
|
|
717
|
+
### Primary Theme
|
|
718
|
+
|
|
719
|
+
Use the `primary` option to designate one theme as the primary. Its tokens are duplicated without prefix, providing convenient short aliases alongside the prefixed versions:
|
|
720
|
+
|
|
721
|
+
```ts
|
|
722
|
+
const palette = glaze.palette({ primary, danger, success });
|
|
723
|
+
const tokens = palette.tokens({ primary: 'primary' });
|
|
724
|
+
// → {
|
|
725
|
+
// light: {
|
|
726
|
+
// 'primary-surface': 'okhsl(...)', // prefixed (all themes)
|
|
727
|
+
// 'danger-surface': 'okhsl(...)',
|
|
728
|
+
// 'success-surface': 'okhsl(...)',
|
|
729
|
+
// 'surface': 'okhsl(...)', // unprefixed alias (primary only)
|
|
730
|
+
// },
|
|
731
|
+
// }
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
The `primary` option works on `tokens()`, `tasty()`, and `css()`. It combines with any prefix mode — when using a custom prefix map, primary tokens are still duplicated without prefix:
|
|
735
|
+
|
|
736
|
+
```ts
|
|
737
|
+
palette.tokens({ prefix: { primary: 'p-', danger: 'd-' }, primary: 'primary' });
|
|
738
|
+
// → 'p-surface' + 'surface' (alias) + 'd-surface'
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
An error is thrown if the primary name doesn't match any theme in the palette.
|
|
742
|
+
|
|
715
743
|
### Tasty Export (for [Tasty](https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs) style system)
|
|
716
744
|
|
|
717
745
|
The `tasty()` method exports tokens in the [Tasty](https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs) style-to-state binding format — `#name` color token keys with state aliases (`''`, `@dark`, etc.):
|
|
718
746
|
|
|
719
747
|
```ts
|
|
720
|
-
const tastyTokens = palette.tasty({
|
|
748
|
+
const tastyTokens = palette.tasty({ primary: 'primary' });
|
|
721
749
|
// → {
|
|
722
750
|
// '#primary-surface': { '': 'okhsl(...)', '@dark': 'okhsl(...)' },
|
|
723
751
|
// '#danger-surface': { '': 'okhsl(...)', '@dark': 'okhsl(...)' },
|
|
752
|
+
// '#surface': { '': 'okhsl(...)', '@dark': 'okhsl(...)' }, // alias
|
|
724
753
|
// }
|
|
725
754
|
```
|
|
726
755
|
|
|
@@ -787,8 +816,10 @@ palette.tasty({ states: { dark: '@dark', highContrast: '@hc' } });
|
|
|
787
816
|
|
|
788
817
|
### JSON Export (Framework-Agnostic)
|
|
789
818
|
|
|
819
|
+
JSON export groups by theme name (no prefix needed):
|
|
820
|
+
|
|
790
821
|
```ts
|
|
791
|
-
const data = palette.json(
|
|
822
|
+
const data = palette.json();
|
|
792
823
|
// → {
|
|
793
824
|
// primary: { surface: { light: 'okhsl(...)', dark: 'okhsl(...)' } },
|
|
794
825
|
// danger: { surface: { light: 'okhsl(...)', dark: 'okhsl(...)' } },
|
|
@@ -810,7 +841,7 @@ const css = theme.css();
|
|
|
810
841
|
Use in a stylesheet:
|
|
811
842
|
|
|
812
843
|
```ts
|
|
813
|
-
const css = palette.css({
|
|
844
|
+
const css = palette.css({ primary: 'primary' });
|
|
814
845
|
|
|
815
846
|
const stylesheet = `
|
|
816
847
|
:root { ${css.light} }
|
|
@@ -826,7 +857,8 @@ Options:
|
|
|
826
857
|
|---|---|---|
|
|
827
858
|
| `format` | `'rgb'` | Color format (`'rgb'`, `'hsl'`, `'okhsl'`, `'oklch'`) |
|
|
828
859
|
| `suffix` | `'-color'` | Suffix appended to each CSS property name |
|
|
829
|
-
| `prefix` |
|
|
860
|
+
| `prefix` | `true` (palette) | (palette only) `true` uses `"<themeName>-"`, or provide a custom map |
|
|
861
|
+
| `primary` | — | (palette only) Theme name to duplicate without prefix |
|
|
830
862
|
|
|
831
863
|
```ts
|
|
832
864
|
// Custom suffix
|
|
@@ -837,9 +869,9 @@ theme.css({ suffix: '' });
|
|
|
837
869
|
theme.css({ format: 'hsl' });
|
|
838
870
|
// → "--surface-color: hsl(...);"
|
|
839
871
|
|
|
840
|
-
// Palette with
|
|
841
|
-
palette.css({
|
|
842
|
-
// → "--primary-surface-color: rgb(...);\n--danger-surface-color: rgb(...);"
|
|
872
|
+
// Palette with primary
|
|
873
|
+
palette.css({ primary: 'primary' });
|
|
874
|
+
// → "--primary-surface-color: rgb(...);\n--surface-color: rgb(...);\n--danger-surface-color: rgb(...);"
|
|
843
875
|
```
|
|
844
876
|
|
|
845
877
|
## Output Modes
|
|
@@ -1011,16 +1043,16 @@ const note = primary.extend({ hue: 302 });
|
|
|
1011
1043
|
|
|
1012
1044
|
const palette = glaze.palette({ primary, danger, success, warning, note });
|
|
1013
1045
|
|
|
1014
|
-
// Export as flat token map grouped by variant
|
|
1015
|
-
const tokens = palette.tokens({
|
|
1016
|
-
// tokens.light → { 'primary-surface': '
|
|
1046
|
+
// Export as flat token map grouped by variant (prefix defaults to true)
|
|
1047
|
+
const tokens = palette.tokens({ primary: 'primary' });
|
|
1048
|
+
// tokens.light → { 'primary-surface': '...', 'surface': '...', 'danger-surface': '...' }
|
|
1017
1049
|
|
|
1018
1050
|
// Export as tasty style-to-state bindings (for Tasty style system)
|
|
1019
|
-
const tastyTokens = palette.tasty({
|
|
1051
|
+
const tastyTokens = palette.tasty({ primary: 'primary' });
|
|
1020
1052
|
|
|
1021
1053
|
// Export as CSS custom properties (rgb format by default)
|
|
1022
|
-
const css = palette.css({
|
|
1023
|
-
// css.light → "--primary-surface-color: rgb(...);\n--
|
|
1054
|
+
const css = palette.css({ primary: 'primary' });
|
|
1055
|
+
// css.light → "--primary-surface-color: rgb(...);\n--surface-color: rgb(...);\n--danger-surface-color: rgb(...);"
|
|
1024
1056
|
|
|
1025
1057
|
// Standalone shadow computation
|
|
1026
1058
|
const v = glaze.shadow({ bg: '#f0eef5', fg: '#1a1a2e', intensity: 10 });
|
package/dist/index.cjs
CHANGED
|
@@ -81,8 +81,8 @@ const OKLab_to_linear_sRGB_coefficients = [
|
|
|
81
81
|
.73956515,
|
|
82
82
|
-.45954404,
|
|
83
83
|
.08285427,
|
|
84
|
-
.
|
|
85
|
-
|
|
84
|
+
.1254107,
|
|
85
|
+
.14503204
|
|
86
86
|
]],
|
|
87
87
|
[[.13110757611180954, 1.813339709266608], [
|
|
88
88
|
1.35733652,
|
|
@@ -254,10 +254,9 @@ const getCs = (L, a, b, cusp) => {
|
|
|
254
254
|
];
|
|
255
255
|
};
|
|
256
256
|
/**
|
|
257
|
-
* Convert OKHSL (h: 0–360, s: 0–1, l: 0–1) to
|
|
258
|
-
* Channels may exceed [0, 1] near gamut boundaries — caller must clamp if needed.
|
|
257
|
+
* Convert OKHSL (h: 0–360, s: 0–1, l: 0–1) to OKLab [L, a, b].
|
|
259
258
|
*/
|
|
260
|
-
function
|
|
259
|
+
function okhslToOklab(h, s, l) {
|
|
261
260
|
const L = toeInv(l);
|
|
262
261
|
let a = 0;
|
|
263
262
|
let b = 0;
|
|
@@ -284,11 +283,18 @@ function okhslToLinearSrgb(h, s, l) {
|
|
|
284
283
|
a = c * a_;
|
|
285
284
|
b = c * b_;
|
|
286
285
|
}
|
|
287
|
-
return
|
|
286
|
+
return [
|
|
288
287
|
L,
|
|
289
288
|
a,
|
|
290
289
|
b
|
|
291
|
-
]
|
|
290
|
+
];
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Convert OKHSL (h: 0–360, s: 0–1, l: 0–1) to linear sRGB.
|
|
294
|
+
* Channels may exceed [0, 1] near gamut boundaries — caller must clamp if needed.
|
|
295
|
+
*/
|
|
296
|
+
function okhslToLinearSrgb(h, s, l) {
|
|
297
|
+
return OKLabToLinearSRGB(okhslToOklab(h, s, l));
|
|
292
298
|
}
|
|
293
299
|
/**
|
|
294
300
|
* Compute relative luminance Y from linear sRGB channels.
|
|
@@ -327,40 +333,15 @@ function okhslToSrgb(h, s, l) {
|
|
|
327
333
|
];
|
|
328
334
|
}
|
|
329
335
|
/**
|
|
330
|
-
*
|
|
336
|
+
* Compute WCAG 2 relative luminance from linear sRGB, matching the browser
|
|
337
|
+
* rendering pipeline: gamma-encode, clamp to sRGB gamut [0,1], then linearize.
|
|
338
|
+
* This avoids over/under-estimating luminance for out-of-gamut OKHSL colors.
|
|
331
339
|
*/
|
|
332
|
-
function
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (L !== 0 && L !== 1 && s !== 0) {
|
|
338
|
-
const a_ = Math.cos(TAU * hNorm);
|
|
339
|
-
const b_ = Math.sin(TAU * hNorm);
|
|
340
|
-
const [c0, cMid, cMax] = getCs(L, a_, b_, findCuspOKLCH(a_, b_));
|
|
341
|
-
const mid = .8;
|
|
342
|
-
const midInv = 1.25;
|
|
343
|
-
let t, k0, k1, k2;
|
|
344
|
-
if (s < mid) {
|
|
345
|
-
t = midInv * s;
|
|
346
|
-
k0 = 0;
|
|
347
|
-
k1 = mid * c0;
|
|
348
|
-
k2 = 1 - k1 / cMid;
|
|
349
|
-
} else {
|
|
350
|
-
t = 5 * (s - .8);
|
|
351
|
-
k0 = cMid;
|
|
352
|
-
k1 = .2 * cMid ** 2 * 1.25 ** 2 / c0;
|
|
353
|
-
k2 = 1 - k1 / (cMax - cMid);
|
|
354
|
-
}
|
|
355
|
-
const c = k0 + t * k1 / (1 - k2 * t);
|
|
356
|
-
a = c * a_;
|
|
357
|
-
b = c * b_;
|
|
358
|
-
}
|
|
359
|
-
return [
|
|
360
|
-
L,
|
|
361
|
-
a,
|
|
362
|
-
b
|
|
363
|
-
];
|
|
340
|
+
function gamutClampedLuminance(linearRgb) {
|
|
341
|
+
const r = sRGBGammaToLinear(Math.max(0, Math.min(1, sRGBLinearToGamma(linearRgb[0]))));
|
|
342
|
+
const g = sRGBGammaToLinear(Math.max(0, Math.min(1, sRGBLinearToGamma(linearRgb[1]))));
|
|
343
|
+
const b = sRGBGammaToLinear(Math.max(0, Math.min(1, sRGBLinearToGamma(linearRgb[2]))));
|
|
344
|
+
return .2126 * r + .7152 * g + .0722 * b;
|
|
364
345
|
}
|
|
365
346
|
const linearSrgbToOklab = (rgb) => {
|
|
366
347
|
return transform(cbrt3(transform(rgb, linear_sRGB_to_LMS_M)), LMS_to_OKLab_M);
|
|
@@ -452,12 +433,13 @@ function formatOkhsl(h, s, l) {
|
|
|
452
433
|
return `okhsl(${fmt$1(h, 2)} ${fmt$1(s, 2)}% ${fmt$1(l, 2)}%)`;
|
|
453
434
|
}
|
|
454
435
|
/**
|
|
455
|
-
* Format OKHSL values as a CSS `rgb(R G B)` string
|
|
436
|
+
* Format OKHSL values as a CSS `rgb(R G B)` string.
|
|
437
|
+
* Uses 2 decimal places to avoid 8-bit quantization contrast loss.
|
|
456
438
|
* h: 0–360, s: 0–100, l: 0–100 (percentage scale for s and l).
|
|
457
439
|
*/
|
|
458
440
|
function formatRgb(h, s, l) {
|
|
459
441
|
const [r, g, b] = okhslToSrgb(h, s / 100, l / 100);
|
|
460
|
-
return `rgb(${
|
|
442
|
+
return `rgb(${parseFloat((r * 255).toFixed(2))} ${parseFloat((g * 255).toFixed(2))} ${parseFloat((b * 255).toFixed(2))})`;
|
|
461
443
|
}
|
|
462
444
|
/**
|
|
463
445
|
* Format OKHSL values as a CSS `hsl(H S% L%)` string.
|
|
@@ -513,23 +495,12 @@ function resolveMinContrast(value) {
|
|
|
513
495
|
const CACHE_SIZE = 512;
|
|
514
496
|
const luminanceCache = /* @__PURE__ */ new Map();
|
|
515
497
|
const cacheOrder = [];
|
|
516
|
-
/**
|
|
517
|
-
* Compute WCAG 2 relative luminance from linear sRGB, matching the browser
|
|
518
|
-
* rendering pipeline: gamma-encode, clamp to sRGB gamut [0,1], then linearize.
|
|
519
|
-
* This avoids over/under-estimating luminance for out-of-gamut OKHSL colors.
|
|
520
|
-
*/
|
|
521
|
-
function gamutClampedLuminance$1(linearRgb) {
|
|
522
|
-
const r = sRGBGammaToLinear(Math.max(0, Math.min(1, sRGBLinearToGamma(linearRgb[0]))));
|
|
523
|
-
const g = sRGBGammaToLinear(Math.max(0, Math.min(1, sRGBLinearToGamma(linearRgb[1]))));
|
|
524
|
-
const b = sRGBGammaToLinear(Math.max(0, Math.min(1, sRGBLinearToGamma(linearRgb[2]))));
|
|
525
|
-
return .2126 * r + .7152 * g + .0722 * b;
|
|
526
|
-
}
|
|
527
498
|
function cachedLuminance(h, s, l) {
|
|
528
499
|
const lRounded = Math.round(l * 1e4) / 1e4;
|
|
529
500
|
const key = `${h}|${s}|${lRounded}`;
|
|
530
501
|
const cached = luminanceCache.get(key);
|
|
531
502
|
if (cached !== void 0) return cached;
|
|
532
|
-
const y = gamutClampedLuminance
|
|
503
|
+
const y = gamutClampedLuminance(okhslToLinearSrgb(h, s, lRounded));
|
|
533
504
|
if (luminanceCache.size >= CACHE_SIZE) {
|
|
534
505
|
const evict = cacheOrder.shift();
|
|
535
506
|
luminanceCache.delete(evict);
|
|
@@ -649,8 +620,8 @@ function coarseScan(h, s, lo, hi, yBase, target, epsilon, maxIter) {
|
|
|
649
620
|
function findLightnessForContrast(options) {
|
|
650
621
|
const { hue, saturation, preferredLightness, baseLinearRgb, contrast: contrastInput, lightnessRange = [0, 1], epsilon = 1e-4, maxIterations = 14 } = options;
|
|
651
622
|
const target = resolveMinContrast(contrastInput);
|
|
652
|
-
const searchTarget = target
|
|
653
|
-
const yBase = gamutClampedLuminance
|
|
623
|
+
const searchTarget = target * 1.005;
|
|
624
|
+
const yBase = gamutClampedLuminance(baseLinearRgb);
|
|
654
625
|
const crPref = contrastRatioFromLuminance(cachedLuminance(hue, saturation, preferredLightness), yBase);
|
|
655
626
|
if (crPref >= searchTarget) return {
|
|
656
627
|
lightness: preferredLightness,
|
|
@@ -773,8 +744,8 @@ function searchMixBranch(lo, hi, yBase, target, epsilon, maxIter, preferred, lum
|
|
|
773
744
|
function findValueForMixContrast(options) {
|
|
774
745
|
const { preferredValue, baseLinearRgb, contrast: contrastInput, luminanceAtValue, epsilon = 1e-4, maxIterations = 20 } = options;
|
|
775
746
|
const target = resolveMinContrast(contrastInput);
|
|
776
|
-
const searchTarget = target
|
|
777
|
-
const yBase = gamutClampedLuminance
|
|
747
|
+
const searchTarget = target * 1.005;
|
|
748
|
+
const yBase = gamutClampedLuminance(baseLinearRgb);
|
|
778
749
|
const crPref = contrastRatioFromLuminance(luminanceAtValue(preferredValue), yBase);
|
|
779
750
|
if (crPref >= searchTarget) return {
|
|
780
751
|
value: preferredValue,
|
|
@@ -1005,6 +976,11 @@ function mapSaturationDark(s, mode) {
|
|
|
1005
976
|
if (mode === "static") return s;
|
|
1006
977
|
return s * (1 - globalConfig.darkDesaturation);
|
|
1007
978
|
}
|
|
979
|
+
function schemeLightnessRange(isDark, mode) {
|
|
980
|
+
if (mode === "static") return [0, 1];
|
|
981
|
+
const [lo, hi] = isDark ? globalConfig.darkLightness : globalConfig.lightLightness;
|
|
982
|
+
return [lo / 100, hi / 100];
|
|
983
|
+
}
|
|
1008
984
|
function clamp(v, min, max) {
|
|
1009
985
|
return Math.max(min, Math.min(max, v));
|
|
1010
986
|
}
|
|
@@ -1065,20 +1041,22 @@ function resolveDependentColor(name, def, ctx, isHighContrast, isDark, effective
|
|
|
1065
1041
|
if (isDark && mode === "auto") delta = -delta;
|
|
1066
1042
|
preferredL = clamp(baseL + delta, 0, 100);
|
|
1067
1043
|
} else if (isDark) preferredL = mapLightnessDark(parsed.value, mode);
|
|
1068
|
-
else preferredL =
|
|
1044
|
+
else preferredL = mapLightnessLight(parsed.value, mode);
|
|
1069
1045
|
}
|
|
1070
1046
|
const rawContrast = def.contrast;
|
|
1071
1047
|
if (rawContrast !== void 0) {
|
|
1072
1048
|
const minCr = isHighContrast ? pairHC(rawContrast) : pairNormal(rawContrast);
|
|
1073
1049
|
const effectiveSat = isDark ? mapSaturationDark(satFactor * ctx.saturation / 100, mode) : satFactor * ctx.saturation / 100;
|
|
1074
1050
|
const baseLinearRgb = okhslToLinearSrgb(baseVariant.h, baseVariant.s, baseVariant.l);
|
|
1051
|
+
const lightnessRange = schemeLightnessRange(isDark, mode);
|
|
1075
1052
|
return {
|
|
1076
1053
|
l: findLightnessForContrast({
|
|
1077
1054
|
hue: effectiveHue,
|
|
1078
1055
|
saturation: effectiveSat,
|
|
1079
|
-
preferredLightness: preferredL / 100,
|
|
1056
|
+
preferredLightness: clamp(preferredL / 100, lightnessRange[0], lightnessRange[1]),
|
|
1080
1057
|
baseLinearRgb,
|
|
1081
|
-
contrast: minCr
|
|
1058
|
+
contrast: minCr,
|
|
1059
|
+
lightnessRange
|
|
1082
1060
|
}).lightness * 100,
|
|
1083
1061
|
satFactor
|
|
1084
1062
|
};
|
|
@@ -1145,12 +1123,6 @@ function resolveShadowForScheme(def, ctx, isDark, isHighContrast) {
|
|
|
1145
1123
|
function variantToLinearRgb(v) {
|
|
1146
1124
|
return okhslToLinearSrgb(v.h, v.s, v.l);
|
|
1147
1125
|
}
|
|
1148
|
-
function gamutClampedLuminance(linearRgb) {
|
|
1149
|
-
const r = sRGBGammaToLinear(Math.max(0, Math.min(1, sRGBLinearToGamma(linearRgb[0]))));
|
|
1150
|
-
const g = sRGBGammaToLinear(Math.max(0, Math.min(1, sRGBLinearToGamma(linearRgb[1]))));
|
|
1151
|
-
const b = sRGBGammaToLinear(Math.max(0, Math.min(1, sRGBLinearToGamma(linearRgb[2]))));
|
|
1152
|
-
return .2126 * r + .7152 * g + .0722 * b;
|
|
1153
|
-
}
|
|
1154
1126
|
/**
|
|
1155
1127
|
* Resolve hue for OKHSL mixing, handling achromatic colors.
|
|
1156
1128
|
* When one color has no saturation, its hue is meaningless —
|
|
@@ -1449,26 +1421,40 @@ function createTheme(hue, saturation, initialColors) {
|
|
|
1449
1421
|
}
|
|
1450
1422
|
};
|
|
1451
1423
|
}
|
|
1452
|
-
function resolvePrefix(options, themeName) {
|
|
1453
|
-
|
|
1454
|
-
if (
|
|
1424
|
+
function resolvePrefix(options, themeName, defaultPrefix = false) {
|
|
1425
|
+
const prefix = options?.prefix ?? defaultPrefix;
|
|
1426
|
+
if (prefix === true) return `${themeName}-`;
|
|
1427
|
+
if (typeof prefix === "object" && prefix !== null) return prefix[themeName] ?? `${themeName}-`;
|
|
1455
1428
|
return "";
|
|
1456
1429
|
}
|
|
1430
|
+
function validatePrimaryTheme(primary, themes) {
|
|
1431
|
+
if (primary !== void 0 && !(primary in themes)) {
|
|
1432
|
+
const available = Object.keys(themes).join(", ");
|
|
1433
|
+
throw new Error(`glaze: primary theme "${primary}" not found in palette. Available: ${available}.`);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1457
1436
|
function createPalette(themes) {
|
|
1458
1437
|
return {
|
|
1459
1438
|
tokens(options) {
|
|
1439
|
+
validatePrimaryTheme(options?.primary, themes);
|
|
1460
1440
|
const modes = resolveModes(options?.modes);
|
|
1461
1441
|
const allTokens = {};
|
|
1462
1442
|
for (const [themeName, theme] of Object.entries(themes)) {
|
|
1463
|
-
const
|
|
1443
|
+
const resolved = theme.resolve();
|
|
1444
|
+
const tokens = buildFlatTokenMap(resolved, resolvePrefix(options, themeName, true), modes, options?.format);
|
|
1464
1445
|
for (const variant of Object.keys(tokens)) {
|
|
1465
1446
|
if (!allTokens[variant]) allTokens[variant] = {};
|
|
1466
1447
|
Object.assign(allTokens[variant], tokens[variant]);
|
|
1467
1448
|
}
|
|
1449
|
+
if (themeName === options?.primary) {
|
|
1450
|
+
const unprefixed = buildFlatTokenMap(resolved, "", modes, options?.format);
|
|
1451
|
+
for (const variant of Object.keys(unprefixed)) Object.assign(allTokens[variant], unprefixed[variant]);
|
|
1452
|
+
}
|
|
1468
1453
|
}
|
|
1469
1454
|
return allTokens;
|
|
1470
1455
|
},
|
|
1471
1456
|
tasty(options) {
|
|
1457
|
+
validatePrimaryTheme(options?.primary, themes);
|
|
1472
1458
|
const states = {
|
|
1473
1459
|
dark: options?.states?.dark ?? globalConfig.states.dark,
|
|
1474
1460
|
highContrast: options?.states?.highContrast ?? globalConfig.states.highContrast
|
|
@@ -1476,8 +1462,13 @@ function createPalette(themes) {
|
|
|
1476
1462
|
const modes = resolveModes(options?.modes);
|
|
1477
1463
|
const allTokens = {};
|
|
1478
1464
|
for (const [themeName, theme] of Object.entries(themes)) {
|
|
1479
|
-
const
|
|
1465
|
+
const resolved = theme.resolve();
|
|
1466
|
+
const tokens = buildTokenMap(resolved, resolvePrefix(options, themeName, true), states, modes, options?.format);
|
|
1480
1467
|
Object.assign(allTokens, tokens);
|
|
1468
|
+
if (themeName === options?.primary) {
|
|
1469
|
+
const unprefixed = buildTokenMap(resolved, "", states, modes, options?.format);
|
|
1470
|
+
Object.assign(allTokens, unprefixed);
|
|
1471
|
+
}
|
|
1481
1472
|
}
|
|
1482
1473
|
return allTokens;
|
|
1483
1474
|
},
|
|
@@ -1488,6 +1479,7 @@ function createPalette(themes) {
|
|
|
1488
1479
|
return result;
|
|
1489
1480
|
},
|
|
1490
1481
|
css(options) {
|
|
1482
|
+
validatePrimaryTheme(options?.primary, themes);
|
|
1491
1483
|
const suffix = options?.suffix ?? "-color";
|
|
1492
1484
|
const format = options?.format ?? "rgb";
|
|
1493
1485
|
const allLines = {
|
|
@@ -1497,13 +1489,23 @@ function createPalette(themes) {
|
|
|
1497
1489
|
darkContrast: []
|
|
1498
1490
|
};
|
|
1499
1491
|
for (const [themeName, theme] of Object.entries(themes)) {
|
|
1500
|
-
const
|
|
1492
|
+
const resolved = theme.resolve();
|
|
1493
|
+
const css = buildCssMap(resolved, resolvePrefix(options, themeName, true), suffix, format);
|
|
1501
1494
|
for (const key of [
|
|
1502
1495
|
"light",
|
|
1503
1496
|
"dark",
|
|
1504
1497
|
"lightContrast",
|
|
1505
1498
|
"darkContrast"
|
|
1506
1499
|
]) if (css[key]) allLines[key].push(css[key]);
|
|
1500
|
+
if (themeName === options?.primary) {
|
|
1501
|
+
const unprefixed = buildCssMap(resolved, "", suffix, format);
|
|
1502
|
+
for (const key of [
|
|
1503
|
+
"light",
|
|
1504
|
+
"dark",
|
|
1505
|
+
"lightContrast",
|
|
1506
|
+
"darkContrast"
|
|
1507
|
+
]) if (unprefixed[key]) allLines[key].push(unprefixed[key]);
|
|
1508
|
+
}
|
|
1507
1509
|
}
|
|
1508
1510
|
return {
|
|
1509
1511
|
light: allLines.light.join("\n"),
|
|
@@ -1681,6 +1683,7 @@ exports.formatHsl = formatHsl;
|
|
|
1681
1683
|
exports.formatOkhsl = formatOkhsl;
|
|
1682
1684
|
exports.formatOklch = formatOklch;
|
|
1683
1685
|
exports.formatRgb = formatRgb;
|
|
1686
|
+
exports.gamutClampedLuminance = gamutClampedLuminance;
|
|
1684
1687
|
exports.glaze = glaze;
|
|
1685
1688
|
exports.okhslToLinearSrgb = okhslToLinearSrgb;
|
|
1686
1689
|
exports.okhslToOklab = okhslToOklab;
|