@parto-system-design/ui 1.1.4 → 1.1.7

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 (302) hide show
  1. package/AGENTS.md +233 -0
  2. package/LICENSE +21 -0
  3. package/README.md +96 -43
  4. package/dist/chunk-2UD3LGVX.cjs +316 -0
  5. package/dist/chunk-2UD3LGVX.cjs.map +1 -0
  6. package/dist/chunk-34JUCX2G.cjs +43 -0
  7. package/dist/chunk-34JUCX2G.cjs.map +1 -0
  8. package/dist/chunk-3AIJKXBV.cjs +242 -0
  9. package/dist/chunk-3AIJKXBV.cjs.map +1 -0
  10. package/dist/chunk-4SVQNEVH.js +173 -0
  11. package/dist/chunk-4SVQNEVH.js.map +1 -0
  12. package/dist/chunk-53QY4PD3.js +908 -0
  13. package/dist/chunk-53QY4PD3.js.map +1 -0
  14. package/dist/chunk-5JJSRGJD.js +31 -0
  15. package/dist/chunk-5JJSRGJD.js.map +1 -0
  16. package/dist/chunk-5K6E4ZSW.cjs +77 -0
  17. package/dist/chunk-5K6E4ZSW.cjs.map +1 -0
  18. package/dist/chunk-5NY26ULO.js +89 -0
  19. package/dist/chunk-5NY26ULO.js.map +1 -0
  20. package/dist/chunk-7RVPG3LE.cjs +231 -0
  21. package/dist/chunk-7RVPG3LE.cjs.map +1 -0
  22. package/dist/chunk-7Y4V3R3Y.cjs +120 -0
  23. package/dist/chunk-7Y4V3R3Y.cjs.map +1 -0
  24. package/dist/chunk-AXAY64KL.js +39 -0
  25. package/dist/chunk-AXAY64KL.js.map +1 -0
  26. package/dist/chunk-AYEK3WOM.js +207 -0
  27. package/dist/chunk-AYEK3WOM.js.map +1 -0
  28. package/dist/chunk-BRMBLIQG.js +53 -0
  29. package/dist/chunk-BRMBLIQG.js.map +1 -0
  30. package/dist/chunk-CAJKSTXX.cjs +54 -0
  31. package/dist/chunk-CAJKSTXX.cjs.map +1 -0
  32. package/dist/chunk-CKFWMHQU.js +401 -0
  33. package/dist/chunk-CKFWMHQU.js.map +1 -0
  34. package/dist/chunk-CV3N3HVK.js +672 -0
  35. package/dist/chunk-CV3N3HVK.js.map +1 -0
  36. package/dist/chunk-D2EBLE2B.cjs +220 -0
  37. package/dist/chunk-D2EBLE2B.cjs.map +1 -0
  38. package/dist/chunk-D5XCQDFS.js +92 -0
  39. package/dist/chunk-D5XCQDFS.js.map +1 -0
  40. package/dist/chunk-GDHRYKVM.js +45 -0
  41. package/dist/chunk-GDHRYKVM.js.map +1 -0
  42. package/dist/chunk-GKRAZGDI.cjs +84 -0
  43. package/dist/chunk-GKRAZGDI.cjs.map +1 -0
  44. package/dist/chunk-HEYMLQOV.cjs +94 -0
  45. package/dist/chunk-HEYMLQOV.cjs.map +1 -0
  46. package/dist/chunk-HF6XU5NI.js +84 -0
  47. package/dist/chunk-HF6XU5NI.js.map +1 -0
  48. package/dist/chunk-HJPDZOMJ.cjs +87 -0
  49. package/dist/chunk-HJPDZOMJ.cjs.map +1 -0
  50. package/dist/chunk-HUCC3QH5.cjs +53 -0
  51. package/dist/chunk-HUCC3QH5.cjs.map +1 -0
  52. package/dist/chunk-HYZ6BQPS.cjs +425 -0
  53. package/dist/chunk-HYZ6BQPS.cjs.map +1 -0
  54. package/dist/chunk-IQHKJ4SS.js +213 -0
  55. package/dist/chunk-IQHKJ4SS.js.map +1 -0
  56. package/dist/chunk-ISCSZMYW.cjs +106 -0
  57. package/dist/chunk-ISCSZMYW.cjs.map +1 -0
  58. package/dist/chunk-IXFEFIDO.js +82 -0
  59. package/dist/chunk-IXFEFIDO.js.map +1 -0
  60. package/dist/chunk-JUBHQAA2.js +53 -0
  61. package/dist/chunk-JUBHQAA2.js.map +1 -0
  62. package/dist/chunk-KCWRCSI7.js +62 -0
  63. package/dist/chunk-KCWRCSI7.js.map +1 -0
  64. package/dist/chunk-L2L5CKC2.js +291 -0
  65. package/dist/chunk-L2L5CKC2.js.map +1 -0
  66. package/dist/chunk-LLJR7FV3.js +135 -0
  67. package/dist/chunk-LLJR7FV3.js.map +1 -0
  68. package/dist/chunk-LZMCMZZF.js +118 -0
  69. package/dist/chunk-LZMCMZZF.js.map +1 -0
  70. package/dist/chunk-M5CHZ5BA.js +124 -0
  71. package/dist/chunk-M5CHZ5BA.js.map +1 -0
  72. package/dist/chunk-MBCTRNTG.js +89 -0
  73. package/dist/chunk-MBCTRNTG.js.map +1 -0
  74. package/dist/chunk-MEK4RSGC.js +65 -0
  75. package/dist/chunk-MEK4RSGC.js.map +1 -0
  76. package/dist/chunk-MFTX2DDQ.js +27 -0
  77. package/dist/chunk-MFTX2DDQ.js.map +1 -0
  78. package/dist/chunk-MKYVQQBV.cjs +114 -0
  79. package/dist/chunk-MKYVQQBV.cjs.map +1 -0
  80. package/dist/chunk-MQGQVI3W.cjs +950 -0
  81. package/dist/chunk-MQGQVI3W.cjs.map +1 -0
  82. package/dist/chunk-NEFZJHE4.cjs +157 -0
  83. package/dist/chunk-NEFZJHE4.cjs.map +1 -0
  84. package/dist/chunk-NEML6RCV.js +405 -0
  85. package/dist/chunk-NEML6RCV.js.map +1 -0
  86. package/dist/chunk-NV4JOKWL.cjs +197 -0
  87. package/dist/chunk-NV4JOKWL.cjs.map +1 -0
  88. package/dist/chunk-O2JG7WY5.cjs +121 -0
  89. package/dist/chunk-O2JG7WY5.cjs.map +1 -0
  90. package/dist/chunk-OEVMKFFL.cjs +140 -0
  91. package/dist/chunk-OEVMKFFL.cjs.map +1 -0
  92. package/dist/chunk-ONO2FTV4.cjs +68 -0
  93. package/dist/chunk-ONO2FTV4.cjs.map +1 -0
  94. package/dist/chunk-OS6CMYAS.cjs +79 -0
  95. package/dist/chunk-OS6CMYAS.cjs.map +1 -0
  96. package/dist/chunk-P5XHPNJG.cjs +430 -0
  97. package/dist/chunk-P5XHPNJG.cjs.map +1 -0
  98. package/dist/chunk-QJ7UB2ZQ.js +98 -0
  99. package/dist/chunk-QJ7UB2ZQ.js.map +1 -0
  100. package/dist/chunk-RA5KZNG5.js +269 -0
  101. package/dist/chunk-RA5KZNG5.js.map +1 -0
  102. package/dist/chunk-RJ3HYZ7S.js +44 -0
  103. package/dist/chunk-RJ3HYZ7S.js.map +1 -0
  104. package/dist/chunk-RZNRIOLT.js +128 -0
  105. package/dist/chunk-RZNRIOLT.js.map +1 -0
  106. package/dist/chunk-S5IPJQZ3.cjs +161 -0
  107. package/dist/chunk-S5IPJQZ3.cjs.map +1 -0
  108. package/dist/chunk-SB5DSYR5.js +211 -0
  109. package/dist/chunk-SB5DSYR5.js.map +1 -0
  110. package/dist/chunk-SCGW2BH4.cjs +69 -0
  111. package/dist/chunk-SCGW2BH4.cjs.map +1 -0
  112. package/dist/chunk-SCX6AR53.cjs +108 -0
  113. package/dist/chunk-SCX6AR53.cjs.map +1 -0
  114. package/dist/chunk-SFXV2DUH.js +106 -0
  115. package/dist/chunk-SFXV2DUH.js.map +1 -0
  116. package/dist/chunk-SXEPGD4Z.cjs +152 -0
  117. package/dist/chunk-SXEPGD4Z.cjs.map +1 -0
  118. package/dist/chunk-SZMVOHT7.cjs +107 -0
  119. package/dist/chunk-SZMVOHT7.cjs.map +1 -0
  120. package/dist/chunk-U5FLLCGC.cjs +151 -0
  121. package/dist/chunk-U5FLLCGC.cjs.map +1 -0
  122. package/dist/chunk-VO3B75F6.cjs +111 -0
  123. package/dist/chunk-VO3B75F6.cjs.map +1 -0
  124. package/dist/chunk-YAJWTNOX.js +106 -0
  125. package/dist/chunk-YAJWTNOX.js.map +1 -0
  126. package/dist/chunk-YC5KLN6I.js +139 -0
  127. package/dist/chunk-YC5KLN6I.js.map +1 -0
  128. package/dist/chunk-YE477L2H.cjs +272 -0
  129. package/dist/chunk-YE477L2H.cjs.map +1 -0
  130. package/dist/chunk-Z2TY4A75.cjs +700 -0
  131. package/dist/chunk-Z2TY4A75.cjs.map +1 -0
  132. package/dist/chunk-Z56O7UEU.cjs +136 -0
  133. package/dist/chunk-Z56O7UEU.cjs.map +1 -0
  134. package/dist/chunk-ZZFNJR2E.js +71 -0
  135. package/dist/chunk-ZZFNJR2E.js.map +1 -0
  136. package/dist/components/charts/PartoAreaChart.cjs +15 -0
  137. package/dist/components/charts/PartoAreaChart.cjs.map +1 -0
  138. package/dist/components/charts/PartoAreaChart.d.cts +51 -0
  139. package/dist/components/charts/PartoAreaChart.d.ts +51 -0
  140. package/dist/components/charts/PartoAreaChart.js +6 -0
  141. package/dist/components/charts/PartoAreaChart.js.map +1 -0
  142. package/dist/components/charts/PartoBarChart.cjs +15 -0
  143. package/dist/components/charts/PartoBarChart.cjs.map +1 -0
  144. package/dist/components/charts/PartoBarChart.d.cts +55 -0
  145. package/dist/components/charts/PartoBarChart.d.ts +55 -0
  146. package/dist/components/charts/PartoBarChart.js +6 -0
  147. package/dist/components/charts/PartoBarChart.js.map +1 -0
  148. package/dist/components/charts/PartoLineChart.cjs +15 -0
  149. package/dist/components/charts/PartoLineChart.cjs.map +1 -0
  150. package/dist/components/charts/PartoLineChart.d.cts +49 -0
  151. package/dist/components/charts/PartoLineChart.d.ts +49 -0
  152. package/dist/components/charts/PartoLineChart.js +6 -0
  153. package/dist/components/charts/PartoLineChart.js.map +1 -0
  154. package/dist/components/charts/PartoPieChart.cjs +15 -0
  155. package/dist/components/charts/PartoPieChart.cjs.map +1 -0
  156. package/dist/components/charts/PartoPieChart.d.cts +44 -0
  157. package/dist/components/charts/PartoPieChart.d.ts +44 -0
  158. package/dist/components/charts/PartoPieChart.js +6 -0
  159. package/dist/components/charts/PartoPieChart.js.map +1 -0
  160. package/dist/components/ui/alert-rule-card.cjs +15 -0
  161. package/dist/components/ui/alert-rule-card.cjs.map +1 -0
  162. package/dist/components/ui/alert-rule-card.d.cts +38 -0
  163. package/dist/components/ui/alert-rule-card.d.ts +38 -0
  164. package/dist/components/ui/alert-rule-card.js +6 -0
  165. package/dist/components/ui/alert-rule-card.js.map +1 -0
  166. package/dist/components/ui/avatar.cjs +21 -0
  167. package/dist/components/ui/avatar.cjs.map +1 -0
  168. package/dist/components/ui/avatar.d.cts +18 -0
  169. package/dist/components/ui/avatar.d.ts +18 -0
  170. package/dist/components/ui/avatar.js +4 -0
  171. package/dist/components/ui/avatar.js.map +1 -0
  172. package/dist/components/ui/badge.cjs +17 -0
  173. package/dist/components/ui/badge.cjs.map +1 -0
  174. package/dist/components/ui/badge.d.cts +16 -0
  175. package/dist/components/ui/badge.d.ts +16 -0
  176. package/dist/components/ui/badge.js +4 -0
  177. package/dist/components/ui/badge.js.map +1 -0
  178. package/dist/components/ui/button.cjs +18 -0
  179. package/dist/components/ui/button.cjs.map +1 -0
  180. package/dist/components/ui/button.d.cts +37 -0
  181. package/dist/components/ui/button.d.ts +37 -0
  182. package/dist/components/ui/button.js +5 -0
  183. package/dist/components/ui/button.js.map +1 -0
  184. package/dist/components/ui/calendar.cjs +15 -0
  185. package/dist/components/ui/calendar.cjs.map +1 -0
  186. package/dist/components/ui/calendar.d.cts +17 -0
  187. package/dist/components/ui/calendar.d.ts +17 -0
  188. package/dist/components/ui/calendar.js +6 -0
  189. package/dist/components/ui/calendar.js.map +1 -0
  190. package/dist/components/ui/card.cjs +37 -0
  191. package/dist/components/ui/card.cjs.map +1 -0
  192. package/dist/components/ui/card.d.cts +18 -0
  193. package/dist/components/ui/card.d.ts +18 -0
  194. package/dist/components/ui/card.js +4 -0
  195. package/dist/components/ui/card.js.map +1 -0
  196. package/dist/components/ui/concept-card.cjs +18 -0
  197. package/dist/components/ui/concept-card.cjs.map +1 -0
  198. package/dist/components/ui/concept-card.d.cts +5 -0
  199. package/dist/components/ui/concept-card.d.ts +5 -0
  200. package/dist/components/ui/concept-card.js +9 -0
  201. package/dist/components/ui/concept-card.js.map +1 -0
  202. package/dist/components/ui/data-table.cjs +18 -0
  203. package/dist/components/ui/data-table.cjs.map +1 -0
  204. package/dist/components/ui/data-table.d.cts +181 -0
  205. package/dist/components/ui/data-table.d.ts +181 -0
  206. package/dist/components/ui/data-table.js +9 -0
  207. package/dist/components/ui/data-table.js.map +1 -0
  208. package/dist/components/ui/dialog.cjs +49 -0
  209. package/dist/components/ui/dialog.cjs.map +1 -0
  210. package/dist/components/ui/dialog.d.cts +22 -0
  211. package/dist/components/ui/dialog.d.ts +22 -0
  212. package/dist/components/ui/dialog.js +4 -0
  213. package/dist/components/ui/dialog.js.map +1 -0
  214. package/dist/components/ui/filter-provider.cjs +20 -0
  215. package/dist/components/ui/filter-provider.cjs.map +1 -0
  216. package/dist/components/ui/filter-provider.d.cts +49 -0
  217. package/dist/components/ui/filter-provider.d.ts +49 -0
  218. package/dist/components/ui/filter-provider.js +3 -0
  219. package/dist/components/ui/filter-provider.js.map +1 -0
  220. package/dist/components/ui/input.cjs +22 -0
  221. package/dist/components/ui/input.cjs.map +1 -0
  222. package/dist/components/ui/input.d.cts +16 -0
  223. package/dist/components/ui/input.d.ts +16 -0
  224. package/dist/components/ui/input.js +5 -0
  225. package/dist/components/ui/input.js.map +1 -0
  226. package/dist/components/ui/iran-province-heat.cjs +13 -0
  227. package/dist/components/ui/iran-province-heat.cjs.map +1 -0
  228. package/dist/components/ui/iran-province-heat.d.cts +64 -0
  229. package/dist/components/ui/iran-province-heat.d.ts +64 -0
  230. package/dist/components/ui/iran-province-heat.js +4 -0
  231. package/dist/components/ui/iran-province-heat.js.map +1 -0
  232. package/dist/components/ui/page-card.cjs +16 -0
  233. package/dist/components/ui/page-card.cjs.map +1 -0
  234. package/dist/components/ui/page-card.d.cts +6 -0
  235. package/dist/components/ui/page-card.d.ts +6 -0
  236. package/dist/components/ui/page-card.js +7 -0
  237. package/dist/components/ui/page-card.js.map +1 -0
  238. package/dist/components/ui/popover.cjs +25 -0
  239. package/dist/components/ui/popover.cjs.map +1 -0
  240. package/dist/components/ui/popover.d.cts +9 -0
  241. package/dist/components/ui/popover.d.ts +9 -0
  242. package/dist/components/ui/popover.js +4 -0
  243. package/dist/components/ui/popover.js.map +1 -0
  244. package/dist/components/ui/saved-query-card.cjs +15 -0
  245. package/dist/components/ui/saved-query-card.cjs.map +1 -0
  246. package/dist/components/ui/saved-query-card.d.cts +41 -0
  247. package/dist/components/ui/saved-query-card.d.ts +41 -0
  248. package/dist/components/ui/saved-query-card.js +6 -0
  249. package/dist/components/ui/saved-query-card.js.map +1 -0
  250. package/dist/components/ui/separator.cjs +13 -0
  251. package/dist/components/ui/separator.cjs.map +1 -0
  252. package/dist/components/ui/separator.d.cts +9 -0
  253. package/dist/components/ui/separator.d.ts +9 -0
  254. package/dist/components/ui/separator.js +4 -0
  255. package/dist/components/ui/separator.js.map +1 -0
  256. package/dist/components/ui/sheet.cjs +45 -0
  257. package/dist/components/ui/sheet.cjs.map +1 -0
  258. package/dist/components/ui/sheet.d.cts +44 -0
  259. package/dist/components/ui/sheet.d.ts +44 -0
  260. package/dist/components/ui/sheet.js +4 -0
  261. package/dist/components/ui/sheet.js.map +1 -0
  262. package/dist/components/ui/sparkline.cjs +13 -0
  263. package/dist/components/ui/sparkline.cjs.map +1 -0
  264. package/dist/components/ui/sparkline.d.cts +36 -0
  265. package/dist/components/ui/sparkline.d.ts +36 -0
  266. package/dist/components/ui/sparkline.js +4 -0
  267. package/dist/components/ui/sparkline.js.map +1 -0
  268. package/dist/components/ui/tooltip.cjs +25 -0
  269. package/dist/components/ui/tooltip.cjs.map +1 -0
  270. package/dist/components/ui/tooltip.d.cts +17 -0
  271. package/dist/components/ui/tooltip.d.ts +17 -0
  272. package/dist/components/ui/tooltip.js +4 -0
  273. package/dist/components/ui/tooltip.js.map +1 -0
  274. package/dist/concept-card-CcOBb2Nz.d.ts +83 -0
  275. package/dist/concept-card-RwPbqJ06.d.cts +83 -0
  276. package/dist/hooks/use-hotkey-registry.cjs +21 -0
  277. package/dist/hooks/use-hotkey-registry.cjs.map +1 -0
  278. package/dist/hooks/use-hotkey-registry.d.cts +65 -0
  279. package/dist/hooks/use-hotkey-registry.d.ts +65 -0
  280. package/dist/hooks/use-hotkey-registry.js +4 -0
  281. package/dist/hooks/use-hotkey-registry.js.map +1 -0
  282. package/dist/hooks/use-hotkeys.cjs +16 -0
  283. package/dist/hooks/use-hotkeys.cjs.map +1 -0
  284. package/dist/hooks/use-hotkeys.d.cts +66 -0
  285. package/dist/hooks/use-hotkeys.d.ts +66 -0
  286. package/dist/hooks/use-hotkeys.js +3 -0
  287. package/dist/hooks/use-hotkeys.js.map +1 -0
  288. package/dist/i18n-ArS3mqj0.d.ts +344 -0
  289. package/dist/i18n-CAd9wGOr.d.cts +344 -0
  290. package/dist/index.cjs +16630 -10326
  291. package/dist/index.cjs.map +1 -1
  292. package/dist/index.css +910 -119
  293. package/dist/index.d.cts +3177 -844
  294. package/dist/index.d.ts +3177 -844
  295. package/dist/index.js +14211 -8649
  296. package/dist/index.js.map +1 -1
  297. package/dist/page-card-CO92oXkc.d.ts +100 -0
  298. package/dist/page-card-DOl50DqJ.d.cts +100 -0
  299. package/dist/utils-DlXWmDZ-.d.cts +35 -0
  300. package/dist/utils-DlXWmDZ-.d.ts +35 -0
  301. package/package.json +160 -4
  302. package/tailwind.config.ts +61 -2
@@ -0,0 +1,242 @@
1
+ 'use strict';
2
+
3
+ var chunkD2EBLE2B_cjs = require('./chunk-D2EBLE2B.cjs');
4
+ var chunkNV4JOKWL_cjs = require('./chunk-NV4JOKWL.cjs');
5
+ var React = require('react');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n.default = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
27
+
28
+ function useRootStyles() {
29
+ const [version, setVersion] = React.useState(0);
30
+ React.useEffect(() => {
31
+ if (typeof window === "undefined" || !document?.documentElement) {
32
+ return;
33
+ }
34
+ const target = document.documentElement;
35
+ const observer = new MutationObserver(() => {
36
+ setVersion((prev) => prev + 1);
37
+ });
38
+ observer.observe(target, {
39
+ attributes: true,
40
+ attributeFilter: ["class", "data-theme"]
41
+ });
42
+ const media = window.matchMedia("(prefers-color-scheme: dark)");
43
+ const mediaHandler = () => setVersion((prev) => prev + 1);
44
+ media.addEventListener("change", mediaHandler);
45
+ return () => {
46
+ observer.disconnect();
47
+ media.removeEventListener("change", mediaHandler);
48
+ };
49
+ }, []);
50
+ return React.useMemo(() => {
51
+ if (typeof window === "undefined" || !document?.documentElement) {
52
+ return null;
53
+ }
54
+ return getComputedStyle(document.documentElement);
55
+ }, [version]);
56
+ }
57
+
58
+ // src/lib/theme.ts
59
+ var COLOR_VALUE_REGEX = /^(#|rgb|hsl|oklch)/i;
60
+ function resolveCssColor(styles, variable, fallback) {
61
+ if (!styles) return fallback;
62
+ const raw = styles.getPropertyValue(variable).trim();
63
+ if (!raw) return fallback;
64
+ if (COLOR_VALUE_REGEX.test(raw)) return raw;
65
+ if (raw.includes("%")) return `hsl(${raw})`;
66
+ return raw;
67
+ }
68
+
69
+ // src/hooks/use-chart-theme.ts
70
+ var FALLBACKS = {
71
+ foregroundMuted: "hsl(0 0% 50%)",
72
+ border: "hsl(0 0% 22%)",
73
+ popover: "hsl(0 0% 10%)",
74
+ popoverForeground: "hsl(0 0% 98%)",
75
+ chart1: "hsl(153 55% 42%)",
76
+ chart2: "hsl(198 50% 48%)",
77
+ chart3: "hsl(240 40% 54%)",
78
+ chart4: "hsl(310 38% 52%)",
79
+ chart5: "hsl(355 45% 52%)",
80
+ chart6: "hsl(35 52% 48%)",
81
+ chart7: "hsl(75 38% 46%)",
82
+ chart8: "hsl(118 35% 46%)"
83
+ };
84
+ var CHART_FONT_FAMILY = "Yekan Bakh, system-ui, -apple-system, sans-serif";
85
+ function useChartTheme() {
86
+ const styles = useRootStyles();
87
+ return React__namespace.useMemo(() => {
88
+ const getColor = (variable, fallback) => resolveCssColor(styles, variable, fallback);
89
+ const chartColors = [
90
+ getColor("--chart-1", FALLBACKS.chart1),
91
+ getColor("--chart-2", FALLBACKS.chart2),
92
+ getColor("--chart-3", FALLBACKS.chart3),
93
+ getColor("--chart-4", FALLBACKS.chart4),
94
+ getColor("--chart-5", FALLBACKS.chart5),
95
+ getColor("--chart-6", FALLBACKS.chart6),
96
+ getColor("--chart-7", FALLBACKS.chart7),
97
+ getColor("--chart-8", FALLBACKS.chart8)
98
+ ];
99
+ const axisTickStyle = {
100
+ fontFamily: CHART_FONT_FAMILY,
101
+ fill: getColor("--foreground-lighter", FALLBACKS.foregroundMuted),
102
+ fontSize: 11,
103
+ fontWeight: 400
104
+ };
105
+ const gridStyle = {
106
+ stroke: getColor("--border", FALLBACKS.border),
107
+ strokeDasharray: "3 3",
108
+ strokeOpacity: 0.15
109
+ };
110
+ const tooltipStyle = {
111
+ fontFamily: CHART_FONT_FAMILY,
112
+ background: getColor("--background-overlay-default", FALLBACKS.popover),
113
+ color: getColor("--foreground-default", FALLBACKS.popoverForeground),
114
+ fontSize: 12,
115
+ lineHeight: "1.5",
116
+ borderRadius: "10px",
117
+ border: `1px solid ${getColor("--border-muted", FALLBACKS.border)}`,
118
+ boxShadow: "0 4px 24px -4px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.06)",
119
+ padding: "10px 14px",
120
+ backdropFilter: "blur(8px)",
121
+ WebkitBackdropFilter: "blur(8px)"
122
+ };
123
+ const crosshairStyle = {
124
+ stroke: getColor("--foreground-muted", FALLBACKS.foregroundMuted),
125
+ strokeWidth: 1,
126
+ strokeDasharray: "4 4",
127
+ strokeOpacity: 0.5
128
+ };
129
+ return {
130
+ chartColors,
131
+ getColor,
132
+ fontFamily: CHART_FONT_FAMILY,
133
+ axisTickStyle,
134
+ gridStyle,
135
+ tooltipStyle,
136
+ crosshairStyle
137
+ };
138
+ }, [styles]);
139
+ }
140
+ var ChartContainer = React__namespace.forwardRef(
141
+ ({ className, dataSlot, ariaLabel, children }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
142
+ "div",
143
+ {
144
+ ref,
145
+ className,
146
+ dir: "ltr",
147
+ "data-slot": dataSlot,
148
+ role: "img",
149
+ "aria-label": ariaLabel ?? "\u0646\u0645\u0648\u062F\u0627\u0631",
150
+ style: { position: "relative", width: "100%", height: "100%" },
151
+ children
152
+ }
153
+ )
154
+ );
155
+ ChartContainer.displayName = "ChartContainer";
156
+ function ChartLoadingSkeleton({ className, shape = "rect" }) {
157
+ return /* @__PURE__ */ jsxRuntime.jsx(
158
+ "div",
159
+ {
160
+ "data-slot": "chart-loading-skeleton",
161
+ className,
162
+ dir: "ltr",
163
+ style: { position: "relative", width: "100%", height: "100%" },
164
+ role: "status",
165
+ "aria-label": "Loading chart",
166
+ children: /* @__PURE__ */ jsxRuntime.jsx(
167
+ chunkD2EBLE2B_cjs.Skeleton,
168
+ {
169
+ shape,
170
+ className: shape === "circle" ? "w-full h-full min-h-[200px] aspect-square mx-auto" : "w-full h-full min-h-[200px]"
171
+ }
172
+ )
173
+ }
174
+ );
175
+ }
176
+ var LOCALE_TO_BCP47 = {
177
+ fa: "fa-IR",
178
+ ar: "ar",
179
+ en: "en-US"
180
+ };
181
+ function ChartTooltip({ active, payload, label, tooltipStyle, formatter, locale = "fa" }) {
182
+ if (!active || !payload?.length) return null;
183
+ const bcp47 = LOCALE_TO_BCP47[locale] ?? "fa-IR";
184
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "chart-tooltip", style: tooltipStyle, children: [
185
+ label && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 500, fontSize: 13, marginBottom: 6 }, children: label }),
186
+ payload.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: i > 0 ? 4 : 0 }, children: [
187
+ /* @__PURE__ */ jsxRuntime.jsx(
188
+ "div",
189
+ {
190
+ style: {
191
+ width: 10,
192
+ height: 10,
193
+ borderRadius: 2,
194
+ backgroundColor: entry.color,
195
+ flexShrink: 0
196
+ }
197
+ }
198
+ ),
199
+ formatter ? formatter(entry.name, entry.value) : /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", justifyContent: "space-between", width: "100%", gap: 16 }, children: [
200
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { opacity: 0.7 }, children: entry.name }),
201
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, fontVariantNumeric: "tabular-nums" }, children: typeof entry.value === "number" ? entry.value.toLocaleString(bcp47) : entry.value })
202
+ ] })
203
+ ] }, i))
204
+ ] });
205
+ }
206
+ function localeAwareNumberTick(locale) {
207
+ return (value) => {
208
+ if (typeof value === "number") return chunkNV4JOKWL_cjs.formatLargeNumber(value, locale);
209
+ if (typeof value === "string") {
210
+ if (/^-?\d+(\.\d+)?$/.test(value)) return chunkNV4JOKWL_cjs.convertToLocalNumbers(value, locale);
211
+ return value;
212
+ }
213
+ return String(value ?? "");
214
+ };
215
+ }
216
+ function localeAwareCategoryTick(locale) {
217
+ return (value) => chunkNV4JOKWL_cjs.convertToLocalNumbers(String(value ?? ""), locale);
218
+ }
219
+ function transformNivoLineData(nivoData) {
220
+ const dataKeys = nivoData.map((s) => s.id);
221
+ const xValues = nivoData[0]?.data.map((d) => d.x) ?? [];
222
+ const data = xValues.map((x, xi) => {
223
+ const row = { name: x };
224
+ for (const series of nivoData) {
225
+ row[series.id] = series.data[xi]?.y ?? 0;
226
+ }
227
+ return row;
228
+ });
229
+ return { data, dataKeys };
230
+ }
231
+
232
+ exports.CHART_FONT_FAMILY = CHART_FONT_FAMILY;
233
+ exports.ChartContainer = ChartContainer;
234
+ exports.ChartLoadingSkeleton = ChartLoadingSkeleton;
235
+ exports.ChartTooltip = ChartTooltip;
236
+ exports.localeAwareCategoryTick = localeAwareCategoryTick;
237
+ exports.localeAwareNumberTick = localeAwareNumberTick;
238
+ exports.transformNivoLineData = transformNivoLineData;
239
+ exports.useChartTheme = useChartTheme;
240
+ exports.useRootStyles = useRootStyles;
241
+ //# sourceMappingURL=chunk-3AIJKXBV.cjs.map
242
+ //# sourceMappingURL=chunk-3AIJKXBV.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/use-root-styles.ts","../src/lib/theme.ts","../src/hooks/use-chart-theme.ts","../src/components/charts/chart-utils.tsx"],"names":["useState","useEffect","useMemo","React","React2","jsx","Skeleton","jsxs","formatLargeNumber","convertToLocalNumbers"],"mappings":"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","file":"chunk-3AIJKXBV.cjs","sourcesContent":["'use client'\n\nimport { useEffect, useMemo, useState } from 'react'\n\n/**\n * Returns a snapshot of the current document root computed styles and\n * re-renders when the theme class or OS color scheme changes.\n */\nexport function useRootStyles() {\n const [version, setVersion] = useState(0)\n\n useEffect(() => {\n if (typeof window === 'undefined' || !document?.documentElement) {\n return\n }\n\n const target = document.documentElement\n const observer = new MutationObserver(() => {\n setVersion((prev) => prev + 1)\n })\n\n observer.observe(target, {\n attributes: true,\n attributeFilter: ['class', 'data-theme'],\n })\n\n const media = window.matchMedia('(prefers-color-scheme: dark)')\n const mediaHandler = () => setVersion((prev) => prev + 1)\n media.addEventListener('change', mediaHandler)\n\n return () => {\n observer.disconnect()\n media.removeEventListener('change', mediaHandler)\n }\n }, [])\n\n return useMemo(() => {\n if (typeof window === 'undefined' || !document?.documentElement) {\n return null\n }\n\n return getComputedStyle(document.documentElement)\n }, [version])\n}\n","const COLOR_VALUE_REGEX = /^(#|rgb|hsl|oklch)/i;\n\nexport function resolveCssColor(\n styles: CSSStyleDeclaration | null,\n variable: string,\n fallback: string,\n) {\n if (!styles) return fallback;\n const raw = styles.getPropertyValue(variable).trim();\n if (!raw) return fallback;\n if (COLOR_VALUE_REGEX.test(raw)) return raw;\n if (raw.includes('%')) return `hsl(${raw})`;\n return raw;\n}\n\n","'use client'\n\nimport * as React from 'react'\nimport { useRootStyles } from './use-root-styles'\nimport { resolveCssColor } from '@/lib/theme'\n\n/**\n * Chart theme hook — reads CSS design tokens at runtime and produces\n * resolved colors and styles for Recharts + Visx chart components.\n * Inspired by Linear, Vercel, and Stripe data visualizations.\n */\n\nconst FALLBACKS = {\n foreground: 'hsl(0 0% 98%)',\n foregroundMuted: 'hsl(0 0% 50%)',\n border: 'hsl(0 0% 22%)',\n popover: 'hsl(0 0% 10%)',\n popoverForeground: 'hsl(0 0% 98%)',\n chart1: 'hsl(153 55% 42%)',\n chart2: 'hsl(198 50% 48%)',\n chart3: 'hsl(240 40% 54%)',\n chart4: 'hsl(310 38% 52%)',\n chart5: 'hsl(355 45% 52%)',\n chart6: 'hsl(35 52% 48%)',\n chart7: 'hsl(75 38% 46%)',\n chart8: 'hsl(118 35% 46%)',\n}\n\nexport const CHART_FONT_FAMILY = 'Yekan Bakh, system-ui, -apple-system, sans-serif'\n\nexport function useChartTheme() {\n const styles = useRootStyles()\n\n return React.useMemo(() => {\n const getColor = (variable: string, fallback: string) => resolveCssColor(styles, variable, fallback)\n\n const chartColors = [\n getColor('--chart-1', FALLBACKS.chart1),\n getColor('--chart-2', FALLBACKS.chart2),\n getColor('--chart-3', FALLBACKS.chart3),\n getColor('--chart-4', FALLBACKS.chart4),\n getColor('--chart-5', FALLBACKS.chart5),\n getColor('--chart-6', FALLBACKS.chart6),\n getColor('--chart-7', FALLBACKS.chart7),\n getColor('--chart-8', FALLBACKS.chart8),\n ]\n\n const axisTickStyle = {\n fontFamily: CHART_FONT_FAMILY,\n fill: getColor('--foreground-lighter', FALLBACKS.foregroundMuted),\n fontSize: 11,\n fontWeight: 400 as const,\n }\n\n const gridStyle = {\n stroke: getColor('--border', FALLBACKS.border),\n strokeDasharray: '3 3',\n strokeOpacity: 0.15,\n }\n\n const tooltipStyle: React.CSSProperties = {\n fontFamily: CHART_FONT_FAMILY,\n background: getColor('--background-overlay-default', FALLBACKS.popover),\n color: getColor('--foreground-default', FALLBACKS.popoverForeground),\n fontSize: 12,\n lineHeight: '1.5',\n borderRadius: '10px',\n border: `1px solid ${getColor('--border-muted', FALLBACKS.border)}`,\n boxShadow: '0 4px 24px -4px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.06)',\n padding: '10px 14px',\n backdropFilter: 'blur(8px)',\n WebkitBackdropFilter: 'blur(8px)',\n }\n\n const crosshairStyle = {\n stroke: getColor('--foreground-muted', FALLBACKS.foregroundMuted),\n strokeWidth: 1,\n strokeDasharray: '4 4',\n strokeOpacity: 0.5,\n }\n\n return {\n chartColors,\n getColor,\n fontFamily: CHART_FONT_FAMILY,\n axisTickStyle,\n gridStyle,\n tooltipStyle,\n crosshairStyle,\n }\n }, [styles])\n}\n","'use client'\n\nimport * as React from 'react'\nimport { Skeleton } from '@/components/ui/skeleton'\nimport { convertToLocalNumbers, formatLargeNumber, type SupportedLocale } from '@/lib/utils'\n\n// ─── Chart Container ─────────────────────────────────────────────────────────\n\ninterface ChartContainerProps {\n className?: string\n dataSlot: string\n ariaLabel?: string\n children: React.ReactNode\n}\n\nexport const ChartContainer = React.forwardRef<HTMLDivElement, ChartContainerProps>(\n ({ className, dataSlot, ariaLabel, children }, ref) => (\n <div\n ref={ref}\n className={className}\n dir=\"ltr\"\n data-slot={dataSlot}\n role=\"img\"\n aria-label={ariaLabel ?? 'نمودار'}\n style={{ position: 'relative', width: '100%', height: '100%' }}\n >\n {children}\n </div>\n )\n)\nChartContainer.displayName = 'ChartContainer'\n\n// ─── Chart Skeleton ──────────────────────────────────────────────────────────\n\ninterface ChartSkeletonProps {\n className?: string\n shape?: 'rect' | 'circle'\n}\n\nexport function ChartLoadingSkeleton({ className, shape = 'rect' }: ChartSkeletonProps) {\n return (\n <div\n data-slot=\"chart-loading-skeleton\"\n className={className}\n dir=\"ltr\"\n style={{ position: 'relative', width: '100%', height: '100%' }}\n role=\"status\"\n aria-label=\"Loading chart\"\n >\n <Skeleton\n shape={shape}\n className={\n shape === 'circle' ? 'w-full h-full min-h-[200px] aspect-square mx-auto' : 'w-full h-full min-h-[200px]'\n }\n />\n </div>\n )\n}\n\n// ─── Chart Tooltip ───────────────────────────────────────────────────────────\n\ninterface ChartTooltipProps {\n active?: boolean\n payload?: Array<{ name: string; value: number; color: string; dataKey?: string }>\n label?: string\n tooltipStyle: React.CSSProperties\n formatter?: (name: string, value: number) => React.ReactNode\n /** Locale for the default value formatter. fa/ar render Persian/Arabic digits with thousands separators; en uses Latin. */\n locale?: SupportedLocale\n}\n\nconst LOCALE_TO_BCP47: Record<SupportedLocale, string> = {\n fa: 'fa-IR',\n ar: 'ar',\n en: 'en-US',\n}\n\nexport function ChartTooltip({ active, payload, label, tooltipStyle, formatter, locale = 'fa' }: ChartTooltipProps) {\n if (!active || !payload?.length) return null\n\n const bcp47 = LOCALE_TO_BCP47[locale] ?? 'fa-IR'\n\n return (\n <div data-slot=\"chart-tooltip\" style={tooltipStyle}>\n {label && <div style={{ fontWeight: 500, fontSize: 13, marginBottom: 6 }}>{label}</div>}\n {payload.map((entry, i) => (\n <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: i > 0 ? 4 : 0 }}>\n <div\n style={{\n width: 10,\n height: 10,\n borderRadius: 2,\n backgroundColor: entry.color,\n flexShrink: 0,\n }}\n />\n {formatter ? (\n formatter(entry.name, entry.value)\n ) : (\n <span style={{ display: 'flex', justifyContent: 'space-between', width: '100%', gap: 16 }}>\n <span style={{ opacity: 0.7 }}>{entry.name}</span>\n <span style={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>\n {typeof entry.value === 'number' ? entry.value.toLocaleString(bcp47) : entry.value}\n </span>\n </span>\n )}\n </div>\n ))}\n </div>\n )\n}\n\n// ─── Locale-aware tick formatter ─────────────────────────────────────────────\n\n/**\n * Default tickFormatter for numeric chart axes (Y axis on Line/Area/Bar, both\n * axes on Scatter, radial on Radar). Renders Persian/Arabic digits + locale\n * suffix (\"۱.۵ هزار\", \"1.5K\") for fa/ar, Latin K/M/B for en.\n *\n * Pass via `axisLeft={{ tickFormatter: localeAwareNumberTick('fa') }}`, or rely\n * on the chart wrapper's `locale` prop which wires this in by default.\n */\nexport function localeAwareNumberTick(locale: SupportedLocale): (value: unknown) => string {\n return (value) => {\n if (typeof value === 'number') return formatLargeNumber(value, locale)\n if (typeof value === 'string') {\n // Numeric strings: convert digits only (don't touch labels).\n if (/^-?\\d+(\\.\\d+)?$/.test(value)) return convertToLocalNumbers(value, locale)\n return value\n }\n return String(value ?? '')\n }\n}\n\n/**\n * Default tickFormatter for categorical chart axes — converts embedded digits\n * to the locale's numerals (e.g. \"۱۴۰۳-۰۱\" for \"1403-01\") without altering\n * letters. Use on date/time axes whose labels carry digits.\n */\nexport function localeAwareCategoryTick(locale: SupportedLocale): (value: unknown) => string {\n return (value) => convertToLocalNumbers(String(value ?? ''), locale)\n}\n\n// ─── Data Transform Utility ──────────────────────────────────────────────────\n\n/**\n * Transforms Nivo line/area data format to Recharts row-oriented format.\n * Useful for consumers migrating from Nivo data shape.\n *\n * @example\n * // Nivo: [{ id: \"فروش\", data: [{ x: \"فروردین\", y: 50 }] }]\n * // Recharts: [{ name: \"فروردین\", فروش: 50 }]\n */\nexport function transformNivoLineData(\n nivoData: Array<{ id: string; data: Array<{ x: string | number; y: number }> }>\n): { data: Array<Record<string, string | number>>; dataKeys: string[] } {\n const dataKeys = nivoData.map((s) => s.id)\n const xValues = nivoData[0]?.data.map((d) => d.x) ?? []\n\n const data = xValues.map((x, xi) => {\n const row: Record<string, string | number> = { name: x }\n for (const series of nivoData) {\n row[series.id] = series.data[xi]?.y ?? 0\n }\n return row\n })\n\n return { data, dataKeys }\n}\n"]}
@@ -0,0 +1,173 @@
1
+ import { format, getMonth, getYear, getDate, parse } from 'date-fns-jalali';
2
+ import { faIR } from 'date-fns-jalali/locale';
3
+ import { clsx } from 'clsx';
4
+ import { twMerge } from 'tailwind-merge';
5
+
6
+ // src/lib/jalali-utils.ts
7
+ var PERSIAN_MONTHS = [
8
+ "\u0641\u0631\u0648\u0631\u062F\u06CC\u0646",
9
+ "\u0627\u0631\u062F\u06CC\u0628\u0647\u0634\u062A",
10
+ "\u062E\u0631\u062F\u0627\u062F",
11
+ "\u062A\u06CC\u0631",
12
+ "\u0645\u0631\u062F\u0627\u062F",
13
+ "\u0634\u0647\u0631\u06CC\u0648\u0631",
14
+ "\u0645\u0647\u0631",
15
+ "\u0622\u0628\u0627\u0646",
16
+ "\u0622\u0630\u0631",
17
+ "\u062F\u06CC",
18
+ "\u0628\u0647\u0645\u0646",
19
+ "\u0627\u0633\u0641\u0646\u062F"
20
+ ];
21
+ var PERSIAN_MONTHS_SHORT = ["\u0641\u0631\u0648", "\u0627\u0631\u062F", "\u062E\u0631\u062F", "\u062A\u06CC\u0631", "\u0645\u0631\u062F", "\u0634\u0647\u0631", "\u0645\u0647\u0631", "\u0622\u0628\u0627", "\u0622\u0630\u0631", "\u062F\u06CC", "\u0628\u0647\u0645", "\u0627\u0633\u0641"];
22
+ var PERSIAN_WEEKDAYS = ["\u06CC\u06A9\u0634\u0646\u0628\u0647", "\u062F\u0648\u0634\u0646\u0628\u0647", "\u0633\u0647\u200C\u0634\u0646\u0628\u0647", "\u0686\u0647\u0627\u0631\u0634\u0646\u0628\u0647", "\u067E\u0646\u062C\u200C\u0634\u0646\u0628\u0647", "\u062C\u0645\u0639\u0647", "\u0634\u0646\u0628\u0647"];
23
+ var PERSIAN_WEEKDAYS_SHORT = ["\u06CC", "\u062F", "\u0633", "\u0686", "\u067E", "\u062C", "\u0634"];
24
+ function toPersianDigits(num) {
25
+ const persianDigits = ["\u06F0", "\u06F1", "\u06F2", "\u06F3", "\u06F4", "\u06F5", "\u06F6", "\u06F7", "\u06F8", "\u06F9"];
26
+ return String(num).replace(/\d/g, (digit) => persianDigits[parseInt(digit)]);
27
+ }
28
+ function toEnglishDigits(str) {
29
+ const persianDigits = ["\u06F0", "\u06F1", "\u06F2", "\u06F3", "\u06F4", "\u06F5", "\u06F6", "\u06F7", "\u06F8", "\u06F9"];
30
+ const arabicDigits = ["\u0660", "\u0661", "\u0662", "\u0663", "\u0664", "\u0665", "\u0666", "\u0667", "\u0668", "\u0669"];
31
+ return str.replace(/[۰-۹]/g, (digit) => String(persianDigits.indexOf(digit))).replace(/[٠-٩]/g, (digit) => String(arabicDigits.indexOf(digit)));
32
+ }
33
+ function formatJalaliDate(date, formatStr = "yyyy/MM/dd") {
34
+ return format(date, formatStr, { locale: faIR });
35
+ }
36
+ function getPersianMonthName(date) {
37
+ const monthIndex = getMonth(date);
38
+ return PERSIAN_MONTHS[monthIndex];
39
+ }
40
+ function getPersianMonthNameShort(date) {
41
+ const monthIndex = getMonth(date);
42
+ return PERSIAN_MONTHS_SHORT[monthIndex];
43
+ }
44
+ function getPersianWeekdayName(date, short = false) {
45
+ if (short) return format(date, "EEEEE", { locale: faIR });
46
+ return format(date, "EEEE", { locale: faIR });
47
+ }
48
+ function getPersianYear(date) {
49
+ return getYear(date);
50
+ }
51
+ function getPersianMonth(date) {
52
+ return getMonth(date);
53
+ }
54
+ function getPersianDay(date) {
55
+ return getDate(date);
56
+ }
57
+ function jalaliToGregorian(year, month, day) {
58
+ const dateStr = `${year}/${month + 1}/${day}`;
59
+ return parse(dateStr, "yyyy/M/d", /* @__PURE__ */ new Date(), { locale: faIR });
60
+ }
61
+ function formatPersianDateRange(from, to) {
62
+ const fromYear = getYear(from);
63
+ const toYear = getYear(to);
64
+ const fromMonth = getMonth(from);
65
+ const toMonth = getMonth(to);
66
+ const fromDay = getDate(from);
67
+ const toDay = getDate(to);
68
+ if (fromYear === toYear && fromMonth === toMonth && fromDay === toDay) {
69
+ return `${toPersianDigits(fromDay)} ${PERSIAN_MONTHS[fromMonth]} ${toPersianDigits(fromYear)}`;
70
+ }
71
+ if (fromYear === toYear && fromMonth === toMonth) {
72
+ return `${toPersianDigits(fromDay)} - ${toPersianDigits(toDay)} ${PERSIAN_MONTHS[fromMonth]} ${toPersianDigits(fromYear)}`;
73
+ }
74
+ if (fromYear === toYear) {
75
+ return `${toPersianDigits(fromDay)} ${PERSIAN_MONTHS[fromMonth]} - ${toPersianDigits(toDay)} ${PERSIAN_MONTHS[toMonth]} ${toPersianDigits(fromYear)}`;
76
+ }
77
+ return `${toPersianDigits(fromDay)} ${PERSIAN_MONTHS[fromMonth]} ${toPersianDigits(fromYear)} - ${toPersianDigits(toDay)} ${PERSIAN_MONTHS[toMonth]} ${toPersianDigits(toYear)}`;
78
+ }
79
+ function getPersianMonthsForDropdown() {
80
+ return PERSIAN_MONTHS.map((month, index) => ({
81
+ value: index,
82
+ label: month
83
+ }));
84
+ }
85
+ function getPersianYearsForDropdown(fromYear, toYear) {
86
+ const years = [];
87
+ for (let year = fromYear; year <= toYear; year++) {
88
+ years.push({
89
+ value: year,
90
+ label: toPersianDigits(year)
91
+ });
92
+ }
93
+ return years;
94
+ }
95
+ function cn(...inputs) {
96
+ return twMerge(clsx(inputs));
97
+ }
98
+ function convertToLocalNumbers(text, locale) {
99
+ if (locale === "fa" || locale === "ar") {
100
+ const persianDigits = ["\u06F0", "\u06F1", "\u06F2", "\u06F3", "\u06F4", "\u06F5", "\u06F6", "\u06F7", "\u06F8", "\u06F9"];
101
+ return String(text).replace(/\d/g, (digit) => persianDigits[parseInt(digit)]);
102
+ }
103
+ return String(text);
104
+ }
105
+ function formatLargeNumber(num, locale) {
106
+ if (num >= 1e9) {
107
+ const formatted = (num / 1e9).toFixed(1).replace(/\.0$/, "");
108
+ return convertToLocalNumbers(formatted, locale) + (locale === "en" ? "B" : " \u0645\u06CC\u0644\u06CC\u0627\u0631\u062F");
109
+ }
110
+ if (num >= 1e6) {
111
+ const formatted = (num / 1e6).toFixed(1).replace(/\.0$/, "");
112
+ return convertToLocalNumbers(formatted, locale) + (locale === "en" ? "M" : " \u0645\u06CC\u0644\u06CC\u0648\u0646");
113
+ }
114
+ if (num >= 1e3) {
115
+ const formatted = (num / 1e3).toFixed(1).replace(/\.0$/, "");
116
+ return convertToLocalNumbers(formatted, locale) + (locale === "en" ? "K" : " \u0647\u0632\u0627\u0631");
117
+ }
118
+ return convertToLocalNumbers(num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","), locale);
119
+ }
120
+ function formatNumber(num, format2 = "exact") {
121
+ if (num === void 0 || num === null) return "0";
122
+ if (format2 === "exact") {
123
+ return num.toLocaleString("en-US");
124
+ }
125
+ if (num >= 1e9) {
126
+ return `${(num / 1e9).toFixed(1).replace(/\.0$/, "")}B`;
127
+ }
128
+ if (num >= 1e6) {
129
+ return `${(num / 1e6).toFixed(1).replace(/\.0$/, "")}M`;
130
+ }
131
+ if (num >= 1e3) {
132
+ return `${(num / 1e3).toFixed(1).replace(/\.0$/, "")}K`;
133
+ }
134
+ return num.toString();
135
+ }
136
+ function formatRelativeTime(date) {
137
+ const now = /* @__PURE__ */ new Date();
138
+ const then = new Date(date);
139
+ const diffInSeconds = Math.floor((now.getTime() - then.getTime()) / 1e3);
140
+ if (diffInSeconds < 60) {
141
+ return "\u0647\u0645\u06CC\u0646 \u0627\u0644\u0627\u0646";
142
+ }
143
+ const diffInMinutes = Math.floor(diffInSeconds / 60);
144
+ if (diffInMinutes < 60) {
145
+ return `${convertToLocalNumbers(diffInMinutes, "fa")} \u062F\u0642\u06CC\u0642\u0647 \u067E\u06CC\u0634`;
146
+ }
147
+ const diffInHours = Math.floor(diffInMinutes / 60);
148
+ if (diffInHours < 24) {
149
+ return `${convertToLocalNumbers(diffInHours, "fa")} \u0633\u0627\u0639\u062A \u067E\u06CC\u0634`;
150
+ }
151
+ const diffInDays = Math.floor(diffInHours / 24);
152
+ if (diffInDays < 7) {
153
+ return `${convertToLocalNumbers(diffInDays, "fa")} \u0631\u0648\u0632 \u067E\u06CC\u0634`;
154
+ }
155
+ const diffInWeeks = Math.floor(diffInDays / 7);
156
+ if (diffInWeeks < 4) {
157
+ return `${convertToLocalNumbers(diffInWeeks, "fa")} \u0647\u0641\u062A\u0647 \u067E\u06CC\u0634`;
158
+ }
159
+ const diffInMonths = Math.floor(diffInDays / 30);
160
+ if (diffInMonths < 12) {
161
+ return `${convertToLocalNumbers(diffInMonths, "fa")} \u0645\u0627\u0647 \u067E\u06CC\u0634`;
162
+ }
163
+ const diffInYears = Math.floor(diffInDays / 365);
164
+ return `${convertToLocalNumbers(diffInYears, "fa")} \u0633\u0627\u0644 \u067E\u06CC\u0634`;
165
+ }
166
+ function formatAbsoluteTime(date) {
167
+ const d = new Date(date);
168
+ return formatJalaliDate(d, "d MMMM yyyy\u060C HH:mm");
169
+ }
170
+
171
+ export { PERSIAN_MONTHS, PERSIAN_MONTHS_SHORT, PERSIAN_WEEKDAYS, PERSIAN_WEEKDAYS_SHORT, cn, convertToLocalNumbers, formatAbsoluteTime, formatJalaliDate, formatLargeNumber, formatNumber, formatPersianDateRange, formatRelativeTime, getPersianDay, getPersianMonth, getPersianMonthName, getPersianMonthNameShort, getPersianMonthsForDropdown, getPersianWeekdayName, getPersianYear, getPersianYearsForDropdown, jalaliToGregorian, toEnglishDigits, toPersianDigits };
172
+ //# sourceMappingURL=chunk-4SVQNEVH.js.map
173
+ //# sourceMappingURL=chunk-4SVQNEVH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/jalali-utils.ts","../src/lib/utils.ts"],"names":["format"],"mappings":"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","file":"chunk-4SVQNEVH.js","sourcesContent":["/**\n * Persian (Jalali / Solar Hijri) calendar utilities.\n *\n * Backed by **date-fns-jalali** — a Jalali-native fork of date-fns v4.\n * Chosen over moment-jalaali (unmaintained since 2019) because:\n * • Tree-shakeable, zero dependencies\n * • Built-in TypeScript types\n * • Tracks upstream date-fns releases\n * • Built-in fa-IR locale with month/weekday names\n * • ~5-10KB gzipped for typical usage\n *\n * DO NOT replace this library again. This decision was made after\n * evaluating date-fns-jalali, jalaali-js, jalaliday (dayjs), moment-jalaali,\n * and persian-date in April 2026. date-fns-jalali is the clear winner\n * for a design system that needs formatting, parsing, and locale support.\n */\n\nimport { format, getMonth, getDate, getYear, parse } from 'date-fns-jalali'\nimport { faIR } from 'date-fns-jalali/locale'\n\n/**\n * Persian/Farsi month names\n */\nexport const PERSIAN_MONTHS = [\n 'فروردین',\n 'اردیبهشت',\n 'خرداد',\n 'تیر',\n 'مرداد',\n 'شهریور',\n 'مهر',\n 'آبان',\n 'آذر',\n 'دی',\n 'بهمن',\n 'اسفند',\n]\n\n/**\n * Persian/Farsi short month names\n */\nexport const PERSIAN_MONTHS_SHORT = ['فرو', 'ارد', 'خرد', 'تیر', 'مرد', 'شهر', 'مهر', 'آبا', 'آذر', 'دی', 'بهم', 'اسف']\n\n/**\n * Persian/Farsi weekday names\n */\nexport const PERSIAN_WEEKDAYS = ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنج‌شنبه', 'جمعه', 'شنبه']\n\n/**\n * Persian/Farsi short weekday names\n */\nexport const PERSIAN_WEEKDAYS_SHORT = ['ی', 'د', 'س', 'چ', 'پ', 'ج', 'ش']\n\n/**\n * Convert English digits to Persian/Farsi digits\n */\nexport function toPersianDigits(num: number | string): string {\n const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']\n return String(num).replace(/\\d/g, (digit) => persianDigits[parseInt(digit)])\n}\n\n/**\n * Convert Persian/Farsi digits to English digits\n */\nexport function toEnglishDigits(str: string): string {\n const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']\n const arabicDigits = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩']\n\n return str\n .replace(/[۰-۹]/g, (digit) => String(persianDigits.indexOf(digit)))\n .replace(/[٠-٩]/g, (digit) => String(arabicDigits.indexOf(digit)))\n}\n\n/**\n * Format a Date object to Persian/Jalali date string.\n *\n * Uses date-fns-jalali format tokens:\n * yyyy = Jalali year, MM = month (01-12), dd = day (01-31)\n * MMMM = full month name, EEEE = full weekday name\n * HH:mm = 24h time, hh:mm a = 12h time\n */\nexport function formatJalaliDate(date: Date, formatStr: string = 'yyyy/MM/dd'): string {\n return format(date, formatStr, { locale: faIR })\n}\n\n/**\n * Get Persian month name from a Date object\n */\nexport function getPersianMonthName(date: Date): string {\n const monthIndex = getMonth(date)\n return PERSIAN_MONTHS[monthIndex]\n}\n\n/**\n * Get Persian short month name from a Date object\n */\nexport function getPersianMonthNameShort(date: Date): string {\n const monthIndex = getMonth(date)\n return PERSIAN_MONTHS_SHORT[monthIndex]\n}\n\n/**\n * Get Persian weekday name from a Date object\n */\nexport function getPersianWeekdayName(date: Date, short: boolean = false): string {\n if (short) return format(date, 'EEEEE', { locale: faIR })\n return format(date, 'EEEE', { locale: faIR })\n}\n\n/**\n * Get Persian year from a Date object\n */\nexport function getPersianYear(date: Date): number {\n return getYear(date)\n}\n\n/**\n * Get Persian month (0-11) from a Date object\n */\nexport function getPersianMonth(date: Date): number {\n return getMonth(date)\n}\n\n/**\n * Get Persian day from a Date object\n */\nexport function getPersianDay(date: Date): number {\n return getDate(date)\n}\n\n/**\n * Create a Date object from Persian/Jalali date\n */\nexport function jalaliToGregorian(year: number, month: number, day: number): Date {\n const dateStr = `${year}/${month + 1}/${day}`\n return parse(dateStr, 'yyyy/M/d', new Date(), { locale: faIR })\n}\n\n/**\n * Format date range in Persian\n */\nexport function formatPersianDateRange(from: Date, to: Date): string {\n const fromYear = getYear(from)\n const toYear = getYear(to)\n const fromMonth = getMonth(from)\n const toMonth = getMonth(to)\n const fromDay = getDate(from)\n const toDay = getDate(to)\n\n // Same day\n if (fromYear === toYear && fromMonth === toMonth && fromDay === toDay) {\n return `${toPersianDigits(fromDay)} ${PERSIAN_MONTHS[fromMonth]} ${toPersianDigits(fromYear)}`\n }\n\n // Same month and year\n if (fromYear === toYear && fromMonth === toMonth) {\n return `${toPersianDigits(fromDay)} - ${toPersianDigits(toDay)} ${PERSIAN_MONTHS[fromMonth]} ${toPersianDigits(fromYear)}`\n }\n\n // Same year\n if (fromYear === toYear) {\n return `${toPersianDigits(fromDay)} ${PERSIAN_MONTHS[fromMonth]} - ${toPersianDigits(toDay)} ${PERSIAN_MONTHS[toMonth]} ${toPersianDigits(fromYear)}`\n }\n\n // Different years\n return `${toPersianDigits(fromDay)} ${PERSIAN_MONTHS[fromMonth]} ${toPersianDigits(fromYear)} - ${toPersianDigits(toDay)} ${PERSIAN_MONTHS[toMonth]} ${toPersianDigits(toYear)}`\n}\n\n/**\n * Get all months for a dropdown (returns array of {value, label})\n */\nexport function getPersianMonthsForDropdown(): Array<{\n value: number\n label: string\n}> {\n return PERSIAN_MONTHS.map((month, index) => ({\n value: index,\n label: month,\n }))\n}\n\n/**\n * Get years range for a dropdown\n */\nexport function getPersianYearsForDropdown(fromYear: number, toYear: number): Array<{ value: number; label: string }> {\n const years: Array<{ value: number; label: string }> = []\n for (let year = fromYear; year <= toYear; year++) {\n years.push({\n value: year,\n label: toPersianDigits(year),\n })\n }\n return years\n}\n","import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\nimport { formatJalaliDate } from '@/lib/jalali-utils'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport type SupportedLocale = 'fa' | 'ar' | 'en'\n\n/**\n * Convert digits in a string to Persian/Arabic numerals based on locale.\n * @example convertToLocalNumbers('123', 'fa') => '۱۲۳'\n * @example convertToLocalNumbers('123', 'en') => '123'\n */\nexport function convertToLocalNumbers(text: string | number, locale: SupportedLocale): string {\n if (locale === 'fa' || locale === 'ar') {\n const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']\n return String(text).replace(/\\d/g, (digit) => persianDigits[parseInt(digit)])\n }\n return String(text)\n}\n\n/**\n * Format large numbers with locale-aware suffixes (K/M/B).\n * @example formatLargeNumber(1500, 'fa') => '۱.۵ هزار'\n * @example formatLargeNumber(1500, 'en') => '1.5K'\n */\nexport function formatLargeNumber(num: number, locale: SupportedLocale): string {\n if (num >= 1_000_000_000) {\n const formatted = (num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'B' : ' میلیارد')\n }\n if (num >= 1_000_000) {\n const formatted = (num / 1_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'M' : ' میلیون')\n }\n if (num >= 1_000) {\n const formatted = (num / 1_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'K' : ' هزار')\n }\n return convertToLocalNumbers(num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ','), locale)\n}\n\n/**\n * Format number to Instagram-style short format (English only).\n * @example formatNumber(123456, 'short') => '123K'\n * @example formatNumber(123456, 'exact') => '123,456'\n */\nexport function formatNumber(num: number | undefined, format: 'exact' | 'short' = 'exact'): string {\n if (num === undefined || num === null) return '0'\n\n if (format === 'exact') {\n return num.toLocaleString('en-US')\n }\n\n // Short format (Instagram style)\n if (num >= 1_000_000_000) {\n return `${(num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')}B`\n }\n if (num >= 1_000_000) {\n return `${(num / 1_000_000).toFixed(1).replace(/\\.0$/, '')}M`\n }\n if (num >= 1_000) {\n return `${(num / 1_000).toFixed(1).replace(/\\.0$/, '')}K`\n }\n return num.toString()\n}\n\n/**\n * Format date to relative time with absolute on hover (Persian)\n * @example formatRelativeTime(new Date()) => '۲ ساعت پیش'\n */\nexport function formatRelativeTime(date: Date | string | number): string {\n const now = new Date()\n const then = new Date(date)\n const diffInSeconds = Math.floor((now.getTime() - then.getTime()) / 1000)\n\n if (diffInSeconds < 60) {\n return 'همین الان'\n }\n\n const diffInMinutes = Math.floor(diffInSeconds / 60)\n if (diffInMinutes < 60) {\n return `${convertToLocalNumbers(diffInMinutes, 'fa')} دقیقه پیش`\n }\n\n const diffInHours = Math.floor(diffInMinutes / 60)\n if (diffInHours < 24) {\n return `${convertToLocalNumbers(diffInHours, 'fa')} ساعت پیش`\n }\n\n const diffInDays = Math.floor(diffInHours / 24)\n if (diffInDays < 7) {\n return `${convertToLocalNumbers(diffInDays, 'fa')} روز پیش`\n }\n\n const diffInWeeks = Math.floor(diffInDays / 7)\n if (diffInWeeks < 4) {\n return `${convertToLocalNumbers(diffInWeeks, 'fa')} هفته پیش`\n }\n\n const diffInMonths = Math.floor(diffInDays / 30)\n if (diffInMonths < 12) {\n return `${convertToLocalNumbers(diffInMonths, 'fa')} ماه پیش`\n }\n\n const diffInYears = Math.floor(diffInDays / 365)\n return `${convertToLocalNumbers(diffInYears, 'fa')} سال پیش`\n}\n\n/**\n * Format date to absolute format (Persian / Jalali)\n * Uses date-fns-jalali for accurate Jalali conversion.\n * @example formatAbsoluteTime(new Date()) => '۱۵ دی ۱۴۰۳، ۱۵:۳۰'\n */\nexport function formatAbsoluteTime(date: Date | string | number): string {\n const d = new Date(date)\n return formatJalaliDate(d, 'd MMMM yyyy، HH:mm')\n}\n"]}