@wealthx/shadcn 1.0.2 → 1.2.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 (300) hide show
  1. package/.turbo/turbo-build.log +235 -138
  2. package/CHANGELOG.md +12 -0
  3. package/README.md +82 -0
  4. package/dist/{chunk-6OJF6XRN.mjs → chunk-24FUO7TD.mjs} +4 -8
  5. package/dist/{chunk-4AJ5HWHD.mjs → chunk-2I5S2AMY.mjs} +3 -3
  6. package/dist/chunk-2SF672SZ.mjs +161 -0
  7. package/dist/{chunk-GPRJQ24C.mjs → chunk-34NWQURD.mjs} +2 -2
  8. package/dist/{chunk-MQ72DIBH.mjs → chunk-3GF7OVTP.mjs} +14 -5
  9. package/dist/chunk-3WMX6KWS.mjs +245 -0
  10. package/dist/{chunk-PMKODV6M.mjs → chunk-462HMNO4.mjs} +6 -10
  11. package/dist/chunk-4CX4SBRO.mjs +153 -0
  12. package/dist/chunk-4MN6UQHG.mjs +443 -0
  13. package/dist/chunk-5QQVZTVZ.mjs +233 -0
  14. package/dist/{chunk-BGP2N52Z.mjs → chunk-66MI7Q4B.mjs} +5 -5
  15. package/dist/chunk-6FCGKSZX.mjs +268 -0
  16. package/dist/{chunk-CGOKTPXU.mjs → chunk-6JQFUE5I.mjs} +20 -23
  17. package/dist/{chunk-Z3MK2KKZ.mjs → chunk-7DHU4VGG.mjs} +7 -3
  18. package/dist/{chunk-VZ2NR7L3.mjs → chunk-7PYJD5JI.mjs} +35 -27
  19. package/dist/{chunk-JU2RUWHF.mjs → chunk-7XJHLGUV.mjs} +1 -1
  20. package/dist/{chunk-BMFN37JH.mjs → chunk-7YAU5CY6.mjs} +1 -1
  21. package/dist/chunk-A56YQQHG.mjs +402 -0
  22. package/dist/chunk-AH52LG6N.mjs +315 -0
  23. package/dist/{chunk-SLWCCURD.mjs → chunk-CLIN5525.mjs} +8 -4
  24. package/dist/{chunk-3VQNJ235.mjs → chunk-CSDO6VBW.mjs} +7 -0
  25. package/dist/chunk-D4ILTPOG.mjs +293 -0
  26. package/dist/{chunk-HS7TFG7V.mjs → chunk-D6ID6M4V.mjs} +1 -1
  27. package/dist/chunk-DOH3EHX7.mjs +378 -0
  28. package/dist/{chunk-MJIEMGRD.mjs → chunk-EFRENWEJ.mjs} +9 -17
  29. package/dist/chunk-ERGGHC2V.mjs +185 -0
  30. package/dist/{chunk-OXQQNQZI.mjs → chunk-FEZKMUCF.mjs} +10 -1
  31. package/dist/{chunk-55CEW76V.mjs → chunk-FH6QVUVZ.mjs} +1 -1
  32. package/dist/chunk-FMAXJ2SI.mjs +71 -0
  33. package/dist/chunk-FZIXGLMV.mjs +173 -0
  34. package/dist/{chunk-DS2AMHN2.mjs → chunk-GYMYRIZP.mjs} +2 -2
  35. package/dist/{chunk-KQDD5MU3.mjs → chunk-H45TKD34.mjs} +5 -5
  36. package/dist/{chunk-BBJBJSXQ.mjs → chunk-J5UICVJS.mjs} +1 -1
  37. package/dist/{chunk-RL772EH7.mjs → chunk-JHJHG4GO.mjs} +4 -12
  38. package/dist/chunk-KMCGSZTX.mjs +177 -0
  39. package/dist/{chunk-FHNT55I5.mjs → chunk-KUDCQ4FI.mjs} +4 -4
  40. package/dist/chunk-LE6YFY6D.mjs +209 -0
  41. package/dist/{chunk-HUVTPUV2.mjs → chunk-LLVQKSU3.mjs} +23 -19
  42. package/dist/{chunk-KKHTJNMM.mjs → chunk-MARPPFOJ.mjs} +8 -4
  43. package/dist/{chunk-6AFMNC42.mjs → chunk-N2PT566P.mjs} +15 -11
  44. package/dist/chunk-NLCKVHWB.mjs +161 -0
  45. package/dist/{chunk-YN5SYTOO.mjs → chunk-NQPOYKAQ.mjs} +9 -5
  46. package/dist/{chunk-ZZV5JVNW.mjs → chunk-NSLMILBT.mjs} +3 -7
  47. package/dist/chunk-NXA3CZ7A.mjs +248 -0
  48. package/dist/chunk-OGOYQ7BG.mjs +150 -0
  49. package/dist/{chunk-3NQGYJEZ.mjs → chunk-P6AM5V7O.mjs} +10 -18
  50. package/dist/{chunk-CZ3BW5GL.mjs → chunk-P76HMUI6.mjs} +5 -11
  51. package/dist/chunk-PCPLO5HT.mjs +671 -0
  52. package/dist/chunk-PG6K5XEC.mjs +475 -0
  53. package/dist/chunk-PJHPSRYD.mjs +234 -0
  54. package/dist/{chunk-DDPA2XXS.mjs → chunk-PMB3A7V3.mjs} +2 -2
  55. package/dist/chunk-PR6V5XKM.mjs +209 -0
  56. package/dist/{chunk-46OFHMQA.mjs → chunk-Q76O3RIQ.mjs} +10 -6
  57. package/dist/chunk-QVKWW6KE.mjs +272 -0
  58. package/dist/chunk-RGU7HOEC.mjs +140 -0
  59. package/dist/{chunk-JF4PHPD5.mjs → chunk-RGVKLTLH.mjs} +4 -4
  60. package/dist/{chunk-VG6UF6UT.mjs → chunk-RP3SQYA3.mjs} +2 -2
  61. package/dist/chunk-RRBS6D63.mjs +163 -0
  62. package/dist/chunk-SMQ3DG25.mjs +285 -0
  63. package/dist/chunk-SPJ5KXW7.mjs +199 -0
  64. package/dist/chunk-SYOD63OZ.mjs +225 -0
  65. package/dist/chunk-UFYSFDER.mjs +42 -0
  66. package/dist/chunk-VACKZOMY.mjs +190 -0
  67. package/dist/chunk-VLQZANBF.mjs +42 -0
  68. package/dist/chunk-WA6O6EUR.mjs +1885 -0
  69. package/dist/{chunk-E3K6O4FZ.mjs → chunk-WAZD7NFU.mjs} +5 -2
  70. package/dist/chunk-WG6JGJXB.mjs +165 -0
  71. package/dist/{chunk-I64K754C.mjs → chunk-WNGWBVLV.mjs} +2 -2
  72. package/dist/{chunk-3U7SD3MS.mjs → chunk-WOEHFRGB.mjs} +3 -3
  73. package/dist/{chunk-DKZRJOMF.mjs → chunk-XIRTEFKH.mjs} +12 -12
  74. package/dist/chunk-Y6DWJSKZ.mjs +79 -0
  75. package/dist/chunk-YKPROFLB.mjs +161 -0
  76. package/dist/{chunk-K76E2TQU.mjs → chunk-ZRO5JO3H.mjs} +107 -67
  77. package/dist/{chunk-VYMHBV6D.mjs → chunk-ZU4NV6RG.mjs} +5 -3
  78. package/dist/components/ui/accordion.js +40 -4
  79. package/dist/components/ui/accordion.mjs +2 -2
  80. package/dist/components/ui/add-column-modal.js +789 -0
  81. package/dist/components/ui/add-column-modal.mjs +17 -0
  82. package/dist/components/ui/add-lead-modal.js +647 -0
  83. package/dist/components/ui/add-lead-modal.mjs +16 -0
  84. package/dist/components/ui/ai-assistant-drawer.js +686 -0
  85. package/dist/components/ui/ai-assistant-drawer.mjs +16 -0
  86. package/dist/components/ui/alert-dialog.js +37 -5
  87. package/dist/components/ui/alert-dialog.mjs +4 -4
  88. package/dist/components/ui/alert.js +37 -11
  89. package/dist/components/ui/alert.mjs +2 -2
  90. package/dist/components/ui/avatar.js +36 -8
  91. package/dist/components/ui/avatar.mjs +2 -2
  92. package/dist/components/ui/backoffice-alert-history-chart.js +624 -0
  93. package/dist/components/ui/backoffice-alert-history-chart.mjs +16 -0
  94. package/dist/components/ui/backoffice-contact-history-chart.js +687 -0
  95. package/dist/components/ui/backoffice-contact-history-chart.mjs +16 -0
  96. package/dist/components/ui/badge.js +37 -2
  97. package/dist/components/ui/badge.mjs +2 -2
  98. package/dist/components/ui/borrowing-capacity-line-chart.js +639 -0
  99. package/dist/components/ui/borrowing-capacity-line-chart.mjs +16 -0
  100. package/dist/components/ui/button.js +35 -3
  101. package/dist/components/ui/button.mjs +2 -2
  102. package/dist/components/ui/calendar.js +43 -19
  103. package/dist/components/ui/calendar.mjs +3 -3
  104. package/dist/components/ui/card.js +40 -4
  105. package/dist/components/ui/card.mjs +2 -2
  106. package/dist/components/ui/cash-balance-line-chart.js +627 -0
  107. package/dist/components/ui/cash-balance-line-chart.mjs +16 -0
  108. package/dist/components/ui/cashflow-bar-chart.js +650 -0
  109. package/dist/components/ui/cashflow-bar-chart.mjs +16 -0
  110. package/dist/components/ui/checkbox.js +36 -5
  111. package/dist/components/ui/checkbox.mjs +2 -3
  112. package/dist/components/ui/chip.js +37 -2
  113. package/dist/components/ui/chip.mjs +3 -3
  114. package/dist/components/ui/combobox.js +280 -0
  115. package/dist/components/ui/combobox.mjs +28 -0
  116. package/dist/components/ui/data-table.js +160 -88
  117. package/dist/components/ui/data-table.mjs +10 -11
  118. package/dist/components/ui/date-picker.js +44 -20
  119. package/dist/components/ui/date-picker.mjs +6 -7
  120. package/dist/components/ui/dialog.js +44 -12
  121. package/dist/components/ui/dialog.mjs +4 -4
  122. package/dist/components/ui/drawer.js +46 -10
  123. package/dist/components/ui/drawer.mjs +3 -3
  124. package/dist/components/ui/dropdown-menu.js +40 -16
  125. package/dist/components/ui/dropdown-menu.mjs +3 -3
  126. package/dist/components/ui/empty.js +41 -5
  127. package/dist/components/ui/empty.mjs +2 -2
  128. package/dist/components/ui/expense-bar-chart.js +642 -0
  129. package/dist/components/ui/expense-bar-chart.mjs +16 -0
  130. package/dist/components/ui/field.js +53 -21
  131. package/dist/components/ui/field.mjs +4 -4
  132. package/dist/components/ui/financial-cards.js +1002 -0
  133. package/dist/components/ui/financial-cards.mjs +24 -0
  134. package/dist/components/ui/financial-drawers.js +637 -0
  135. package/dist/components/ui/financial-drawers.mjs +17 -0
  136. package/dist/components/ui/financial-primitives.js +218 -0
  137. package/dist/components/ui/financial-primitives.mjs +22 -0
  138. package/dist/components/ui/financial-sections.js +1422 -0
  139. package/dist/components/ui/financial-sections.mjs +30 -0
  140. package/dist/components/ui/form-primitives.js +682 -0
  141. package/dist/components/ui/form-primitives.mjs +19 -0
  142. package/dist/components/ui/income-bar-chart.js +641 -0
  143. package/dist/components/ui/income-bar-chart.mjs +16 -0
  144. package/dist/components/ui/input-group.js +43 -7
  145. package/dist/components/ui/input-group.mjs +5 -5
  146. package/dist/components/ui/input-otp.js +39 -3
  147. package/dist/components/ui/input-otp.mjs +2 -2
  148. package/dist/components/ui/input.js +34 -2
  149. package/dist/components/ui/input.mjs +2 -2
  150. package/dist/components/ui/kanban-column.js +1143 -0
  151. package/dist/components/ui/kanban-column.mjs +20 -0
  152. package/dist/components/ui/label.js +35 -7
  153. package/dist/components/ui/label.mjs +2 -2
  154. package/dist/components/ui/opportunity-card.js +960 -0
  155. package/dist/components/ui/opportunity-card.mjs +20 -0
  156. package/dist/components/ui/opportunity-edit-modals.js +3360 -0
  157. package/dist/components/ui/opportunity-edit-modals.mjs +37 -0
  158. package/dist/components/ui/opportunity-summary-tab.js +4365 -0
  159. package/dist/components/ui/opportunity-summary-tab.mjs +34 -0
  160. package/dist/components/ui/pagination.js +35 -3
  161. package/dist/components/ui/pagination.mjs +3 -3
  162. package/dist/components/ui/pipeline-alerts.js +103 -0
  163. package/dist/components/ui/pipeline-alerts.mjs +8 -0
  164. package/dist/components/ui/pipeline-board.js +1408 -0
  165. package/dist/components/ui/pipeline-board.mjs +24 -0
  166. package/dist/components/ui/pipeline-chart.js +216 -0
  167. package/dist/components/ui/pipeline-chart.mjs +10 -0
  168. package/dist/components/ui/pipeline-dialogs.js +1183 -0
  169. package/dist/components/ui/pipeline-dialogs.mjs +23 -0
  170. package/dist/components/ui/pipeline-primitives.js +300 -0
  171. package/dist/components/ui/pipeline-primitives.mjs +11 -0
  172. package/dist/components/ui/popover.js +45 -4
  173. package/dist/components/ui/popover.mjs +3 -3
  174. package/dist/components/ui/progress.js +33 -1
  175. package/dist/components/ui/progress.mjs +2 -2
  176. package/dist/components/ui/property-cashflow-doughnut-chart.js +523 -0
  177. package/dist/components/ui/property-cashflow-doughnut-chart.mjs +16 -0
  178. package/dist/components/ui/property-debt-equity-doughnut-chart.js +521 -0
  179. package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +16 -0
  180. package/dist/components/ui/property-mobile-estimate-line-chart.js +682 -0
  181. package/dist/components/ui/property-mobile-estimate-line-chart.mjs +16 -0
  182. package/dist/components/ui/radio-group.js +33 -1
  183. package/dist/components/ui/radio-group.mjs +2 -2
  184. package/dist/components/ui/select.js +66 -26
  185. package/dist/components/ui/select.mjs +3 -3
  186. package/dist/components/ui/separator.js +33 -1
  187. package/dist/components/ui/separator.mjs +2 -2
  188. package/dist/components/ui/sheet.js +37 -9
  189. package/dist/components/ui/sheet.mjs +3 -3
  190. package/dist/components/ui/skeleton.js +33 -1
  191. package/dist/components/ui/skeleton.mjs +2 -2
  192. package/dist/components/ui/slider.js +86 -102
  193. package/dist/components/ui/slider.mjs +2 -2
  194. package/dist/components/ui/spinner.js +33 -1
  195. package/dist/components/ui/spinner.mjs +2 -2
  196. package/dist/components/ui/stage-timeline.js +579 -0
  197. package/dist/components/ui/stage-timeline.mjs +15 -0
  198. package/dist/components/ui/switch.js +37 -4
  199. package/dist/components/ui/switch.mjs +2 -3
  200. package/dist/components/ui/table.js +37 -5
  201. package/dist/components/ui/table.mjs +2 -2
  202. package/dist/components/ui/tabs.js +36 -12
  203. package/dist/components/ui/tabs.mjs +2 -2
  204. package/dist/components/ui/textarea.js +34 -2
  205. package/dist/components/ui/textarea.mjs +2 -2
  206. package/dist/components/ui/toggle-group.js +35 -4
  207. package/dist/components/ui/toggle-group.mjs +3 -4
  208. package/dist/components/ui/toggle.js +35 -4
  209. package/dist/components/ui/toggle.mjs +2 -3
  210. package/dist/components/ui/tooltip.js +51 -22
  211. package/dist/components/ui/tooltip.mjs +3 -3
  212. package/dist/components/ui/transactions-expense-categories-doughnut-chart.js +528 -0
  213. package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +16 -0
  214. package/dist/components/ui/transactions-income-expense-bar-chart.js +516 -0
  215. package/dist/components/ui/transactions-income-expense-bar-chart.mjs +16 -0
  216. package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.js +528 -0
  217. package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +16 -0
  218. package/dist/index.js +11613 -2868
  219. package/dist/index.mjs +377 -164
  220. package/dist/lib/theme-provider.js +10 -1
  221. package/dist/lib/theme-provider.mjs +1 -1
  222. package/dist/lib/typography.js +8 -0
  223. package/dist/lib/typography.mjs +3 -1
  224. package/dist/lib/utils.js +33 -1
  225. package/dist/lib/utils.mjs +1 -1
  226. package/dist/styles.css +1 -1
  227. package/package.json +169 -6
  228. package/src/components/index.tsx +323 -13
  229. package/src/components/ui/accordion.tsx +6 -3
  230. package/src/components/ui/add-column-modal.tsx +339 -0
  231. package/src/components/ui/add-lead-modal.tsx +290 -0
  232. package/src/components/ui/ai-assistant-drawer.tsx +408 -0
  233. package/src/components/ui/alert-dialog.tsx +80 -54
  234. package/src/components/ui/alert.tsx +28 -28
  235. package/src/components/ui/avatar.tsx +30 -29
  236. package/src/components/ui/backoffice-alert-history-chart.tsx +260 -0
  237. package/src/components/ui/backoffice-contact-history-chart.tsx +325 -0
  238. package/src/components/ui/badge.tsx +17 -15
  239. package/src/components/ui/borrowing-capacity-line-chart.tsx +357 -0
  240. package/src/components/ui/button.tsx +30 -27
  241. package/src/components/ui/calendar.tsx +53 -67
  242. package/src/components/ui/card.tsx +27 -24
  243. package/src/components/ui/cash-balance-line-chart.tsx +302 -0
  244. package/src/components/ui/cashflow-bar-chart.tsx +363 -0
  245. package/src/components/ui/chart-shared.tsx +261 -0
  246. package/src/components/ui/checkbox.tsx +30 -26
  247. package/src/components/ui/combobox.tsx +223 -0
  248. package/src/components/ui/data-table.tsx +160 -99
  249. package/src/components/ui/date-picker.tsx +0 -2
  250. package/src/components/ui/dialog.tsx +70 -60
  251. package/src/components/ui/drawer.tsx +57 -48
  252. package/src/components/ui/dropdown-menu.tsx +90 -82
  253. package/src/components/ui/empty.tsx +31 -27
  254. package/src/components/ui/expense-bar-chart.tsx +296 -0
  255. package/src/components/ui/field.tsx +70 -62
  256. package/src/components/ui/financial-cards.tsx +830 -0
  257. package/src/components/ui/financial-drawers.tsx +339 -0
  258. package/src/components/ui/financial-primitives.tsx +331 -0
  259. package/src/components/ui/financial-sections.tsx +672 -0
  260. package/src/components/ui/form-primitives.tsx +536 -0
  261. package/src/components/ui/income-bar-chart.tsx +297 -0
  262. package/src/components/ui/input-group.tsx +41 -34
  263. package/src/components/ui/input-otp.tsx +29 -24
  264. package/src/components/ui/input.tsx +8 -8
  265. package/src/components/ui/kanban-column.tsx +333 -0
  266. package/src/components/ui/label.tsx +9 -12
  267. package/src/components/ui/opportunity-card.tsx +616 -0
  268. package/src/components/ui/opportunity-edit-modals.tsx +2528 -0
  269. package/src/components/ui/opportunity-summary-tab.tsx +579 -0
  270. package/src/components/ui/pipeline-alerts.tsx +74 -0
  271. package/src/components/ui/pipeline-board.tsx +268 -0
  272. package/src/components/ui/pipeline-chart.tsx +173 -0
  273. package/src/components/ui/pipeline-dialogs.tsx +303 -0
  274. package/src/components/ui/pipeline-primitives.tsx +108 -0
  275. package/src/components/ui/popover.tsx +41 -36
  276. package/src/components/ui/property-cashflow-doughnut-chart.tsx +188 -0
  277. package/src/components/ui/property-debt-equity-doughnut-chart.tsx +185 -0
  278. package/src/components/ui/property-mobile-estimate-line-chart.tsx +393 -0
  279. package/src/components/ui/select.tsx +65 -52
  280. package/src/components/ui/sheet.tsx +55 -52
  281. package/src/components/ui/slider.tsx +54 -77
  282. package/src/components/ui/stage-timeline.tsx +205 -0
  283. package/src/components/ui/switch.tsx +42 -29
  284. package/src/components/ui/table.tsx +28 -28
  285. package/src/components/ui/tabs.tsx +22 -28
  286. package/src/components/ui/textarea.tsx +8 -8
  287. package/src/components/ui/toggle-group.tsx +0 -2
  288. package/src/components/ui/toggle.tsx +13 -15
  289. package/src/components/ui/tooltip.tsx +30 -28
  290. package/src/components/ui/transactions-expense-categories-doughnut-chart.tsx +191 -0
  291. package/src/components/ui/transactions-income-expense-bar-chart.tsx +205 -0
  292. package/src/components/ui/transactions-liabilities-breakdown-doughnut-chart.tsx +191 -0
  293. package/src/lib/theme-provider.tsx +10 -0
  294. package/src/lib/typography.ts +9 -0
  295. package/src/lib/utils.ts +41 -3
  296. package/src/styles/globals.css +371 -124
  297. package/src/styles/styles-css.ts +1 -1
  298. package/tsup.config.ts +32 -0
  299. package/dist/chunk-K74JRTJR.mjs +0 -105
  300. package/dist/chunk-V7CNWJT3.mjs +0 -10
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Shared utilities and sub-components for all shadcn chart components.
3
+ * Not part of the public package API — internal use only.
4
+ */
5
+ import React from "react";
6
+ import { Button } from "./button";
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Types
10
+ // ---------------------------------------------------------------------------
11
+
12
+ export type ChartPeriod = 1 | 3 | 6 | 12;
13
+ export type ChartGranularity = "monthly" | "daily";
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Period / slice config
17
+ // ---------------------------------------------------------------------------
18
+
19
+ /**
20
+ * How many data points to slice per period × granularity combination.
21
+ * monthly: slice by calendar month count.
22
+ * daily: slice by approximate day count (1M=30d, 3M=90d, 6M=180d, 12M=365d).
23
+ */
24
+ export const CHART_SLICE_COUNT: Record<
25
+ ChartGranularity,
26
+ Record<ChartPeriod, number>
27
+ > = {
28
+ monthly: { 1: 1, 3: 3, 6: 6, 12: 12 },
29
+ daily: { 1: 30, 3: 90, 6: 180, 12: 365 },
30
+ };
31
+
32
+ /** Period buttons shown per granularity. monthly hides 1M; daily shows all four. */
33
+ export const CHART_PERIODS: Record<ChartGranularity, ChartPeriod[]> = {
34
+ monthly: [3, 6, 12],
35
+ daily: [1, 3, 6, 12],
36
+ };
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // Chart.js helpers
40
+ // ---------------------------------------------------------------------------
41
+
42
+ export function hexToRgba(hex: string, alpha: number): string {
43
+ const clean = hex.replace("#", "");
44
+ const full =
45
+ clean.length === 3
46
+ ? clean
47
+ .split("")
48
+ .map((c) => c + c)
49
+ .join("")
50
+ : clean;
51
+ const r = parseInt(full.slice(0, 2), 16);
52
+ const g = parseInt(full.slice(2, 4), 16);
53
+ const b = parseInt(full.slice(4, 6), 16);
54
+ return `rgba(${r},${g},${b},${alpha})`;
55
+ }
56
+
57
+ /** Opacity steps to derive distinct shades from a single brand color (up to 6 datasets). */
58
+ export const DATASET_ALPHAS = [1, 0.72, 0.52, 0.36, 0.24, 0.15];
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Fallback resolved colors for Chart.js canvas API.
62
+ // Chart.js requires actual hex/rgb strings — CSS variables cannot be used directly.
63
+ // All values match the :root defaults defined in globals.css.
64
+ // ---------------------------------------------------------------------------
65
+
66
+ /** Fallback for --primary (WealthX green) */
67
+ export const FALLBACK_PRIMARY = "#33FF99";
68
+ /** Fallback for --brand-secondary (WealthX dark navy) */
69
+ export const FALLBACK_SECONDARY = "#162029";
70
+ /** Fallback for --background (white) */
71
+ export const FALLBACK_BG = "#ffffff";
72
+ /** Fallback for --foreground (near-black) */
73
+ export const FALLBACK_FOREGROUND = "#040D13";
74
+ /** Fallback for --muted-foreground used as axis tick color */
75
+ export const FALLBACK_TICK = "#9EAAB5";
76
+ /** Fallback neutral grey for comparison / suburb lines */
77
+ export const FALLBACK_NEUTRAL = "#B9BCBF";
78
+ /** Fallback semi-transparent grid line color */
79
+ export const FALLBACK_GRID_COLOR = "rgba(0,0,0,0.06)";
80
+
81
+ /**
82
+ * Semantic severity colors for alert / status charts.
83
+ * Match WealthX design tokens: --destructive, --warning, --success.
84
+ * Intentionally fixed — severity meaning must be recognisable regardless of tenant theme.
85
+ */
86
+ export const SEVERITY_COLORS = {
87
+ high: "#F44336", // default --destructive oklch(0.643 0.215 28.8)
88
+ medium: "#FF9800", // default --warning oklch(0.77 0.174 64.1)
89
+ low: "#4CAF50", // default --success oklch(0.673 0.162 144.2)
90
+ } as const;
91
+
92
+ /**
93
+ * Format a dollar amount as an abbreviated string for chart axis ticks.
94
+ * e.g. 1_200_000 → "$1.2M", 580_000 → "$580K", -250_000 → "-$250K"
95
+ */
96
+ export function formatAbbrev(value: number): string {
97
+ const abs = Math.abs(value);
98
+ const sign = value < 0 ? "-" : "";
99
+ if (abs >= 1_000_000_000)
100
+ return `${sign}$${(abs / 1_000_000_000).toFixed(1)}B`;
101
+ if (abs >= 1_000_000) return `${sign}$${(abs / 1_000_000).toFixed(1)}M`;
102
+ if (abs >= 1_000) return `${sign}$${(abs / 1_000).toFixed(0)}K`;
103
+ return `${sign}$${abs.toFixed(0)}`;
104
+ }
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // Tooltip date format
108
+ // ---------------------------------------------------------------------------
109
+
110
+ /**
111
+ * Format an ISO date string for the chart tooltip title.
112
+ * Daily granularity includes the day; monthly shows only month + year.
113
+ */
114
+ export function formatTooltipDate(
115
+ iso: string,
116
+ granularity: ChartGranularity,
117
+ ): string {
118
+ const d = new Date(iso);
119
+ return d.toLocaleDateString(
120
+ "en-US",
121
+ granularity === "daily"
122
+ ? { month: "short", day: "numeric", year: "numeric" }
123
+ : { month: "short", year: "numeric" },
124
+ );
125
+ }
126
+
127
+ // ---------------------------------------------------------------------------
128
+ // Date / count formatters (shared across bar and doughnut charts)
129
+ // ---------------------------------------------------------------------------
130
+
131
+ /** Format an ISO date string as "Mon 'YY" for X-axis month labels. */
132
+ export function formatMonthLabel(iso: string): string {
133
+ return new Date(iso).toLocaleDateString("en-US", {
134
+ month: "short",
135
+ year: "2-digit",
136
+ });
137
+ }
138
+
139
+ /** Format a raw integer count for axis ticks and tooltips. */
140
+ export function formatCount(n: number): string {
141
+ if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;
142
+ return String(Math.round(n));
143
+ }
144
+
145
+ // ---------------------------------------------------------------------------
146
+ // Sub-components
147
+ // ---------------------------------------------------------------------------
148
+
149
+ export function ChartLegendItem({
150
+ label,
151
+ color,
152
+ lineStyle,
153
+ }: {
154
+ label: string;
155
+ color: string;
156
+ /** When provided, renders a line indicator instead of a square swatch */
157
+ lineStyle?: "solid" | "dashed";
158
+ }) {
159
+ return (
160
+ <div className="flex items-center gap-1.5">
161
+ {lineStyle ? (
162
+ <svg
163
+ width="20"
164
+ height="10"
165
+ viewBox="0 0 20 10"
166
+ aria-hidden="true"
167
+ style={{ flexShrink: 0 }}
168
+ >
169
+ <line
170
+ x1="0"
171
+ y1="5"
172
+ x2="20"
173
+ y2="5"
174
+ stroke={color}
175
+ strokeWidth="2"
176
+ strokeLinecap="square"
177
+ strokeDasharray={lineStyle === "dashed" ? "5 3" : undefined}
178
+ />
179
+ </svg>
180
+ ) : (
181
+ <div
182
+ style={{
183
+ width: 10,
184
+ height: 10,
185
+ backgroundColor: color,
186
+ flexShrink: 0,
187
+ }}
188
+ />
189
+ )}
190
+ <span className="text-[11px] text-muted-foreground leading-none">
191
+ {label}
192
+ </span>
193
+ </div>
194
+ );
195
+ }
196
+
197
+ /**
198
+ * One row in a doughnut chart legend — circle swatch, label, dollar value, percent.
199
+ * The label truncates when the container is constrained.
200
+ */
201
+ export function DoughnutLegendRow({
202
+ label,
203
+ color,
204
+ value,
205
+ percent,
206
+ }: {
207
+ label: string;
208
+ color: string;
209
+ value: number;
210
+ percent: string;
211
+ }) {
212
+ return (
213
+ <div className="flex items-center justify-between gap-2">
214
+ <div className="flex items-center gap-1.5 min-w-0">
215
+ <div
216
+ style={{
217
+ width: 10,
218
+ height: 10,
219
+ borderRadius: "50%",
220
+ backgroundColor: color,
221
+ flexShrink: 0,
222
+ }}
223
+ />
224
+ <span className="text-[11px] text-muted-foreground leading-none truncate">
225
+ {label}
226
+ </span>
227
+ </div>
228
+ <div className="flex items-center gap-2 shrink-0">
229
+ <span className="text-[11px] font-medium leading-none">
230
+ {formatAbbrev(value)}
231
+ </span>
232
+ <span className="text-[11px] text-muted-foreground leading-none w-10 text-right">
233
+ {percent}
234
+ </span>
235
+ </div>
236
+ </div>
237
+ );
238
+ }
239
+
240
+ export function ChartPeriodButton({
241
+ period,
242
+ active,
243
+ onClick,
244
+ unit = "M",
245
+ }: {
246
+ period: number;
247
+ active: boolean;
248
+ onClick: () => void;
249
+ unit?: string;
250
+ }) {
251
+ return (
252
+ <Button
253
+ variant={active ? "default" : "outline"}
254
+ size="xs"
255
+ onClick={onClick}
256
+ >
257
+ {period}
258
+ {unit}
259
+ </Button>
260
+ );
261
+ }
@@ -1,9 +1,7 @@
1
- "use client"
2
-
3
- import { type ReactElement, useState, type ComponentProps } from "react"
4
- import { CheckIcon, MinusIcon } from "lucide-react"
5
- import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
6
- import { cn } from "@/lib/utils"
1
+ import { type ReactElement, useState, type ComponentProps } from "react";
2
+ import { CheckIcon, MinusIcon } from "lucide-react";
3
+ import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
4
+ import { cn } from "@/lib/utils";
7
5
 
8
6
  /**
9
7
  * Checkbox — shadcn/WealthX Design System
@@ -13,13 +11,13 @@ import { cn } from "@/lib/utils"
13
11
  * White-label: checked/indeterminate use `primary` token → adapts to tenant color.
14
12
  * Error+checked/indeterminate: stacked variant overrides primary with destructive (higher specificity).
15
13
  */
16
- export type CheckboxProps = ComponentProps<typeof CheckboxPrimitive.Root>
14
+ export type CheckboxProps = ComponentProps<typeof CheckboxPrimitive.Root>;
17
15
 
18
16
  function Checkbox({ className, ...props }: CheckboxProps): ReactElement {
19
17
  return (
20
18
  <CheckboxPrimitive.Root
21
19
  className={cn(
22
- "peer group inline-flex size-4 shrink-0 rounded-[4px] border border-input shadow-xs transition-all outline-none",
20
+ "peer group inline-flex size-4 shrink-0 border border-input shadow-xs transition-all outline-none",
23
21
  "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
24
22
  "disabled:cursor-not-allowed disabled:opacity-50",
25
23
  "aria-invalid:border-destructive aria-invalid:ring-destructive/20",
@@ -30,7 +28,7 @@ function Checkbox({ className, ...props }: CheckboxProps): ReactElement {
30
28
  // Stacked (2 attr selectors) → wins over single-attr rules above
31
29
  "aria-invalid:data-checked:border-destructive aria-invalid:data-checked:bg-destructive aria-invalid:data-checked:text-destructive-foreground",
32
30
  "aria-invalid:data-indeterminate:border-destructive aria-invalid:data-indeterminate:bg-destructive aria-invalid:data-indeterminate:text-destructive-foreground",
33
- className
31
+ className,
34
32
  )}
35
33
  data-slot="checkbox"
36
34
  {...props}
@@ -43,7 +41,7 @@ function Checkbox({ className, ...props }: CheckboxProps): ReactElement {
43
41
  <MinusIcon className="size-3.5 hidden group-data-indeterminate:block" />
44
42
  </CheckboxPrimitive.Indicator>
45
43
  </CheckboxPrimitive.Root>
46
- )
44
+ );
47
45
  }
48
46
 
49
47
  /**
@@ -53,11 +51,13 @@ function Checkbox({ className, ...props }: CheckboxProps): ReactElement {
53
51
  * Card background: primary/5 when checked/indeterminate; destructive/5 when error+checked.
54
52
  * White-label: opacity modifier on primary token → adapts to tenant color.
55
53
  */
56
- export type CheckboxCardProps = ComponentProps<typeof CheckboxPrimitive.Root> & {
57
- label: string
58
- description?: string
59
- error?: boolean
60
- }
54
+ export type CheckboxCardProps = ComponentProps<
55
+ typeof CheckboxPrimitive.Root
56
+ > & {
57
+ label: string;
58
+ description?: string;
59
+ error?: boolean;
60
+ };
61
61
 
62
62
  function CheckboxCard({
63
63
  className,
@@ -71,11 +71,11 @@ function CheckboxCard({
71
71
  ...props
72
72
  }: CheckboxCardProps): ReactElement {
73
73
  const [internalChecked, setInternalChecked] = useState<boolean>(
74
- Boolean(defaultChecked)
75
- )
74
+ Boolean(defaultChecked),
75
+ );
76
76
 
77
- const resolvedChecked = checked ?? internalChecked
78
- const isTinted = resolvedChecked
77
+ const resolvedChecked = checked ?? internalChecked;
78
+ const isTinted = resolvedChecked;
79
79
 
80
80
  return (
81
81
  <label
@@ -85,7 +85,7 @@ function CheckboxCard({
85
85
  ? ["border-destructive", isTinted && "bg-destructive/5"]
86
86
  : isTinted && "border-primary bg-primary/5",
87
87
  disabled && "cursor-not-allowed opacity-50",
88
- className
88
+ className,
89
89
  )}
90
90
  data-slot="checkbox-card"
91
91
  >
@@ -95,17 +95,21 @@ function CheckboxCard({
95
95
  className="mt-0.5"
96
96
  disabled={disabled}
97
97
  onCheckedChange={(value, event) => {
98
- setInternalChecked(value as boolean)
99
- onCheckedChange?.(value, event)
98
+ setInternalChecked(value as boolean);
99
+ onCheckedChange?.(value, event);
100
100
  }}
101
101
  {...props}
102
102
  />
103
103
  <div className="flex flex-col gap-1">
104
- <span className="text-sm font-medium leading-none">{label}</span>
105
- {description ? <span className="text-sm text-muted-foreground">{description}</span> : null}
104
+ <span className="text-label-medium leading-none">{label}</span>
105
+ {description ? (
106
+ <span className="text-body-small text-muted-foreground">
107
+ {description}
108
+ </span>
109
+ ) : null}
106
110
  </div>
107
111
  </label>
108
- )
112
+ );
109
113
  }
110
114
 
111
- export { Checkbox, CheckboxCard }
115
+ export { Checkbox, CheckboxCard };
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Combobox — WealthX Design System
3
+ * Base: @base-ui/react/combobox
4
+ * WealthX overrides: square corners (rounded-none), design token colors,
5
+ * consistent styling with Select component, built-in search filtering.
6
+ */
7
+ import * as React from "react";
8
+ import { CheckIcon, ChevronDownIcon, SearchIcon } from "lucide-react";
9
+ import { Combobox as ComboboxPrimitive } from "@base-ui/react/combobox";
10
+
11
+ import { cn } from "@/lib/utils";
12
+
13
+ export type ComboboxProps<
14
+ Value = string,
15
+ Multiple extends boolean | undefined = false,
16
+ > = React.ComponentProps<typeof ComboboxPrimitive.Root<Value, Multiple>>;
17
+
18
+ function Combobox<Value, Multiple extends boolean | undefined = false>({
19
+ ...props
20
+ }: React.ComponentProps<typeof ComboboxPrimitive.Root<Value, Multiple>>) {
21
+ return <ComboboxPrimitive.Root data-slot="combobox" {...props} />;
22
+ }
23
+
24
+ export type ComboboxTriggerProps = React.ComponentProps<
25
+ typeof ComboboxPrimitive.Trigger
26
+ > & {
27
+ size?: "sm" | "default";
28
+ };
29
+
30
+ function ComboboxTrigger({
31
+ className,
32
+ size = "default",
33
+ children,
34
+ ...props
35
+ }: ComboboxTriggerProps) {
36
+ return (
37
+ <ComboboxPrimitive.Trigger
38
+ data-slot="combobox-trigger"
39
+ data-size={size}
40
+ className={cn(
41
+ "flex w-fit items-center justify-between gap-2 border border-input bg-transparent px-3 py-2 text-body-small whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-primary focus-visible:ring-[3px] focus-visible:ring-primary/20 data-[popup-open]:border-primary data-[popup-open]:ring-[3px] data-[popup-open]:ring-primary/20 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[placeholder]:font-normal data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=combobox-value]:line-clamp-1 *:data-[slot=combobox-value]:flex *:data-[slot=combobox-value]:items-center *:data-[slot=combobox-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
42
+ className,
43
+ )}
44
+ {...props}
45
+ >
46
+ {children}
47
+ <ComboboxPrimitive.Icon className="transition-transform duration-200 data-[popup-open]:rotate-180">
48
+ <ChevronDownIcon className="size-4 opacity-50" />
49
+ </ComboboxPrimitive.Icon>
50
+ </ComboboxPrimitive.Trigger>
51
+ );
52
+ }
53
+
54
+ export type ComboboxValueProps = React.ComponentProps<
55
+ typeof ComboboxPrimitive.Value
56
+ >;
57
+
58
+ function ComboboxValue({ ...props }: ComboboxValueProps) {
59
+ return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />;
60
+ }
61
+
62
+ export type ComboboxInputProps = React.ComponentProps<
63
+ typeof ComboboxPrimitive.Input
64
+ >;
65
+
66
+ function ComboboxInput({ className, ...props }: ComboboxInputProps) {
67
+ return (
68
+ <div
69
+ data-slot="combobox-input-wrapper"
70
+ className="flex items-center gap-2 border-b border-border px-3"
71
+ >
72
+ <SearchIcon className="size-4 shrink-0 text-muted-foreground" />
73
+ <ComboboxPrimitive.Input
74
+ data-slot="combobox-input"
75
+ className={cn(
76
+ "h-9 w-full min-w-0 bg-transparent py-1 text-body-small outline-none placeholder:font-normal placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
77
+ className,
78
+ )}
79
+ {...props}
80
+ />
81
+ </div>
82
+ );
83
+ }
84
+
85
+ export type ComboboxContentProps = React.ComponentProps<
86
+ typeof ComboboxPrimitive.Popup
87
+ >;
88
+
89
+ function ComboboxContent({
90
+ className,
91
+ children,
92
+ ...props
93
+ }: ComboboxContentProps) {
94
+ return (
95
+ <ComboboxPrimitive.Portal>
96
+ <ComboboxPrimitive.Positioner sideOffset={4} align="start">
97
+ <ComboboxPrimitive.Popup
98
+ data-slot="combobox-content"
99
+ className={cn(
100
+ "relative z-50 max-h-[var(--available-height)] min-w-[8rem] overflow-hidden border bg-popover text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[ending-style]:animate-out data-[ending-style]:fade-out-0 data-[ending-style]:zoom-out-95 data-[open]:animate-in data-[open]:fade-in-0 data-[open]:zoom-in-95",
101
+ className,
102
+ )}
103
+ {...props}
104
+ >
105
+ {children}
106
+ </ComboboxPrimitive.Popup>
107
+ </ComboboxPrimitive.Positioner>
108
+ </ComboboxPrimitive.Portal>
109
+ );
110
+ }
111
+
112
+ export type ComboboxListProps = React.ComponentProps<
113
+ typeof ComboboxPrimitive.List
114
+ >;
115
+
116
+ function ComboboxList({ className, ...props }: ComboboxListProps) {
117
+ return (
118
+ <ComboboxPrimitive.List
119
+ data-slot="combobox-list"
120
+ className={cn(
121
+ "max-h-[min(var(--available-height),18rem)] overflow-y-auto p-1",
122
+ className,
123
+ )}
124
+ {...props}
125
+ />
126
+ );
127
+ }
128
+
129
+ export type ComboboxItemProps = React.ComponentProps<
130
+ typeof ComboboxPrimitive.Item
131
+ >;
132
+
133
+ function ComboboxItem({ className, children, ...props }: ComboboxItemProps) {
134
+ return (
135
+ <ComboboxPrimitive.Item
136
+ data-slot="combobox-item"
137
+ className={cn(
138
+ "relative flex w-full cursor-default items-center gap-2 py-1.5 pr-8 pl-2 text-body-small outline-hidden select-none data-highlighted:bg-primary/5 data-highlighted:text-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
139
+ className,
140
+ )}
141
+ {...props}
142
+ >
143
+ <span
144
+ data-slot="combobox-item-indicator"
145
+ className="absolute right-2 flex size-3.5 items-center justify-center"
146
+ >
147
+ <ComboboxPrimitive.ItemIndicator>
148
+ <CheckIcon className="size-4" />
149
+ </ComboboxPrimitive.ItemIndicator>
150
+ </span>
151
+ {children}
152
+ </ComboboxPrimitive.Item>
153
+ );
154
+ }
155
+
156
+ export type ComboboxEmptyProps = React.ComponentProps<
157
+ typeof ComboboxPrimitive.Empty
158
+ >;
159
+
160
+ function ComboboxEmpty({ className, ...props }: ComboboxEmptyProps) {
161
+ return (
162
+ <ComboboxPrimitive.Empty
163
+ data-slot="combobox-empty"
164
+ className={cn(
165
+ "text-body-small py-6 text-center text-muted-foreground empty:hidden",
166
+ className,
167
+ )}
168
+ {...props}
169
+ />
170
+ );
171
+ }
172
+
173
+ export type ComboboxGroupProps = React.ComponentProps<
174
+ typeof ComboboxPrimitive.Group
175
+ >;
176
+
177
+ function ComboboxGroup({ ...props }: ComboboxGroupProps) {
178
+ return <ComboboxPrimitive.Group data-slot="combobox-group" {...props} />;
179
+ }
180
+
181
+ export type ComboboxGroupLabelProps = React.ComponentProps<
182
+ typeof ComboboxPrimitive.GroupLabel
183
+ >;
184
+
185
+ function ComboboxGroupLabel({ className, ...props }: ComboboxGroupLabelProps) {
186
+ return (
187
+ <ComboboxPrimitive.GroupLabel
188
+ data-slot="combobox-group-label"
189
+ className={cn(
190
+ "text-label-small px-2 py-1.5 uppercase text-muted-foreground",
191
+ className,
192
+ )}
193
+ {...props}
194
+ />
195
+ );
196
+ }
197
+
198
+ export type ComboboxSeparatorProps = React.ComponentProps<"div">;
199
+
200
+ function ComboboxSeparator({ className, ...props }: ComboboxSeparatorProps) {
201
+ return (
202
+ <div
203
+ role="separator"
204
+ data-slot="combobox-separator"
205
+ className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)}
206
+ {...props}
207
+ />
208
+ );
209
+ }
210
+
211
+ export {
212
+ Combobox,
213
+ ComboboxTrigger,
214
+ ComboboxValue,
215
+ ComboboxInput,
216
+ ComboboxContent,
217
+ ComboboxList,
218
+ ComboboxItem,
219
+ ComboboxEmpty,
220
+ ComboboxGroup,
221
+ ComboboxGroupLabel,
222
+ ComboboxSeparator,
223
+ };