@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
@@ -0,0 +1,56 @@
1
+ import type { IntentDefinition } from '../../core/intent-registry.js';
2
+ export declare const USAGES: readonly ["fill", "visualVocabulary", "lines", "overlays"];
3
+ export type Usage = (typeof USAGES)[number];
4
+ export type UsageStrategyInput = Readonly<{
5
+ intent: Readonly<IntentDefinition>;
6
+ }>;
7
+ export type UsageStrategyResult<U extends Usage = Usage> = Readonly<{
8
+ usage: U;
9
+ intent: Readonly<IntentDefinition>;
10
+ }>;
11
+ export type UsageStrategy<U extends Usage = Usage> = Readonly<{
12
+ usage: U;
13
+ resolve(input: UsageStrategyInput): UsageStrategyResult<U>;
14
+ }>;
15
+ export declare function isUsage(value: unknown): value is Usage;
16
+ export declare function assertUsage(value: unknown): asserts value is Usage;
17
+ export declare const usageStrategies: Readonly<{
18
+ fill: Readonly<{
19
+ resolve(input: Readonly<{
20
+ intent: Readonly<IntentDefinition>;
21
+ }>): Readonly<{
22
+ intent: Readonly<IntentDefinition>;
23
+ usage: "fill";
24
+ }>;
25
+ usage: "fill";
26
+ }>;
27
+ lines: Readonly<{
28
+ resolve(input: Readonly<{
29
+ intent: Readonly<IntentDefinition>;
30
+ }>): Readonly<{
31
+ intent: Readonly<IntentDefinition>;
32
+ usage: "lines";
33
+ }>;
34
+ usage: "lines";
35
+ }>;
36
+ overlays: Readonly<{
37
+ resolve(input: Readonly<{
38
+ intent: Readonly<IntentDefinition>;
39
+ }>): Readonly<{
40
+ intent: Readonly<IntentDefinition>;
41
+ usage: "overlays";
42
+ }>;
43
+ usage: "overlays";
44
+ }>;
45
+ visualVocabulary: Readonly<{
46
+ resolve(input: Readonly<{
47
+ intent: Readonly<IntentDefinition>;
48
+ }>): Readonly<{
49
+ intent: Readonly<IntentDefinition>;
50
+ usage: "visualVocabulary";
51
+ }>;
52
+ usage: "visualVocabulary";
53
+ }>;
54
+ }>;
55
+ export declare function getUsageStrategy<U extends Usage>(usage: U): UsageStrategy<U>;
56
+ export declare function getUsageStrategy(usage: unknown): UsageStrategy;
@@ -0,0 +1,30 @@
1
+ import { fillUsageStrategy } from './fill.js';
2
+ import { linesUsageStrategy } from './lines.js';
3
+ import { overlaysUsageStrategy } from './overlays.js';
4
+ import { visualVocabularyUsageStrategy } from './visualVocabulary.js';
5
+ export const USAGES = Object.freeze([
6
+ 'fill',
7
+ 'visualVocabulary',
8
+ 'lines',
9
+ 'overlays',
10
+ ]);
11
+ const usageList = USAGES.join(', ');
12
+ const formatUnknownUsageError = (value) => `Unknown usage "${String(value)}". Expected one of: ${usageList}.`;
13
+ export function isUsage(value) {
14
+ return (typeof value === 'string' && USAGES.includes(value));
15
+ }
16
+ export function assertUsage(value) {
17
+ if (!isUsage(value)) {
18
+ throw new Error(formatUnknownUsageError(value));
19
+ }
20
+ }
21
+ export const usageStrategies = Object.freeze({
22
+ fill: fillUsageStrategy,
23
+ lines: linesUsageStrategy,
24
+ overlays: overlaysUsageStrategy,
25
+ visualVocabulary: visualVocabularyUsageStrategy,
26
+ });
27
+ export function getUsageStrategy(usage) {
28
+ assertUsage(usage);
29
+ return usageStrategies[usage];
30
+ }
@@ -0,0 +1,9 @@
1
+ export declare const visualVocabularyUsageStrategy: Readonly<{
2
+ resolve(input: Readonly<{
3
+ intent: Readonly<import("../../core/intent-registry.js").IntentDefinition>;
4
+ }>): Readonly<{
5
+ intent: Readonly<import("../../core/intent-registry.js").IntentDefinition>;
6
+ usage: "visualVocabulary";
7
+ }>;
8
+ usage: "visualVocabulary";
9
+ }>;
@@ -0,0 +1,9 @@
1
+ export const visualVocabularyUsageStrategy = Object.freeze({
2
+ resolve(input) {
3
+ return Object.freeze({
4
+ intent: input.intent,
5
+ usage: 'visualVocabulary',
6
+ });
7
+ },
8
+ usage: 'visualVocabulary',
9
+ });
@@ -0,0 +1,14 @@
1
+ import { normalizeOklch, type OklchInput } from '../core/oklch.js';
2
+ import { oklchToOklab } from '../operators/convert.js';
3
+ import type { ColorOutput, RgbaColor, RgbColor } from './types.js';
4
+ export type GamutStrategy = 'clip';
5
+ export type SerializationOptions = Readonly<{
6
+ gamutStrategy?: GamutStrategy;
7
+ }>;
8
+ export type ColorSerializer<T> = (color: OklchInput, options?: SerializationOptions) => T;
9
+ export declare const serializeOklchToRgba: ColorSerializer<RgbaColor>;
10
+ export declare const serializeOklchToOklab: ColorSerializer<ReturnType<typeof oklchToOklab>>;
11
+ export declare const serializeOklchToSrgb: ColorSerializer<RgbColor>;
12
+ export declare const serializeOklchToP3: ColorSerializer<RgbColor>;
13
+ export declare const serializeOklchToHex: ColorSerializer<string>;
14
+ export declare function serializeColor(color: OklchInput, output: ColorOutput, options?: SerializationOptions): ReturnType<typeof normalizeOklch | typeof serializeOklchToOklab | typeof serializeOklchToSrgb | typeof serializeOklchToP3 | typeof serializeOklchToHex | typeof serializeOklchToRgba>;
@@ -0,0 +1,89 @@
1
+ import { normalizeOklch } from '../core/oklch.js';
2
+ import { oklabToLinearRgb, oklchToOklab } from '../operators/convert.js';
3
+ import { createUnsupportedOutputError } from '../utils/errors/errors.js';
4
+ const DEFAULT_GAMUT_STRATEGY = 'clip';
5
+ const clampUnit = (value) => Math.min(1, Math.max(0, value));
6
+ const toSrgbChannel = (linearChannel) => {
7
+ const encoded = linearChannel <= 0.0031308
8
+ ? 12.92 * linearChannel
9
+ : 1.055 * linearChannel ** (1 / 2.4) - 0.055;
10
+ return Math.round(clampUnit(encoded) * 255);
11
+ };
12
+ const toEncodedRgbColor = (linearRgb) => Object.freeze({
13
+ alpha: linearRgb.alpha,
14
+ b: toSrgbChannel(linearRgb.b),
15
+ g: toSrgbChannel(linearRgb.g),
16
+ r: toSrgbChannel(linearRgb.r),
17
+ });
18
+ const oklabToLinearDisplayP3 = (oklab) => {
19
+ const lPrime = oklab.l + 0.3963377774 * oklab.a + 0.2158037573 * oklab.b;
20
+ const mPrime = oklab.l - 0.1055613458 * oklab.a - 0.0638541728 * oklab.b;
21
+ const sPrime = oklab.l - 0.0894841775 * oklab.a - 1.291485548 * oklab.b;
22
+ const l = lPrime ** 3;
23
+ const m = mPrime ** 3;
24
+ const s = sPrime ** 3;
25
+ const x = 1.2270138511 * l - 0.5577999807 * m + 0.281256149 * s;
26
+ const y = -0.0405801784 * l + 1.1122568696 * m - 0.0716766787 * s;
27
+ const z = -0.0763812845 * l - 0.4214819784 * m + 1.5861632204 * s;
28
+ return {
29
+ alpha: oklab.alpha,
30
+ b: 0.0358458302 * x - 0.0761723893 * y + 0.956884524 * z,
31
+ g: -0.8294889696 * x + 1.7626640603 * y + 0.0236246858 * z,
32
+ r: 2.4934969119 * x - 0.9313836179 * y - 0.4027107845 * z,
33
+ };
34
+ };
35
+ const toHexChannel = (channel) => channel.toString(16).padStart(2, '0');
36
+ const resolveGamutStrategy = (options) => {
37
+ const strategy = options?.gamutStrategy ?? DEFAULT_GAMUT_STRATEGY;
38
+ if (strategy !== 'clip') {
39
+ throw new Error(`Unsupported gamut strategy "${String(strategy)}". Expected "clip".`);
40
+ }
41
+ return strategy;
42
+ };
43
+ export const serializeOklchToRgba = (input, options) => {
44
+ const srgb = serializeOklchToSrgb(input, options);
45
+ return Object.freeze({
46
+ a: srgb.alpha,
47
+ b: srgb.b,
48
+ g: srgb.g,
49
+ r: srgb.r,
50
+ });
51
+ };
52
+ export const serializeOklchToOklab = (input) => oklchToOklab(input);
53
+ export const serializeOklchToSrgb = (input, options) => {
54
+ resolveGamutStrategy(options);
55
+ const color = normalizeOklch(input);
56
+ const linearRgb = oklabToLinearRgb(oklchToOklab(color));
57
+ return toEncodedRgbColor(linearRgb);
58
+ };
59
+ export const serializeOklchToP3 = (input, options) => {
60
+ resolveGamutStrategy(options);
61
+ const color = normalizeOklch(input);
62
+ const linearP3 = oklabToLinearDisplayP3(oklchToOklab(color));
63
+ return toEncodedRgbColor(linearP3);
64
+ };
65
+ export const serializeOklchToHex = (input, options) => {
66
+ const rgba = serializeOklchToRgba(input, options);
67
+ return `#${toHexChannel(rgba.r)}${toHexChannel(rgba.g)}${toHexChannel(rgba.b)}`;
68
+ };
69
+ export function serializeColor(color, output, options) {
70
+ if (output === 'oklch') {
71
+ return normalizeOklch(color);
72
+ }
73
+ if (output === 'oklab') {
74
+ return serializeOklchToOklab(color);
75
+ }
76
+ if (output === 'srgb') {
77
+ return serializeOklchToSrgb(color, options);
78
+ }
79
+ if (output === 'p3') {
80
+ return serializeOklchToP3(color, options);
81
+ }
82
+ if (output === 'hex') {
83
+ return serializeOklchToHex(color, options);
84
+ }
85
+ if (output === 'rgba') {
86
+ return serializeOklchToRgba(color, options);
87
+ }
88
+ throw createUnsupportedOutputError(output);
89
+ }
@@ -0,0 +1,37 @@
1
+ import type { OklchColor } from '../core/oklch.js';
2
+ import type { OklabColor } from '../operators/convert.js';
3
+ export declare const OUTPUTS: readonly ["oklch", "oklab", "srgb", "p3", "hex", "rgba"];
4
+ export type ColorOutput = (typeof OUTPUTS)[number];
5
+ export type RgbColor = Readonly<{
6
+ r: number;
7
+ g: number;
8
+ b: number;
9
+ alpha: number;
10
+ }>;
11
+ export type RgbaColor = Readonly<{
12
+ r: number;
13
+ g: number;
14
+ b: number;
15
+ a: number;
16
+ }>;
17
+ export type OutputMap = Readonly<{
18
+ oklch: OklchColor;
19
+ oklab: OklabColor;
20
+ srgb: RgbColor;
21
+ p3: RgbColor;
22
+ hex: string;
23
+ rgba: RgbaColor;
24
+ }>;
25
+ export type ResolveOutput<O extends ColorOutput> = OutputMap[O];
26
+ export type ResolveOptionsWithOutput<O extends ColorOutput> = Readonly<{
27
+ output?: O;
28
+ }>;
29
+ export type TypedResolver<O extends ColorOutput> = (options: ResolveOptionsWithOutput<O>) => ResolveOutput<O>;
30
+ export type OutputResolutionInput = Readonly<{
31
+ resolverOutput?: unknown;
32
+ paletteOutput?: unknown;
33
+ systemDefaultOutput?: unknown;
34
+ }>;
35
+ export declare function isColorOutput(value: unknown): value is ColorOutput;
36
+ export declare function assertColorOutput(value: unknown): asserts value is ColorOutput;
37
+ export declare function resolveOutput({ resolverOutput, paletteOutput, systemDefaultOutput, }: OutputResolutionInput): ColorOutput;
@@ -0,0 +1,31 @@
1
+ import { createUnsupportedOutputError } from '../utils/errors/errors.js';
2
+ export const OUTPUTS = Object.freeze([
3
+ 'oklch',
4
+ 'oklab',
5
+ 'srgb',
6
+ 'p3',
7
+ 'hex',
8
+ 'rgba',
9
+ ]);
10
+ const outputList = OUTPUTS.join(', ');
11
+ const formatInvalidOutputError = (value) => `Invalid output "${String(value)}". Expected one of: ${outputList}.`;
12
+ export function isColorOutput(value) {
13
+ return (typeof value === 'string' && OUTPUTS.includes(value));
14
+ }
15
+ export function assertColorOutput(value) {
16
+ if (!isColorOutput(value)) {
17
+ throw createUnsupportedOutputError(String(value), formatInvalidOutputError(value));
18
+ }
19
+ }
20
+ export function resolveOutput({ resolverOutput, paletteOutput, systemDefaultOutput, }) {
21
+ if (resolverOutput !== undefined) {
22
+ assertColorOutput(resolverOutput);
23
+ }
24
+ if (paletteOutput !== undefined) {
25
+ assertColorOutput(paletteOutput);
26
+ }
27
+ if (systemDefaultOutput !== undefined) {
28
+ assertColorOutput(systemDefaultOutput);
29
+ }
30
+ return resolverOutput ?? paletteOutput ?? systemDefaultOutput ?? 'oklch';
31
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export type { PaletteConfig, TokenPresetName } from "./cli/config.js";
2
- export * from "./core/index.js";
3
- export * from "./types/index.js";
1
+ export { createPaletteKit } from './create-palette-kit.js';
2
+ export { defaultResolverConfig, neutralResolverConfig, softResolverConfig, strongResolverConfig, } from './presets/presets.js';
3
+ export type { ChromaConfig, ColorOutput, Context, IntentDefinition, Level, OklchColor, PaletteKit, PaletteKitConfig, PaletteResolveOptions, PaletteResolveOutput, RelationParamsConfig, ResolverConfig, ResolverConfigOverrides, ResolverPresetName, RgbaColor, RgbColor, State, StateDeltaDirection, Usage, } from './types/index.js';
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export * from "./core/index.js";
2
- export * from "./types/index.js";
1
+ export { createPaletteKit } from './create-palette-kit.js';
2
+ export { defaultResolverConfig, neutralResolverConfig, softResolverConfig, strongResolverConfig, } from './presets/presets.js';
@@ -0,0 +1,32 @@
1
+ import { normalizeOklch, type OklchInput } from '../core/oklch.js';
2
+ export declare const CONVERSION_EPSILON = 1e-10;
3
+ export type OklabColor = {
4
+ space: 'oklab';
5
+ l: number;
6
+ a: number;
7
+ b: number;
8
+ alpha: number;
9
+ };
10
+ export type LinearRgbColor = {
11
+ space: 'linear-rgb';
12
+ r: number;
13
+ g: number;
14
+ b: number;
15
+ alpha: number;
16
+ };
17
+ export type OklabInput = {
18
+ l: number;
19
+ a: number;
20
+ b: number;
21
+ alpha?: number;
22
+ };
23
+ export type LinearRgbInput = {
24
+ r: number;
25
+ g: number;
26
+ b: number;
27
+ alpha?: number;
28
+ };
29
+ export declare function oklchToOklab(input: OklchInput): OklabColor;
30
+ export declare function oklabToOklch(input: OklabInput): ReturnType<typeof normalizeOklch>;
31
+ export declare function oklabToLinearRgb(input: OklabInput): LinearRgbColor;
32
+ export declare function linearRgbToOklab(input: LinearRgbInput): OklabColor;
@@ -0,0 +1,80 @@
1
+ import { normalizeOklch } from '../core/oklch.js';
2
+ export const CONVERSION_EPSILON = 1e-10;
3
+ const isFiniteNumber = (value) => typeof value === 'number' && Number.isFinite(value);
4
+ const normalizePrecision = (value) => Math.abs(value) <= CONVERSION_EPSILON ? 0 : value;
5
+ const normalizeHue = (hue) => {
6
+ const normalized = ((hue % 360) + 360) % 360;
7
+ return normalizePrecision(normalized);
8
+ };
9
+ const validateFiniteChannel = (space, name, value) => {
10
+ if (!isFiniteNumber(value)) {
11
+ throw new Error(`${space} ${name} must be a finite number.`);
12
+ }
13
+ };
14
+ const normalizeAlpha = (space, alphaInput) => {
15
+ const alpha = alphaInput ?? 1;
16
+ validateFiniteChannel(space, 'alpha', alpha);
17
+ return normalizePrecision(alpha);
18
+ };
19
+ export function oklchToOklab(input) {
20
+ const color = normalizeOklch(input);
21
+ const hueRadians = (color.h * Math.PI) / 180;
22
+ return {
23
+ a: normalizePrecision(color.c * Math.cos(hueRadians)),
24
+ alpha: normalizePrecision(color.alpha),
25
+ b: normalizePrecision(color.c * Math.sin(hueRadians)),
26
+ l: normalizePrecision(color.l / 100),
27
+ space: 'oklab',
28
+ };
29
+ }
30
+ export function oklabToOklch(input) {
31
+ validateFiniteChannel('OKLab', 'l', input.l);
32
+ validateFiniteChannel('OKLab', 'a', input.a);
33
+ validateFiniteChannel('OKLab', 'b', input.b);
34
+ const alpha = normalizeAlpha('OKLab', input.alpha);
35
+ const c = Math.hypot(input.a, input.b);
36
+ const hue = c <= CONVERSION_EPSILON
37
+ ? 0
38
+ : (Math.atan2(input.b, input.a) * 180) / Math.PI;
39
+ return normalizeOklch({
40
+ alpha,
41
+ c: normalizePrecision(c),
42
+ h: normalizeHue(hue),
43
+ l: normalizePrecision(input.l * 100),
44
+ });
45
+ }
46
+ export function oklabToLinearRgb(input) {
47
+ validateFiniteChannel('OKLab', 'l', input.l);
48
+ validateFiniteChannel('OKLab', 'a', input.a);
49
+ validateFiniteChannel('OKLab', 'b', input.b);
50
+ const alpha = normalizeAlpha('OKLab', input.alpha);
51
+ const lPrime = input.l + 0.3963377774 * input.a + 0.2158037573 * input.b;
52
+ const mPrime = input.l - 0.1055613458 * input.a - 0.0638541728 * input.b;
53
+ const sPrime = input.l - 0.0894841775 * input.a - 1.291485548 * input.b;
54
+ const l = lPrime ** 3;
55
+ const m = mPrime ** 3;
56
+ const s = sPrime ** 3;
57
+ return {
58
+ alpha,
59
+ b: normalizePrecision(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s),
60
+ g: normalizePrecision(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s),
61
+ r: normalizePrecision(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s),
62
+ space: 'linear-rgb',
63
+ };
64
+ }
65
+ export function linearRgbToOklab(input) {
66
+ validateFiniteChannel('linear RGB', 'r', input.r);
67
+ validateFiniteChannel('linear RGB', 'g', input.g);
68
+ validateFiniteChannel('linear RGB', 'b', input.b);
69
+ const alpha = normalizeAlpha('linear RGB', input.alpha);
70
+ const l = Math.cbrt(0.4122214708 * input.r + 0.5363325363 * input.g + 0.0514459929 * input.b);
71
+ const m = Math.cbrt(0.2119034982 * input.r + 0.6806995451 * input.g + 0.1073969566 * input.b);
72
+ const s = Math.cbrt(0.0883024619 * input.r + 0.2817188376 * input.g + 0.6299787005 * input.b);
73
+ return {
74
+ a: normalizePrecision(1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s),
75
+ alpha,
76
+ b: normalizePrecision(0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s),
77
+ l: normalizePrecision(0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s),
78
+ space: 'oklab',
79
+ };
80
+ }
@@ -0,0 +1,95 @@
1
+ import { type LevelCurveConfig } from '../engine/level/curves.js';
2
+ import { type Level } from '../engine/level/level.js';
3
+ import { type StateDeltaConfig, type StateDeltaTable } from '../engine/state/state.js';
4
+ export declare const RESOLVER_PRESETS: readonly ["soft", "neutral", "strong"];
5
+ export type ResolverPresetName = (typeof RESOLVER_PRESETS)[number];
6
+ export type RelationLevelAlphaTable = Readonly<Record<Level, number>>;
7
+ export type RelationParamsConfig = Readonly<{
8
+ on: Readonly<{
9
+ contrastTarget: number;
10
+ maxLuminanceShift: number;
11
+ }>;
12
+ over: Readonly<{
13
+ baseAlphaByLevel: RelationLevelAlphaTable;
14
+ }>;
15
+ under: Readonly<{
16
+ baseAlphaByLevel: RelationLevelAlphaTable;
17
+ luminanceReduction: number;
18
+ }>;
19
+ }>;
20
+ export type ChromaConfig = Readonly<{
21
+ maxReduction: number;
22
+ reductionStep: number;
23
+ }>;
24
+ export type ResolverConfig = Readonly<{
25
+ levelCurves: LevelCurveConfig;
26
+ stateDeltas: StateDeltaConfig;
27
+ relationParams: RelationParamsConfig;
28
+ chromaLimits: ChromaConfig;
29
+ }>;
30
+ export type ResolverConfigOverrides = Readonly<{
31
+ levelCurves?: Partial<LevelCurveConfig>;
32
+ stateDeltas?: Readonly<{
33
+ luminance?: Partial<StateDeltaTable>;
34
+ alpha?: Partial<StateDeltaTable>;
35
+ }>;
36
+ relationParams?: Readonly<{
37
+ on?: Partial<RelationParamsConfig['on']>;
38
+ over?: Readonly<{
39
+ baseAlphaByLevel?: Partial<RelationLevelAlphaTable>;
40
+ }>;
41
+ under?: Readonly<{
42
+ baseAlphaByLevel?: Partial<RelationLevelAlphaTable>;
43
+ luminanceReduction?: number;
44
+ }>;
45
+ }>;
46
+ chromaLimits?: Partial<ChromaConfig>;
47
+ }>;
48
+ export declare const softResolverConfig: Readonly<{
49
+ levelCurves: LevelCurveConfig;
50
+ stateDeltas: StateDeltaConfig;
51
+ relationParams: RelationParamsConfig;
52
+ chromaLimits: ChromaConfig;
53
+ }>;
54
+ export declare const neutralResolverConfig: Readonly<{
55
+ levelCurves: LevelCurveConfig;
56
+ stateDeltas: StateDeltaConfig;
57
+ relationParams: RelationParamsConfig;
58
+ chromaLimits: ChromaConfig;
59
+ }>;
60
+ export declare const strongResolverConfig: Readonly<{
61
+ levelCurves: LevelCurveConfig;
62
+ stateDeltas: StateDeltaConfig;
63
+ relationParams: RelationParamsConfig;
64
+ chromaLimits: ChromaConfig;
65
+ }>;
66
+ export declare const defaultResolverConfig: Readonly<{
67
+ levelCurves: LevelCurveConfig;
68
+ stateDeltas: StateDeltaConfig;
69
+ relationParams: RelationParamsConfig;
70
+ chromaLimits: ChromaConfig;
71
+ }>;
72
+ export declare const resolverPresetConfigs: Readonly<{
73
+ neutral: Readonly<{
74
+ levelCurves: LevelCurveConfig;
75
+ stateDeltas: StateDeltaConfig;
76
+ relationParams: RelationParamsConfig;
77
+ chromaLimits: ChromaConfig;
78
+ }>;
79
+ soft: Readonly<{
80
+ levelCurves: LevelCurveConfig;
81
+ stateDeltas: StateDeltaConfig;
82
+ relationParams: RelationParamsConfig;
83
+ chromaLimits: ChromaConfig;
84
+ }>;
85
+ strong: Readonly<{
86
+ levelCurves: LevelCurveConfig;
87
+ stateDeltas: StateDeltaConfig;
88
+ relationParams: RelationParamsConfig;
89
+ chromaLimits: ChromaConfig;
90
+ }>;
91
+ }>;
92
+ export declare function isResolverPresetName(value: unknown): value is ResolverPresetName;
93
+ export declare function assertResolverPresetName(value: unknown): asserts value is ResolverPresetName;
94
+ export declare function getResolverPresetConfig(preset: unknown): ResolverConfig;
95
+ export declare function mergeResolverConfig(base: ResolverConfig, overrides: ResolverConfigOverrides | undefined): ResolverConfig;