@ankhorage/surface 0.2.3 → 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.
Files changed (71) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/examples/DocsExamples.d.ts.map +1 -1
  3. package/dist/examples/DocsExamples.js +0 -2
  4. package/dist/examples/DocsExamples.js.map +1 -1
  5. package/dist/internal/resolvers/resolveControlSize.d.ts +2 -2
  6. package/dist/internal/resolvers/resolveControlSize.d.ts.map +1 -1
  7. package/dist/internal/resolvers/resolveControlSize.js.map +1 -1
  8. package/dist/internal/resolvers/resolveIconSize.d.ts +2 -2
  9. package/dist/internal/resolvers/resolveIconSize.d.ts.map +1 -1
  10. package/dist/internal/resolvers/resolveIconSize.js.map +1 -1
  11. package/dist/internal/resolvers/resolveInteractiveColors.d.ts +3 -3
  12. package/dist/internal/resolvers/resolveInteractiveColors.d.ts.map +1 -1
  13. package/dist/internal/resolvers/resolveInteractiveColors.js.map +1 -1
  14. package/dist/internal/resolvers/resolveSelectionControlColors.d.ts +2 -2
  15. package/dist/internal/resolvers/resolveSelectionControlColors.d.ts.map +1 -1
  16. package/dist/internal/resolvers/resolveSelectionControlColors.js.map +1 -1
  17. package/dist/internal/resolvers/resolveTextColor.d.ts +3 -3
  18. package/dist/internal/resolvers/resolveTextColor.d.ts.map +1 -1
  19. package/dist/internal/resolvers/resolveTextColor.js.map +1 -1
  20. package/dist/internal/resolvers/resolveTextStyles.d.ts +3 -3
  21. package/dist/internal/resolvers/resolveTextStyles.d.ts.map +1 -1
  22. package/dist/internal/resolvers/resolveTextStyles.js.map +1 -1
  23. package/dist/internal/resolvers/resolveTone.d.ts +2 -2
  24. package/dist/internal/resolvers/resolveTone.d.ts.map +1 -1
  25. package/dist/internal/resolvers/resolveTone.js.map +1 -1
  26. package/dist/layout/Container.d.ts +2 -2
  27. package/dist/layout/Container.d.ts.map +1 -1
  28. package/dist/layout/Container.js.map +1 -1
  29. package/dist/layout/helpers.d.ts +9 -9
  30. package/dist/layout/helpers.d.ts.map +1 -1
  31. package/dist/layout/helpers.js.map +1 -1
  32. package/dist/primitives/heading/resolveHeadingStyle.d.ts +2 -2
  33. package/dist/primitives/heading/resolveHeadingStyle.d.ts.map +1 -1
  34. package/dist/primitives/heading/resolveHeadingStyle.js.map +1 -1
  35. package/dist/primitives/icon/Icon.d.ts +3 -3
  36. package/dist/primitives/icon/Icon.d.ts.map +1 -1
  37. package/dist/primitives/icon/Icon.js.map +1 -1
  38. package/dist/theme/ThemeContext.d.ts +3 -3
  39. package/dist/theme/ThemeContext.d.ts.map +1 -1
  40. package/dist/theme/ThemeContext.js.map +1 -1
  41. package/dist/theme/colorEngine.d.ts +10 -11
  42. package/dist/theme/colorEngine.d.ts.map +1 -1
  43. package/dist/theme/colorEngine.js +102 -412
  44. package/dist/theme/colorEngine.js.map +1 -1
  45. package/dist/theme/createTheme.d.ts +3 -3
  46. package/dist/theme/createTheme.d.ts.map +1 -1
  47. package/dist/theme/createTheme.js +2 -4
  48. package/dist/theme/createTheme.js.map +1 -1
  49. package/dist/theme/types.d.ts +5 -17
  50. package/dist/theme/types.d.ts.map +1 -1
  51. package/dist/theme/types.js.map +1 -1
  52. package/package.json +4 -4
  53. package/src/examples/DocsExamples.tsx +0 -2
  54. package/src/internal/resolvers/resolveControlSize.ts +5 -2
  55. package/src/internal/resolvers/resolveIconSize.ts +2 -2
  56. package/src/internal/resolvers/resolveInteractiveColors.ts +3 -3
  57. package/src/internal/resolvers/resolveSelectionControlColors.ts +2 -2
  58. package/src/internal/resolvers/resolveTextColor.ts +3 -3
  59. package/src/internal/resolvers/resolveTextStyles.ts +6 -6
  60. package/src/internal/resolvers/resolveTone.ts +2 -2
  61. package/src/layout/Container.tsx +2 -2
  62. package/src/layout/helpers.test.ts +2 -2
  63. package/src/layout/helpers.ts +12 -9
  64. package/src/primitives/heading/resolveHeadingStyle.ts +2 -2
  65. package/src/primitives/icon/Icon.tsx +3 -3
  66. package/src/theme/ThemeContext.tsx +2 -2
  67. package/src/theme/colorEngine.test.ts +158 -154
  68. package/src/theme/colorEngine.ts +128 -477
  69. package/src/theme/createTheme.ts +6 -8
  70. package/src/theme/types.ts +15 -18
  71. package/src/utils/deepMerge.test.ts +0 -4
@@ -1,418 +1,94 @@
1
- import { formatHex, modeOklch, oklch, useMode } from 'culori';
2
- useMode(modeOklch);
3
- export const SCALE_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
4
- /**
5
- * Deterministic Lightness Curves (OKLCH L)
6
- */
7
- const LIGHTNESS_CURVES = {
8
- light: [0.98, 0.95, 0.9, 0.82, 0.72, 0.62, 0.52, 0.42, 0.32, 0.22, 0.15],
9
- dark: [0.12, 0.16, 0.2, 0.26, 0.34, 0.62, 0.7, 0.78, 0.86, 0.92, 0.96],
10
- };
11
- /**
12
- * Lightness anchors per internal palette kind
13
- */
14
- const ROLE_PALETTE_LIGHTNESS_ANCHORS = {
15
- grayscale: 0.62,
16
- neutral: 0.62,
17
- pastel: 0.7,
18
- earth: 0.55,
19
- mineral: 0.58,
20
- muted: 0.6,
21
- jewel: 0.62,
22
- fluorescent: 0.65,
23
- obsidian: 0.12,
24
- vaporwave: 0.7,
25
- monochromeAccent: 0.62,
26
- };
27
- /**
28
- * Chroma curve per step to prevent "tinted whites" and "glow"
29
- * Peak energy at 500, falloff at extremes.
30
- */
31
- const CHROMA_BY_STEP = [0.1, 0.18, 0.3, 0.45, 0.7, 1.0, 0.92, 0.8, 0.6, 0.4, 0.25];
32
- /**
33
- * Deterministic Chroma Anchors (OKLCH C)
34
- */
35
- const ROLE_PALETTE_CHROMA_ANCHORS = {
36
- grayscale: 0,
37
- neutral: 0.02,
38
- pastel: 0.08,
39
- earth: 0.05,
40
- mineral: 0.07,
41
- muted: 0.04,
42
- jewel: 0.16,
43
- fluorescent: 0.26,
44
- obsidian: 0.01,
45
- vaporwave: 0.2,
46
- monochromeAccent: 0.02,
47
- };
48
- /**
49
- * Chroma Hierarchy Rule
50
- */
51
- const CHROMA_HIERARCHY = {
52
- primary: 1.0,
53
- secondary: 0.7,
54
- accent: 0.4,
55
- surface: 0.1,
56
- };
57
- /**
58
- * Semantic Step Mapping
59
- */
60
- const SEMANTIC_STEPS = {
61
- light: {
62
- bg: 0, // 50
63
- bgSubtle: 1, // 100
64
- surface: 1, // 100
65
- surfaceHover: 2, // 200
66
- surfaceActive: 3, // 300
67
- border: 3, // 300
68
- borderStrong: 4, // 400
69
- divider: 2, // 200
70
- text: 9, // 900
71
- textMuted: 7, // 700
72
- textSubtle: 6, // 600
73
- solid: 5, // 500
74
- softBg: 1, // 100
75
- softHover: 2, // 200
76
- softActive: 3, // 300
77
- outline: 4, // 400
78
- },
79
- dark: {
80
- bg: 0, // 50
81
- bgSubtle: 1, // 100
82
- surface: 1, // 100
83
- surfaceHover: 2, // 200
84
- surfaceActive: 3, // 300
85
- border: 3, // 300
86
- borderStrong: 4, // 400
87
- divider: 2, // 200
88
- text: 10, // 950
89
- textMuted: 8, // 800
90
- textSubtle: 7, // 700
91
- solid: 5, // 500
92
- softBg: 1, // 100
93
- softHover: 2, // 200
94
- softActive: 3, // 300
95
- outline: 4, // 400
96
- },
97
- };
98
- export function generateColorScale(baseColor, isDark) {
99
- const scale = {};
100
- const curve = isDark ? LIGHTNESS_CURVES.dark : LIGHTNESS_CURVES.light;
101
- // Dark-mode chroma rule: reduce chroma by 25%
102
- const chromaMultiplier = isDark ? 0.75 : 1.0;
103
- const targetChroma = baseColor.c * chromaMultiplier;
104
- SCALE_STEPS.forEach((step, index) => {
105
- const lightness = curve[index];
106
- const chromaByStep = CHROMA_BY_STEP[index];
107
- if (lightness === undefined || chromaByStep === undefined) {
108
- return;
1
+ import { generateColorSwatch, generateThemeModeColors, getReadableForeground, parseHexColorOrThrow, } from '@ankhorage/color-theory';
2
+ // Fixed hex values for semantic status colors (not theme-generated)
3
+ const DANGER_HEX = parseHexColorOrThrow('#ef4444');
4
+ const SUCCESS_HEX = parseHexColorOrThrow('#22c55e');
5
+ const WARNING_HEX = parseHexColorOrThrow('#f59e0b');
6
+ export function resolveSemanticColors(generated, references) {
7
+ return Object.fromEntries(Object.entries(references).map(([token, ref]) => {
8
+ const swatch = generated.swatches[ref.role];
9
+ if (!swatch) {
10
+ throw new Error(`Missing swatch for role '${ref.role}' (token: '${token}')`);
109
11
  }
110
- // Apply chroma falloff curve per step
111
- const stepChroma = targetChroma * chromaByStep;
112
- const stepColor = { ...baseColor, l: lightness, c: stepChroma };
113
- scale[step] = formatHex(stepColor);
114
- });
115
- return scale;
12
+ return [token, swatch[ref.step]];
13
+ }));
116
14
  }
117
- /**
118
- * Deterministic Harmony Hues
119
- */
120
- function getHarmonyHues(baseHue, mode) {
121
- const h = (baseHue + 360) % 360;
122
- switch (mode) {
123
- case 'monochromatic':
124
- return [h];
125
- case 'analogous':
126
- return [h, (h - 30 + 360) % 360, (h + 30) % 360];
127
- case 'complementary':
128
- return [h, (h + 180) % 360];
129
- case 'splitComplementary':
130
- return [h, (h + 150) % 360, (h + 210) % 360];
131
- case 'triadic':
132
- return [h, (h + 120) % 360, (h + 240) % 360];
133
- case 'tetradic':
134
- return [h, (h + 90) % 360, (h + 180) % 360, (h + 270) % 360];
135
- default:
136
- return [h];
15
+ function buildNeutralSemantics(neutralSwatch, isDark) {
16
+ if (isDark) {
17
+ return {
18
+ bg: neutralSwatch[950],
19
+ bgSubtle: neutralSwatch[900],
20
+ surface: neutralSwatch[900],
21
+ surfaceHover: neutralSwatch[800],
22
+ surfaceActive: neutralSwatch[700],
23
+ border: neutralSwatch[800],
24
+ borderStrong: neutralSwatch[600],
25
+ divider: neutralSwatch[800],
26
+ text: neutralSwatch[50],
27
+ textMuted: neutralSwatch[200],
28
+ textSubtle: neutralSwatch[300],
29
+ };
137
30
  }
31
+ return {
32
+ bg: neutralSwatch[50],
33
+ bgSubtle: neutralSwatch[100],
34
+ surface: neutralSwatch[100],
35
+ surfaceHover: neutralSwatch[200],
36
+ surfaceActive: neutralSwatch[300],
37
+ border: neutralSwatch[200],
38
+ borderStrong: neutralSwatch[300],
39
+ divider: neutralSwatch[200],
40
+ text: neutralSwatch[900],
41
+ textMuted: neutralSwatch[700],
42
+ textSubtle: neutralSwatch[600],
43
+ };
138
44
  }
139
- function getColorToneRolePalette(colorTone) {
140
- switch (colorTone) {
141
- case 'pastel':
142
- return {
143
- bg: 'pastel',
144
- surface: 'pastel',
145
- primary: 'jewel',
146
- secondary: 'jewel',
147
- accent: 'jewel',
148
- highlight: 'fluorescent',
149
- };
150
- case 'earth':
151
- return {
152
- bg: 'earth',
153
- surface: 'earth',
154
- primary: 'mineral',
155
- secondary: 'mineral',
156
- accent: 'jewel',
157
- highlight: 'jewel',
158
- };
159
- case 'mineral':
160
- return {
161
- bg: 'mineral',
162
- surface: 'mineral',
163
- primary: 'jewel',
164
- secondary: 'mineral',
165
- accent: 'jewel',
166
- highlight: 'fluorescent',
167
- };
168
- case 'muted':
169
- return {
170
- bg: 'muted',
171
- surface: 'muted',
172
- primary: 'jewel',
173
- secondary: 'muted',
174
- accent: 'jewel',
175
- highlight: 'fluorescent',
176
- };
177
- case 'jewel':
178
- return {
179
- bg: 'grayscale',
180
- surface: 'grayscale',
181
- primary: 'jewel',
182
- secondary: 'jewel',
183
- accent: 'jewel',
184
- highlight: 'fluorescent',
185
- };
186
- case 'fluorescent':
187
- return {
188
- bg: 'obsidian',
189
- surface: 'obsidian',
190
- primary: 'fluorescent',
191
- secondary: 'jewel',
192
- accent: 'fluorescent',
193
- highlight: 'fluorescent',
194
- };
195
- case 'obsidian':
196
- return {
197
- bg: 'obsidian',
198
- surface: 'obsidian',
199
- primary: 'fluorescent',
200
- secondary: 'jewel',
201
- accent: 'fluorescent',
202
- highlight: 'fluorescent',
203
- };
204
- case 'vaporwave':
205
- return {
206
- bg: 'pastel',
207
- surface: 'pastel',
208
- primary: 'fluorescent',
209
- secondary: 'jewel',
210
- accent: 'fluorescent',
211
- highlight: 'fluorescent',
212
- };
213
- case 'monochromeAccent':
214
- return {
215
- bg: 'grayscale',
216
- surface: 'grayscale',
217
- primary: 'jewel',
218
- secondary: 'grayscale',
219
- accent: 'jewel',
220
- highlight: 'fluorescent',
221
- };
222
- default: // neutral
223
- return {
224
- bg: 'grayscale',
225
- surface: 'grayscale',
226
- primary: 'jewel',
227
- secondary: 'pastel',
228
- accent: 'jewel',
229
- highlight: 'fluorescent',
230
- };
45
+ function buildRoleSemantics(swatch, isDark) {
46
+ const base = swatch[500];
47
+ const { foreground: onSolidText } = getReadableForeground(base);
48
+ if (isDark) {
49
+ return {
50
+ base,
51
+ hover: swatch[400],
52
+ strong: swatch[300],
53
+ softBg: swatch[900],
54
+ softHover: swatch[800],
55
+ softActive: swatch[700],
56
+ outline: swatch[500],
57
+ onSolidText,
58
+ };
231
59
  }
232
- }
233
- /**
234
- * Simple OKLCH L-based contrast check
235
- */
236
- function getBestContrast(solidHex, neutral50, neutral950) {
237
- const solid = oklch(solidHex);
238
- const n50 = oklch(neutral50);
239
- const n950 = oklch(neutral950);
240
- if (!solid || !n50 || !n950)
241
- return neutral50;
242
- const diff50 = Math.abs(solid.l - n50.l);
243
- const diff950 = Math.abs(solid.l - n950.l);
244
- return diff50 >= diff950 ? neutral50 : neutral950;
60
+ return {
61
+ base,
62
+ hover: swatch[600],
63
+ strong: swatch[700],
64
+ softBg: swatch[100],
65
+ softHover: swatch[200],
66
+ softActive: swatch[300],
67
+ outline: swatch[400],
68
+ onSolidText,
69
+ };
245
70
  }
246
71
  export function generatePalette(config, mode = 'light') {
247
72
  const modeConfig = mode === 'dark' ? config.dark : config.light;
248
- const { primaryColor, harmony, colorTone } = modeConfig;
249
- let base = oklch(primaryColor);
250
- if (!base) {
251
- console.warn(`[colorEngine] Invalid primary color: "${primaryColor}". Falling back to default blue.`);
252
- base = oklch('#3B82F6');
253
- }
254
- const baseHue = base?.h ?? 0;
255
- const hues = getHarmonyHues(baseHue, harmony);
256
- const rolePalette = getColorToneRolePalette(colorTone);
257
- // 1. Resolve Chromas
258
- const getC = (t) => ROLE_PALETTE_CHROMA_ANCHORS[t];
259
- const getHue = (index, fallback) => hues[index] ?? fallback;
260
- const primaryChroma = getC(rolePalette.primary);
261
- const secondaryChroma = getC(rolePalette.secondary) * CHROMA_HIERARCHY.secondary;
262
- const tertiaryChroma = getC(rolePalette.accent) * CHROMA_HIERARCHY.accent;
263
- const highlightChroma = getC(rolePalette.highlight);
264
- const surfaceChroma = Math.min(0.02, getC(rolePalette.bg) * CHROMA_HIERARCHY.surface);
265
- // 2. Stable Role Assignment
266
- let pHue = getHue(0, baseHue);
267
- let sHue = getHue(0, baseHue);
268
- let aHue = getHue(0, baseHue);
269
- let hHue = harmony === 'tetradic' ? getHue(3, getHue(0, baseHue)) : (getHue(0, baseHue) + 60) % 360; // Yellow-ish offset if no tetradic
270
- switch (harmony) {
271
- case 'complementary':
272
- pHue = getHue(0, pHue);
273
- aHue = getHue(1, pHue);
274
- sHue = (getHue(0, pHue) + 30) % 360;
275
- break;
276
- case 'splitComplementary':
277
- case 'triadic':
278
- pHue = getHue(0, pHue);
279
- sHue = getHue(1, pHue);
280
- aHue = getHue(2, sHue);
281
- break;
282
- case 'tetradic':
283
- pHue = getHue(0, pHue);
284
- sHue = getHue(1, pHue);
285
- aHue = getHue(2, sHue);
286
- hHue = getHue(3, aHue);
287
- break;
288
- case 'analogous':
289
- pHue = getHue(1, pHue);
290
- sHue = getHue(0, pHue);
291
- aHue = getHue(2, sHue);
292
- break;
293
- }
294
- // 3. Build Bases with tuned lightness
295
- const getL = (t) => ROLE_PALETTE_LIGHTNESS_ANCHORS[t];
296
- const primaryBase = {
297
- mode: 'oklch',
298
- l: getL(rolePalette.primary),
299
- c: primaryChroma,
300
- h: pHue,
301
- };
302
- const secondaryBase = {
303
- mode: 'oklch',
304
- l: getL(rolePalette.secondary),
305
- c: secondaryChroma,
306
- h: sHue,
307
- };
308
- const accentBase = {
309
- mode: 'oklch',
310
- l: getL(rolePalette.accent),
311
- c: tertiaryChroma,
312
- h: aHue,
313
- };
314
- const highlightBase = {
315
- mode: 'oklch',
316
- l: getL(rolePalette.highlight),
317
- c: highlightChroma,
318
- h: hHue,
319
- };
320
- const dangerBase = {
321
- mode: 'oklch',
322
- l: 0.6,
323
- c: 0.2,
324
- h: 25,
325
- };
326
- const successBase = {
327
- mode: 'oklch',
328
- l: 0.6,
329
- c: 0.2,
330
- h: 145,
331
- };
332
- const warningBase = {
333
- mode: 'oklch',
334
- l: 0.75,
335
- c: 0.15,
336
- h: 85,
337
- };
338
- const neutralBase = surfaceChroma === 0
339
- ? { mode: 'oklch', l: 0.62, c: 0 }
340
- : { mode: 'oklch', l: 0.62, c: surfaceChroma, h: 260 };
341
- // 4. Generate Scales
342
73
  const isDark = mode === 'dark';
343
- const scales = {
344
- primary: generateColorScale(primaryBase, isDark),
345
- secondary: generateColorScale(secondaryBase, isDark),
346
- accent: generateColorScale(accentBase, isDark),
347
- highlight: generateColorScale(highlightBase, isDark),
348
- neutral: generateColorScale(neutralBase, isDark),
349
- danger: generateColorScale(dangerBase, isDark),
350
- success: generateColorScale(successBase, isDark),
351
- warning: generateColorScale(warningBase, isDark),
352
- };
353
- // 5. Mappings
354
- const steps = isDark ? SEMANTIC_STEPS.dark : SEMANTIC_STEPS.light;
355
- const getStep = (s, idx) => {
356
- const key = SCALE_STEPS[idx] ?? SCALE_STEPS[SCALE_STEPS.length - 1] ?? 950;
357
- return s[key];
358
- };
359
- const getNeutralMapping = (scale) => ({
360
- bg: getStep(scale, steps.bg),
361
- bgSubtle: getStep(scale, steps.bgSubtle),
362
- surface: getStep(scale, steps.surface),
363
- surfaceHover: getStep(scale, steps.surfaceHover),
364
- surfaceActive: getStep(scale, steps.surfaceActive),
365
- border: getStep(scale, steps.border),
366
- borderStrong: getStep(scale, steps.borderStrong),
367
- divider: getStep(scale, steps.divider),
368
- text: getStep(scale, steps.text),
369
- textMuted: getStep(scale, steps.textMuted),
370
- textSubtle: getStep(scale, steps.textSubtle),
371
- });
372
- const getColorMapping = (scale, neutralScale) => {
373
- const solid = getStep(scale, steps.solid);
374
- const softChromaLimit = 0.08;
375
- // Chroma capping for soft tokens
376
- const getSoftStep = (idx) => {
377
- const hex = getStep(scale, idx);
378
- const color = oklch(hex);
379
- if (color && color.c > softChromaLimit) {
380
- return formatHex({ ...color, c: softChromaLimit });
381
- }
382
- return hex;
383
- };
384
- return {
385
- base: solid,
386
- hover: getStep(scale, 6), // 600
387
- strong: getStep(scale, 7), // 700
388
- softBg: getSoftStep(steps.softBg),
389
- softHover: getSoftStep(steps.softHover),
390
- softActive: getSoftStep(steps.softActive),
391
- outline: getStep(scale, steps.outline),
392
- onSolidText: getBestContrast(solid, getStep(neutralScale, 0), getStep(neutralScale, 10)),
393
- };
394
- };
395
- const neutral = getNeutralMapping(scales.neutral);
396
- const brand = getColorMapping(scales.primary, scales.neutral);
397
- const neutralAction = getColorMapping(scales.neutral, scales.neutral);
398
- const danger = getColorMapping(scales.danger, scales.neutral);
399
- const success = getColorMapping(scales.success, scales.neutral);
400
- const warning = getColorMapping(scales.warning, scales.neutral);
401
- const colors = {
402
- primary: getStep(scales.primary, steps.solid),
403
- secondary: getStep(scales.secondary, steps.solid),
404
- accent: getStep(scales.accent, steps.solid),
405
- highlight: getStep(scales.highlight, steps.solid),
406
- background: neutral.bg,
407
- surface: neutral.surface,
408
- text: neutral.text,
409
- textSecondary: neutral.textMuted,
410
- border: neutral.border,
411
- error: getStep(scales.danger, steps.solid),
412
- success: getStep(scales.success, steps.solid),
413
- warning: getStep(scales.warning, steps.solid),
414
- };
415
- const surface = {
74
+ // Throws deterministically on invalid primary color
75
+ parseHexColorOrThrow(modeConfig.primaryColor);
76
+ const generated = generateThemeModeColors(modeConfig);
77
+ const { swatches } = generated;
78
+ const neutralSwatch = swatches.neutral;
79
+ const neutral = buildNeutralSemantics(neutralSwatch, isDark);
80
+ const brand = buildRoleSemantics(swatches.primary, isDark);
81
+ // Fallback to primary swatch for missing ordinal roles
82
+ const secondarySwatch = swatches.secondary ?? swatches.primary;
83
+ const tertiarySwatch = swatches.tertiary ?? swatches.primary;
84
+ const quaternarySwatch = swatches.quaternary ?? swatches.primary;
85
+ const dangerSwatch = generateColorSwatch(DANGER_HEX).swatch;
86
+ const successSwatch = generateColorSwatch(SUCCESS_HEX).swatch;
87
+ const warningSwatch = generateColorSwatch(WARNING_HEX).swatch;
88
+ const danger = buildRoleSemantics(dangerSwatch, isDark);
89
+ const success = buildRoleSemantics(successSwatch, isDark);
90
+ const warning = buildRoleSemantics(warningSwatch, isDark);
91
+ const surfaceSemantics = {
416
92
  default: neutral.surface,
417
93
  subtle: neutral.bgSubtle,
418
94
  raised: neutral.surface,
@@ -430,22 +106,36 @@ export function generatePalette(config, mode = 'light') {
430
106
  };
431
107
  const action = {
432
108
  primary: brand,
433
- neutral: neutralAction,
109
+ neutral: buildRoleSemantics(neutralSwatch, isDark),
434
110
  danger,
435
111
  };
112
+ const colors = {
113
+ primary: brand.base,
114
+ secondary: secondarySwatch[500],
115
+ accent: tertiarySwatch[500],
116
+ highlight: quaternarySwatch[500],
117
+ background: neutral.bg,
118
+ surface: neutral.surface,
119
+ text: neutral.text,
120
+ textSecondary: neutral.textMuted,
121
+ border: neutral.border,
122
+ error: danger.base,
123
+ success: success.base,
124
+ warning: warning.base,
125
+ };
436
126
  return {
437
127
  colors,
438
- scales,
128
+ swatches,
439
129
  semantics: {
440
130
  neutral,
441
131
  brand,
442
- secondary: getColorMapping(scales.secondary, scales.neutral),
443
- accent: getColorMapping(scales.accent, scales.neutral),
444
- highlight: getColorMapping(scales.highlight, scales.neutral),
132
+ secondary: buildRoleSemantics(secondarySwatch, isDark),
133
+ accent: buildRoleSemantics(tertiarySwatch, isDark),
134
+ highlight: buildRoleSemantics(quaternarySwatch, isDark),
445
135
  danger,
446
136
  success,
447
137
  warning,
448
- surface,
138
+ surface: surfaceSemantics,
449
139
  content,
450
140
  border,
451
141
  action,
@@ -1 +1 @@
1
- {"version":3,"file":"colorEngine.js","sourceRoot":"","sources":["../../src/theme/colorEngine.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatHex, modeOklch, oklch, useMode } from 'culori';\n\nimport type {\n ActionSemantics,\n BorderSemantics,\n ColorHarmony,\n ColorScale,\n ColorTone,\n ContentSemantics,\n NeutralSemantics,\n RoleSemantics,\n SurfaceSemantics,\n ThemeConfig,\n ThemeSemantics,\n} from './types';\n\nuseMode(modeOklch);\n\ninterface OklchColor {\n mode: 'oklch';\n l: number;\n c: number;\n h?: number;\n}\n\nexport const SCALE_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const;\n\ntype RolePaletteKind =\n | 'grayscale'\n | 'neutral'\n | 'pastel'\n | 'earth'\n | 'mineral'\n | 'muted'\n | 'jewel'\n | 'fluorescent'\n | 'obsidian'\n | 'vaporwave'\n | 'monochromeAccent';\n\n/**\n * Deterministic Lightness Curves (OKLCH L)\n */\nconst LIGHTNESS_CURVES = {\n light: [0.98, 0.95, 0.9, 0.82, 0.72, 0.62, 0.52, 0.42, 0.32, 0.22, 0.15],\n dark: [0.12, 0.16, 0.2, 0.26, 0.34, 0.62, 0.7, 0.78, 0.86, 0.92, 0.96],\n} as const;\n\n/**\n * Lightness anchors per internal palette kind\n */\nconst ROLE_PALETTE_LIGHTNESS_ANCHORS: Record<RolePaletteKind, number> = {\n grayscale: 0.62,\n neutral: 0.62,\n pastel: 0.7,\n earth: 0.55,\n mineral: 0.58,\n muted: 0.6,\n jewel: 0.62,\n fluorescent: 0.65,\n obsidian: 0.12,\n vaporwave: 0.7,\n monochromeAccent: 0.62,\n};\n\n/**\n * Chroma curve per step to prevent \"tinted whites\" and \"glow\"\n * Peak energy at 500, falloff at extremes.\n */\nconst CHROMA_BY_STEP = [0.1, 0.18, 0.3, 0.45, 0.7, 1.0, 0.92, 0.8, 0.6, 0.4, 0.25] as const;\n\n/**\n * Deterministic Chroma Anchors (OKLCH C)\n */\nconst ROLE_PALETTE_CHROMA_ANCHORS: Record<RolePaletteKind, number> = {\n grayscale: 0,\n neutral: 0.02,\n pastel: 0.08,\n earth: 0.05,\n mineral: 0.07,\n muted: 0.04,\n jewel: 0.16,\n fluorescent: 0.26,\n obsidian: 0.01,\n vaporwave: 0.2,\n monochromeAccent: 0.02,\n};\n\n/**\n * Chroma Hierarchy Rule\n */\nconst CHROMA_HIERARCHY = {\n primary: 1.0,\n secondary: 0.7,\n accent: 0.4,\n surface: 0.1,\n} as const;\n\n/**\n * Semantic Step Mapping\n */\nconst SEMANTIC_STEPS = {\n light: {\n bg: 0, // 50\n bgSubtle: 1, // 100\n surface: 1, // 100\n surfaceHover: 2, // 200\n surfaceActive: 3, // 300\n border: 3, // 300\n borderStrong: 4, // 400\n divider: 2, // 200\n text: 9, // 900\n textMuted: 7, // 700\n textSubtle: 6, // 600\n solid: 5, // 500\n softBg: 1, // 100\n softHover: 2, // 200\n softActive: 3, // 300\n outline: 4, // 400\n },\n dark: {\n bg: 0, // 50\n bgSubtle: 1, // 100\n surface: 1, // 100\n surfaceHover: 2, // 200\n surfaceActive: 3, // 300\n border: 3, // 300\n borderStrong: 4, // 400\n divider: 2, // 200\n text: 10, // 950\n textMuted: 8, // 800\n textSubtle: 7, // 700\n solid: 5, // 500\n softBg: 1, // 100\n softHover: 2, // 200\n softActive: 3, // 300\n outline: 4, // 400\n },\n} as const;\n\nexport function generateColorScale(baseColor: OklchColor, isDark: boolean): ColorScale {\n const scale: Partial<ColorScale> = {};\n const curve = isDark ? LIGHTNESS_CURVES.dark : LIGHTNESS_CURVES.light;\n\n // Dark-mode chroma rule: reduce chroma by 25%\n const chromaMultiplier = isDark ? 0.75 : 1.0;\n const targetChroma = baseColor.c * chromaMultiplier;\n\n SCALE_STEPS.forEach((step, index) => {\n const lightness = curve[index];\n const chromaByStep = CHROMA_BY_STEP[index];\n if (lightness === undefined || chromaByStep === undefined) {\n return;\n }\n // Apply chroma falloff curve per step\n const stepChroma = targetChroma * chromaByStep;\n const stepColor = { ...baseColor, l: lightness, c: stepChroma };\n scale[step as keyof ColorScale] = formatHex(stepColor);\n });\n\n return scale as ColorScale;\n}\n\n/**\n * Deterministic Harmony Hues\n */\nfunction getHarmonyHues(baseHue: number, mode: ColorHarmony): number[] {\n const h = (baseHue + 360) % 360;\n switch (mode) {\n case 'monochromatic':\n return [h];\n case 'analogous':\n return [h, (h - 30 + 360) % 360, (h + 30) % 360];\n case 'complementary':\n return [h, (h + 180) % 360];\n case 'splitComplementary':\n return [h, (h + 150) % 360, (h + 210) % 360];\n case 'triadic':\n return [h, (h + 120) % 360, (h + 240) % 360];\n case 'tetradic':\n return [h, (h + 90) % 360, (h + 180) % 360, (h + 270) % 360];\n default:\n return [h];\n }\n}\n\nfunction getColorToneRolePalette(colorTone: ColorTone): {\n bg: RolePaletteKind;\n surface: RolePaletteKind;\n primary: RolePaletteKind;\n secondary: RolePaletteKind;\n accent: RolePaletteKind;\n highlight: RolePaletteKind;\n} {\n switch (colorTone) {\n case 'pastel':\n return {\n bg: 'pastel',\n surface: 'pastel',\n primary: 'jewel',\n secondary: 'jewel',\n accent: 'jewel',\n highlight: 'fluorescent',\n };\n\n case 'earth':\n return {\n bg: 'earth',\n surface: 'earth',\n primary: 'mineral',\n secondary: 'mineral',\n accent: 'jewel',\n highlight: 'jewel',\n };\n\n case 'mineral':\n return {\n bg: 'mineral',\n surface: 'mineral',\n primary: 'jewel',\n secondary: 'mineral',\n accent: 'jewel',\n highlight: 'fluorescent',\n };\n\n case 'muted':\n return {\n bg: 'muted',\n surface: 'muted',\n primary: 'jewel',\n secondary: 'muted',\n accent: 'jewel',\n highlight: 'fluorescent',\n };\n\n case 'jewel':\n return {\n bg: 'grayscale',\n surface: 'grayscale',\n primary: 'jewel',\n secondary: 'jewel',\n accent: 'jewel',\n highlight: 'fluorescent',\n };\n\n case 'fluorescent':\n return {\n bg: 'obsidian',\n surface: 'obsidian',\n primary: 'fluorescent',\n secondary: 'jewel',\n accent: 'fluorescent',\n highlight: 'fluorescent',\n };\n\n case 'obsidian':\n return {\n bg: 'obsidian',\n surface: 'obsidian',\n primary: 'fluorescent',\n secondary: 'jewel',\n accent: 'fluorescent',\n highlight: 'fluorescent',\n };\n\n case 'vaporwave':\n return {\n bg: 'pastel',\n surface: 'pastel',\n primary: 'fluorescent',\n secondary: 'jewel',\n accent: 'fluorescent',\n highlight: 'fluorescent',\n };\n\n case 'monochromeAccent':\n return {\n bg: 'grayscale',\n surface: 'grayscale',\n primary: 'jewel',\n secondary: 'grayscale',\n accent: 'jewel',\n highlight: 'fluorescent',\n };\n\n default: // neutral\n return {\n bg: 'grayscale',\n surface: 'grayscale',\n primary: 'jewel',\n secondary: 'pastel',\n accent: 'jewel',\n highlight: 'fluorescent',\n };\n }\n}\n\n/**\n * Simple OKLCH L-based contrast check\n */\nfunction getBestContrast(solidHex: string, neutral50: string, neutral950: string): string {\n const solid = oklch(solidHex);\n const n50 = oklch(neutral50);\n const n950 = oklch(neutral950);\n\n if (!solid || !n50 || !n950) return neutral50;\n\n const diff50 = Math.abs(solid.l - n50.l);\n const diff950 = Math.abs(solid.l - n950.l);\n\n return diff50 >= diff950 ? neutral50 : neutral950;\n}\n\nexport function generatePalette(\n config: ThemeConfig,\n mode: 'light' | 'dark' = 'light',\n): {\n colors: Record<string, string>;\n scales: Record<string, ColorScale>;\n semantics: ThemeSemantics;\n} {\n const modeConfig = mode === 'dark' ? config.dark : config.light;\n const { primaryColor, harmony, colorTone } = modeConfig;\n\n let base = oklch(primaryColor);\n if (!base) {\n console.warn(\n `[colorEngine] Invalid primary color: \"${primaryColor}\". Falling back to default blue.`,\n );\n base = oklch('#3B82F6');\n }\n\n const baseHue = base?.h ?? 0;\n const hues = getHarmonyHues(baseHue, harmony);\n const rolePalette = getColorToneRolePalette(colorTone);\n\n // 1. Resolve Chromas\n const getC = (t: RolePaletteKind) => ROLE_PALETTE_CHROMA_ANCHORS[t];\n const getHue = (index: number, fallback: number) => hues[index] ?? fallback;\n\n const primaryChroma = getC(rolePalette.primary);\n const secondaryChroma = getC(rolePalette.secondary) * CHROMA_HIERARCHY.secondary;\n const tertiaryChroma = getC(rolePalette.accent) * CHROMA_HIERARCHY.accent;\n const highlightChroma = getC(rolePalette.highlight);\n const surfaceChroma = Math.min(0.02, getC(rolePalette.bg) * CHROMA_HIERARCHY.surface);\n\n // 2. Stable Role Assignment\n let pHue = getHue(0, baseHue);\n let sHue = getHue(0, baseHue);\n let aHue = getHue(0, baseHue);\n let hHue =\n harmony === 'tetradic' ? getHue(3, getHue(0, baseHue)) : (getHue(0, baseHue) + 60) % 360; // Yellow-ish offset if no tetradic\n\n switch (harmony) {\n case 'complementary':\n pHue = getHue(0, pHue);\n aHue = getHue(1, pHue);\n sHue = (getHue(0, pHue) + 30) % 360;\n break;\n case 'splitComplementary':\n case 'triadic':\n pHue = getHue(0, pHue);\n sHue = getHue(1, pHue);\n aHue = getHue(2, sHue);\n break;\n case 'tetradic':\n pHue = getHue(0, pHue);\n sHue = getHue(1, pHue);\n aHue = getHue(2, sHue);\n hHue = getHue(3, aHue);\n break;\n case 'analogous':\n pHue = getHue(1, pHue);\n sHue = getHue(0, pHue);\n aHue = getHue(2, sHue);\n break;\n }\n\n // 3. Build Bases with tuned lightness\n const getL = (t: RolePaletteKind) => ROLE_PALETTE_LIGHTNESS_ANCHORS[t];\n\n const primaryBase: OklchColor = {\n mode: 'oklch',\n l: getL(rolePalette.primary),\n c: primaryChroma,\n h: pHue,\n };\n const secondaryBase: OklchColor = {\n mode: 'oklch',\n l: getL(rolePalette.secondary),\n c: secondaryChroma,\n h: sHue,\n };\n const accentBase: OklchColor = {\n mode: 'oklch',\n l: getL(rolePalette.accent),\n c: tertiaryChroma,\n h: aHue,\n };\n const highlightBase: OklchColor = {\n mode: 'oklch',\n l: getL(rolePalette.highlight),\n c: highlightChroma,\n h: hHue,\n };\n const dangerBase: OklchColor = {\n mode: 'oklch',\n l: 0.6,\n c: 0.2,\n h: 25,\n };\n const successBase: OklchColor = {\n mode: 'oklch',\n l: 0.6,\n c: 0.2,\n h: 145,\n };\n const warningBase: OklchColor = {\n mode: 'oklch',\n l: 0.75,\n c: 0.15,\n h: 85,\n };\n\n const neutralBase: OklchColor =\n surfaceChroma === 0\n ? { mode: 'oklch', l: 0.62, c: 0 }\n : { mode: 'oklch', l: 0.62, c: surfaceChroma, h: 260 };\n\n // 4. Generate Scales\n const isDark = mode === 'dark';\n const scales = {\n primary: generateColorScale(primaryBase, isDark),\n secondary: generateColorScale(secondaryBase, isDark),\n accent: generateColorScale(accentBase, isDark),\n highlight: generateColorScale(highlightBase, isDark),\n neutral: generateColorScale(neutralBase, isDark),\n danger: generateColorScale(dangerBase, isDark),\n success: generateColorScale(successBase, isDark),\n warning: generateColorScale(warningBase, isDark),\n };\n\n // 5. Mappings\n const steps = isDark ? SEMANTIC_STEPS.dark : SEMANTIC_STEPS.light;\n const getStep = (s: ColorScale, idx: number) => {\n const key = SCALE_STEPS[idx] ?? SCALE_STEPS[SCALE_STEPS.length - 1] ?? 950;\n return s[key];\n };\n\n const getNeutralMapping = (scale: ColorScale): NeutralSemantics => ({\n bg: getStep(scale, steps.bg),\n bgSubtle: getStep(scale, steps.bgSubtle),\n surface: getStep(scale, steps.surface),\n surfaceHover: getStep(scale, steps.surfaceHover),\n surfaceActive: getStep(scale, steps.surfaceActive),\n border: getStep(scale, steps.border),\n borderStrong: getStep(scale, steps.borderStrong),\n divider: getStep(scale, steps.divider),\n text: getStep(scale, steps.text),\n textMuted: getStep(scale, steps.textMuted),\n textSubtle: getStep(scale, steps.textSubtle),\n });\n\n const getColorMapping = (scale: ColorScale, neutralScale: ColorScale): RoleSemantics => {\n const solid = getStep(scale, steps.solid);\n const softChromaLimit = 0.08;\n\n // Chroma capping for soft tokens\n const getSoftStep = (idx: number) => {\n const hex = getStep(scale, idx);\n const color = oklch(hex);\n if (color && color.c > softChromaLimit) {\n return formatHex({ ...color, c: softChromaLimit });\n }\n return hex;\n };\n\n return {\n base: solid,\n hover: getStep(scale, 6), // 600\n strong: getStep(scale, 7), // 700\n softBg: getSoftStep(steps.softBg),\n softHover: getSoftStep(steps.softHover),\n softActive: getSoftStep(steps.softActive),\n outline: getStep(scale, steps.outline),\n onSolidText: getBestContrast(solid, getStep(neutralScale, 0), getStep(neutralScale, 10)),\n };\n };\n\n const neutral = getNeutralMapping(scales.neutral);\n const brand = getColorMapping(scales.primary, scales.neutral);\n const neutralAction = getColorMapping(scales.neutral, scales.neutral);\n const danger = getColorMapping(scales.danger, scales.neutral);\n const success = getColorMapping(scales.success, scales.neutral);\n const warning = getColorMapping(scales.warning, scales.neutral);\n\n const colors: Record<string, string> = {\n primary: getStep(scales.primary, steps.solid),\n secondary: getStep(scales.secondary, steps.solid),\n accent: getStep(scales.accent, steps.solid),\n highlight: getStep(scales.highlight, steps.solid),\n background: neutral.bg,\n surface: neutral.surface,\n text: neutral.text,\n textSecondary: neutral.textMuted,\n border: neutral.border,\n error: getStep(scales.danger, steps.solid),\n success: getStep(scales.success, steps.solid),\n warning: getStep(scales.warning, steps.solid),\n };\n\n const surface: SurfaceSemantics = {\n default: neutral.surface,\n subtle: neutral.bgSubtle,\n raised: neutral.surface,\n };\n\n const content: ContentSemantics = {\n default: neutral.text,\n muted: neutral.textMuted,\n subtle: neutral.textSubtle,\n inverse: brand.onSolidText,\n };\n\n const border: BorderSemantics = {\n default: neutral.border,\n strong: neutral.borderStrong,\n focus: brand.outline,\n };\n\n const action: ActionSemantics = {\n primary: brand,\n neutral: neutralAction,\n danger,\n };\n\n return {\n colors,\n scales,\n semantics: {\n neutral,\n brand,\n secondary: getColorMapping(scales.secondary, scales.neutral),\n accent: getColorMapping(scales.accent, scales.neutral),\n highlight: getColorMapping(scales.highlight, scales.neutral),\n danger,\n success,\n warning,\n surface,\n content,\n border,\n action,\n },\n };\n}\n"]}
1
+ {"version":3,"file":"colorEngine.js","sourceRoot":"","sources":["../../src/theme/colorEngine.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ColorSwatch,\n GeneratedThemeModeColors,\n GeneratedThemeSwatches,\n HexColor,\n SemanticColorReferenceMap,\n SemanticColorToken,\n} from '@ankhorage/color-theory';\nimport {\n generateColorSwatch,\n generateThemeModeColors,\n getReadableForeground,\n parseHexColorOrThrow,\n} from '@ankhorage/color-theory';\nimport type { ThemeConfig } from '@ankhorage/contracts';\n\nimport type {\n ActionSemantics,\n BorderSemantics,\n ContentSemantics,\n NeutralSemantics,\n RoleSemantics,\n SurfaceSemantics,\n ThemeSemantics,\n} from './types';\n\n// Fixed hex values for semantic status colors (not theme-generated)\nconst DANGER_HEX = parseHexColorOrThrow('#ef4444');\nconst SUCCESS_HEX = parseHexColorOrThrow('#22c55e');\nconst WARNING_HEX = parseHexColorOrThrow('#f59e0b');\n\n/**\n * Surface semantic resolver: maps color-theory SemanticColorToken references\n * to hex values from the generated swatches.\n */\nexport type SurfaceSemanticColors = Record<SemanticColorToken, HexColor>;\n\nexport function resolveSemanticColors(\n generated: GeneratedThemeModeColors,\n references: SemanticColorReferenceMap,\n): SurfaceSemanticColors {\n return Object.fromEntries(\n Object.entries(references).map(([token, ref]) => {\n const swatch = generated.swatches[ref.role];\n if (!swatch) {\n throw new Error(`Missing swatch for role '${ref.role}' (token: '${token}')`);\n }\n return [token, swatch[ref.step]];\n }),\n ) as SurfaceSemanticColors;\n}\n\nfunction buildNeutralSemantics(neutralSwatch: ColorSwatch, isDark: boolean): NeutralSemantics {\n if (isDark) {\n return {\n bg: neutralSwatch[950],\n bgSubtle: neutralSwatch[900],\n surface: neutralSwatch[900],\n surfaceHover: neutralSwatch[800],\n surfaceActive: neutralSwatch[700],\n border: neutralSwatch[800],\n borderStrong: neutralSwatch[600],\n divider: neutralSwatch[800],\n text: neutralSwatch[50],\n textMuted: neutralSwatch[200],\n textSubtle: neutralSwatch[300],\n };\n }\n return {\n bg: neutralSwatch[50],\n bgSubtle: neutralSwatch[100],\n surface: neutralSwatch[100],\n surfaceHover: neutralSwatch[200],\n surfaceActive: neutralSwatch[300],\n border: neutralSwatch[200],\n borderStrong: neutralSwatch[300],\n divider: neutralSwatch[200],\n text: neutralSwatch[900],\n textMuted: neutralSwatch[700],\n textSubtle: neutralSwatch[600],\n };\n}\n\nfunction buildRoleSemantics(swatch: ColorSwatch, isDark: boolean): RoleSemantics {\n const base = swatch[500];\n const { foreground: onSolidText } = getReadableForeground(base);\n\n if (isDark) {\n return {\n base,\n hover: swatch[400],\n strong: swatch[300],\n softBg: swatch[900],\n softHover: swatch[800],\n softActive: swatch[700],\n outline: swatch[500],\n onSolidText,\n };\n }\n\n return {\n base,\n hover: swatch[600],\n strong: swatch[700],\n softBg: swatch[100],\n softHover: swatch[200],\n softActive: swatch[300],\n outline: swatch[400],\n onSolidText,\n };\n}\n\nexport function generatePalette(\n config: ThemeConfig,\n mode: 'light' | 'dark' = 'light',\n): {\n colors: Record<string, string>;\n swatches: GeneratedThemeSwatches;\n semantics: ThemeSemantics;\n} {\n const modeConfig = mode === 'dark' ? config.dark : config.light;\n const isDark = mode === 'dark';\n\n // Throws deterministically on invalid primary color\n parseHexColorOrThrow(modeConfig.primaryColor);\n\n const generated = generateThemeModeColors(modeConfig);\n\n const { swatches } = generated;\n const neutralSwatch = swatches.neutral;\n\n const neutral = buildNeutralSemantics(neutralSwatch, isDark);\n const brand = buildRoleSemantics(swatches.primary, isDark);\n\n // Fallback to primary swatch for missing ordinal roles\n const secondarySwatch = swatches.secondary ?? swatches.primary;\n const tertiarySwatch = swatches.tertiary ?? swatches.primary;\n const quaternarySwatch = swatches.quaternary ?? swatches.primary;\n\n const dangerSwatch = generateColorSwatch(DANGER_HEX).swatch;\n const successSwatch = generateColorSwatch(SUCCESS_HEX).swatch;\n const warningSwatch = generateColorSwatch(WARNING_HEX).swatch;\n\n const danger = buildRoleSemantics(dangerSwatch, isDark);\n const success = buildRoleSemantics(successSwatch, isDark);\n const warning = buildRoleSemantics(warningSwatch, isDark);\n\n const surfaceSemantics: SurfaceSemantics = {\n default: neutral.surface,\n subtle: neutral.bgSubtle,\n raised: neutral.surface,\n };\n\n const content: ContentSemantics = {\n default: neutral.text,\n muted: neutral.textMuted,\n subtle: neutral.textSubtle,\n inverse: brand.onSolidText,\n };\n\n const border: BorderSemantics = {\n default: neutral.border,\n strong: neutral.borderStrong,\n focus: brand.outline,\n };\n\n const action: ActionSemantics = {\n primary: brand,\n neutral: buildRoleSemantics(neutralSwatch, isDark),\n danger,\n };\n\n const colors: Record<string, string> = {\n primary: brand.base,\n secondary: secondarySwatch[500],\n accent: tertiarySwatch[500],\n highlight: quaternarySwatch[500],\n background: neutral.bg,\n surface: neutral.surface,\n text: neutral.text,\n textSecondary: neutral.textMuted,\n border: neutral.border,\n error: danger.base,\n success: success.base,\n warning: warning.base,\n };\n\n return {\n colors,\n swatches,\n semantics: {\n neutral,\n brand,\n secondary: buildRoleSemantics(secondarySwatch, isDark),\n accent: buildRoleSemantics(tertiarySwatch, isDark),\n highlight: buildRoleSemantics(quaternarySwatch, isDark),\n danger,\n success,\n warning,\n surface: surfaceSemantics,\n content,\n border,\n action,\n },\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
- import type { AnkhTheme, ThemeConfig, ThemeTokens } from './types';
2
- export declare const DEFAULT_TOKENS: Omit<ThemeTokens, 'colors' | 'scales' | 'semantics'>;
1
+ import type { SurfaceTheme, ThemeConfig, ThemeTokens } from './types';
2
+ export declare const DEFAULT_TOKENS: Omit<ThemeTokens, 'colors' | 'swatches' | 'semantics'>;
3
3
  export declare const DEFAULT_CONFIG: ThemeConfig;
4
- export declare function createTheme(config?: ThemeConfig, mode?: 'light' | 'dark', activeFontId?: string | null): AnkhTheme;
4
+ export declare function createTheme(config?: ThemeConfig, mode?: 'light' | 'dark', activeFontId?: string | null): SurfaceTheme;
5
5
  //# sourceMappingURL=createTheme.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createTheme.d.ts","sourceRoot":"","sources":["../../src/theme/createTheme.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAc,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/E,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CA8D/E,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAa5B,CAAC;AAaF,wBAAgB,WAAW,CACzB,MAAM,GAAE,WAA4B,EACpC,IAAI,GAAE,OAAO,GAAG,MAAgB,EAChC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,SAAS,CAuBX"}
1
+ {"version":3,"file":"createTheme.d.ts","sourceRoot":"","sources":["../../src/theme/createTheme.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAElF,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,UAAU,GAAG,WAAW,CA8DjF,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAW5B,CAAC;AAaF,wBAAgB,WAAW,CACzB,MAAM,GAAE,WAA4B,EACpC,IAAI,GAAE,OAAO,GAAG,MAAgB,EAChC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,YAAY,CAuBd"}