@tenphi/glaze 0.0.0-snapshot.7e2a1da → 0.0.0-snapshot.7f7cab2

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
@@ -70,8 +70,8 @@ const danger = primary.extend({ hue: 23 });
70
70
  const success = primary.extend({ hue: 157 });
71
71
 
72
72
  // Compose into a palette and export
73
- const palette = glaze.palette({ primary, danger, success });
74
- const tokens = palette.tokens({ primary: 'primary' });
73
+ const palette = glaze.palette({ primary, danger, success }, { primary: 'primary' });
74
+ const tokens = palette.tokens();
75
75
  // → { light: { 'primary-surface': 'okhsl(...)', 'surface': 'okhsl(...)', ... }, dark: { ... } }
76
76
  ```
77
77
 
@@ -603,7 +603,7 @@ Modes control how colors adapt across schemes:
603
603
 
604
604
  ```ts
605
605
  // Light: surface L=97, text lightness='-52' → L=45 (dark text on light bg)
606
- // Dark: surface inverts to L≈29 (power curve), sign flips → L=29+52=81
606
+ // Dark: surface inverts to L≈20 (Möbius curve), sign flips → L=20+52=72
607
607
  // contrast solver may push further (light text on dark bg)
608
608
  ```
609
609
 
@@ -639,15 +639,15 @@ Both `auto` and `fixed` modes use the same linear formula. `static` mode and hig
639
639
 
640
640
  ### Lightness
641
641
 
642
- **`auto`** — inverted with a power curve within the configured window:
642
+ **`auto`** — inverted with a Möbius transformation within the configured window:
643
643
 
644
644
  ```ts
645
645
  const [lo, hi] = darkLightness; // default: [15, 95]
646
- const d = (100 - lightness) / 100;
647
- const invertedL = lo + (hi - lo) * Math.pow(d, darkCurve); // darkCurve default: 0.5
646
+ const t = (100 - lightness) / 100;
647
+ const invertedL = lo + (hi - lo) * t / (t + darkCurve * (1 - t)); // darkCurve default: 0.5
648
648
  ```
649
649
 
650
- The `darkCurve` exponent (default `0.5`) expands small light-theme deltas near white into larger usable deltas in dark mode. This preserves subtle surface hierarchy (e.g. L=97 vs L=95) that would otherwise collapse to near-identical dark values. Set `darkCurve: 1` for linear (legacy) behavior.
650
+ The `darkCurve` parameter (default `0.5`, range 0–1) controls how much the dark-mode inversion expands lightness deltas. Lower values produce stronger expansion; `1` gives linear (legacy) behavior. Accepts a `[normal, highContrast]` pair for separate HC tuning (e.g. `darkCurve: [0.5, 0.3]`); a single number applies to both. Unlike a power curve, the Möbius transformation provides **proportional expansion** — small and large deltas are scaled by similar ratios, preserving the visual hierarchy of the light theme.
651
651
 
652
652
  **`fixed`** — mapped without inversion (not affected by `darkCurve`):
653
653
 
@@ -657,11 +657,11 @@ const mappedL = (lightness * (hi - lo)) / 100 + lo;
657
657
 
658
658
  | Color | Light L | Auto (curve=0.5) | Auto (curve=1, linear) | Fixed (mapped) |
659
659
  |---|---|---|---|---|
660
- | surface (L=97) | 97 | 28.9 | 17.4 | 92.6 |
661
- | accent-fill (L=52) | 52 | 70.4 | 53.4 | 56.6 |
660
+ | surface (L=97) | 97 | 19.7 | 17.4 | 92.6 |
661
+ | accent-fill (L=52) | 52 | 66.9 | 53.4 | 56.6 |
662
662
  | accent-text (L=100) | 100 | 15 | 15 | 95 |
663
663
 
664
- In high-contrast variants, the `darkLightness` window is bypassed. Auto uses pure inversion (`100 - L`), fixed uses identity (`L`). This allows HC colors to reach the full 0–100 range.
664
+ In high-contrast variants, the `darkLightness` window is bypassed auto uses the Möbius curve over the full [0, 100] range, and fixed uses identity (`L`). To use a different curve shape for HC, pass a `[normal, hc]` pair to `darkCurve` (e.g. `darkCurve: [0.5, 0.3]`).
665
665
 
666
666
  ### Saturation
667
667
 
@@ -701,6 +701,15 @@ Combine multiple themes into a single palette:
701
701
  const palette = glaze.palette({ primary, danger, success, warning });
702
702
  ```
703
703
 
704
+ Optionally designate a primary theme at creation time:
705
+
706
+ ```ts
707
+ const palette = glaze.palette(
708
+ { primary, danger, success, warning },
709
+ { primary: 'primary' },
710
+ );
711
+ ```
712
+
704
713
  ### Prefix Behavior
705
714
 
706
715
  Palette export methods (`tokens()`, `tasty()`, `css()`) default to `prefix: true` — all tokens are automatically prefixed with the theme name to avoid collisions:
@@ -719,15 +728,28 @@ Custom prefix mapping:
719
728
  palette.tokens({ prefix: { primary: 'brand-', danger: 'error-' } });
720
729
  ```
721
730
 
722
- To disable prefixing entirely, pass `prefix: false` explicitly. Note that tokens with the same name will overwrite each other (last theme wins).
731
+ To disable prefixing entirely, pass `prefix: false` explicitly.
732
+
733
+ ### Collision Detection
734
+
735
+ When two themes produce the same output key (via `prefix: false`, custom prefix maps, or primary unprefixed aliases), the first-written value wins and a `console.warn` is emitted:
736
+
737
+ ```ts
738
+ const palette = glaze.palette({ a, b });
739
+ palette.tokens({ prefix: false });
740
+ // ⚠ glaze: token "surface" from theme "b" collides with theme "a" — skipping.
741
+ ```
723
742
 
724
743
  ### Primary Theme
725
744
 
726
- 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:
745
+ The primary theme's tokens are duplicated without prefix, providing convenient short aliases alongside the prefixed versions. Set at palette creation to apply to all exports automatically:
727
746
 
728
747
  ```ts
729
- const palette = glaze.palette({ primary, danger, success });
730
- const tokens = palette.tokens({ primary: 'primary' });
748
+ const palette = glaze.palette(
749
+ { primary, danger, success },
750
+ { primary: 'primary' },
751
+ );
752
+ const tokens = palette.tokens();
731
753
  // → {
732
754
  // light: {
733
755
  // 'primary-surface': 'okhsl(...)', // prefixed (all themes)
@@ -738,11 +760,18 @@ const tokens = palette.tokens({ primary: 'primary' });
738
760
  // }
739
761
  ```
740
762
 
763
+ Override or disable per-export:
764
+
765
+ ```ts
766
+ palette.tokens({ primary: 'danger' }); // use danger as primary for this call
767
+ palette.tokens({ primary: false }); // no primary for this call
768
+ ```
769
+
741
770
  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:
742
771
 
743
772
  ```ts
744
- palette.tokens({ prefix: { primary: 'p-', danger: 'd-' }, primary: 'primary' });
745
- // → 'p-surface' + 'surface' (alias) + 'd-surface'
773
+ palette.tokens({ prefix: { primary: 'p-', danger: 'd-' } });
774
+ // → 'p-surface' + 'surface' (alias from palette-level primary) + 'd-surface'
746
775
  ```
747
776
 
748
777
  An error is thrown if the primary name doesn't match any theme in the palette.
@@ -752,7 +781,11 @@ An error is thrown if the primary name doesn't match any theme in the palette.
752
781
  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.):
753
782
 
754
783
  ```ts
755
- const tastyTokens = palette.tasty({ primary: 'primary' });
784
+ const palette = glaze.palette(
785
+ { primary, danger, success },
786
+ { primary: 'primary' },
787
+ );
788
+ const tastyTokens = palette.tasty();
756
789
  // → {
757
790
  // '#primary-surface': { '': 'okhsl(...)', '@dark': 'okhsl(...)' },
758
791
  // '#danger-surface': { '': 'okhsl(...)', '@dark': 'okhsl(...)' },
@@ -848,7 +881,11 @@ const css = theme.css();
848
881
  Use in a stylesheet:
849
882
 
850
883
  ```ts
851
- const css = palette.css({ primary: 'primary' });
884
+ const palette = glaze.palette(
885
+ { primary, danger, success },
886
+ { primary: 'primary' },
887
+ );
888
+ const css = palette.css();
852
889
 
853
890
  const stylesheet = `
854
891
  :root { ${css.light} }
@@ -865,7 +902,7 @@ Options:
865
902
  | `format` | `'rgb'` | Color format (`'rgb'`, `'hsl'`, `'okhsl'`, `'oklch'`) |
866
903
  | `suffix` | `'-color'` | Suffix appended to each CSS property name |
867
904
  | `prefix` | `true` (palette) | (palette only) `true` uses `"<themeName>-"`, or provide a custom map |
868
- | `primary` | | (palette only) Theme name to duplicate without prefix |
905
+ | `primary` | inherited | (palette only) Override or disable (`false`) the palette-level primary for this call |
869
906
 
870
907
  ```ts
871
908
  // Custom suffix
@@ -876,8 +913,8 @@ theme.css({ suffix: '' });
876
913
  theme.css({ format: 'hsl' });
877
914
  // → "--surface-color: hsl(...);"
878
915
 
879
- // Palette with primary
880
- palette.css({ primary: 'primary' });
916
+ // Palette with primary (inherited from palette creation)
917
+ palette.css();
881
918
  // → "--primary-surface-color: rgb(...);\n--surface-color: rgb(...);\n--danger-surface-color: rgb(...);"
882
919
  ```
883
920
 
@@ -914,7 +951,7 @@ glaze.configure({
914
951
  lightLightness: [10, 100], // Light scheme lightness window [lo, hi] (bypassed in HC)
915
952
  darkLightness: [15, 95], // Dark scheme lightness window [lo, hi] (bypassed in HC)
916
953
  darkDesaturation: 0.1, // Saturation reduction in dark scheme (0–1)
917
- darkCurve: 0.5, // Power-curve exponent for dark auto-inversion (0–1)
954
+ darkCurve: 0.5, // Möbius beta for dark auto-inversion (0–1); or [normal, hc] pair
918
955
  states: {
919
956
  dark: '@dark', // State alias for dark mode tokens
920
957
  highContrast: '@high-contrast',
@@ -1049,17 +1086,20 @@ const success = primary.extend({ hue: 157 });
1049
1086
  const warning = primary.extend({ hue: 84 });
1050
1087
  const note = primary.extend({ hue: 302 });
1051
1088
 
1052
- const palette = glaze.palette({ primary, danger, success, warning, note });
1089
+ const palette = glaze.palette(
1090
+ { primary, danger, success, warning, note },
1091
+ { primary: 'primary' },
1092
+ );
1053
1093
 
1054
1094
  // Export as flat token map grouped by variant (prefix defaults to true)
1055
- const tokens = palette.tokens({ primary: 'primary' });
1095
+ const tokens = palette.tokens();
1056
1096
  // tokens.light → { 'primary-surface': '...', 'surface': '...', 'danger-surface': '...' }
1057
1097
 
1058
1098
  // Export as tasty style-to-state bindings (for Tasty style system)
1059
- const tastyTokens = palette.tasty({ primary: 'primary' });
1099
+ const tastyTokens = palette.tasty();
1060
1100
 
1061
1101
  // Export as CSS custom properties (rgb format by default)
1062
- const css = palette.css({ primary: 'primary' });
1102
+ const css = palette.css();
1063
1103
  // css.light → "--primary-surface-color: rgb(...);\n--surface-color: rgb(...);\n--danger-surface-color: rgb(...);"
1064
1104
 
1065
1105
  // Standalone shadow computation
@@ -1115,7 +1155,7 @@ brand.colors({ surface: { lightness: 97 }, text: { base: 'surface', lightness: '
1115
1155
  | Method | Description |
1116
1156
  |---|---|
1117
1157
  | `glaze.configure(config)` | Set global configuration |
1118
- | `glaze.palette(themes)` | Compose themes into a palette |
1158
+ | `glaze.palette(themes, options?)` | Compose themes into a palette (options: `{ primary? }`) |
1119
1159
  | `glaze.getConfig()` | Get current global config |
1120
1160
  | `glaze.resetConfig()` | Reset to defaults |
1121
1161
 
package/dist/index.cjs CHANGED
@@ -962,31 +962,42 @@ function topoSort(defs) {
962
962
  for (const name of Object.keys(defs)) visit(name);
963
963
  return result;
964
964
  }
965
+ function lightnessWindow(isHighContrast, kind) {
966
+ if (isHighContrast) return [0, 100];
967
+ return kind === "dark" ? globalConfig.darkLightness : globalConfig.lightLightness;
968
+ }
965
969
  function mapLightnessLight(l, mode, isHighContrast) {
966
- if (mode === "static" || isHighContrast) return l;
967
- const [lo, hi] = globalConfig.lightLightness;
970
+ if (mode === "static") return l;
971
+ const [lo, hi] = lightnessWindow(isHighContrast, "light");
968
972
  return l * (hi - lo) / 100 + lo;
969
973
  }
974
+ function mobiusCurve(t, beta) {
975
+ if (beta >= 1) return t;
976
+ return t / (t + beta * (1 - t));
977
+ }
970
978
  function mapLightnessDark(l, mode, isHighContrast) {
971
979
  if (mode === "static") return l;
972
- if (isHighContrast) {
973
- if (mode === "fixed") return l;
974
- const t = (100 - l) / 100;
975
- return 100 * Math.pow(t, globalConfig.darkCurve);
976
- }
977
- const [darkLo, darkHi] = globalConfig.darkLightness;
980
+ const beta = isHighContrast ? pairHC(globalConfig.darkCurve) : pairNormal(globalConfig.darkCurve);
981
+ const [darkLo, darkHi] = lightnessWindow(isHighContrast, "dark");
978
982
  if (mode === "fixed") return l * (darkHi - darkLo) / 100 + darkLo;
979
- const [lightLo, lightHi] = globalConfig.lightLightness;
983
+ const [lightLo, lightHi] = lightnessWindow(isHighContrast, "light");
980
984
  const t = (lightHi - (l * (lightHi - lightLo) / 100 + lightLo)) / (lightHi - lightLo);
981
- return darkLo + (darkHi - darkLo) * Math.pow(t, globalConfig.darkCurve);
985
+ return darkLo + (darkHi - darkLo) * mobiusCurve(t, beta);
986
+ }
987
+ function lightMappedToDark(lightL, isHighContrast) {
988
+ const beta = isHighContrast ? pairHC(globalConfig.darkCurve) : pairNormal(globalConfig.darkCurve);
989
+ const [lightLo, lightHi] = lightnessWindow(isHighContrast, "light");
990
+ const [darkLo, darkHi] = lightnessWindow(isHighContrast, "dark");
991
+ const t = (lightHi - clamp(lightL, lightLo, lightHi)) / (lightHi - lightLo);
992
+ return darkLo + (darkHi - darkLo) * mobiusCurve(t, beta);
982
993
  }
983
994
  function mapSaturationDark(s, mode) {
984
995
  if (mode === "static") return s;
985
996
  return s * (1 - globalConfig.darkDesaturation);
986
997
  }
987
998
  function schemeLightnessRange(isDark, mode, isHighContrast) {
988
- if (mode === "static" || isHighContrast) return [0, 1];
989
- const [lo, hi] = isDark ? globalConfig.darkLightness : globalConfig.lightLightness;
999
+ if (mode === "static") return [0, 1];
1000
+ const [lo, hi] = lightnessWindow(isHighContrast, isDark ? "dark" : "light");
990
1001
  return [lo / 100, hi / 100];
991
1002
  }
992
1003
  function clamp(v, min, max) {
@@ -1045,9 +1056,9 @@ function resolveDependentColor(name, def, ctx, isHighContrast, isDark, effective
1045
1056
  else {
1046
1057
  const parsed = parseRelativeOrAbsolute(isHighContrast ? pairHC(rawLightness) : pairNormal(rawLightness));
1047
1058
  if (parsed.relative) {
1048
- let delta = parsed.value;
1049
- if (isDark && mode === "auto") delta = -delta;
1050
- preferredL = clamp(baseL + delta, 0, 100);
1059
+ const delta = parsed.value;
1060
+ if (isDark && mode === "auto") preferredL = lightMappedToDark(clamp(getSchemeVariant(baseResolved, false, isHighContrast).l * 100 + delta, 0, 100), isHighContrast);
1061
+ else preferredL = clamp(baseL + delta, 0, 100);
1051
1062
  } else if (isDark) preferredL = mapLightnessDark(parsed.value, mode, isHighContrast);
1052
1063
  else preferredL = mapLightnessLight(parsed.value, mode, isHighContrast);
1053
1064
  }
@@ -1404,10 +1415,14 @@ function createTheme(hue, saturation, initialColors) {
1404
1415
  };
1405
1416
  },
1406
1417
  extend(options) {
1407
- return createTheme(options.hue ?? hue, options.saturation ?? saturation, options.colors ? {
1408
- ...colorDefs,
1418
+ const newHue = options.hue ?? hue;
1419
+ const newSat = options.saturation ?? saturation;
1420
+ const inheritedColors = {};
1421
+ for (const [name, def] of Object.entries(colorDefs)) if (def.inherit !== false) inheritedColors[name] = def;
1422
+ return createTheme(newHue, newSat, options.colors ? {
1423
+ ...inheritedColors,
1409
1424
  ...options.colors
1410
- } : { ...colorDefs });
1425
+ } : { ...inheritedColors });
1411
1426
  },
1412
1427
  resolve() {
1413
1428
  return resolveAllColors(hue, saturation, colorDefs);
@@ -1441,40 +1456,74 @@ function validatePrimaryTheme(primary, themes) {
1441
1456
  throw new Error(`glaze: primary theme "${primary}" not found in palette. Available: ${available}.`);
1442
1457
  }
1443
1458
  }
1444
- function createPalette(themes) {
1459
+ /**
1460
+ * Resolve the effective primary for an export call.
1461
+ * `false` disables, a string overrides, `undefined` inherits from palette.
1462
+ */
1463
+ function resolveEffectivePrimary(exportPrimary, palettePrimary) {
1464
+ if (exportPrimary === false) return void 0;
1465
+ return exportPrimary ?? palettePrimary;
1466
+ }
1467
+ /**
1468
+ * Filter a resolved color map, skipping keys already in `seen`.
1469
+ * Warns on collision and keeps the first-written value (first-write-wins).
1470
+ * Returns a new map containing only non-colliding entries.
1471
+ */
1472
+ function filterCollisions(resolved, prefix, seen, themeName, isPrimary) {
1473
+ const filtered = /* @__PURE__ */ new Map();
1474
+ const label = isPrimary ? `${themeName} (primary)` : themeName;
1475
+ for (const [name, color] of resolved) {
1476
+ const key = `${prefix}${name}`;
1477
+ if (seen.has(key)) {
1478
+ console.warn(`glaze: token "${key}" from theme "${label}" collides with theme "${seen.get(key)}" — skipping.`);
1479
+ continue;
1480
+ }
1481
+ seen.set(key, label);
1482
+ filtered.set(name, color);
1483
+ }
1484
+ return filtered;
1485
+ }
1486
+ function createPalette(themes, paletteOptions) {
1487
+ validatePrimaryTheme(paletteOptions?.primary, themes);
1445
1488
  return {
1446
1489
  tokens(options) {
1447
- validatePrimaryTheme(options?.primary, themes);
1490
+ const effectivePrimary = resolveEffectivePrimary(options?.primary, paletteOptions?.primary);
1491
+ if (options?.primary !== void 0) validatePrimaryTheme(effectivePrimary, themes);
1448
1492
  const modes = resolveModes(options?.modes);
1449
1493
  const allTokens = {};
1494
+ const seen = /* @__PURE__ */ new Map();
1450
1495
  for (const [themeName, theme] of Object.entries(themes)) {
1451
1496
  const resolved = theme.resolve();
1452
- const tokens = buildFlatTokenMap(resolved, resolvePrefix(options, themeName, true), modes, options?.format);
1497
+ const prefix = resolvePrefix(options, themeName, true);
1498
+ const tokens = buildFlatTokenMap(filterCollisions(resolved, prefix, seen, themeName), prefix, modes, options?.format);
1453
1499
  for (const variant of Object.keys(tokens)) {
1454
1500
  if (!allTokens[variant]) allTokens[variant] = {};
1455
1501
  Object.assign(allTokens[variant], tokens[variant]);
1456
1502
  }
1457
- if (themeName === options?.primary) {
1458
- const unprefixed = buildFlatTokenMap(resolved, "", modes, options?.format);
1503
+ if (themeName === effectivePrimary) {
1504
+ const unprefixed = buildFlatTokenMap(filterCollisions(resolved, "", seen, themeName, true), "", modes, options?.format);
1459
1505
  for (const variant of Object.keys(unprefixed)) Object.assign(allTokens[variant], unprefixed[variant]);
1460
1506
  }
1461
1507
  }
1462
1508
  return allTokens;
1463
1509
  },
1464
1510
  tasty(options) {
1465
- validatePrimaryTheme(options?.primary, themes);
1511
+ const effectivePrimary = resolveEffectivePrimary(options?.primary, paletteOptions?.primary);
1512
+ if (options?.primary !== void 0) validatePrimaryTheme(effectivePrimary, themes);
1466
1513
  const states = {
1467
1514
  dark: options?.states?.dark ?? globalConfig.states.dark,
1468
1515
  highContrast: options?.states?.highContrast ?? globalConfig.states.highContrast
1469
1516
  };
1470
1517
  const modes = resolveModes(options?.modes);
1471
1518
  const allTokens = {};
1519
+ const seen = /* @__PURE__ */ new Map();
1472
1520
  for (const [themeName, theme] of Object.entries(themes)) {
1473
1521
  const resolved = theme.resolve();
1474
- const tokens = buildTokenMap(resolved, resolvePrefix(options, themeName, true), states, modes, options?.format);
1522
+ const prefix = resolvePrefix(options, themeName, true);
1523
+ const tokens = buildTokenMap(filterCollisions(resolved, prefix, seen, themeName), prefix, states, modes, options?.format);
1475
1524
  Object.assign(allTokens, tokens);
1476
- if (themeName === options?.primary) {
1477
- const unprefixed = buildTokenMap(resolved, "", states, modes, options?.format);
1525
+ if (themeName === effectivePrimary) {
1526
+ const unprefixed = buildTokenMap(filterCollisions(resolved, "", seen, themeName, true), "", states, modes, options?.format);
1478
1527
  Object.assign(allTokens, unprefixed);
1479
1528
  }
1480
1529
  }
@@ -1487,7 +1536,8 @@ function createPalette(themes) {
1487
1536
  return result;
1488
1537
  },
1489
1538
  css(options) {
1490
- validatePrimaryTheme(options?.primary, themes);
1539
+ const effectivePrimary = resolveEffectivePrimary(options?.primary, paletteOptions?.primary);
1540
+ if (options?.primary !== void 0) validatePrimaryTheme(effectivePrimary, themes);
1491
1541
  const suffix = options?.suffix ?? "-color";
1492
1542
  const format = options?.format ?? "rgb";
1493
1543
  const allLines = {
@@ -1496,17 +1546,19 @@ function createPalette(themes) {
1496
1546
  lightContrast: [],
1497
1547
  darkContrast: []
1498
1548
  };
1549
+ const seen = /* @__PURE__ */ new Map();
1499
1550
  for (const [themeName, theme] of Object.entries(themes)) {
1500
1551
  const resolved = theme.resolve();
1501
- const css = buildCssMap(resolved, resolvePrefix(options, themeName, true), suffix, format);
1552
+ const prefix = resolvePrefix(options, themeName, true);
1553
+ const css = buildCssMap(filterCollisions(resolved, prefix, seen, themeName), prefix, suffix, format);
1502
1554
  for (const key of [
1503
1555
  "light",
1504
1556
  "dark",
1505
1557
  "lightContrast",
1506
1558
  "darkContrast"
1507
1559
  ]) if (css[key]) allLines[key].push(css[key]);
1508
- if (themeName === options?.primary) {
1509
- const unprefixed = buildCssMap(resolved, "", suffix, format);
1560
+ if (themeName === effectivePrimary) {
1561
+ const unprefixed = buildCssMap(filterCollisions(resolved, "", seen, themeName, true), "", suffix, format);
1510
1562
  for (const key of [
1511
1563
  "light",
1512
1564
  "dark",
@@ -1588,8 +1640,8 @@ glaze.configure = function configure(config) {
1588
1640
  /**
1589
1641
  * Compose multiple themes into a palette.
1590
1642
  */
1591
- glaze.palette = function palette(themes) {
1592
- return createPalette(themes);
1643
+ glaze.palette = function palette(themes, options) {
1644
+ return createPalette(themes, options);
1593
1645
  };
1594
1646
  /**
1595
1647
  * Create a theme from a serialized export.