@hanzogui/themes 2.0.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 (324) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/componentThemeDefinitions.cjs +124 -0
  3. package/dist/cjs/componentThemeDefinitions.native.js +127 -0
  4. package/dist/cjs/componentThemeDefinitions.native.js.map +1 -0
  5. package/dist/cjs/generated-new.cjs +2021 -0
  6. package/dist/cjs/generated-new.native.js +2040 -0
  7. package/dist/cjs/generated-new.native.js.map +1 -0
  8. package/dist/cjs/generated-v3.cjs +1099 -0
  9. package/dist/cjs/generated-v3.native.js +1118 -0
  10. package/dist/cjs/generated-v3.native.js.map +1 -0
  11. package/dist/cjs/generated-v4-gui.cjs +933 -0
  12. package/dist/cjs/generated-v4-gui.native.js +952 -0
  13. package/dist/cjs/generated-v4-gui.native.js.map +1 -0
  14. package/dist/cjs/generated-v4.cjs +391 -0
  15. package/dist/cjs/generated-v4.native.js +410 -0
  16. package/dist/cjs/generated-v4.native.js.map +1 -0
  17. package/dist/cjs/generated-v5-subtle.cjs +549 -0
  18. package/dist/cjs/generated-v5-subtle.native.js +568 -0
  19. package/dist/cjs/generated-v5-subtle.native.js.map +1 -0
  20. package/dist/cjs/generated-v5.cjs +549 -0
  21. package/dist/cjs/generated-v5.native.js +568 -0
  22. package/dist/cjs/generated-v5.native.js.map +1 -0
  23. package/dist/cjs/helpers.cjs +34 -0
  24. package/dist/cjs/helpers.native.js +39 -0
  25. package/dist/cjs/helpers.native.js.map +1 -0
  26. package/dist/cjs/index.cjs +25 -0
  27. package/dist/cjs/index.native.js +28 -0
  28. package/dist/cjs/index.native.js.map +1 -0
  29. package/dist/cjs/opacify.cjs +96 -0
  30. package/dist/cjs/opacify.native.js +106 -0
  31. package/dist/cjs/opacify.native.js.map +1 -0
  32. package/dist/cjs/palettes.cjs +52 -0
  33. package/dist/cjs/palettes.native.js +63 -0
  34. package/dist/cjs/palettes.native.js.map +1 -0
  35. package/dist/cjs/shadows.cjs +43 -0
  36. package/dist/cjs/shadows.native.js +46 -0
  37. package/dist/cjs/shadows.native.js.map +1 -0
  38. package/dist/cjs/subtleChildrenThemes.cjs +65 -0
  39. package/dist/cjs/subtleChildrenThemes.native.js +74 -0
  40. package/dist/cjs/subtleChildrenThemes.native.js.map +1 -0
  41. package/dist/cjs/templates.cjs +118 -0
  42. package/dist/cjs/templates.native.js +121 -0
  43. package/dist/cjs/templates.native.js.map +1 -0
  44. package/dist/cjs/themes-new.cjs +86 -0
  45. package/dist/cjs/themes-new.native.js +88 -0
  46. package/dist/cjs/themes-new.native.js.map +1 -0
  47. package/dist/cjs/themes-old.cjs +284 -0
  48. package/dist/cjs/themes-old.native.js +303 -0
  49. package/dist/cjs/themes-old.native.js.map +1 -0
  50. package/dist/cjs/themes.cjs +26 -0
  51. package/dist/cjs/themes.native.js +29 -0
  52. package/dist/cjs/themes.native.js.map +1 -0
  53. package/dist/cjs/tokens.cjs +155 -0
  54. package/dist/cjs/tokens.native.js +167 -0
  55. package/dist/cjs/tokens.native.js.map +1 -0
  56. package/dist/cjs/utils.cjs +40 -0
  57. package/dist/cjs/utils.native.js +46 -0
  58. package/dist/cjs/utils.native.js.map +1 -0
  59. package/dist/cjs/v3-themes.cjs +472 -0
  60. package/dist/cjs/v3-themes.native.js +487 -0
  61. package/dist/cjs/v3-themes.native.js.map +1 -0
  62. package/dist/cjs/v3-tokens.cjs +99 -0
  63. package/dist/cjs/v3-tokens.native.js +108 -0
  64. package/dist/cjs/v3-tokens.native.js.map +1 -0
  65. package/dist/cjs/v3.cjs +52 -0
  66. package/dist/cjs/v3.native.js +55 -0
  67. package/dist/cjs/v3.native.js.map +1 -0
  68. package/dist/cjs/v4-default.cjs +167 -0
  69. package/dist/cjs/v4-default.native.js +170 -0
  70. package/dist/cjs/v4-default.native.js.map +1 -0
  71. package/dist/cjs/v4-gui.cjs +235 -0
  72. package/dist/cjs/v4-gui.native.js +243 -0
  73. package/dist/cjs/v4-gui.native.js.map +1 -0
  74. package/dist/cjs/v4-tokens.cjs +99 -0
  75. package/dist/cjs/v4-tokens.native.js +108 -0
  76. package/dist/cjs/v4-tokens.native.js.map +1 -0
  77. package/dist/cjs/v4.cjs +32 -0
  78. package/dist/cjs/v4.native.js +35 -0
  79. package/dist/cjs/v4.native.js.map +1 -0
  80. package/dist/cjs/v5-subtle.cjs +34 -0
  81. package/dist/cjs/v5-subtle.native.js +37 -0
  82. package/dist/cjs/v5-subtle.native.js.map +1 -0
  83. package/dist/cjs/v5-templates.cjs +110 -0
  84. package/dist/cjs/v5-templates.native.js +126 -0
  85. package/dist/cjs/v5-templates.native.js.map +1 -0
  86. package/dist/cjs/v5-themes-subtle.cjs +37 -0
  87. package/dist/cjs/v5-themes-subtle.native.js +40 -0
  88. package/dist/cjs/v5-themes-subtle.native.js.map +1 -0
  89. package/dist/cjs/v5-themes.cjs +400 -0
  90. package/dist/cjs/v5-themes.native.js +445 -0
  91. package/dist/cjs/v5-themes.native.js.map +1 -0
  92. package/dist/cjs/v5-tokens.cjs +99 -0
  93. package/dist/cjs/v5-tokens.native.js +108 -0
  94. package/dist/cjs/v5-tokens.native.js.map +1 -0
  95. package/dist/cjs/v5.cjs +34 -0
  96. package/dist/cjs/v5.native.js +37 -0
  97. package/dist/cjs/v5.native.js.map +1 -0
  98. package/dist/esm/componentThemeDefinitions.mjs +100 -0
  99. package/dist/esm/componentThemeDefinitions.mjs.map +1 -0
  100. package/dist/esm/componentThemeDefinitions.native.js +100 -0
  101. package/dist/esm/componentThemeDefinitions.native.js.map +1 -0
  102. package/dist/esm/generated-new.mjs +1997 -0
  103. package/dist/esm/generated-new.mjs.map +1 -0
  104. package/dist/esm/generated-new.native.js +2013 -0
  105. package/dist/esm/generated-new.native.js.map +1 -0
  106. package/dist/esm/generated-v3.mjs +1075 -0
  107. package/dist/esm/generated-v3.mjs.map +1 -0
  108. package/dist/esm/generated-v3.native.js +1091 -0
  109. package/dist/esm/generated-v3.native.js.map +1 -0
  110. package/dist/esm/generated-v4-gui.mjs +909 -0
  111. package/dist/esm/generated-v4-gui.mjs.map +1 -0
  112. package/dist/esm/generated-v4-gui.native.js +925 -0
  113. package/dist/esm/generated-v4-gui.native.js.map +1 -0
  114. package/dist/esm/generated-v4.mjs +367 -0
  115. package/dist/esm/generated-v4.mjs.map +1 -0
  116. package/dist/esm/generated-v4.native.js +383 -0
  117. package/dist/esm/generated-v4.native.js.map +1 -0
  118. package/dist/esm/generated-v5-subtle.mjs +525 -0
  119. package/dist/esm/generated-v5-subtle.mjs.map +1 -0
  120. package/dist/esm/generated-v5-subtle.native.js +541 -0
  121. package/dist/esm/generated-v5-subtle.native.js.map +1 -0
  122. package/dist/esm/generated-v5.mjs +525 -0
  123. package/dist/esm/generated-v5.mjs.map +1 -0
  124. package/dist/esm/generated-v5.native.js +541 -0
  125. package/dist/esm/generated-v5.native.js.map +1 -0
  126. package/dist/esm/helpers.mjs +9 -0
  127. package/dist/esm/helpers.mjs.map +1 -0
  128. package/dist/esm/helpers.native.js +11 -0
  129. package/dist/esm/helpers.native.js.map +1 -0
  130. package/dist/esm/index.js +9 -0
  131. package/dist/esm/index.js.map +1 -0
  132. package/dist/esm/index.mjs +9 -0
  133. package/dist/esm/index.mjs.map +1 -0
  134. package/dist/esm/index.native.js +9 -0
  135. package/dist/esm/index.native.js.map +1 -0
  136. package/dist/esm/opacify.mjs +72 -0
  137. package/dist/esm/opacify.mjs.map +1 -0
  138. package/dist/esm/opacify.native.js +79 -0
  139. package/dist/esm/opacify.native.js.map +1 -0
  140. package/dist/esm/palettes.mjs +29 -0
  141. package/dist/esm/palettes.mjs.map +1 -0
  142. package/dist/esm/palettes.native.js +37 -0
  143. package/dist/esm/palettes.native.js.map +1 -0
  144. package/dist/esm/shadows.mjs +20 -0
  145. package/dist/esm/shadows.mjs.map +1 -0
  146. package/dist/esm/shadows.native.js +20 -0
  147. package/dist/esm/shadows.native.js.map +1 -0
  148. package/dist/esm/subtleChildrenThemes.mjs +41 -0
  149. package/dist/esm/subtleChildrenThemes.mjs.map +1 -0
  150. package/dist/esm/subtleChildrenThemes.native.js +47 -0
  151. package/dist/esm/subtleChildrenThemes.native.js.map +1 -0
  152. package/dist/esm/templates.mjs +94 -0
  153. package/dist/esm/templates.mjs.map +1 -0
  154. package/dist/esm/templates.native.js +94 -0
  155. package/dist/esm/templates.native.js.map +1 -0
  156. package/dist/esm/themes-new.mjs +63 -0
  157. package/dist/esm/themes-new.mjs.map +1 -0
  158. package/dist/esm/themes-new.native.js +62 -0
  159. package/dist/esm/themes-new.native.js.map +1 -0
  160. package/dist/esm/themes-old.mjs +261 -0
  161. package/dist/esm/themes-old.mjs.map +1 -0
  162. package/dist/esm/themes-old.native.js +277 -0
  163. package/dist/esm/themes-old.native.js.map +1 -0
  164. package/dist/esm/themes.mjs +3 -0
  165. package/dist/esm/themes.mjs.map +1 -0
  166. package/dist/esm/themes.native.js +3 -0
  167. package/dist/esm/themes.native.js.map +1 -0
  168. package/dist/esm/tokens.mjs +124 -0
  169. package/dist/esm/tokens.mjs.map +1 -0
  170. package/dist/esm/tokens.native.js +133 -0
  171. package/dist/esm/tokens.native.js.map +1 -0
  172. package/dist/esm/utils.mjs +14 -0
  173. package/dist/esm/utils.mjs.map +1 -0
  174. package/dist/esm/utils.native.js +17 -0
  175. package/dist/esm/utils.native.js.map +1 -0
  176. package/dist/esm/v3-themes.mjs +444 -0
  177. package/dist/esm/v3-themes.mjs.map +1 -0
  178. package/dist/esm/v3-themes.native.js +456 -0
  179. package/dist/esm/v3-themes.native.js.map +1 -0
  180. package/dist/esm/v3-tokens.mjs +70 -0
  181. package/dist/esm/v3-tokens.mjs.map +1 -0
  182. package/dist/esm/v3-tokens.native.js +76 -0
  183. package/dist/esm/v3-tokens.native.js.map +1 -0
  184. package/dist/esm/v3.mjs +12 -0
  185. package/dist/esm/v3.mjs.map +1 -0
  186. package/dist/esm/v3.native.js +12 -0
  187. package/dist/esm/v3.native.js.map +1 -0
  188. package/dist/esm/v4-default.mjs +133 -0
  189. package/dist/esm/v4-default.mjs.map +1 -0
  190. package/dist/esm/v4-default.native.js +133 -0
  191. package/dist/esm/v4-default.native.js.map +1 -0
  192. package/dist/esm/v4-gui.mjs +201 -0
  193. package/dist/esm/v4-gui.mjs.map +1 -0
  194. package/dist/esm/v4-gui.native.js +206 -0
  195. package/dist/esm/v4-gui.native.js.map +1 -0
  196. package/dist/esm/v4-tokens.mjs +70 -0
  197. package/dist/esm/v4-tokens.mjs.map +1 -0
  198. package/dist/esm/v4-tokens.native.js +76 -0
  199. package/dist/esm/v4-tokens.native.js.map +1 -0
  200. package/dist/esm/v4.mjs +6 -0
  201. package/dist/esm/v4.mjs.map +1 -0
  202. package/dist/esm/v4.native.js +6 -0
  203. package/dist/esm/v4.native.js.map +1 -0
  204. package/dist/esm/v5-subtle.mjs +7 -0
  205. package/dist/esm/v5-subtle.mjs.map +1 -0
  206. package/dist/esm/v5-subtle.native.js +7 -0
  207. package/dist/esm/v5-subtle.native.js.map +1 -0
  208. package/dist/esm/v5-templates.mjs +87 -0
  209. package/dist/esm/v5-templates.mjs.map +1 -0
  210. package/dist/esm/v5-templates.native.js +100 -0
  211. package/dist/esm/v5-templates.native.js.map +1 -0
  212. package/dist/esm/v5-themes-subtle.mjs +13 -0
  213. package/dist/esm/v5-themes-subtle.mjs.map +1 -0
  214. package/dist/esm/v5-themes-subtle.native.js +13 -0
  215. package/dist/esm/v5-themes-subtle.native.js.map +1 -0
  216. package/dist/esm/v5-themes.mjs +361 -0
  217. package/dist/esm/v5-themes.mjs.map +1 -0
  218. package/dist/esm/v5-themes.native.js +403 -0
  219. package/dist/esm/v5-themes.native.js.map +1 -0
  220. package/dist/esm/v5-tokens.mjs +70 -0
  221. package/dist/esm/v5-tokens.mjs.map +1 -0
  222. package/dist/esm/v5-tokens.native.js +76 -0
  223. package/dist/esm/v5-tokens.native.js.map +1 -0
  224. package/dist/esm/v5.mjs +7 -0
  225. package/dist/esm/v5.mjs.map +1 -0
  226. package/dist/esm/v5.native.js +7 -0
  227. package/dist/esm/v5.native.js.map +1 -0
  228. package/package.json +95 -0
  229. package/src/componentThemeDefinitions.tsx +129 -0
  230. package/src/generated-new.ts +2571 -0
  231. package/src/generated-v3.ts +1826 -0
  232. package/src/generated-v4-gui.ts +2200 -0
  233. package/src/generated-v4.ts +1004 -0
  234. package/src/generated-v5-subtle.ts +2170 -0
  235. package/src/generated-v5.ts +2188 -0
  236. package/src/helpers.ts +44 -0
  237. package/src/index.tsx +8 -0
  238. package/src/opacify.ts +125 -0
  239. package/src/palettes.tsx +91 -0
  240. package/src/shadows.tsx +19 -0
  241. package/src/subtleChildrenThemes.ts +54 -0
  242. package/src/templates.tsx +104 -0
  243. package/src/themes-new.ts +74 -0
  244. package/src/themes-old.tsx +378 -0
  245. package/src/themes.tsx +1 -0
  246. package/src/tokens.tsx +199 -0
  247. package/src/utils.ts +51 -0
  248. package/src/v3-themes.ts +650 -0
  249. package/src/v3-tokens.ts +103 -0
  250. package/src/v3.tsx +12 -0
  251. package/src/v4-default.ts +191 -0
  252. package/src/v4-gui.ts +287 -0
  253. package/src/v4-tokens.ts +105 -0
  254. package/src/v4.tsx +4 -0
  255. package/src/v5-subtle.tsx +11 -0
  256. package/src/v5-templates.ts +126 -0
  257. package/src/v5-themes-subtle.ts +18 -0
  258. package/src/v5-themes.ts +626 -0
  259. package/src/v5-tokens.ts +107 -0
  260. package/src/v5.tsx +11 -0
  261. package/tests/v5-themes.test.ts +215 -0
  262. package/tsconfig.json +43 -0
  263. package/types/componentThemeDefinitions.d.ts +771 -0
  264. package/types/generated-new.d.ts +135 -0
  265. package/types/generated-v3.d.ts +144 -0
  266. package/types/generated-v4-gui.d.ts +190 -0
  267. package/types/generated-v4.d.ts +137 -0
  268. package/types/generated-v5-subtle.d.ts +244 -0
  269. package/types/generated-v5.d.ts +244 -0
  270. package/types/helpers.d.ts +24 -0
  271. package/types/index.d.ts +9 -0
  272. package/types/opacify.d.ts +9 -0
  273. package/types/palettes.d.ts +21 -0
  274. package/types/shadows.d.ts +15 -0
  275. package/types/subtleChildrenThemes.d.ts +305 -0
  276. package/types/templates.d.ts +155 -0
  277. package/types/themes-new.d.ts +42243 -0
  278. package/types/themes-old.d.ts +51411 -0
  279. package/types/themes.d.ts +2 -0
  280. package/types/tokens.d.ts +1308 -0
  281. package/types/utils.d.ts +21 -0
  282. package/types/v3-themes.d.ts +16304 -0
  283. package/types/v3-tokens.d.ts +184 -0
  284. package/types/v3.d.ts +11 -0
  285. package/types/v4-default.d.ts +274 -0
  286. package/types/v4-gui.d.ts +195 -0
  287. package/types/v4-tokens.d.ts +184 -0
  288. package/types/v4.d.ts +5 -0
  289. package/types/v5-subtle.d.ts +8 -0
  290. package/types/v5-templates.d.ts +42 -0
  291. package/types/v5-themes-subtle.d.ts +250 -0
  292. package/types/v5-themes.d.ts +752 -0
  293. package/types/v5-tokens.d.ts +185 -0
  294. package/types/v5.d.ts +8 -0
  295. package/v3/index.cjs +2 -0
  296. package/v3/index.js +2 -0
  297. package/v3/index.native.cjs +2 -0
  298. package/v3/index.native.js +2 -0
  299. package/v3-themes/index.cjs +2 -0
  300. package/v3-themes/index.js +2 -0
  301. package/v3-themes/index.native.cjs +2 -0
  302. package/v3-themes/index.native.js +2 -0
  303. package/v3-themes.cjs +1 -0
  304. package/v3-themes.d.ts +1 -0
  305. package/v3.cjs +1 -0
  306. package/v3.d.ts +1 -0
  307. package/v4/index.cjs +2 -0
  308. package/v4/index.js +2 -0
  309. package/v4/index.native.cjs +2 -0
  310. package/v4/index.native.js +2 -0
  311. package/v4.cjs +1 -0
  312. package/v4.d.ts +1 -0
  313. package/v5/index.cjs +2 -0
  314. package/v5/index.js +2 -0
  315. package/v5/index.native.cjs +2 -0
  316. package/v5/index.native.js +2 -0
  317. package/v5-subtle/index.cjs +2 -0
  318. package/v5-subtle/index.js +2 -0
  319. package/v5-subtle/index.native.cjs +2 -0
  320. package/v5-subtle/index.native.js +2 -0
  321. package/v5-subtle.cjs +1 -0
  322. package/v5-subtle.d.ts +1 -0
  323. package/v5.cjs +1 -0
  324. package/v5.d.ts +1 -0
@@ -0,0 +1,626 @@
1
+ import {
2
+ blue,
3
+ blueDark,
4
+ gray,
5
+ grayDark,
6
+ green,
7
+ greenDark,
8
+ orange,
9
+ orangeDark,
10
+ pink,
11
+ pinkDark,
12
+ purple,
13
+ purpleDark,
14
+ red,
15
+ redDark,
16
+ teal,
17
+ tealDark,
18
+ yellow,
19
+ yellowDark,
20
+ } from '@hanzogui/colors'
21
+ import { createThemes, type CreateThemesProps } from '@hanzogui/theme-builder'
22
+ import { opacify } from './opacify'
23
+ import { v5Templates } from './v5-templates'
24
+
25
+ // base theme uses elevated background (like old surface1)
26
+ // this offset aligns getTheme's palette index with that elevation
27
+ export const V5_BG_OFFSET = 6 + 1
28
+
29
+ // re-export color utilities for users
30
+ export { interpolateColor, opacify } from './opacify'
31
+
32
+ export const v5ComponentThemes = {
33
+ Button: { template: 'surface2' },
34
+ Input: { template: 'surface1' },
35
+ Progress: { template: 'surface1' },
36
+ ProgressIndicator: { template: 'surface3' },
37
+ Slider: { template: 'surface1' },
38
+ SliderActive: { template: 'surface3' },
39
+ SliderThumb: { template: 'surface2' },
40
+ Switch: { template: 'surface2' },
41
+ TextArea: { template: 'surface1' },
42
+ Tooltip: { template: 'accent' },
43
+ SwitchThumb: { template: 'accent' },
44
+ } as const
45
+
46
+ // inverses are confusing af
47
+ export const v5ComponentThemesWithInverses = {
48
+ ...v5ComponentThemes,
49
+ ProgressIndicator: { template: 'accent' },
50
+ SliderThumb: { template: 'accent' },
51
+ Tooltip: { template: 'accent' },
52
+ } as const
53
+
54
+ /** Default grandchildren themes available in v5 */
55
+ export const v5GrandchildrenThemes = {
56
+ accent: { template: 'accent' },
57
+ surface1: { template: 'surface1' },
58
+ surface2: { template: 'surface2' },
59
+ } satisfies Record<string, GrandChildrenThemeDefinition>
60
+
61
+ // ---- adjustPalette: generic HSL color adjustment ----
62
+
63
+ export type HSL = { h: number; s: number; l: number }
64
+
65
+ /** callback receives hsl and 1-based index, returns adjusted hsl */
66
+ export type AdjustFn = (hsl: HSL, index: number) => HSL
67
+
68
+ /** parse hsl string to HSL object */
69
+ export function parseHSL(str: string): HSL | null {
70
+ const m = str.match(/hsl\((\d+(?:\.\d+)?),\s*(\d+(?:\.\d+)?)%,\s*(\d+(?:\.\d+)?)%\)/)
71
+ return m ? { h: +m[1]!, s: +m[2]!, l: +m[3]! } : null
72
+ }
73
+
74
+ /** parse hex color to HSL object */
75
+ export function parseHex(str: string): HSL | null {
76
+ if (!str.startsWith('#')) return null
77
+ let hex = str.slice(1)
78
+ if (hex.length === 3) {
79
+ hex = hex
80
+ .split('')
81
+ .map((c) => c + c)
82
+ .join('')
83
+ }
84
+ if (hex.length !== 6) return null
85
+
86
+ const r = Number.parseInt(hex.slice(0, 2), 16) / 255
87
+ const g = Number.parseInt(hex.slice(2, 4), 16) / 255
88
+ const b = Number.parseInt(hex.slice(4, 6), 16) / 255
89
+
90
+ const max = Math.max(r, g, b)
91
+ const min = Math.min(r, g, b)
92
+ const l = (max + min) / 2
93
+
94
+ if (max === min) {
95
+ return { h: 0, s: 0, l: l * 100 }
96
+ }
97
+
98
+ const d = max - min
99
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
100
+
101
+ let h = 0
102
+ if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6
103
+ else if (max === g) h = ((b - r) / d + 2) / 6
104
+ else h = ((r - g) / d + 4) / 6
105
+
106
+ return { h: Math.round(h * 360), s: s * 100, l: l * 100 }
107
+ }
108
+
109
+ /** parse any color format to HSL */
110
+ export function parseColor(str: string): HSL | null {
111
+ return parseHSL(str) ?? parseHex(str)
112
+ }
113
+
114
+ export function hslToString(hsl: HSL): string {
115
+ return `hsl(${hsl.h}, ${Math.round(Math.min(100, Math.max(0, hsl.s)))}%, ${Math.round(Math.min(100, Math.max(0, hsl.l)))}%)`
116
+ }
117
+
118
+ /** adjust a palette of colors (hsl or hex) using a callback */
119
+ export function adjustPalette(
120
+ palette: Record<string, string>,
121
+ fn: AdjustFn
122
+ ): Record<string, string> {
123
+ const out: Record<string, string> = {}
124
+ const keys = Object.keys(palette)
125
+
126
+ for (let i = 0; i < keys.length; i++) {
127
+ const key = keys[i]!
128
+ const parsed = parseColor(palette[key]!)
129
+ if (!parsed) {
130
+ out[key] = palette[key]!
131
+ continue
132
+ }
133
+ out[key] = hslToString(fn(parsed, i + 1))
134
+ }
135
+ return out
136
+ }
137
+
138
+ type SingleAdjustment = {
139
+ light?: AdjustFn
140
+ dark?: AdjustFn
141
+ }
142
+
143
+ export type PaletteAdjustments<T extends Record<string, any>> = {
144
+ [K in keyof T]?: SingleAdjustment
145
+ } & {
146
+ /** fallback for themes not explicitly listed */
147
+ default?: SingleAdjustment
148
+ }
149
+
150
+ const identity: AdjustFn = (hsl) => hsl
151
+
152
+ /**
153
+ * Adjust color palettes using callback functions.
154
+ *
155
+ * @example
156
+ * const adjusted = adjustPalettes(defaultChildrenThemes, {
157
+ * default: {
158
+ * light: (hsl, i) => ({ ...hsl, s: hsl.s * 0.8 }),
159
+ * dark: (hsl, i) => ({ ...hsl, s: hsl.s * 0.5, l: hsl.l * 0.9 }),
160
+ * },
161
+ * yellow: {
162
+ * light: (hsl, i) => ({ ...hsl, s: hsl.s * 0.5 }),
163
+ * },
164
+ * })
165
+ */
166
+ export function adjustPalettes<
167
+ T extends Record<
168
+ string,
169
+ { light: Record<string, string>; dark: Record<string, string> }
170
+ >,
171
+ >(themes: T, adjustments: PaletteAdjustments<T>): T {
172
+ const result = {} as T
173
+
174
+ for (const [name, theme] of Object.entries(themes)) {
175
+ const adj = adjustments[name as keyof T] ?? adjustments.default
176
+ if (!adj) {
177
+ ;(result as any)[name] = theme
178
+ continue
179
+ }
180
+ ;(result as any)[name] = {
181
+ light: adjustPalette(theme.light, adj.light ?? identity),
182
+ dark: adjustPalette(theme.dark, adj.dark ?? identity),
183
+ }
184
+ }
185
+
186
+ return result
187
+ }
188
+
189
+ // component themes removed in v5 - use defaultProps in your config instead
190
+ // see: https://gui.hanzo.ai/docs/core/config-v5#migrating-from-component-themes
191
+
192
+ /** Generate named colors from a palette: ['#fff', ...] -> { name1: '#fff', name2: ... } */
193
+ function paletteToNamedColors<N extends string>(name: N, palette: readonly string[]) {
194
+ return Object.fromEntries(palette.map((color, i) => [`${name}${i + 1}`, color])) as {
195
+ [K in `${N}${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12}`]: string
196
+ }
197
+ }
198
+
199
+ // Base palettes
200
+ const darkPalette = [
201
+ '#090909',
202
+ '#151515',
203
+ '#191919',
204
+ '#232323',
205
+ '#333',
206
+ '#444',
207
+ '#666',
208
+ '#777',
209
+ '#858585',
210
+ '#aaa',
211
+ '#ccc',
212
+ '#ffffff',
213
+ ]
214
+
215
+ const lightPalette = [
216
+ '#fff',
217
+ '#f8f8f8',
218
+ 'hsl(0, 0%, 93%)',
219
+ 'hsl(0, 0%, 85%)',
220
+ 'hsl(0, 0%, 80%)',
221
+ 'hsl(0, 0%, 70%)',
222
+ 'hsl(0, 0%, 59%)',
223
+ 'hsl(0, 0%, 45%)',
224
+ 'hsl(0, 0%, 30%)',
225
+ 'hsl(0, 0%, 20%)',
226
+ 'hsl(0, 0%, 14%)',
227
+ 'hsl(0, 0%, 2%)',
228
+ ]
229
+
230
+ /** Neutral grey - sufficient contrast on both white and black backgrounds */
231
+ const neutralPalette = [
232
+ 'hsl(0, 0%, 68%)',
233
+ 'hsl(0, 0%, 65%)',
234
+ 'hsl(0, 0%, 62%)',
235
+ 'hsl(0, 0%, 59%)',
236
+ 'hsl(0, 0%, 56%)',
237
+ 'hsl(0, 0%, 53%)',
238
+ 'hsl(0, 0%, 50%)',
239
+ 'hsl(0, 0%, 47%)',
240
+ 'hsl(0, 0%, 44%)',
241
+ 'hsl(0, 0%, 41%)',
242
+ 'hsl(0, 0%, 38%)',
243
+ 'hsl(0, 0%, 32%)',
244
+ ]
245
+
246
+ // Generate neutral colors from palette (used in defaultChildrenThemes)
247
+ const neutral = paletteToNamedColors('neutral', neutralPalette)
248
+
249
+ // Constants for forcing white/black with opacity variants
250
+ const whiteBlack = {
251
+ white: 'rgba(255,255,255,1)',
252
+ white0: 'rgba(255,255,255,0)',
253
+ white02: 'rgba(255,255,255,0.2)',
254
+ white04: 'rgba(255,255,255,0.4)',
255
+ white06: 'rgba(255,255,255,0.6)',
256
+ white08: 'rgba(255,255,255,0.8)',
257
+ black: 'rgba(0,0,0,1)',
258
+ black0: 'rgba(0,0,0,0)',
259
+ black02: 'rgba(0,0,0,0.2)',
260
+ black04: 'rgba(0,0,0,0.4)',
261
+ black06: 'rgba(0,0,0,0.6)',
262
+ black08: 'rgba(0,0,0,0.8)',
263
+ }
264
+
265
+ const darkShadows = {
266
+ shadow1: 'rgba(0,0,0,0.15)',
267
+ shadow2: 'rgba(0,0,0,0.23)',
268
+ shadow3: 'rgba(0,0,0,0.33)',
269
+ shadow4: 'rgba(0,0,0,0.45)',
270
+ shadow5: 'rgba(0,0,0,0.65)',
271
+ shadow6: 'rgba(0,0,0,0.8)',
272
+ shadow7: 'rgba(0,0,0,0.9)',
273
+ shadow8: 'rgba(0,0,0,1)',
274
+ }
275
+
276
+ const lightShadows = {
277
+ shadow1: 'rgba(0,0,0,0.04)',
278
+ shadow2: 'rgba(0,0,0,0.08)',
279
+ shadow3: 'rgba(0,0,0,0.12)',
280
+ shadow4: 'rgba(0,0,0,0.22)',
281
+ shadow5: 'rgba(0,0,0,0.33)',
282
+ shadow6: 'rgba(0,0,0,0.44)',
283
+ shadow7: 'rgba(0,0,0,0.6)',
284
+ shadow8: 'rgba(0,0,0,0.75)',
285
+ }
286
+
287
+ const darkHighlights = {
288
+ highlight1: 'rgba(255,255,255,0.1)',
289
+ highlight2: 'rgba(255,255,255,0.2)',
290
+ highlight3: 'rgba(255,255,255,0.3)',
291
+ highlight4: 'rgba(255,255,255,0.45)',
292
+ highlight5: 'rgba(255,255,255,0.65)',
293
+ highlight6: 'rgba(255,255,255,0.85)',
294
+ highlight7: 'rgba(255,255,255,0.95)',
295
+ highlight8: 'rgba(255,255,255,1)',
296
+ }
297
+
298
+ const lightHighlights = {
299
+ highlight1: 'rgba(255,255,255,0.05)',
300
+ highlight2: 'rgba(255,255,255,0.1)',
301
+ highlight3: 'rgba(255,255,255,0.15)',
302
+ highlight4: 'rgba(255,255,255,0.3)',
303
+ highlight5: 'rgba(255,255,255,0.4)',
304
+ highlight6: 'rgba(255,255,255,0.55)',
305
+ highlight7: 'rgba(255,255,255,0.7)',
306
+ highlight8: 'rgba(255,255,255,0.85)',
307
+ }
308
+
309
+ // Export palettes for customization
310
+ export { darkPalette as defaultDarkPalette, lightPalette as defaultLightPalette }
311
+
312
+ // Internal types
313
+ type NamedColors = Record<string, string>
314
+ type ChildTheme<T extends NamedColors = NamedColors> = { light: T; dark: T }
315
+ type GrandChildrenThemeDefinition = { template: string }
316
+
317
+ /** Default children themes - accepts radix colors directly */
318
+ export const defaultChildrenThemes = {
319
+ gray: { light: gray, dark: grayDark },
320
+ blue: { light: blue, dark: blueDark },
321
+ red: { light: red, dark: redDark },
322
+ yellow: { light: yellow, dark: yellowDark },
323
+ green: { light: green, dark: greenDark },
324
+ orange: { light: orange, dark: orangeDark },
325
+ pink: { light: pink, dark: pinkDark },
326
+ purple: { light: purple, dark: purpleDark },
327
+ teal: { light: teal, dark: tealDark },
328
+ neutral: { light: neutral, dark: neutral },
329
+ }
330
+
331
+ /** Union of all color values from children themes (for light or dark) */
332
+ type ChildrenColors<
333
+ T extends Record<string, ChildTheme>,
334
+ Mode extends 'light' | 'dark',
335
+ > = {
336
+ [K in keyof T]: T[K][Mode]
337
+ }[keyof T]
338
+
339
+ /** Merge all color objects from children into one type */
340
+ type MergedChildrenColors<
341
+ T extends Record<string, ChildTheme>,
342
+ Mode extends 'light' | 'dark',
343
+ > = UnionToIntersection<ChildrenColors<T, Mode>>
344
+
345
+ // Helper to convert union to intersection
346
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
347
+ k: infer I
348
+ ) => void
349
+ ? I
350
+ : never
351
+
352
+ // Named color types for black/white (generated from palettes in createV5Theme)
353
+ type BlackColors = ReturnType<typeof paletteToNamedColors<'black'>>
354
+ type WhiteColors = ReturnType<typeof paletteToNamedColors<'white'>>
355
+
356
+ // Base extra colors type (always included) - getTheme computes opacity/interpolation colors
357
+ type BaseExtraCommon = BlackColors & WhiteColors & typeof whiteBlack
358
+ type BaseExtraLight = BaseExtraCommon &
359
+ typeof lightShadows &
360
+ typeof lightHighlights & { shadowColor: string }
361
+ type BaseExtraDark = BaseExtraCommon &
362
+ typeof darkShadows &
363
+ typeof darkHighlights & { shadowColor: string }
364
+
365
+ type PaletteEntry = { palette: { light: string[]; dark: string[] } }
366
+ type ChildrenWithPalettes<Children extends Record<string, ChildTheme>> = {
367
+ [K in keyof Children | 'black' | 'white']: PaletteEntry
368
+ }
369
+ type V5ExtraByScheme<Children extends Record<string, ChildTheme>> = {
370
+ light: BaseExtraLight & MergedChildrenColors<Children, 'light'>
371
+ dark: BaseExtraDark & MergedChildrenColors<Children, 'dark'>
372
+ }
373
+ type V5GetThemeProps = Parameters<
374
+ NonNullable<
375
+ CreateThemesProps<any, any, any, any, any, typeof v5Templates, any>['getTheme']
376
+ >
377
+ >[0]
378
+ type Merge<A, B> = Omit<A, keyof B> & B
379
+
380
+ type DefaultV5ThemeValues = {
381
+ color01: string
382
+ color0075: string
383
+ color005: string
384
+ color0025: string
385
+ color002: string
386
+ color001: string
387
+ background01: string
388
+ background0075: string
389
+ background005: string
390
+ background0025: string
391
+ background002: string
392
+ background001: string
393
+ background02: string
394
+ background04: string
395
+ background06: string
396
+ background08: string
397
+ outlineColor: string
398
+ }
399
+
400
+ type ComponentThemeOption = Exclude<
401
+ Parameters<typeof createThemes>[0]['componentThemes'],
402
+ undefined
403
+ >
404
+
405
+ function getDefaultV5ThemeValues({ palette }: V5GetThemeProps): DefaultV5ThemeValues {
406
+ if (!palette || palette.length < 3) {
407
+ throw new Error(`invalid palette: ${JSON.stringify(palette)}`)
408
+ }
409
+
410
+ const bgColor = palette[V5_BG_OFFSET]!
411
+ const fgColor = palette[palette.length - 2]!
412
+
413
+ return {
414
+ color01: opacify(fgColor, 0.1),
415
+ color0075: opacify(fgColor, 0.075),
416
+ color005: opacify(fgColor, 0.05),
417
+ color0025: opacify(fgColor, 0.025),
418
+ color002: opacify(fgColor, 0.02),
419
+ color001: opacify(fgColor, 0.01),
420
+ background01: opacify(bgColor, 0.1),
421
+ background0075: opacify(bgColor, 0.075),
422
+ background005: opacify(bgColor, 0.05),
423
+ background0025: opacify(bgColor, 0.025),
424
+ background002: opacify(bgColor, 0.02),
425
+ background001: opacify(bgColor, 0.01),
426
+ background02: opacify(bgColor, 0.2),
427
+ background04: opacify(bgColor, 0.4),
428
+ background06: opacify(bgColor, 0.6),
429
+ background08: opacify(bgColor, 0.8),
430
+ outlineColor: opacify(palette[V5_BG_OFFSET + 4], 0.6),
431
+ }
432
+ }
433
+
434
+ export type CreateV5ThemeOptions<
435
+ Children extends Record<string, ChildTheme> = typeof defaultChildrenThemes,
436
+ GrandChildren extends Record<string, GrandChildrenThemeDefinition> =
437
+ typeof v5GrandchildrenThemes,
438
+ GetThemeReturn extends Record<string, string | number> = {},
439
+ > = {
440
+ /** Override the dark base palette (12 colors from darkest to lightest) */
441
+ darkPalette?: string[]
442
+ /** Override the light base palette (12 colors from lightest to darkest) */
443
+ lightPalette?: string[]
444
+ /**
445
+ * Custom accent palette. If not provided, accent uses the inverted base palette.
446
+ * Accepts named color objects: { light: { accent1: '#...', ... }, dark: { accent1: '#...', ... } }
447
+ */
448
+ accent?: ChildTheme
449
+ /**
450
+ * Override children themes (color themes like blue, red, etc.)
451
+ * Accepts radix color objects directly: { blue: { light: blue, dark: blueDark } }
452
+ */
453
+ childrenThemes?: Children
454
+ /**
455
+ * Override grandChildren themes (alt1, alt2, surface1, etc.)
456
+ * Pass undefined or omit to use v5GrandchildrenThemes
457
+ */
458
+ grandChildrenThemes?: GrandChildren
459
+ /**
460
+ * @deprecated component themes are no longer recommended -
461
+ * configure component styles directly via themes or component defaultProps instead
462
+ */
463
+ componentThemes?: false | ComponentThemeOption
464
+ /**
465
+ * Add computed values to every generated theme.
466
+ * These values merge on top of the built-in v5 computed tokens.
467
+ */
468
+ getTheme?: (props: V5GetThemeProps) => GetThemeReturn
469
+ }
470
+
471
+ /**
472
+ * Creates v5 themes with optional customizations.
473
+ *
474
+ * @example
475
+ * Use default themes
476
+ * const themes = createV5Theme()
477
+ *
478
+ * @example
479
+ * Custom children themes with brand color (accepts radix colors directly)
480
+ * const themes = createV5Theme({
481
+ * childrenThemes: {
482
+ * ...defaultChildrenThemes,
483
+ * brand: { light: brandLight, dark: brandDark },
484
+ * },
485
+ * })
486
+ *
487
+ * @example
488
+ * Minimal - no color themes
489
+ * const themes = createV5Theme({
490
+ * childrenThemes: {},
491
+ * })
492
+ */
493
+ export function createV5Theme<
494
+ Children extends Record<string, ChildTheme> = typeof defaultChildrenThemes,
495
+ GrandChildren extends Record<string, GrandChildrenThemeDefinition> =
496
+ typeof v5GrandchildrenThemes,
497
+ GetThemeReturn extends Record<string, string | number> = {},
498
+ >(
499
+ options: CreateV5ThemeOptions<
500
+ Children,
501
+ GrandChildren,
502
+ GetThemeReturn
503
+ > = {} as CreateV5ThemeOptions<Children, GrandChildren, GetThemeReturn>
504
+ ) {
505
+ const {
506
+ darkPalette: customDarkPalette = darkPalette,
507
+ lightPalette: customLightPalette = lightPalette,
508
+ accent: customAccent,
509
+ childrenThemes = defaultChildrenThemes as unknown as Children,
510
+ grandChildrenThemes = v5GrandchildrenThemes as unknown as GrandChildren,
511
+ componentThemes: customComponentThemes = v5ComponentThemes,
512
+ getTheme: userGetTheme,
513
+ } = options
514
+
515
+ // Generate black/white named colors from palettes
516
+ const blackColors = paletteToNamedColors('black', customDarkPalette)
517
+ const whiteColors = paletteToNamedColors('white', customLightPalette)
518
+
519
+ // Build extra colors - spread children color objects directly (types flow naturally)
520
+ // Note: opacity/interpolation colors (color01, background01, etc.) are computed by getTheme
521
+ const extraBase = {
522
+ ...blackColors,
523
+ ...whiteColors,
524
+ ...whiteBlack,
525
+ }
526
+ const lightExtraBase = {
527
+ ...extraBase,
528
+ ...lightShadows,
529
+ ...lightHighlights,
530
+ shadowColor: lightShadows.shadow3,
531
+ }
532
+ const darkExtraBase = {
533
+ ...extraBase,
534
+ ...darkShadows,
535
+ ...darkHighlights,
536
+ shadowColor: darkShadows.shadow3,
537
+ }
538
+
539
+ // Spread all children colors into extra - types flow from Children generic
540
+ type LightExtra = BaseExtraLight & MergedChildrenColors<Children, 'light'>
541
+ type DarkExtra = BaseExtraDark & MergedChildrenColors<Children, 'dark'>
542
+
543
+ const lightExtra = { ...lightExtraBase } as LightExtra
544
+ const darkExtra = { ...darkExtraBase } as DarkExtra
545
+
546
+ for (const theme of Object.values(childrenThemes)) {
547
+ if (theme.light) Object.assign(lightExtra, theme.light)
548
+ if (theme.dark) Object.assign(darkExtra, theme.dark)
549
+ }
550
+
551
+ // Convert children to palette format for createThemes, adding black/white internally
552
+ const childrenWithPalettes = {
553
+ // Always include black/white for theme generation
554
+ black: {
555
+ palette: { dark: Object.values(blackColors), light: Object.values(blackColors) },
556
+ },
557
+ white: {
558
+ palette: { dark: Object.values(whiteColors), light: Object.values(whiteColors) },
559
+ },
560
+ ...(Object.fromEntries(
561
+ Object.entries(childrenThemes).map(([name, theme]) => [
562
+ name,
563
+ {
564
+ palette: {
565
+ light: Object.values(theme.light),
566
+ dark: Object.values(theme.dark),
567
+ },
568
+ },
569
+ ])
570
+ ) as { [K in keyof Children]: PaletteEntry }),
571
+ } as ChildrenWithPalettes<Children>
572
+
573
+ return createThemes({
574
+ // componentThemes: false disables them, undefined/truthy values enable them
575
+ componentThemes: customComponentThemes,
576
+
577
+ templates: v5Templates,
578
+
579
+ base: {
580
+ palette: {
581
+ dark: customDarkPalette,
582
+ light: customLightPalette,
583
+ },
584
+
585
+ extra: {
586
+ light: lightExtra,
587
+ dark: darkExtra,
588
+ },
589
+ },
590
+
591
+ accent: {
592
+ palette: customAccent
593
+ ? {
594
+ light: Object.values(customAccent.light),
595
+ dark: Object.values(customAccent.dark),
596
+ }
597
+ : {
598
+ dark: customLightPalette,
599
+ light: customDarkPalette,
600
+ },
601
+ },
602
+
603
+ childrenThemes: childrenWithPalettes,
604
+
605
+ grandChildrenThemes,
606
+
607
+ getTheme: (props): Merge<DefaultV5ThemeValues, GetThemeReturn> => {
608
+ const builtInTheme = getDefaultV5ThemeValues(props)
609
+ const customTheme = userGetTheme?.(props)
610
+ return (
611
+ customTheme ? { ...builtInTheme, ...customTheme } : (builtInTheme as unknown)
612
+ ) as Merge<DefaultV5ThemeValues, GetThemeReturn>
613
+ },
614
+ })
615
+ }
616
+
617
+ // Default themes using the createV5Theme function
618
+ export const themes = createV5Theme()
619
+
620
+ // don't remove this - type sanity checks - these should not cause type errors:
621
+ themes.dark.background0075
622
+ themes.dark_yellow.background0075
623
+ themes.dark.background
624
+ themes.dark.accent1
625
+ // @ts-expect-error
626
+ themes.dark.nonValid