@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,222 +0,0 @@
1
- import { describe, expect, it, vi } from "vitest";
2
-
3
- import { normalizeQuery } from "./normalize.js";
4
-
5
- describe("normalizeQuery", () => {
6
- it("applies defaults", () => {
7
- const result = normalizeQuery({ role: "text.primary", surface: "surface" });
8
-
9
- expect(result.usage).toBe("text");
10
- expect(result.context).toBe("light");
11
- expect(result.surface).toBe("surface");
12
- expect(result.state).toBe("default");
13
- expect(result.emphasis).toBe("default");
14
- });
15
-
16
- it("throws when role is missing", () => {
17
- expect(() => normalizeQuery({} as never)).toThrowError(/role/i);
18
- });
19
-
20
- it("applies output defaults", () => {
21
- const result = normalizeQuery({ role: "text.primary", surface: "surface" });
22
-
23
- expect(result.output.preferSpace).toBe("oklch");
24
- expect(result.output.gamutMapping).toBe("preferP3ThenCompress");
25
- expect(result.output.precision).toMatchObject({ l: 1, c: 3, h: 1 });
26
- expect(result.output.strict).toBe(false);
27
- expect(result.output.includeMeta).toBe(false);
28
- });
29
-
30
- it("infers usage from role prefixes", () => {
31
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
32
-
33
- try {
34
- expect(normalizeQuery({ role: "icon.primary" }).usage).toBe("icon");
35
- expect(normalizeQuery({ role: "border.muted" }).usage).toBe("border");
36
- expect(normalizeQuery({ role: "bg.canvas" }).usage).toBe("bg");
37
- expect(normalizeQuery({ role: "ring.focus" }).usage).toBe("ring");
38
- expect(normalizeQuery({ role: "chart.axis.stroke" }).usage).toBe("stroke");
39
- expect(normalizeQuery({ role: "chart.fill.primary" }).usage).toBe("fill");
40
- expect(normalizeQuery({ role: "chart.grid.muted" }).usage).toBe("border");
41
- expect(normalizeQuery({ role: "chart.label" }).usage).toBe("text");
42
- } finally {
43
- warnSpy.mockRestore();
44
- }
45
- });
46
-
47
- it("infers surface when obvious", () => {
48
- expect(normalizeQuery({ role: "bg.app" }).surface).toBe("app");
49
- expect(normalizeQuery({ role: "bg.surface" }).surface).toBe("surface");
50
- expect(normalizeQuery({ role: "app.bg", usage: "bg" }).surface).toBe("app");
51
- });
52
-
53
- it("infers variant from role token", () => {
54
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
55
-
56
- try {
57
- expect(
58
- normalizeQuery({ role: "success.bg", usage: "bg", surface: "surface" }).variant,
59
- ).toBe("success");
60
- expect(
61
- normalizeQuery({ role: "warning.text", usage: "text", surface: "surface" }).variant,
62
- ).toBe("warning");
63
- expect(
64
- normalizeQuery({ role: "danger.border", usage: "border", surface: "surface" }).variant,
65
- ).toBe("danger");
66
- expect(
67
- normalizeQuery({ role: "category:sales.fill", usage: "fill", surface: "surface" }).variant,
68
- ).toBe("category:sales");
69
- expect(
70
- normalizeQuery({
71
- role: "chart:revenue.stroke",
72
- usage: "stroke",
73
- surface: "surface",
74
- }).variant,
75
- ).toBe("chart:revenue");
76
-
77
- expect(
78
- normalizeQuery({ role: "text.primary", usage: "text", surface: "surface" }).variant,
79
- ).toBeUndefined();
80
- } finally {
81
- warnSpy.mockRestore();
82
- }
83
- });
84
-
85
- it("requires usage when strict and inference fails", () => {
86
- expect(() =>
87
- normalizeQuery({ role: "brand.primary", output: { strict: true } }),
88
- ).toThrowError(/Provide usage explicitly/i);
89
- });
90
-
91
- it("warns when usage cannot be inferred in non-strict mode", () => {
92
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
93
-
94
- expect(normalizeQuery({ role: "brand.primary" }).usage).toBe("bg");
95
- expect(warnSpy).toHaveBeenCalledWith(
96
- expect.stringContaining('Defaulting usage to "bg"'),
97
- );
98
-
99
- warnSpy.mockRestore();
100
- });
101
-
102
- it("requires surface when strict and inference fails", () => {
103
- expect(() =>
104
- normalizeQuery({ role: "text.primary", output: { strict: true } }),
105
- ).toThrowError(/Provide surface explicitly/i);
106
- });
107
-
108
- it("warns when surface cannot be inferred in non-strict mode", () => {
109
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
110
-
111
- expect(normalizeQuery({ role: "text.primary" }).surface).toBe("surface");
112
- expect(warnSpy).toHaveBeenCalledWith(
113
- expect.stringContaining('Defaulting surface to "surface"'),
114
- );
115
-
116
- warnSpy.mockRestore();
117
- });
118
-
119
- it("validates background hint color values", () => {
120
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
121
-
122
- expect(
123
- normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "color", value: "#fff" } })
124
- .on,
125
- ).toEqual({ kind: "color", value: "#fff" });
126
- expect(
127
- normalizeQuery({
128
- role: "bg.canvas",
129
- surface: "surface",
130
- on: { kind: "color", value: "oklch(62% 0.18 265)" },
131
- }).on,
132
- ).toEqual({ kind: "color", value: "oklch(62% 0.18 265)" });
133
- expect(
134
- normalizeQuery({
135
- role: "bg.canvas",
136
- surface: "surface",
137
- on: { kind: "color", value: "color(display-p3 1 0.5 0.25)" },
138
- }).on,
139
- ).toEqual({ kind: "color", value: "color(display-p3 1 0.5 0.25)" });
140
- expect(
141
- normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "color", value: "banana" } })
142
- .on,
143
- ).toEqual({ kind: "color", value: "banana" });
144
-
145
- expect(warnSpy).toHaveBeenCalledTimes(3);
146
- warnSpy.mockRestore();
147
- });
148
-
149
- it("normalizes nested background hints", () => {
150
- expect(
151
- normalizeQuery({
152
- role: "bg.canvas",
153
- surface: "surface",
154
- on: { kind: "role", role: " text.primary " },
155
- })
156
- .on,
157
- ).toEqual({ kind: "role", role: "text.primary" });
158
- expect(
159
- normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "auto" } }).on,
160
- ).toEqual({
161
- kind: "auto",
162
- });
163
- expect(() =>
164
- normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "color", value: " " } }),
165
- ).toThrowError(/color value is required/i);
166
- expect(() =>
167
- normalizeQuery({
168
- role: "bg.canvas",
169
- surface: "surface",
170
- on: { kind: "color", value: "banana" },
171
- output: { strict: true },
172
- }),
173
- ).toThrowError(/background hint color value/i);
174
- expect(() =>
175
- normalizeQuery({ role: "bg.canvas", surface: "surface", on: { kind: "nope" } as never }),
176
- ).toThrowError(/background hint kind/i);
177
- });
178
-
179
- it("validates contrast requirements", () => {
180
- expect(
181
- normalizeQuery({ role: "text.primary", contrast: { model: "apca", targetLc: 75 } })
182
- .contrast,
183
- ).toEqual({ model: "apca", targetLc: 75 });
184
- expect(
185
- normalizeQuery({ role: "text.primary", contrast: { model: "wcag2", minRatio: 4.5 } })
186
- .contrast,
187
- ).toEqual({ model: "wcag2", minRatio: 4.5 });
188
- expect(
189
- normalizeQuery({ role: "text.primary", contrast: { model: "none" } }).contrast,
190
- ).toEqual({ model: "none" });
191
- expect(() =>
192
- normalizeQuery({ role: "text.primary", contrast: { model: "apca" } as never }),
193
- ).toThrowError(/targetLc/i);
194
- expect(() =>
195
- normalizeQuery({ role: "text.primary", contrast: { model: "wcag2" } as never }),
196
- ).toThrowError(/minRatio.*ratio/i);
197
- expect(() =>
198
- normalizeQuery({ role: "text.primary", contrast: { model: "wcag2", minRatio: NaN } as never }),
199
- ).toThrowError(/minRatio must be a number/i);
200
- expect(() =>
201
- normalizeQuery({ role: "text.primary", contrast: { model: "nope" } as never }),
202
- ).toThrowError(/contrast model/i);
203
- });
204
-
205
- it("validates alpha strategies", () => {
206
- expect(
207
- normalizeQuery({ role: "bg.canvas", alpha: { mode: "none" } }).alpha,
208
- ).toEqual({ mode: "none" });
209
- expect(
210
- normalizeQuery({ role: "bg.canvas", alpha: { mode: "fixed", alpha: 0.5 } }).alpha,
211
- ).toEqual({ mode: "fixed", alpha: 0.5 });
212
- expect(
213
- normalizeQuery({ role: "bg.canvas", alpha: { mode: "solveOnBackground" } }).alpha,
214
- ).toEqual({ mode: "solveOnBackground" });
215
- expect(() =>
216
- normalizeQuery({ role: "bg.canvas", alpha: { mode: "fixed" } as never }),
217
- ).toThrowError(/fixed alpha/i);
218
- expect(() =>
219
- normalizeQuery({ role: "bg.canvas", alpha: { mode: "nope" } as never }),
220
- ).toThrowError(/alpha strategy mode/i);
221
- });
222
- });