@clhaas/palette-kit 0.3.0 → 0.4.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 (312) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +80 -87
  3. package/dist/contrast/contrast.d.ts +16 -0
  4. package/dist/contrast/contrast.js +102 -0
  5. package/dist/core/intent-registry.d.ts +11 -0
  6. package/dist/core/intent-registry.js +70 -0
  7. package/dist/core/oklch.d.ts +16 -0
  8. package/dist/core/oklch.js +56 -0
  9. package/dist/create-palette-kit.d.ts +9 -0
  10. package/dist/create-palette-kit.js +67 -0
  11. package/dist/engine/context/context.d.ts +13 -0
  12. package/dist/engine/context/context.js +37 -0
  13. package/dist/engine/level/curves.d.ts +17 -0
  14. package/dist/engine/level/curves.js +49 -0
  15. package/dist/engine/level/level.d.ts +4 -0
  16. package/dist/engine/level/level.js +13 -0
  17. package/dist/engine/relation/relation.d.ts +105 -0
  18. package/dist/engine/relation/relation.js +137 -0
  19. package/dist/engine/resolve/resolve.d.ts +36 -0
  20. package/dist/engine/resolve/resolve.js +116 -0
  21. package/dist/engine/state/state.d.ts +46 -0
  22. package/dist/engine/state/state.js +68 -0
  23. package/dist/engine/usage/fill.d.ts +9 -0
  24. package/dist/engine/usage/fill.js +9 -0
  25. package/dist/engine/usage/lines.d.ts +9 -0
  26. package/dist/engine/usage/lines.js +9 -0
  27. package/dist/engine/usage/overlays.d.ts +9 -0
  28. package/dist/engine/usage/overlays.js +9 -0
  29. package/dist/engine/usage/strategy.d.ts +56 -0
  30. package/dist/engine/usage/strategy.js +30 -0
  31. package/dist/engine/usage/visualVocabulary.d.ts +9 -0
  32. package/dist/engine/usage/visualVocabulary.js +9 -0
  33. package/dist/export/serialize.d.ts +14 -0
  34. package/dist/export/serialize.js +89 -0
  35. package/dist/export/types.d.ts +37 -0
  36. package/dist/export/types.js +31 -0
  37. package/dist/index.d.ts +3 -3
  38. package/dist/index.js +2 -2
  39. package/dist/operators/convert.d.ts +32 -0
  40. package/dist/operators/convert.js +80 -0
  41. package/dist/presets/presets.d.ts +95 -0
  42. package/dist/presets/presets.js +308 -0
  43. package/dist/types/index.d.ts +111 -187
  44. package/dist/utils/errors/errors.d.ts +17 -0
  45. package/dist/utils/errors/errors.js +22 -0
  46. package/docs/API.md +167 -0
  47. package/docs/Alpha.md +14 -0
  48. package/docs/Architecture.md +56 -0
  49. package/docs/CLI.md +22 -0
  50. package/docs/Concepts.md +73 -0
  51. package/docs/Config.md +144 -0
  52. package/docs/Diagnostics.md +22 -0
  53. package/docs/Exporters.md +33 -0
  54. package/docs/FAQ.md +59 -0
  55. package/docs/Migration.md +61 -0
  56. package/docs/Overlays.md +33 -0
  57. package/docs/README.md +60 -0
  58. package/docs/Text.md +41 -0
  59. package/docs/Tokens.md +42 -0
  60. package/docs/Usage-JSON.md +39 -0
  61. package/docs/Usage-ReactNative.md +63 -0
  62. package/docs/Usage-Web.md +66 -0
  63. package/docs/Validation.md +97 -0
  64. package/docs/Why.md +37 -0
  65. package/docs/_api-surface.md +53 -0
  66. package/docs/snippets/serialize-oklch.md +9 -0
  67. package/docs/spec.md +98 -0
  68. package/package.json +74 -59
  69. package/.codex/skills/color-pipeline-implementer/SKILL.md +0 -23
  70. package/.codex/skills/commit-message-crafter/SKILL.md +0 -63
  71. package/.codex/skills/commit-message-crafter/references/benchmarks.md +0 -20
  72. package/.codex/skills/contrast-solver-helper/SKILL.md +0 -20
  73. package/.codex/skills/exporters-builder/SKILL.md +0 -20
  74. package/.codex/skills/markdownlint-writer/SKILL.md +0 -32
  75. package/.codex/skills/phase-implementation-runbook/SKILL.md +0 -92
  76. package/.codex/skills/type-contract-auditor/SKILL.md +0 -21
  77. package/.github/skills/review-guide/SKILL.md +0 -23
  78. package/.github/skills/review-guide/references/review-guide-v0.3.md +0 -629
  79. package/.markdownlint.json +0 -4
  80. package/AGENTS.md +0 -16
  81. package/biome.json +0 -43
  82. package/dist/cli/args.d.ts +0 -12
  83. package/dist/cli/args.js +0 -56
  84. package/dist/cli/args.test.d.ts +0 -1
  85. package/dist/cli/args.test.js +0 -22
  86. package/dist/cli/codegen/__snapshots__/tokens.test.js.snap +0 -87
  87. package/dist/cli/codegen/tokens.d.ts +0 -12
  88. package/dist/cli/codegen/tokens.js +0 -139
  89. package/dist/cli/codegen/tokens.test.d.ts +0 -1
  90. package/dist/cli/codegen/tokens.test.js +0 -51
  91. package/dist/cli/config.d.ts +0 -40
  92. package/dist/cli/config.js +0 -34
  93. package/dist/cli/validate.d.ts +0 -2
  94. package/dist/cli/validate.js +0 -33
  95. package/dist/cli/validate.test.d.ts +0 -1
  96. package/dist/cli/validate.test.js +0 -40
  97. package/dist/cli.d.ts +0 -2
  98. package/dist/cli.js +0 -148
  99. package/dist/contrast/apca.d.ts +0 -2
  100. package/dist/contrast/apca.js +0 -15
  101. package/dist/contrast/apca.test.d.ts +0 -1
  102. package/dist/contrast/apca.test.js +0 -16
  103. package/dist/contrast/index.d.ts +0 -4
  104. package/dist/contrast/index.js +0 -4
  105. package/dist/contrast/scoring.d.ts +0 -4
  106. package/dist/contrast/scoring.js +0 -31
  107. package/dist/contrast/scoring.test.d.ts +0 -1
  108. package/dist/contrast/scoring.test.js +0 -148
  109. package/dist/contrast/solver.d.ts +0 -13
  110. package/dist/contrast/solver.js +0 -170
  111. package/dist/contrast/solver.test.d.ts +0 -1
  112. package/dist/contrast/solver.test.js +0 -75
  113. package/dist/contrast/types.d.ts +0 -17
  114. package/dist/contrast/types.js +0 -1
  115. package/dist/contrast/utils.d.ts +0 -4
  116. package/dist/contrast/utils.js +0 -18
  117. package/dist/contrast/wcag2.d.ts +0 -3
  118. package/dist/contrast/wcag2.js +0 -19
  119. package/dist/contrast/wcag2.test.d.ts +0 -1
  120. package/dist/contrast/wcag2.test.js +0 -17
  121. package/dist/core/createTheme.d.ts +0 -35
  122. package/dist/core/createTheme.js +0 -24
  123. package/dist/core/dx-helpers.test.d.ts +0 -1
  124. package/dist/core/dx-helpers.test.js +0 -61
  125. package/dist/core/index.d.ts +0 -2
  126. package/dist/core/index.js +0 -2
  127. package/dist/core/onSolid.test.d.ts +0 -1
  128. package/dist/core/onSolid.test.js +0 -118
  129. package/dist/core/qa.v1.test.d.ts +0 -1
  130. package/dist/core/qa.v1.test.js +0 -112
  131. package/dist/core/resolve.d.ts +0 -3
  132. package/dist/core/resolve.js +0 -8
  133. package/dist/core/resolve.test.d.ts +0 -1
  134. package/dist/core/resolve.test.js +0 -89
  135. package/dist/core/resolveMany.d.ts +0 -8
  136. package/dist/core/resolveMany.js +0 -17
  137. package/dist/core/tokenRegistry.d.ts +0 -23
  138. package/dist/core/tokenRegistry.js +0 -83
  139. package/dist/core/tokenRegistry.test.d.ts +0 -1
  140. package/dist/core/tokenRegistry.test.js +0 -133
  141. package/dist/engine/applyOperators.d.ts +0 -3
  142. package/dist/engine/applyOperators.js +0 -23
  143. package/dist/engine/context.d.ts +0 -4
  144. package/dist/engine/context.js +0 -1
  145. package/dist/engine/gamut.d.ts +0 -13
  146. package/dist/engine/gamut.js +0 -101
  147. package/dist/engine/gamut.test.d.ts +0 -1
  148. package/dist/engine/gamut.test.js +0 -23
  149. package/dist/engine/generateScale.d.ts +0 -15
  150. package/dist/engine/generateScale.js +0 -29
  151. package/dist/engine/generateScale.test.d.ts +0 -1
  152. package/dist/engine/generateScale.test.js +0 -32
  153. package/dist/engine/index.d.ts +0 -8
  154. package/dist/engine/index.js +0 -4
  155. package/dist/engine/normalize.d.ts +0 -43
  156. package/dist/engine/normalize.js +0 -403
  157. package/dist/engine/normalize.test.d.ts +0 -1
  158. package/dist/engine/normalize.test.js +0 -136
  159. package/dist/engine/onSolid.d.ts +0 -3
  160. package/dist/engine/onSolid.js +0 -110
  161. package/dist/engine/resolveBaseColor.d.ts +0 -25
  162. package/dist/engine/resolveBaseColor.js +0 -127
  163. package/dist/engine/resolveBaseColor.test.d.ts +0 -1
  164. package/dist/engine/resolveBaseColor.test.js +0 -97
  165. package/dist/export/__snapshots__/exportTheme.test.js.snap +0 -74
  166. package/dist/export/exportTheme.d.ts +0 -47
  167. package/dist/export/exportTheme.js +0 -170
  168. package/dist/export/exportTheme.test.d.ts +0 -1
  169. package/dist/export/exportTheme.test.js +0 -118
  170. package/dist/export/index.d.ts +0 -1
  171. package/dist/export/index.js +0 -1
  172. package/dist/export/serializeColor.d.ts +0 -1
  173. package/dist/export/serializeColor.js +0 -1
  174. package/dist/export/serializeColor.test.d.ts +0 -1
  175. package/dist/export/serializeColor.test.js +0 -54
  176. package/dist/export.d.ts +0 -1
  177. package/dist/export.js +0 -1
  178. package/dist/operators/emphasis.d.ts +0 -3
  179. package/dist/operators/emphasis.js +0 -113
  180. package/dist/operators/emphasis.test.d.ts +0 -1
  181. package/dist/operators/emphasis.test.js +0 -69
  182. package/dist/operators/index.d.ts +0 -3
  183. package/dist/operators/index.js +0 -2
  184. package/dist/operators/state.d.ts +0 -3
  185. package/dist/operators/state.js +0 -102
  186. package/dist/operators/state.test.d.ts +0 -1
  187. package/dist/operators/state.test.js +0 -48
  188. package/dist/operators/types.d.ts +0 -13
  189. package/dist/operators/types.js +0 -1
  190. package/dist/operators/utils.d.ts +0 -16
  191. package/dist/operators/utils.js +0 -23
  192. package/dist/presets/curves.d.ts +0 -28
  193. package/dist/presets/curves.js +0 -145
  194. package/dist/presets/index.d.ts +0 -2
  195. package/dist/presets/index.js +0 -1
  196. package/dist/presets/tokens/index.d.ts +0 -3
  197. package/dist/presets/tokens/index.js +0 -3
  198. package/dist/presets/tokens/minimal-ui.d.ts +0 -6
  199. package/dist/presets/tokens/minimal-ui.js +0 -53
  200. package/dist/presets/tokens/modern-ui.d.ts +0 -5
  201. package/dist/presets/tokens/modern-ui.js +0 -83
  202. package/dist/presets/tokens/presets.test.d.ts +0 -1
  203. package/dist/presets/tokens/presets.test.js +0 -31
  204. package/dist/presets/tokens/radixLike-ui.d.ts +0 -6
  205. package/dist/presets/tokens/radixLike-ui.js +0 -77
  206. package/dist/serialize/index.d.ts +0 -1
  207. package/dist/serialize/index.js +0 -1
  208. package/dist/serialize/normalizeOutput.d.ts +0 -6
  209. package/dist/serialize/normalizeOutput.js +0 -45
  210. package/dist/serialize/serializeColor.d.ts +0 -21
  211. package/dist/serialize/serializeColor.js +0 -178
  212. package/dist/serialize/serializeResolved.test.d.ts +0 -1
  213. package/dist/serialize/serializeResolved.test.js +0 -45
  214. package/dist/serialize.d.ts +0 -1
  215. package/dist/serialize.js +0 -1
  216. package/dist/utils/clamp.d.ts +0 -1
  217. package/dist/utils/clamp.js +0 -1
  218. package/dist/utils/index.d.ts +0 -1
  219. package/dist/utils/index.js +0 -1
  220. package/dist/utils/lerp.d.ts +0 -1
  221. package/dist/utils/lerp.js +0 -1
  222. package/dist/utils/parseColor.d.ts +0 -6
  223. package/dist/utils/parseColor.js +0 -67
  224. package/dist/utils/parseColor.test.d.ts +0 -1
  225. package/dist/utils/parseColor.test.js +0 -51
  226. package/dist/utils/smoothstep.d.ts +0 -1
  227. package/dist/utils/smoothstep.js +0 -5
  228. package/planning/phase-10-review.md +0 -550
  229. package/planning/phase-7-review.md +0 -411
  230. package/planning/phase-8-review.md +0 -669
  231. package/planning/phase-9-review.md +0 -564
  232. package/planning/roadmap-v0.3.md +0 -284
  233. package/planning/spec-serializer-v0.3.md +0 -324
  234. package/planning/spec-v0.3.md +0 -305
  235. package/src/cli/args.test.ts +0 -28
  236. package/src/cli/args.ts +0 -66
  237. package/src/cli/codegen/__snapshots__/tokens.test.ts.snap +0 -87
  238. package/src/cli/codegen/tokens.test.ts +0 -61
  239. package/src/cli/codegen/tokens.ts +0 -191
  240. package/src/cli/config.ts +0 -71
  241. package/src/cli/validate.test.ts +0 -49
  242. package/src/cli/validate.ts +0 -38
  243. package/src/cli.ts +0 -183
  244. package/src/contrast/apca.test.ts +0 -20
  245. package/src/contrast/apca.ts +0 -26
  246. package/src/contrast/index.ts +0 -4
  247. package/src/contrast/scoring.test.ts +0 -188
  248. package/src/contrast/scoring.ts +0 -48
  249. package/src/contrast/solver.test.ts +0 -147
  250. package/src/contrast/solver.ts +0 -235
  251. package/src/contrast/types.ts +0 -20
  252. package/src/contrast/utils.ts +0 -28
  253. package/src/contrast/wcag2.test.ts +0 -21
  254. package/src/contrast/wcag2.ts +0 -24
  255. package/src/core/createTheme.ts +0 -78
  256. package/src/core/dx-helpers.test.ts +0 -82
  257. package/src/core/index.ts +0 -7
  258. package/src/core/onSolid.test.ts +0 -146
  259. package/src/core/qa.v1.test.ts +0 -149
  260. package/src/core/resolve.test.ts +0 -99
  261. package/src/core/resolve.ts +0 -11
  262. package/src/core/resolveMany.ts +0 -22
  263. package/src/core/tokenRegistry.test.ts +0 -153
  264. package/src/core/tokenRegistry.ts +0 -114
  265. package/src/engine/applyOperators.ts +0 -32
  266. package/src/engine/context.ts +0 -8
  267. package/src/engine/gamut.test.ts +0 -30
  268. package/src/engine/gamut.ts +0 -144
  269. package/src/engine/generateScale.test.ts +0 -46
  270. package/src/engine/generateScale.ts +0 -48
  271. package/src/engine/index.ts +0 -8
  272. package/src/engine/normalize.test.ts +0 -222
  273. package/src/engine/normalize.ts +0 -550
  274. package/src/engine/onSolid.ts +0 -178
  275. package/src/engine/resolveBaseColor.test.ts +0 -117
  276. package/src/engine/resolveBaseColor.ts +0 -203
  277. package/src/export/__snapshots__/exportTheme.test.ts.snap +0 -74
  278. package/src/export/exportTheme.test.ts +0 -144
  279. package/src/export/exportTheme.ts +0 -251
  280. package/src/export/index.ts +0 -1
  281. package/src/export/serializeColor.test.ts +0 -73
  282. package/src/export/serializeColor.ts +0 -1
  283. package/src/export.ts +0 -1
  284. package/src/index.ts +0 -3
  285. package/src/operators/emphasis.test.ts +0 -85
  286. package/src/operators/emphasis.ts +0 -132
  287. package/src/operators/index.ts +0 -3
  288. package/src/operators/state.test.ts +0 -66
  289. package/src/operators/state.ts +0 -122
  290. package/src/operators/types.ts +0 -14
  291. package/src/operators/utils.ts +0 -44
  292. package/src/presets/curves.ts +0 -168
  293. package/src/presets/index.ts +0 -2
  294. package/src/presets/tokens/index.ts +0 -3
  295. package/src/presets/tokens/minimal-ui.ts +0 -55
  296. package/src/presets/tokens/modern-ui.ts +0 -85
  297. package/src/presets/tokens/presets.test.ts +0 -46
  298. package/src/presets/tokens/radixLike-ui.ts +0 -79
  299. package/src/serialize/index.ts +0 -1
  300. package/src/serialize/normalizeOutput.ts +0 -63
  301. package/src/serialize/serializeColor.ts +0 -260
  302. package/src/serialize/serializeResolved.test.ts +0 -57
  303. package/src/serialize.ts +0 -1
  304. package/src/types/index.ts +0 -207
  305. package/src/utils/clamp.ts +0 -2
  306. package/src/utils/index.ts +0 -1
  307. package/src/utils/lerp.ts +0 -1
  308. package/src/utils/parseColor.test.ts +0 -66
  309. package/src/utils/parseColor.ts +0 -87
  310. package/src/utils/smoothstep.ts +0 -6
  311. package/tsconfig.build.json +0 -11
  312. package/tsconfig.json +0 -15
@@ -1,191 +0,0 @@
1
- import type { TokenDefinition, TokenRegistry } from "../../types/index.js";
2
-
3
- type TokenTreeNode = {
4
- children: Map<string, TokenTreeNode>;
5
- token?: TokenDefinition;
6
- };
7
-
8
- const RESERVED_WORDS = new Set([
9
- "break",
10
- "case",
11
- "catch",
12
- "class",
13
- "const",
14
- "continue",
15
- "debugger",
16
- "default",
17
- "delete",
18
- "do",
19
- "else",
20
- "export",
21
- "extends",
22
- "finally",
23
- "for",
24
- "function",
25
- "if",
26
- "import",
27
- "in",
28
- "instanceof",
29
- "new",
30
- "return",
31
- "super",
32
- "switch",
33
- "this",
34
- "throw",
35
- "try",
36
- "typeof",
37
- "var",
38
- "void",
39
- "while",
40
- "with",
41
- "yield",
42
- ]);
43
-
44
- const isValidIdentifier = (value: string) => {
45
- if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value)) return false;
46
- return !RESERVED_WORDS.has(value);
47
- };
48
-
49
- const toPropertyKey = (key: string) => (isValidIdentifier(key) ? key : JSON.stringify(key));
50
-
51
- const indentLines = (lines: string[], spaces: number) => {
52
- const prefix = " ".repeat(spaces);
53
- return lines.map((line) => (line.length ? `${prefix}${line}` : line));
54
- };
55
-
56
- const escapeJsDoc = (value: string) => value.replace(/\*\//g, "*\\/");
57
-
58
- const buildTokenJsDocLines = (tokenName: string, token: TokenDefinition) => {
59
- const lines: string[] = [];
60
- if (token.description?.trim()) {
61
- lines.push(escapeJsDoc(token.description.trim()));
62
- }
63
-
64
- lines.push(`@token ${tokenName}`);
65
-
66
- if (token.category?.trim()) {
67
- lines.push(`@category ${escapeJsDoc(token.category.trim())}`);
68
- }
69
-
70
- const states = token.states ? Object.keys(token.states).sort() : [];
71
- if (states.length > 0) {
72
- lines.push(`@states ${states.join(", ")}`);
73
- }
74
-
75
- return ["/**", ...lines.map((line) => ` * ${line}`), " */"];
76
- };
77
-
78
- const buildTree = (registry: TokenRegistry): TokenTreeNode => {
79
- const root: TokenTreeNode = { children: new Map() };
80
-
81
- const entries = Object.entries(registry.tokens).sort(([a], [b]) => a.localeCompare(b));
82
- for (const [tokenName, token] of entries) {
83
- const segments = tokenName.split(".").filter(Boolean);
84
- if (segments.length === 0) continue;
85
-
86
- let node = root;
87
- for (const segment of segments) {
88
- let child = node.children.get(segment);
89
- if (!child) {
90
- child = { children: new Map() };
91
- node.children.set(segment, child);
92
- }
93
- node = child;
94
- }
95
-
96
- node.token = token;
97
- }
98
-
99
- return root;
100
- };
101
-
102
- const renderTreeTs = (node: TokenTreeNode, tokenNamePrefix: string): string[] => {
103
- const lines: string[] = ["{"];
104
-
105
- const keys = [...node.children.keys()].sort((a, b) => a.localeCompare(b));
106
- for (const key of keys) {
107
- const child = node.children.get(key);
108
- if (!child) continue;
109
-
110
- const fullTokenName = tokenNamePrefix ? `${tokenNamePrefix}.${key}` : key;
111
- const propKey = toPropertyKey(key);
112
-
113
- if (child.token && child.children.size === 0) {
114
- lines.push(...buildTokenJsDocLines(fullTokenName, child.token));
115
- lines.push(`${propKey}: "${fullTokenName}",`);
116
- continue;
117
- }
118
-
119
- const childLines = renderTreeTs(child, fullTokenName);
120
- lines.push(`${propKey}: ${childLines[0]}`);
121
- lines.push(...indentLines(childLines.slice(1), 2));
122
- lines[lines.length - 1] = `${lines[lines.length - 1]},`;
123
- }
124
-
125
- lines.push("}");
126
- return lines;
127
- };
128
-
129
- const renderTreeDts = (node: TokenTreeNode, tokenNamePrefix: string): string[] => {
130
- const lines: string[] = ["{"];
131
-
132
- const keys = [...node.children.keys()].sort((a, b) => a.localeCompare(b));
133
- for (const key of keys) {
134
- const child = node.children.get(key);
135
- if (!child) continue;
136
-
137
- const fullTokenName = tokenNamePrefix ? `${tokenNamePrefix}.${key}` : key;
138
- const propKey = toPropertyKey(key);
139
-
140
- if (child.token && child.children.size === 0) {
141
- lines.push(...buildTokenJsDocLines(fullTokenName, child.token));
142
- lines.push(`${propKey}: "${fullTokenName}";`);
143
- continue;
144
- }
145
-
146
- const childLines = renderTreeDts(child, fullTokenName);
147
- lines.push(`${propKey}: ${childLines[0]}`);
148
- lines.push(...indentLines(childLines.slice(1), 2));
149
- lines[lines.length - 1] = `${lines[lines.length - 1]};`;
150
- }
151
-
152
- lines.push("}");
153
- return lines;
154
- };
155
-
156
- export type GeneratedTokens = {
157
- tokenNames: string[];
158
- tokensTs: string;
159
- tokensDts: string;
160
- };
161
-
162
- /**
163
- * Generate `dist/palette/tokens.ts` and `dist/palette/tokens.d.ts` sources.
164
- *
165
- * Output is deterministic and derived from the token registry.
166
- */
167
- export const generateTokenArtifacts = (registry: TokenRegistry): GeneratedTokens => {
168
- const tokenNames = Object.keys(registry.tokens).sort((a, b) => a.localeCompare(b));
169
- const tree = buildTree(registry);
170
-
171
- const tokensObject = renderTreeTs(tree, "");
172
- const tokensDtsObject = renderTreeDts(tree, "");
173
-
174
- const tokensTs = `/* This file is generated by palette-kit build (Phase 7). */\n\nexport const tokens = ${tokensObject.join(
175
- "\n",
176
- )} as const;\n\nexport const tokenNames = ${JSON.stringify(
177
- tokenNames,
178
- null,
179
- 2,
180
- )} as const;\n\nexport type TokenName = (typeof tokenNames)[number];\n\nexport type ColorRole = TokenName;\n`;
181
-
182
- const tokensDts = `/* This file is generated by palette-kit build (Phase 7). */\n\nexport declare const tokens: ${tokensDtsObject.join(
183
- "\n",
184
- )};\n\nexport declare const tokenNames: readonly ${JSON.stringify(
185
- tokenNames,
186
- null,
187
- 2,
188
- )};\n\nexport type TokenName = (typeof tokenNames)[number];\n\nexport type ColorRole = TokenName;\n`;
189
-
190
- return { tokenNames, tokensTs, tokensDts };
191
- };
package/src/cli/config.ts DELETED
@@ -1,71 +0,0 @@
1
- import type { ThemeConfig } from "../engine/resolveBaseColor.js";
2
- import type { OutputOptions } from "../types/index.js";
3
-
4
- /**
5
- * Official token preset names supported by Palette Kit tooling.
6
- *
7
- * These map to `src/presets/tokens/*` registries.
8
- */
9
- export type TokenPresetName = "minimal-ui" | "radixLike-ui" | "modern-ui";
10
-
11
- /**
12
- * Configuration contract for `palette-kit build`.
13
- *
14
- * This file is consumed by the CLI and is intended to be used from
15
- * `palette.config.ts` created by `palette-kit init`.
16
- */
17
- export type PaletteConfig = {
18
- /**
19
- * Theme inputs for palette generation (seed colors + optional variants).
20
- */
21
- theme: ThemeConfig;
22
- /**
23
- * Token preset selection for exporters/CLI.
24
- */
25
- tokens: {
26
- preset: TokenPresetName;
27
- };
28
- /**
29
- * Exporter options (formatting, gamut mapping, precision).
30
- */
31
- output?: OutputOptions;
32
- };
33
-
34
- /**
35
- * Build a `palette.config.ts` template for `palette-kit init`.
36
- *
37
- * @param packageName - Import path used for `PaletteConfig` typing (usually the package name).
38
- */
39
- export const buildConfigTemplate = (
40
- packageName: string,
41
- ) => `import type { PaletteConfig } from "${packageName}";
42
-
43
- /**
44
- * Palette Kit configuration.
45
- * Update seeds, preset, and output options to match your design system.
46
- */
47
- const config: PaletteConfig = {
48
- theme: {
49
- seeds: {
50
- light: { neutral: "#8B8D98", accent: "#3D63DD" },
51
- dark: { neutral: "#8B8D98", accent: "#3D63DD" },
52
- },
53
- preset: "modern",
54
- },
55
- tokens: {
56
- preset: "modern-ui",
57
- },
58
- output: {
59
- preferSpace: "oklch",
60
- includeSpaces: ["srgb", "p3"],
61
- },
62
- };
63
-
64
- export default config;
65
- `;
66
-
67
- /**
68
- * Runtime guard for token preset strings coming from user config.
69
- */
70
- export const isTokenPresetName = (value: string): value is TokenPresetName =>
71
- value === "minimal-ui" || value === "radixLike-ui" || value === "modern-ui";
@@ -1,49 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import { validateConfig } from "./validate.js";
4
- import type { PaletteConfig } from "./config.js";
5
-
6
- describe("cli config validation", () => {
7
- it("accepts a valid config", () => {
8
- const config: PaletteConfig = {
9
- theme: {
10
- seeds: {
11
- light: { neutral: "#111827", accent: "#3d63dd" },
12
- dark: { neutral: "#111827", accent: "#3d63dd" },
13
- },
14
- },
15
- tokens: { preset: "modern-ui" },
16
- };
17
-
18
- expect(() => validateConfig(config)).not.toThrow();
19
- });
20
-
21
- it("rejects missing neutral/accent", () => {
22
- const config = {
23
- theme: {
24
- seeds: {
25
- light: { neutral: "#111827" },
26
- dark: { accent: "#3d63dd" },
27
- },
28
- },
29
- tokens: { preset: "modern-ui" },
30
- } as unknown as PaletteConfig;
31
-
32
- expect(() => validateConfig(config)).toThrow(/must be a string color/);
33
- });
34
-
35
- it("rejects invalid preset", () => {
36
- const config = {
37
- theme: {
38
- seeds: {
39
- light: { neutral: "#111827", accent: "#3d63dd" },
40
- dark: { neutral: "#111827", accent: "#3d63dd" },
41
- },
42
- },
43
- tokens: { preset: "nope" },
44
- } as unknown as PaletteConfig;
45
-
46
- expect(() => validateConfig(config)).toThrow(/Unsupported token preset/);
47
- });
48
- });
49
-
@@ -1,38 +0,0 @@
1
- import { isTokenPresetName, type PaletteConfig } from "./config.js";
2
-
3
- const validateSeed = (context: "light" | "dark", value: unknown) => {
4
- if (!value || typeof value !== "object") {
5
- throw new Error(`Config.theme.seeds.${context} must be an object`);
6
- }
7
- const seed = value as Record<string, unknown>;
8
- if (typeof seed.neutral !== "string") {
9
- throw new Error(`Config.theme.seeds.${context}.neutral must be a string color`);
10
- }
11
- if (typeof seed.accent !== "string") {
12
- throw new Error(`Config.theme.seeds.${context}.accent must be a string color`);
13
- }
14
- };
15
-
16
- export const validateConfig = (config: PaletteConfig) => {
17
- if (!config || typeof config !== "object") {
18
- throw new Error("Config must export a default object");
19
- }
20
- if (!config.theme) {
21
- throw new Error("Config.theme is required");
22
- }
23
-
24
- const seeds = config.theme.seeds;
25
- if (!seeds?.light || !seeds?.dark) {
26
- throw new Error("Config.theme.seeds.light and .dark are required");
27
- }
28
-
29
- validateSeed("light", seeds.light);
30
- validateSeed("dark", seeds.dark);
31
-
32
- if (!config.tokens?.preset) {
33
- throw new Error("Config.tokens.preset is required");
34
- }
35
- if (!isTokenPresetName(config.tokens.preset)) {
36
- throw new Error(`Unsupported token preset: ${config.tokens.preset}`);
37
- }
38
- };
package/src/cli.ts DELETED
@@ -1,183 +0,0 @@
1
- #!/usr/bin/env node
2
- import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
3
- import { basename, join, resolve } from "node:path";
4
- import { pathToFileURL } from "node:url";
5
- import { CliUsageError, COMMANDS, HELP_TEXT, type ParsedArgs, parseArgs } from "./cli/args.js";
6
- import { generateTokenArtifacts } from "./cli/codegen/tokens.js";
7
- import { buildConfigTemplate, type PaletteConfig } from "./cli/config.js";
8
- import { validateConfig } from "./cli/validate.js";
9
- import { createTheme } from "./core/createTheme.js";
10
- import { validateTokenRegistry } from "./core/tokenRegistry.js";
11
- import type { ThemeTokens } from "./export/exportTheme.js";
12
- import { exportThemeCss, exportThemeJson } from "./export/exportTheme.js";
13
- import { minimalUiTokens, modernUiTokens, radixLikeUiTokens } from "./presets/tokens/index.js";
14
-
15
- const readPackageJson = async () => {
16
- const url = new URL("../package.json", import.meta.url);
17
- const content = await readFile(url, "utf8");
18
- return JSON.parse(content) as { name: string; version: string };
19
- };
20
-
21
- const printHelp = () => {
22
- console.log(HELP_TEXT);
23
- };
24
-
25
- const printVersion = async () => {
26
- const pkg = await readPackageJson();
27
- console.log(pkg.version);
28
- };
29
-
30
- const ensureDir = async (dir: string) => {
31
- await mkdir(dir, { recursive: true });
32
- };
33
-
34
- const exists = async (filePath: string) => {
35
- try {
36
- await stat(filePath);
37
- return true;
38
- } catch {
39
- return false;
40
- }
41
- };
42
-
43
- const loadConfig = async (configPath: string): Promise<PaletteConfig> => {
44
- const resolved = resolve(configPath);
45
- try {
46
- const module = await import(pathToFileURL(resolved).href);
47
- const config = (module.default ?? module) as PaletteConfig;
48
- return config;
49
- } catch (error) {
50
- const suffix = resolved.endsWith(".ts")
51
- ? "\nTip: Use a .mjs config or run Node with a TS loader (e.g. tsx)."
52
- : "";
53
- const message = error instanceof Error ? error.message : String(error);
54
- throw new Error(`Unable to load config at ${resolved}. ${message}${suffix}`);
55
- }
56
- };
57
-
58
- const tokenPresetMap = {
59
- "minimal-ui": minimalUiTokens,
60
- "radixLike-ui": radixLikeUiTokens,
61
- "modern-ui": modernUiTokens,
62
- };
63
-
64
- const toThemeTokens = (registry: typeof minimalUiTokens): ThemeTokens =>
65
- Object.fromEntries(Object.entries(registry.tokens).map(([name, token]) => [name, token.query]));
66
-
67
- const writeTokensCodegen = async (outDir: string, registry: typeof minimalUiTokens) => {
68
- const generated = generateTokenArtifacts(registry);
69
- await writeFile(join(outDir, "tokens.ts"), generated.tokensTs, "utf8");
70
- await writeFile(join(outDir, "tokens.d.ts"), generated.tokensDts, "utf8");
71
- return generated.tokenNames;
72
- };
73
-
74
- const writeReport = async (
75
- outDir: string,
76
- config: PaletteConfig,
77
- tokenCount: number,
78
- outputFiles: string[],
79
- ) => {
80
- const lines = [
81
- "# Palette Kit Report",
82
- "",
83
- `- preset: ${config.tokens.preset}`,
84
- `- tokens: ${tokenCount}`,
85
- `- output: preferSpace=${config.output?.preferSpace ?? "oklch"}`,
86
- `- includeSpaces: ${(config.output?.includeSpaces ?? []).join(", ") || "(none)"}`,
87
- `- files: ${outputFiles.join(", ")}`,
88
- ];
89
-
90
- await writeFile(join(outDir, "report.md"), `${lines.join("\n")}\n`, "utf8");
91
- };
92
-
93
- const runInit = async (flags: ParsedArgs["flags"]) => {
94
- const targetPath = typeof flags.path === "string" ? flags.path : ".";
95
- const force = Boolean(flags.force);
96
- const outDir = resolve(targetPath);
97
- await ensureDir(outDir);
98
-
99
- const filePath = join(outDir, "palette.config.ts");
100
- if (!force && (await exists(filePath))) {
101
- throw new Error(`Config already exists at ${filePath}. Use --force to overwrite`);
102
- }
103
-
104
- const pkg = await readPackageJson();
105
- await writeFile(filePath, buildConfigTemplate(pkg.name), "utf8");
106
-
107
- console.log(`Created ${filePath}`);
108
- };
109
-
110
- const runBuild = async (flags: ParsedArgs["flags"]) => {
111
- const configPath = typeof flags.config === "string" ? flags.config : "palette.config.ts";
112
- const outDir = resolve(typeof flags.outDir === "string" ? flags.outDir : "dist/palette");
113
- const report = Boolean(flags.report);
114
-
115
- const config = await loadConfig(configPath);
116
- validateConfig(config);
117
-
118
- const registry = tokenPresetMap[config.tokens.preset];
119
- validateTokenRegistry(registry);
120
-
121
- const theme = createTheme(config.theme);
122
- const tokens = toThemeTokens(registry);
123
-
124
- const css = exportThemeCss(theme, tokens, config.output).css;
125
- const json = exportThemeJson(theme, tokens, config.output);
126
-
127
- await ensureDir(outDir);
128
- const tokenNames = await writeTokensCodegen(outDir, registry);
129
-
130
- await writeFile(join(outDir, "tokens.css"), css, "utf8");
131
- await writeFile(join(outDir, "tokens.json"), `${JSON.stringify(json, null, 2)}\n`, "utf8");
132
-
133
- if (report) {
134
- await writeReport(outDir, config, tokenNames.length, [
135
- "tokens.css",
136
- "tokens.json",
137
- "tokens.ts",
138
- "tokens.d.ts",
139
- ]);
140
- }
141
-
142
- console.log(`Wrote ${basename(outDir)}/tokens.css, tokens.json, tokens.ts, tokens.d.ts`);
143
- };
144
-
145
- const main = async () => {
146
- try {
147
- const parsed = parseArgs(process.argv.slice(2));
148
-
149
- if (parsed.version) {
150
- await printVersion();
151
- return;
152
- }
153
-
154
- if (parsed.help || !parsed.command) {
155
- printHelp();
156
- return;
157
- }
158
-
159
- if (!COMMANDS.includes(parsed.command as (typeof COMMANDS)[number])) {
160
- throw new CliUsageError(`Unknown command: ${parsed.command}`);
161
- }
162
-
163
- if (parsed.command === "init") {
164
- await runInit(parsed.flags);
165
- return;
166
- }
167
-
168
- if (parsed.command === "build") {
169
- await runBuild(parsed.flags);
170
- return;
171
- }
172
- } catch (error) {
173
- const message = error instanceof Error ? error.message : String(error);
174
- console.error(message);
175
- if (error instanceof CliUsageError) {
176
- console.error("");
177
- printHelp();
178
- }
179
- process.exitCode = 1;
180
- }
181
- };
182
-
183
- void main();
@@ -1,20 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import { computeApcaLc } from "./apca.js";
4
-
5
- describe("computeApcaLc", () => {
6
- it("reports high magnitude for black on white", () => {
7
- const lc = computeApcaLc({ r: 0, g: 0, b: 0 }, { r: 1, g: 1, b: 1 });
8
- expect(Math.abs(lc)).toBeGreaterThan(60);
9
- });
10
-
11
- it("reports high magnitude for white on black", () => {
12
- const lc = computeApcaLc({ r: 1, g: 1, b: 1 }, { r: 0, g: 0, b: 0 });
13
- expect(Math.abs(lc)).toBeGreaterThan(60);
14
- });
15
-
16
- it("does not return NaN", () => {
17
- const lc = computeApcaLc({ r: 0.2, g: 0.4, b: 0.6 }, { r: 0.1, g: 0.1, b: 0.1 });
18
- expect(Number.isNaN(lc)).toBe(false);
19
- });
20
- });
@@ -1,26 +0,0 @@
1
- import { APCAcontrast, sRGBtoY } from "apca-w3";
2
-
3
- import type { SrgbColor } from "./types.js";
4
-
5
- // NOTE:
6
- // sRGBtoY expects 0-255 RGB values (3-tuple). Also APCA impl can yield
7
- // a string|number, so normalize to number before Number.isFinite.
8
-
9
- type SrgbTriplet = [r: number, g: number, b: number];
10
-
11
- const clamp01 = (value: number) => Math.min(1, Math.max(0, value));
12
-
13
- const toApcaInput = (color: SrgbColor): SrgbTriplet => [
14
- clamp01(color.r) * 255,
15
- clamp01(color.g) * 255,
16
- clamp01(color.b) * 255,
17
- ];
18
-
19
- export function computeApcaLc(fg: SrgbColor, bg: SrgbColor): number {
20
- const fgY = sRGBtoY(toApcaInput(fg));
21
- const bgY = sRGBtoY(toApcaInput(bg));
22
- const raw = APCAcontrast(fgY, bgY);
23
- const value = typeof raw === "number" ? raw : Number(raw);
24
- // Fail-soft to avoid propagating NaN into solver scoring.
25
- return Number.isFinite(value) ? value : 0;
26
- }
@@ -1,4 +0,0 @@
1
- export * from "./apca.js";
2
- export * from "./solver.js";
3
- export * from "./types.js";
4
- export * from "./wcag2.js";