@tenphi/glaze 0.6.3 → 0.8.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 +70 -30
- package/dist/index.cjs +79 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -18
- package/dist/index.d.mts +44 -18
- package/dist/index.mjs +79 -27
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -242,6 +242,12 @@ 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
|
+
* Power-curve exponent 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
|
+
*/
|
|
250
|
+
darkCurve?: number;
|
|
245
251
|
/** State alias names for token export. */
|
|
246
252
|
states?: {
|
|
247
253
|
dark?: string;
|
|
@@ -256,6 +262,7 @@ interface GlazeConfigResolved {
|
|
|
256
262
|
lightLightness: [number, number];
|
|
257
263
|
darkLightness: [number, number];
|
|
258
264
|
darkDesaturation: number;
|
|
265
|
+
darkCurve: number;
|
|
259
266
|
states: {
|
|
260
267
|
dark: string;
|
|
261
268
|
highContrast: string;
|
|
@@ -385,33 +392,54 @@ interface GlazeCssResult {
|
|
|
385
392
|
lightContrast: string;
|
|
386
393
|
darkContrast: string;
|
|
387
394
|
}
|
|
395
|
+
/** Options shared by palette `tokens()`, `tasty()`, and `css()` exports. */
|
|
396
|
+
interface GlazePaletteExportOptions {
|
|
397
|
+
/**
|
|
398
|
+
* Prefix mode. `true` uses `"<themeName>-"`, or provide a custom map.
|
|
399
|
+
* Defaults to `true` for palette export methods.
|
|
400
|
+
* Set to `false` explicitly to disable prefixing (last-write-wins on collisions).
|
|
401
|
+
*/
|
|
402
|
+
prefix?: boolean | Record<string, string>;
|
|
403
|
+
/**
|
|
404
|
+
* Name of the primary theme. The primary theme's tokens are duplicated
|
|
405
|
+
* without prefix, providing convenient short aliases alongside the
|
|
406
|
+
* prefixed versions.
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```ts
|
|
410
|
+
* palette.tokens({ primary: 'brand' })
|
|
411
|
+
* // → { light: { 'brand-surface': '...', 'surface': '...', 'accent-surface': '...' } }
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
primary?: string;
|
|
415
|
+
}
|
|
388
416
|
interface GlazePalette {
|
|
389
417
|
/**
|
|
390
418
|
* Export all themes as a flat token map grouped by scheme variant.
|
|
419
|
+
* Prefix defaults to `true` — all tokens are prefixed with the theme name.
|
|
420
|
+
* Use `primary` to duplicate one theme's tokens without prefix.
|
|
391
421
|
*
|
|
392
422
|
* ```ts
|
|
393
|
-
* palette.tokens({
|
|
394
|
-
* // → { light: { '
|
|
423
|
+
* palette.tokens({ primary: 'brand' })
|
|
424
|
+
* // → { light: { 'brand-surface': '...', 'surface': '...', 'accent-surface': '...' } }
|
|
395
425
|
* ```
|
|
396
426
|
*/
|
|
397
|
-
tokens(options?: GlazeJsonOptions &
|
|
398
|
-
prefix?: boolean | Record<string, string>;
|
|
399
|
-
}): Record<string, Record<string, string>>;
|
|
427
|
+
tokens(options?: GlazeJsonOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
400
428
|
/**
|
|
401
429
|
* Export all themes as tasty style-to-state bindings.
|
|
402
430
|
* Uses `#name` color token keys and state aliases (`''`, `@dark`, etc.).
|
|
403
|
-
*
|
|
431
|
+
* Prefix defaults to `true`. Use `primary` to duplicate one theme without prefix.
|
|
404
432
|
* @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
|
|
405
433
|
*/
|
|
406
|
-
tasty(options?: GlazeTokenOptions
|
|
407
|
-
|
|
434
|
+
tasty(options?: GlazeTokenOptions & {
|
|
435
|
+
primary?: string;
|
|
436
|
+
}): Record<string, Record<string, string>>;
|
|
437
|
+
/** Export all themes as plain JSON grouped by theme name. */
|
|
408
438
|
json(options?: GlazeJsonOptions & {
|
|
409
439
|
prefix?: boolean | Record<string, string>;
|
|
410
440
|
}): Record<string, Record<string, Record<string, string>>>;
|
|
411
441
|
/** Export all themes as CSS custom property declarations. */
|
|
412
|
-
css(options?: GlazeCssOptions &
|
|
413
|
-
prefix?: boolean | Record<string, string>;
|
|
414
|
-
}): GlazeCssResult;
|
|
442
|
+
css(options?: GlazeCssOptions & GlazePaletteExportOptions): GlazeCssResult;
|
|
415
443
|
}
|
|
416
444
|
//#endregion
|
|
417
445
|
//#region src/glaze.d.ts
|
|
@@ -433,16 +461,14 @@ declare function glaze(hueOrOptions: number | {
|
|
|
433
461
|
declare namespace glaze {
|
|
434
462
|
var configure: (config: GlazeConfig) => void;
|
|
435
463
|
var palette: (themes: PaletteInput) => {
|
|
436
|
-
tokens(options?: GlazeJsonOptions &
|
|
437
|
-
|
|
464
|
+
tokens(options?: GlazeJsonOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
465
|
+
tasty(options?: GlazeTokenOptions & {
|
|
466
|
+
primary?: string;
|
|
438
467
|
}): Record<string, Record<string, string>>;
|
|
439
|
-
tasty(options?: GlazeTokenOptions): Record<string, Record<string, string>>;
|
|
440
468
|
json(options?: GlazeJsonOptions & {
|
|
441
469
|
prefix?: boolean | Record<string, string>;
|
|
442
470
|
}): Record<string, Record<string, Record<string, string>>>;
|
|
443
|
-
css(options?: GlazeCssOptions &
|
|
444
|
-
prefix?: boolean | Record<string, string>;
|
|
445
|
-
}): GlazeCssResult;
|
|
471
|
+
css(options?: GlazeCssOptions & GlazePaletteExportOptions): GlazeCssResult;
|
|
446
472
|
};
|
|
447
473
|
var from: (data: GlazeThemeExport) => GlazeTheme;
|
|
448
474
|
var color: (input: GlazeColorInput) => GlazeColorToken;
|
|
@@ -522,5 +548,5 @@ declare function formatHsl(h: number, s: number, l: number): string;
|
|
|
522
548
|
*/
|
|
523
549
|
declare function formatOklch(h: number, s: number, l: number): string;
|
|
524
550
|
//#endregion
|
|
525
|
-
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 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 };
|
|
551
|
+
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 };
|
|
526
552
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -242,6 +242,12 @@ 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
|
+
* Power-curve exponent 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
|
+
*/
|
|
250
|
+
darkCurve?: number;
|
|
245
251
|
/** State alias names for token export. */
|
|
246
252
|
states?: {
|
|
247
253
|
dark?: string;
|
|
@@ -256,6 +262,7 @@ interface GlazeConfigResolved {
|
|
|
256
262
|
lightLightness: [number, number];
|
|
257
263
|
darkLightness: [number, number];
|
|
258
264
|
darkDesaturation: number;
|
|
265
|
+
darkCurve: number;
|
|
259
266
|
states: {
|
|
260
267
|
dark: string;
|
|
261
268
|
highContrast: string;
|
|
@@ -385,33 +392,54 @@ interface GlazeCssResult {
|
|
|
385
392
|
lightContrast: string;
|
|
386
393
|
darkContrast: string;
|
|
387
394
|
}
|
|
395
|
+
/** Options shared by palette `tokens()`, `tasty()`, and `css()` exports. */
|
|
396
|
+
interface GlazePaletteExportOptions {
|
|
397
|
+
/**
|
|
398
|
+
* Prefix mode. `true` uses `"<themeName>-"`, or provide a custom map.
|
|
399
|
+
* Defaults to `true` for palette export methods.
|
|
400
|
+
* Set to `false` explicitly to disable prefixing (last-write-wins on collisions).
|
|
401
|
+
*/
|
|
402
|
+
prefix?: boolean | Record<string, string>;
|
|
403
|
+
/**
|
|
404
|
+
* Name of the primary theme. The primary theme's tokens are duplicated
|
|
405
|
+
* without prefix, providing convenient short aliases alongside the
|
|
406
|
+
* prefixed versions.
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```ts
|
|
410
|
+
* palette.tokens({ primary: 'brand' })
|
|
411
|
+
* // → { light: { 'brand-surface': '...', 'surface': '...', 'accent-surface': '...' } }
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
primary?: string;
|
|
415
|
+
}
|
|
388
416
|
interface GlazePalette {
|
|
389
417
|
/**
|
|
390
418
|
* Export all themes as a flat token map grouped by scheme variant.
|
|
419
|
+
* Prefix defaults to `true` — all tokens are prefixed with the theme name.
|
|
420
|
+
* Use `primary` to duplicate one theme's tokens without prefix.
|
|
391
421
|
*
|
|
392
422
|
* ```ts
|
|
393
|
-
* palette.tokens({
|
|
394
|
-
* // → { light: { '
|
|
423
|
+
* palette.tokens({ primary: 'brand' })
|
|
424
|
+
* // → { light: { 'brand-surface': '...', 'surface': '...', 'accent-surface': '...' } }
|
|
395
425
|
* ```
|
|
396
426
|
*/
|
|
397
|
-
tokens(options?: GlazeJsonOptions &
|
|
398
|
-
prefix?: boolean | Record<string, string>;
|
|
399
|
-
}): Record<string, Record<string, string>>;
|
|
427
|
+
tokens(options?: GlazeJsonOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
400
428
|
/**
|
|
401
429
|
* Export all themes as tasty style-to-state bindings.
|
|
402
430
|
* Uses `#name` color token keys and state aliases (`''`, `@dark`, etc.).
|
|
403
|
-
*
|
|
431
|
+
* Prefix defaults to `true`. Use `primary` to duplicate one theme without prefix.
|
|
404
432
|
* @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
|
|
405
433
|
*/
|
|
406
|
-
tasty(options?: GlazeTokenOptions
|
|
407
|
-
|
|
434
|
+
tasty(options?: GlazeTokenOptions & {
|
|
435
|
+
primary?: string;
|
|
436
|
+
}): Record<string, Record<string, string>>;
|
|
437
|
+
/** Export all themes as plain JSON grouped by theme name. */
|
|
408
438
|
json(options?: GlazeJsonOptions & {
|
|
409
439
|
prefix?: boolean | Record<string, string>;
|
|
410
440
|
}): Record<string, Record<string, Record<string, string>>>;
|
|
411
441
|
/** Export all themes as CSS custom property declarations. */
|
|
412
|
-
css(options?: GlazeCssOptions &
|
|
413
|
-
prefix?: boolean | Record<string, string>;
|
|
414
|
-
}): GlazeCssResult;
|
|
442
|
+
css(options?: GlazeCssOptions & GlazePaletteExportOptions): GlazeCssResult;
|
|
415
443
|
}
|
|
416
444
|
//#endregion
|
|
417
445
|
//#region src/glaze.d.ts
|
|
@@ -433,16 +461,14 @@ declare function glaze(hueOrOptions: number | {
|
|
|
433
461
|
declare namespace glaze {
|
|
434
462
|
var configure: (config: GlazeConfig) => void;
|
|
435
463
|
var palette: (themes: PaletteInput) => {
|
|
436
|
-
tokens(options?: GlazeJsonOptions &
|
|
437
|
-
|
|
464
|
+
tokens(options?: GlazeJsonOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
|
|
465
|
+
tasty(options?: GlazeTokenOptions & {
|
|
466
|
+
primary?: string;
|
|
438
467
|
}): Record<string, Record<string, string>>;
|
|
439
|
-
tasty(options?: GlazeTokenOptions): Record<string, Record<string, string>>;
|
|
440
468
|
json(options?: GlazeJsonOptions & {
|
|
441
469
|
prefix?: boolean | Record<string, string>;
|
|
442
470
|
}): Record<string, Record<string, Record<string, string>>>;
|
|
443
|
-
css(options?: GlazeCssOptions &
|
|
444
|
-
prefix?: boolean | Record<string, string>;
|
|
445
|
-
}): GlazeCssResult;
|
|
471
|
+
css(options?: GlazeCssOptions & GlazePaletteExportOptions): GlazeCssResult;
|
|
446
472
|
};
|
|
447
473
|
var from: (data: GlazeThemeExport) => GlazeTheme;
|
|
448
474
|
var color: (input: GlazeColorInput) => GlazeColorToken;
|
|
@@ -522,5 +548,5 @@ declare function formatHsl(h: number, s: number, l: number): string;
|
|
|
522
548
|
*/
|
|
523
549
|
declare function formatOklch(h: number, s: number, l: number): string;
|
|
524
550
|
//#endregion
|
|
525
|
-
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 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 };
|
|
551
|
+
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 };
|
|
526
552
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -468,7 +468,7 @@ function formatOklch(h, s, l) {
|
|
|
468
468
|
const C = Math.sqrt(a * a + b * b);
|
|
469
469
|
let hh = Math.atan2(b, a) * (180 / Math.PI);
|
|
470
470
|
hh = constrainAngle(hh);
|
|
471
|
-
return `oklch(${fmt$1(L, 4)} ${fmt$1(C, 4)} ${fmt$1(hh,
|
|
471
|
+
return `oklch(${fmt$1(L, 4)} ${fmt$1(C, 4)} ${fmt$1(hh, 2)})`;
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
//#endregion
|
|
@@ -618,7 +618,7 @@ function coarseScan(h, s, lo, hi, yBase, target, epsilon, maxIter) {
|
|
|
618
618
|
function findLightnessForContrast(options) {
|
|
619
619
|
const { hue, saturation, preferredLightness, baseLinearRgb, contrast: contrastInput, lightnessRange = [0, 1], epsilon = 1e-4, maxIterations = 14 } = options;
|
|
620
620
|
const target = resolveMinContrast(contrastInput);
|
|
621
|
-
const searchTarget = target * 1.
|
|
621
|
+
const searchTarget = target * 1.007;
|
|
622
622
|
const yBase = gamutClampedLuminance(baseLinearRgb);
|
|
623
623
|
const crPref = contrastRatioFromLuminance(cachedLuminance(hue, saturation, preferredLightness), yBase);
|
|
624
624
|
if (crPref >= searchTarget) return {
|
|
@@ -742,7 +742,7 @@ function searchMixBranch(lo, hi, yBase, target, epsilon, maxIter, preferred, lum
|
|
|
742
742
|
function findValueForMixContrast(options) {
|
|
743
743
|
const { preferredValue, baseLinearRgb, contrast: contrastInput, luminanceAtValue, epsilon = 1e-4, maxIterations = 20 } = options;
|
|
744
744
|
const target = resolveMinContrast(contrastInput);
|
|
745
|
-
const searchTarget = target * 1.
|
|
745
|
+
const searchTarget = target * 1.01;
|
|
746
746
|
const yBase = gamutClampedLuminance(baseLinearRgb);
|
|
747
747
|
const crPref = contrastRatioFromLuminance(luminanceAtValue(preferredValue), yBase);
|
|
748
748
|
if (crPref >= searchTarget) return {
|
|
@@ -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,23 +960,42 @@ function topoSort(defs) {
|
|
|
959
960
|
for (const name of Object.keys(defs)) visit(name);
|
|
960
961
|
return result;
|
|
961
962
|
}
|
|
962
|
-
function mapLightnessLight(l, mode) {
|
|
963
|
-
if (mode === "static") return l;
|
|
963
|
+
function mapLightnessLight(l, mode, isHighContrast) {
|
|
964
|
+
if (mode === "static" || isHighContrast) return l;
|
|
964
965
|
const [lo, hi] = globalConfig.lightLightness;
|
|
965
966
|
return l * (hi - lo) / 100 + lo;
|
|
966
967
|
}
|
|
967
|
-
function
|
|
968
|
+
function mobiusCurve(t, beta) {
|
|
969
|
+
if (beta >= 1) return t;
|
|
970
|
+
return t / (t + beta * (1 - t));
|
|
971
|
+
}
|
|
972
|
+
function mapLightnessDark(l, mode, isHighContrast) {
|
|
968
973
|
if (mode === "static") return l;
|
|
969
|
-
const
|
|
970
|
-
if (
|
|
971
|
-
|
|
974
|
+
const beta = globalConfig.darkCurve;
|
|
975
|
+
if (isHighContrast) {
|
|
976
|
+
if (mode === "fixed") return l;
|
|
977
|
+
return 100 * mobiusCurve((100 - l) / 100, beta);
|
|
978
|
+
}
|
|
979
|
+
const [darkLo, darkHi] = globalConfig.darkLightness;
|
|
980
|
+
if (mode === "fixed") return l * (darkHi - darkLo) / 100 + darkLo;
|
|
981
|
+
const [lightLo, lightHi] = globalConfig.lightLightness;
|
|
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 = globalConfig.darkCurve;
|
|
987
|
+
if (isHighContrast) return 100 * mobiusCurve((100 - lightL) / 100, beta);
|
|
988
|
+
const [lightLo, lightHi] = globalConfig.lightLightness;
|
|
989
|
+
const [darkLo, darkHi] = globalConfig.darkLightness;
|
|
990
|
+
const t = (lightHi - clamp(lightL, lightLo, lightHi)) / (lightHi - lightLo);
|
|
991
|
+
return darkLo + (darkHi - darkLo) * mobiusCurve(t, beta);
|
|
972
992
|
}
|
|
973
993
|
function mapSaturationDark(s, mode) {
|
|
974
994
|
if (mode === "static") return s;
|
|
975
995
|
return s * (1 - globalConfig.darkDesaturation);
|
|
976
996
|
}
|
|
977
|
-
function schemeLightnessRange(isDark, mode) {
|
|
978
|
-
if (mode === "static") return [0, 1];
|
|
997
|
+
function schemeLightnessRange(isDark, mode, isHighContrast) {
|
|
998
|
+
if (mode === "static" || isHighContrast) return [0, 1];
|
|
979
999
|
const [lo, hi] = isDark ? globalConfig.darkLightness : globalConfig.lightLightness;
|
|
980
1000
|
return [lo / 100, hi / 100];
|
|
981
1001
|
}
|
|
@@ -1035,26 +1055,26 @@ function resolveDependentColor(name, def, ctx, isHighContrast, isDark, effective
|
|
|
1035
1055
|
else {
|
|
1036
1056
|
const parsed = parseRelativeOrAbsolute(isHighContrast ? pairHC(rawLightness) : pairNormal(rawLightness));
|
|
1037
1057
|
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);
|
|
1058
|
+
const delta = parsed.value;
|
|
1059
|
+
if (isDark && mode === "auto") preferredL = lightMappedToDark(clamp(getSchemeVariant(baseResolved, false, isHighContrast).l * 100 + delta, 0, 100), isHighContrast);
|
|
1060
|
+
else preferredL = clamp(baseL + delta, 0, 100);
|
|
1061
|
+
} else if (isDark) preferredL = mapLightnessDark(parsed.value, mode, isHighContrast);
|
|
1062
|
+
else preferredL = mapLightnessLight(parsed.value, mode, isHighContrast);
|
|
1043
1063
|
}
|
|
1044
1064
|
const rawContrast = def.contrast;
|
|
1045
1065
|
if (rawContrast !== void 0) {
|
|
1046
1066
|
const minCr = isHighContrast ? pairHC(rawContrast) : pairNormal(rawContrast);
|
|
1047
1067
|
const effectiveSat = isDark ? mapSaturationDark(satFactor * ctx.saturation / 100, mode) : satFactor * ctx.saturation / 100;
|
|
1048
1068
|
const baseLinearRgb = okhslToLinearSrgb(baseVariant.h, baseVariant.s, baseVariant.l);
|
|
1049
|
-
const
|
|
1069
|
+
const windowRange = schemeLightnessRange(isDark, mode, isHighContrast);
|
|
1050
1070
|
return {
|
|
1051
1071
|
l: findLightnessForContrast({
|
|
1052
1072
|
hue: effectiveHue,
|
|
1053
1073
|
saturation: effectiveSat,
|
|
1054
|
-
preferredLightness: clamp(preferredL / 100,
|
|
1074
|
+
preferredLightness: clamp(preferredL / 100, windowRange[0], windowRange[1]),
|
|
1055
1075
|
baseLinearRgb,
|
|
1056
1076
|
contrast: minCr,
|
|
1057
|
-
lightnessRange
|
|
1077
|
+
lightnessRange: [0, 1]
|
|
1058
1078
|
}).lightness * 100,
|
|
1059
1079
|
satFactor
|
|
1060
1080
|
};
|
|
@@ -1091,13 +1111,13 @@ function resolveColorForScheme(name, def, ctx, isDark, isHighContrast) {
|
|
|
1091
1111
|
let finalL;
|
|
1092
1112
|
let finalSat;
|
|
1093
1113
|
if (isDark && isRoot) {
|
|
1094
|
-
finalL = mapLightnessDark(lightL, mode);
|
|
1114
|
+
finalL = mapLightnessDark(lightL, mode, isHighContrast);
|
|
1095
1115
|
finalSat = mapSaturationDark(satFactor * ctx.saturation / 100, mode);
|
|
1096
1116
|
} else if (isDark && !isRoot) {
|
|
1097
1117
|
finalL = lightL;
|
|
1098
1118
|
finalSat = mapSaturationDark(satFactor * ctx.saturation / 100, mode);
|
|
1099
1119
|
} else if (isRoot) {
|
|
1100
|
-
finalL = mapLightnessLight(lightL, mode);
|
|
1120
|
+
finalL = mapLightnessLight(lightL, mode, isHighContrast);
|
|
1101
1121
|
finalSat = satFactor * ctx.saturation / 100;
|
|
1102
1122
|
} else {
|
|
1103
1123
|
finalL = lightL;
|
|
@@ -1419,26 +1439,40 @@ function createTheme(hue, saturation, initialColors) {
|
|
|
1419
1439
|
}
|
|
1420
1440
|
};
|
|
1421
1441
|
}
|
|
1422
|
-
function resolvePrefix(options, themeName) {
|
|
1423
|
-
|
|
1424
|
-
if (
|
|
1442
|
+
function resolvePrefix(options, themeName, defaultPrefix = false) {
|
|
1443
|
+
const prefix = options?.prefix ?? defaultPrefix;
|
|
1444
|
+
if (prefix === true) return `${themeName}-`;
|
|
1445
|
+
if (typeof prefix === "object" && prefix !== null) return prefix[themeName] ?? `${themeName}-`;
|
|
1425
1446
|
return "";
|
|
1426
1447
|
}
|
|
1448
|
+
function validatePrimaryTheme(primary, themes) {
|
|
1449
|
+
if (primary !== void 0 && !(primary in themes)) {
|
|
1450
|
+
const available = Object.keys(themes).join(", ");
|
|
1451
|
+
throw new Error(`glaze: primary theme "${primary}" not found in palette. Available: ${available}.`);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1427
1454
|
function createPalette(themes) {
|
|
1428
1455
|
return {
|
|
1429
1456
|
tokens(options) {
|
|
1457
|
+
validatePrimaryTheme(options?.primary, themes);
|
|
1430
1458
|
const modes = resolveModes(options?.modes);
|
|
1431
1459
|
const allTokens = {};
|
|
1432
1460
|
for (const [themeName, theme] of Object.entries(themes)) {
|
|
1433
|
-
const
|
|
1461
|
+
const resolved = theme.resolve();
|
|
1462
|
+
const tokens = buildFlatTokenMap(resolved, resolvePrefix(options, themeName, true), modes, options?.format);
|
|
1434
1463
|
for (const variant of Object.keys(tokens)) {
|
|
1435
1464
|
if (!allTokens[variant]) allTokens[variant] = {};
|
|
1436
1465
|
Object.assign(allTokens[variant], tokens[variant]);
|
|
1437
1466
|
}
|
|
1467
|
+
if (themeName === options?.primary) {
|
|
1468
|
+
const unprefixed = buildFlatTokenMap(resolved, "", modes, options?.format);
|
|
1469
|
+
for (const variant of Object.keys(unprefixed)) Object.assign(allTokens[variant], unprefixed[variant]);
|
|
1470
|
+
}
|
|
1438
1471
|
}
|
|
1439
1472
|
return allTokens;
|
|
1440
1473
|
},
|
|
1441
1474
|
tasty(options) {
|
|
1475
|
+
validatePrimaryTheme(options?.primary, themes);
|
|
1442
1476
|
const states = {
|
|
1443
1477
|
dark: options?.states?.dark ?? globalConfig.states.dark,
|
|
1444
1478
|
highContrast: options?.states?.highContrast ?? globalConfig.states.highContrast
|
|
@@ -1446,8 +1480,13 @@ function createPalette(themes) {
|
|
|
1446
1480
|
const modes = resolveModes(options?.modes);
|
|
1447
1481
|
const allTokens = {};
|
|
1448
1482
|
for (const [themeName, theme] of Object.entries(themes)) {
|
|
1449
|
-
const
|
|
1483
|
+
const resolved = theme.resolve();
|
|
1484
|
+
const tokens = buildTokenMap(resolved, resolvePrefix(options, themeName, true), states, modes, options?.format);
|
|
1450
1485
|
Object.assign(allTokens, tokens);
|
|
1486
|
+
if (themeName === options?.primary) {
|
|
1487
|
+
const unprefixed = buildTokenMap(resolved, "", states, modes, options?.format);
|
|
1488
|
+
Object.assign(allTokens, unprefixed);
|
|
1489
|
+
}
|
|
1451
1490
|
}
|
|
1452
1491
|
return allTokens;
|
|
1453
1492
|
},
|
|
@@ -1458,6 +1497,7 @@ function createPalette(themes) {
|
|
|
1458
1497
|
return result;
|
|
1459
1498
|
},
|
|
1460
1499
|
css(options) {
|
|
1500
|
+
validatePrimaryTheme(options?.primary, themes);
|
|
1461
1501
|
const suffix = options?.suffix ?? "-color";
|
|
1462
1502
|
const format = options?.format ?? "rgb";
|
|
1463
1503
|
const allLines = {
|
|
@@ -1467,13 +1507,23 @@ function createPalette(themes) {
|
|
|
1467
1507
|
darkContrast: []
|
|
1468
1508
|
};
|
|
1469
1509
|
for (const [themeName, theme] of Object.entries(themes)) {
|
|
1470
|
-
const
|
|
1510
|
+
const resolved = theme.resolve();
|
|
1511
|
+
const css = buildCssMap(resolved, resolvePrefix(options, themeName, true), suffix, format);
|
|
1471
1512
|
for (const key of [
|
|
1472
1513
|
"light",
|
|
1473
1514
|
"dark",
|
|
1474
1515
|
"lightContrast",
|
|
1475
1516
|
"darkContrast"
|
|
1476
1517
|
]) if (css[key]) allLines[key].push(css[key]);
|
|
1518
|
+
if (themeName === options?.primary) {
|
|
1519
|
+
const unprefixed = buildCssMap(resolved, "", suffix, format);
|
|
1520
|
+
for (const key of [
|
|
1521
|
+
"light",
|
|
1522
|
+
"dark",
|
|
1523
|
+
"lightContrast",
|
|
1524
|
+
"darkContrast"
|
|
1525
|
+
]) if (unprefixed[key]) allLines[key].push(unprefixed[key]);
|
|
1526
|
+
}
|
|
1477
1527
|
}
|
|
1478
1528
|
return {
|
|
1479
1529
|
light: allLines.light.join("\n"),
|
|
@@ -1533,6 +1583,7 @@ glaze.configure = function configure(config) {
|
|
|
1533
1583
|
lightLightness: config.lightLightness ?? globalConfig.lightLightness,
|
|
1534
1584
|
darkLightness: config.darkLightness ?? globalConfig.darkLightness,
|
|
1535
1585
|
darkDesaturation: config.darkDesaturation ?? globalConfig.darkDesaturation,
|
|
1586
|
+
darkCurve: config.darkCurve ?? globalConfig.darkCurve,
|
|
1536
1587
|
states: {
|
|
1537
1588
|
dark: config.states?.dark ?? globalConfig.states.dark,
|
|
1538
1589
|
highContrast: config.states?.highContrast ?? globalConfig.states.highContrast
|
|
@@ -1632,6 +1683,7 @@ glaze.resetConfig = function resetConfig() {
|
|
|
1632
1683
|
lightLightness: [10, 100],
|
|
1633
1684
|
darkLightness: [15, 95],
|
|
1634
1685
|
darkDesaturation: .1,
|
|
1686
|
+
darkCurve: .5,
|
|
1635
1687
|
states: {
|
|
1636
1688
|
dark: "@dark",
|
|
1637
1689
|
highContrast: "@high-contrast"
|