@mbao01/common 0.8.1 → 0.9.1

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 (277) hide show
  1. package/dist/types/components/ActivityFeed/ActivityFeed.d.ts +6 -0
  2. package/dist/types/components/ActivityFeed/constants.d.ts +6 -0
  3. package/dist/types/components/ActivityFeed/index.d.ts +2 -0
  4. package/dist/types/components/ActivityFeed/types.d.ts +21 -0
  5. package/dist/types/components/Amount/Amount.d.ts +6 -0
  6. package/dist/types/components/Amount/index.d.ts +2 -0
  7. package/dist/types/components/Amount/types.d.ts +19 -0
  8. package/dist/types/components/AnimatedCounter/AnimatedCounter.d.ts +6 -0
  9. package/dist/types/components/AnimatedCounter/index.d.ts +2 -0
  10. package/dist/types/components/AnimatedCounter/types.d.ts +13 -0
  11. package/dist/types/components/AnimatedGroup/AnimatedGroup.d.ts +6 -0
  12. package/dist/types/components/AnimatedGroup/index.d.ts +2 -0
  13. package/dist/types/components/AnimatedGroup/types.d.ts +22 -0
  14. package/dist/types/components/AnimatedList/AnimatedList.d.ts +6 -0
  15. package/dist/types/components/AnimatedList/index.d.ts +2 -0
  16. package/dist/types/components/AnimatedList/types.d.ts +13 -0
  17. package/dist/types/components/BorderBeam/BorderBeam.d.ts +6 -0
  18. package/dist/types/components/BorderBeam/index.d.ts +2 -0
  19. package/dist/types/components/BorderBeam/types.d.ts +13 -0
  20. package/dist/types/components/Box/Box.d.ts +4 -0
  21. package/dist/types/components/Box/constants.d.ts +4 -0
  22. package/dist/types/components/CalendarHeatmap/CalendarHeatmap.d.ts +6 -0
  23. package/dist/types/components/CalendarHeatmap/index.d.ts +2 -0
  24. package/dist/types/components/CalendarHeatmap/types.d.ts +25 -0
  25. package/dist/types/components/Chart/stories/examples/AreaChart.d.ts +6 -0
  26. package/dist/types/components/Chart/stories/examples/BarChart.d.ts +11 -0
  27. package/dist/types/components/Chart/stories/examples/LineChart.d.ts +10 -0
  28. package/dist/types/components/Chart/stories/examples/PieChart.d.ts +5 -0
  29. package/dist/types/components/Chart/stories/examples/RadialChart.d.ts +5 -0
  30. package/dist/types/components/CircularProgress/CircularProgress.d.ts +6 -0
  31. package/dist/types/components/CircularProgress/constants.d.ts +5 -0
  32. package/dist/types/components/CircularProgress/index.d.ts +2 -0
  33. package/dist/types/components/CircularProgress/types.d.ts +17 -0
  34. package/dist/types/components/ComparisonBar/ComparisonBar.d.ts +6 -0
  35. package/dist/types/components/ComparisonBar/constants.d.ts +4 -0
  36. package/dist/types/components/ComparisonBar/index.d.ts +2 -0
  37. package/dist/types/components/ComparisonBar/types.d.ts +21 -0
  38. package/dist/types/components/Confetti/Confetti.d.ts +6 -0
  39. package/dist/types/components/Confetti/index.d.ts +2 -0
  40. package/dist/types/components/Confetti/types.d.ts +19 -0
  41. package/dist/types/components/CountdownTimer/CountdownTimer.d.ts +6 -0
  42. package/dist/types/components/CountdownTimer/index.d.ts +2 -0
  43. package/dist/types/components/CountdownTimer/types.d.ts +13 -0
  44. package/dist/types/components/DataList/DataList.d.ts +6 -0
  45. package/dist/types/components/DataList/constants.d.ts +12 -0
  46. package/dist/types/components/DataList/index.d.ts +2 -0
  47. package/dist/types/components/DataList/types.d.ts +15 -0
  48. package/dist/types/components/DatePicker/DateRangePresetPicker.d.ts +2 -0
  49. package/dist/types/components/DatePicker/index.d.ts +1 -0
  50. package/dist/types/components/DatePicker/types.d.ts +19 -0
  51. package/dist/types/components/Description/Description.d.ts +2 -1
  52. package/dist/types/components/Description/DescriptionGroup.d.ts +6 -0
  53. package/dist/types/components/Description/constants.d.ts +23 -0
  54. package/dist/types/components/Description/index.d.ts +2 -0
  55. package/dist/types/components/Description/types.d.ts +28 -3
  56. package/dist/types/components/Form/DatetimeInput/DatetimeInput.d.ts +1 -1
  57. package/dist/types/components/GlowCard/GlowCard.d.ts +6 -0
  58. package/dist/types/components/GlowCard/index.d.ts +2 -0
  59. package/dist/types/components/GlowCard/types.d.ts +8 -0
  60. package/dist/types/components/GradientText/GradientText.d.ts +6 -0
  61. package/dist/types/components/GradientText/index.d.ts +2 -0
  62. package/dist/types/components/GradientText/types.d.ts +14 -0
  63. package/dist/types/components/Greeting/Greeting.d.ts +6 -0
  64. package/dist/types/components/Greeting/index.d.ts +2 -0
  65. package/dist/types/components/Greeting/types.d.ts +9 -0
  66. package/dist/types/components/IconContainer/IconContainer.d.ts +2 -0
  67. package/dist/types/components/IconContainer/constants.d.ts +15 -0
  68. package/dist/types/components/IconContainer/index.d.ts +1 -0
  69. package/dist/types/components/IconContainer/types.d.ts +3 -0
  70. package/dist/types/components/KPICard/KPICard.d.ts +6 -0
  71. package/dist/types/components/KPICard/index.d.ts +2 -0
  72. package/dist/types/components/KPICard/types.d.ts +17 -0
  73. package/dist/types/components/Marquee/Marquee.d.ts +6 -0
  74. package/dist/types/components/Marquee/index.d.ts +2 -0
  75. package/dist/types/components/Marquee/types.d.ts +12 -0
  76. package/dist/types/components/Meteors/Meteors.d.ts +6 -0
  77. package/dist/types/components/Meteors/index.d.ts +2 -0
  78. package/dist/types/components/Meteors/types.d.ts +5 -0
  79. package/dist/types/components/MiniAreaChart/MiniAreaChart.d.ts +6 -0
  80. package/dist/types/components/MiniAreaChart/index.d.ts +2 -0
  81. package/dist/types/components/MiniAreaChart/types.d.ts +10 -0
  82. package/dist/types/components/MiniBarChart/MiniBarChart.d.ts +6 -0
  83. package/dist/types/components/MiniBarChart/index.d.ts +2 -0
  84. package/dist/types/components/MiniBarChart/types.d.ts +15 -0
  85. package/dist/types/components/MiniDonutChart/MiniDonutChart.d.ts +6 -0
  86. package/dist/types/components/MiniDonutChart/index.d.ts +2 -0
  87. package/dist/types/components/MiniDonutChart/types.d.ts +15 -0
  88. package/dist/types/components/MiniStackedBar/MiniStackedBar.d.ts +6 -0
  89. package/dist/types/components/MiniStackedBar/index.d.ts +2 -0
  90. package/dist/types/components/MiniStackedBar/types.d.ts +13 -0
  91. package/dist/types/components/NumberTicker/NumberTicker.d.ts +6 -0
  92. package/dist/types/components/NumberTicker/index.d.ts +2 -0
  93. package/dist/types/components/NumberTicker/types.d.ts +11 -0
  94. package/dist/types/components/Pulse/Pulse.d.ts +6 -0
  95. package/dist/types/components/Pulse/constants.d.ts +10 -0
  96. package/dist/types/components/Pulse/index.d.ts +2 -0
  97. package/dist/types/components/Pulse/types.d.ts +11 -0
  98. package/dist/types/components/ShinyButton/ShinyButton.d.ts +6 -0
  99. package/dist/types/components/ShinyButton/index.d.ts +2 -0
  100. package/dist/types/components/ShinyButton/types.d.ts +4 -0
  101. package/dist/types/components/Sparkline/Sparkline.d.ts +6 -0
  102. package/dist/types/components/Sparkline/index.d.ts +2 -0
  103. package/dist/types/components/Sparkline/types.d.ts +17 -0
  104. package/dist/types/components/SpotlightCard/SpotlightCard.d.ts +6 -0
  105. package/dist/types/components/SpotlightCard/index.d.ts +2 -0
  106. package/dist/types/components/SpotlightCard/types.d.ts +7 -0
  107. package/dist/types/components/StatCard/StatCard.d.ts +6 -0
  108. package/dist/types/components/StatCard/index.d.ts +2 -0
  109. package/dist/types/components/StatCard/types.d.ts +15 -0
  110. package/dist/types/components/TextShimmer/TextShimmer.d.ts +6 -0
  111. package/dist/types/components/TextShimmer/index.d.ts +2 -0
  112. package/dist/types/components/TextShimmer/types.d.ts +7 -0
  113. package/dist/types/components/TrendBadge/TrendBadge.d.ts +6 -0
  114. package/dist/types/components/TrendBadge/constants.d.ts +7 -0
  115. package/dist/types/components/TrendBadge/index.d.ts +2 -0
  116. package/dist/types/components/TrendBadge/types.d.ts +15 -0
  117. package/dist/types/components/WidgetShell/WidgetShell.d.ts +6 -0
  118. package/dist/types/components/WidgetShell/index.d.ts +2 -0
  119. package/dist/types/components/WidgetShell/types.d.ts +20 -0
  120. package/dist/types/index.d.ts +34 -0
  121. package/package.json +2 -1
  122. package/src/components/Accordion/constants.ts +1 -1
  123. package/src/components/ActivityFeed/ActivityFeed.tsx +51 -0
  124. package/src/components/ActivityFeed/constants.ts +19 -0
  125. package/src/components/ActivityFeed/index.ts +2 -0
  126. package/src/components/ActivityFeed/types.ts +23 -0
  127. package/src/components/Alert/constants.ts +1 -1
  128. package/src/components/AlertDialog/constants.ts +1 -1
  129. package/src/components/Amount/Amount.tsx +50 -0
  130. package/src/components/Amount/index.ts +2 -0
  131. package/src/components/Amount/types.ts +20 -0
  132. package/src/components/AnimatedCounter/AnimatedCounter.tsx +68 -0
  133. package/src/components/AnimatedCounter/index.ts +2 -0
  134. package/src/components/AnimatedCounter/types.ts +14 -0
  135. package/src/components/AnimatedGroup/AnimatedGroup.tsx +97 -0
  136. package/src/components/AnimatedGroup/index.ts +2 -0
  137. package/src/components/AnimatedGroup/types.ts +21 -0
  138. package/src/components/AnimatedList/AnimatedList.tsx +42 -0
  139. package/src/components/AnimatedList/index.ts +2 -0
  140. package/src/components/AnimatedList/types.ts +15 -0
  141. package/src/components/Badge/constants.ts +1 -1
  142. package/src/components/Banner/constants.ts +1 -1
  143. package/src/components/BorderBeam/BorderBeam.tsx +41 -0
  144. package/src/components/BorderBeam/index.ts +2 -0
  145. package/src/components/BorderBeam/types.ts +14 -0
  146. package/src/components/Box/Box.tsx +8 -2
  147. package/src/components/Box/constants.ts +35 -0
  148. package/src/components/Button/constants.ts +66 -63
  149. package/src/components/CalendarHeatmap/CalendarHeatmap.tsx +141 -0
  150. package/src/components/CalendarHeatmap/index.ts +2 -0
  151. package/src/components/CalendarHeatmap/types.ts +27 -0
  152. package/src/components/Card/constants.ts +24 -21
  153. package/src/components/Carousel/constants.ts +2 -2
  154. package/src/components/Chart/stories/examples/AreaChart.tsx +55 -0
  155. package/src/components/Chart/stories/examples/BarChart.tsx +95 -0
  156. package/src/components/Chart/stories/examples/LineChart.tsx +111 -0
  157. package/src/components/Chart/stories/examples/PieChart.tsx +55 -0
  158. package/src/components/Chart/stories/examples/RadialChart.tsx +65 -0
  159. package/src/components/CircularProgress/CircularProgress.tsx +46 -0
  160. package/src/components/CircularProgress/constants.ts +32 -0
  161. package/src/components/CircularProgress/index.ts +2 -0
  162. package/src/components/CircularProgress/types.ts +18 -0
  163. package/src/components/Command/constants.ts +1 -1
  164. package/src/components/ComparisonBar/ComparisonBar.tsx +65 -0
  165. package/src/components/ComparisonBar/constants.ts +23 -0
  166. package/src/components/ComparisonBar/index.ts +2 -0
  167. package/src/components/ComparisonBar/types.ts +23 -0
  168. package/src/components/Confetti/Confetti.tsx +82 -0
  169. package/src/components/Confetti/index.ts +2 -0
  170. package/src/components/Confetti/types.ts +20 -0
  171. package/src/components/CountdownTimer/CountdownTimer.tsx +91 -0
  172. package/src/components/CountdownTimer/index.ts +2 -0
  173. package/src/components/CountdownTimer/types.ts +14 -0
  174. package/src/components/DataList/DataList.tsx +32 -0
  175. package/src/components/DataList/constants.ts +47 -0
  176. package/src/components/DataList/index.ts +2 -0
  177. package/src/components/DataList/types.ts +17 -0
  178. package/src/components/DatePicker/DateRangePresetPicker.tsx +122 -0
  179. package/src/components/DatePicker/index.ts +1 -0
  180. package/src/components/DatePicker/types.ts +22 -0
  181. package/src/components/Description/Description.tsx +67 -5
  182. package/src/components/Description/DescriptionGroup.tsx +39 -0
  183. package/src/components/Description/constants.ts +128 -0
  184. package/src/components/Description/index.ts +10 -0
  185. package/src/components/Description/types.ts +31 -3
  186. package/src/components/Dialog/constants.ts +2 -2
  187. package/src/components/Dock/constants.ts +2 -2
  188. package/src/components/Drawer/constants.ts +2 -2
  189. package/src/components/Form/Checkbox/constants.ts +1 -1
  190. package/src/components/Form/DatetimeInput/constants.ts +1 -1
  191. package/src/components/Form/Input/constants.ts +1 -1
  192. package/src/components/Form/MultiSelect/constants.ts +1 -1
  193. package/src/components/Form/NativeSelect/constants.ts +1 -1
  194. package/src/components/Form/Radio/constants.ts +1 -1
  195. package/src/components/Form/Select/constants.ts +1 -1
  196. package/src/components/Form/Slider/constants.ts +1 -1
  197. package/src/components/Form/Switch/constants.ts +1 -1
  198. package/src/components/Form/Textarea/constants.ts +1 -1
  199. package/src/components/GlowCard/GlowCard.tsx +46 -0
  200. package/src/components/GlowCard/index.ts +2 -0
  201. package/src/components/GlowCard/types.ts +9 -0
  202. package/src/components/GradientText/GradientText.tsx +36 -0
  203. package/src/components/GradientText/index.ts +2 -0
  204. package/src/components/GradientText/types.ts +15 -0
  205. package/src/components/Greeting/Greeting.tsx +46 -0
  206. package/src/components/Greeting/index.ts +2 -0
  207. package/src/components/Greeting/types.ts +10 -0
  208. package/src/components/IconContainer/IconContainer.tsx +44 -0
  209. package/src/components/IconContainer/constants.ts +112 -0
  210. package/src/components/IconContainer/index.ts +1 -0
  211. package/src/components/IconContainer/types.ts +5 -0
  212. package/src/components/KPICard/KPICard.tsx +75 -0
  213. package/src/components/KPICard/index.ts +2 -0
  214. package/src/components/KPICard/types.ts +18 -0
  215. package/src/components/Marquee/Marquee.tsx +45 -0
  216. package/src/components/Marquee/index.ts +2 -0
  217. package/src/components/Marquee/types.ts +13 -0
  218. package/src/components/Menu/Menubar/constants.ts +2 -2
  219. package/src/components/Menu/NavigationMenu/constants.ts +2 -2
  220. package/src/components/Meteors/Meteors.tsx +38 -0
  221. package/src/components/Meteors/index.ts +2 -0
  222. package/src/components/Meteors/types.ts +6 -0
  223. package/src/components/MiniAreaChart/MiniAreaChart.tsx +68 -0
  224. package/src/components/MiniAreaChart/index.ts +2 -0
  225. package/src/components/MiniAreaChart/types.ts +11 -0
  226. package/src/components/MiniBarChart/MiniBarChart.tsx +49 -0
  227. package/src/components/MiniBarChart/index.ts +2 -0
  228. package/src/components/MiniBarChart/types.ts +16 -0
  229. package/src/components/MiniDonutChart/MiniDonutChart.tsx +87 -0
  230. package/src/components/MiniDonutChart/index.ts +2 -0
  231. package/src/components/MiniDonutChart/types.ts +17 -0
  232. package/src/components/MiniStackedBar/MiniStackedBar.tsx +61 -0
  233. package/src/components/MiniStackedBar/index.ts +2 -0
  234. package/src/components/MiniStackedBar/types.ts +15 -0
  235. package/src/components/NumberTicker/NumberTicker.tsx +58 -0
  236. package/src/components/NumberTicker/index.ts +2 -0
  237. package/src/components/NumberTicker/types.ts +12 -0
  238. package/src/components/Pagination/constants.ts +2 -2
  239. package/src/components/Progress/constants.ts +1 -1
  240. package/src/components/Pulse/Pulse.tsx +26 -0
  241. package/src/components/Pulse/constants.ts +55 -0
  242. package/src/components/Pulse/index.ts +2 -0
  243. package/src/components/Pulse/types.ts +12 -0
  244. package/src/components/Resizable/constants.ts +1 -1
  245. package/src/components/Sheet/constants.ts +1 -1
  246. package/src/components/ShinyButton/ShinyButton.tsx +57 -0
  247. package/src/components/ShinyButton/index.ts +2 -0
  248. package/src/components/ShinyButton/types.ts +8 -0
  249. package/src/components/Skeleton/constants.ts +1 -1
  250. package/src/components/Sonner/constants.ts +1 -1
  251. package/src/components/Sparkline/Sparkline.tsx +108 -0
  252. package/src/components/Sparkline/index.ts +2 -0
  253. package/src/components/Sparkline/types.ts +18 -0
  254. package/src/components/SpotlightCard/SpotlightCard.tsx +56 -0
  255. package/src/components/SpotlightCard/index.ts +2 -0
  256. package/src/components/SpotlightCard/types.ts +8 -0
  257. package/src/components/Stat/constants.ts +1 -1
  258. package/src/components/StatCard/StatCard.tsx +59 -0
  259. package/src/components/StatCard/index.ts +2 -0
  260. package/src/components/StatCard/types.ts +16 -0
  261. package/src/components/Tabs/constants.ts +1 -1
  262. package/src/components/TextShimmer/TextShimmer.tsx +34 -0
  263. package/src/components/TextShimmer/index.ts +2 -0
  264. package/src/components/TextShimmer/types.ts +8 -0
  265. package/src/components/Timeline/constants.ts +1 -1
  266. package/src/components/Toggle/constants.ts +1 -1
  267. package/src/components/Tooltip/constants.ts +1 -1
  268. package/src/components/TrendBadge/TrendBadge.tsx +40 -0
  269. package/src/components/TrendBadge/constants.ts +38 -0
  270. package/src/components/TrendBadge/index.ts +2 -0
  271. package/src/components/TrendBadge/types.ts +16 -0
  272. package/src/components/WidgetShell/WidgetShell.tsx +101 -0
  273. package/src/components/WidgetShell/index.ts +2 -0
  274. package/src/components/WidgetShell/types.ts +22 -0
  275. package/src/index.ts +36 -0
  276. package/src/stylesheets/tailwind.css +208 -0
  277. package/src/utilities/getSubpaths/getSubpaths.ts +1 -2
@@ -0,0 +1,108 @@
1
+ import { useMemo } from "react";
2
+ import { cn } from "../../utilities";
3
+ import type { SparklineProps } from "./types";
4
+
5
+ const Sparkline = ({
6
+ data,
7
+ className,
8
+ width = 120,
9
+ height = 32,
10
+ color = "currentColor",
11
+ filled = false,
12
+ strokeWidth = 1.5,
13
+ animated = true,
14
+ ...props
15
+ }: SparklineProps) => {
16
+ const path = useMemo(() => {
17
+ if (data.length < 2) return "";
18
+ const min = Math.min(...data);
19
+ const max = Math.max(...data);
20
+ const range = max - min || 1;
21
+ const padding = strokeWidth;
22
+ const plotWidth = width - padding * 2;
23
+ const plotHeight = height - padding * 2;
24
+
25
+ const points = data.map((value, i) => ({
26
+ x: padding + (i / (data.length - 1)) * plotWidth,
27
+ y: padding + plotHeight - ((value - min) / range) * plotHeight,
28
+ }));
29
+
30
+ return points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
31
+ }, [data, width, height, strokeWidth]);
32
+
33
+ const areaPath = useMemo(() => {
34
+ if (!filled || !path) return "";
35
+ const padding = strokeWidth;
36
+ const firstX = padding;
37
+ const lastX = width - padding;
38
+ return `${path} L ${lastX} ${height - padding} L ${firstX} ${height - padding} Z`;
39
+ }, [filled, path, width, height, strokeWidth]);
40
+
41
+ const pathLength = useMemo(() => {
42
+ if (data.length < 2) return 0;
43
+ const min = Math.min(...data);
44
+ const max = Math.max(...data);
45
+ const range = max - min || 1;
46
+ const padding = strokeWidth;
47
+ const plotWidth = width - padding * 2;
48
+ const plotHeight = height - padding * 2;
49
+
50
+ let length = 0;
51
+ for (let i = 1; i < data.length; i++) {
52
+ const x1 = padding + ((i - 1) / (data.length - 1)) * plotWidth;
53
+ const y1 = padding + plotHeight - ((data[i - 1] - min) / range) * plotHeight;
54
+ const x2 = padding + (i / (data.length - 1)) * plotWidth;
55
+ const y2 = padding + plotHeight - ((data[i] - min) / range) * plotHeight;
56
+ length += Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
57
+ }
58
+ return Math.ceil(length);
59
+ }, [data, width, height, strokeWidth]);
60
+
61
+ if (data.length < 2) return null;
62
+
63
+ return (
64
+ <div className={cn("inline-flex items-center", className)} {...props}>
65
+ <svg
66
+ width={width}
67
+ height={height}
68
+ viewBox={`0 0 ${width} ${height}`}
69
+ fill="none"
70
+ aria-hidden="true"
71
+ >
72
+ {filled && areaPath && (
73
+ <path
74
+ d={areaPath}
75
+ fill={color}
76
+ opacity={0.1}
77
+ />
78
+ )}
79
+ <path
80
+ d={path}
81
+ stroke={color}
82
+ strokeWidth={strokeWidth}
83
+ strokeLinecap="round"
84
+ strokeLinejoin="round"
85
+ fill="none"
86
+ {...(animated
87
+ ? {
88
+ strokeDasharray: pathLength,
89
+ strokeDashoffset: pathLength,
90
+ style: {
91
+ animation: `sparkline-draw 1s ease-out forwards`,
92
+ },
93
+ }
94
+ : {})}
95
+ />
96
+ <style>{`
97
+ @keyframes sparkline-draw {
98
+ to { stroke-dashoffset: 0; }
99
+ }
100
+ `}</style>
101
+ </svg>
102
+ </div>
103
+ );
104
+ };
105
+
106
+ Sparkline.displayName = "Sparkline";
107
+
108
+ export { Sparkline };
@@ -0,0 +1,2 @@
1
+ export { Sparkline } from "./Sparkline";
2
+ export type { SparklineProps } from "./types";
@@ -0,0 +1,18 @@
1
+ import type { HTMLAttributes } from "react";
2
+
3
+ export type SparklineProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
4
+ /** Array of numeric data points */
5
+ data: number[];
6
+ /** Width of the sparkline in pixels */
7
+ width?: number;
8
+ /** Height of the sparkline in pixels */
9
+ height?: number;
10
+ /** Stroke color (CSS color value) */
11
+ color?: string;
12
+ /** Whether to show a filled area under the line */
13
+ filled?: boolean;
14
+ /** Stroke width in pixels */
15
+ strokeWidth?: number;
16
+ /** Whether to animate the line drawing */
17
+ animated?: boolean;
18
+ };
@@ -0,0 +1,56 @@
1
+ "use client";
2
+
3
+ import type { CSSProperties, MouseEvent } from "react";
4
+ import { useCallback, useRef, useState } from "react";
5
+ import type { SpotlightCardProps } from "./types";
6
+ import { cn } from "../../utilities";
7
+
8
+ const SpotlightCard = ({
9
+ children,
10
+ className,
11
+ spotlightColor = "oklch(0.7 0.15 250 / 0.15)",
12
+ spotlightSize = 400,
13
+ ...props
14
+ }: SpotlightCardProps) => {
15
+ const containerRef = useRef<HTMLDivElement>(null);
16
+ const [position, setPosition] = useState({ x: 0, y: 0 });
17
+ const [, setIsHovered] = useState(false);
18
+
19
+ const handleMouseMove = useCallback((e: MouseEvent<HTMLDivElement>) => {
20
+ if (!containerRef.current) return;
21
+ const rect = containerRef.current.getBoundingClientRect();
22
+ setPosition({
23
+ x: e.clientX - rect.left,
24
+ y: e.clientY - rect.top,
25
+ });
26
+ }, []);
27
+
28
+ return (
29
+ <div
30
+ ref={containerRef}
31
+ className={cn(
32
+ "group relative overflow-hidden rounded-lg border bg-base-100 shadow-sm transition-shadow duration-300 hover:shadow-lg",
33
+ className
34
+ )}
35
+ onMouseMove={handleMouseMove}
36
+ onMouseEnter={() => setIsHovered(true)}
37
+ onMouseLeave={() => setIsHovered(false)}
38
+ {...props}
39
+ >
40
+ <div
41
+ className="pointer-events-none absolute -inset-px rounded-[inherit] opacity-0 transition-opacity duration-300 group-hover:opacity-100"
42
+ style={
43
+ {
44
+ background: `radial-gradient(${spotlightSize}px circle at ${position.x}px ${position.y}px, ${spotlightColor}, transparent 80%)`,
45
+ } as CSSProperties
46
+ }
47
+ aria-hidden="true"
48
+ />
49
+ <div className="relative">{children}</div>
50
+ </div>
51
+ );
52
+ };
53
+
54
+ SpotlightCard.displayName = "SpotlightCard";
55
+
56
+ export { SpotlightCard };
@@ -0,0 +1,2 @@
1
+ export { SpotlightCard } from "./SpotlightCard";
2
+ export type { SpotlightCardProps } from "./types";
@@ -0,0 +1,8 @@
1
+ import type { HTMLAttributes } from "react";
2
+
3
+ export type SpotlightCardProps = HTMLAttributes<HTMLDivElement> & {
4
+ /** Spotlight gradient color */
5
+ spotlightColor?: string;
6
+ /** Size of the spotlight in pixels */
7
+ spotlightSize?: number;
8
+ };
@@ -1,7 +1,7 @@
1
1
  import { cva } from "../../libs";
2
2
  import { createVariants } from "../../utilities";
3
3
 
4
- export const getStatsClasses = cva("stats", {
4
+ export const getStatsClasses = cva("stats shadow-sm", {
5
5
  variants: createVariants({
6
6
  direction: {
7
7
  horizontal: "stats-horizontal",
@@ -0,0 +1,59 @@
1
+ import { cn } from "../../utilities";
2
+ import type { StatCardProps } from "./types";
3
+
4
+ const StatCard = ({
5
+ icon,
6
+ title,
7
+ value,
8
+ description,
9
+ trend,
10
+ trendLabel,
11
+ className,
12
+ ...props
13
+ }: StatCardProps) => {
14
+ const isPositive = trend?.startsWith("+");
15
+ const isNegative = trend?.startsWith("-");
16
+
17
+ return (
18
+ <div
19
+ className={cn(
20
+ "relative rounded-2xl border border-base-200 bg-base-100 px-6 pb-6 pt-10 shadow-sm",
21
+ icon && "pt-14",
22
+ className
23
+ )}
24
+ {...props}
25
+ >
26
+ {icon && (
27
+ <div className="absolute -top-5 left-6">
28
+ <div className="flex size-10 items-center justify-center rounded-full bg-base-100 shadow-md ring-1 ring-base-200">
29
+ {icon}
30
+ </div>
31
+ </div>
32
+ )}
33
+ <p className="text-sm text-base-content/60">{title}</p>
34
+ <p className="mt-2 text-3xl font-bold tracking-tight text-base-content">{value}</p>
35
+ {(trend || description) && (
36
+ <p className="mt-2 text-sm text-base-content/60">
37
+ {trend && (
38
+ <span
39
+ className={cn(
40
+ "font-medium",
41
+ isPositive && "text-success",
42
+ isNegative && "text-error"
43
+ )}
44
+ >
45
+ {trend}
46
+ </span>
47
+ )}
48
+ {trend && trendLabel && <span> </span>}
49
+ {trendLabel && <span>{trendLabel}</span>}
50
+ {!trend && !trendLabel && description}
51
+ </p>
52
+ )}
53
+ </div>
54
+ );
55
+ };
56
+
57
+ StatCard.displayName = "StatCard";
58
+
59
+ export { StatCard };
@@ -0,0 +1,2 @@
1
+ export { StatCard } from "./StatCard";
2
+ export type { StatCardProps } from "./types";
@@ -0,0 +1,16 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+
3
+ export type StatCardProps = Omit<HTMLAttributes<HTMLDivElement>, "title"> & {
4
+ /** Icon element rendered in the lifted badge */
5
+ icon?: ReactNode;
6
+ /** Stat label / title */
7
+ title: ReactNode;
8
+ /** Main stat value */
9
+ value: ReactNode;
10
+ /** Description text below the value */
11
+ description?: ReactNode;
12
+ /** Trend value (e.g. "+9.8%") — colored green if positive, red if negative */
13
+ trend?: string;
14
+ /** Description shown next to the trend */
15
+ trendLabel?: string;
16
+ };
@@ -5,7 +5,7 @@ export const getTabsListClasses = cva(
5
5
  );
6
6
 
7
7
  export const getTabsTriggerClasses = cva(
8
- "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-base-100 data-[state=active]:text-foreground data-[state=active]:shadow-sm"
8
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-base-100 data-[state=active]:text-foreground data-[state=active]:shadow-sm"
9
9
  );
10
10
 
11
11
  export const getTabsContentClasses = cva(
@@ -0,0 +1,34 @@
1
+ import type { CSSProperties } from "react";
2
+ import { cn } from "../../utilities";
3
+ import type { TextShimmerProps } from "./types";
4
+
5
+ const TextShimmer = ({
6
+ children,
7
+ className,
8
+ duration = 2,
9
+ spread = 2,
10
+ ...props
11
+ }: TextShimmerProps) => {
12
+ return (
13
+ <p
14
+ className={cn(
15
+ "animate-text-gradient bg-[length:250%_100%] bg-clip-text text-transparent",
16
+ "bg-[linear-gradient(90deg,var(--shimmer-from,currentColor)_0%,var(--shimmer-via,oklch(0.7_0.15_250))_50%,var(--shimmer-from,currentColor)_100%)]",
17
+ className
18
+ )}
19
+ style={
20
+ {
21
+ "--shimmer-spread": spread,
22
+ animationDuration: `${duration}s`,
23
+ } as CSSProperties
24
+ }
25
+ {...props}
26
+ >
27
+ {children}
28
+ </p>
29
+ );
30
+ };
31
+
32
+ TextShimmer.displayName = "TextShimmer";
33
+
34
+ export { TextShimmer };
@@ -0,0 +1,2 @@
1
+ export { TextShimmer } from "./TextShimmer";
2
+ export type { TextShimmerProps } from "./types";
@@ -0,0 +1,8 @@
1
+ import type { HTMLAttributes } from "react";
2
+
3
+ export type TextShimmerProps = HTMLAttributes<HTMLParagraphElement> & {
4
+ /** Duration of the shimmer animation in seconds */
5
+ duration?: number;
6
+ /** Spread of the shimmer gradient (0-1) */
7
+ spread?: number;
8
+ };
@@ -31,7 +31,7 @@ export const getTimelineItemClasses = cva("grid items-center gap-x-2", {
31
31
  });
32
32
 
33
33
  export const getTimelineDotClasses = cva(
34
- "timeline-dot col-start-2 col-end-3 row-start-1 row-end-1 flex size-4 items-center justify-center rounded-full border",
34
+ "timeline-dot col-start-2 col-end-3 row-start-1 row-end-1 flex size-4 items-center justify-center rounded-full border transition-all duration-200",
35
35
  {
36
36
  variants: createVariants({
37
37
  status: {
@@ -2,7 +2,7 @@ import { cva } from "../../libs";
2
2
  import { createVariants } from "../../utilities";
3
3
 
4
4
  export const getToggleClasses = cva(
5
- "transition-colors disabled:pointer-events-none disabled:opacity-50 data-[state=off]:btn-ghost",
5
+ "transition-all duration-200 disabled:pointer-events-none disabled:opacity-50 data-[state=off]:btn-ghost",
6
6
  {
7
7
  variants: createVariants({
8
8
  link: {
@@ -2,7 +2,7 @@ import { cva } from "../../libs";
2
2
  import { createVariants } from "../../utilities";
3
3
 
4
4
  export const getTooltipContentClasses = cva(
5
- "bg-base-200 text-base-content z-50 overflow-hidden rounded-md px-3 py-1.5 text-xs animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 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",
5
+ "bg-base-200 text-base-content z-50 overflow-hidden rounded-md px-3 py-1.5 text-xs shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 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",
6
6
  {
7
7
  variants: createVariants({
8
8
  variant: {
@@ -0,0 +1,40 @@
1
+ import { TrendingDownIcon, TrendingUpIcon, MinusIcon } from "lucide-react";
2
+ import { cn } from "../../utilities";
3
+ import { getTrendBadgeClasses, getTrendIconClasses } from "./constants";
4
+ import type { TrendBadgeProps } from "./types";
5
+
6
+ const TrendBadge = ({
7
+ value,
8
+ className,
9
+ decimalPlaces = 1,
10
+ showPercent = true,
11
+ showIcon = true,
12
+ size = "sm",
13
+ trend: trendOverride,
14
+ ...props
15
+ }: TrendBadgeProps) => {
16
+ const trend = trendOverride ?? (value > 0 ? "up" : value < 0 ? "down" : "neutral");
17
+ const absValue = Math.abs(value).toFixed(decimalPlaces);
18
+ const prefix = trend === "up" ? "+" : trend === "down" ? "-" : "";
19
+
20
+ const Icon =
21
+ trend === "up" ? TrendingUpIcon : trend === "down" ? TrendingDownIcon : MinusIcon;
22
+
23
+ return (
24
+ <span
25
+ className={cn(getTrendBadgeClasses({ trend, size }), className)}
26
+ {...props}
27
+ >
28
+ {showIcon && <Icon className={getTrendIconClasses({ size })} />}
29
+ <span>
30
+ {prefix}
31
+ {absValue}
32
+ {showPercent && "%"}
33
+ </span>
34
+ </span>
35
+ );
36
+ };
37
+
38
+ TrendBadge.displayName = "TrendBadge";
39
+
40
+ export { TrendBadge };
@@ -0,0 +1,38 @@
1
+ import { cva } from "../../libs";
2
+ import { createVariants } from "../../utilities";
3
+
4
+ export const getTrendBadgeClasses = cva(
5
+ "inline-flex items-center gap-1 font-medium tabular-nums transition-colors duration-200",
6
+ {
7
+ variants: createVariants({
8
+ trend: {
9
+ up: "text-success",
10
+ down: "text-error",
11
+ neutral: "text-base-content/60",
12
+ },
13
+ size: {
14
+ xs: "text-xs",
15
+ sm: "text-sm",
16
+ md: "text-base",
17
+ lg: "text-lg",
18
+ },
19
+ }),
20
+ defaultVariants: {
21
+ size: "sm",
22
+ },
23
+ }
24
+ );
25
+
26
+ export const getTrendIconClasses = cva("", {
27
+ variants: createVariants({
28
+ size: {
29
+ xs: "size-3",
30
+ sm: "size-3.5",
31
+ md: "size-4",
32
+ lg: "size-5",
33
+ },
34
+ }),
35
+ defaultVariants: {
36
+ size: "sm",
37
+ },
38
+ });
@@ -0,0 +1,2 @@
1
+ export { TrendBadge } from "./TrendBadge";
2
+ export type { TrendBadgeProps } from "./types";
@@ -0,0 +1,16 @@
1
+ import type { HTMLAttributes } from "react";
2
+
3
+ export type TrendBadgeProps = Omit<HTMLAttributes<HTMLSpanElement>, "children"> & {
4
+ /** The change value (positive = up, negative = down, zero = neutral) */
5
+ value: number;
6
+ /** Number of decimal places to display */
7
+ decimalPlaces?: number;
8
+ /** Whether to show the percentage sign */
9
+ showPercent?: boolean;
10
+ /** Whether to show the trend arrow icon */
11
+ showIcon?: boolean;
12
+ /** Size variant */
13
+ size?: "xs" | "sm" | "md" | "lg";
14
+ /** Override automatic trend direction */
15
+ trend?: "up" | "down" | "neutral";
16
+ };
@@ -0,0 +1,101 @@
1
+ import { AlertCircleIcon, InboxIcon, RefreshCwIcon } from "lucide-react";
2
+ import { cn } from "../../utilities";
3
+ import type { WidgetShellProps } from "./types";
4
+
5
+ const WidgetShell = ({
6
+ state = "ready",
7
+ title,
8
+ description,
9
+ children,
10
+ className,
11
+ errorContent,
12
+ emptyContent,
13
+ skeletonLines = 3,
14
+ onRetry,
15
+ ...props
16
+ }: WidgetShellProps) => {
17
+ return (
18
+ <div
19
+ className={cn(
20
+ "rounded-lg border bg-base-100 shadow-sm transition-shadow duration-300",
21
+ className
22
+ )}
23
+ {...props}
24
+ >
25
+ {(title || description) && (
26
+ <div className="border-b px-4 py-3">
27
+ {title && (
28
+ <h3 className="text-sm font-semibold">
29
+ {state === "loading" ? (
30
+ <span className="skeleton inline-block h-4 w-32 rounded" />
31
+ ) : (
32
+ title
33
+ )}
34
+ </h3>
35
+ )}
36
+ {description && (
37
+ <p className="mt-0.5 text-xs text-base-content/60">
38
+ {state === "loading" ? (
39
+ <span className="skeleton inline-block h-3 w-48 rounded" />
40
+ ) : (
41
+ description
42
+ )}
43
+ </p>
44
+ )}
45
+ </div>
46
+ )}
47
+
48
+ <div className="p-4">
49
+ {state === "loading" && (
50
+ <div className="flex flex-col gap-3" role="status" aria-label="Loading">
51
+ {Array.from({ length: skeletonLines }, (_, i) => (
52
+ <span
53
+ key={i}
54
+ className="skeleton h-4 rounded"
55
+ style={{ width: `${100 - i * 15}%` }}
56
+ />
57
+ ))}
58
+ </div>
59
+ )}
60
+
61
+ {state === "error" &&
62
+ (errorContent ?? (
63
+ <div className="flex flex-col items-center justify-center gap-3 py-6 text-center">
64
+ <AlertCircleIcon className="size-8 text-error/60" />
65
+ <div>
66
+ <p className="text-sm font-medium">Something went wrong</p>
67
+ <p className="text-xs text-base-content/60">Failed to load data</p>
68
+ </div>
69
+ {onRetry && (
70
+ <button
71
+ type="button"
72
+ onClick={onRetry}
73
+ className="inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-xs font-medium transition-colors duration-200 hover:bg-base-200"
74
+ >
75
+ <RefreshCwIcon className="size-3" />
76
+ Retry
77
+ </button>
78
+ )}
79
+ </div>
80
+ ))}
81
+
82
+ {state === "empty" &&
83
+ (emptyContent ?? (
84
+ <div className="flex flex-col items-center justify-center gap-3 py-6 text-center">
85
+ <InboxIcon className="size-8 text-base-content/30" />
86
+ <div>
87
+ <p className="text-sm font-medium">No data</p>
88
+ <p className="text-xs text-base-content/60">Nothing to display yet</p>
89
+ </div>
90
+ </div>
91
+ ))}
92
+
93
+ {state === "ready" && children}
94
+ </div>
95
+ </div>
96
+ );
97
+ };
98
+
99
+ WidgetShell.displayName = "WidgetShell";
100
+
101
+ export { WidgetShell };
@@ -0,0 +1,2 @@
1
+ export { WidgetShell } from "./WidgetShell";
2
+ export type { WidgetShellProps, WidgetShellState } from "./types";
@@ -0,0 +1,22 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+
3
+ export type WidgetShellState = "loading" | "error" | "empty" | "ready";
4
+
5
+ export type WidgetShellProps = HTMLAttributes<HTMLDivElement> & {
6
+ /** Current state of the widget */
7
+ state?: WidgetShellState;
8
+ /** Widget title */
9
+ title?: ReactNode;
10
+ /** Widget description */
11
+ description?: ReactNode;
12
+ /** Content to show when state is "ready" */
13
+ children: ReactNode;
14
+ /** Custom content for error state */
15
+ errorContent?: ReactNode;
16
+ /** Custom content for empty state */
17
+ emptyContent?: ReactNode;
18
+ /** Number of skeleton lines to show in loading state */
19
+ skeletonLines?: number;
20
+ /** Callback when retry is clicked in error state */
21
+ onRetry?: () => void;
22
+ };