@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,403 +0,0 @@
1
- const usages = ["bg", "border", "text", "icon", "ring", "shadow", "stroke", "fill"];
2
- const onSolidUsages = ["text", "icon"];
3
- const contexts = ["light", "dark", "highContrast", "dimmed"];
4
- const surfaces = [
5
- "app",
6
- "surface",
7
- "subtle",
8
- "solid",
9
- "overlay",
10
- "data",
11
- "transparent",
12
- ];
13
- export const COLOR_STATES = [
14
- "default",
15
- "hover",
16
- "active",
17
- "selected",
18
- "focus",
19
- "disabled",
20
- ];
21
- const emphases = ["muted", "subtle", "default", "strong", "inverted"];
22
- const semanticVariants = [
23
- "neutral",
24
- "accent",
25
- "success",
26
- "warning",
27
- "danger",
28
- "info",
29
- "highlight",
30
- "premium",
31
- ];
32
- const colorSpaces = ["srgb", "p3", "oklch"];
33
- const gamutMappings = [
34
- "clip",
35
- "compressChroma",
36
- "preferP3ThenCompress",
37
- ];
38
- const srgbFormats = ["hex", "rgb", "rgba"];
39
- const formatString = (value) => (value ? value.trim() : undefined);
40
- const assertOneOf = (value, options, label) => {
41
- if (!options.includes(value)) {
42
- throw new Error(`Invalid ${label}: "${value}"`);
43
- }
44
- return value;
45
- };
46
- const normalizeRole = (role) => {
47
- if (role === undefined) {
48
- throw new Error("Color role is required");
49
- }
50
- const trimmed = role.trim();
51
- if (!trimmed) {
52
- throw new Error("Color role is required");
53
- }
54
- return trimmed;
55
- };
56
- const normalizeBgRole = (role) => {
57
- if (role === undefined) {
58
- throw new Error("Background role (bgRole) is required");
59
- }
60
- const trimmed = role.trim();
61
- if (!trimmed) {
62
- throw new Error("Background role (bgRole) is required");
63
- }
64
- return trimmed;
65
- };
66
- const hexColorPattern = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
67
- const inferUsageFromRole = (role) => {
68
- const normalizedRole = role.trim().toLowerCase();
69
- if (normalizedRole.startsWith("text.")) {
70
- return "text";
71
- }
72
- if (normalizedRole.startsWith("icon.")) {
73
- return "icon";
74
- }
75
- if (normalizedRole.startsWith("border.")) {
76
- return "border";
77
- }
78
- if (normalizedRole.startsWith("bg.") ||
79
- normalizedRole.startsWith("surface.") ||
80
- normalizedRole.startsWith("overlay.")) {
81
- return "bg";
82
- }
83
- if (normalizedRole.startsWith("focus.") || normalizedRole.startsWith("ring.")) {
84
- return "ring";
85
- }
86
- if (normalizedRole.startsWith("chart.")) {
87
- const tokens = normalizedRole.split(".");
88
- if (tokens.includes("stroke")) {
89
- return "stroke";
90
- }
91
- if (tokens.includes("fill")) {
92
- return "fill";
93
- }
94
- if (tokens.includes("grid")) {
95
- return "border";
96
- }
97
- if (tokens.includes("label") || tokens.includes("text")) {
98
- return "text";
99
- }
100
- }
101
- return undefined;
102
- };
103
- /**
104
- * Infer surface intent from role naming patterns.
105
- *
106
- * Recognizes:
107
- * - Direct surface token prefixes: `"app.*"`, `"surface.*"`, `"solid.*"`, etc.
108
- * - Background patterns: `"bg.app"`, `"bg.surface"`, `"bg.solid"`, etc.
109
- *
110
- * @example
111
- * inferSurfaceFromRole("bg.app") // "app"
112
- * @example
113
- * inferSurfaceFromRole("app.bg") // "app"
114
- */
115
- const inferSurfaceFromRole = (role) => {
116
- const normalizedRole = role.trim().toLowerCase();
117
- const tokens = normalizedRole.split(".");
118
- const [first, second] = tokens;
119
- if (first && surfaces.includes(first)) {
120
- return first;
121
- }
122
- if (first === "bg" && second && surfaces.includes(second)) {
123
- return second;
124
- }
125
- return undefined;
126
- };
127
- /**
128
- * Infer semantic variant from role token.
129
- *
130
- * Recognizes:
131
- * - Semantic variants: `"neutral"`, `"accent"`, `"success"`, `"warning"`, etc.
132
- * - Custom categories: `"category:*"`
133
- * - Chart variants: `"chart:*"`
134
- *
135
- * @example
136
- * inferVariantFromRole("success.bg") // "success"
137
- * @example
138
- * inferVariantFromRole("category:sales.fill") // "category:sales"
139
- */
140
- const inferVariantFromRole = (role) => {
141
- const token = role.trim().split(".")[0];
142
- const normalized = token?.toLowerCase();
143
- if (!normalized) {
144
- return undefined;
145
- }
146
- if (semanticVariants.includes(normalized)) {
147
- return normalized;
148
- }
149
- if (/^(category|chart):.+/.test(normalized)) {
150
- return normalized;
151
- }
152
- return undefined;
153
- };
154
- const normalizeVariant = (variant) => {
155
- if (!variant) {
156
- return undefined;
157
- }
158
- const trimmed = variant.trim();
159
- if (semanticVariants.includes(trimmed)) {
160
- return trimmed;
161
- }
162
- if (/^(category|chart):.+/.test(trimmed)) {
163
- return trimmed;
164
- }
165
- throw new Error(`Invalid variant: "${variant}"`);
166
- };
167
- const warn = (message) => {
168
- console.warn(message);
169
- };
170
- /**
171
- * Cache used to deduplicate inference warnings.
172
- *
173
- * Notes:
174
- * - This is intentionally module-scoped so repeated calls don't spam logs.
175
- * - To avoid unbounded growth in long-running processes, this cache is capped
176
- * and clears itself when the cap is reached.
177
- */
178
- const inferenceWarnings = new Set();
179
- const MAX_INFERENCE_WARNINGS = 1000;
180
- const warnInferenceOnce = (key, message) => {
181
- if (inferenceWarnings.has(key))
182
- return;
183
- if (inferenceWarnings.size >= MAX_INFERENCE_WARNINGS) {
184
- inferenceWarnings.clear();
185
- }
186
- inferenceWarnings.add(key);
187
- console.warn(message);
188
- };
189
- const missingUsageMessage = (role) => `Usage is required for role: "${role}". Provide usage explicitly (e.g. { usage: "text" }) or use a role prefix like "text.", "icon.", "bg.", "border.", "ring."`;
190
- const missingSurfaceMessage = (role) => `Surface is required for role: "${role}". Provide surface explicitly (e.g. { surface: "surface" }) or use a role pattern like "bg.app", "bg.surface", "app.*"`;
191
- const normalizeBackgroundHint = (hint, strict) => {
192
- if (!hint) {
193
- return undefined;
194
- }
195
- if (hint.kind === "auto") {
196
- return hint;
197
- }
198
- if (hint.kind === "role") {
199
- const trimmedRole = normalizeRole(hint.role);
200
- return { kind: "role", role: trimmedRole };
201
- }
202
- if (hint.kind === "color") {
203
- const value = hint.value.trim();
204
- if (!value) {
205
- throw new Error("Background hint color value is required");
206
- }
207
- if (!hexColorPattern.test(value)) {
208
- if (strict) {
209
- throw new Error(`Invalid background hint color value: "${hint.value}"`);
210
- }
211
- warn(`Unvalidated background hint color value: "${hint.value}"`);
212
- }
213
- return { kind: "color", value };
214
- }
215
- throw new Error(`Invalid background hint kind: "${hint.kind}"`);
216
- };
217
- const normalizeContrast = (contrast) => {
218
- if (!contrast) {
219
- return undefined;
220
- }
221
- if (contrast.model === "apca") {
222
- if (!Number.isFinite(contrast.targetLc)) {
223
- throw new Error("APCA targetLc must be a number");
224
- }
225
- if (contrast.minLc !== undefined && !Number.isFinite(contrast.minLc)) {
226
- throw new Error("APCA minLc must be a number");
227
- }
228
- if (contrast.maxLc !== undefined && !Number.isFinite(contrast.maxLc)) {
229
- throw new Error("APCA maxLc must be a number");
230
- }
231
- // Validate logical relationships between APCA contrast bounds
232
- if (contrast.minLc !== undefined && contrast.maxLc !== undefined) {
233
- if (contrast.minLc > contrast.maxLc) {
234
- throw new Error("APCA minLc cannot be greater than maxLc");
235
- }
236
- }
237
- if (contrast.minLc !== undefined && contrast.minLc > contrast.targetLc) {
238
- throw new Error("APCA minLc cannot be greater than targetLc");
239
- }
240
- if (contrast.maxLc !== undefined && contrast.targetLc > contrast.maxLc) {
241
- throw new Error("APCA targetLc cannot be greater than maxLc");
242
- }
243
- return contrast;
244
- }
245
- if (contrast.model === "wcag2") {
246
- const minRatio = "minRatio" in contrast ? contrast.minRatio : contrast.ratio;
247
- if (minRatio === undefined) {
248
- throw new Error("WCAG2 contrast requires either 'minRatio' or legacy 'ratio' property");
249
- }
250
- if (!Number.isFinite(minRatio)) {
251
- throw new Error("WCAG2 minRatio must be a number");
252
- }
253
- return { model: "wcag2", minRatio };
254
- }
255
- if (contrast.model === "none") {
256
- return contrast;
257
- }
258
- throw new Error(`Invalid contrast model: "${contrast.model}"`);
259
- };
260
- const validateIncludeSpaces = (includeSpaces) => {
261
- const value = includeSpaces ?? [];
262
- value.forEach((space) => {
263
- assertOneOf(space, colorSpaces, "output includeSpaces");
264
- });
265
- return value;
266
- };
267
- const normalizeAlpha = (alpha) => {
268
- if (!alpha) {
269
- return undefined;
270
- }
271
- if (alpha.mode === "none") {
272
- return alpha;
273
- }
274
- if (alpha.mode === "fixed") {
275
- if (!Number.isFinite(alpha.alpha)) {
276
- throw new Error("Fixed alpha must be a number");
277
- }
278
- return alpha;
279
- }
280
- if (alpha.mode === "solveOnBackground") {
281
- return alpha;
282
- }
283
- throw new Error(`Invalid alpha strategy mode: "${alpha.mode}"`);
284
- };
285
- const normalizeOutput = (output) => {
286
- const preferSpaceValue = formatString(output?.preferSpace);
287
- const gamutMappingValue = formatString(output?.gamutMapping);
288
- const srgbFormatValue = formatString(output?.srgbFormat);
289
- const includeSpaces = validateIncludeSpaces(output?.includeSpaces);
290
- const preferSpace = preferSpaceValue
291
- ? assertOneOf(preferSpaceValue, colorSpaces, "output preferSpace")
292
- : "oklch";
293
- const gamutMapping = gamutMappingValue
294
- ? assertOneOf(gamutMappingValue, gamutMappings, "output gamutMapping")
295
- : "preferP3ThenCompress";
296
- const srgbFormat = srgbFormatValue
297
- ? assertOneOf(srgbFormatValue, srgbFormats, "output srgbFormat")
298
- : "hex";
299
- if (output?.strict !== undefined && typeof output.strict !== "boolean") {
300
- throw new Error("Output strict must be a boolean");
301
- }
302
- if (output?.includeMeta !== undefined && typeof output.includeMeta !== "boolean") {
303
- throw new Error("Output includeMeta must be a boolean");
304
- }
305
- return {
306
- preferSpace,
307
- includeSpaces,
308
- gamutMapping,
309
- strict: output?.strict ?? false,
310
- precision: {
311
- l: 1,
312
- c: 3,
313
- h: 1,
314
- ...output?.precision,
315
- },
316
- includeMeta: output?.includeMeta ?? false,
317
- srgbFormat,
318
- };
319
- };
320
- /**
321
- * Normalize a user-facing ColorQuery into a fully populated, validated structure.
322
- *
323
- * - Applies defaults for missing fields (context, surface, state, emphasis, output).
324
- * - Infers usage and surface from role naming patterns when not provided.
325
- * - In strict mode, missing required fields throw actionable errors.
326
- * - In non-strict mode, safe defaults are applied with explicit warnings.
327
- * - Validates nested objects (background hints, contrast requirements, alpha strategies).
328
- * - Trims string inputs and enforces allowed enum values.
329
- *
330
- * @example
331
- * normalizeQuery({ role: "text.primary" });
332
- * @example
333
- * normalizeQuery({
334
- * role: "bg.canvas",
335
- * on: { kind: "color", value: "#fff" },
336
- * contrast: { model: "apca", targetLc: 60 },
337
- * output: { strict: true },
338
- * });
339
- */
340
- export function normalizeQuery(q) {
341
- const role = normalizeRole(formatString(q.role));
342
- const contextValue = formatString(q.context) ?? "light";
343
- const inferredSurface = inferSurfaceFromRole(role);
344
- const surfaceValue = formatString(q.surface) ?? inferredSurface ?? "surface";
345
- const stateValue = formatString(q.state) ?? "default";
346
- const emphasisValue = formatString(q.emphasis) ?? "default";
347
- const output = normalizeOutput(q.output);
348
- const usageValue = formatString(q.usage) ?? inferUsageFromRole(role);
349
- const variantValue = formatString(q.variant) ?? inferVariantFromRole(role);
350
- if (!usageValue) {
351
- if (output.strict) {
352
- throw new Error(missingUsageMessage(role));
353
- }
354
- warnInferenceOnce(`usage:${role}`, `Defaulting usage to "bg" for role: "${role}". ${missingUsageMessage(role)}`);
355
- }
356
- if (!formatString(q.surface) && !inferredSurface) {
357
- if (output.strict) {
358
- throw new Error(missingSurfaceMessage(role));
359
- }
360
- warnInferenceOnce(`surface:${role}`, `Defaulting surface to "surface" for role: "${role}". ${missingSurfaceMessage(role)}`);
361
- }
362
- return {
363
- role,
364
- usage: assertOneOf(usageValue ?? "bg", usages, "usage"),
365
- context: assertOneOf(contextValue, contexts, "context"),
366
- surface: assertOneOf(surfaceValue, surfaces, "surface"),
367
- state: assertOneOf(stateValue, COLOR_STATES, "state"),
368
- emphasis: assertOneOf(emphasisValue, emphases, "emphasis"),
369
- variant: normalizeVariant(variantValue),
370
- on: normalizeBackgroundHint(q.on, output.strict),
371
- contrast: normalizeContrast(q.contrast),
372
- alpha: normalizeAlpha(q.alpha),
373
- output,
374
- };
375
- }
376
- /**
377
- * Normalize a user-facing OnSolidQuery into a fully populated, validated structure.
378
- *
379
- * - Applies defaults for missing fields (context, state, emphasis, output).
380
- * - Validates usage ("text" | "icon") and required background role.
381
- * - Validates nested objects (contrast requirements, alpha strategies).
382
- */
383
- export function normalizeOnSolidQuery(q) {
384
- const bgRole = normalizeBgRole(formatString(q.bgRole));
385
- const usageValue = formatString(q.usage);
386
- const contextValue = formatString(q.context) ?? "light";
387
- const stateValue = formatString(q.state) ?? "default";
388
- const emphasisValue = formatString(q.emphasis) ?? "default";
389
- const output = normalizeOutput(q.output);
390
- if (!usageValue) {
391
- throw new Error("On-solid usage is required (text or icon)");
392
- }
393
- return {
394
- bgRole,
395
- usage: assertOneOf(usageValue, onSolidUsages, "onSolid usage"),
396
- context: assertOneOf(contextValue, contexts, "context"),
397
- state: assertOneOf(stateValue, COLOR_STATES, "state"),
398
- emphasis: assertOneOf(emphasisValue, emphases, "emphasis"),
399
- contrast: normalizeContrast(q.contrast),
400
- alpha: normalizeAlpha(q.alpha),
401
- output,
402
- };
403
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,136 +0,0 @@
1
- import { describe, expect, it, vi } from "vitest";
2
- import { normalizeQuery } from "./normalize.js";
3
- describe("normalizeQuery", () => {
4
- it("applies defaults", () => {
5
- const result = normalizeQuery({ role: "text.primary", surface: "surface" });
6
- expect(result.usage).toBe("text");
7
- expect(result.context).toBe("light");
8
- expect(result.surface).toBe("surface");
9
- expect(result.state).toBe("default");
10
- expect(result.emphasis).toBe("default");
11
- });
12
- it("throws when role is missing", () => {
13
- expect(() => normalizeQuery({})).toThrowError(/role/i);
14
- });
15
- it("applies output defaults", () => {
16
- const result = normalizeQuery({ role: "text.primary", surface: "surface" });
17
- expect(result.output.preferSpace).toBe("oklch");
18
- expect(result.output.gamutMapping).toBe("preferP3ThenCompress");
19
- expect(result.output.precision).toMatchObject({ l: 1, c: 3, h: 1 });
20
- expect(result.output.strict).toBe(false);
21
- expect(result.output.includeMeta).toBe(false);
22
- });
23
- it("infers usage from role prefixes", () => {
24
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
25
- try {
26
- expect(normalizeQuery({ role: "icon.primary" }).usage).toBe("icon");
27
- expect(normalizeQuery({ role: "border.muted" }).usage).toBe("border");
28
- expect(normalizeQuery({ role: "bg.canvas" }).usage).toBe("bg");
29
- expect(normalizeQuery({ role: "ring.focus" }).usage).toBe("ring");
30
- expect(normalizeQuery({ role: "chart.axis.stroke" }).usage).toBe("stroke");
31
- expect(normalizeQuery({ role: "chart.fill.primary" }).usage).toBe("fill");
32
- expect(normalizeQuery({ role: "chart.grid.muted" }).usage).toBe("border");
33
- expect(normalizeQuery({ role: "chart.label" }).usage).toBe("text");
34
- }
35
- finally {
36
- warnSpy.mockRestore();
37
- }
38
- });
39
- it("infers surface when obvious", () => {
40
- expect(normalizeQuery({ role: "bg.app" }).surface).toBe("app");
41
- expect(normalizeQuery({ role: "bg.surface" }).surface).toBe("surface");
42
- expect(normalizeQuery({ role: "app.bg", usage: "bg" }).surface).toBe("app");
43
- });
44
- it("infers variant from role token", () => {
45
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
46
- try {
47
- expect(normalizeQuery({ role: "success.bg", usage: "bg", surface: "surface" }).variant).toBe("success");
48
- expect(normalizeQuery({ role: "warning.text", usage: "text", surface: "surface" }).variant).toBe("warning");
49
- expect(normalizeQuery({ role: "danger.border", usage: "border", surface: "surface" }).variant).toBe("danger");
50
- expect(normalizeQuery({ role: "category:sales.fill", usage: "fill", surface: "surface" }).variant).toBe("category:sales");
51
- expect(normalizeQuery({
52
- role: "chart:revenue.stroke",
53
- usage: "stroke",
54
- surface: "surface",
55
- }).variant).toBe("chart:revenue");
56
- expect(normalizeQuery({ role: "text.primary", usage: "text", surface: "surface" }).variant).toBeUndefined();
57
- }
58
- finally {
59
- warnSpy.mockRestore();
60
- }
61
- });
62
- it("requires usage when strict and inference fails", () => {
63
- expect(() => normalizeQuery({ role: "brand.primary", output: { strict: true } })).toThrowError(/Provide usage explicitly/i);
64
- });
65
- it("warns when usage cannot be inferred in non-strict mode", () => {
66
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
67
- expect(normalizeQuery({ role: "brand.primary" }).usage).toBe("bg");
68
- expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Defaulting usage to "bg"'));
69
- warnSpy.mockRestore();
70
- });
71
- it("requires surface when strict and inference fails", () => {
72
- expect(() => normalizeQuery({ role: "text.primary", output: { strict: true } })).toThrowError(/Provide surface explicitly/i);
73
- });
74
- it("warns when surface cannot be inferred in non-strict mode", () => {
75
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
76
- expect(normalizeQuery({ role: "text.primary" }).surface).toBe("surface");
77
- expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Defaulting surface to "surface"'));
78
- warnSpy.mockRestore();
79
- });
80
- it("validates background hint color values", () => {
81
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
82
- expect(normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "color", value: "#fff" } })
83
- .on).toEqual({ kind: "color", value: "#fff" });
84
- expect(normalizeQuery({
85
- role: "bg.canvas",
86
- surface: "surface",
87
- on: { kind: "color", value: "oklch(62% 0.18 265)" },
88
- }).on).toEqual({ kind: "color", value: "oklch(62% 0.18 265)" });
89
- expect(normalizeQuery({
90
- role: "bg.canvas",
91
- surface: "surface",
92
- on: { kind: "color", value: "color(display-p3 1 0.5 0.25)" },
93
- }).on).toEqual({ kind: "color", value: "color(display-p3 1 0.5 0.25)" });
94
- expect(normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "color", value: "banana" } })
95
- .on).toEqual({ kind: "color", value: "banana" });
96
- expect(warnSpy).toHaveBeenCalledTimes(3);
97
- warnSpy.mockRestore();
98
- });
99
- it("normalizes nested background hints", () => {
100
- expect(normalizeQuery({
101
- role: "bg.canvas",
102
- surface: "surface",
103
- on: { kind: "role", role: " text.primary " },
104
- })
105
- .on).toEqual({ kind: "role", role: "text.primary" });
106
- expect(normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "auto" } }).on).toEqual({
107
- kind: "auto",
108
- });
109
- expect(() => normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "color", value: " " } })).toThrowError(/color value is required/i);
110
- expect(() => normalizeQuery({
111
- role: "bg.canvas",
112
- surface: "surface",
113
- on: { kind: "color", value: "banana" },
114
- output: { strict: true },
115
- })).toThrowError(/background hint color value/i);
116
- expect(() => normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "nope" } })).toThrowError(/background hint kind/i);
117
- });
118
- it("validates contrast requirements", () => {
119
- expect(normalizeQuery({ role: "text.primary", contrast: { model: "apca", targetLc: 75 } })
120
- .contrast).toEqual({ model: "apca", targetLc: 75 });
121
- expect(normalizeQuery({ role: "text.primary", contrast: { model: "wcag2", minRatio: 4.5 } })
122
- .contrast).toEqual({ model: "wcag2", minRatio: 4.5 });
123
- expect(normalizeQuery({ role: "text.primary", contrast: { model: "none" } }).contrast).toEqual({ model: "none" });
124
- expect(() => normalizeQuery({ role: "text.primary", contrast: { model: "apca" } })).toThrowError(/targetLc/i);
125
- expect(() => normalizeQuery({ role: "text.primary", contrast: { model: "wcag2" } })).toThrowError(/minRatio.*ratio/i);
126
- expect(() => normalizeQuery({ role: "text.primary", contrast: { model: "wcag2", minRatio: NaN } })).toThrowError(/minRatio must be a number/i);
127
- expect(() => normalizeQuery({ role: "text.primary", contrast: { model: "nope" } })).toThrowError(/contrast model/i);
128
- });
129
- it("validates alpha strategies", () => {
130
- expect(normalizeQuery({ role: "bg.canvas", alpha: { mode: "none" } }).alpha).toEqual({ mode: "none" });
131
- expect(normalizeQuery({ role: "bg.canvas", alpha: { mode: "fixed", alpha: 0.5 } }).alpha).toEqual({ mode: "fixed", alpha: 0.5 });
132
- expect(normalizeQuery({ role: "bg.canvas", alpha: { mode: "solveOnBackground" } }).alpha).toEqual({ mode: "solveOnBackground" });
133
- expect(() => normalizeQuery({ role: "bg.canvas", alpha: { mode: "fixed" } })).toThrowError(/fixed alpha/i);
134
- expect(() => normalizeQuery({ role: "bg.canvas", alpha: { mode: "nope" } })).toThrowError(/alpha strategy mode/i);
135
- });
136
- });
@@ -1,3 +0,0 @@
1
- import type { OnSolidQuery } from "../types/index.js";
2
- import type { BaseResolvedColor, ThemeConfig } from "./resolveBaseColor.js";
3
- export declare function onSolid(query: OnSolidQuery, theme: ThemeConfig): BaseResolvedColor;
@@ -1,110 +0,0 @@
1
- import { computeApcaLc } from "../contrast/apca.js";
2
- import { solveContrast } from "../contrast/solver.js";
3
- import { blendSrgb, toSrgbColor } from "../contrast/utils.js";
4
- import { contrastRatio } from "../contrast/wcag2.js";
5
- import { applyOperators } from "./applyOperators.js";
6
- import { mapColorContextToEngine } from "./context.js";
7
- import { normalizeOnSolidQuery, normalizeQuery } from "./normalize.js";
8
- import { resolveBaseColor } from "./resolveBaseColor.js";
9
- const DEFAULT_SOLVE_EPSILON = 0.01;
10
- const nearWhite = { l: 97, c: 0, h: 0, alpha: 1 };
11
- const nearBlack = { l: 15, c: 0, h: 0, alpha: 1 };
12
- const defaultContrastForUsage = (usage) => ({
13
- model: "apca",
14
- targetLc: usage === "text" ? 75 : 60,
15
- });
16
- const validateFixedAlpha = (alpha) => {
17
- if (alpha < 0 || alpha > 1) {
18
- throw new Error("Fixed alpha must be between 0 and 1");
19
- }
20
- return alpha;
21
- };
22
- const resolveAlphaStrategy = (alpha, usage, strict) => {
23
- if (!alpha) {
24
- return { mode: "fixed", alpha: usage === "text" ? 0.92 : 0.72 };
25
- }
26
- if (alpha.mode === "none") {
27
- return alpha;
28
- }
29
- if (alpha.mode === "fixed") {
30
- return { mode: "fixed", alpha: validateFixedAlpha(alpha.alpha) };
31
- }
32
- if (strict) {
33
- throw new Error('onSolid does not support alpha.mode "solveOnBackground"');
34
- }
35
- console.warn('onSolid does not support alpha.mode "solveOnBackground"; falling back to fixed defaults');
36
- return { mode: "fixed", alpha: usage === "text" ? 0.92 : 0.72 };
37
- };
38
- const checkContrastWithAlpha = (fg, bg, req, alpha, epsilon = DEFAULT_SOLVE_EPSILON) => {
39
- if (req.model === "none") {
40
- return { pass: true, value: 0 };
41
- }
42
- const fgSrgb = toSrgbColor(fg);
43
- const bgSrgb = toSrgbColor(bg);
44
- if (!fgSrgb || !bgSrgb) {
45
- return { pass: false, value: Number.NaN };
46
- }
47
- const composite = blendSrgb(fgSrgb, bgSrgb, alpha);
48
- if (req.model === "apca") {
49
- const value = Math.abs(computeApcaLc(composite, bgSrgb));
50
- const minTarget = req.minLc ?? req.targetLc;
51
- const maxTarget = req.maxLc ?? Number.POSITIVE_INFINITY;
52
- return {
53
- pass: Number.isFinite(value) && value >= minTarget - epsilon && value <= maxTarget + epsilon,
54
- value,
55
- };
56
- }
57
- const value = contrastRatio(composite, bgSrgb);
58
- return { pass: Number.isFinite(value) && value + epsilon >= req.minRatio, value };
59
- };
60
- export function onSolid(query, theme) {
61
- const normalized = normalizeOnSolidQuery(query);
62
- const contrastRequirement = normalized.contrast ?? defaultContrastForUsage(normalized.usage);
63
- const alphaStrategy = resolveAlphaStrategy(normalized.alpha, normalized.usage, normalized.output.strict);
64
- const alpha = alphaStrategy.mode === "none" ? 1 : alphaStrategy.alpha;
65
- const bgNormalized = normalizeQuery({
66
- role: normalized.bgRole,
67
- usage: "bg",
68
- surface: "solid",
69
- context: normalized.context,
70
- state: normalized.state,
71
- emphasis: normalized.emphasis,
72
- });
73
- const bgBase = resolveBaseColor(bgNormalized, theme);
74
- // Apply state/emphasis operators to the background before onSolid solves.
75
- const bgResolved = applyOperators(bgBase, bgNormalized, theme);
76
- const bg = bgResolved.oklch;
77
- const baseFg = bg.l >= 50 ? nearBlack : nearWhite;
78
- const seedUsed = `oklch(${baseFg.l}% ${baseFg.c} ${baseFg.h})`;
79
- const solverContext = {
80
- preset: theme.preset,
81
- surface: bgNormalized.surface,
82
- context: mapColorContextToEngine(bgNormalized.context),
83
- };
84
- const solved = solveContrast({ ...baseFg, alpha }, bg, contrastRequirement, solverContext, {
85
- strict: normalized.output.strict,
86
- });
87
- let finalAlpha = alpha;
88
- let finalColor = solved.color;
89
- let finalCheck = checkContrastWithAlpha(finalColor, bg, contrastRequirement, finalAlpha, DEFAULT_SOLVE_EPSILON);
90
- if (!finalCheck.pass && finalAlpha < 1) {
91
- finalAlpha = 1;
92
- const solvedOpaque = solveContrast({ ...baseFg, alpha: 1 }, bg, contrastRequirement, solverContext, { strict: normalized.output.strict });
93
- finalColor = solvedOpaque.color;
94
- finalCheck = checkContrastWithAlpha(finalColor, bg, contrastRequirement, finalAlpha, DEFAULT_SOLVE_EPSILON);
95
- }
96
- if (!finalCheck.pass && normalized.output.strict) {
97
- const target = contrastRequirement.model === "apca"
98
- ? contrastRequirement.targetLc
99
- : contrastRequirement.model === "wcag2"
100
- ? contrastRequirement.minRatio
101
- : 0;
102
- throw new Error(`onSolid contrast failed (${contrastRequirement.model}) target=${target} value=${finalCheck.value}`);
103
- }
104
- return {
105
- oklch: { ...finalColor, alpha: finalAlpha },
106
- step: 0,
107
- variantUsed: "onSolid",
108
- seedUsed,
109
- };
110
- }
@@ -1,25 +0,0 @@
1
- import type { CurvePresetName } from "../presets/index.js";
2
- import type { ColorQuery, CssColorString } from "../types/index.js";
3
- import { type OkLchColor } from "./generateScale.js";
4
- import type { NormalizedQuery } from "./normalize.js";
5
- type ThemeSeeds = {
6
- neutral: CssColorString;
7
- accent: CssColorString;
8
- };
9
- export type ThemeConfig = {
10
- seeds: {
11
- light: ThemeSeeds;
12
- dark: ThemeSeeds;
13
- };
14
- variants?: Record<string, CssColorString>;
15
- preset?: CurvePresetName;
16
- };
17
- export type BaseResolvedColor = {
18
- oklch: OkLchColor;
19
- step: number;
20
- variantUsed: string;
21
- seedUsed: CssColorString;
22
- };
23
- export declare function resolveBaseColor(query: ColorQuery, theme: ThemeConfig): BaseResolvedColor;
24
- export declare function resolveBaseColor(normalized: NormalizedQuery, theme: ThemeConfig): BaseResolvedColor;
25
- export {};