@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,6 +0,0 @@
1
- import type { TokenRegistry } from "../../types/index.js";
2
- /**
3
- * Minimal token preset aimed at quick adoption.
4
- * Focuses on a small, coherent base set for app surfaces and text.
5
- */
6
- export declare const minimalUiTokens: TokenRegistry;
@@ -1,53 +0,0 @@
1
- /**
2
- * Minimal token preset aimed at quick adoption.
3
- * Focuses on a small, coherent base set for app surfaces and text.
4
- */
5
- export const minimalUiTokens = {
6
- tokens: {
7
- "bg.app": {
8
- name: "bg.app",
9
- description: "Base application background.",
10
- category: "background",
11
- query: { role: "bg.app", usage: "bg", surface: "app" },
12
- },
13
- "bg.surface": {
14
- name: "bg.surface",
15
- description: "Default surface background for containers.",
16
- category: "background",
17
- query: { role: "bg.surface", usage: "bg", surface: "surface" },
18
- },
19
- "text.primary": {
20
- name: "text.primary",
21
- description: "Primary text on standard surfaces.",
22
- category: "text",
23
- query: { role: "text.primary", usage: "text", surface: "surface" },
24
- },
25
- "text.secondary": {
26
- name: "text.secondary",
27
- description: "Secondary text on standard surfaces.",
28
- category: "text",
29
- query: { role: "text.secondary", usage: "text", surface: "surface", emphasis: "muted" },
30
- },
31
- "border.default": {
32
- name: "border.default",
33
- description: "Default border for surfaces and containers.",
34
- category: "border",
35
- query: { role: "border.default", usage: "border", surface: "surface" },
36
- states: { hover: true },
37
- },
38
- "icon.default": {
39
- name: "icon.default",
40
- description: "Default icon color on standard surfaces.",
41
- category: "icon",
42
- query: { role: "icon.default", usage: "icon", surface: "surface" },
43
- states: { hover: true },
44
- },
45
- "ring.default": {
46
- name: "ring.default",
47
- description: "Base ring color (derive focus via state operator).",
48
- category: "ring",
49
- query: { role: "ring.default", usage: "ring", surface: "surface", emphasis: "strong" },
50
- states: { focus: true },
51
- },
52
- },
53
- };
@@ -1,5 +0,0 @@
1
- import type { TokenRegistry } from "../../types/index.js";
2
- /**
3
- * Modern preset aimed at richer UI surfaces with strong emphasis options.
4
- */
5
- export declare const modernUiTokens: TokenRegistry;
@@ -1,83 +0,0 @@
1
- /**
2
- * Modern preset aimed at richer UI surfaces with strong emphasis options.
3
- */
4
- export const modernUiTokens = {
5
- tokens: {
6
- "bg.app": {
7
- name: "bg.app",
8
- description: "Primary application background.",
9
- category: "background",
10
- query: { role: "bg.app", usage: "bg", surface: "app" },
11
- },
12
- "bg.surface": {
13
- name: "bg.surface",
14
- description: "Default surface background for content containers.",
15
- category: "background",
16
- query: { role: "bg.surface", usage: "bg", surface: "surface" },
17
- },
18
- "bg.subtle": {
19
- name: "bg.subtle",
20
- description: "Subtle surface for secondary sections.",
21
- category: "background",
22
- query: { role: "bg.subtle", usage: "bg", surface: "subtle" },
23
- },
24
- "bg.solid": {
25
- name: "bg.solid",
26
- description: "Solid surface for emphasized elements.",
27
- category: "background",
28
- query: { role: "bg.solid", usage: "bg", surface: "solid" },
29
- states: { hover: true, active: true },
30
- },
31
- "text.primary": {
32
- name: "text.primary",
33
- description: "Primary text for default surfaces.",
34
- category: "text",
35
- query: { role: "text.primary", usage: "text", surface: "surface" },
36
- },
37
- "text.secondary": {
38
- name: "text.secondary",
39
- description: "Secondary text for supporting content.",
40
- category: "text",
41
- query: { role: "text.secondary", usage: "text", surface: "surface", emphasis: "muted" },
42
- },
43
- "text.inverse": {
44
- name: "text.inverse",
45
- description: "Inverse text for solid or accented surfaces.",
46
- category: "text",
47
- query: { role: "text.inverse", usage: "text", surface: "solid", emphasis: "inverted" },
48
- },
49
- "border.default": {
50
- name: "border.default",
51
- description: "Default border for containers and layout.",
52
- category: "border",
53
- query: { role: "border.default", usage: "border", surface: "surface" },
54
- },
55
- "border.strong": {
56
- name: "border.strong",
57
- description: "High-emphasis border for focused containers.",
58
- category: "border",
59
- query: { role: "border.strong", usage: "border", surface: "surface", emphasis: "strong" },
60
- states: { hover: true },
61
- },
62
- "icon.default": {
63
- name: "icon.default",
64
- description: "Primary icon color for default surfaces.",
65
- category: "icon",
66
- query: { role: "icon.default", usage: "icon", surface: "surface" },
67
- states: { hover: true },
68
- },
69
- "icon.muted": {
70
- name: "icon.muted",
71
- description: "Muted icons for less prominent actions.",
72
- category: "icon",
73
- query: { role: "icon.muted", usage: "icon", surface: "surface", emphasis: "muted" },
74
- },
75
- "ring.default": {
76
- name: "ring.default",
77
- description: "Base ring color (derive focus via state operator).",
78
- category: "ring",
79
- query: { role: "ring.default", usage: "ring", surface: "surface", emphasis: "strong" },
80
- states: { focus: true },
81
- },
82
- },
83
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1,31 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { createTheme } from "../../core/createTheme.js";
3
- import { minimalUiTokens, modernUiTokens, radixLikeUiTokens, } from "./index.js";
4
- import { validateTokenRegistry } from "../../core/tokenRegistry.js";
5
- import { exportThemeCss, exportThemeJson } from "../../export/exportTheme.js";
6
- const toThemeTokens = (registry) => Object.fromEntries(Object.entries(registry.tokens).map(([name, token]) => [name, token.query]));
7
- describe("token presets", () => {
8
- const theme = createTheme({
9
- seeds: {
10
- light: { neutral: "#8B8D98", accent: "#3D63DD" },
11
- dark: { neutral: "#8B8D98", accent: "#3D63DD" },
12
- },
13
- preset: "modern",
14
- });
15
- it("validates all preset registries", () => {
16
- expect(() => validateTokenRegistry(minimalUiTokens)).not.toThrow();
17
- expect(() => validateTokenRegistry(radixLikeUiTokens)).not.toThrow();
18
- expect(() => validateTokenRegistry(modernUiTokens)).not.toThrow();
19
- });
20
- it("exports CSS/JSON for each preset", () => {
21
- const registries = [minimalUiTokens, radixLikeUiTokens, modernUiTokens];
22
- for (const registry of registries) {
23
- const tokens = toThemeTokens(registry);
24
- const css = exportThemeCss(theme, tokens, { preferSpace: "oklch" }).css;
25
- const json = exportThemeJson(theme, tokens, { preferSpace: "oklch" }).tokens;
26
- expect(css.length).toBeGreaterThan(0);
27
- expect(Object.keys(json.light).length).toBeGreaterThan(0);
28
- expect(Object.keys(json.dark).length).toBeGreaterThan(0);
29
- }
30
- });
31
- });
@@ -1,6 +0,0 @@
1
- import type { TokenRegistry } from "../../types/index.js";
2
- /**
3
- * Radix-like preset aligned with common component library semantics.
4
- * Expands coverage for subtle/surface/solid layers and semantic text.
5
- */
6
- export declare const radixLikeUiTokens: TokenRegistry;
@@ -1,77 +0,0 @@
1
- /**
2
- * Radix-like preset aligned with common component library semantics.
3
- * Expands coverage for subtle/surface/solid layers and semantic text.
4
- */
5
- export const radixLikeUiTokens = {
6
- tokens: {
7
- "bg.app": {
8
- name: "bg.app",
9
- description: "Application background for the overall canvas.",
10
- category: "background",
11
- query: { role: "bg.app", usage: "bg", surface: "app" },
12
- },
13
- "bg.surface": {
14
- name: "bg.surface",
15
- description: "Base surface background for cards and panels.",
16
- category: "background",
17
- query: { role: "bg.surface", usage: "bg", surface: "surface" },
18
- },
19
- "bg.subtle": {
20
- name: "bg.subtle",
21
- description: "Subtle background for secondary sections.",
22
- category: "background",
23
- query: { role: "bg.subtle", usage: "bg", surface: "subtle" },
24
- },
25
- "bg.solid": {
26
- name: "bg.solid",
27
- description: "Solid background for high-emphasis elements.",
28
- category: "background",
29
- query: { role: "bg.solid", usage: "bg", surface: "solid" },
30
- states: { hover: true, active: true },
31
- },
32
- "text.primary": {
33
- name: "text.primary",
34
- description: "Primary text on standard surfaces.",
35
- category: "text",
36
- query: { role: "text.primary", usage: "text", surface: "surface" },
37
- },
38
- "text.secondary": {
39
- name: "text.secondary",
40
- description: "Secondary text for supporting content.",
41
- category: "text",
42
- query: { role: "text.secondary", usage: "text", surface: "surface", emphasis: "muted" },
43
- },
44
- "text.inverse": {
45
- name: "text.inverse",
46
- description: "Inverse text for solid backgrounds.",
47
- category: "text",
48
- query: { role: "text.inverse", usage: "text", surface: "solid", emphasis: "inverted" },
49
- },
50
- "border.default": {
51
- name: "border.default",
52
- description: "Default border for layout and surfaces.",
53
- category: "border",
54
- query: { role: "border.default", usage: "border", surface: "surface" },
55
- },
56
- "border.subtle": {
57
- name: "border.subtle",
58
- description: "Subtle border for separators.",
59
- category: "border",
60
- query: { role: "border.subtle", usage: "border", surface: "subtle" },
61
- },
62
- "icon.default": {
63
- name: "icon.default",
64
- description: "Default icon color on surfaces.",
65
- category: "icon",
66
- query: { role: "icon.default", usage: "icon", surface: "surface" },
67
- states: { hover: true },
68
- },
69
- "ring.default": {
70
- name: "ring.default",
71
- description: "Base ring color (derive focus via state operator).",
72
- category: "ring",
73
- query: { role: "ring.default", usage: "ring", surface: "surface", emphasis: "strong" },
74
- states: { focus: true },
75
- },
76
- },
77
- };
@@ -1 +0,0 @@
1
- export { serializeColor, serializeResolved } from "./serializeColor.js";
@@ -1 +0,0 @@
1
- export { serializeColor, serializeResolved } from "./serializeColor.js";
@@ -1,6 +0,0 @@
1
- import type { OutputOptions } from "../types/index.js";
2
- export type NormalizedOutput = Required<Pick<OutputOptions, "preferSpace" | "includeSpaces" | "gamutMapping" | "strict" | "srgbFormat">> & {
3
- precision: Required<NonNullable<OutputOptions["precision"]>>;
4
- includeMeta: boolean;
5
- };
6
- export declare const normalizeOutput: (output?: OutputOptions) => NormalizedOutput;
@@ -1,45 +0,0 @@
1
- const gamutMappings = [
2
- "clip",
3
- "compressChroma",
4
- "preferP3ThenCompress",
5
- ];
6
- const srgbFormats = ["hex", "rgb", "rgba"];
7
- const formatString = (value) => (value ? value.trim() : undefined);
8
- const assertOneOf = (value, options, label) => {
9
- if (!options.includes(value)) {
10
- throw new Error(`${label} must be one of: ${options.join(", ")} (received "${value}")`);
11
- }
12
- return value;
13
- };
14
- export const normalizeOutput = (output) => {
15
- const preferSpaceValue = formatString(output?.preferSpace);
16
- const gamutMappingValue = formatString(output?.gamutMapping);
17
- const srgbFormatValue = formatString(output?.srgbFormat);
18
- const preferSpace = preferSpaceValue
19
- ? assertOneOf(preferSpaceValue, ["oklch", "srgb", "p3"], "output preferSpace")
20
- : "oklch";
21
- const gamutMapping = gamutMappingValue
22
- ? assertOneOf(gamutMappingValue, gamutMappings, "output gamutMapping")
23
- : "preferP3ThenCompress";
24
- const srgbFormat = srgbFormatValue
25
- ? assertOneOf(srgbFormatValue, srgbFormats, "output srgbFormat")
26
- : "hex";
27
- if (output?.strict !== undefined && typeof output.strict !== "boolean") {
28
- throw new Error("Output strict must be a boolean");
29
- }
30
- return {
31
- preferSpace,
32
- includeSpaces: output?.includeSpaces ?? [],
33
- gamutMapping,
34
- precision: {
35
- l: 1,
36
- c: 3,
37
- h: 1,
38
- alpha: 2,
39
- ...output?.precision,
40
- },
41
- strict: output?.strict ?? false,
42
- includeMeta: output?.includeMeta ?? false,
43
- srgbFormat,
44
- };
45
- };
@@ -1,21 +0,0 @@
1
- import type { OkLchColor } from "../engine/generateScale.js";
2
- import type { BaseResolvedColor } from "../engine/resolveBaseColor.js";
3
- import type { ColorMeta, OutputOptions, ResolvedColor } from "../types/index.js";
4
- type SerializedColorJson = ResolvedColor;
5
- /**
6
- * Serialize raw OKLCH channels into CSS-ready strings for the requested spaces.
7
- *
8
- * @param color - OKLCH channels resolved by the core resolver.
9
- * @param output - Serialization options for precision, gamut mapping, and output spaces.
10
- * @param meta - Optional metadata to include when `includeMeta` is enabled.
11
- */
12
- export declare const serializeColor: (color: OkLchColor, output?: OutputOptions, meta?: ColorMeta) => ResolvedColor;
13
- /**
14
- * Serialize a resolver output while preserving resolver metadata.
15
- *
16
- * @param color - Result of the core resolver.
17
- * @param output - Serialization options for precision, gamut mapping, and output spaces.
18
- */
19
- export declare const serializeResolved: (color: BaseResolvedColor, output?: OutputOptions) => ResolvedColor;
20
- export declare const serializeColorJson: (color: OkLchColor, output?: OutputOptions, meta?: ColorMeta) => SerializedColorJson;
21
- export {};
@@ -1,178 +0,0 @@
1
- import { formatHex, formatHex8 } from "culori";
2
- import { isInGamut, mapToGamut, toGamutRgb } from "../engine/gamut.js";
3
- import { clamp } from "../utils/clamp.js";
4
- import { normalizeOutput } from "./normalizeOutput.js";
5
- const roundTo = (value, digits) => {
6
- const factor = 10 ** digits;
7
- return Math.round(value * factor) / factor;
8
- };
9
- const formatNumber = (value, digits) => {
10
- const rounded = roundTo(value, digits);
11
- if (digits === 0) {
12
- return String(Math.round(rounded));
13
- }
14
- const fixed = rounded.toFixed(digits);
15
- return fixed.replace(/\.?0+$/, "");
16
- };
17
- const normalizeHue = (hue) => ((hue % 360) + 360) % 360;
18
- const formatOklch = (color, precision) => {
19
- const alpha = clamp(color.alpha ?? 1, 0, 1);
20
- const hasAlpha = alpha < 1;
21
- const l = formatNumber(clamp(color.l, 0, 100), precision.l);
22
- const c = formatNumber(Math.max(0, color.c), precision.c);
23
- const h = formatNumber(normalizeHue(color.h), precision.h);
24
- const alphaPart = hasAlpha ? ` / ${formatNumber(alpha, precision.alpha)}` : "";
25
- return `oklch(${l}% ${c} ${h}${alphaPart})`;
26
- };
27
- const formatDisplayP3 = (rgb, alpha, precision) => {
28
- const r = formatNumber(clamp(rgb.r, 0, 1), precision.c);
29
- const g = formatNumber(clamp(rgb.g, 0, 1), precision.c);
30
- const b = formatNumber(clamp(rgb.b, 0, 1), precision.c);
31
- const alphaPart = alpha < 1 ? ` / ${formatNumber(alpha, precision.alpha)}` : "";
32
- return `color(display-p3 ${r} ${g} ${b}${alphaPart})`;
33
- };
34
- const formatSrgbHex = (rgb, alpha) => {
35
- const rgbColor = {
36
- mode: "rgb",
37
- r: clamp(rgb.r, 0, 1),
38
- g: clamp(rgb.g, 0, 1),
39
- b: clamp(rgb.b, 0, 1),
40
- alpha,
41
- };
42
- return alpha < 1 ? formatHex8(rgbColor) : formatHex(rgbColor);
43
- };
44
- const formatSrgbFunction = (rgb, alpha, precision, forceAlpha) => {
45
- const toChannel = (value) => String(Math.round(clamp(value, 0, 1) * 255));
46
- const r = toChannel(rgb.r);
47
- const g = toChannel(rgb.g);
48
- const b = toChannel(rgb.b);
49
- if (forceAlpha || alpha < 1) {
50
- return `rgba(${r} ${g} ${b} / ${formatNumber(alpha, precision.alpha)})`;
51
- }
52
- return `rgb(${r} ${g} ${b})`;
53
- };
54
- const formatSrgb = (rgb, alpha, output) => {
55
- switch (output.srgbFormat) {
56
- case "rgb":
57
- return formatSrgbFunction(rgb, alpha, output.precision, false);
58
- case "rgba":
59
- return formatSrgbFunction(rgb, alpha, output.precision, true);
60
- default:
61
- return formatSrgbHex(rgb, alpha);
62
- }
63
- };
64
- const buildDiagnostics = (spaceUsed, clipped, compressed) => ({
65
- spaceUsed,
66
- ...(clipped ? { clipped } : {}),
67
- ...(compressed ? { compressed } : {}),
68
- });
69
- const buildMeta = (meta, output, diagnostics) => output.includeMeta
70
- ? {
71
- ...meta,
72
- spaceUsed: diagnostics.spaceUsed,
73
- gamutMapping: output.gamutMapping,
74
- ...(diagnostics.clipped ? { clipped: diagnostics.clipped } : {}),
75
- ...(diagnostics.compressed ? { compressed: diagnostics.compressed } : {}),
76
- }
77
- : undefined;
78
- const resolveAlpha = (baseAlpha, mapped) => clamp(mapped?.alpha ?? baseAlpha, 0, 1);
79
- const requirePreferredSpace = (prefer, strict, value, fallback) => {
80
- if (!strict)
81
- return value ?? fallback;
82
- // In strict mode, do not silently fall back for explicit non-oklch preferences.
83
- if (prefer !== "oklch" && !value) {
84
- throw new Error(`Unable to serialize preferred space: ${prefer}`);
85
- }
86
- return value ?? fallback;
87
- };
88
- const resolveUsedSpace = (prefer, preferredValue) => {
89
- if (prefer === "oklch") {
90
- return "oklch";
91
- }
92
- return preferredValue ? prefer : "oklch";
93
- };
94
- /**
95
- * Serialize raw OKLCH channels into CSS-ready strings for the requested spaces.
96
- *
97
- * @param color - OKLCH channels resolved by the core resolver.
98
- * @param output - Serialization options for precision, gamut mapping, and output spaces.
99
- * @param meta - Optional metadata to include when `includeMeta` is enabled.
100
- */
101
- export const serializeColor = (color, output, meta) => {
102
- const normalized = normalizeOutput(output);
103
- const alpha = clamp(color.alpha ?? 1, 0, 1);
104
- const spaces = new Set([normalized.preferSpace, ...normalized.includeSpaces]);
105
- const oklchText = formatOklch(color, normalized.precision);
106
- const needsSrgb = spaces.has("srgb") || normalized.preferSpace === "srgb";
107
- const srgbInGamut = needsSrgb ? isInGamut(color, "srgb") : false;
108
- const srgbColor = needsSrgb
109
- ? mapToGamut(color, "srgb", normalized.gamutMapping, normalized.strict)
110
- : undefined;
111
- const srgbRgb = srgbColor ? toGamutRgb(srgbColor, "srgb") : null;
112
- const srgbAlpha = resolveAlpha(alpha, srgbColor);
113
- const srgbText = srgbRgb ? formatSrgb(srgbRgb, srgbAlpha, normalized) : undefined;
114
- const srgbClipped = needsSrgb && normalized.gamutMapping === "clip" && !srgbInGamut;
115
- const srgbCompressed = needsSrgb && normalized.gamutMapping !== "clip" && !srgbInGamut ? true : undefined;
116
- const needsP3 = spaces.has("p3") || normalized.preferSpace === "p3";
117
- const p3InGamut = needsP3 ? isInGamut(color, "p3") : false;
118
- const p3Color = needsP3
119
- ? normalized.gamutMapping === "preferP3ThenCompress" && p3InGamut
120
- ? color
121
- : mapToGamut(color, "p3", normalized.gamutMapping, normalized.strict)
122
- : undefined;
123
- const p3Rgb = p3Color ? toGamutRgb(p3Color, "p3") : null;
124
- const p3Alpha = resolveAlpha(alpha, p3Color);
125
- const p3Text = p3Rgb ? formatDisplayP3(p3Rgb, p3Alpha, normalized.precision) : undefined;
126
- const p3Clipped = needsP3 && normalized.gamutMapping === "clip" && !p3InGamut;
127
- const p3Compressed = needsP3 && normalized.gamutMapping !== "clip" && !p3InGamut ? true : undefined;
128
- const preferredValue = normalized.preferSpace === "srgb"
129
- ? srgbText
130
- : normalized.preferSpace === "p3"
131
- ? p3Text
132
- : oklchText;
133
- const value = (() => {
134
- if (normalized.preferSpace === "srgb") {
135
- return requirePreferredSpace("srgb", normalized.strict, srgbText, oklchText);
136
- }
137
- if (normalized.preferSpace === "p3") {
138
- return requirePreferredSpace("p3", normalized.strict, p3Text, oklchText);
139
- }
140
- return oklchText;
141
- })();
142
- const spaceUsed = resolveUsedSpace(normalized.preferSpace, preferredValue);
143
- const diagnostics = (() => {
144
- if (spaceUsed === "srgb") {
145
- return buildDiagnostics(spaceUsed, srgbClipped, srgbCompressed);
146
- }
147
- if (spaceUsed === "p3") {
148
- return buildDiagnostics(spaceUsed, p3Clipped, p3Compressed);
149
- }
150
- return buildDiagnostics(spaceUsed);
151
- })();
152
- return {
153
- value,
154
- srgb: spaces.has("srgb") ? srgbText : undefined,
155
- p3: spaces.has("p3") ? p3Text : undefined,
156
- oklch: spaces.has("oklch") ? oklchText : undefined,
157
- alpha,
158
- meta: buildMeta(meta, normalized, diagnostics),
159
- };
160
- };
161
- /**
162
- * Serialize a resolver output while preserving resolver metadata.
163
- *
164
- * @param color - Result of the core resolver.
165
- * @param output - Serialization options for precision, gamut mapping, and output spaces.
166
- */
167
- export const serializeResolved = (color, output) => {
168
- const meta = {
169
- step: color.step,
170
- variantUsed: color.variantUsed,
171
- seedUsed: color.seedUsed,
172
- };
173
- return serializeColor(color.oklch, output, meta);
174
- };
175
- export const serializeColorJson = (color, output, meta) => {
176
- // JSON export is string-based and mirrors CSS serialization intentionally.
177
- return serializeColor(color, output, meta);
178
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1,45 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { createTheme } from "../core/createTheme.js";
3
- import { serializeColor, serializeResolved } from "./serializeColor.js";
4
- describe("serializeResolved", () => {
5
- it("includes resolver metadata when includeMeta is true", () => {
6
- const resolved = {
7
- oklch: { l: 60, c: 0.2, h: 40, alpha: 0.5 },
8
- step: 7,
9
- variantUsed: "accent",
10
- seedUsed: "#123456",
11
- };
12
- const result = serializeResolved(resolved, { includeMeta: true, preferSpace: "oklch" });
13
- expect(result.meta?.step).toBe(7);
14
- expect(result.meta?.variantUsed).toBe("accent");
15
- expect(result.meta?.seedUsed).toBe("#123456");
16
- expect(result.meta?.spaceUsed).toBe("oklch");
17
- expect(result.meta?.gamutMapping).toBe("preferP3ThenCompress");
18
- });
19
- });
20
- describe("serializeColor", () => {
21
- it("uses rgba output when explicitly requested", () => {
22
- const color = { l: 60, c: 0.2, h: 40, alpha: 1 };
23
- const result = serializeColor(color, { preferSpace: "srgb", srgbFormat: "rgba" });
24
- expect(result.value.startsWith("rgba(")).toBe(true);
25
- });
26
- });
27
- describe("theme.serialize", () => {
28
- it("serializes a resolved query using the theme", () => {
29
- const theme = createTheme({
30
- seeds: {
31
- light: { neutral: "#8B8D98", accent: "#3D63DD" },
32
- dark: { neutral: "#8B8D98", accent: "#3D63DD" },
33
- },
34
- preset: "modern",
35
- });
36
- const result = theme.serialize({
37
- role: "bg.solid",
38
- usage: "bg",
39
- surface: "solid",
40
- context: "light",
41
- }, { preferSpace: "oklch" });
42
- expect(result.value.startsWith("oklch(")).toBe(true);
43
- expect(result.alpha).toBeGreaterThanOrEqual(0);
44
- });
45
- });
@@ -1 +0,0 @@
1
- export * from "./serialize/index.js";
package/dist/serialize.js DELETED
@@ -1 +0,0 @@
1
- export * from "./serialize/index.js";
@@ -1 +0,0 @@
1
- export declare const clamp: (value: number, min: number, max: number) => number;
@@ -1 +0,0 @@
1
- export const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
@@ -1 +0,0 @@
1
- export { parseColor } from "./parseColor.js";
@@ -1 +0,0 @@
1
- export { parseColor } from "./parseColor.js";
@@ -1 +0,0 @@
1
- export declare const lerp: (start: number, end: number, t: number) => number;
@@ -1 +0,0 @@
1
- export const lerp = (start, end, t) => start + (end - start) * t;
@@ -1,6 +0,0 @@
1
- import type { CssColorString, RawColor } from "../types/index.js";
2
- export declare function parseColor(input: CssColorString): {
3
- input: CssColorString;
4
- okLch: RawColor;
5
- srgb: RawColor;
6
- };