omni-color 0.1.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 (293) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +1042 -0
  3. package/dist/__test__/color-interop.test.d.ts +1 -0
  4. package/dist/__test__/color-interop.test.js +82 -0
  5. package/dist/__test__/comparison_culori.test.d.ts +1 -0
  6. package/dist/__test__/comparison_culori.test.js +169 -0
  7. package/dist/__test__/interop-chroma.test.d.ts +1 -0
  8. package/dist/__test__/interop-chroma.test.js +676 -0
  9. package/dist/__test__/interop-tinycolor.test.d.ts +1 -0
  10. package/dist/__test__/interop-tinycolor.test.js +499 -0
  11. package/dist/color/__test__/baseColor.test.d.ts +2 -0
  12. package/dist/color/__test__/baseColor.test.d.ts.map +1 -0
  13. package/dist/color/__test__/baseColor.test.js +34 -0
  14. package/dist/color/__test__/baseColor.test.js.map +1 -0
  15. package/dist/color/__test__/blank.d.ts +1 -0
  16. package/dist/color/__test__/blank.js +3 -0
  17. package/dist/color/__test__/color.test.d.ts +1 -0
  18. package/dist/color/__test__/color.test.js +1073 -0
  19. package/dist/color/__test__/colorSpaces.test.d.ts +1 -0
  20. package/dist/color/__test__/colorSpaces.test.js +69 -0
  21. package/dist/color/__test__/combinations.test.d.ts +1 -0
  22. package/dist/color/__test__/combinations.test.js +665 -0
  23. package/dist/color/__test__/conversions.test.d.ts +1 -0
  24. package/dist/color/__test__/conversions.test.js +719 -0
  25. package/dist/color/__test__/deltaE.test.d.ts +1 -0
  26. package/dist/color/__test__/deltaE.test.js +120 -0
  27. package/dist/color/__test__/formats.test.d.ts +1 -0
  28. package/dist/color/__test__/formats.test.js +514 -0
  29. package/dist/color/__test__/gradients.test.d.ts +1 -0
  30. package/dist/color/__test__/gradients.test.js +414 -0
  31. package/dist/color/__test__/harmonies.test.d.ts +1 -0
  32. package/dist/color/__test__/harmonies.test.js +676 -0
  33. package/dist/color/__test__/manipulations.test.d.ts +1 -0
  34. package/dist/color/__test__/manipulations.test.js +264 -0
  35. package/dist/color/__test__/names.test.d.ts +1 -0
  36. package/dist/color/__test__/names.test.js +67 -0
  37. package/dist/color/__test__/parse.test.d.ts +1 -0
  38. package/dist/color/__test__/parse.test.js +256 -0
  39. package/dist/color/__test__/random.test.d.ts +1 -0
  40. package/dist/color/__test__/random.test.js +262 -0
  41. package/dist/color/__test__/readability.test.d.ts +1 -0
  42. package/dist/color/__test__/readability.test.js +2596 -0
  43. package/dist/color/__test__/srgb.test.d.ts +1 -0
  44. package/dist/color/__test__/srgb.test.js +43 -0
  45. package/dist/color/__test__/swatch.test.d.ts +1 -0
  46. package/dist/color/__test__/swatch.test.js +267 -0
  47. package/dist/color/__test__/temperature.test.d.ts +1 -0
  48. package/dist/color/__test__/temperature.test.js +223 -0
  49. package/dist/color/__test__/utils.test.d.ts +1 -0
  50. package/dist/color/__test__/utils.test.js +409 -0
  51. package/dist/color/__test__/validations.test.d.ts +1 -0
  52. package/dist/color/__test__/validations.test.js +239 -0
  53. package/dist/color/color.constants.d.ts +4 -0
  54. package/dist/color/color.constants.d.ts.map +1 -0
  55. package/dist/color/color.constants.js +152 -0
  56. package/dist/color/color.constants.js.map +1 -0
  57. package/dist/color/color.consts.d.ts +4 -0
  58. package/dist/color/color.consts.js +152 -0
  59. package/dist/color/color.d.ts +788 -0
  60. package/dist/color/color.d.ts.map +1 -0
  61. package/dist/color/color.helpers.d.ts +6 -0
  62. package/dist/color/color.helpers.js +4 -0
  63. package/dist/color/color.js +919 -0
  64. package/dist/color/color.js.map +1 -0
  65. package/dist/color/colorSpaces.d.ts +15 -0
  66. package/dist/color/colorSpaces.js +127 -0
  67. package/dist/color/combinations.d.ts +45 -0
  68. package/dist/color/combinations.js +562 -0
  69. package/dist/color/conversions.d.ts +16 -0
  70. package/dist/color/conversions.d.ts.map +1 -0
  71. package/dist/color/conversions.js +705 -0
  72. package/dist/color/conversions.js.map +1 -0
  73. package/dist/color/deltaE.d.ts +59 -0
  74. package/dist/color/deltaE.js +110 -0
  75. package/dist/color/formats.d.ts +128 -0
  76. package/dist/color/formats.d.ts.map +1 -0
  77. package/dist/color/formats.js +153 -0
  78. package/dist/color/formats.js.map +1 -0
  79. package/dist/color/gradients.d.ts +49 -0
  80. package/dist/color/gradients.js +672 -0
  81. package/dist/color/harmonies.d.ts +18 -0
  82. package/dist/color/harmonies.js +128 -0
  83. package/dist/color/manipulations.d.ts +29 -0
  84. package/dist/color/manipulations.js +106 -0
  85. package/dist/color/names.d.ts +38 -0
  86. package/dist/color/names.js +108 -0
  87. package/dist/color/parse.d.ts +2 -0
  88. package/dist/color/parse.js +437 -0
  89. package/dist/color/random.d.ts +30 -0
  90. package/dist/color/random.js +65 -0
  91. package/dist/color/readability.d.ts +53 -0
  92. package/dist/color/readability.js +284 -0
  93. package/dist/color/srgb.d.ts +8 -0
  94. package/dist/color/srgb.js +33 -0
  95. package/dist/color/swatch.d.ts +49 -0
  96. package/dist/color/swatch.js +118 -0
  97. package/dist/color/temperature.d.ts +26 -0
  98. package/dist/color/temperature.js +141 -0
  99. package/dist/color/utils.d.ts +49 -0
  100. package/dist/color/utils.d.ts.map +1 -0
  101. package/dist/color/utils.js +104 -0
  102. package/dist/color/utils.js.map +1 -0
  103. package/dist/color/validations.d.ts +2 -0
  104. package/dist/color/validations.d.ts.map +1 -0
  105. package/dist/color/validations.js +178 -0
  106. package/dist/color/validations.js.map +1 -0
  107. package/dist/demo/src/AppFooter.d.ts +1 -0
  108. package/dist/demo/src/AppFooter.js +4 -0
  109. package/dist/demo/src/AppHeader.d.ts +5 -0
  110. package/dist/demo/src/AppHeader.js +6 -0
  111. package/dist/demo/src/components/Card.d.ts +9 -0
  112. package/dist/demo/src/components/Card.js +9 -0
  113. package/dist/demo/src/components/Chip.d.ts +21 -0
  114. package/dist/demo/src/components/Chip.js +23 -0
  115. package/dist/demo/src/components/ColorBox.d.ts +16 -0
  116. package/dist/demo/src/components/ColorBox.js +45 -0
  117. package/dist/demo/src/components/ColorInfoCard.d.ts +7 -0
  118. package/dist/demo/src/components/ColorInfoCard.js +50 -0
  119. package/dist/demo/src/components/ExpandableCodeSnippet.d.ts +5 -0
  120. package/dist/demo/src/components/ExpandableCodeSnippet.js +17 -0
  121. package/dist/demo/src/components/Icon.d.ts +11 -0
  122. package/dist/demo/src/components/Icon.js +50 -0
  123. package/dist/demo/src/components/Icon.types.d.ts +14 -0
  124. package/dist/demo/src/components/Icon.types.js +15 -0
  125. package/dist/demo/src/components/SectionContainer.d.ts +10 -0
  126. package/dist/demo/src/components/SectionContainer.js +12 -0
  127. package/dist/demo/src/components/VSpace.d.ts +5 -0
  128. package/dist/demo/src/components/VSpace.js +4 -0
  129. package/dist/demo/src/components/inputs/Checkbox.d.ts +7 -0
  130. package/dist/demo/src/components/inputs/Checkbox.js +4 -0
  131. package/dist/demo/src/components/inputs/InputGroup.d.ts +6 -0
  132. package/dist/demo/src/components/inputs/InputGroup.js +4 -0
  133. package/dist/demo/src/components/inputs/NumberInput.d.ts +10 -0
  134. package/dist/demo/src/components/inputs/NumberInput.js +8 -0
  135. package/dist/demo/src/components/inputs/Select.d.ts +12 -0
  136. package/dist/demo/src/components/inputs/Select.js +6 -0
  137. package/dist/demo/src/components/inputs/Slider.d.ts +10 -0
  138. package/dist/demo/src/components/inputs/Slider.js +4 -0
  139. package/dist/demo/src/components/utils.d.ts +17 -0
  140. package/dist/demo/src/components/utils.js +24 -0
  141. package/dist/demo/src/demo/ColorDemo.d.ts +1 -0
  142. package/dist/demo/src/demo/ColorDemo.js +45 -0
  143. package/dist/demo/src/demo/ColorHarmonyDemo.d.ts +6 -0
  144. package/dist/demo/src/demo/ColorHarmonyDemo.js +18 -0
  145. package/dist/demo/src/demo/ColorInfo.d.ts +6 -0
  146. package/dist/demo/src/demo/ColorInfo.js +14 -0
  147. package/dist/demo/src/demo/ColorInput.d.ts +7 -0
  148. package/dist/demo/src/demo/ColorInput.js +58 -0
  149. package/dist/demo/src/demo/ColorManipulationDemo.d.ts +6 -0
  150. package/dist/demo/src/demo/ColorManipulationDemo.js +63 -0
  151. package/dist/demo/src/demo/ColorSwatch.d.ts +13 -0
  152. package/dist/demo/src/demo/ColorSwatch.js +15 -0
  153. package/dist/demo/src/demo/ReadabilityDemo.d.ts +6 -0
  154. package/dist/demo/src/demo/ReadabilityDemo.js +24 -0
  155. package/dist/demo/src/demo/combinations/AverageColorsOptionInputs.d.ts +7 -0
  156. package/dist/demo/src/demo/combinations/AverageColorsOptionInputs.js +7 -0
  157. package/dist/demo/src/demo/combinations/BlendColorsOptionInputs.d.ts +7 -0
  158. package/dist/demo/src/demo/combinations/BlendColorsOptionInputs.js +13 -0
  159. package/dist/demo/src/demo/combinations/ColorCombinationDemo.d.ts +6 -0
  160. package/dist/demo/src/demo/combinations/ColorCombinationDemo.js +78 -0
  161. package/dist/demo/src/demo/combinations/MixColorsOptionInputs.d.ts +7 -0
  162. package/dist/demo/src/demo/combinations/MixColorsOptionInputs.js +10 -0
  163. package/dist/demo/src/demo/combinations/colorCombinationDemo.consts.d.ts +4 -0
  164. package/dist/demo/src/demo/combinations/colorCombinationDemo.consts.js +12 -0
  165. package/dist/demo/src/demo/gradients/GradientOptionInputs.d.ts +10 -0
  166. package/dist/demo/src/demo/gradients/GradientOptionInputs.js +42 -0
  167. package/dist/demo/src/demo/gradients/GradientThroughCard.d.ts +6 -0
  168. package/dist/demo/src/demo/gradients/GradientThroughCard.js +50 -0
  169. package/dist/demo/src/demo/gradients/GradientToCard.d.ts +6 -0
  170. package/dist/demo/src/demo/gradients/GradientToCard.js +54 -0
  171. package/dist/demo/src/demo/gradients/GradientsDemo.d.ts +6 -0
  172. package/dist/demo/src/demo/gradients/GradientsDemo.js +6 -0
  173. package/dist/demo/src/demo/gradients/gradientOptions.consts.d.ts +3 -0
  174. package/dist/demo/src/demo/gradients/gradientOptions.consts.js +16 -0
  175. package/dist/demo/src/demo/palette/ColorPaletteDemo.d.ts +6 -0
  176. package/dist/demo/src/demo/palette/ColorPaletteDemo.js +26 -0
  177. package/dist/demo/src/demo/palette/PaletteGenerationOptions.d.ts +8 -0
  178. package/dist/demo/src/demo/palette/PaletteGenerationOptions.js +53 -0
  179. package/dist/demo/src/demo/palette/PaletteHarmonyOptions.d.ts +7 -0
  180. package/dist/demo/src/demo/palette/PaletteHarmonyOptions.js +5 -0
  181. package/dist/demo/src/main.d.ts +1 -0
  182. package/dist/demo/src/main.js +14 -0
  183. package/dist/demo/src/pages/DemoPage.d.ts +1 -0
  184. package/dist/demo/src/pages/DemoPage.js +28 -0
  185. package/dist/demo/src/pages/PlaygroundPage.d.ts +1 -0
  186. package/dist/demo/src/pages/PlaygroundPage.js +24 -0
  187. package/dist/demo/src/playground/Playground.d.ts +1 -0
  188. package/dist/demo/src/playground/Playground.js +42 -0
  189. package/dist/demo/src/playground/playgroundUtils.d.ts +16 -0
  190. package/dist/demo/src/playground/playgroundUtils.js +202 -0
  191. package/dist/demo/src/seo/PageHead.d.ts +9 -0
  192. package/dist/demo/src/seo/PageHead.js +76 -0
  193. package/dist/demo/src/seo/StructuredData.d.ts +6 -0
  194. package/dist/demo/src/seo/StructuredData.js +13 -0
  195. package/dist/demo/src/toast/ToastProvider.d.ts +2 -0
  196. package/dist/demo/src/toast/ToastProvider.js +62 -0
  197. package/dist/demo/src/toast/index.d.ts +2 -0
  198. package/dist/demo/src/toast/index.js +2 -0
  199. package/dist/demo/src/toast/toastBus.d.ts +13 -0
  200. package/dist/demo/src/toast/toastBus.js +27 -0
  201. package/dist/index.d.ts +1233 -0
  202. package/dist/index.d.ts.map +1 -0
  203. package/dist/index.js +5235 -0
  204. package/dist/index.js.map +1 -0
  205. package/dist/palette/__test__/palette.test.d.ts +1 -0
  206. package/dist/palette/__test__/palette.test.js +397 -0
  207. package/dist/palette/palette.d.ts +41 -0
  208. package/dist/palette/palette.js +126 -0
  209. package/dist/src/__test__/interop-chroma.test.d.ts +1 -0
  210. package/dist/src/__test__/interop-chroma.test.js +673 -0
  211. package/dist/src/__test__/interop-tinycolor.test.d.ts +1 -0
  212. package/dist/src/__test__/interop-tinycolor.test.js +499 -0
  213. package/dist/src/color/__test__/color.test.d.ts +1 -0
  214. package/dist/src/color/__test__/color.test.js +1071 -0
  215. package/dist/src/color/__test__/colorSpaces.test.d.ts +1 -0
  216. package/dist/src/color/__test__/colorSpaces.test.js +69 -0
  217. package/dist/src/color/__test__/combinations.test.d.ts +1 -0
  218. package/dist/src/color/__test__/combinations.test.js +665 -0
  219. package/dist/src/color/__test__/conversions.test.d.ts +1 -0
  220. package/dist/src/color/__test__/conversions.test.js +719 -0
  221. package/dist/src/color/__test__/deltaE.test.d.ts +1 -0
  222. package/dist/src/color/__test__/deltaE.test.js +120 -0
  223. package/dist/src/color/__test__/formats.test.d.ts +1 -0
  224. package/dist/src/color/__test__/formats.test.js +470 -0
  225. package/dist/src/color/__test__/gradients.test.d.ts +1 -0
  226. package/dist/src/color/__test__/gradients.test.js +414 -0
  227. package/dist/src/color/__test__/harmonies.test.d.ts +1 -0
  228. package/dist/src/color/__test__/harmonies.test.js +734 -0
  229. package/dist/src/color/__test__/manipulations.test.d.ts +1 -0
  230. package/dist/src/color/__test__/manipulations.test.js +264 -0
  231. package/dist/src/color/__test__/names.test.d.ts +1 -0
  232. package/dist/src/color/__test__/names.test.js +67 -0
  233. package/dist/src/color/__test__/parse.test.d.ts +1 -0
  234. package/dist/src/color/__test__/parse.test.js +251 -0
  235. package/dist/src/color/__test__/random.test.d.ts +1 -0
  236. package/dist/src/color/__test__/random.test.js +262 -0
  237. package/dist/src/color/__test__/readability.test.d.ts +1 -0
  238. package/dist/src/color/__test__/readability.test.js +2596 -0
  239. package/dist/src/color/__test__/swatch.test.d.ts +1 -0
  240. package/dist/src/color/__test__/swatch.test.js +267 -0
  241. package/dist/src/color/__test__/temperature.test.d.ts +1 -0
  242. package/dist/src/color/__test__/temperature.test.js +223 -0
  243. package/dist/src/color/__test__/utils.test.d.ts +1 -0
  244. package/dist/src/color/__test__/utils.test.js +409 -0
  245. package/dist/src/color/__test__/validations.test.d.ts +1 -0
  246. package/dist/src/color/__test__/validations.test.js +239 -0
  247. package/dist/src/color/color.consts.d.ts +4 -0
  248. package/dist/src/color/color.consts.js +152 -0
  249. package/dist/src/color/color.d.ts +775 -0
  250. package/dist/src/color/color.js +903 -0
  251. package/dist/src/color/colorSpaces.d.ts +15 -0
  252. package/dist/src/color/colorSpaces.js +127 -0
  253. package/dist/src/color/combinations.d.ts +45 -0
  254. package/dist/src/color/combinations.js +557 -0
  255. package/dist/src/color/conversions.d.ts +16 -0
  256. package/dist/src/color/conversions.js +705 -0
  257. package/dist/src/color/deltaE.d.ts +59 -0
  258. package/dist/src/color/deltaE.js +110 -0
  259. package/dist/src/color/formats.d.ts +126 -0
  260. package/dist/src/color/formats.js +150 -0
  261. package/dist/src/color/gradients.d.ts +49 -0
  262. package/dist/src/color/gradients.js +673 -0
  263. package/dist/src/color/harmonies.d.ts +18 -0
  264. package/dist/src/color/harmonies.js +129 -0
  265. package/dist/src/color/manipulations.d.ts +29 -0
  266. package/dist/src/color/manipulations.js +107 -0
  267. package/dist/src/color/names.d.ts +38 -0
  268. package/dist/src/color/names.js +108 -0
  269. package/dist/src/color/parse.d.ts +2 -0
  270. package/dist/src/color/parse.js +438 -0
  271. package/dist/src/color/random.d.ts +30 -0
  272. package/dist/src/color/random.js +65 -0
  273. package/dist/src/color/readability.d.ts +53 -0
  274. package/dist/src/color/readability.js +284 -0
  275. package/dist/src/color/swatch.d.ts +49 -0
  276. package/dist/src/color/swatch.js +117 -0
  277. package/dist/src/color/temperature.d.ts +26 -0
  278. package/dist/src/color/temperature.js +142 -0
  279. package/dist/src/color/utils.d.ts +57 -0
  280. package/dist/src/color/utils.js +142 -0
  281. package/dist/src/color/validations.d.ts +2 -0
  282. package/dist/src/color/validations.js +178 -0
  283. package/dist/src/index.d.ts +20 -0
  284. package/dist/src/index.js +2 -0
  285. package/dist/src/palette/__test__/palette.test.d.ts +1 -0
  286. package/dist/src/palette/__test__/palette.test.js +397 -0
  287. package/dist/src/palette/palette.d.ts +41 -0
  288. package/dist/src/palette/palette.js +127 -0
  289. package/dist/src/utils.d.ts +20 -0
  290. package/dist/src/utils.js +42 -0
  291. package/dist/utils.d.ts +20 -0
  292. package/dist/utils.js +42 -0
  293. package/package.json +96 -0
@@ -0,0 +1,734 @@
1
+ import { Color } from '../color';
2
+ import { getAnalogousHarmonyColors, getComplementaryColors, getHarmonyColors, getMonochromaticHarmonyColors, getSplitComplementaryColors, getSquareHarmonyColors, getTetradicHarmonyColors, getTriadicHarmonyColors, } from '../harmonies';
3
+ describe('getComplementaryColors', () => {
4
+ it('returns complementary pairs for primary colors', () => {
5
+ const [redOrig, redComp] = getComplementaryColors(new Color('#ff0000'));
6
+ expect(redOrig.toHex()).toBe('#ff0000');
7
+ expect(redComp.toHex()).toBe('#00ffff');
8
+ const [greenOrig, greenComp] = getComplementaryColors(new Color('#00ff00'));
9
+ expect(greenOrig.toHex()).toBe('#00ff00');
10
+ expect(greenComp.toHex()).toBe('#ff00ff');
11
+ const [blueOrig, blueComp] = getComplementaryColors(new Color('#0000ff'));
12
+ expect(blueOrig.toHex()).toBe('#0000ff');
13
+ expect(blueComp.toHex()).toBe('#ffff00');
14
+ });
15
+ it('returns complementary pairs for brand colors', () => {
16
+ const [purpleOrig, purpleComp] = getComplementaryColors(new Color('#ee6ffc'));
17
+ expect(purpleOrig.toHex()).toBe('#ee6ffc');
18
+ expect(purpleComp.toHex()).toBe('#7dfc6f');
19
+ const [blueOrig, blueComp] = getComplementaryColors(new Color('#2e3575'));
20
+ expect(blueOrig.toHex()).toBe('#2e3575');
21
+ expect(blueComp.toHex()).toBe('#756e2e');
22
+ const [yellowOrig, yellowComp] = getComplementaryColors(new Color('#d3e204'));
23
+ expect(yellowOrig.toHex()).toBe('#d3e204');
24
+ expect(yellowComp.toHex()).toBe('#1304e2');
25
+ const [greenOrig, greenComp] = getComplementaryColors(new Color('#29cc53'));
26
+ expect(greenOrig.toHex()).toBe('#29cc53');
27
+ expect(greenComp.toHex()).toBe('#cc29a2');
28
+ const [pinkOrig, pinkComp] = getComplementaryColors(new Color('#811242'));
29
+ expect(pinkOrig.toHex()).toBe('#811242');
30
+ expect(pinkComp.toHex()).toBe('#128151');
31
+ const [brandRedOrig, brandRedComp] = getComplementaryColors(new Color('#de0d14'));
32
+ expect(brandRedOrig.toHex()).toBe('#de0d14');
33
+ expect(brandRedComp.toHex()).toBe('#0dded7');
34
+ });
35
+ it('returns complementary pairs for grayscale colors', () => {
36
+ const [blackOrig, blackComp] = getComplementaryColors(new Color('#000000'));
37
+ expect(blackOrig.toHex()).toBe('#000000');
38
+ expect(blackComp.toHex()).toBe('#ffffff');
39
+ const [whiteOrig, whiteComp] = getComplementaryColors(new Color('#ffffff'));
40
+ expect(whiteOrig.toHex()).toBe('#ffffff');
41
+ expect(whiteComp.toHex()).toBe('#000000');
42
+ const [lightGrayOrig, lightGrayComp] = getComplementaryColors(new Color('#d3d3d3'));
43
+ expect(lightGrayOrig.toHex()).toBe('#d3d3d3');
44
+ expect(lightGrayComp.toHex()).toBe('#2b2b2b');
45
+ const [grayOrig, grayComp] = getComplementaryColors(new Color('#808080'));
46
+ expect(grayOrig.toHex()).toBe('#808080');
47
+ expect(grayComp.toHex()).toBe('#808080');
48
+ const [darkGrayOrig, darkGrayComp] = getComplementaryColors(new Color('#333333'));
49
+ expect(darkGrayOrig.toHex()).toBe('#333333');
50
+ expect(darkGrayComp.toHex()).toBe('#cccccc');
51
+ });
52
+ it('handles grayscale color modes', () => {
53
+ const spin = getComplementaryColors(new Color('#000000'), {
54
+ grayscaleHandlingMode: 'SPIN_LIGHTNESS',
55
+ }).map((c) => c.toHex());
56
+ expect(spin).toEqual(['#000000', '#ffffff']);
57
+ const ignore = getComplementaryColors(new Color('#000000'), {
58
+ grayscaleHandlingMode: 'IGNORE',
59
+ }).map((c) => c.toHex());
60
+ expect(ignore).toEqual(['#000000', '#000000']);
61
+ });
62
+ it('preserves alpha when creating complements', () => {
63
+ const [base, complement] = getComplementaryColors(new Color('rgba(255, 0, 0, 0.4)'));
64
+ expect(base.toRGBA().a).toBeCloseTo(0.4, 5);
65
+ expect(complement.toRGBA().a).toBeCloseTo(0.4, 5);
66
+ expect(complement.toHex8()).toBe('#00ffff66');
67
+ });
68
+ });
69
+ describe('getSplitComplementaryColors', () => {
70
+ it('returns split complement colors for primary colors', () => {
71
+ const [redOrig, redComp2, redComp3] = getSplitComplementaryColors(new Color('#ff0000'));
72
+ expect(redOrig.toHex()).toBe('#ff0000');
73
+ expect(redComp2.toHex()).toBe('#0080ff');
74
+ expect(redComp3.toHex()).toBe('#00ff80');
75
+ const [greenOrig, greenComp2, greenComp3] = getSplitComplementaryColors(new Color('#00ff00'));
76
+ expect(greenOrig.toHex()).toBe('#00ff00');
77
+ expect(greenComp2.toHex()).toBe('#ff0080');
78
+ expect(greenComp3.toHex()).toBe('#8000ff');
79
+ const [blueOrig, blueComp2, blueComp3] = getSplitComplementaryColors(new Color('#0000ff'));
80
+ expect(blueOrig.toHex()).toBe('#0000ff');
81
+ expect(blueComp2.toHex()).toBe('#80ff00');
82
+ expect(blueComp3.toHex()).toBe('#ff8000');
83
+ });
84
+ it('returns split complement colors for brand colors', () => {
85
+ const [purpleOrig, purpleComp2, purpleComp3] = getSplitComplementaryColors(new Color('#ee6ffc'));
86
+ expect(purpleOrig.toHex()).toBe('#ee6ffc');
87
+ expect(purpleComp2.toHex()).toBe('#6ffca7');
88
+ expect(purpleComp3.toHex()).toBe('#c4fc6f');
89
+ const [brandBlueOrig, brandBlueComp2, brandBlueComp3] = getSplitComplementaryColors(new Color('#2e3575'));
90
+ expect(brandBlueOrig.toHex()).toBe('#2e3575');
91
+ expect(brandBlueComp2.toHex()).toBe('#58752e');
92
+ expect(brandBlueComp3.toHex()).toBe('#754b2e');
93
+ const [yellowOrig, yellowComp2, yellowComp3] = getSplitComplementaryColors(new Color('#d3e204'));
94
+ expect(yellowOrig.toHex()).toBe('#d3e204');
95
+ expect(yellowComp2.toHex()).toBe('#8204e2');
96
+ expect(yellowComp3.toHex()).toBe('#0464e2');
97
+ const [greenOrig, greenComp2, greenComp3] = getSplitComplementaryColors(new Color('#29cc53'));
98
+ expect(greenOrig.toHex()).toBe('#29cc53');
99
+ expect(greenComp2.toHex()).toBe('#cc2951');
100
+ expect(greenComp3.toHex()).toBe('#a429cc');
101
+ const [pinkOrig, pinkComp2, pinkComp3] = getSplitComplementaryColors(new Color('#811242'));
102
+ expect(pinkOrig.toHex()).toBe('#811242');
103
+ expect(pinkComp2.toHex()).toBe('#127a81');
104
+ expect(pinkComp3.toHex()).toBe('#128119');
105
+ const [brandRedOrig, brandRedComp2, brandRedComp3] = getSplitComplementaryColors(new Color('#de0d14'));
106
+ expect(brandRedOrig.toHex()).toBe('#de0d14');
107
+ expect(brandRedComp2.toHex()).toBe('#0d7cde');
108
+ expect(brandRedComp3.toHex()).toBe('#0dde6f');
109
+ });
110
+ it('returns split complement colors for grayscale colors', () => {
111
+ const [blackOrig, blackComp2, blackComp3] = getSplitComplementaryColors(new Color('#000000'));
112
+ expect(blackOrig.toHex()).toBe('#000000');
113
+ expect(blackComp2.toHex()).toBe('#d4d4d4');
114
+ expect(blackComp3.toHex()).toBe('#d4d4d4');
115
+ const [whiteOrig, whiteComp2, whiteComp3] = getSplitComplementaryColors(new Color('#ffffff'));
116
+ expect(whiteOrig.toHex()).toBe('#ffffff');
117
+ expect(whiteComp2.toHex()).toBe('#2b2b2b');
118
+ expect(whiteComp3.toHex()).toBe('#2b2b2b');
119
+ const [lightGrayOrig, lightGrayComp2, lightGrayComp3] = getSplitComplementaryColors(new Color('#d3d3d3'));
120
+ expect(lightGrayOrig.toHex()).toBe('#d3d3d3');
121
+ expect(lightGrayComp2.toHex()).toBe('#474747');
122
+ expect(lightGrayComp3.toHex()).toBe('#474747');
123
+ const [grayOrig, grayComp2, grayComp3] = getSplitComplementaryColors(new Color('#808080'));
124
+ expect(grayOrig.toHex()).toBe('#808080');
125
+ expect(grayComp2.toHex()).toBe('#808080');
126
+ expect(grayComp3.toHex()).toBe('#808080');
127
+ const [darkGrayOrig, darkGrayComp2, darkGrayComp3] = getSplitComplementaryColors(new Color('#333333'));
128
+ expect(darkGrayOrig.toHex()).toBe('#333333');
129
+ expect(darkGrayComp2.toHex()).toBe('#b3b3b3');
130
+ expect(darkGrayComp3.toHex()).toBe('#b3b3b3');
131
+ });
132
+ it('handles grayscale color modes', () => {
133
+ const spin = getSplitComplementaryColors(new Color('#000000'), {
134
+ grayscaleHandlingMode: 'SPIN_LIGHTNESS',
135
+ }).map((c) => c.toHex());
136
+ expect(spin).toEqual(['#000000', '#d4d4d4', '#d4d4d4']);
137
+ const ignore = getSplitComplementaryColors(new Color('#000000'), {
138
+ grayscaleHandlingMode: 'IGNORE',
139
+ }).map((c) => c.toHex());
140
+ expect(ignore).toEqual(['#000000', '#000000', '#000000']);
141
+ });
142
+ });
143
+ describe('getTriadicHarmonyColors', () => {
144
+ it('returns triadic harmony colors for primary colors', () => {
145
+ const [redOrig, redTriad2, redTriad3] = getTriadicHarmonyColors(new Color('#ff0000'));
146
+ expect(redOrig.toHex()).toBe('#ff0000');
147
+ expect(redTriad2.toHex()).toBe('#0000ff');
148
+ expect(redTriad3.toHex()).toBe('#00ff00');
149
+ const [greenOrig, greenTriad2, greenTriad3] = getTriadicHarmonyColors(new Color('#00ff00'));
150
+ expect(greenOrig.toHex()).toBe('#00ff00');
151
+ expect(greenTriad2.toHex()).toBe('#ff0000');
152
+ expect(greenTriad3.toHex()).toBe('#0000ff');
153
+ const [blueOrig, blueTriad2, blueTriad3] = getTriadicHarmonyColors(new Color('#0000ff'));
154
+ expect(blueOrig.toHex()).toBe('#0000ff');
155
+ expect(blueTriad2.toHex()).toBe('#00ff00');
156
+ expect(blueTriad3.toHex()).toBe('#ff0000');
157
+ });
158
+ it('returns triadic harmony colors for brand colors', () => {
159
+ const [purpleOrig, purpleTriad2, purpleTriad3] = getTriadicHarmonyColors(new Color('#ee6ffc'));
160
+ expect(purpleOrig.toHex()).toBe('#ee6ffc');
161
+ expect(purpleTriad2.toHex()).toBe('#6ffcee');
162
+ expect(purpleTriad3.toHex()).toBe('#fcee6f');
163
+ const [brandBlueOrig, brandBlueTriad2, brandBlueTriad3] = getTriadicHarmonyColors(new Color('#2e3575'));
164
+ expect(brandBlueOrig.toHex()).toBe('#2e3575');
165
+ expect(brandBlueTriad2.toHex()).toBe('#35752e');
166
+ expect(brandBlueTriad3.toHex()).toBe('#752e35');
167
+ const [yellowOrig, yellowTriad2, yellowTriad3] = getTriadicHarmonyColors(new Color('#d3e204'));
168
+ expect(yellowOrig.toHex()).toBe('#d3e204');
169
+ expect(yellowTriad2.toHex()).toBe('#e204d3');
170
+ expect(yellowTriad3.toHex()).toBe('#04d3e2');
171
+ const [greenOrig, greenTriad2, greenTriad3] = getTriadicHarmonyColors(new Color('#29cc53'));
172
+ expect(greenOrig.toHex()).toBe('#29cc53');
173
+ expect(greenTriad2.toHex()).toBe('#cc5329');
174
+ expect(greenTriad3.toHex()).toBe('#5329cc');
175
+ const [pinkOrig, pinkTriad2, pinkTriad3] = getTriadicHarmonyColors(new Color('#811242'));
176
+ expect(pinkOrig.toHex()).toBe('#811242');
177
+ expect(pinkTriad2.toHex()).toBe('#124281');
178
+ expect(pinkTriad3.toHex()).toBe('#428112');
179
+ const [brandRedOrig, brandRedTriad2, brandRedTriad3] = getTriadicHarmonyColors(new Color('#de0d14'));
180
+ expect(brandRedOrig.toHex()).toBe('#de0d14');
181
+ expect(brandRedTriad2.toHex()).toBe('#0d14de');
182
+ expect(brandRedTriad3.toHex()).toBe('#14de0d');
183
+ });
184
+ it('returns triadic harmony colors for grayscale colors', () => {
185
+ const [blackOrig, blackTriad2, blackTriad3] = getTriadicHarmonyColors(new Color('#000000'));
186
+ expect(blackOrig.toHex()).toBe('#000000');
187
+ expect(blackTriad2.toHex()).toBe('#ababab');
188
+ expect(blackTriad3.toHex()).toBe('#ababab');
189
+ const [whiteOrig, whiteTriad2, whiteTriad3] = getTriadicHarmonyColors(new Color('#ffffff'));
190
+ expect(whiteOrig.toHex()).toBe('#ffffff');
191
+ expect(whiteTriad2.toHex()).toBe('#545454');
192
+ expect(whiteTriad3.toHex()).toBe('#545454');
193
+ const [lightGrayOrig, lightGrayTriad2, lightGrayTriad3] = getTriadicHarmonyColors(new Color('#d3d3d3'));
194
+ expect(lightGrayOrig.toHex()).toBe('#d3d3d3');
195
+ expect(lightGrayTriad2.toHex()).toBe('#636363');
196
+ expect(lightGrayTriad3.toHex()).toBe('#636363');
197
+ const [grayOrig, grayTriad2, grayTriad3] = getTriadicHarmonyColors(new Color('#808080'));
198
+ expect(grayOrig.toHex()).toBe('#808080');
199
+ expect(grayTriad2.toHex()).toBe('#808080');
200
+ expect(grayTriad3.toHex()).toBe('#808080');
201
+ const [darkGrayOrig, darkGrayTriad2, darkGrayTriad3] = getTriadicHarmonyColors(new Color('#333333'));
202
+ expect(darkGrayOrig.toHex()).toBe('#333333');
203
+ expect(darkGrayTriad2.toHex()).toBe('#999999');
204
+ expect(darkGrayTriad3.toHex()).toBe('#999999');
205
+ });
206
+ it('handles grayscale color modes', () => {
207
+ const spin = getTriadicHarmonyColors(new Color('#000000'), {
208
+ grayscaleHandlingMode: 'SPIN_LIGHTNESS',
209
+ }).map((c) => c.toHex());
210
+ expect(spin).toEqual(['#000000', '#ababab', '#ababab']);
211
+ const ignore = getTriadicHarmonyColors(new Color('#000000'), {
212
+ grayscaleHandlingMode: 'IGNORE',
213
+ }).map((c) => c.toHex());
214
+ expect(ignore).toEqual(['#000000', '#000000', '#000000']);
215
+ });
216
+ });
217
+ describe('getSquareHarmonyColors', () => {
218
+ it('returns square harmony colors for primary colors', () => {
219
+ const [red1, red2, red3, red4] = getSquareHarmonyColors(new Color('#ff0000'));
220
+ expect(red1.toHex()).toBe('#ff0000');
221
+ expect(red2.toHex()).toBe('#80ff00');
222
+ expect(red3.toHex()).toBe('#00ffff');
223
+ expect(red4.toHex()).toBe('#8000ff');
224
+ const [green1, green2, green3, green4] = getSquareHarmonyColors(new Color('#00ff00'));
225
+ expect(green1.toHex()).toBe('#00ff00');
226
+ expect(green2.toHex()).toBe('#0080ff');
227
+ expect(green3.toHex()).toBe('#ff00ff');
228
+ expect(green4.toHex()).toBe('#ff8000');
229
+ const [blue1, blue2, blue3, blue4] = getSquareHarmonyColors(new Color('#0000ff'));
230
+ expect(blue1.toHex()).toBe('#0000ff');
231
+ expect(blue2.toHex()).toBe('#ff0080');
232
+ expect(blue3.toHex()).toBe('#ffff00');
233
+ expect(blue4.toHex()).toBe('#00ff80');
234
+ });
235
+ it('returns square harmony colors for brand colors', () => {
236
+ const [purple1, purple2, purple3, purple4] = getSquareHarmonyColors(new Color('#ee6ffc'));
237
+ expect(purple1.toHex()).toBe('#ee6ffc');
238
+ expect(purple2.toHex()).toBe('#fca76f');
239
+ expect(purple3.toHex()).toBe('#7dfc6f');
240
+ expect(purple4.toHex()).toBe('#6fc4fc');
241
+ const [brandBlue1, brandBlue2, brandBlue3, brandBlue4] = getSquareHarmonyColors(new Color('#2e3575'));
242
+ expect(brandBlue1.toHex()).toBe('#2e3575');
243
+ expect(brandBlue2.toHex()).toBe('#752e58');
244
+ expect(brandBlue3.toHex()).toBe('#756e2e');
245
+ expect(brandBlue4.toHex()).toBe('#2e754b');
246
+ const [yellow1, yellow2, yellow3, yellow4] = getSquareHarmonyColors(new Color('#d3e204'));
247
+ expect(yellow1.toHex()).toBe('#d3e204');
248
+ expect(yellow2.toHex()).toBe('#04e282');
249
+ expect(yellow3.toHex()).toBe('#1304e2');
250
+ expect(yellow4.toHex()).toBe('#e20464');
251
+ const [green1, green2b, green3b, green4b] = getSquareHarmonyColors(new Color('#29cc53'));
252
+ expect(green1.toHex()).toBe('#29cc53');
253
+ expect(green2b.toHex()).toBe('#2950cc');
254
+ expect(green3b.toHex()).toBe('#cc29a2');
255
+ expect(green4b.toHex()).toBe('#cca429');
256
+ const [pink1, pink2, pink3, pink4] = getSquareHarmonyColors(new Color('#811242'));
257
+ expect(pink1.toHex()).toBe('#811242');
258
+ expect(pink2.toHex()).toBe('#7a8112');
259
+ expect(pink3.toHex()).toBe('#128151');
260
+ expect(pink4.toHex()).toBe('#1a1281');
261
+ const [brandRed1, brandRed2, brandRed3, brandRed4] = getSquareHarmonyColors(new Color('#de0d14'));
262
+ expect(brandRed1.toHex()).toBe('#de0d14');
263
+ expect(brandRed2.toHex()).toBe('#7cde0d');
264
+ expect(brandRed3.toHex()).toBe('#0dded7');
265
+ expect(brandRed4.toHex()).toBe('#6f0dde');
266
+ });
267
+ it('returns square harmony colors for grayscale colors', () => {
268
+ const [black1, black2, black3, black4] = getSquareHarmonyColors(new Color('#000000'));
269
+ expect(black1.toHex()).toBe('#000000');
270
+ expect(black2.toHex()).toBe('#808080');
271
+ expect(black3.toHex()).toBe('#ffffff');
272
+ expect(black4.toHex()).toBe('#808080');
273
+ const [white1, white2, white3, white4] = getSquareHarmonyColors(new Color('#ffffff'));
274
+ expect(white1.toHex()).toBe('#ffffff');
275
+ expect(white2.toHex()).toBe('#808080');
276
+ expect(white3.toHex()).toBe('#000000');
277
+ expect(white4.toHex()).toBe('#808080');
278
+ const [lightGray1, lightGray2, lightGray3, lightGray4] = getSquareHarmonyColors(new Color('#d3d3d3'));
279
+ expect(lightGray1.toHex()).toBe('#d3d3d3');
280
+ expect(lightGray2.toHex()).toBe('#808080');
281
+ expect(lightGray3.toHex()).toBe('#2b2b2b');
282
+ expect(lightGray4.toHex()).toBe('#808080');
283
+ const [gray1, gray2, gray3, gray4] = getSquareHarmonyColors(new Color('#808080'));
284
+ expect(gray1.toHex()).toBe('#808080');
285
+ expect(gray2.toHex()).toBe('#808080');
286
+ expect(gray3.toHex()).toBe('#808080');
287
+ expect(gray4.toHex()).toBe('#808080');
288
+ const [darkGray1, darkGray2, darkGray3, darkGray4] = getSquareHarmonyColors(new Color('#333333'));
289
+ expect(darkGray1.toHex()).toBe('#333333');
290
+ expect(darkGray2.toHex()).toBe('#808080');
291
+ expect(darkGray3.toHex()).toBe('#cccccc');
292
+ expect(darkGray4.toHex()).toBe('#808080');
293
+ });
294
+ it('handles grayscale color modes', () => {
295
+ const spin = getSquareHarmonyColors(new Color('#000000'), {
296
+ grayscaleHandlingMode: 'SPIN_LIGHTNESS',
297
+ }).map((c) => c.toHex());
298
+ expect(spin).toEqual(['#000000', '#808080', '#ffffff', '#808080']);
299
+ const ignore = getSquareHarmonyColors(new Color('#000000'), {
300
+ grayscaleHandlingMode: 'IGNORE',
301
+ }).map((c) => c.toHex());
302
+ expect(ignore).toEqual(['#000000', '#000000', '#000000', '#000000']);
303
+ });
304
+ });
305
+ describe('getTetradicHarmonyColors', () => {
306
+ it('returns tetradic harmony colors for primary colors', () => {
307
+ const [red1, red2, red3, red4] = getTetradicHarmonyColors(new Color('#ff0000'));
308
+ expect(red1.toHex()).toBe('#ff0000');
309
+ expect(red2.toHex()).toBe('#ffff00');
310
+ expect(red3.toHex()).toBe('#00ffff');
311
+ expect(red4.toHex()).toBe('#0000ff');
312
+ const [green1, green2, green3, green4] = getTetradicHarmonyColors(new Color('#00ff00'));
313
+ expect(green1.toHex()).toBe('#00ff00');
314
+ expect(green2.toHex()).toBe('#00ffff');
315
+ expect(green3.toHex()).toBe('#ff00ff');
316
+ expect(green4.toHex()).toBe('#ff0000');
317
+ const [blue1, blue2, blue3, blue4] = getTetradicHarmonyColors(new Color('#0000ff'));
318
+ expect(blue1.toHex()).toBe('#0000ff');
319
+ expect(blue2.toHex()).toBe('#ff00ff');
320
+ expect(blue3.toHex()).toBe('#ffff00');
321
+ expect(blue4.toHex()).toBe('#00ff00');
322
+ });
323
+ it('returns tetradic harmony colors for brand colors', () => {
324
+ const [purple1, purple2, purple3, purple4] = getTetradicHarmonyColors(new Color('#ee6ffc'));
325
+ expect(purple1.toHex()).toBe('#ee6ffc');
326
+ expect(purple2.toHex()).toBe('#fc6f7d');
327
+ expect(purple3.toHex()).toBe('#7dfc6f');
328
+ expect(purple4.toHex()).toBe('#6ffcee');
329
+ const [brandBlue1, brandBlue2, brandBlue3, brandBlue4] = getTetradicHarmonyColors(new Color('#2e3575'));
330
+ expect(brandBlue1.toHex()).toBe('#2e3575');
331
+ expect(brandBlue2.toHex()).toBe('#6e2e75');
332
+ expect(brandBlue3.toHex()).toBe('#756e2e');
333
+ expect(brandBlue4.toHex()).toBe('#35752e');
334
+ const [yellow1, yellow2, yellow3, yellow4] = getTetradicHarmonyColors(new Color('#d3e204'));
335
+ expect(yellow1.toHex()).toBe('#d3e204');
336
+ expect(yellow2.toHex()).toBe('#04e213');
337
+ expect(yellow3.toHex()).toBe('#1304e2');
338
+ expect(yellow4.toHex()).toBe('#e204d3');
339
+ const [green1b, green2b, green3b, green4b] = getTetradicHarmonyColors(new Color('#29cc53'));
340
+ expect(green1b.toHex()).toBe('#29cc53');
341
+ expect(green2b.toHex()).toBe('#29a2cc');
342
+ expect(green3b.toHex()).toBe('#cc29a2');
343
+ expect(green4b.toHex()).toBe('#cc5329');
344
+ const [pink1, pink2, pink3, pink4] = getTetradicHarmonyColors(new Color('#811242'));
345
+ expect(pink1.toHex()).toBe('#811242');
346
+ expect(pink2.toHex()).toBe('#815112');
347
+ expect(pink3.toHex()).toBe('#128151');
348
+ expect(pink4.toHex()).toBe('#124281');
349
+ const [brandRed1, brandRed2, brandRed3, brandRed4] = getTetradicHarmonyColors(new Color('#de0d14'));
350
+ expect(brandRed1.toHex()).toBe('#de0d14');
351
+ expect(brandRed2.toHex()).toBe('#ded70d');
352
+ expect(brandRed3.toHex()).toBe('#0dded7');
353
+ expect(brandRed4.toHex()).toBe('#0d14de');
354
+ });
355
+ it('returns tetradic harmony colors for grayscale colors', () => {
356
+ const [black1, black2, black3, black4] = getTetradicHarmonyColors(new Color('#000000'));
357
+ expect(black1.toHex()).toBe('#000000');
358
+ expect(black2.toHex()).toBe('#545454');
359
+ expect(black3.toHex()).toBe('#ffffff');
360
+ expect(black4.toHex()).toBe('#ababab');
361
+ const [white1, white2, white3, white4] = getTetradicHarmonyColors(new Color('#ffffff'));
362
+ expect(white1.toHex()).toBe('#ffffff');
363
+ expect(white2.toHex()).toBe('#ababab');
364
+ expect(white3.toHex()).toBe('#000000');
365
+ expect(white4.toHex()).toBe('#545454');
366
+ const [lightGray1, lightGray2, lightGray3, lightGray4] = getTetradicHarmonyColors(new Color('#d3d3d3'));
367
+ expect(lightGray1.toHex()).toBe('#d3d3d3');
368
+ expect(lightGray2.toHex()).toBe('#9c9c9c');
369
+ expect(lightGray3.toHex()).toBe('#2b2b2b');
370
+ expect(lightGray4.toHex()).toBe('#636363');
371
+ const [gray1, gray2, gray3, gray4] = getTetradicHarmonyColors(new Color('#808080'));
372
+ expect(gray1.toHex()).toBe('#808080');
373
+ expect(gray2.toHex()).toBe('#808080');
374
+ expect(gray3.toHex()).toBe('#808080');
375
+ expect(gray4.toHex()).toBe('#808080');
376
+ const [darkGray1, darkGray2, darkGray3, darkGray4] = getTetradicHarmonyColors(new Color('#333333'));
377
+ expect(darkGray1.toHex()).toBe('#333333');
378
+ expect(darkGray2.toHex()).toBe('#666666');
379
+ expect(darkGray3.toHex()).toBe('#cccccc');
380
+ expect(darkGray4.toHex()).toBe('#999999');
381
+ });
382
+ it('handles grayscale color modes', () => {
383
+ const spin = getTetradicHarmonyColors(new Color('#000000'), {
384
+ grayscaleHandlingMode: 'SPIN_LIGHTNESS',
385
+ }).map((c) => c.toHex());
386
+ expect(spin).toEqual(['#000000', '#545454', '#ffffff', '#ababab']);
387
+ const ignore = getTetradicHarmonyColors(new Color('#000000'), {
388
+ grayscaleHandlingMode: 'IGNORE',
389
+ }).map((c) => c.toHex());
390
+ expect(ignore).toEqual(['#000000', '#000000', '#000000', '#000000']);
391
+ });
392
+ });
393
+ describe('getAnalogousHarmonyColors', () => {
394
+ it('returns analogous harmony colors for primary colors', () => {
395
+ const [red1, red2, red3, red4, red5] = getAnalogousHarmonyColors(new Color('#ff0000'));
396
+ expect(red1.toHex()).toBe('#ff0000');
397
+ expect(red2.toHex()).toBe('#ff0080');
398
+ expect(red3.toHex()).toBe('#ff8000');
399
+ expect(red4.toHex()).toBe('#ff00ff');
400
+ expect(red5.toHex()).toBe('#ffff00');
401
+ const [green1, green2, green3, green4, green5] = getAnalogousHarmonyColors(new Color('#00ff00'));
402
+ expect(green1.toHex()).toBe('#00ff00');
403
+ expect(green2.toHex()).toBe('#80ff00');
404
+ expect(green3.toHex()).toBe('#00ff80');
405
+ expect(green4.toHex()).toBe('#ffff00');
406
+ expect(green5.toHex()).toBe('#00ffff');
407
+ const [blue1, blue2, blue3, blue4, blue5] = getAnalogousHarmonyColors(new Color('#0000ff'));
408
+ expect(blue1.toHex()).toBe('#0000ff');
409
+ expect(blue2.toHex()).toBe('#0080ff');
410
+ expect(blue3.toHex()).toBe('#8000ff');
411
+ expect(blue4.toHex()).toBe('#00ffff');
412
+ expect(blue5.toHex()).toBe('#ff00ff');
413
+ });
414
+ it('returns analogous harmony colors for brand colors', () => {
415
+ const [purple1, purple2, purple3, purple4, purple5] = getAnalogousHarmonyColors(new Color('#ee6ffc'));
416
+ expect(purple1.toHex()).toBe('#ee6ffc');
417
+ expect(purple2.toHex()).toBe('#a76ffc');
418
+ expect(purple3.toHex()).toBe('#fc6fc4');
419
+ expect(purple4.toHex()).toBe('#6f7dfc');
420
+ expect(purple5.toHex()).toBe('#fc6f7d');
421
+ const [brandBlue1, brandBlue2, brandBlue3, brandBlue4, brandBlue5] = getAnalogousHarmonyColors(new Color('#2e3575'));
422
+ expect(brandBlue1.toHex()).toBe('#2e3575');
423
+ expect(brandBlue2.toHex()).toBe('#2e5875');
424
+ expect(brandBlue3.toHex()).toBe('#4b2e75');
425
+ expect(brandBlue4.toHex()).toBe('#2e756e');
426
+ expect(brandBlue5.toHex()).toBe('#6e2e75');
427
+ const [yellow1, yellow2, yellow3, yellow4, yellow5] = getAnalogousHarmonyColors(new Color('#d3e204'));
428
+ expect(yellow1.toHex()).toBe('#d3e204');
429
+ expect(yellow2.toHex()).toBe('#e28204');
430
+ expect(yellow3.toHex()).toBe('#64e204');
431
+ expect(yellow4.toHex()).toBe('#e21304');
432
+ expect(yellow5.toHex()).toBe('#04e213');
433
+ const [green1b, green2b, green3b, green4b, green5b] = getAnalogousHarmonyColors(new Color('#29cc53'));
434
+ expect(green1b.toHex()).toBe('#29cc53');
435
+ expect(green2b.toHex()).toBe('#51cc29');
436
+ expect(green3b.toHex()).toBe('#29cca4');
437
+ expect(green4b.toHex()).toBe('#a2cc29');
438
+ expect(green5b.toHex()).toBe('#29a2cc');
439
+ const [pink1, pink2, pink3, pink4, pink5] = getAnalogousHarmonyColors(new Color('#811242'));
440
+ expect(pink1.toHex()).toBe('#811242');
441
+ expect(pink2.toHex()).toBe('#81127a');
442
+ expect(pink3.toHex()).toBe('#811a12');
443
+ expect(pink4.toHex()).toBe('#511281');
444
+ expect(pink5.toHex()).toBe('#815112');
445
+ const [brandRed1, brandRed2, brandRed3, brandRed4, brandRed5] = getAnalogousHarmonyColors(new Color('#de0d14'));
446
+ expect(brandRed1.toHex()).toBe('#de0d14');
447
+ expect(brandRed2.toHex()).toBe('#de0d7c');
448
+ expect(brandRed3.toHex()).toBe('#de6f0d');
449
+ expect(brandRed4.toHex()).toBe('#d70dde');
450
+ expect(brandRed5.toHex()).toBe('#ded70d');
451
+ });
452
+ it('returns analogous harmony colors for grayscale colors', () => {
453
+ const [black1, black2, black3, black4, black5] = getAnalogousHarmonyColors(new Color('#000000'));
454
+ expect(black1.toHex()).toBe('#000000');
455
+ expect(black2.toHex()).toBe('#2b2b2b');
456
+ expect(black3.toHex()).toBe('#2b2b2b');
457
+ expect(black4.toHex()).toBe('#545454');
458
+ expect(black5.toHex()).toBe('#545454');
459
+ const [white1, white2, white3, white4, white5] = getAnalogousHarmonyColors(new Color('#ffffff'));
460
+ expect(white1.toHex()).toBe('#ffffff');
461
+ expect(white2.toHex()).toBe('#d4d4d4');
462
+ expect(white3.toHex()).toBe('#d4d4d4');
463
+ expect(white4.toHex()).toBe('#ababab');
464
+ expect(white5.toHex()).toBe('#ababab');
465
+ const [lightGray1, lightGray2, lightGray3, lightGray4, lightGray5] = getAnalogousHarmonyColors(new Color('#d3d3d3'));
466
+ expect(lightGray1.toHex()).toBe('#d3d3d3');
467
+ expect(lightGray2.toHex()).toBe('#b8b8b8');
468
+ expect(lightGray3.toHex()).toBe('#b8b8b8');
469
+ expect(lightGray4.toHex()).toBe('#9c9c9c');
470
+ expect(lightGray5.toHex()).toBe('#9c9c9c');
471
+ const [gray1, gray2, gray3, gray4, gray5] = getAnalogousHarmonyColors(new Color('#808080'));
472
+ expect(gray1.toHex()).toBe('#808080');
473
+ expect(gray2.toHex()).toBe('#808080');
474
+ expect(gray3.toHex()).toBe('#808080');
475
+ expect(gray4.toHex()).toBe('#808080');
476
+ expect(gray5.toHex()).toBe('#808080');
477
+ const [darkGray1, darkGray2, darkGray3, darkGray4, darkGray5] = getAnalogousHarmonyColors(new Color('#333333'));
478
+ expect(darkGray1.toHex()).toBe('#333333');
479
+ expect(darkGray2.toHex()).toBe('#4d4d4d');
480
+ expect(darkGray3.toHex()).toBe('#4d4d4d');
481
+ expect(darkGray4.toHex()).toBe('#666666');
482
+ expect(darkGray5.toHex()).toBe('#666666');
483
+ });
484
+ it('handles grayscale color modes', () => {
485
+ const spin = getAnalogousHarmonyColors(new Color('#000000'), {
486
+ grayscaleHandlingMode: 'SPIN_LIGHTNESS',
487
+ }).map((c) => c.toHex());
488
+ expect(spin).toEqual(['#000000', '#2b2b2b', '#2b2b2b', '#545454', '#545454']);
489
+ const ignore = getAnalogousHarmonyColors(new Color('#000000'), {
490
+ grayscaleHandlingMode: 'IGNORE',
491
+ }).map((c) => c.toHex());
492
+ expect(ignore).toEqual(['#000000', '#000000', '#000000', '#000000', '#000000']);
493
+ });
494
+ });
495
+ describe('getMonochromaticHarmonyColors', () => {
496
+ it('returns monochromatic harmony colors', () => {
497
+ const start = new Color({ h: 210, s: 60, l: 50 });
498
+ const [base, lighter, darker, saturated, desaturated] = getMonochromaticHarmonyColors(start);
499
+ const [baseHsl, lighterHsl, darkerHsl, saturatedHsl, desaturatedHsl] = [
500
+ base.toHSL(),
501
+ lighter.toHSL(),
502
+ darker.toHSL(),
503
+ saturated.toHSL(),
504
+ desaturated.toHSL(),
505
+ ];
506
+ expect(baseHsl.h).toBeCloseTo(210, 0);
507
+ expect(baseHsl.s).toBeCloseTo(60, 0);
508
+ expect(baseHsl.l).toBeCloseTo(50, 0);
509
+ expect(lighterHsl.h).toBeCloseTo(210, 0);
510
+ expect(lighterHsl.s).toBeCloseTo(60, 0);
511
+ expect(lighterHsl.l).toBeCloseTo(70, 0);
512
+ expect(darkerHsl.h).toBeCloseTo(210, 0);
513
+ expect(darkerHsl.s).toBeCloseTo(60, 0);
514
+ expect(darkerHsl.l).toBeCloseTo(30, 0);
515
+ expect(saturatedHsl.h).toBeCloseTo(210, 0);
516
+ expect(saturatedHsl.s).toBeCloseTo(80, 0);
517
+ expect(saturatedHsl.l).toBeCloseTo(50, 0);
518
+ expect(desaturatedHsl.h).toBeCloseTo(210, 0);
519
+ expect(desaturatedHsl.s).toBeCloseTo(40, 0);
520
+ expect(desaturatedHsl.l).toBeCloseTo(50, 0);
521
+ });
522
+ it('clamps saturation and lightness', () => {
523
+ const [base, lighter, darker, saturated, desaturated] = getMonochromaticHarmonyColors(new Color({ h: 10, s: 5, l: 95 }));
524
+ const [baseHsl, lighterHsl, darkerHsl, saturatedHsl, desaturatedHsl] = [
525
+ base.toHSL(),
526
+ lighter.toHSL(),
527
+ darker.toHSL(),
528
+ saturated.toHSL(),
529
+ desaturated.toHSL(),
530
+ ];
531
+ expect(Math.min(baseHsl.h, 360 - baseHsl.h)).toBeLessThanOrEqual(10.1);
532
+ expect(baseHsl.s).toBeCloseTo(5, 0);
533
+ expect(baseHsl.l).toBeCloseTo(95, 0);
534
+ expect(lighterHsl.h).toBeCloseTo(0, 0);
535
+ expect(lighterHsl.s).toBeCloseTo(0, 0);
536
+ expect(lighterHsl.l).toBeCloseTo(100, 0);
537
+ expect(Math.min(darkerHsl.h, 360 - darkerHsl.h)).toBeLessThanOrEqual(10.1);
538
+ expect(darkerHsl.s).toBeCloseTo(5, 0);
539
+ expect(darkerHsl.l).toBeCloseTo(75, 0);
540
+ expect(Math.min(saturatedHsl.h, 360 - saturatedHsl.h)).toBeLessThanOrEqual(10.1);
541
+ expect(saturatedHsl.s).toBeCloseTo(25, 0);
542
+ expect(saturatedHsl.l).toBeCloseTo(95, 0);
543
+ expect(desaturatedHsl.h).toBeCloseTo(0, 0);
544
+ expect(desaturatedHsl.s).toBeCloseTo(0, 0);
545
+ expect(desaturatedHsl.l).toBeCloseTo(95, 0);
546
+ });
547
+ it('returns monochromatic harmony colors for diverse inputs', () => {
548
+ const [redOrig, red2, red3, red4, red5] = getMonochromaticHarmonyColors(new Color('#ff0000'));
549
+ expect(redOrig.toHex()).toBe('#ff0000');
550
+ expect(red2.toHex()).toBe('#ff6666');
551
+ expect(red3.toHex()).toBe('#990000');
552
+ expect(red4.toHex()).toBe('#ff0000');
553
+ expect(red5.toHex()).toBe('#e61919');
554
+ const [greenOrig, green2, green3, green4, green5] = getMonochromaticHarmonyColors(new Color('#00ff00'));
555
+ expect(greenOrig.toHex()).toBe('#00ff00');
556
+ expect(green2.toHex()).toBe('#66ff66');
557
+ expect(green3.toHex()).toBe('#009900');
558
+ expect(green4.toHex()).toBe('#00ff00');
559
+ expect(green5.toHex()).toBe('#19e619');
560
+ const [blueOrig, blue2, blue3, blue4, blue5] = getMonochromaticHarmonyColors(new Color('#0000ff'));
561
+ expect(blueOrig.toHex()).toBe('#0000ff');
562
+ expect(blue2.toHex()).toBe('#6666ff');
563
+ expect(blue3.toHex()).toBe('#000099');
564
+ expect(blue4.toHex()).toBe('#0000ff');
565
+ expect(blue5.toHex()).toBe('#1919e6');
566
+ const [purpleOrig, purple2, purple3, purple4, purple5] = getMonochromaticHarmonyColors(new Color('#ee6ffc'));
567
+ expect(purpleOrig.toHex()).toBe('#ee6ffc');
568
+ expect(purple2.toHex()).toBe('#fad3fe');
569
+ expect(purple3.toHex()).toBe('#e20bfa');
570
+ expect(purple4.toHex()).toBe('#f06cff');
571
+ expect(purple5.toHex()).toBe('#e27eed');
572
+ const [brandBlueOrig, brandBlue2, brandBlue3, brandBlue4, brandBlue5] = getMonochromaticHarmonyColors(new Color('#2e3575'));
573
+ expect(brandBlueOrig.toHex()).toBe('#2e3575');
574
+ expect(brandBlue2.toHex()).toBe('#4f5aba');
575
+ expect(brandBlue3.toHex()).toBe('#11142c');
576
+ expect(brandBlue4.toHex()).toBe('#1e2885');
577
+ expect(brandBlue5.toHex()).toBe('#3e4265');
578
+ const [yellowOrig, yellow2, yellow3, yellow4, yellow5] = getMonochromaticHarmonyColors(new Color('#d3e204'));
579
+ expect(yellowOrig.toHex()).toBe('#d3e204');
580
+ expect(yellow2.toHex()).toBe('#f0fc50');
581
+ expect(yellow3.toHex()).toBe('#757e02');
582
+ expect(yellow4.toHex()).toBe('#d6e600');
583
+ expect(yellow5.toHex()).toBe('#bfcb1b');
584
+ const [brandGreenOrig, brandGreen2, brandGreen3, brandGreen4, brandGreen5] = getMonochromaticHarmonyColors(new Color('#29cc53'));
585
+ expect(brandGreenOrig.toHex()).toBe('#29cc53');
586
+ expect(brandGreen2.toHex()).toBe('#77e493');
587
+ expect(brandGreen3.toHex()).toBe('#187730');
588
+ expect(brandGreen4.toHex()).toBe('#10e547');
589
+ expect(brandGreen5.toHex()).toBe('#42b45f');
590
+ const [pinkOrig, pink2, pink3, pink4, pink5] = getMonochromaticHarmonyColors(new Color('#811242'));
591
+ expect(pinkOrig.toHex()).toBe('#811242');
592
+ expect(pink2.toHex()).toBe('#db1e70');
593
+ expect(pink3.toHex()).toBe('#270614');
594
+ expect(pink4.toHex()).toBe('#900340');
595
+ expect(pink5.toHex()).toBe('#722144');
596
+ const [brandRedOrig, brandRed2, brandRed3, brandRed4, brandRed5] = getMonochromaticHarmonyColors(new Color('#de0d14'));
597
+ expect(brandRedOrig.toHex()).toBe('#de0d14');
598
+ expect(brandRed2.toHex()).toBe('#f55c61');
599
+ expect(brandRed3.toHex()).toBe('#7e070b');
600
+ expect(brandRed4.toHex()).toBe('#eb0008');
601
+ expect(brandRed5.toHex()).toBe('#c6252a');
602
+ const [blackOrig, black2, black3, black4, black5] = getMonochromaticHarmonyColors(new Color('#000000'));
603
+ expect(blackOrig.toHex()).toBe('#000000');
604
+ expect(black2.toHex()).toBe('#333333');
605
+ expect(black3.toHex()).toBe('#000000');
606
+ expect(black4.toHex()).toBe('#000000');
607
+ expect(black5.toHex()).toBe('#000000');
608
+ const [whiteOrig, white2, white3, white4, white5] = getMonochromaticHarmonyColors(new Color('#ffffff'));
609
+ expect(whiteOrig.toHex()).toBe('#ffffff');
610
+ expect(white2.toHex()).toBe('#ffffff');
611
+ expect(white3.toHex()).toBe('#cccccc');
612
+ expect(white4.toHex()).toBe('#ffffff');
613
+ expect(white5.toHex()).toBe('#ffffff');
614
+ const [lightGrayOrig, lightGray2, lightGray3, lightGray4, lightGray5] = getMonochromaticHarmonyColors(new Color('#d3d3d3'));
615
+ expect(lightGrayOrig.toHex()).toBe('#d3d3d3');
616
+ expect(lightGray2.toHex()).toBe('#ffffff');
617
+ expect(lightGray3.toHex()).toBe('#a0a0a0');
618
+ expect(lightGray4.toHex()).toBe('#dccaca');
619
+ expect(lightGray5.toHex()).toBe('#d3d3d3');
620
+ const [grayOrig, gray2, gray3, gray4, gray5] = getMonochromaticHarmonyColors(new Color('#808080'));
621
+ expect(grayOrig.toHex()).toBe('#808080');
622
+ expect(gray2.toHex()).toBe('#b3b3b3');
623
+ expect(gray3.toHex()).toBe('#4d4d4d');
624
+ expect(gray4.toHex()).toBe('#996767');
625
+ expect(gray5.toHex()).toBe('#808080');
626
+ const [darkGrayOrig, darkGray2, darkGray3, darkGray4, darkGray5] = getMonochromaticHarmonyColors(new Color('#333333'));
627
+ expect(darkGrayOrig.toHex()).toBe('#333333');
628
+ expect(darkGray2.toHex()).toBe('#666666');
629
+ expect(darkGray3.toHex()).toBe('#000000');
630
+ expect(darkGray4.toHex()).toBe('#3d2929');
631
+ expect(darkGray5.toHex()).toBe('#333333');
632
+ });
633
+ it('keeps alpha across monochromatic variants', () => {
634
+ const [base, lighter, darker, saturated, desaturated] = getMonochromaticHarmonyColors(new Color('rgba(20, 40, 60, 0.25)'));
635
+ expect(base.toRGBA().a).toBeCloseTo(0.25, 5);
636
+ expect(lighter.toRGBA().a).toBeCloseTo(0.25, 5);
637
+ expect(darker.toRGBA().a).toBeCloseTo(0.25, 5);
638
+ expect(saturated.toRGBA().a).toBeCloseTo(0.25, 5);
639
+ expect(desaturated.toRGBA().a).toBeCloseTo(0.25, 5);
640
+ });
641
+ });
642
+ describe('getHarmonyColors', () => {
643
+ it('delegates to individual harmony functions', () => {
644
+ expect(getHarmonyColors(new Color('#ff0000'), 'COMPLEMENTARY').map((c) => c.toHex())).toEqual([
645
+ '#ff0000',
646
+ '#00ffff',
647
+ ]);
648
+ expect(getHarmonyColors(new Color('#ff0000'), 'SPLIT_COMPLEMENTARY').map((c) => c.toHex())).toEqual(['#ff0000', '#0080ff', '#00ff80']);
649
+ expect(getHarmonyColors(new Color('#ff0000'), 'TRIADIC').map((c) => c.toHex())).toEqual([
650
+ '#ff0000',
651
+ '#0000ff',
652
+ '#00ff00',
653
+ ]);
654
+ expect(getHarmonyColors(new Color('#ff0000'), 'SQUARE').map((c) => c.toHex())).toEqual([
655
+ '#ff0000',
656
+ '#80ff00',
657
+ '#00ffff',
658
+ '#8000ff',
659
+ ]);
660
+ expect(getHarmonyColors(new Color('#ff0000'), 'TETRADIC').map((c) => c.toHex())).toEqual([
661
+ '#ff0000',
662
+ '#ffff00',
663
+ '#00ffff',
664
+ '#0000ff',
665
+ ]);
666
+ expect(getHarmonyColors(new Color('#ff0000'), 'ANALOGOUS').map((c) => c.toHex())).toEqual([
667
+ '#ff0000',
668
+ '#ff0080',
669
+ '#ff8000',
670
+ '#ff00ff',
671
+ '#ffff00',
672
+ ]);
673
+ expect(getHarmonyColors(new Color('#ff0000'), 'MONOCHROMATIC').map((c) => c.toHex())).toEqual([
674
+ '#ff0000',
675
+ '#ff6666',
676
+ '#990000',
677
+ '#ff0000',
678
+ '#e61919',
679
+ ]);
680
+ });
681
+ it('accepts mixed case harmony', () => {
682
+ const c = new Color('red');
683
+ const h1 = getHarmonyColors(c, 'TRIADIC');
684
+ const h2 = getHarmonyColors(c, 'triadic');
685
+ expect(h1.length).toBe(h2.length);
686
+ expect(h1[1].toHex()).toBe(h2[1].toHex());
687
+ });
688
+ it('delegates for brand purple as well', () => {
689
+ expect(getHarmonyColors(new Color('#ee6ffc'), 'COMPLEMENTARY').map((c) => c.toHex())).toEqual([
690
+ '#ee6ffc',
691
+ '#7dfc6f',
692
+ ]);
693
+ expect(getHarmonyColors(new Color('#ee6ffc'), 'SPLIT_COMPLEMENTARY').map((c) => c.toHex())).toEqual(['#ee6ffc', '#6ffca7', '#c4fc6f']);
694
+ expect(getHarmonyColors(new Color('#ee6ffc'), 'TRIADIC').map((c) => c.toHex())).toEqual([
695
+ '#ee6ffc',
696
+ '#6ffcee',
697
+ '#fcee6f',
698
+ ]);
699
+ expect(getHarmonyColors(new Color('#ee6ffc'), 'SQUARE').map((c) => c.toHex())).toEqual([
700
+ '#ee6ffc',
701
+ '#fca76f',
702
+ '#7dfc6f',
703
+ '#6fc4fc',
704
+ ]);
705
+ expect(getHarmonyColors(new Color('#ee6ffc'), 'TETRADIC').map((c) => c.toHex())).toEqual([
706
+ '#ee6ffc',
707
+ '#fc6f7d',
708
+ '#7dfc6f',
709
+ '#6ffcee',
710
+ ]);
711
+ expect(getHarmonyColors(new Color('#ee6ffc'), 'ANALOGOUS').map((c) => c.toHex())).toEqual([
712
+ '#ee6ffc',
713
+ '#a76ffc',
714
+ '#fc6fc4',
715
+ '#6f7dfc',
716
+ '#fc6f7d',
717
+ ]);
718
+ expect(getHarmonyColors(new Color('#ee6ffc'), 'MONOCHROMATIC').map((c) => c.toHex())).toEqual([
719
+ '#ee6ffc',
720
+ '#fad3fe',
721
+ '#e20bfa',
722
+ '#f06cff',
723
+ '#e27eed',
724
+ ]);
725
+ });
726
+ it('throws for unknown harmony type', () => {
727
+ expect(() => getHarmonyColors(new Color('#ff0000'), 'unknown')).toThrow("Invalid 'harmony'");
728
+ });
729
+ it('throws for invalid grayscale handling mode', () => {
730
+ expect(() => getComplementaryColors(new Color('#808080'), {
731
+ grayscaleHandlingMode: 'unknown',
732
+ })).toThrow("Invalid 'grayscaleHandlingMode'");
733
+ });
734
+ });