@ankhorage/zora 0.16.2 → 1.0.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/CHANGELOG.md +62 -0
- package/README.md +11 -13
- package/dist/components/heading/resolveHeadingRecipe.d.ts +2 -2
- package/dist/components/heading/resolveHeadingRecipe.d.ts.map +1 -1
- package/dist/components/heading/resolveHeadingRecipe.js.map +1 -1
- package/dist/components/text/resolveTextRecipe.d.ts +2 -2
- package/dist/components/text/resolveTextRecipe.d.ts.map +1 -1
- package/dist/components/text/resolveTextRecipe.js.map +1 -1
- package/dist/patterns/theme-composer/ThemeComposer.d.ts.map +1 -1
- package/dist/patterns/theme-composer/ThemeComposer.js +10 -86
- package/dist/patterns/theme-composer/ThemeComposer.js.map +1 -1
- package/dist/patterns/theme-composer/index.d.ts +1 -1
- package/dist/patterns/theme-composer/index.d.ts.map +1 -1
- package/dist/patterns/theme-composer/index.js.map +1 -1
- package/dist/patterns/theme-composer/types.d.ts +1 -13
- package/dist/patterns/theme-composer/types.d.ts.map +1 -1
- package/dist/patterns/theme-composer/types.js.map +1 -1
- package/dist/theme/createZoraThemeConfig.d.ts +1 -1
- package/dist/theme/createZoraThemeConfig.d.ts.map +1 -1
- package/dist/theme/createZoraThemeConfig.js +5 -6
- package/dist/theme/createZoraThemeConfig.js.map +1 -1
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/types.d.ts +16 -11
- package/dist/theme/types.d.ts.map +1 -1
- package/dist/theme/types.js +1 -20
- package/dist/theme/types.js.map +1 -1
- package/dist/theme/useZoraTheme.d.ts +1 -1
- package/dist/theme/zoraDefaultTheme.js +1 -1
- package/dist/theme/zoraDefaultTheme.js.map +1 -1
- package/package.json +4 -4
- package/src/components/heading/resolveHeadingRecipe.test.ts +30 -5
- package/src/components/heading/resolveHeadingRecipe.ts +6 -6
- package/src/components/text/resolveTextRecipe.test.ts +30 -5
- package/src/components/text/resolveTextRecipe.ts +6 -6
- package/src/patterns/theme-composer/ThemeComposer.test.ts +9 -141
- package/src/patterns/theme-composer/ThemeComposer.tsx +10 -131
- package/src/patterns/theme-composer/index.ts +1 -6
- package/src/patterns/theme-composer/types.ts +1 -15
- package/src/showcaseCoverage.test.ts +14 -0
- package/src/theme/createZoraThemeConfig.test.ts +51 -26
- package/src/theme/createZoraThemeConfig.ts +7 -7
- package/src/theme/index.ts +1 -3
- package/src/theme/types.ts +22 -34
- package/src/theme/zoraDefaultTheme.ts +1 -1
- package/dist/internal/color/colorToneRecipes.d.ts +0 -23
- package/dist/internal/color/colorToneRecipes.d.ts.map +0 -1
- package/dist/internal/color/colorToneRecipes.js +0 -139
- package/dist/internal/color/colorToneRecipes.js.map +0 -1
- package/dist/internal/color/harmony.d.ts +0 -12
- package/dist/internal/color/harmony.d.ts.map +0 -1
- package/dist/internal/color/harmony.js +0 -69
- package/dist/internal/color/harmony.js.map +0 -1
- package/dist/internal/color/hue.d.ts +0 -3
- package/dist/internal/color/hue.d.ts.map +0 -1
- package/dist/internal/color/hue.js +0 -7
- package/dist/internal/color/hue.js.map +0 -1
- package/dist/internal/color/index.d.ts +0 -10
- package/dist/internal/color/index.d.ts.map +0 -1
- package/dist/internal/color/index.js +0 -10
- package/dist/internal/color/index.js.map +0 -1
- package/dist/internal/color/oklch.d.ts +0 -6
- package/dist/internal/color/oklch.d.ts.map +0 -1
- package/dist/internal/color/oklch.js +0 -50
- package/dist/internal/color/oklch.js.map +0 -1
- package/dist/internal/color/primary.d.ts +0 -3
- package/dist/internal/color/primary.d.ts.map +0 -1
- package/dist/internal/color/primary.js +0 -44
- package/dist/internal/color/primary.js.map +0 -1
- package/dist/internal/color/roleHues.d.ts +0 -15
- package/dist/internal/color/roleHues.d.ts.map +0 -1
- package/dist/internal/color/roleHues.js +0 -103
- package/dist/internal/color/roleHues.js.map +0 -1
- package/dist/internal/color/roleScales.d.ts +0 -20
- package/dist/internal/color/roleScales.d.ts.map +0 -1
- package/dist/internal/color/roleScales.js +0 -79
- package/dist/internal/color/roleScales.js.map +0 -1
- package/dist/internal/color/scales.d.ts +0 -19
- package/dist/internal/color/scales.d.ts.map +0 -1
- package/dist/internal/color/scales.js +0 -135
- package/dist/internal/color/scales.js.map +0 -1
- package/dist/internal/color/semanticTokens.d.ts +0 -28
- package/dist/internal/color/semanticTokens.d.ts.map +0 -1
- package/dist/internal/color/semanticTokens.js +0 -84
- package/dist/internal/color/semanticTokens.js.map +0 -1
- package/dist/internal/color/types.d.ts +0 -10
- package/dist/internal/color/types.d.ts.map +0 -1
- package/dist/internal/color/types.js +0 -4
- package/dist/internal/color/types.js.map +0 -1
- package/dist/patterns/theme-composer/recommendations.d.ts +0 -14
- package/dist/patterns/theme-composer/recommendations.d.ts.map +0 -1
- package/dist/patterns/theme-composer/recommendations.js +0 -58
- package/dist/patterns/theme-composer/recommendations.js.map +0 -1
- package/src/internal/color/colorToneRecipes.test.ts +0 -89
- package/src/internal/color/colorToneRecipes.ts +0 -167
- package/src/internal/color/harmony.test.ts +0 -145
- package/src/internal/color/harmony.ts +0 -96
- package/src/internal/color/hue.test.ts +0 -28
- package/src/internal/color/hue.ts +0 -7
- package/src/internal/color/index.ts +0 -44
- package/src/internal/color/oklch.ts +0 -65
- package/src/internal/color/primary.test.ts +0 -105
- package/src/internal/color/primary.ts +0 -64
- package/src/internal/color/roleHues.test.ts +0 -197
- package/src/internal/color/roleHues.ts +0 -142
- package/src/internal/color/roleScales.test.ts +0 -220
- package/src/internal/color/roleScales.ts +0 -127
- package/src/internal/color/scales.test.ts +0 -151
- package/src/internal/color/scales.ts +0 -194
- package/src/internal/color/semanticTokens.test.ts +0 -170
- package/src/internal/color/semanticTokens.ts +0 -114
- package/src/internal/color/types.ts +0 -15
- package/src/patterns/theme-composer/recommendations.ts +0 -85
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { getZoraColorToneRoleChromaFactor } from './colorToneRecipes';
|
|
2
|
-
import { clampOklchToGamut, formatOklchAsHex, parseHexToOklch } from './oklch';
|
|
3
|
-
import {} from './types';
|
|
4
|
-
const PRIMARY_LIGHTNESS_BY_STEP = {
|
|
5
|
-
50: 0.97,
|
|
6
|
-
100: 0.93,
|
|
7
|
-
200: 0.86,
|
|
8
|
-
300: 0.78,
|
|
9
|
-
400: 0.68,
|
|
10
|
-
500: 0.58,
|
|
11
|
-
600: 0.5,
|
|
12
|
-
700: 0.42,
|
|
13
|
-
800: 0.34,
|
|
14
|
-
900: 0.27,
|
|
15
|
-
950: 0.2,
|
|
16
|
-
};
|
|
17
|
-
const NEUTRAL_LIGHTNESS_BY_STEP = {
|
|
18
|
-
50: 0.98,
|
|
19
|
-
100: 0.95,
|
|
20
|
-
200: 0.89,
|
|
21
|
-
300: 0.8,
|
|
22
|
-
400: 0.68,
|
|
23
|
-
500: 0.55,
|
|
24
|
-
600: 0.44,
|
|
25
|
-
700: 0.34,
|
|
26
|
-
800: 0.25,
|
|
27
|
-
900: 0.18,
|
|
28
|
-
950: 0.12,
|
|
29
|
-
};
|
|
30
|
-
const PRIMARY_CHROMA_MULTIPLIER_BY_STEP = {
|
|
31
|
-
50: 0.2,
|
|
32
|
-
100: 0.3,
|
|
33
|
-
200: 0.45,
|
|
34
|
-
300: 0.7,
|
|
35
|
-
400: 0.95,
|
|
36
|
-
500: 1,
|
|
37
|
-
600: 0.95,
|
|
38
|
-
700: 0.85,
|
|
39
|
-
800: 0.65,
|
|
40
|
-
900: 0.45,
|
|
41
|
-
950: 0.3,
|
|
42
|
-
};
|
|
43
|
-
const MAX_PRIMARY_SCALE_CHROMA = 0.2;
|
|
44
|
-
const MIN_PRIMARY_SCALE_CHROMA = 0.04;
|
|
45
|
-
const NEUTRAL_CHROMA = 0.012;
|
|
46
|
-
const DEFAULT_NEUTRAL_HUE_DEGREES = 260;
|
|
47
|
-
function clampNumber(value, min, max) {
|
|
48
|
-
return Math.max(min, Math.min(value, max));
|
|
49
|
-
}
|
|
50
|
-
function resolvePrimaryScaleChroma(seedChroma, step) {
|
|
51
|
-
const cappedSeedChroma = clampNumber(seedChroma, 0, MAX_PRIMARY_SCALE_CHROMA);
|
|
52
|
-
const multiplier = PRIMARY_CHROMA_MULTIPLIER_BY_STEP[step];
|
|
53
|
-
const scaled = cappedSeedChroma * multiplier;
|
|
54
|
-
const bounded = clampNumber(scaled, 0, MAX_PRIMARY_SCALE_CHROMA);
|
|
55
|
-
const shouldEnforceMin = step >= 300 && step <= 700 && seedChroma >= MIN_PRIMARY_SCALE_CHROMA;
|
|
56
|
-
return shouldEnforceMin ? Math.max(bounded, MIN_PRIMARY_SCALE_CHROMA) : bounded;
|
|
57
|
-
}
|
|
58
|
-
function resolveRoleScaleChroma(options) {
|
|
59
|
-
const cappedSeedChroma = clampNumber(options.seedChroma, 0, options.maxChroma);
|
|
60
|
-
const multiplier = PRIMARY_CHROMA_MULTIPLIER_BY_STEP[options.step];
|
|
61
|
-
const scaled = cappedSeedChroma * multiplier;
|
|
62
|
-
const bounded = clampNumber(scaled, 0, options.maxChroma);
|
|
63
|
-
const shouldEnforceMin = options.step >= 300 && options.step <= 700 && options.seedChroma >= options.minMidChroma;
|
|
64
|
-
return shouldEnforceMin ? Math.max(bounded, options.minMidChroma) : bounded;
|
|
65
|
-
}
|
|
66
|
-
function resolveHueScaleChroma(options, step) {
|
|
67
|
-
const factor = getZoraColorToneRoleChromaFactor(options.colorToneRecipe, options.role);
|
|
68
|
-
return resolveRoleScaleChroma({
|
|
69
|
-
seedChroma: options.seedChroma * factor,
|
|
70
|
-
step,
|
|
71
|
-
maxChroma: options.colorToneRecipe.maxChroma,
|
|
72
|
-
minMidChroma: options.colorToneRecipe.minMidChroma,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
function createScaleEntries(options) {
|
|
76
|
-
const seed = parseHexToOklch(options.seed);
|
|
77
|
-
if (options.role === 'neutral') {
|
|
78
|
-
const hue = typeof seed.h === 'number' ? seed.h : DEFAULT_NEUTRAL_HUE_DEGREES;
|
|
79
|
-
return createScaleFromRamp({
|
|
80
|
-
hue,
|
|
81
|
-
chroma: NEUTRAL_CHROMA,
|
|
82
|
-
lightnessByStep: NEUTRAL_LIGHTNESS_BY_STEP,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
return createScaleFromRamp({
|
|
86
|
-
hue: seed.h,
|
|
87
|
-
chromaByStep: (step) => resolvePrimaryScaleChroma(seed.c, step),
|
|
88
|
-
lightnessByStep: PRIMARY_LIGHTNESS_BY_STEP,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
function createScaleColor(options, step) {
|
|
92
|
-
const lightness = options.lightnessByStep[step];
|
|
93
|
-
const chroma = typeof options.chromaByStep === 'function' ? options.chromaByStep(step) : (options.chroma ?? 0);
|
|
94
|
-
const clamped = clampOklchToGamut({
|
|
95
|
-
l: clampNumber(lightness, 0, 1),
|
|
96
|
-
c: clampNumber(chroma, 0, 1),
|
|
97
|
-
h: options.hue,
|
|
98
|
-
});
|
|
99
|
-
return formatOklchAsHex(clamped);
|
|
100
|
-
}
|
|
101
|
-
function createScaleFromRamp(options) {
|
|
102
|
-
return {
|
|
103
|
-
50: createScaleColor(options, 50),
|
|
104
|
-
100: createScaleColor(options, 100),
|
|
105
|
-
200: createScaleColor(options, 200),
|
|
106
|
-
300: createScaleColor(options, 300),
|
|
107
|
-
400: createScaleColor(options, 400),
|
|
108
|
-
500: createScaleColor(options, 500),
|
|
109
|
-
600: createScaleColor(options, 600),
|
|
110
|
-
700: createScaleColor(options, 700),
|
|
111
|
-
800: createScaleColor(options, 800),
|
|
112
|
-
900: createScaleColor(options, 900),
|
|
113
|
-
950: createScaleColor(options, 950),
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
export function createZoraColorScale(options) {
|
|
117
|
-
return createScaleEntries({
|
|
118
|
-
seed: options.seed,
|
|
119
|
-
role: options.role,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
export function createZoraPrimaryScale(seed) {
|
|
123
|
-
return createZoraColorScale({ seed, role: 'primary' });
|
|
124
|
-
}
|
|
125
|
-
export function createZoraNeutralScale(seed = '#94a3b8') {
|
|
126
|
-
return createZoraColorScale({ seed, role: 'neutral' });
|
|
127
|
-
}
|
|
128
|
-
export function createZoraHueScale(options) {
|
|
129
|
-
return createScaleFromRamp({
|
|
130
|
-
hue: options.hue,
|
|
131
|
-
chromaByStep: (step) => resolveHueScaleChroma(options, step),
|
|
132
|
-
lightnessByStep: PRIMARY_LIGHTNESS_BY_STEP,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
//# sourceMappingURL=scales.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scales.js","sourceRoot":"","sources":["../../../src/internal/color/scales.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gCAAgC,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/E,OAAO,EAAgD,MAAM,SAAS,CAAC;AAgBvE,MAAM,yBAAyB,GAAuC;IACpE,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,GAAG;CACT,CAAC;AAEF,MAAM,yBAAyB,GAAuC;IACpE,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;CACV,CAAC;AAEF,MAAM,iCAAiC,GAAuC;IAC5E,EAAE,EAAE,GAAG;IACP,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,GAAG;CACT,CAAC;AAEF,MAAM,wBAAwB,GAAG,GAAG,CAAC;AACrC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AACtC,MAAM,cAAc,GAAG,KAAK,CAAC;AAC7B,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAExC,SAAS,WAAW,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IAC1D,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,yBAAyB,CAAC,UAAkB,EAAE,IAAwB;IAC7E,MAAM,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC,EAAE,wBAAwB,CAAC,CAAC;IAC9E,MAAM,UAAU,GAAG,iCAAiC,CAAC,IAAI,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,gBAAgB,GAAG,UAAU,CAAC;IAE7C,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,wBAAwB,CAAC,CAAC;IACjE,MAAM,gBAAgB,GAAG,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,IAAI,UAAU,IAAI,wBAAwB,CAAC;IAE9F,OAAO,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAClF,CAAC;AAED,SAAS,sBAAsB,CAAC,OAK/B;IACC,MAAM,gBAAgB,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/E,MAAM,UAAU,GAAG,iCAAiC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,gBAAgB,GAAG,UAAU,CAAC;IAC7C,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1D,MAAM,gBAAgB,GACpB,OAAO,CAAC,IAAI,IAAI,GAAG,IAAI,OAAO,CAAC,IAAI,IAAI,GAAG,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC;IAE3F,OAAO,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9E,CAAC;AAED,SAAS,qBAAqB,CAC5B,OAAkC,EAClC,IAAwB;IAExB,MAAM,MAAM,GAAG,gCAAgC,CAAC,OAAO,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvF,OAAO,sBAAsB,CAAC;QAC5B,UAAU,EAAE,OAAO,CAAC,UAAU,GAAG,MAAM;QACvC,IAAI;QACJ,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,SAAS;QAC5C,YAAY,EAAE,OAAO,CAAC,eAAe,CAAC,YAAY;KACnD,CAAC,CAAC;AACL,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAoC;IAC9D,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC;QAE9E,OAAO,mBAAmB,CAAC;YACzB,GAAG;YACH,MAAM,EAAE,cAAc;YACtB,eAAe,EAAE,yBAAyB;SAC3C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,mBAAmB,CAAC;QACzB,GAAG,EAAE,IAAI,CAAC,CAAC;QACX,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;QAC/D,eAAe,EAAE,yBAAyB;KAC3C,CAAC,CAAC;AACL,CAAC;AASD,SAAS,gBAAgB,CACvB,OAAmC,EACnC,IAAwB;IAExB,MAAM,SAAS,GAAG,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,MAAM,GACV,OAAO,OAAO,CAAC,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAElG,MAAM,OAAO,GAAG,iBAAiB,CAAC;QAChC,CAAC,EAAE,WAAW,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC,EAAE,OAAO,CAAC,GAAG;KACf,CAAC,CAAC;IAEH,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAmC;IAC9D,OAAO;QACL,EAAE,EAAE,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC;QACjC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAoC;IACvE,OAAO,kBAAkB,CAAC;QACxB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;KACnB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAkB;IACvD,OAAO,oBAAoB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAqB,SAAS;IACnE,OAAO,oBAAoB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAkC;IACnE,OAAO,mBAAmB,CAAC;QACzB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC;QAC5D,eAAe,EAAE,yBAAyB;KAC3C,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { ZoraHexColor } from '../../theme/types';\nimport type { ZoraColorToneRecipe } from './colorToneRecipes';\nimport { getZoraColorToneRoleChromaFactor } from './colorToneRecipes';\nimport { clampOklchToGamut, formatOklchAsHex, parseHexToOklch } from './oklch';\nimport { type ZoraColorScale, type ZoraColorScaleStep } from './types';\n\nexport interface CreateZoraColorScaleOptions {\n seed: ZoraHexColor;\n role?: 'primary' | 'neutral';\n}\n\nexport type ZoraHueScaleRoleId = 'primary' | 'secondary' | 'accent' | 'highlight' | 'surfaceTint';\n\nexport interface CreateZoraHueScaleOptions {\n hue: number;\n seedChroma: number;\n role: ZoraHueScaleRoleId;\n colorToneRecipe: ZoraColorToneRecipe;\n}\n\nconst PRIMARY_LIGHTNESS_BY_STEP: Record<ZoraColorScaleStep, number> = {\n 50: 0.97,\n 100: 0.93,\n 200: 0.86,\n 300: 0.78,\n 400: 0.68,\n 500: 0.58,\n 600: 0.5,\n 700: 0.42,\n 800: 0.34,\n 900: 0.27,\n 950: 0.2,\n};\n\nconst NEUTRAL_LIGHTNESS_BY_STEP: Record<ZoraColorScaleStep, number> = {\n 50: 0.98,\n 100: 0.95,\n 200: 0.89,\n 300: 0.8,\n 400: 0.68,\n 500: 0.55,\n 600: 0.44,\n 700: 0.34,\n 800: 0.25,\n 900: 0.18,\n 950: 0.12,\n};\n\nconst PRIMARY_CHROMA_MULTIPLIER_BY_STEP: Record<ZoraColorScaleStep, number> = {\n 50: 0.2,\n 100: 0.3,\n 200: 0.45,\n 300: 0.7,\n 400: 0.95,\n 500: 1,\n 600: 0.95,\n 700: 0.85,\n 800: 0.65,\n 900: 0.45,\n 950: 0.3,\n};\n\nconst MAX_PRIMARY_SCALE_CHROMA = 0.2;\nconst MIN_PRIMARY_SCALE_CHROMA = 0.04;\nconst NEUTRAL_CHROMA = 0.012;\nconst DEFAULT_NEUTRAL_HUE_DEGREES = 260;\n\nfunction clampNumber(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(value, max));\n}\n\nfunction resolvePrimaryScaleChroma(seedChroma: number, step: ZoraColorScaleStep): number {\n const cappedSeedChroma = clampNumber(seedChroma, 0, MAX_PRIMARY_SCALE_CHROMA);\n const multiplier = PRIMARY_CHROMA_MULTIPLIER_BY_STEP[step];\n const scaled = cappedSeedChroma * multiplier;\n\n const bounded = clampNumber(scaled, 0, MAX_PRIMARY_SCALE_CHROMA);\n const shouldEnforceMin = step >= 300 && step <= 700 && seedChroma >= MIN_PRIMARY_SCALE_CHROMA;\n\n return shouldEnforceMin ? Math.max(bounded, MIN_PRIMARY_SCALE_CHROMA) : bounded;\n}\n\nfunction resolveRoleScaleChroma(options: {\n seedChroma: number;\n step: ZoraColorScaleStep;\n maxChroma: number;\n minMidChroma: number;\n}): number {\n const cappedSeedChroma = clampNumber(options.seedChroma, 0, options.maxChroma);\n const multiplier = PRIMARY_CHROMA_MULTIPLIER_BY_STEP[options.step];\n const scaled = cappedSeedChroma * multiplier;\n const bounded = clampNumber(scaled, 0, options.maxChroma);\n const shouldEnforceMin =\n options.step >= 300 && options.step <= 700 && options.seedChroma >= options.minMidChroma;\n\n return shouldEnforceMin ? Math.max(bounded, options.minMidChroma) : bounded;\n}\n\nfunction resolveHueScaleChroma(\n options: CreateZoraHueScaleOptions,\n step: ZoraColorScaleStep,\n): number {\n const factor = getZoraColorToneRoleChromaFactor(options.colorToneRecipe, options.role);\n\n return resolveRoleScaleChroma({\n seedChroma: options.seedChroma * factor,\n step,\n maxChroma: options.colorToneRecipe.maxChroma,\n minMidChroma: options.colorToneRecipe.minMidChroma,\n });\n}\n\nfunction createScaleEntries(options: CreateZoraColorScaleOptions): ZoraColorScale {\n const seed = parseHexToOklch(options.seed);\n\n if (options.role === 'neutral') {\n const hue = typeof seed.h === 'number' ? seed.h : DEFAULT_NEUTRAL_HUE_DEGREES;\n\n return createScaleFromRamp({\n hue,\n chroma: NEUTRAL_CHROMA,\n lightnessByStep: NEUTRAL_LIGHTNESS_BY_STEP,\n });\n }\n\n return createScaleFromRamp({\n hue: seed.h,\n chromaByStep: (step) => resolvePrimaryScaleChroma(seed.c, step),\n lightnessByStep: PRIMARY_LIGHTNESS_BY_STEP,\n });\n}\n\ninterface CreateScaleFromRampOptions {\n hue: number;\n chroma?: number;\n chromaByStep?: (step: ZoraColorScaleStep) => number;\n lightnessByStep: Record<ZoraColorScaleStep, number>;\n}\n\nfunction createScaleColor(\n options: CreateScaleFromRampOptions,\n step: ZoraColorScaleStep,\n): ZoraHexColor {\n const lightness = options.lightnessByStep[step];\n const chroma =\n typeof options.chromaByStep === 'function' ? options.chromaByStep(step) : (options.chroma ?? 0);\n\n const clamped = clampOklchToGamut({\n l: clampNumber(lightness, 0, 1),\n c: clampNumber(chroma, 0, 1),\n h: options.hue,\n });\n\n return formatOklchAsHex(clamped);\n}\n\nfunction createScaleFromRamp(options: CreateScaleFromRampOptions): ZoraColorScale {\n return {\n 50: createScaleColor(options, 50),\n 100: createScaleColor(options, 100),\n 200: createScaleColor(options, 200),\n 300: createScaleColor(options, 300),\n 400: createScaleColor(options, 400),\n 500: createScaleColor(options, 500),\n 600: createScaleColor(options, 600),\n 700: createScaleColor(options, 700),\n 800: createScaleColor(options, 800),\n 900: createScaleColor(options, 900),\n 950: createScaleColor(options, 950),\n };\n}\n\nexport function createZoraColorScale(options: CreateZoraColorScaleOptions): ZoraColorScale {\n return createScaleEntries({\n seed: options.seed,\n role: options.role,\n });\n}\n\nexport function createZoraPrimaryScale(seed: ZoraHexColor): ZoraColorScale {\n return createZoraColorScale({ seed, role: 'primary' });\n}\n\nexport function createZoraNeutralScale(seed: ZoraHexColor = '#94a3b8'): ZoraColorScale {\n return createZoraColorScale({ seed, role: 'neutral' });\n}\n\nexport function createZoraHueScale(options: CreateZoraHueScaleOptions): ZoraColorScale {\n return createScaleFromRamp({\n hue: options.hue,\n chromaByStep: (step) => resolveHueScaleChroma(options, step),\n lightnessByStep: PRIMARY_LIGHTNESS_BY_STEP,\n });\n}\n"]}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { ZoraColorTone, ZoraHexColor, ZoraThemeMode } from '../../theme/types';
|
|
2
|
-
import { type ZoraComputedRoleColorScales } from './roleScales';
|
|
3
|
-
export interface ZoraSemanticColorTokens {
|
|
4
|
-
background: ZoraHexColor;
|
|
5
|
-
surface: ZoraHexColor;
|
|
6
|
-
surfaceRaised: ZoraHexColor;
|
|
7
|
-
surfaceTint: ZoraHexColor;
|
|
8
|
-
border: ZoraHexColor;
|
|
9
|
-
text: ZoraHexColor;
|
|
10
|
-
textMuted: ZoraHexColor;
|
|
11
|
-
primary: ZoraHexColor;
|
|
12
|
-
secondary: ZoraHexColor;
|
|
13
|
-
accent: ZoraHexColor;
|
|
14
|
-
highlight: ZoraHexColor;
|
|
15
|
-
onPrimary: ZoraHexColor;
|
|
16
|
-
onAccent: ZoraHexColor;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Selects the more readable of two candidate hex colors against a given background,
|
|
20
|
-
* using OKLCH lightness as a simple contrast proxy.
|
|
21
|
-
*/
|
|
22
|
-
export declare function getReadableTextColor(background: ZoraHexColor, candidates: readonly [ZoraHexColor, ZoraHexColor]): ZoraHexColor;
|
|
23
|
-
export declare function createZoraSemanticColorTokens(options: {
|
|
24
|
-
roleScales: ZoraComputedRoleColorScales;
|
|
25
|
-
mode: ZoraThemeMode;
|
|
26
|
-
colorTone: ZoraColorTone;
|
|
27
|
-
}): ZoraSemanticColorTokens;
|
|
28
|
-
//# sourceMappingURL=semanticTokens.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"semanticTokens.d.ts","sourceRoot":"","sources":["../../../src/internal/color/semanticTokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEpF,OAAO,EAAyB,KAAK,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAEvF,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,YAAY,CAAC;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,aAAa,EAAE,YAAY,CAAC;IAC5B,WAAW,EAAE,YAAY,CAAC;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,YAAY,CAAC;IACxB,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,YAAY,CAAC;IACxB,SAAS,EAAE,YAAY,CAAC;IACxB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,YAAY,EACxB,UAAU,EAAE,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC,GAChD,YAAY,CAMd;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE;IACrD,UAAU,EAAE,2BAA2B,CAAC;IACxC,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,aAAa,CAAC;CAC1B,GAAG,uBAAuB,CA0E1B"}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { parseHexToOklch } from './oklch';
|
|
2
|
-
import { getZoraRoleColorScale } from './roleScales';
|
|
3
|
-
/**
|
|
4
|
-
* Selects the more readable of two candidate hex colors against a given background,
|
|
5
|
-
* using OKLCH lightness as a simple contrast proxy.
|
|
6
|
-
*/
|
|
7
|
-
export function getReadableTextColor(background, candidates) {
|
|
8
|
-
const bgL = parseHexToOklch(background).l;
|
|
9
|
-
const [a, b] = candidates;
|
|
10
|
-
const diffA = Math.abs(parseHexToOklch(a).l - bgL);
|
|
11
|
-
const diffB = Math.abs(parseHexToOklch(b).l - bgL);
|
|
12
|
-
return diffA >= diffB ? a : b;
|
|
13
|
-
}
|
|
14
|
-
export function createZoraSemanticColorTokens(options) {
|
|
15
|
-
// colorTone is accepted now and reserved for future per-tone step overrides
|
|
16
|
-
// (e.g. obsidian/pastel may shift surface selections differently).
|
|
17
|
-
const { roleScales, mode } = options;
|
|
18
|
-
const neutral = getZoraRoleColorScale(roleScales, 'neutral').scale;
|
|
19
|
-
const surfaceTintScale = getZoraRoleColorScale(roleScales, 'surfaceTint').scale;
|
|
20
|
-
const primaryScale = getZoraRoleColorScale(roleScales, 'primary').scale;
|
|
21
|
-
const secondaryScale = getZoraRoleColorScale(roleScales, 'secondary').scale;
|
|
22
|
-
const accentScale = getZoraRoleColorScale(roleScales, 'accent').scale;
|
|
23
|
-
const highlightScale = getZoraRoleColorScale(roleScales, 'highlight').scale;
|
|
24
|
-
if (mode === 'light') {
|
|
25
|
-
const background = neutral[50];
|
|
26
|
-
const surface = neutral[100];
|
|
27
|
-
const surfaceRaised = neutral[50];
|
|
28
|
-
const surfaceTint = surfaceTintScale[100];
|
|
29
|
-
const border = neutral[200];
|
|
30
|
-
const text = neutral[900];
|
|
31
|
-
const textMuted = neutral[700];
|
|
32
|
-
const primary = primaryScale[600];
|
|
33
|
-
const secondary = secondaryScale[600];
|
|
34
|
-
const accent = accentScale[600];
|
|
35
|
-
const highlight = highlightScale[600];
|
|
36
|
-
const onPrimary = getReadableTextColor(primary, [neutral[50], neutral[950]]);
|
|
37
|
-
const onAccent = getReadableTextColor(accent, [neutral[50], neutral[950]]);
|
|
38
|
-
return {
|
|
39
|
-
background,
|
|
40
|
-
surface,
|
|
41
|
-
surfaceRaised,
|
|
42
|
-
surfaceTint,
|
|
43
|
-
border,
|
|
44
|
-
text,
|
|
45
|
-
textMuted,
|
|
46
|
-
primary,
|
|
47
|
-
secondary,
|
|
48
|
-
accent,
|
|
49
|
-
highlight,
|
|
50
|
-
onPrimary,
|
|
51
|
-
onAccent,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
// dark mode
|
|
55
|
-
const background = neutral[950];
|
|
56
|
-
const surface = neutral[900];
|
|
57
|
-
const surfaceRaised = neutral[800];
|
|
58
|
-
const surfaceTint = surfaceTintScale[900];
|
|
59
|
-
const border = neutral[700];
|
|
60
|
-
const text = neutral[50];
|
|
61
|
-
const textMuted = neutral[300];
|
|
62
|
-
const primary = primaryScale[400];
|
|
63
|
-
const secondary = secondaryScale[400];
|
|
64
|
-
const accent = accentScale[400];
|
|
65
|
-
const highlight = highlightScale[400];
|
|
66
|
-
const onPrimary = getReadableTextColor(primary, [neutral[50], neutral[950]]);
|
|
67
|
-
const onAccent = getReadableTextColor(accent, [neutral[50], neutral[950]]);
|
|
68
|
-
return {
|
|
69
|
-
background,
|
|
70
|
-
surface,
|
|
71
|
-
surfaceRaised,
|
|
72
|
-
surfaceTint,
|
|
73
|
-
border,
|
|
74
|
-
text,
|
|
75
|
-
textMuted,
|
|
76
|
-
primary,
|
|
77
|
-
secondary,
|
|
78
|
-
accent,
|
|
79
|
-
highlight,
|
|
80
|
-
onPrimary,
|
|
81
|
-
onAccent,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
//# sourceMappingURL=semanticTokens.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"semanticTokens.js","sourceRoot":"","sources":["../../../src/internal/color/semanticTokens.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAoC,MAAM,cAAc,CAAC;AAkBvF;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAAwB,EACxB,UAAiD;IAEjD,MAAM,GAAG,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC;IAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IACnD,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,OAI7C;IACC,4EAA4E;IAC5E,mEAAmE;IACnE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAErC,MAAM,OAAO,GAAG,qBAAqB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC;IACnE,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,KAAK,CAAC;IAChF,MAAM,YAAY,GAAG,qBAAqB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC;IACxE,MAAM,cAAc,GAAG,qBAAqB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC;IAC5E,MAAM,WAAW,GAAG,qBAAqB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC;IACtE,MAAM,cAAc,GAAG,qBAAqB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC;IAE5E,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,MAAM,UAAU,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,aAAa,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7E,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAE3E,OAAO;YACL,UAAU;YACV,OAAO;YACP,aAAa;YACb,WAAW;YACX,MAAM;YACN,IAAI;YACJ,SAAS;YACT,OAAO;YACP,SAAS;YACT,MAAM;YACN,SAAS;YACT,SAAS;YACT,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,YAAY;IACZ,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IACzB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAE3E,OAAO;QACL,UAAU;QACV,OAAO;QACP,aAAa;QACb,WAAW;QACX,MAAM;QACN,IAAI;QACJ,SAAS;QACT,OAAO;QACP,SAAS;QACT,MAAM;QACN,SAAS;QACT,SAAS;QACT,QAAQ;KACT,CAAC;AACJ,CAAC","sourcesContent":["import type { ZoraColorTone, ZoraHexColor, ZoraThemeMode } from '../../theme/types';\nimport { parseHexToOklch } from './oklch';\nimport { getZoraRoleColorScale, type ZoraComputedRoleColorScales } from './roleScales';\n\nexport interface ZoraSemanticColorTokens {\n background: ZoraHexColor;\n surface: ZoraHexColor;\n surfaceRaised: ZoraHexColor;\n surfaceTint: ZoraHexColor;\n border: ZoraHexColor;\n text: ZoraHexColor;\n textMuted: ZoraHexColor;\n primary: ZoraHexColor;\n secondary: ZoraHexColor;\n accent: ZoraHexColor;\n highlight: ZoraHexColor;\n onPrimary: ZoraHexColor;\n onAccent: ZoraHexColor;\n}\n\n/**\n * Selects the more readable of two candidate hex colors against a given background,\n * using OKLCH lightness as a simple contrast proxy.\n */\nexport function getReadableTextColor(\n background: ZoraHexColor,\n candidates: readonly [ZoraHexColor, ZoraHexColor],\n): ZoraHexColor {\n const bgL = parseHexToOklch(background).l;\n const [a, b] = candidates;\n const diffA = Math.abs(parseHexToOklch(a).l - bgL);\n const diffB = Math.abs(parseHexToOklch(b).l - bgL);\n return diffA >= diffB ? a : b;\n}\n\nexport function createZoraSemanticColorTokens(options: {\n roleScales: ZoraComputedRoleColorScales;\n mode: ZoraThemeMode;\n colorTone: ZoraColorTone;\n}): ZoraSemanticColorTokens {\n // colorTone is accepted now and reserved for future per-tone step overrides\n // (e.g. obsidian/pastel may shift surface selections differently).\n const { roleScales, mode } = options;\n\n const neutral = getZoraRoleColorScale(roleScales, 'neutral').scale;\n const surfaceTintScale = getZoraRoleColorScale(roleScales, 'surfaceTint').scale;\n const primaryScale = getZoraRoleColorScale(roleScales, 'primary').scale;\n const secondaryScale = getZoraRoleColorScale(roleScales, 'secondary').scale;\n const accentScale = getZoraRoleColorScale(roleScales, 'accent').scale;\n const highlightScale = getZoraRoleColorScale(roleScales, 'highlight').scale;\n\n if (mode === 'light') {\n const background = neutral[50];\n const surface = neutral[100];\n const surfaceRaised = neutral[50];\n const surfaceTint = surfaceTintScale[100];\n const border = neutral[200];\n const text = neutral[900];\n const textMuted = neutral[700];\n const primary = primaryScale[600];\n const secondary = secondaryScale[600];\n const accent = accentScale[600];\n const highlight = highlightScale[600];\n const onPrimary = getReadableTextColor(primary, [neutral[50], neutral[950]]);\n const onAccent = getReadableTextColor(accent, [neutral[50], neutral[950]]);\n\n return {\n background,\n surface,\n surfaceRaised,\n surfaceTint,\n border,\n text,\n textMuted,\n primary,\n secondary,\n accent,\n highlight,\n onPrimary,\n onAccent,\n };\n }\n\n // dark mode\n const background = neutral[950];\n const surface = neutral[900];\n const surfaceRaised = neutral[800];\n const surfaceTint = surfaceTintScale[900];\n const border = neutral[700];\n const text = neutral[50];\n const textMuted = neutral[300];\n const primary = primaryScale[400];\n const secondary = secondaryScale[400];\n const accent = accentScale[400];\n const highlight = highlightScale[400];\n const onPrimary = getReadableTextColor(primary, [neutral[50], neutral[950]]);\n const onAccent = getReadableTextColor(accent, [neutral[50], neutral[950]]);\n\n return {\n background,\n surface,\n surfaceRaised,\n surfaceTint,\n border,\n text,\n textMuted,\n primary,\n secondary,\n accent,\n highlight,\n onPrimary,\n onAccent,\n };\n}\n"]}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ZoraHexColor } from '../../theme/types';
|
|
2
|
-
export interface ZoraOklchColor {
|
|
3
|
-
l: number;
|
|
4
|
-
c: number;
|
|
5
|
-
h: number;
|
|
6
|
-
}
|
|
7
|
-
export declare const ZORA_COLOR_SCALE_STEPS: readonly [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
|
|
8
|
-
export type ZoraColorScaleStep = (typeof ZORA_COLOR_SCALE_STEPS)[number];
|
|
9
|
-
export type ZoraColorScale = Record<ZoraColorScaleStep, ZoraHexColor>;
|
|
10
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/internal/color/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,eAAO,MAAM,sBAAsB,iEAEzB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/internal/color/types.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;CAC5C,CAAC","sourcesContent":["import type { ZoraHexColor } from '../../theme/types';\n\nexport interface ZoraOklchColor {\n l: number;\n c: number;\n h: number;\n}\n\nexport const ZORA_COLOR_SCALE_STEPS = [\n 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950,\n] as const;\n\nexport type ZoraColorScaleStep = (typeof ZORA_COLOR_SCALE_STEPS)[number];\n\nexport type ZoraColorScale = Record<ZoraColorScaleStep, ZoraHexColor>;\n"]}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { ZoraHexColor, ZoraTheme } from '../../theme/types';
|
|
2
|
-
import type { ThemeComposerAppCategory, ThemeComposerAppMood, ThemeComposerRecommendation } from './types';
|
|
3
|
-
export declare function findThemeComposerRecommendation(options: {
|
|
4
|
-
appCategory?: ThemeComposerAppCategory;
|
|
5
|
-
appMood?: ThemeComposerAppMood;
|
|
6
|
-
recommendations?: readonly ThemeComposerRecommendation[];
|
|
7
|
-
}): ThemeComposerRecommendation | undefined;
|
|
8
|
-
export declare function formatThemeComposerLabel(value: string): string;
|
|
9
|
-
export declare function hueDegreesToZoraHexColor(hueDegrees: number): ZoraHexColor;
|
|
10
|
-
export declare function createThemeFromThemeComposerRecommendation(options: {
|
|
11
|
-
value: ZoraTheme;
|
|
12
|
-
recommendation: ThemeComposerRecommendation;
|
|
13
|
-
}): ZoraTheme;
|
|
14
|
-
//# sourceMappingURL=recommendations.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"recommendations.d.ts","sourceRoot":"","sources":["../../../src/patterns/theme-composer/recommendations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EACpB,2BAA2B,EAC5B,MAAM,SAAS,CAAC;AAEjB,wBAAgB,+BAA+B,CAAC,OAAO,EAAE;IACvD,WAAW,CAAC,EAAE,wBAAwB,CAAC;IACvC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,eAAe,CAAC,EAAE,SAAS,2BAA2B,EAAE,CAAC;CAC1D,GAAG,2BAA2B,GAAG,SAAS,CAU1C;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAW9D;AAED,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CA+BzE;AAED,wBAAgB,0CAA0C,CAAC,OAAO,EAAE;IAClE,KAAK,EAAE,SAAS,CAAC;IACjB,cAAc,EAAE,2BAA2B,CAAC;CAC7C,GAAG,SAAS,CAYZ"}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
export function findThemeComposerRecommendation(options) {
|
|
2
|
-
if (options.appCategory === undefined || options.recommendations === undefined) {
|
|
3
|
-
return undefined;
|
|
4
|
-
}
|
|
5
|
-
return options.recommendations.find((recommendation) => recommendation.appCategory === options.appCategory &&
|
|
6
|
-
(options.appMood === undefined || recommendation.appMood === options.appMood));
|
|
7
|
-
}
|
|
8
|
-
export function formatThemeComposerLabel(value) {
|
|
9
|
-
const spaced = value
|
|
10
|
-
.replace(/_/g, ' ')
|
|
11
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
12
|
-
.trim();
|
|
13
|
-
if (spaced.length === 0) {
|
|
14
|
-
return value;
|
|
15
|
-
}
|
|
16
|
-
return `${spaced.slice(0, 1).toUpperCase()}${spaced.slice(1)}`;
|
|
17
|
-
}
|
|
18
|
-
export function hueDegreesToZoraHexColor(hueDegrees) {
|
|
19
|
-
const normalizedHue = ((hueDegrees % 360) + 360) % 360;
|
|
20
|
-
const chroma = 0.56;
|
|
21
|
-
const lightness = 0.46;
|
|
22
|
-
const second = chroma * (1 - Math.abs(((normalizedHue / 60) % 2) - 1));
|
|
23
|
-
const match = lightness - chroma / 2;
|
|
24
|
-
const hueSector = Math.floor(normalizedHue / 60);
|
|
25
|
-
const [redPrime, greenPrime, bluePrime] = (() => {
|
|
26
|
-
switch (hueSector) {
|
|
27
|
-
case 0:
|
|
28
|
-
return [chroma, second, 0];
|
|
29
|
-
case 1:
|
|
30
|
-
return [second, chroma, 0];
|
|
31
|
-
case 2:
|
|
32
|
-
return [0, chroma, second];
|
|
33
|
-
case 3:
|
|
34
|
-
return [0, second, chroma];
|
|
35
|
-
case 4:
|
|
36
|
-
return [second, 0, chroma];
|
|
37
|
-
default:
|
|
38
|
-
return [chroma, 0, second];
|
|
39
|
-
}
|
|
40
|
-
})();
|
|
41
|
-
const toHexChannel = (channel) => {
|
|
42
|
-
const value = Math.round(Math.min(1, Math.max(0, channel + match)) * 255);
|
|
43
|
-
return value.toString(16).padStart(2, '0');
|
|
44
|
-
};
|
|
45
|
-
return `#${toHexChannel(redPrime)}${toHexChannel(greenPrime)}${toHexChannel(bluePrime)}`;
|
|
46
|
-
}
|
|
47
|
-
export function createThemeFromThemeComposerRecommendation(options) {
|
|
48
|
-
const suggestedPrimaryColor = options.recommendation.suggestedPrimaryHueDegrees === undefined
|
|
49
|
-
? options.value.primaryColor
|
|
50
|
-
: hueDegreesToZoraHexColor(options.recommendation.suggestedPrimaryHueDegrees);
|
|
51
|
-
return {
|
|
52
|
-
...options.value,
|
|
53
|
-
primaryColor: suggestedPrimaryColor,
|
|
54
|
-
harmony: options.recommendation.suggestedHarmony,
|
|
55
|
-
colorTone: options.recommendation.suggestedColorTone,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=recommendations.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"recommendations.js","sourceRoot":"","sources":["../../../src/patterns/theme-composer/recommendations.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ZoraHexColor, ZoraTheme } from '../../theme/types';\nimport type {\n ThemeComposerAppCategory,\n ThemeComposerAppMood,\n ThemeComposerRecommendation,\n} from './types';\n\nexport function findThemeComposerRecommendation(options: {\n appCategory?: ThemeComposerAppCategory;\n appMood?: ThemeComposerAppMood;\n recommendations?: readonly ThemeComposerRecommendation[];\n}): ThemeComposerRecommendation | undefined {\n if (options.appCategory === undefined || options.recommendations === undefined) {\n return undefined;\n }\n\n return options.recommendations.find(\n (recommendation) =>\n recommendation.appCategory === options.appCategory &&\n (options.appMood === undefined || recommendation.appMood === options.appMood),\n );\n}\n\nexport function formatThemeComposerLabel(value: string): string {\n const spaced = value\n .replace(/_/g, ' ')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .trim();\n\n if (spaced.length === 0) {\n return value;\n }\n\n return `${spaced.slice(0, 1).toUpperCase()}${spaced.slice(1)}`;\n}\n\nexport function hueDegreesToZoraHexColor(hueDegrees: number): ZoraHexColor {\n const normalizedHue = ((hueDegrees % 360) + 360) % 360;\n const chroma = 0.56;\n const lightness = 0.46;\n const second = chroma * (1 - Math.abs(((normalizedHue / 60) % 2) - 1));\n const match = lightness - chroma / 2;\n\n const hueSector = Math.floor(normalizedHue / 60);\n const [redPrime, greenPrime, bluePrime] = (() => {\n switch (hueSector) {\n case 0:\n return [chroma, second, 0] as const;\n case 1:\n return [second, chroma, 0] as const;\n case 2:\n return [0, chroma, second] as const;\n case 3:\n return [0, second, chroma] as const;\n case 4:\n return [second, 0, chroma] as const;\n default:\n return [chroma, 0, second] as const;\n }\n })();\n\n const toHexChannel = (channel: number): string => {\n const value = Math.round(Math.min(1, Math.max(0, channel + match)) * 255);\n return value.toString(16).padStart(2, '0');\n };\n\n return `#${toHexChannel(redPrime)}${toHexChannel(greenPrime)}${toHexChannel(bluePrime)}`;\n}\n\nexport function createThemeFromThemeComposerRecommendation(options: {\n value: ZoraTheme;\n recommendation: ThemeComposerRecommendation;\n}): ZoraTheme {\n const suggestedPrimaryColor =\n options.recommendation.suggestedPrimaryHueDegrees === undefined\n ? options.value.primaryColor\n : hueDegreesToZoraHexColor(options.recommendation.suggestedPrimaryHueDegrees);\n\n return {\n ...options.value,\n primaryColor: suggestedPrimaryColor,\n harmony: options.recommendation.suggestedHarmony,\n colorTone: options.recommendation.suggestedColorTone,\n };\n}\n"]}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
|
|
3
|
-
import { ZORA_COLOR_TONES } from '../../theme/types';
|
|
4
|
-
import {
|
|
5
|
-
getZoraColorToneRecipe,
|
|
6
|
-
getZoraColorToneRoleChromaFactor,
|
|
7
|
-
type ZoraColorToneRecipe,
|
|
8
|
-
type ZoraHueScaleRoleId,
|
|
9
|
-
} from './index';
|
|
10
|
-
|
|
11
|
-
const HUE_BACKED_ROLES: readonly ZoraHueScaleRoleId[] = [
|
|
12
|
-
'primary',
|
|
13
|
-
'secondary',
|
|
14
|
-
'accent',
|
|
15
|
-
'highlight',
|
|
16
|
-
'surfaceTint',
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
function expectFinitePositive(value: number) {
|
|
20
|
-
expect(Number.isFinite(value)).toBe(true);
|
|
21
|
-
expect(value).toBeGreaterThan(0);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function expectSaneRecipe(recipe: ZoraColorToneRecipe) {
|
|
25
|
-
expectFinitePositive(recipe.maxChroma);
|
|
26
|
-
expectFinitePositive(recipe.minMidChroma);
|
|
27
|
-
expect(recipe.minMidChroma).toBeLessThan(recipe.maxChroma);
|
|
28
|
-
|
|
29
|
-
for (const role of HUE_BACKED_ROLES) {
|
|
30
|
-
expectFinitePositive(getZoraColorToneRoleChromaFactor(recipe, role));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
describe('color tone recipes', () => {
|
|
35
|
-
test('every ZORA color tone has a recipe', () => {
|
|
36
|
-
for (const colorTone of ZORA_COLOR_TONES) {
|
|
37
|
-
expect(getZoraColorToneRecipe(colorTone).colorTone).toBe(colorTone);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('every recipe has sane chroma values and all hue-backed role factors', () => {
|
|
42
|
-
for (const colorTone of ZORA_COLOR_TONES) {
|
|
43
|
-
expectSaneRecipe(getZoraColorToneRecipe(colorTone));
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test('records the initial background and foreground lane pairings', () => {
|
|
48
|
-
expect(getZoraColorToneRecipe('fluorescent').laneRecipe).toEqual({
|
|
49
|
-
backgroundTone: 'obsidian',
|
|
50
|
-
foregroundTone: 'fluorescent',
|
|
51
|
-
});
|
|
52
|
-
expect(getZoraColorToneRecipe('obsidian').laneRecipe).toEqual({
|
|
53
|
-
backgroundTone: 'obsidian',
|
|
54
|
-
foregroundTone: 'fluorescent',
|
|
55
|
-
});
|
|
56
|
-
expect(getZoraColorToneRecipe('pastel').laneRecipe).toEqual({
|
|
57
|
-
backgroundTone: 'pastel',
|
|
58
|
-
foregroundTone: 'jewel',
|
|
59
|
-
});
|
|
60
|
-
expect(getZoraColorToneRecipe('earth').laneRecipe).toEqual({
|
|
61
|
-
backgroundTone: 'earth',
|
|
62
|
-
foregroundTone: 'mineral',
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('surface tint remains lower intensity than foreground action roles', () => {
|
|
67
|
-
for (const colorTone of ZORA_COLOR_TONES) {
|
|
68
|
-
const recipe = getZoraColorToneRecipe(colorTone);
|
|
69
|
-
const surfaceTint = getZoraColorToneRoleChromaFactor(recipe, 'surfaceTint');
|
|
70
|
-
|
|
71
|
-
expect(surfaceTint).toBeLessThan(getZoraColorToneRoleChromaFactor(recipe, 'primary'));
|
|
72
|
-
expect(surfaceTint).toBeLessThan(getZoraColorToneRoleChromaFactor(recipe, 'accent'));
|
|
73
|
-
expect(surfaceTint).toBeLessThan(getZoraColorToneRoleChromaFactor(recipe, 'highlight'));
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('high-energy tones allow higher chroma than neutral and pastel', () => {
|
|
78
|
-
expect(getZoraColorToneRecipe('fluorescent').maxChroma).toBeGreaterThan(
|
|
79
|
-
getZoraColorToneRecipe('neutral').maxChroma,
|
|
80
|
-
);
|
|
81
|
-
expect(getZoraColorToneRecipe('fluorescent').maxChroma).toBeGreaterThan(
|
|
82
|
-
getZoraColorToneRecipe('pastel').maxChroma,
|
|
83
|
-
);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('getter is deterministic', () => {
|
|
87
|
-
expect(getZoraColorToneRecipe('jewel')).toEqual(getZoraColorToneRecipe('jewel'));
|
|
88
|
-
});
|
|
89
|
-
});
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import type { ZoraColorTone } from '../../theme/types';
|
|
2
|
-
import type { ZoraHueScaleRoleId } from './scales';
|
|
3
|
-
|
|
4
|
-
export interface ZoraColorToneLaneRecipe {
|
|
5
|
-
backgroundTone: ZoraColorTone;
|
|
6
|
-
foregroundTone: ZoraColorTone;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface ZoraColorToneRoleChromaFactors {
|
|
10
|
-
primary: number;
|
|
11
|
-
secondary: number;
|
|
12
|
-
accent: number;
|
|
13
|
-
highlight: number;
|
|
14
|
-
surfaceTint: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface ZoraColorToneRecipe {
|
|
18
|
-
colorTone: ZoraColorTone;
|
|
19
|
-
laneRecipe: ZoraColorToneLaneRecipe;
|
|
20
|
-
roleChromaFactors: ZoraColorToneRoleChromaFactors;
|
|
21
|
-
maxChroma: number;
|
|
22
|
-
minMidChroma: number;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const ZORA_COLOR_TONE_RECIPES = {
|
|
26
|
-
neutral: {
|
|
27
|
-
colorTone: 'neutral',
|
|
28
|
-
laneRecipe: { backgroundTone: 'neutral', foregroundTone: 'jewel' },
|
|
29
|
-
roleChromaFactors: {
|
|
30
|
-
primary: 0.72,
|
|
31
|
-
secondary: 0.48,
|
|
32
|
-
accent: 0.56,
|
|
33
|
-
highlight: 0.6,
|
|
34
|
-
surfaceTint: 0.12,
|
|
35
|
-
},
|
|
36
|
-
maxChroma: 0.14,
|
|
37
|
-
minMidChroma: 0.025,
|
|
38
|
-
},
|
|
39
|
-
pastel: {
|
|
40
|
-
colorTone: 'pastel',
|
|
41
|
-
laneRecipe: { backgroundTone: 'pastel', foregroundTone: 'jewel' },
|
|
42
|
-
roleChromaFactors: {
|
|
43
|
-
primary: 0.58,
|
|
44
|
-
secondary: 0.48,
|
|
45
|
-
accent: 0.55,
|
|
46
|
-
highlight: 0.62,
|
|
47
|
-
surfaceTint: 0.2,
|
|
48
|
-
},
|
|
49
|
-
maxChroma: 0.12,
|
|
50
|
-
minMidChroma: 0.02,
|
|
51
|
-
},
|
|
52
|
-
earth: {
|
|
53
|
-
colorTone: 'earth',
|
|
54
|
-
laneRecipe: { backgroundTone: 'earth', foregroundTone: 'mineral' },
|
|
55
|
-
roleChromaFactors: {
|
|
56
|
-
primary: 0.64,
|
|
57
|
-
secondary: 0.52,
|
|
58
|
-
accent: 0.58,
|
|
59
|
-
highlight: 0.6,
|
|
60
|
-
surfaceTint: 0.16,
|
|
61
|
-
},
|
|
62
|
-
maxChroma: 0.13,
|
|
63
|
-
minMidChroma: 0.022,
|
|
64
|
-
},
|
|
65
|
-
mineral: {
|
|
66
|
-
colorTone: 'mineral',
|
|
67
|
-
laneRecipe: { backgroundTone: 'mineral', foregroundTone: 'jewel' },
|
|
68
|
-
roleChromaFactors: {
|
|
69
|
-
primary: 0.7,
|
|
70
|
-
secondary: 0.56,
|
|
71
|
-
accent: 0.64,
|
|
72
|
-
highlight: 0.68,
|
|
73
|
-
surfaceTint: 0.16,
|
|
74
|
-
},
|
|
75
|
-
maxChroma: 0.14,
|
|
76
|
-
minMidChroma: 0.025,
|
|
77
|
-
},
|
|
78
|
-
muted: {
|
|
79
|
-
colorTone: 'muted',
|
|
80
|
-
laneRecipe: { backgroundTone: 'muted', foregroundTone: 'jewel' },
|
|
81
|
-
roleChromaFactors: {
|
|
82
|
-
primary: 0.6,
|
|
83
|
-
secondary: 0.5,
|
|
84
|
-
accent: 0.56,
|
|
85
|
-
highlight: 0.6,
|
|
86
|
-
surfaceTint: 0.14,
|
|
87
|
-
},
|
|
88
|
-
maxChroma: 0.12,
|
|
89
|
-
minMidChroma: 0.02,
|
|
90
|
-
},
|
|
91
|
-
jewel: {
|
|
92
|
-
colorTone: 'jewel',
|
|
93
|
-
laneRecipe: { backgroundTone: 'neutral', foregroundTone: 'jewel' },
|
|
94
|
-
roleChromaFactors: {
|
|
95
|
-
primary: 1,
|
|
96
|
-
secondary: 0.72,
|
|
97
|
-
accent: 0.85,
|
|
98
|
-
highlight: 1,
|
|
99
|
-
surfaceTint: 0.18,
|
|
100
|
-
},
|
|
101
|
-
maxChroma: 0.2,
|
|
102
|
-
minMidChroma: 0.04,
|
|
103
|
-
},
|
|
104
|
-
fluorescent: {
|
|
105
|
-
colorTone: 'fluorescent',
|
|
106
|
-
laneRecipe: { backgroundTone: 'obsidian', foregroundTone: 'fluorescent' },
|
|
107
|
-
roleChromaFactors: {
|
|
108
|
-
primary: 1.12,
|
|
109
|
-
secondary: 0.82,
|
|
110
|
-
accent: 1.05,
|
|
111
|
-
highlight: 1.18,
|
|
112
|
-
surfaceTint: 0.22,
|
|
113
|
-
},
|
|
114
|
-
maxChroma: 0.24,
|
|
115
|
-
minMidChroma: 0.045,
|
|
116
|
-
},
|
|
117
|
-
obsidian: {
|
|
118
|
-
colorTone: 'obsidian',
|
|
119
|
-
laneRecipe: { backgroundTone: 'obsidian', foregroundTone: 'fluorescent' },
|
|
120
|
-
roleChromaFactors: {
|
|
121
|
-
primary: 1.08,
|
|
122
|
-
secondary: 0.78,
|
|
123
|
-
accent: 1,
|
|
124
|
-
highlight: 1.12,
|
|
125
|
-
surfaceTint: 0.2,
|
|
126
|
-
},
|
|
127
|
-
maxChroma: 0.22,
|
|
128
|
-
minMidChroma: 0.04,
|
|
129
|
-
},
|
|
130
|
-
vaporwave: {
|
|
131
|
-
colorTone: 'vaporwave',
|
|
132
|
-
laneRecipe: { backgroundTone: 'pastel', foregroundTone: 'fluorescent' },
|
|
133
|
-
roleChromaFactors: {
|
|
134
|
-
primary: 0.95,
|
|
135
|
-
secondary: 0.72,
|
|
136
|
-
accent: 1,
|
|
137
|
-
highlight: 1.08,
|
|
138
|
-
surfaceTint: 0.24,
|
|
139
|
-
},
|
|
140
|
-
maxChroma: 0.2,
|
|
141
|
-
minMidChroma: 0.035,
|
|
142
|
-
},
|
|
143
|
-
monochromeAccent: {
|
|
144
|
-
colorTone: 'monochromeAccent',
|
|
145
|
-
laneRecipe: { backgroundTone: 'neutral', foregroundTone: 'jewel' },
|
|
146
|
-
roleChromaFactors: {
|
|
147
|
-
primary: 0.88,
|
|
148
|
-
secondary: 0.36,
|
|
149
|
-
accent: 0.95,
|
|
150
|
-
highlight: 0.88,
|
|
151
|
-
surfaceTint: 0.08,
|
|
152
|
-
},
|
|
153
|
-
maxChroma: 0.18,
|
|
154
|
-
minMidChroma: 0.035,
|
|
155
|
-
},
|
|
156
|
-
} satisfies Record<ZoraColorTone, ZoraColorToneRecipe>;
|
|
157
|
-
|
|
158
|
-
export function getZoraColorToneRecipe(colorTone: ZoraColorTone): ZoraColorToneRecipe {
|
|
159
|
-
return ZORA_COLOR_TONE_RECIPES[colorTone];
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export function getZoraColorToneRoleChromaFactor(
|
|
163
|
-
recipe: ZoraColorToneRecipe,
|
|
164
|
-
role: ZoraHueScaleRoleId,
|
|
165
|
-
): number {
|
|
166
|
-
return recipe.roleChromaFactors[role];
|
|
167
|
-
}
|