@ankhorage/zora 0.12.3 → 0.13.2

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +10 -4
  3. package/dist/internal/color/colorToneRecipes.d.ts +23 -0
  4. package/dist/internal/color/colorToneRecipes.d.ts.map +1 -0
  5. package/dist/internal/color/colorToneRecipes.js +139 -0
  6. package/dist/internal/color/colorToneRecipes.js.map +1 -0
  7. package/dist/internal/color/index.d.ts +2 -1
  8. package/dist/internal/color/index.d.ts.map +1 -1
  9. package/dist/internal/color/index.js +1 -0
  10. package/dist/internal/color/index.js.map +1 -1
  11. package/dist/internal/color/roleScales.d.ts +2 -1
  12. package/dist/internal/color/roleScales.d.ts.map +1 -1
  13. package/dist/internal/color/roleScales.js +33 -5
  14. package/dist/internal/color/roleScales.js.map +1 -1
  15. package/dist/internal/color/scales.d.ts +2 -0
  16. package/dist/internal/color/scales.d.ts.map +1 -1
  17. package/dist/internal/color/scales.js +16 -9
  18. package/dist/internal/color/scales.js.map +1 -1
  19. package/dist/theme/createZoraThemeConfig.js +2 -2
  20. package/dist/theme/createZoraThemeConfig.js.map +1 -1
  21. package/dist/theme/types.d.ts +6 -4
  22. package/dist/theme/types.d.ts.map +1 -1
  23. package/dist/theme/types.js +20 -1
  24. package/dist/theme/types.js.map +1 -1
  25. package/dist/theme/zoraDefaultTheme.js +1 -1
  26. package/dist/theme/zoraDefaultTheme.js.map +1 -1
  27. package/package.json +2 -2
  28. package/src/components/heading/resolveHeadingRecipe.test.ts +2 -2
  29. package/src/components/text/resolveTextRecipe.test.ts +2 -2
  30. package/src/internal/color/colorToneRecipes.test.ts +89 -0
  31. package/src/internal/color/colorToneRecipes.ts +167 -0
  32. package/src/internal/color/index.ts +9 -0
  33. package/src/internal/color/roleScales.test.ts +72 -99
  34. package/src/internal/color/roleScales.ts +36 -6
  35. package/src/internal/color/scales.ts +27 -10
  36. package/src/theme/createZoraThemeConfig.test.ts +5 -5
  37. package/src/theme/createZoraThemeConfig.ts +2 -2
  38. package/src/theme/types.ts +26 -10
  39. package/src/theme/zoraDefaultTheme.ts +1 -1
@@ -1,4 +1,6 @@
1
1
  import type { ZoraHexColor } from '../../theme/types';
2
+ import type { ZoraColorToneRecipe } from './colorToneRecipes';
3
+ import { getZoraColorToneRoleChromaFactor } from './colorToneRecipes';
2
4
  import { clampOklchToGamut, formatOklchAsHex, parseHexToOklch } from './oklch';
3
5
  import { type ZoraColorScale, type ZoraColorScaleStep } from './types';
4
6
 
@@ -13,6 +15,7 @@ export interface CreateZoraHueScaleOptions {
13
15
  hue: number;
14
16
  seedChroma: number;
15
17
  role: ZoraHueScaleRoleId;
18
+ colorToneRecipe: ZoraColorToneRecipe;
16
19
  }
17
20
 
18
21
  const PRIMARY_LIGHTNESS_BY_STEP: Record<ZoraColorScaleStep, number> = {
@@ -62,14 +65,6 @@ const MIN_PRIMARY_SCALE_CHROMA = 0.04;
62
65
  const NEUTRAL_CHROMA = 0.012;
63
66
  const DEFAULT_NEUTRAL_HUE_DEGREES = 260;
64
67
 
65
- const ROLE_CHROMA_FACTOR = {
66
- primary: 1,
67
- secondary: 0.72,
68
- accent: 0.85,
69
- highlight: 1,
70
- surfaceTint: 0.18,
71
- } satisfies Record<ZoraHueScaleRoleId, number>;
72
-
73
68
  function clampNumber(value: number, min: number, max: number): number {
74
69
  return Math.max(min, Math.min(value, max));
75
70
  }
@@ -85,12 +80,34 @@ function resolvePrimaryScaleChroma(seedChroma: number, step: ZoraColorScaleStep)
85
80
  return shouldEnforceMin ? Math.max(bounded, MIN_PRIMARY_SCALE_CHROMA) : bounded;
86
81
  }
87
82
 
83
+ function resolveRoleScaleChroma(options: {
84
+ seedChroma: number;
85
+ step: ZoraColorScaleStep;
86
+ maxChroma: number;
87
+ minMidChroma: number;
88
+ }): number {
89
+ const cappedSeedChroma = clampNumber(options.seedChroma, 0, options.maxChroma);
90
+ const multiplier = PRIMARY_CHROMA_MULTIPLIER_BY_STEP[options.step];
91
+ const scaled = cappedSeedChroma * multiplier;
92
+ const bounded = clampNumber(scaled, 0, options.maxChroma);
93
+ const shouldEnforceMin =
94
+ options.step >= 300 && options.step <= 700 && options.seedChroma >= options.minMidChroma;
95
+
96
+ return shouldEnforceMin ? Math.max(bounded, options.minMidChroma) : bounded;
97
+ }
98
+
88
99
  function resolveHueScaleChroma(
89
100
  options: CreateZoraHueScaleOptions,
90
101
  step: ZoraColorScaleStep,
91
102
  ): number {
92
- const factor = ROLE_CHROMA_FACTOR[options.role];
93
- return resolvePrimaryScaleChroma(options.seedChroma * factor, step);
103
+ const factor = getZoraColorToneRoleChromaFactor(options.colorToneRecipe, options.role);
104
+
105
+ return resolveRoleScaleChroma({
106
+ seedChroma: options.seedChroma * factor,
107
+ step,
108
+ maxChroma: options.colorToneRecipe.maxChroma,
109
+ minMidChroma: options.colorToneRecipe.minMidChroma,
110
+ });
94
111
  }
95
112
 
96
113
  function createScaleEntries(options: CreateZoraColorScaleOptions): ZoraColorScale {
@@ -16,10 +16,10 @@ describe('createZoraThemeConfig', () => {
16
16
  expect(themeConfig.name).toBe('ZORA');
17
17
  expect(isSixDigitHexColor(themeConfig.light.primaryColor)).toBe(true);
18
18
  expect(themeConfig.light.harmony).toBe('analogous');
19
- expect(themeConfig.light.systemTone).toBe('jewel');
19
+ expect(themeConfig.light.colorTone).toBe('jewel');
20
20
  expect(isSixDigitHexColor(themeConfig.dark.primaryColor)).toBe(true);
21
21
  expect(themeConfig.dark.harmony).toBe('analogous');
22
- expect(themeConfig.dark.systemTone).toBe('jewel');
22
+ expect(themeConfig.dark.colorTone).toBe('jewel');
23
23
 
24
24
  expect(themeConfig.light.primaryColor).not.toBe(themeConfig.dark.primaryColor);
25
25
 
@@ -33,17 +33,17 @@ describe('createZoraThemeConfig', () => {
33
33
  id: 'studio',
34
34
  primaryColor: '#0f766e',
35
35
  harmony: 'analogous',
36
- tone: 'jewel',
36
+ colorTone: 'jewel',
37
37
  });
38
38
 
39
39
  expect(themeConfig.id).toBe('studio');
40
40
  expect(themeConfig.name).toBe('studio');
41
41
  expect(isSixDigitHexColor(themeConfig.light.primaryColor)).toBe(true);
42
42
  expect(themeConfig.light.harmony).toBe('analogous');
43
- expect(themeConfig.light.systemTone).toBe('jewel');
43
+ expect(themeConfig.light.colorTone).toBe('jewel');
44
44
  expect(isSixDigitHexColor(themeConfig.dark.primaryColor)).toBe(true);
45
45
  expect(themeConfig.dark.harmony).toBe('analogous');
46
- expect(themeConfig.dark.systemTone).toBe('jewel');
46
+ expect(themeConfig.dark.colorTone).toBe('jewel');
47
47
 
48
48
  expect(themeConfig.light.primaryColor).not.toBe(themeConfig.dark.primaryColor);
49
49
  });
@@ -11,12 +11,12 @@ export function createZoraThemeConfig(theme: ZoraTheme = zoraDefaultTheme): Them
11
11
  light: {
12
12
  primaryColor: resolveModePrimaryColor(theme.primaryColor, 'light'),
13
13
  harmony: theme.harmony,
14
- systemTone: theme.tone,
14
+ colorTone: theme.colorTone,
15
15
  },
16
16
  dark: {
17
17
  primaryColor: resolveModePrimaryColor(theme.primaryColor, 'dark'),
18
18
  harmony: theme.harmony,
19
- systemTone: theme.tone,
19
+ colorTone: theme.colorTone,
20
20
  },
21
21
  };
22
22
  }
@@ -1,4 +1,4 @@
1
- import type { ThemeConfig } from '@ankhorage/surface';
1
+ import type { ColorHarmony, ColorTone, ThemeConfig } from '@ankhorage/surface';
2
2
 
3
3
  export type ZoraThemeId = string;
4
4
 
@@ -6,22 +6,38 @@ export type ZoraThemeMode = 'light' | 'dark';
6
6
 
7
7
  export type ZoraHexColor = `#${string}`;
8
8
 
9
- export type ZoraColorHarmony =
10
- | 'monochromatic'
11
- | 'analogous'
12
- | 'complementary'
13
- | 'splitComplementary'
14
- | 'triadic'
15
- | 'tetradic';
9
+ export const ZORA_COLOR_HARMONIES = [
10
+ 'monochromatic',
11
+ 'analogous',
12
+ 'complementary',
13
+ 'splitComplementary',
14
+ 'triadic',
15
+ 'tetradic',
16
+ ] as const satisfies readonly ColorHarmony[];
16
17
 
17
- export type ZoraColorTone = 'neutral' | 'pastel' | 'earth' | 'jewel' | 'fluorescent';
18
+ export type ZoraColorHarmony = ColorHarmony;
19
+
20
+ export const ZORA_COLOR_TONES = [
21
+ 'neutral',
22
+ 'pastel',
23
+ 'earth',
24
+ 'mineral',
25
+ 'muted',
26
+ 'jewel',
27
+ 'fluorescent',
28
+ 'obsidian',
29
+ 'vaporwave',
30
+ 'monochromeAccent',
31
+ ] as const satisfies readonly ColorTone[];
32
+
33
+ export type ZoraColorTone = ColorTone;
18
34
 
19
35
  export interface ZoraTheme {
20
36
  id: ZoraThemeId;
21
37
  name?: string;
22
38
  primaryColor: ZoraHexColor;
23
39
  harmony: ZoraColorHarmony;
24
- tone: ZoraColorTone;
40
+ colorTone: ZoraColorTone;
25
41
  }
26
42
 
27
43
  export interface ZoraComputedTheme {
@@ -5,5 +5,5 @@ export const zoraDefaultTheme: ZoraTheme = {
5
5
  name: 'ZORA',
6
6
  primaryColor: '#0f766e',
7
7
  harmony: 'analogous',
8
- tone: 'jewel',
8
+ colorTone: 'jewel',
9
9
  };