@clhaas/palette-kit 0.1.8 → 0.3.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 (295) hide show
  1. package/.codex/skills/color-pipeline-implementer/SKILL.md +23 -0
  2. package/.codex/skills/commit-message-crafter/SKILL.md +63 -0
  3. package/.codex/skills/commit-message-crafter/references/benchmarks.md +20 -0
  4. package/.codex/skills/contrast-solver-helper/SKILL.md +20 -0
  5. package/.codex/skills/exporters-builder/SKILL.md +20 -0
  6. package/.codex/skills/markdownlint-writer/SKILL.md +32 -0
  7. package/.codex/skills/phase-implementation-runbook/SKILL.md +92 -0
  8. package/.codex/skills/type-contract-auditor/SKILL.md +21 -0
  9. package/.github/skills/review-guide/SKILL.md +23 -0
  10. package/.github/skills/review-guide/references/review-guide-v0.3.md +629 -0
  11. package/.markdownlint.json +4 -0
  12. package/AGENTS.md +16 -0
  13. package/CHANGELOG.md +34 -0
  14. package/README.md +79 -169
  15. package/biome.json +43 -0
  16. package/dist/cli/args.d.ts +12 -0
  17. package/dist/cli/args.js +56 -0
  18. package/dist/cli/args.test.js +22 -0
  19. package/dist/cli/codegen/__snapshots__/tokens.test.js.snap +87 -0
  20. package/dist/cli/codegen/tokens.d.ts +12 -0
  21. package/dist/cli/codegen/tokens.js +139 -0
  22. package/dist/cli/codegen/tokens.test.d.ts +1 -0
  23. package/dist/cli/codegen/tokens.test.js +51 -0
  24. package/dist/cli/config.d.ts +40 -0
  25. package/dist/cli/config.js +34 -0
  26. package/dist/cli/validate.d.ts +2 -0
  27. package/dist/cli/validate.js +33 -0
  28. package/dist/cli/validate.test.d.ts +1 -0
  29. package/dist/cli/validate.test.js +40 -0
  30. package/dist/cli.js +138 -140
  31. package/dist/contrast/apca.d.ts +2 -2
  32. package/dist/contrast/apca.js +14 -4
  33. package/dist/contrast/apca.test.d.ts +1 -0
  34. package/dist/contrast/apca.test.js +16 -0
  35. package/dist/contrast/index.d.ts +4 -0
  36. package/dist/contrast/index.js +4 -0
  37. package/dist/contrast/scoring.d.ts +4 -0
  38. package/dist/contrast/scoring.js +31 -0
  39. package/dist/contrast/scoring.test.d.ts +1 -0
  40. package/dist/contrast/scoring.test.js +148 -0
  41. package/dist/contrast/solver.d.ts +13 -0
  42. package/dist/contrast/solver.js +170 -0
  43. package/dist/contrast/solver.test.d.ts +1 -0
  44. package/dist/contrast/solver.test.js +75 -0
  45. package/dist/contrast/types.d.ts +17 -0
  46. package/dist/contrast/types.js +1 -0
  47. package/dist/contrast/utils.d.ts +4 -0
  48. package/dist/contrast/utils.js +18 -0
  49. package/dist/contrast/wcag2.d.ts +3 -0
  50. package/dist/contrast/wcag2.js +19 -0
  51. package/dist/contrast/wcag2.test.d.ts +1 -0
  52. package/dist/contrast/wcag2.test.js +17 -0
  53. package/dist/core/createTheme.d.ts +35 -0
  54. package/dist/core/createTheme.js +24 -0
  55. package/dist/core/dx-helpers.test.d.ts +1 -0
  56. package/dist/core/dx-helpers.test.js +61 -0
  57. package/dist/core/index.d.ts +2 -0
  58. package/dist/core/index.js +2 -0
  59. package/dist/core/onSolid.test.d.ts +1 -0
  60. package/dist/core/onSolid.test.js +118 -0
  61. package/dist/core/qa.v1.test.d.ts +1 -0
  62. package/dist/core/qa.v1.test.js +112 -0
  63. package/dist/core/resolve.d.ts +3 -0
  64. package/dist/core/resolve.js +8 -0
  65. package/dist/core/resolve.test.d.ts +1 -0
  66. package/dist/core/resolve.test.js +89 -0
  67. package/dist/core/resolveMany.d.ts +8 -0
  68. package/dist/core/resolveMany.js +17 -0
  69. package/dist/core/tokenRegistry.d.ts +23 -0
  70. package/dist/core/tokenRegistry.js +83 -0
  71. package/dist/core/tokenRegistry.test.d.ts +1 -0
  72. package/dist/core/tokenRegistry.test.js +133 -0
  73. package/dist/engine/applyOperators.d.ts +3 -0
  74. package/dist/engine/applyOperators.js +23 -0
  75. package/dist/engine/context.d.ts +4 -0
  76. package/dist/engine/context.js +1 -0
  77. package/dist/engine/gamut.d.ts +13 -0
  78. package/dist/engine/gamut.js +101 -0
  79. package/dist/engine/gamut.test.d.ts +1 -0
  80. package/dist/engine/gamut.test.js +23 -0
  81. package/dist/engine/generateScale.d.ts +15 -0
  82. package/dist/engine/generateScale.js +29 -0
  83. package/dist/engine/generateScale.test.d.ts +1 -0
  84. package/dist/engine/generateScale.test.js +32 -0
  85. package/dist/engine/index.d.ts +8 -0
  86. package/dist/engine/index.js +4 -0
  87. package/dist/engine/normalize.d.ts +43 -0
  88. package/dist/engine/normalize.js +403 -0
  89. package/dist/engine/normalize.test.d.ts +1 -0
  90. package/dist/engine/normalize.test.js +136 -0
  91. package/dist/engine/onSolid.d.ts +3 -0
  92. package/dist/engine/onSolid.js +110 -0
  93. package/dist/engine/resolveBaseColor.d.ts +25 -0
  94. package/dist/engine/resolveBaseColor.js +127 -0
  95. package/dist/engine/resolveBaseColor.test.d.ts +1 -0
  96. package/dist/engine/resolveBaseColor.test.js +97 -0
  97. package/dist/export/__snapshots__/exportTheme.test.js.snap +74 -0
  98. package/dist/export/exportTheme.d.ts +47 -0
  99. package/dist/export/exportTheme.js +170 -0
  100. package/dist/export/exportTheme.test.d.ts +1 -0
  101. package/dist/export/exportTheme.test.js +118 -0
  102. package/dist/export/index.d.ts +1 -0
  103. package/dist/export/index.js +1 -0
  104. package/dist/export/serializeColor.d.ts +1 -0
  105. package/dist/export/serializeColor.js +1 -0
  106. package/dist/export/serializeColor.test.d.ts +1 -0
  107. package/dist/export/serializeColor.test.js +54 -0
  108. package/dist/export.d.ts +1 -0
  109. package/dist/export.js +1 -0
  110. package/dist/index.d.ts +3 -22
  111. package/dist/index.js +2 -18
  112. package/dist/operators/emphasis.d.ts +3 -0
  113. package/dist/operators/emphasis.js +113 -0
  114. package/dist/operators/emphasis.test.d.ts +1 -0
  115. package/dist/operators/emphasis.test.js +69 -0
  116. package/dist/operators/index.d.ts +3 -0
  117. package/dist/operators/index.js +2 -0
  118. package/dist/operators/state.d.ts +3 -0
  119. package/dist/operators/state.js +102 -0
  120. package/dist/operators/state.test.d.ts +1 -0
  121. package/dist/operators/state.test.js +48 -0
  122. package/dist/operators/types.d.ts +13 -0
  123. package/dist/operators/types.js +1 -0
  124. package/dist/operators/utils.d.ts +16 -0
  125. package/dist/operators/utils.js +23 -0
  126. package/dist/presets/curves.d.ts +28 -0
  127. package/dist/presets/curves.js +145 -0
  128. package/dist/presets/index.d.ts +2 -0
  129. package/dist/presets/index.js +1 -0
  130. package/dist/presets/tokens/index.d.ts +3 -0
  131. package/dist/presets/tokens/index.js +3 -0
  132. package/dist/presets/tokens/minimal-ui.d.ts +6 -0
  133. package/dist/presets/tokens/minimal-ui.js +53 -0
  134. package/dist/presets/tokens/modern-ui.d.ts +5 -0
  135. package/dist/presets/tokens/modern-ui.js +83 -0
  136. package/dist/presets/tokens/presets.test.d.ts +1 -0
  137. package/dist/presets/tokens/presets.test.js +31 -0
  138. package/dist/presets/tokens/radixLike-ui.d.ts +6 -0
  139. package/dist/presets/tokens/radixLike-ui.js +77 -0
  140. package/dist/serialize/index.d.ts +1 -0
  141. package/dist/serialize/index.js +1 -0
  142. package/dist/serialize/normalizeOutput.d.ts +6 -0
  143. package/dist/serialize/normalizeOutput.js +45 -0
  144. package/dist/serialize/serializeColor.d.ts +21 -0
  145. package/dist/serialize/serializeColor.js +178 -0
  146. package/dist/serialize/serializeResolved.test.d.ts +1 -0
  147. package/dist/serialize/serializeResolved.test.js +45 -0
  148. package/dist/serialize.d.ts +1 -0
  149. package/dist/serialize.js +1 -0
  150. package/dist/types/index.d.ts +187 -0
  151. package/dist/types/index.js +1 -0
  152. package/dist/utils/clamp.d.ts +1 -0
  153. package/dist/utils/clamp.js +1 -0
  154. package/dist/utils/index.d.ts +1 -0
  155. package/dist/utils/index.js +1 -0
  156. package/dist/utils/lerp.d.ts +1 -0
  157. package/dist/utils/lerp.js +1 -0
  158. package/dist/utils/parseColor.d.ts +6 -0
  159. package/dist/utils/parseColor.js +67 -0
  160. package/dist/utils/parseColor.test.d.ts +1 -0
  161. package/dist/utils/parseColor.test.js +51 -0
  162. package/dist/utils/smoothstep.d.ts +1 -0
  163. package/dist/utils/smoothstep.js +5 -0
  164. package/package.json +19 -12
  165. package/planning/phase-10-review.md +550 -0
  166. package/planning/phase-7-review.md +411 -0
  167. package/planning/phase-8-review.md +669 -0
  168. package/planning/phase-9-review.md +564 -0
  169. package/planning/roadmap-v0.3.md +284 -0
  170. package/planning/spec-serializer-v0.3.md +324 -0
  171. package/planning/spec-v0.3.md +305 -0
  172. package/src/cli/args.test.ts +28 -0
  173. package/src/cli/args.ts +66 -0
  174. package/src/cli/codegen/__snapshots__/tokens.test.ts.snap +87 -0
  175. package/src/cli/codegen/tokens.test.ts +61 -0
  176. package/src/cli/codegen/tokens.ts +191 -0
  177. package/src/cli/config.ts +71 -0
  178. package/src/cli/validate.test.ts +49 -0
  179. package/src/cli/validate.ts +38 -0
  180. package/src/cli.ts +183 -0
  181. package/src/contrast/apca.test.ts +20 -0
  182. package/src/contrast/apca.ts +26 -0
  183. package/src/contrast/index.ts +4 -0
  184. package/src/contrast/scoring.test.ts +188 -0
  185. package/src/contrast/scoring.ts +48 -0
  186. package/src/contrast/solver.test.ts +147 -0
  187. package/src/contrast/solver.ts +235 -0
  188. package/src/contrast/types.ts +20 -0
  189. package/src/contrast/utils.ts +28 -0
  190. package/src/contrast/wcag2.test.ts +21 -0
  191. package/src/contrast/wcag2.ts +24 -0
  192. package/src/core/createTheme.ts +78 -0
  193. package/src/core/dx-helpers.test.ts +82 -0
  194. package/src/core/index.ts +7 -0
  195. package/src/core/onSolid.test.ts +146 -0
  196. package/src/core/qa.v1.test.ts +149 -0
  197. package/src/core/resolve.test.ts +99 -0
  198. package/src/core/resolve.ts +11 -0
  199. package/src/core/resolveMany.ts +22 -0
  200. package/src/core/tokenRegistry.test.ts +153 -0
  201. package/src/core/tokenRegistry.ts +114 -0
  202. package/src/engine/applyOperators.ts +32 -0
  203. package/src/engine/context.ts +8 -0
  204. package/src/engine/gamut.test.ts +30 -0
  205. package/src/engine/gamut.ts +144 -0
  206. package/src/engine/generateScale.test.ts +46 -0
  207. package/src/engine/generateScale.ts +48 -0
  208. package/src/engine/index.ts +8 -0
  209. package/src/engine/normalize.test.ts +222 -0
  210. package/src/engine/normalize.ts +550 -0
  211. package/src/engine/onSolid.ts +178 -0
  212. package/src/engine/resolveBaseColor.test.ts +117 -0
  213. package/src/engine/resolveBaseColor.ts +203 -0
  214. package/src/export/__snapshots__/exportTheme.test.ts.snap +74 -0
  215. package/src/export/exportTheme.test.ts +144 -0
  216. package/src/export/exportTheme.ts +251 -0
  217. package/src/export/index.ts +1 -0
  218. package/src/export/serializeColor.test.ts +73 -0
  219. package/src/export/serializeColor.ts +1 -0
  220. package/src/export.ts +1 -0
  221. package/src/index.ts +3 -0
  222. package/src/operators/emphasis.test.ts +85 -0
  223. package/src/operators/emphasis.ts +132 -0
  224. package/src/operators/index.ts +3 -0
  225. package/src/operators/state.test.ts +66 -0
  226. package/src/operators/state.ts +122 -0
  227. package/src/operators/types.ts +14 -0
  228. package/src/operators/utils.ts +44 -0
  229. package/src/presets/curves.ts +168 -0
  230. package/src/presets/index.ts +2 -0
  231. package/src/presets/tokens/index.ts +3 -0
  232. package/src/presets/tokens/minimal-ui.ts +55 -0
  233. package/src/presets/tokens/modern-ui.ts +85 -0
  234. package/src/presets/tokens/presets.test.ts +46 -0
  235. package/src/presets/tokens/radixLike-ui.ts +79 -0
  236. package/src/serialize/index.ts +1 -0
  237. package/src/serialize/normalizeOutput.ts +63 -0
  238. package/src/serialize/serializeColor.ts +260 -0
  239. package/src/serialize/serializeResolved.test.ts +57 -0
  240. package/src/serialize.ts +1 -0
  241. package/src/types/index.ts +207 -0
  242. package/src/utils/clamp.ts +2 -0
  243. package/src/utils/index.ts +1 -0
  244. package/src/utils/lerp.ts +1 -0
  245. package/src/utils/parseColor.test.ts +66 -0
  246. package/src/utils/parseColor.ts +87 -0
  247. package/src/utils/smoothstep.ts +6 -0
  248. package/tsconfig.build.json +11 -0
  249. package/tsconfig.json +15 -0
  250. package/dist/alpha/generateAlphaScale.d.ts +0 -5
  251. package/dist/alpha/generateAlphaScale.js +0 -34
  252. package/dist/contrast/onSolid.d.ts +0 -6
  253. package/dist/contrast/onSolid.js +0 -28
  254. package/dist/contrast/solveText.d.ts +0 -2
  255. package/dist/contrast/solveText.js +0 -31
  256. package/dist/createTheme.d.ts +0 -38
  257. package/dist/createTheme.js +0 -148
  258. package/dist/data/radixSeeds.d.ts +0 -3
  259. package/dist/data/radixSeeds.js +0 -34
  260. package/dist/diagnostics/analyzeScale.d.ts +0 -2
  261. package/dist/diagnostics/analyzeScale.js +0 -7
  262. package/dist/diagnostics/analyzeTheme.d.ts +0 -2
  263. package/dist/diagnostics/analyzeTheme.js +0 -35
  264. package/dist/diagnostics/warnings.d.ts +0 -2
  265. package/dist/diagnostics/warnings.js +0 -20
  266. package/dist/engine/curves.d.ts +0 -9
  267. package/dist/engine/curves.js +0 -48
  268. package/dist/engine/oklch.d.ts +0 -8
  269. package/dist/engine/oklch.js +0 -40
  270. package/dist/engine/templates.d.ts +0 -14
  271. package/dist/engine/templates.js +0 -45
  272. package/dist/exporters/selectColorMode.d.ts +0 -2
  273. package/dist/exporters/selectColorMode.js +0 -19
  274. package/dist/exporters/toCssVars.d.ts +0 -13
  275. package/dist/exporters/toCssVars.js +0 -108
  276. package/dist/exporters/toJson.d.ts +0 -3
  277. package/dist/exporters/toJson.js +0 -25
  278. package/dist/exporters/toReactNative.d.ts +0 -54
  279. package/dist/exporters/toReactNative.js +0 -33
  280. package/dist/exporters/toTailwind.d.ts +0 -17
  281. package/dist/exporters/toTailwind.js +0 -111
  282. package/dist/exporters/toTs.d.ts +0 -3
  283. package/dist/exporters/toTs.js +0 -43
  284. package/dist/generateScale.d.ts +0 -48
  285. package/dist/generateScale.js +0 -274
  286. package/dist/overlays/generateOverlayScale.d.ts +0 -2
  287. package/dist/overlays/generateOverlayScale.js +0 -34
  288. package/dist/text/generateTextScale.d.ts +0 -8
  289. package/dist/text/generateTextScale.js +0 -18
  290. package/dist/text/resolveOnBgText.d.ts +0 -9
  291. package/dist/text/resolveOnBgText.js +0 -28
  292. package/dist/tokens/presetRadixLikeUi.d.ts +0 -5
  293. package/dist/tokens/presetRadixLikeUi.js +0 -55
  294. package/dist/types.d.ts +0 -69
  295. /package/dist/{types.js → cli/args.test.d.ts} +0 -0
@@ -1,274 +0,0 @@
1
- import { apcaContrast } from "./contrast/apca.js";
2
- import { onSolidTextTokens } from "./contrast/onSolid.js";
3
- import { radixSeeds } from "./data/radixSeeds.js";
4
- import { resolveCurves } from "./engine/curves.js";
5
- import { compressToP3, compressToSrgb, hexToOklch, inP3Gamut, inSrgbGamut, oklchToHex, oklchToP3, } from "./engine/oklch.js";
6
- import { selectTemplateId, templates } from "./engine/templates.js";
7
- const steps = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
8
- const defaultAutoAnchor = {
9
- candidateSteps: [8, 9, 10],
10
- light: {
11
- backgroundStep: 1,
12
- backgroundSteps: [1, 2, 3],
13
- solidStep: 9,
14
- textStep: 12,
15
- targetContrast: 90,
16
- minBackgroundL: 0.86,
17
- maxBackgroundL: 0.98,
18
- minTextL: 0.22,
19
- maxTextL: 0.55,
20
- },
21
- dark: {
22
- backgroundStep: 1,
23
- backgroundSteps: [1, 2, 3],
24
- solidStep: 9,
25
- textStep: 12,
26
- targetContrast: 75,
27
- minBackgroundL: 0.1,
28
- maxBackgroundL: 0.32,
29
- minTextL: 0.75,
30
- maxTextL: 0.98,
31
- },
32
- };
33
- const defaultSeedNormalize = {
34
- light: {
35
- minL: 0.35,
36
- maxL: 0.9,
37
- },
38
- dark: {
39
- minL: 0.32,
40
- maxL: 0.82,
41
- },
42
- };
43
- function getSeedHex(source) {
44
- if (source.source === "seed") {
45
- return source.value;
46
- }
47
- const seed = radixSeeds[source.name];
48
- if (!seed) {
49
- throw new Error(`Unknown Radix seed: ${source.name}`);
50
- }
51
- return seed;
52
- }
53
- function normalizeHue(hue) {
54
- const normalized = ((hue % 360) + 360) % 360;
55
- return normalized;
56
- }
57
- function clampValue(value, min, max) {
58
- let current = value;
59
- if (min !== undefined) {
60
- current = Math.max(min, current);
61
- }
62
- if (max !== undefined) {
63
- current = Math.min(max, current);
64
- }
65
- return current;
66
- }
67
- function normalizeSeed(seed, range) {
68
- const l = clampValue(seed.l, range.minL, range.maxL);
69
- const c = clampValue(seed.c, range.minC, range.maxC);
70
- return {
71
- l,
72
- c: Math.max(0, c),
73
- h: seed.h,
74
- };
75
- }
76
- function resolveAnchorOption(option, mode) {
77
- if (!option) {
78
- return undefined;
79
- }
80
- if (typeof option === "object") {
81
- return option[mode];
82
- }
83
- return option;
84
- }
85
- function resolveSeedNormalizeOptions(options, autoEnabled) {
86
- const enabled = options?.enabled ?? autoEnabled;
87
- return {
88
- enabled,
89
- light: { ...defaultSeedNormalize.light, ...options?.light },
90
- dark: { ...defaultSeedNormalize.dark, ...options?.dark },
91
- };
92
- }
93
- function resolveCandidateSteps(candidateSteps) {
94
- const unique = Array.from(new Set(candidateSteps ?? defaultAutoAnchor.candidateSteps));
95
- return unique.length > 0 ? unique : [9];
96
- }
97
- function resolveAutoAnchorModeOptions(base, overrides, candidateSteps) {
98
- const resolvedCandidates = resolveCandidateSteps(overrides?.candidateSteps ?? candidateSteps);
99
- const resolvedBackgroundStep = overrides?.backgroundStep ?? base.backgroundStep;
100
- const resolvedBackgroundSteps = overrides?.backgroundSteps ?? base.backgroundSteps;
101
- return {
102
- candidateSteps: resolvedCandidates,
103
- backgroundStep: resolvedBackgroundStep,
104
- backgroundSteps: resolvedBackgroundSteps.length > 0 ? resolvedBackgroundSteps : [resolvedBackgroundStep],
105
- solidStep: overrides?.solidStep ?? base.solidStep,
106
- textStep: overrides?.textStep ?? base.textStep,
107
- targetContrast: overrides?.targetContrast ?? base.targetContrast,
108
- minBackgroundL: overrides?.minBackgroundL ?? base.minBackgroundL,
109
- maxBackgroundL: overrides?.maxBackgroundL ?? base.maxBackgroundL,
110
- minTextL: overrides?.minTextL ?? base.minTextL,
111
- maxTextL: overrides?.maxTextL ?? base.maxTextL,
112
- };
113
- }
114
- function resolveAutoAnchorOptions(options) {
115
- const candidateSteps = resolveCandidateSteps(options?.candidateSteps);
116
- return {
117
- light: resolveAutoAnchorModeOptions(defaultAutoAnchor.light, options?.light, candidateSteps),
118
- dark: resolveAutoAnchorModeOptions(defaultAutoAnchor.dark, options?.dark, candidateSteps),
119
- };
120
- }
121
- function rangePenalty(value, min, max, weight = 100) {
122
- if (value < min) {
123
- return (min - value) * weight;
124
- }
125
- if (value > max) {
126
- return (value - max) * weight;
127
- }
128
- return 0;
129
- }
130
- function scoreScale(scale, options) {
131
- const solid = scale[options.solidStep];
132
- const onSolid = onSolidTextTokens(solid);
133
- const contrast = Math.abs(apcaContrast(onSolid.primary, solid));
134
- const text = scale[options.textStep];
135
- const textL = hexToOklch(text).l;
136
- const backgroundLs = options.backgroundSteps.map((step) => hexToOklch(scale[step]).l);
137
- const minBackgroundL = Math.min(...backgroundLs);
138
- const maxBackgroundL = Math.max(...backgroundLs);
139
- let score = 0;
140
- const contrastDelta = options.targetContrast - contrast;
141
- if (contrastDelta > 0) {
142
- score += contrastDelta * 2.2;
143
- }
144
- score += rangePenalty(minBackgroundL, options.minBackgroundL, options.maxBackgroundL, 180);
145
- score += rangePenalty(maxBackgroundL, options.minBackgroundL, options.maxBackgroundL, 180);
146
- score += rangePenalty(textL, options.minTextL, options.maxTextL, 120);
147
- return score;
148
- }
149
- function pickAutoAnchorStep(seed, templateId, curves, gamutStrategy, mode, options) {
150
- let bestStep = 9;
151
- let bestScore = Number.POSITIVE_INFINITY;
152
- for (const candidate of options.candidateSteps) {
153
- const result = buildScaleForMode(seed, templateId, candidate, curves, gamutStrategy, mode, false);
154
- const score = scoreScale(result.scale, options) + Math.abs(candidate - 9) * 2;
155
- if (score < bestScore) {
156
- bestScore = score;
157
- bestStep = candidate;
158
- }
159
- else if (score === bestScore) {
160
- if (Math.abs(candidate - 9) < Math.abs(bestStep - 9)) {
161
- bestStep = candidate;
162
- }
163
- }
164
- }
165
- return bestStep;
166
- }
167
- function buildScaleForMode(seed, templateId, anchorStep, curves, gamutStrategy = "compress", mode = "light", includeP3 = false) {
168
- const template = templates[mode][templateId];
169
- const anchor = template[anchorStep];
170
- const dL = seed.l - anchor.l;
171
- const dC = seed.c - anchor.c;
172
- const dH = seed.h - anchor.h;
173
- const curveSet = resolveCurves(curves);
174
- const output = {};
175
- const p3Output = includeP3 ? {} : undefined;
176
- let outOfGamutCount = 0;
177
- let outOfP3GamutCount = 0;
178
- for (const step of steps) {
179
- const base = template[step];
180
- const l = base.l + dL * curveSet.lightness[step];
181
- const c = Math.max(0, base.c + dC * curveSet.chroma[step]);
182
- const h = normalizeHue(base.h + dH);
183
- const candidate = { l, c, h };
184
- let current = candidate;
185
- if (!inSrgbGamut(current)) {
186
- outOfGamutCount += 1;
187
- if (gamutStrategy === "compress") {
188
- current = compressToSrgb(current);
189
- }
190
- }
191
- output[step] = oklchToHex(current);
192
- if (p3Output) {
193
- let p3Current = candidate;
194
- if (!inP3Gamut(p3Current)) {
195
- outOfP3GamutCount += 1;
196
- p3Current = compressToP3(p3Current);
197
- }
198
- p3Output[step] = oklchToP3(p3Current);
199
- }
200
- }
201
- return {
202
- scale: output,
203
- p3: p3Output,
204
- outOfGamutCount,
205
- outOfP3GamutCount,
206
- };
207
- }
208
- export function generateScale(options) {
209
- const seedHex = getSeedHex(options.source);
210
- const seedOklch = hexToOklch(seedHex);
211
- const mode = options.mode ?? "both";
212
- const templateId = options.template === "auto" || !options.template
213
- ? selectTemplateId(seedOklch)
214
- : options.template;
215
- const gamutStrategy = options.gamut?.strategy ?? "compress";
216
- const anchorOption = options.anchorStep ?? "auto";
217
- const anchorLightOption = resolveAnchorOption(anchorOption, "light");
218
- const anchorDarkOption = resolveAnchorOption(anchorOption, "dark");
219
- const autoAnchorOptions = resolveAutoAnchorOptions(options.autoAnchor);
220
- const autoEnabled = anchorLightOption === "auto" || anchorDarkOption === "auto";
221
- const seedNormalize = resolveSeedNormalizeOptions(options.seedNormalize, autoEnabled);
222
- const lightSeed = seedNormalize.enabled
223
- ? normalizeSeed(seedOklch, seedNormalize.light)
224
- : seedOklch;
225
- const darkSeed = seedNormalize.enabled ? normalizeSeed(seedOklch, seedNormalize.dark) : seedOklch;
226
- const lightAnchorStep = anchorLightOption === "auto"
227
- ? pickAutoAnchorStep(lightSeed, templateId, options.curves, gamutStrategy, "light", autoAnchorOptions.light)
228
- : (anchorLightOption ?? 9);
229
- const darkAnchorStep = anchorDarkOption === "auto"
230
- ? pickAutoAnchorStep(darkSeed, templateId, options.curves, gamutStrategy, "dark", autoAnchorOptions.dark)
231
- : (anchorDarkOption ?? 9);
232
- const lightResult = buildScaleForMode(lightSeed, templateId, lightAnchorStep, options.curves, gamutStrategy, "light", options.p3 ?? false);
233
- const darkResult = buildScaleForMode(darkSeed, templateId, darkAnchorStep, options.curves, gamutStrategy, "dark", options.p3 ?? false);
234
- const scale = {
235
- light: lightResult.scale,
236
- dark: darkResult.scale,
237
- p3: lightResult.p3 && darkResult.p3 ? { light: lightResult.p3, dark: darkResult.p3 } : undefined,
238
- meta: {
239
- outOfGamutCount: lightResult.outOfGamutCount + darkResult.outOfGamutCount,
240
- outOfP3GamutCount: lightResult.outOfP3GamutCount + darkResult.outOfP3GamutCount,
241
- anchorSteps: {
242
- light: lightAnchorStep,
243
- dark: darkAnchorStep,
244
- },
245
- },
246
- };
247
- if (mode === "light") {
248
- return {
249
- ...scale,
250
- dark: scale.light,
251
- p3: scale.p3 ? { light: scale.p3.light, dark: scale.p3.light } : undefined,
252
- meta: scale.meta
253
- ? {
254
- ...scale.meta,
255
- anchorSteps: { light: lightAnchorStep, dark: lightAnchorStep },
256
- }
257
- : undefined,
258
- };
259
- }
260
- if (mode === "dark") {
261
- return {
262
- ...scale,
263
- light: scale.dark,
264
- p3: scale.p3 ? { light: scale.p3.dark, dark: scale.p3.dark } : undefined,
265
- meta: scale.meta
266
- ? {
267
- ...scale.meta,
268
- anchorSteps: { light: darkAnchorStep, dark: darkAnchorStep },
269
- }
270
- : undefined,
271
- };
272
- }
273
- return scale;
274
- }
@@ -1,2 +0,0 @@
1
- import type { OverlayScale } from "../types.js";
2
- export declare function generateOverlayScale(): OverlayScale;
@@ -1,34 +0,0 @@
1
- import Color from "colorjs.io";
2
- const steps = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
3
- const alphaCurve = {
4
- 1: 0.05,
5
- 2: 0.1,
6
- 3: 0.15,
7
- 4: 0.2,
8
- 5: 0.3,
9
- 6: 0.4,
10
- 7: 0.5,
11
- 8: 0.6,
12
- 9: 0.7,
13
- 10: 0.8,
14
- 11: 0.9,
15
- 12: 0.95,
16
- };
17
- function mixWithAlpha(foreground, alpha) {
18
- const color = new Color(foreground).to("srgb");
19
- const [r, g, b] = color.coords;
20
- const hex = new Color({ space: "srgb", coords: [r, g, b], alpha }).toString({
21
- format: "hex",
22
- });
23
- return hex;
24
- }
25
- export function generateOverlayScale() {
26
- const black = {};
27
- const white = {};
28
- for (const step of steps) {
29
- const alpha = alphaCurve[step];
30
- black[step] = mixWithAlpha("#000000", alpha);
31
- white[step] = mixWithAlpha("#ffffff", alpha);
32
- }
33
- return { black, white };
34
- }
@@ -1,8 +0,0 @@
1
- import type { ColorHex, TextScale } from "../types.js";
2
- type TextScaleOptions = {
3
- darkBase?: ColorHex;
4
- lightBase?: ColorHex;
5
- deltaL?: number;
6
- };
7
- export declare function generateTextScale(options?: TextScaleOptions): TextScale;
8
- export {};
@@ -1,18 +0,0 @@
1
- import { compressToSrgb, hexToOklch, oklchToHex } from "../engine/oklch.js";
2
- const steps = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
3
- export function generateTextScale(options) {
4
- const darkBase = options?.darkBase ?? "#1C1C1E";
5
- const lightBase = options?.lightBase ?? "#F5F5F7";
6
- const deltaL = options?.deltaL ?? 0.055;
7
- const darkBaseOklch = hexToOklch(darkBase);
8
- const lightBaseOklch = hexToOklch(lightBase);
9
- const dark = {};
10
- const light = {};
11
- for (const step of steps) {
12
- const darkL = Math.min(darkBaseOklch.l + (12 - step) * deltaL, 0.92);
13
- const lightL = Math.max(lightBaseOklch.l - (step - 1) * deltaL, 0.12);
14
- dark[step] = oklchToHex(compressToSrgb({ ...darkBaseOklch, l: darkL }));
15
- light[step] = oklchToHex(compressToSrgb({ ...lightBaseOklch, l: lightL }));
16
- }
17
- return { dark, light };
18
- }
@@ -1,9 +0,0 @@
1
- import type { ColorHex, Step, Theme } from "../types.js";
2
- export type TextOnBgTokens = {
3
- zone: "light" | "mid" | "dark";
4
- primary: ColorHex;
5
- secondary: ColorHex;
6
- tertiary?: ColorHex;
7
- disabled?: ColorHex;
8
- };
9
- export declare function resolveOnBgTextTokens(theme: Theme, mode: "light" | "dark", backgroundStep: Step): TextOnBgTokens;
@@ -1,28 +0,0 @@
1
- function resolveZone(step) {
2
- if (step <= 4) {
3
- return "light";
4
- }
5
- if (step <= 8) {
6
- return "mid";
7
- }
8
- return "dark";
9
- }
10
- export function resolveOnBgTextTokens(theme, mode, backgroundStep) {
11
- const zone = resolveZone(backgroundStep);
12
- const tokens = theme.tokens[mode];
13
- const prefix = `text.onBg.${zone}`;
14
- const primary = tokens[`${prefix}.primary`];
15
- const secondary = tokens[`${prefix}.secondary`];
16
- if (!primary || !secondary) {
17
- throw new Error(`Missing text.onBg tokens for ${mode} ${zone}.`);
18
- }
19
- const tertiary = tokens[`${prefix}.tertiary`];
20
- const disabled = tokens[`${prefix}.disabled`];
21
- return {
22
- zone,
23
- primary,
24
- secondary,
25
- tertiary: tertiary || undefined,
26
- disabled: disabled || undefined,
27
- };
28
- }
@@ -1,5 +0,0 @@
1
- import type { ColorHex, Scale } from "../types.js";
2
- export declare function buildPresetTokens(scales: Record<string, Scale>): {
3
- light: Record<string, ColorHex>;
4
- dark: Record<string, ColorHex>;
5
- };
@@ -1,55 +0,0 @@
1
- const tokenMap = [
2
- { token: "bg.app", slot: "neutral", step: 1 },
3
- { token: "bg.subtle", slot: "neutral", step: 2 },
4
- { token: "surface.card", slot: "neutral", step: 2 },
5
- { token: "surface.raised", slot: "neutral", step: 3 },
6
- { token: "component.bg", slot: "neutral", step: 3 },
7
- { token: "component.bgHover", slot: "neutral", step: 4 },
8
- { token: "component.bgActive", slot: "neutral", step: 5 },
9
- { token: "border.subtle", slot: "neutral", step: 6 },
10
- { token: "border.default", slot: "neutral", step: 7 },
11
- { token: "border.strong", slot: "neutral", step: 8 },
12
- { token: "text.secondary", slot: "neutral", step: 11 },
13
- { token: "text.primary", slot: "neutral", step: 12 },
14
- { token: "text.disabled", slot: "neutral", step: 10 },
15
- { token: "focus.ring", slot: "accent", step: 8 },
16
- { token: "accent.solid", slot: "accent", step: 9 },
17
- { token: "accent.solidHover", slot: "accent", step: 10 },
18
- { token: "accent.border", slot: "accent", step: 7 },
19
- { token: "accent.subtle", slot: "accent", step: 3 },
20
- { token: "accent.subtleHover", slot: "accent", step: 4 },
21
- { token: "status.success.solidBg", slot: "success", step: 9, required: false },
22
- { token: "status.success.solidHover", slot: "success", step: 10, required: false },
23
- { token: "status.success.subtleBg", slot: "success", step: 3, required: false },
24
- { token: "status.success.border", slot: "success", step: 7, required: false },
25
- { token: "status.success.text", slot: "success", step: 11, required: false },
26
- { token: "status.success.textStrong", slot: "success", step: 12, required: false },
27
- { token: "status.warning.solidBg", slot: "warning", step: 9, required: false },
28
- { token: "status.warning.solidHover", slot: "warning", step: 10, required: false },
29
- { token: "status.warning.subtleBg", slot: "warning", step: 3, required: false },
30
- { token: "status.warning.border", slot: "warning", step: 7, required: false },
31
- { token: "status.warning.text", slot: "warning", step: 11, required: false },
32
- { token: "status.warning.textStrong", slot: "warning", step: 12, required: false },
33
- { token: "status.danger.solidBg", slot: "danger", step: 9, required: false },
34
- { token: "status.danger.solidHover", slot: "danger", step: 10, required: false },
35
- { token: "status.danger.subtleBg", slot: "danger", step: 3, required: false },
36
- { token: "status.danger.border", slot: "danger", step: 7, required: false },
37
- { token: "status.danger.text", slot: "danger", step: 11, required: false },
38
- { token: "status.danger.textStrong", slot: "danger", step: 12, required: false },
39
- ];
40
- export function buildPresetTokens(scales) {
41
- const light = {};
42
- const dark = {};
43
- for (const { token, slot, step, required } of tokenMap) {
44
- const scale = scales[slot];
45
- if (!scale) {
46
- if (required === false) {
47
- continue;
48
- }
49
- throw new Error(`Missing scale for slot: ${slot}`);
50
- }
51
- light[token] = scale.light[step];
52
- dark[token] = scale.dark[step];
53
- }
54
- return { light, dark };
55
- }
package/dist/types.d.ts DELETED
@@ -1,69 +0,0 @@
1
- export type Step = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
2
- export type ColorHex = `#${string}`;
3
- export type ColorP3 = string;
4
- export type RadixSeedName = string;
5
- export type TemplateId = "neutral" | "warm" | "cool";
6
- export type ColorSource = {
7
- source: "seed";
8
- value: ColorHex;
9
- } | {
10
- source: "radix";
11
- name: RadixSeedName;
12
- };
13
- export type ScaleDiagnostics = {
14
- outOfGamutCount: number;
15
- outOfP3GamutCount?: number;
16
- anchorSteps?: {
17
- light: Step;
18
- dark: Step;
19
- };
20
- };
21
- export type Scale = {
22
- light: Record<Step, ColorHex>;
23
- dark: Record<Step, ColorHex>;
24
- p3?: {
25
- light: Record<Step, ColorP3>;
26
- dark: Record<Step, ColorP3>;
27
- };
28
- meta?: ScaleDiagnostics;
29
- };
30
- export type ScaleColorMode = Omit<Scale, "light" | "dark"> & {
31
- light: Record<Step, string>;
32
- dark: Record<Step, string>;
33
- };
34
- export type AlphaScale = {
35
- light: Record<Step, ColorHex>;
36
- dark: Record<Step, ColorHex>;
37
- };
38
- export type AlphaScales = Record<string, AlphaScale>;
39
- export type OverlayScale = {
40
- black: Record<Step, ColorHex>;
41
- white: Record<Step, ColorHex>;
42
- };
43
- export type TextScale = {
44
- dark: Record<Step, ColorHex>;
45
- light: Record<Step, ColorHex>;
46
- };
47
- export type ThemeDiagnostics = {
48
- contrast: Record<string, number>;
49
- outOfGamutCount: number;
50
- warnings?: readonly string[];
51
- };
52
- export type Theme = {
53
- scales: Record<string, Scale>;
54
- tokens: {
55
- light: Record<string, ColorHex>;
56
- dark: Record<string, ColorHex>;
57
- };
58
- alpha?: AlphaScales;
59
- overlay: OverlayScale;
60
- diagnostics?: ThemeDiagnostics;
61
- };
62
- export type ThemeColorMode = Omit<Theme, "scales"> & {
63
- scales: Record<string, ScaleColorMode>;
64
- };
65
- export type OklchColor = {
66
- l: number;
67
- c: number;
68
- h: number;
69
- };
File without changes