@tenphi/glaze 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -30
- package/dist/index.cjs +91 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -22
- package/dist/index.d.mts +38 -22
- package/dist/index.mjs +91 -33
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -242,6 +242,13 @@ interface GlazeConfig {
|
|
|
242
242
|
darkLightness?: [number, number];
|
|
243
243
|
/** Saturation reduction factor for dark scheme (0–1). Default: 0.1. */
|
|
244
244
|
darkDesaturation?: number;
|
|
245
|
+
/**
|
|
246
|
+
* Möbius beta for dark auto-inversion (0–1).
|
|
247
|
+
* Lower values expand subtle near-white distinctions in dark mode.
|
|
248
|
+
* Set to 1 for linear (legacy) behavior. Default: 0.5.
|
|
249
|
+
* Accepts [normal, highContrast] pair for separate HC tuning.
|
|
250
|
+
*/
|
|
251
|
+
darkCurve?: HCPair<number>;
|
|
245
252
|
/** State alias names for token export. */
|
|
246
253
|
states?: {
|
|
247
254
|
dark?: string;
|
|
@@ -256,6 +263,7 @@ interface GlazeConfigResolved {
|
|
|
256
263
|
lightLightness: [number, number];
|
|
257
264
|
darkLightness: [number, number];
|
|
258
265
|
darkDesaturation: number;
|
|
266
|
+
darkCurve: HCPair<number>;
|
|
259
267
|
states: {
|
|
260
268
|
dark: string;
|
|
261
269
|
highContrast: string;
|
|
@@ -385,35 +393,47 @@ interface GlazeCssResult {
|
|
|
385
393
|
lightContrast: string;
|
|
386
394
|
darkContrast: string;
|
|
387
395
|
}
|
|
388
|
-
/** Options
|
|
389
|
-
interface
|
|
390
|
-
/**
|
|
391
|
-
* Prefix mode. `true` uses `"<themeName>-"`, or provide a custom map.
|
|
392
|
-
* Defaults to `true` for palette export methods.
|
|
393
|
-
* Set to `false` explicitly to disable prefixing (last-write-wins on collisions).
|
|
394
|
-
*/
|
|
395
|
-
prefix?: boolean | Record<string, string>;
|
|
396
|
+
/** Options for `glaze.palette()` creation. */
|
|
397
|
+
interface GlazePaletteOptions {
|
|
396
398
|
/**
|
|
397
399
|
* Name of the primary theme. The primary theme's tokens are duplicated
|
|
398
|
-
* without prefix, providing convenient short aliases
|
|
399
|
-
* prefixed versions.
|
|
400
|
+
* without prefix in all exports, providing convenient short aliases
|
|
401
|
+
* alongside the prefixed versions. Can be overridden per-export.
|
|
400
402
|
*
|
|
401
403
|
* @example
|
|
402
404
|
* ```ts
|
|
403
|
-
* palette.
|
|
405
|
+
* const palette = glaze.palette({ brand, accent }, { primary: 'brand' });
|
|
406
|
+
* palette.tokens()
|
|
404
407
|
* // → { light: { 'brand-surface': '...', 'surface': '...', 'accent-surface': '...' } }
|
|
405
408
|
* ```
|
|
406
409
|
*/
|
|
407
410
|
primary?: string;
|
|
408
411
|
}
|
|
412
|
+
/** Options shared by palette `tokens()`, `tasty()`, and `css()` exports. */
|
|
413
|
+
interface GlazePaletteExportOptions {
|
|
414
|
+
/**
|
|
415
|
+
* Prefix mode. `true` uses `"<themeName>-"`, or provide a custom map.
|
|
416
|
+
* Defaults to `true` for palette export methods.
|
|
417
|
+
* Set to `false` explicitly to disable prefixing. Colliding keys
|
|
418
|
+
* produce a console.warn and the first-written value wins.
|
|
419
|
+
*/
|
|
420
|
+
prefix?: boolean | Record<string, string>;
|
|
421
|
+
/**
|
|
422
|
+
* Override the palette-level primary theme for this export.
|
|
423
|
+
* Pass a theme name to set/change the primary, or `false` to disable it.
|
|
424
|
+
* When omitted, inherits the palette-level `primary`.
|
|
425
|
+
*/
|
|
426
|
+
primary?: string | false;
|
|
427
|
+
}
|
|
409
428
|
interface GlazePalette {
|
|
410
429
|
/**
|
|
411
430
|
* Export all themes as a flat token map grouped by scheme variant.
|
|
412
431
|
* Prefix defaults to `true` — all tokens are prefixed with the theme name.
|
|
413
|
-
*
|
|
432
|
+
* Inherits the palette-level `primary`; override per-call or pass `false` to disable.
|
|
414
433
|
*
|
|
415
434
|
* ```ts
|
|
416
|
-
* palette.
|
|
435
|
+
* const palette = glaze.palette({ brand, accent }, { primary: 'brand' });
|
|
436
|
+
* palette.tokens()
|
|
417
437
|
* // → { light: { 'brand-surface': '...', 'surface': '...', 'accent-surface': '...' } }
|
|
418
438
|
* ```
|
|
419
439
|
*/
|
|
@@ -421,12 +441,10 @@ interface GlazePalette {
|
|
|
421
441
|
/**
|
|
422
442
|
* Export all themes as tasty style-to-state bindings.
|
|
423
443
|
* Uses `#name` color token keys and state aliases (`''`, `@dark`, etc.).
|
|
424
|
-
* Prefix defaults to `true`.
|
|
444
|
+
* Prefix defaults to `true`. Inherits the palette-level `primary`.
|
|
425
445
|
* @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
|
|
426
446
|
*/
|
|
427
|
-
tasty(options?: GlazeTokenOptions &
|
|
428
|
-
primary?: string;
|
|
429
|
-
}): Record<string, Record<string, string>>;
|
|
447
|
+
tasty(options?: GlazeTokenOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
430
448
|
/** Export all themes as plain JSON grouped by theme name. */
|
|
431
449
|
json(options?: GlazeJsonOptions & {
|
|
432
450
|
prefix?: boolean | Record<string, string>;
|
|
@@ -453,11 +471,9 @@ declare function glaze(hueOrOptions: number | {
|
|
|
453
471
|
}, saturation?: number): GlazeTheme;
|
|
454
472
|
declare namespace glaze {
|
|
455
473
|
var configure: (config: GlazeConfig) => void;
|
|
456
|
-
var palette: (themes: PaletteInput) => {
|
|
474
|
+
var palette: (themes: PaletteInput, options?: GlazePaletteOptions) => {
|
|
457
475
|
tokens(options?: GlazeJsonOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
458
|
-
tasty(options?: GlazeTokenOptions &
|
|
459
|
-
primary?: string;
|
|
460
|
-
}): Record<string, Record<string, string>>;
|
|
476
|
+
tasty(options?: GlazeTokenOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
461
477
|
json(options?: GlazeJsonOptions & {
|
|
462
478
|
prefix?: boolean | Record<string, string>;
|
|
463
479
|
}): Record<string, Record<string, Record<string, string>>>;
|
|
@@ -541,5 +557,5 @@ declare function formatHsl(h: number, s: number, l: number): string;
|
|
|
541
557
|
*/
|
|
542
558
|
declare function formatOklch(h: number, s: number, l: number): string;
|
|
543
559
|
//#endregion
|
|
544
|
-
export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type FindLightnessForContrastOptions, type FindLightnessForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, type GlazeColorFormat, type GlazeColorInput, type GlazeColorToken, type GlazeConfig, type GlazeCssOptions, type GlazeCssResult, type GlazeExtendOptions, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExportOptions, type GlazeShadowInput, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type MinContrast, type MixColorDef, type OkhslColor, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ShadowColorDef, type ShadowTuning, contrastRatioFromLuminance, findLightnessForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, gamutClampedLuminance, glaze, okhslToLinearSrgb, okhslToOklab, okhslToSrgb, parseHex, relativeLuminanceFromLinearRgb, resolveMinContrast, srgbToOkhsl };
|
|
560
|
+
export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type FindLightnessForContrastOptions, type FindLightnessForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, type GlazeColorFormat, type GlazeColorInput, type GlazeColorToken, type GlazeConfig, type GlazeCssOptions, type GlazeCssResult, type GlazeExtendOptions, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazeShadowInput, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type MinContrast, type MixColorDef, type OkhslColor, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ShadowColorDef, type ShadowTuning, contrastRatioFromLuminance, findLightnessForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, gamutClampedLuminance, glaze, okhslToLinearSrgb, okhslToOklab, okhslToSrgb, parseHex, relativeLuminanceFromLinearRgb, resolveMinContrast, srgbToOkhsl };
|
|
545
561
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -242,6 +242,13 @@ interface GlazeConfig {
|
|
|
242
242
|
darkLightness?: [number, number];
|
|
243
243
|
/** Saturation reduction factor for dark scheme (0–1). Default: 0.1. */
|
|
244
244
|
darkDesaturation?: number;
|
|
245
|
+
/**
|
|
246
|
+
* Möbius beta for dark auto-inversion (0–1).
|
|
247
|
+
* Lower values expand subtle near-white distinctions in dark mode.
|
|
248
|
+
* Set to 1 for linear (legacy) behavior. Default: 0.5.
|
|
249
|
+
* Accepts [normal, highContrast] pair for separate HC tuning.
|
|
250
|
+
*/
|
|
251
|
+
darkCurve?: HCPair<number>;
|
|
245
252
|
/** State alias names for token export. */
|
|
246
253
|
states?: {
|
|
247
254
|
dark?: string;
|
|
@@ -256,6 +263,7 @@ interface GlazeConfigResolved {
|
|
|
256
263
|
lightLightness: [number, number];
|
|
257
264
|
darkLightness: [number, number];
|
|
258
265
|
darkDesaturation: number;
|
|
266
|
+
darkCurve: HCPair<number>;
|
|
259
267
|
states: {
|
|
260
268
|
dark: string;
|
|
261
269
|
highContrast: string;
|
|
@@ -385,35 +393,47 @@ interface GlazeCssResult {
|
|
|
385
393
|
lightContrast: string;
|
|
386
394
|
darkContrast: string;
|
|
387
395
|
}
|
|
388
|
-
/** Options
|
|
389
|
-
interface
|
|
390
|
-
/**
|
|
391
|
-
* Prefix mode. `true` uses `"<themeName>-"`, or provide a custom map.
|
|
392
|
-
* Defaults to `true` for palette export methods.
|
|
393
|
-
* Set to `false` explicitly to disable prefixing (last-write-wins on collisions).
|
|
394
|
-
*/
|
|
395
|
-
prefix?: boolean | Record<string, string>;
|
|
396
|
+
/** Options for `glaze.palette()` creation. */
|
|
397
|
+
interface GlazePaletteOptions {
|
|
396
398
|
/**
|
|
397
399
|
* Name of the primary theme. The primary theme's tokens are duplicated
|
|
398
|
-
* without prefix, providing convenient short aliases
|
|
399
|
-
* prefixed versions.
|
|
400
|
+
* without prefix in all exports, providing convenient short aliases
|
|
401
|
+
* alongside the prefixed versions. Can be overridden per-export.
|
|
400
402
|
*
|
|
401
403
|
* @example
|
|
402
404
|
* ```ts
|
|
403
|
-
* palette.
|
|
405
|
+
* const palette = glaze.palette({ brand, accent }, { primary: 'brand' });
|
|
406
|
+
* palette.tokens()
|
|
404
407
|
* // → { light: { 'brand-surface': '...', 'surface': '...', 'accent-surface': '...' } }
|
|
405
408
|
* ```
|
|
406
409
|
*/
|
|
407
410
|
primary?: string;
|
|
408
411
|
}
|
|
412
|
+
/** Options shared by palette `tokens()`, `tasty()`, and `css()` exports. */
|
|
413
|
+
interface GlazePaletteExportOptions {
|
|
414
|
+
/**
|
|
415
|
+
* Prefix mode. `true` uses `"<themeName>-"`, or provide a custom map.
|
|
416
|
+
* Defaults to `true` for palette export methods.
|
|
417
|
+
* Set to `false` explicitly to disable prefixing. Colliding keys
|
|
418
|
+
* produce a console.warn and the first-written value wins.
|
|
419
|
+
*/
|
|
420
|
+
prefix?: boolean | Record<string, string>;
|
|
421
|
+
/**
|
|
422
|
+
* Override the palette-level primary theme for this export.
|
|
423
|
+
* Pass a theme name to set/change the primary, or `false` to disable it.
|
|
424
|
+
* When omitted, inherits the palette-level `primary`.
|
|
425
|
+
*/
|
|
426
|
+
primary?: string | false;
|
|
427
|
+
}
|
|
409
428
|
interface GlazePalette {
|
|
410
429
|
/**
|
|
411
430
|
* Export all themes as a flat token map grouped by scheme variant.
|
|
412
431
|
* Prefix defaults to `true` — all tokens are prefixed with the theme name.
|
|
413
|
-
*
|
|
432
|
+
* Inherits the palette-level `primary`; override per-call or pass `false` to disable.
|
|
414
433
|
*
|
|
415
434
|
* ```ts
|
|
416
|
-
* palette.
|
|
435
|
+
* const palette = glaze.palette({ brand, accent }, { primary: 'brand' });
|
|
436
|
+
* palette.tokens()
|
|
417
437
|
* // → { light: { 'brand-surface': '...', 'surface': '...', 'accent-surface': '...' } }
|
|
418
438
|
* ```
|
|
419
439
|
*/
|
|
@@ -421,12 +441,10 @@ interface GlazePalette {
|
|
|
421
441
|
/**
|
|
422
442
|
* Export all themes as tasty style-to-state bindings.
|
|
423
443
|
* Uses `#name` color token keys and state aliases (`''`, `@dark`, etc.).
|
|
424
|
-
* Prefix defaults to `true`.
|
|
444
|
+
* Prefix defaults to `true`. Inherits the palette-level `primary`.
|
|
425
445
|
* @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
|
|
426
446
|
*/
|
|
427
|
-
tasty(options?: GlazeTokenOptions &
|
|
428
|
-
primary?: string;
|
|
429
|
-
}): Record<string, Record<string, string>>;
|
|
447
|
+
tasty(options?: GlazeTokenOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
430
448
|
/** Export all themes as plain JSON grouped by theme name. */
|
|
431
449
|
json(options?: GlazeJsonOptions & {
|
|
432
450
|
prefix?: boolean | Record<string, string>;
|
|
@@ -453,11 +471,9 @@ declare function glaze(hueOrOptions: number | {
|
|
|
453
471
|
}, saturation?: number): GlazeTheme;
|
|
454
472
|
declare namespace glaze {
|
|
455
473
|
var configure: (config: GlazeConfig) => void;
|
|
456
|
-
var palette: (themes: PaletteInput) => {
|
|
474
|
+
var palette: (themes: PaletteInput, options?: GlazePaletteOptions) => {
|
|
457
475
|
tokens(options?: GlazeJsonOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
458
|
-
tasty(options?: GlazeTokenOptions &
|
|
459
|
-
primary?: string;
|
|
460
|
-
}): Record<string, Record<string, string>>;
|
|
476
|
+
tasty(options?: GlazeTokenOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
461
477
|
json(options?: GlazeJsonOptions & {
|
|
462
478
|
prefix?: boolean | Record<string, string>;
|
|
463
479
|
}): Record<string, Record<string, Record<string, string>>>;
|
|
@@ -541,5 +557,5 @@ declare function formatHsl(h: number, s: number, l: number): string;
|
|
|
541
557
|
*/
|
|
542
558
|
declare function formatOklch(h: number, s: number, l: number): string;
|
|
543
559
|
//#endregion
|
|
544
|
-
export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type FindLightnessForContrastOptions, type FindLightnessForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, type GlazeColorFormat, type GlazeColorInput, type GlazeColorToken, type GlazeConfig, type GlazeCssOptions, type GlazeCssResult, type GlazeExtendOptions, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExportOptions, type GlazeShadowInput, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type MinContrast, type MixColorDef, type OkhslColor, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ShadowColorDef, type ShadowTuning, contrastRatioFromLuminance, findLightnessForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, gamutClampedLuminance, glaze, okhslToLinearSrgb, okhslToOklab, okhslToSrgb, parseHex, relativeLuminanceFromLinearRgb, resolveMinContrast, srgbToOkhsl };
|
|
560
|
+
export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type FindLightnessForContrastOptions, type FindLightnessForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, type GlazeColorFormat, type GlazeColorInput, type GlazeColorToken, type GlazeConfig, type GlazeCssOptions, type GlazeCssResult, type GlazeExtendOptions, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazeShadowInput, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type MinContrast, type MixColorDef, type OkhslColor, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ShadowColorDef, type ShadowTuning, contrastRatioFromLuminance, findLightnessForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, gamutClampedLuminance, glaze, okhslToLinearSrgb, okhslToOklab, okhslToSrgb, parseHex, relativeLuminanceFromLinearRgb, resolveMinContrast, srgbToOkhsl };
|
|
545
561
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -812,6 +812,7 @@ let globalConfig = {
|
|
|
812
812
|
lightLightness: [10, 100],
|
|
813
813
|
darkLightness: [15, 95],
|
|
814
814
|
darkDesaturation: .1,
|
|
815
|
+
darkCurve: .5,
|
|
815
816
|
states: {
|
|
816
817
|
dark: "@dark",
|
|
817
818
|
highContrast: "@high-contrast"
|
|
@@ -959,24 +960,42 @@ function topoSort(defs) {
|
|
|
959
960
|
for (const name of Object.keys(defs)) visit(name);
|
|
960
961
|
return result;
|
|
961
962
|
}
|
|
962
|
-
function
|
|
963
|
+
function lightnessWindow(isHighContrast, kind) {
|
|
964
|
+
if (isHighContrast) return [0, 100];
|
|
965
|
+
return kind === "dark" ? globalConfig.darkLightness : globalConfig.lightLightness;
|
|
966
|
+
}
|
|
967
|
+
function mapLightnessLight(l, mode, isHighContrast) {
|
|
963
968
|
if (mode === "static") return l;
|
|
964
|
-
const [lo, hi] =
|
|
969
|
+
const [lo, hi] = lightnessWindow(isHighContrast, "light");
|
|
965
970
|
return l * (hi - lo) / 100 + lo;
|
|
966
971
|
}
|
|
967
|
-
function
|
|
972
|
+
function mobiusCurve(t, beta) {
|
|
973
|
+
if (beta >= 1) return t;
|
|
974
|
+
return t / (t + beta * (1 - t));
|
|
975
|
+
}
|
|
976
|
+
function mapLightnessDark(l, mode, isHighContrast) {
|
|
968
977
|
if (mode === "static") return l;
|
|
969
|
-
const
|
|
970
|
-
|
|
971
|
-
|
|
978
|
+
const beta = isHighContrast ? pairHC(globalConfig.darkCurve) : pairNormal(globalConfig.darkCurve);
|
|
979
|
+
const [darkLo, darkHi] = lightnessWindow(isHighContrast, "dark");
|
|
980
|
+
if (mode === "fixed") return l * (darkHi - darkLo) / 100 + darkLo;
|
|
981
|
+
const [lightLo, lightHi] = lightnessWindow(isHighContrast, "light");
|
|
982
|
+
const t = (lightHi - (l * (lightHi - lightLo) / 100 + lightLo)) / (lightHi - lightLo);
|
|
983
|
+
return darkLo + (darkHi - darkLo) * mobiusCurve(t, beta);
|
|
984
|
+
}
|
|
985
|
+
function lightMappedToDark(lightL, isHighContrast) {
|
|
986
|
+
const beta = isHighContrast ? pairHC(globalConfig.darkCurve) : pairNormal(globalConfig.darkCurve);
|
|
987
|
+
const [lightLo, lightHi] = lightnessWindow(isHighContrast, "light");
|
|
988
|
+
const [darkLo, darkHi] = lightnessWindow(isHighContrast, "dark");
|
|
989
|
+
const t = (lightHi - clamp(lightL, lightLo, lightHi)) / (lightHi - lightLo);
|
|
990
|
+
return darkLo + (darkHi - darkLo) * mobiusCurve(t, beta);
|
|
972
991
|
}
|
|
973
992
|
function mapSaturationDark(s, mode) {
|
|
974
993
|
if (mode === "static") return s;
|
|
975
994
|
return s * (1 - globalConfig.darkDesaturation);
|
|
976
995
|
}
|
|
977
|
-
function schemeLightnessRange(isDark, mode) {
|
|
996
|
+
function schemeLightnessRange(isDark, mode, isHighContrast) {
|
|
978
997
|
if (mode === "static") return [0, 1];
|
|
979
|
-
const [lo, hi] = isDark ?
|
|
998
|
+
const [lo, hi] = lightnessWindow(isHighContrast, isDark ? "dark" : "light");
|
|
980
999
|
return [lo / 100, hi / 100];
|
|
981
1000
|
}
|
|
982
1001
|
function clamp(v, min, max) {
|
|
@@ -1035,26 +1054,26 @@ function resolveDependentColor(name, def, ctx, isHighContrast, isDark, effective
|
|
|
1035
1054
|
else {
|
|
1036
1055
|
const parsed = parseRelativeOrAbsolute(isHighContrast ? pairHC(rawLightness) : pairNormal(rawLightness));
|
|
1037
1056
|
if (parsed.relative) {
|
|
1038
|
-
|
|
1039
|
-
if (isDark && mode === "auto")
|
|
1040
|
-
preferredL = clamp(baseL + delta, 0, 100);
|
|
1041
|
-
} else if (isDark) preferredL = mapLightnessDark(parsed.value, mode);
|
|
1042
|
-
else preferredL = mapLightnessLight(parsed.value, mode);
|
|
1057
|
+
const delta = parsed.value;
|
|
1058
|
+
if (isDark && mode === "auto") preferredL = lightMappedToDark(clamp(getSchemeVariant(baseResolved, false, isHighContrast).l * 100 + delta, 0, 100), isHighContrast);
|
|
1059
|
+
else preferredL = clamp(baseL + delta, 0, 100);
|
|
1060
|
+
} else if (isDark) preferredL = mapLightnessDark(parsed.value, mode, isHighContrast);
|
|
1061
|
+
else preferredL = mapLightnessLight(parsed.value, mode, isHighContrast);
|
|
1043
1062
|
}
|
|
1044
1063
|
const rawContrast = def.contrast;
|
|
1045
1064
|
if (rawContrast !== void 0) {
|
|
1046
1065
|
const minCr = isHighContrast ? pairHC(rawContrast) : pairNormal(rawContrast);
|
|
1047
1066
|
const effectiveSat = isDark ? mapSaturationDark(satFactor * ctx.saturation / 100, mode) : satFactor * ctx.saturation / 100;
|
|
1048
1067
|
const baseLinearRgb = okhslToLinearSrgb(baseVariant.h, baseVariant.s, baseVariant.l);
|
|
1049
|
-
const
|
|
1068
|
+
const windowRange = schemeLightnessRange(isDark, mode, isHighContrast);
|
|
1050
1069
|
return {
|
|
1051
1070
|
l: findLightnessForContrast({
|
|
1052
1071
|
hue: effectiveHue,
|
|
1053
1072
|
saturation: effectiveSat,
|
|
1054
|
-
preferredLightness: clamp(preferredL / 100,
|
|
1073
|
+
preferredLightness: clamp(preferredL / 100, windowRange[0], windowRange[1]),
|
|
1055
1074
|
baseLinearRgb,
|
|
1056
1075
|
contrast: minCr,
|
|
1057
|
-
lightnessRange
|
|
1076
|
+
lightnessRange: [0, 1]
|
|
1058
1077
|
}).lightness * 100,
|
|
1059
1078
|
satFactor
|
|
1060
1079
|
};
|
|
@@ -1091,13 +1110,13 @@ function resolveColorForScheme(name, def, ctx, isDark, isHighContrast) {
|
|
|
1091
1110
|
let finalL;
|
|
1092
1111
|
let finalSat;
|
|
1093
1112
|
if (isDark && isRoot) {
|
|
1094
|
-
finalL = mapLightnessDark(lightL, mode);
|
|
1113
|
+
finalL = mapLightnessDark(lightL, mode, isHighContrast);
|
|
1095
1114
|
finalSat = mapSaturationDark(satFactor * ctx.saturation / 100, mode);
|
|
1096
1115
|
} else if (isDark && !isRoot) {
|
|
1097
1116
|
finalL = lightL;
|
|
1098
1117
|
finalSat = mapSaturationDark(satFactor * ctx.saturation / 100, mode);
|
|
1099
1118
|
} else if (isRoot) {
|
|
1100
|
-
finalL = mapLightnessLight(lightL, mode);
|
|
1119
|
+
finalL = mapLightnessLight(lightL, mode, isHighContrast);
|
|
1101
1120
|
finalSat = satFactor * ctx.saturation / 100;
|
|
1102
1121
|
} else {
|
|
1103
1122
|
finalL = lightL;
|
|
@@ -1431,40 +1450,74 @@ function validatePrimaryTheme(primary, themes) {
|
|
|
1431
1450
|
throw new Error(`glaze: primary theme "${primary}" not found in palette. Available: ${available}.`);
|
|
1432
1451
|
}
|
|
1433
1452
|
}
|
|
1434
|
-
|
|
1453
|
+
/**
|
|
1454
|
+
* Resolve the effective primary for an export call.
|
|
1455
|
+
* `false` disables, a string overrides, `undefined` inherits from palette.
|
|
1456
|
+
*/
|
|
1457
|
+
function resolveEffectivePrimary(exportPrimary, palettePrimary) {
|
|
1458
|
+
if (exportPrimary === false) return void 0;
|
|
1459
|
+
return exportPrimary ?? palettePrimary;
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Filter a resolved color map, skipping keys already in `seen`.
|
|
1463
|
+
* Warns on collision and keeps the first-written value (first-write-wins).
|
|
1464
|
+
* Returns a new map containing only non-colliding entries.
|
|
1465
|
+
*/
|
|
1466
|
+
function filterCollisions(resolved, prefix, seen, themeName, isPrimary) {
|
|
1467
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
1468
|
+
const label = isPrimary ? `${themeName} (primary)` : themeName;
|
|
1469
|
+
for (const [name, color] of resolved) {
|
|
1470
|
+
const key = `${prefix}${name}`;
|
|
1471
|
+
if (seen.has(key)) {
|
|
1472
|
+
console.warn(`glaze: token "${key}" from theme "${label}" collides with theme "${seen.get(key)}" — skipping.`);
|
|
1473
|
+
continue;
|
|
1474
|
+
}
|
|
1475
|
+
seen.set(key, label);
|
|
1476
|
+
filtered.set(name, color);
|
|
1477
|
+
}
|
|
1478
|
+
return filtered;
|
|
1479
|
+
}
|
|
1480
|
+
function createPalette(themes, paletteOptions) {
|
|
1481
|
+
validatePrimaryTheme(paletteOptions?.primary, themes);
|
|
1435
1482
|
return {
|
|
1436
1483
|
tokens(options) {
|
|
1437
|
-
|
|
1484
|
+
const effectivePrimary = resolveEffectivePrimary(options?.primary, paletteOptions?.primary);
|
|
1485
|
+
if (options?.primary !== void 0) validatePrimaryTheme(effectivePrimary, themes);
|
|
1438
1486
|
const modes = resolveModes(options?.modes);
|
|
1439
1487
|
const allTokens = {};
|
|
1488
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1440
1489
|
for (const [themeName, theme] of Object.entries(themes)) {
|
|
1441
1490
|
const resolved = theme.resolve();
|
|
1442
|
-
const
|
|
1491
|
+
const prefix = resolvePrefix(options, themeName, true);
|
|
1492
|
+
const tokens = buildFlatTokenMap(filterCollisions(resolved, prefix, seen, themeName), prefix, modes, options?.format);
|
|
1443
1493
|
for (const variant of Object.keys(tokens)) {
|
|
1444
1494
|
if (!allTokens[variant]) allTokens[variant] = {};
|
|
1445
1495
|
Object.assign(allTokens[variant], tokens[variant]);
|
|
1446
1496
|
}
|
|
1447
|
-
if (themeName ===
|
|
1448
|
-
const unprefixed = buildFlatTokenMap(resolved, "", modes, options?.format);
|
|
1497
|
+
if (themeName === effectivePrimary) {
|
|
1498
|
+
const unprefixed = buildFlatTokenMap(filterCollisions(resolved, "", seen, themeName, true), "", modes, options?.format);
|
|
1449
1499
|
for (const variant of Object.keys(unprefixed)) Object.assign(allTokens[variant], unprefixed[variant]);
|
|
1450
1500
|
}
|
|
1451
1501
|
}
|
|
1452
1502
|
return allTokens;
|
|
1453
1503
|
},
|
|
1454
1504
|
tasty(options) {
|
|
1455
|
-
|
|
1505
|
+
const effectivePrimary = resolveEffectivePrimary(options?.primary, paletteOptions?.primary);
|
|
1506
|
+
if (options?.primary !== void 0) validatePrimaryTheme(effectivePrimary, themes);
|
|
1456
1507
|
const states = {
|
|
1457
1508
|
dark: options?.states?.dark ?? globalConfig.states.dark,
|
|
1458
1509
|
highContrast: options?.states?.highContrast ?? globalConfig.states.highContrast
|
|
1459
1510
|
};
|
|
1460
1511
|
const modes = resolveModes(options?.modes);
|
|
1461
1512
|
const allTokens = {};
|
|
1513
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1462
1514
|
for (const [themeName, theme] of Object.entries(themes)) {
|
|
1463
1515
|
const resolved = theme.resolve();
|
|
1464
|
-
const
|
|
1516
|
+
const prefix = resolvePrefix(options, themeName, true);
|
|
1517
|
+
const tokens = buildTokenMap(filterCollisions(resolved, prefix, seen, themeName), prefix, states, modes, options?.format);
|
|
1465
1518
|
Object.assign(allTokens, tokens);
|
|
1466
|
-
if (themeName ===
|
|
1467
|
-
const unprefixed = buildTokenMap(resolved, "", states, modes, options?.format);
|
|
1519
|
+
if (themeName === effectivePrimary) {
|
|
1520
|
+
const unprefixed = buildTokenMap(filterCollisions(resolved, "", seen, themeName, true), "", states, modes, options?.format);
|
|
1468
1521
|
Object.assign(allTokens, unprefixed);
|
|
1469
1522
|
}
|
|
1470
1523
|
}
|
|
@@ -1477,7 +1530,8 @@ function createPalette(themes) {
|
|
|
1477
1530
|
return result;
|
|
1478
1531
|
},
|
|
1479
1532
|
css(options) {
|
|
1480
|
-
|
|
1533
|
+
const effectivePrimary = resolveEffectivePrimary(options?.primary, paletteOptions?.primary);
|
|
1534
|
+
if (options?.primary !== void 0) validatePrimaryTheme(effectivePrimary, themes);
|
|
1481
1535
|
const suffix = options?.suffix ?? "-color";
|
|
1482
1536
|
const format = options?.format ?? "rgb";
|
|
1483
1537
|
const allLines = {
|
|
@@ -1486,17 +1540,19 @@ function createPalette(themes) {
|
|
|
1486
1540
|
lightContrast: [],
|
|
1487
1541
|
darkContrast: []
|
|
1488
1542
|
};
|
|
1543
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1489
1544
|
for (const [themeName, theme] of Object.entries(themes)) {
|
|
1490
1545
|
const resolved = theme.resolve();
|
|
1491
|
-
const
|
|
1546
|
+
const prefix = resolvePrefix(options, themeName, true);
|
|
1547
|
+
const css = buildCssMap(filterCollisions(resolved, prefix, seen, themeName), prefix, suffix, format);
|
|
1492
1548
|
for (const key of [
|
|
1493
1549
|
"light",
|
|
1494
1550
|
"dark",
|
|
1495
1551
|
"lightContrast",
|
|
1496
1552
|
"darkContrast"
|
|
1497
1553
|
]) if (css[key]) allLines[key].push(css[key]);
|
|
1498
|
-
if (themeName ===
|
|
1499
|
-
const unprefixed = buildCssMap(resolved, "", suffix, format);
|
|
1554
|
+
if (themeName === effectivePrimary) {
|
|
1555
|
+
const unprefixed = buildCssMap(filterCollisions(resolved, "", seen, themeName, true), "", suffix, format);
|
|
1500
1556
|
for (const key of [
|
|
1501
1557
|
"light",
|
|
1502
1558
|
"dark",
|
|
@@ -1563,6 +1619,7 @@ glaze.configure = function configure(config) {
|
|
|
1563
1619
|
lightLightness: config.lightLightness ?? globalConfig.lightLightness,
|
|
1564
1620
|
darkLightness: config.darkLightness ?? globalConfig.darkLightness,
|
|
1565
1621
|
darkDesaturation: config.darkDesaturation ?? globalConfig.darkDesaturation,
|
|
1622
|
+
darkCurve: config.darkCurve ?? globalConfig.darkCurve,
|
|
1566
1623
|
states: {
|
|
1567
1624
|
dark: config.states?.dark ?? globalConfig.states.dark,
|
|
1568
1625
|
highContrast: config.states?.highContrast ?? globalConfig.states.highContrast
|
|
@@ -1577,8 +1634,8 @@ glaze.configure = function configure(config) {
|
|
|
1577
1634
|
/**
|
|
1578
1635
|
* Compose multiple themes into a palette.
|
|
1579
1636
|
*/
|
|
1580
|
-
glaze.palette = function palette(themes) {
|
|
1581
|
-
return createPalette(themes);
|
|
1637
|
+
glaze.palette = function palette(themes, options) {
|
|
1638
|
+
return createPalette(themes, options);
|
|
1582
1639
|
};
|
|
1583
1640
|
/**
|
|
1584
1641
|
* Create a theme from a serialized export.
|
|
@@ -1662,6 +1719,7 @@ glaze.resetConfig = function resetConfig() {
|
|
|
1662
1719
|
lightLightness: [10, 100],
|
|
1663
1720
|
darkLightness: [15, 95],
|
|
1664
1721
|
darkDesaturation: .1,
|
|
1722
|
+
darkCurve: .5,
|
|
1665
1723
|
states: {
|
|
1666
1724
|
dark: "@dark",
|
|
1667
1725
|
highContrast: "@high-contrast"
|