@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 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({ prefix: true });
75
- // → { light: { 'primary-surface': 'okhsl(...)', ... }, dark: { '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
- Root color lightness is mapped linearly within the configured `lightLightness` window:
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
- ### Token Export
697
+ ### Prefix Behavior
698
698
 
699
- Tokens are grouped by scheme variant, with plain color names as keys:
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({ prefix: true });
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({ prefix: true });
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({ prefix: true });
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({ prefix: true });
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` | | (palette only) Same prefix behavior as `tokens()` |
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 prefix
841
- palette.css({ prefix: true });
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({ prefix: true });
1016
- // tokens.light → { 'primary-surface': 'okhsl(...)', 'primary-shadow-md': 'okhsl(... / 0.1)' }
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({ prefix: true });
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({ prefix: true });
1023
- // css.light → "--primary-surface-color: rgb(...);\n--primary-shadow-md-color: rgb(... / 0.1);"
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
- .12541073,
85
- -.14503204
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 linear sRGB.
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 okhslToLinearSrgb(h, s, l) {
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 OKLabToLinearSRGB([
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
- * Convert OKHSL (h: 0–360, s: 0–1, l: 0–1) to OKLab [L, a, b].
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 okhslToOklab(h, s, l) {
333
- const L = toeInv(l);
334
- let a = 0;
335
- let b = 0;
336
- const hNorm = constrainAngle(h) / 360;
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 with rounded integer values.
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(${Math.round(r * 255)} ${Math.round(g * 255)} ${Math.round(b * 255)})`;
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$1(okhslToLinearSrgb(h, s, lRounded));
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 + .01;
653
- const yBase = gamutClampedLuminance$1(baseLinearRgb);
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 + .01;
777
- const yBase = gamutClampedLuminance$1(baseLinearRgb);
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 = clamp(parsed.value, 0, 100);
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
- if (options?.prefix === true) return `${themeName}-`;
1454
- if (typeof options?.prefix === "object" && options.prefix !== null) return options.prefix[themeName] ?? `${themeName}-`;
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 tokens = buildFlatTokenMap(theme.resolve(), resolvePrefix(options, themeName), modes, options?.format);
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 tokens = buildTokenMap(theme.resolve(), resolvePrefix(options, themeName), states, modes, options?.format);
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 css = buildCssMap(theme.resolve(), resolvePrefix(options, themeName), suffix, format);
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;