@arolariu/components 0.1.2 → 0.3.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 (360) hide show
  1. package/DEBUGGING.md +396 -396
  2. package/LICENSE.md +21 -21
  3. package/changelog.md +120 -118
  4. package/dist/components/ui/accordion.d.ts +6 -6
  5. package/dist/components/ui/accordion.d.ts.map +1 -1
  6. package/dist/components/ui/accordion.js +20 -28
  7. package/dist/components/ui/accordion.js.map +1 -1
  8. package/dist/components/ui/alert-dialog.d.ts +19 -13
  9. package/dist/components/ui/alert-dialog.d.ts.map +1 -1
  10. package/dist/components/ui/alert-dialog.js +40 -63
  11. package/dist/components/ui/alert-dialog.js.map +1 -1
  12. package/dist/components/ui/alert.d.ts +7 -8
  13. package/dist/components/ui/alert.d.ts.map +1 -1
  14. package/dist/components/ui/alert.js +18 -21
  15. package/dist/components/ui/alert.js.map +1 -1
  16. package/dist/components/ui/aspect-ratio.d.ts +1 -2
  17. package/dist/components/ui/aspect-ratio.d.ts.map +1 -1
  18. package/dist/components/ui/aspect-ratio.js +1 -8
  19. package/dist/components/ui/aspect-ratio.js.map +1 -1
  20. package/dist/components/ui/avatar.d.ts +5 -5
  21. package/dist/components/ui/avatar.d.ts.map +1 -1
  22. package/dist/components/ui/avatar.js +17 -20
  23. package/dist/components/ui/avatar.js.map +1 -1
  24. package/dist/components/ui/background-beams.d.ts.map +1 -1
  25. package/dist/components/ui/background-beams.js +6 -6
  26. package/dist/components/ui/background-beams.js.map +1 -1
  27. package/dist/components/ui/badge.d.ts +7 -7
  28. package/dist/components/ui/badge.d.ts.map +1 -1
  29. package/dist/components/ui/badge.js +9 -12
  30. package/dist/components/ui/badge.js.map +1 -1
  31. package/dist/components/ui/breadcrumb.d.ts +17 -9
  32. package/dist/components/ui/breadcrumb.d.ts.map +1 -1
  33. package/dist/components/ui/breadcrumb.js +32 -39
  34. package/dist/components/ui/breadcrumb.js.map +1 -1
  35. package/dist/components/ui/bubble-background.d.ts +1 -1
  36. package/dist/components/ui/bubble-background.d.ts.map +1 -1
  37. package/dist/components/ui/bubble-background.js +13 -13
  38. package/dist/components/ui/bubble-background.js.map +1 -1
  39. package/dist/components/ui/button-group.d.ts +13 -0
  40. package/dist/components/ui/button-group.d.ts.map +1 -0
  41. package/dist/components/ui/button-group.js +47 -0
  42. package/dist/components/ui/button-group.js.map +1 -0
  43. package/dist/components/ui/button.d.ts +8 -7
  44. package/dist/components/ui/button.d.ts.map +1 -1
  45. package/dist/components/ui/button.js +16 -15
  46. package/dist/components/ui/button.js.map +1 -1
  47. package/dist/components/ui/calendar.d.ts.map +1 -1
  48. package/dist/components/ui/calendar.js +22 -22
  49. package/dist/components/ui/calendar.js.map +1 -1
  50. package/dist/components/ui/card.d.ts +7 -8
  51. package/dist/components/ui/card.d.ts.map +1 -1
  52. package/dist/components/ui/card.js +33 -46
  53. package/dist/components/ui/card.js.map +1 -1
  54. package/dist/components/ui/carousel.d.ts +7 -8
  55. package/dist/components/ui/carousel.d.ts.map +1 -1
  56. package/dist/components/ui/carousel.js +30 -21
  57. package/dist/components/ui/carousel.js.map +1 -1
  58. package/dist/components/ui/chart.d.ts +37 -29
  59. package/dist/components/ui/chart.d.ts.map +1 -1
  60. package/dist/components/ui/chart.js +29 -27
  61. package/dist/components/ui/chart.js.map +1 -1
  62. package/dist/components/ui/checkbox.d.ts +2 -2
  63. package/dist/components/ui/checkbox.d.ts.map +1 -1
  64. package/dist/components/ui/checkbox.js +11 -13
  65. package/dist/components/ui/checkbox.js.map +1 -1
  66. package/dist/components/ui/collapsible.d.ts +4 -5
  67. package/dist/components/ui/collapsible.d.ts.map +1 -1
  68. package/dist/components/ui/collapsible.js +3 -20
  69. package/dist/components/ui/collapsible.js.map +1 -1
  70. package/dist/components/ui/command.d.ts +79 -17
  71. package/dist/components/ui/command.d.ts.map +1 -1
  72. package/dist/components/ui/command.js +52 -77
  73. package/dist/components/ui/command.js.map +1 -1
  74. package/dist/components/ui/context-menu.d.ts +23 -21
  75. package/dist/components/ui/context-menu.d.ts.map +1 -1
  76. package/dist/components/ui/context-menu.js +60 -104
  77. package/dist/components/ui/context-menu.js.map +1 -1
  78. package/dist/components/ui/counting-number.d.ts +1 -1
  79. package/dist/components/ui/counting-number.d.ts.map +1 -1
  80. package/dist/components/ui/counting-number.js +4 -3
  81. package/dist/components/ui/counting-number.js.map +1 -1
  82. package/dist/components/ui/dialog.d.ts +17 -13
  83. package/dist/components/ui/dialog.d.ts.map +1 -1
  84. package/dist/components/ui/dialog.js +38 -66
  85. package/dist/components/ui/dialog.js.map +1 -1
  86. package/dist/components/ui/dot-background.d.ts +10 -17
  87. package/dist/components/ui/dot-background.d.ts.map +1 -1
  88. package/dist/components/ui/dot-background.js +2 -2
  89. package/dist/components/ui/dot-background.js.map +1 -1
  90. package/dist/components/ui/drawer.d.ts +20 -11
  91. package/dist/components/ui/drawer.d.ts.map +1 -1
  92. package/dist/components/ui/drawer.js +37 -62
  93. package/dist/components/ui/drawer.js.map +1 -1
  94. package/dist/components/ui/dropdown-menu.d.ts +23 -21
  95. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  96. package/dist/components/ui/dropdown-menu.js +65 -109
  97. package/dist/components/ui/dropdown-menu.js.map +1 -1
  98. package/dist/components/ui/dropdrawer.d.ts +3 -3
  99. package/dist/components/ui/dropdrawer.d.ts.map +1 -1
  100. package/dist/components/ui/dropdrawer.js +13 -16
  101. package/dist/components/ui/dropdrawer.js.map +1 -1
  102. package/dist/components/ui/empty.d.ts +13 -0
  103. package/dist/components/ui/empty.d.ts.map +1 -0
  104. package/dist/components/ui/empty.js +65 -0
  105. package/dist/components/ui/empty.js.map +1 -0
  106. package/dist/components/ui/field.d.ts +25 -0
  107. package/dist/components/ui/field.d.ts.map +1 -0
  108. package/dist/components/ui/field.js +135 -0
  109. package/dist/components/ui/field.js.map +1 -0
  110. package/dist/components/ui/fireworks-background.d.ts.map +1 -1
  111. package/dist/components/ui/fireworks-background.js +1 -1
  112. package/dist/components/ui/fireworks-background.js.map +1 -1
  113. package/dist/components/ui/flip-button.d.ts +1 -1
  114. package/dist/components/ui/flip-button.d.ts.map +1 -1
  115. package/dist/components/ui/flip-button.js +3 -3
  116. package/dist/components/ui/flip-button.js.map +1 -1
  117. package/dist/components/ui/form.d.ts +7 -8
  118. package/dist/components/ui/form.d.ts.map +1 -1
  119. package/dist/components/ui/form.js +29 -28
  120. package/dist/components/ui/form.js.map +1 -1
  121. package/dist/components/ui/gradient-background.d.ts +1 -1
  122. package/dist/components/ui/gradient-background.d.ts.map +1 -1
  123. package/dist/components/ui/gradient-background.js +2 -2
  124. package/dist/components/ui/gradient-background.js.map +1 -1
  125. package/dist/components/ui/gradient-text.d.ts +1 -1
  126. package/dist/components/ui/gradient-text.d.ts.map +1 -1
  127. package/dist/components/ui/gradient-text.js +5 -5
  128. package/dist/components/ui/gradient-text.js.map +1 -1
  129. package/dist/components/ui/highlight-text.d.ts +1 -1
  130. package/dist/components/ui/highlight-text.d.ts.map +1 -1
  131. package/dist/components/ui/highlight-text.js +3 -3
  132. package/dist/components/ui/highlight-text.js.map +1 -1
  133. package/dist/components/ui/hole-background.d.ts.map +1 -1
  134. package/dist/components/ui/hole-background.js +11 -10
  135. package/dist/components/ui/hole-background.js.map +1 -1
  136. package/dist/components/ui/hover-card.d.ts +5 -5
  137. package/dist/components/ui/hover-card.d.ts.map +1 -1
  138. package/dist/components/ui/hover-card.js +12 -26
  139. package/dist/components/ui/hover-card.js.map +1 -1
  140. package/dist/components/ui/input-group.d.ts +17 -0
  141. package/dist/components/ui/input-group.d.ts.map +1 -0
  142. package/dist/components/ui/input-group.js +91 -0
  143. package/dist/components/ui/input-group.js.map +1 -0
  144. package/dist/components/ui/input-otp.d.ts +31 -8
  145. package/dist/components/ui/input-otp.d.ts.map +1 -1
  146. package/dist/components/ui/input-otp.js +24 -27
  147. package/dist/components/ui/input-otp.js.map +1 -1
  148. package/dist/components/ui/input.d.ts +1 -1
  149. package/dist/components/ui/input.d.ts.map +1 -1
  150. package/dist/components/ui/input.js +7 -8
  151. package/dist/components/ui/input.js.map +1 -1
  152. package/dist/components/ui/item.d.ts +24 -0
  153. package/dist/components/ui/item.d.ts.map +1 -0
  154. package/dist/components/ui/item.js +122 -0
  155. package/dist/components/ui/item.js.map +1 -0
  156. package/dist/components/ui/kbd.d.ts +5 -0
  157. package/dist/components/ui/kbd.d.ts.map +1 -0
  158. package/dist/components/ui/kbd.js +21 -0
  159. package/dist/components/ui/kbd.js.map +1 -0
  160. package/dist/components/ui/label.d.ts +3 -2
  161. package/dist/components/ui/label.d.ts.map +1 -1
  162. package/dist/components/ui/label.js +9 -8
  163. package/dist/components/ui/label.js.map +1 -1
  164. package/dist/components/ui/menubar.d.ts +20 -18
  165. package/dist/components/ui/menubar.d.ts.map +1 -1
  166. package/dist/components/ui/menubar.js +75 -95
  167. package/dist/components/ui/menubar.js.map +1 -1
  168. package/dist/components/ui/navigation-menu.d.ts +11 -13
  169. package/dist/components/ui/navigation-menu.d.ts.map +1 -1
  170. package/dist/components/ui/navigation-menu.js +39 -58
  171. package/dist/components/ui/navigation-menu.js.map +1 -1
  172. package/dist/components/ui/pagination.d.ts +25 -10
  173. package/dist/components/ui/pagination.d.ts.map +1 -1
  174. package/dist/components/ui/pagination.js +33 -41
  175. package/dist/components/ui/pagination.js.map +1 -1
  176. package/dist/components/ui/popover.d.ts +6 -6
  177. package/dist/components/ui/popover.d.ts.map +1 -1
  178. package/dist/components/ui/popover.js +10 -26
  179. package/dist/components/ui/popover.js.map +1 -1
  180. package/dist/components/ui/progress.d.ts +2 -2
  181. package/dist/components/ui/progress.d.ts.map +1 -1
  182. package/dist/components/ui/progress.js +8 -10
  183. package/dist/components/ui/progress.js.map +1 -1
  184. package/dist/components/ui/radio-group.d.ts +3 -3
  185. package/dist/components/ui/radio-group.d.ts.map +1 -1
  186. package/dist/components/ui/radio-group.js +17 -20
  187. package/dist/components/ui/radio-group.js.map +1 -1
  188. package/dist/components/ui/resizable.d.ts +21 -6
  189. package/dist/components/ui/resizable.d.ts.map +1 -1
  190. package/dist/components/ui/resizable.js +9 -21
  191. package/dist/components/ui/resizable.js.map +1 -1
  192. package/dist/components/ui/ripple-button.d.ts +1 -1
  193. package/dist/components/ui/ripple-button.d.ts.map +1 -1
  194. package/dist/components/ui/ripple-button.js +4 -4
  195. package/dist/components/ui/ripple-button.js.map +1 -1
  196. package/dist/components/ui/scratcher.d.ts.map +1 -1
  197. package/dist/components/ui/scratcher.js +7 -5
  198. package/dist/components/ui/scratcher.js.map +1 -1
  199. package/dist/components/ui/scroll-area.d.ts +3 -3
  200. package/dist/components/ui/scroll-area.d.ts.map +1 -1
  201. package/dist/components/ui/scroll-area.js +14 -18
  202. package/dist/components/ui/scroll-area.js.map +1 -1
  203. package/dist/components/ui/select.d.ts +11 -13
  204. package/dist/components/ui/select.d.ts.map +1 -1
  205. package/dist/components/ui/select.js +55 -78
  206. package/dist/components/ui/select.js.map +1 -1
  207. package/dist/components/ui/separator.d.ts +2 -2
  208. package/dist/components/ui/separator.d.ts.map +1 -1
  209. package/dist/components/ui/separator.js +7 -8
  210. package/dist/components/ui/separator.js.map +1 -1
  211. package/dist/components/ui/sheet.d.ts +24 -12
  212. package/dist/components/ui/sheet.d.ts.map +1 -1
  213. package/dist/components/ui/sheet.js +56 -68
  214. package/dist/components/ui/sheet.js.map +1 -1
  215. package/dist/components/ui/sidebar.d.ts +35 -39
  216. package/dist/components/ui/sidebar.d.ts.map +1 -1
  217. package/dist/components/ui/sidebar.js +115 -124
  218. package/dist/components/ui/sidebar.js.map +1 -1
  219. package/dist/components/ui/skeleton.d.ts +1 -1
  220. package/dist/components/ui/skeleton.d.ts.map +1 -1
  221. package/dist/components/ui/skeleton.js +2 -3
  222. package/dist/components/ui/skeleton.js.map +1 -1
  223. package/dist/components/ui/slider.d.ts +2 -2
  224. package/dist/components/ui/slider.d.ts.map +1 -1
  225. package/dist/components/ui/slider.js +12 -31
  226. package/dist/components/ui/slider.js.map +1 -1
  227. package/dist/components/ui/sonner.d.ts +4 -2
  228. package/dist/components/ui/sonner.d.ts.map +1 -1
  229. package/dist/components/ui/sonner.js +8 -5
  230. package/dist/components/ui/sonner.js.map +1 -1
  231. package/dist/components/ui/spinner.d.ts +4 -0
  232. package/dist/components/ui/spinner.d.ts.map +1 -0
  233. package/dist/components/ui/spinner.js +16 -0
  234. package/dist/components/ui/spinner.js.map +1 -0
  235. package/dist/components/ui/switch.d.ts +2 -2
  236. package/dist/components/ui/switch.d.ts.map +1 -1
  237. package/dist/components/ui/switch.js +8 -10
  238. package/dist/components/ui/switch.js.map +1 -1
  239. package/dist/components/ui/table.d.ts +9 -9
  240. package/dist/components/ui/table.d.ts.map +1 -1
  241. package/dist/components/ui/table.js +40 -49
  242. package/dist/components/ui/table.js.map +1 -1
  243. package/dist/components/ui/tabs.d.ts +6 -6
  244. package/dist/components/ui/tabs.d.ts.map +1 -1
  245. package/dist/components/ui/tabs.js +18 -27
  246. package/dist/components/ui/tabs.js.map +1 -1
  247. package/dist/components/ui/textarea.d.ts +1 -1
  248. package/dist/components/ui/textarea.d.ts.map +1 -1
  249. package/dist/components/ui/textarea.js +7 -8
  250. package/dist/components/ui/textarea.js.map +1 -1
  251. package/dist/components/ui/toggle-group.d.ts +9 -4
  252. package/dist/components/ui/toggle-group.d.ts.map +1 -1
  253. package/dist/components/ui/toggle-group.js +12 -16
  254. package/dist/components/ui/toggle-group.js.map +1 -1
  255. package/dist/components/ui/toggle.d.ts +9 -6
  256. package/dist/components/ui/toggle.d.ts.map +1 -1
  257. package/dist/components/ui/toggle.js +8 -9
  258. package/dist/components/ui/toggle.js.map +1 -1
  259. package/dist/components/ui/tooltip.d.ts +6 -6
  260. package/dist/components/ui/tooltip.d.ts.map +1 -1
  261. package/dist/components/ui/tooltip.js +14 -39
  262. package/dist/components/ui/tooltip.js.map +1 -1
  263. package/dist/components/ui/typewriter.d.ts.map +1 -1
  264. package/dist/components/ui/typewriter.js +9 -9
  265. package/dist/components/ui/typewriter.js.map +1 -1
  266. package/dist/hooks/useIsMobile.d.ts +2 -5
  267. package/dist/hooks/useIsMobile.d.ts.map +1 -1
  268. package/dist/hooks/useIsMobile.js +1 -1
  269. package/dist/hooks/useIsMobile.js.map +1 -1
  270. package/dist/hooks/useWindowSize.d.ts +0 -1
  271. package/dist/hooks/useWindowSize.d.ts.map +1 -1
  272. package/dist/hooks/useWindowSize.js +1 -1
  273. package/dist/hooks/useWindowSize.js.map +1 -1
  274. package/dist/index.css +841 -1128
  275. package/dist/index.css.map +1 -1
  276. package/dist/index.d.ts +43 -37
  277. package/dist/index.d.ts.map +1 -1
  278. package/dist/index.js +11 -5
  279. package/dist/lib/utilities.d.ts +9 -0
  280. package/dist/lib/utilities.d.ts.map +1 -0
  281. package/dist/lib/{utils.js → utilities.js} +1 -1
  282. package/dist/lib/utilities.js.map +1 -0
  283. package/package.json +121 -90
  284. package/{README.md → readme.md} +627 -627
  285. package/src/components/ui/accordion.tsx +55 -66
  286. package/src/components/ui/alert-dialog.tsx +124 -160
  287. package/src/components/ui/alert.tsx +56 -69
  288. package/src/components/ui/aspect-ratio.tsx +7 -12
  289. package/src/components/ui/avatar.tsx +43 -53
  290. package/src/components/ui/background-beams.tsx +145 -142
  291. package/src/components/ui/badge.tsx +39 -48
  292. package/src/components/ui/breadcrumb.tsx +94 -117
  293. package/src/components/ui/bubble-background.tsx +170 -189
  294. package/src/components/ui/button-group.tsx +69 -0
  295. package/src/components/ui/button.tsx +55 -61
  296. package/src/components/ui/calendar.tsx +175 -216
  297. package/src/components/ui/card.tsx +64 -97
  298. package/src/components/ui/carousel.tsx +216 -241
  299. package/src/components/ui/chart.tsx +293 -385
  300. package/src/components/ui/checkbox.tsx +27 -32
  301. package/src/components/ui/collapsible.tsx +11 -34
  302. package/src/components/ui/command.tsx +138 -184
  303. package/src/components/ui/context-menu.tsx +186 -255
  304. package/src/components/ui/counting-number.tsx +92 -108
  305. package/src/components/ui/dialog.tsx +106 -146
  306. package/src/components/ui/dot-background.tsx +153 -158
  307. package/src/components/ui/drawer.tsx +105 -141
  308. package/src/components/ui/dropdown-menu.tsx +188 -260
  309. package/src/components/ui/dropdrawer.tsx +865 -973
  310. package/src/components/ui/empty.tsx +86 -0
  311. package/src/components/ui/field.tsx +198 -0
  312. package/src/components/ui/fireworks-background.tsx +325 -378
  313. package/src/components/ui/flip-button.tsx +89 -110
  314. package/src/components/ui/form.tsx +144 -174
  315. package/src/components/ui/gradient-background.tsx +30 -43
  316. package/src/components/ui/gradient-text.tsx +62 -65
  317. package/src/components/ui/highlight-text.tsx +54 -71
  318. package/src/components/ui/hole-background.tsx +326 -361
  319. package/src/components/ui/hover-card.tsx +29 -44
  320. package/src/components/ui/input-group.tsx +145 -0
  321. package/src/components/ui/input-otp.tsx +66 -77
  322. package/src/components/ui/input.tsx +21 -22
  323. package/src/components/ui/item.tsx +163 -0
  324. package/src/components/ui/kbd.tsx +31 -0
  325. package/src/components/ui/label.tsx +23 -24
  326. package/src/components/ui/menubar.tsx +233 -279
  327. package/src/components/ui/navigation-menu.tsx +120 -171
  328. package/src/components/ui/pagination.tsx +92 -129
  329. package/src/components/ui/popover.tsx +33 -48
  330. package/src/components/ui/progress.tsx +24 -31
  331. package/src/components/ui/radio-group.tsx +43 -45
  332. package/src/components/ui/resizable.tsx +38 -56
  333. package/src/components/ui/ripple-button.tsx +90 -111
  334. package/src/components/ui/scratcher.tsx +167 -171
  335. package/src/components/ui/scroll-area.tsx +42 -58
  336. package/src/components/ui/select.tsx +145 -191
  337. package/src/components/ui/separator.tsx +26 -28
  338. package/src/components/ui/sheet.tsx +112 -145
  339. package/src/components/ui/sidebar.tsx +664 -729
  340. package/src/components/ui/skeleton.tsx +15 -19
  341. package/src/components/ui/slider.tsx +23 -63
  342. package/src/components/ui/sonner.tsx +36 -26
  343. package/src/components/ui/spinner.tsx +18 -0
  344. package/src/components/ui/switch.tsx +28 -31
  345. package/src/components/ui/table.tsx +93 -119
  346. package/src/components/ui/tabs.tsx +54 -66
  347. package/src/components/ui/textarea.tsx +21 -20
  348. package/src/components/ui/toggle-group.tsx +53 -73
  349. package/src/components/ui/toggle.tsx +44 -47
  350. package/src/components/ui/tooltip.tsx +32 -61
  351. package/src/components/ui/typewriter.tsx +173 -188
  352. package/src/hooks/useIsMobile.tsx +42 -45
  353. package/src/hooks/useWindowSize.tsx +66 -72
  354. package/src/index.css +67 -67
  355. package/src/index.ts +342 -408
  356. package/src/lib/utilities.ts +12 -0
  357. package/dist/lib/utils.d.ts +0 -7
  358. package/dist/lib/utils.d.ts.map +0 -1
  359. package/dist/lib/utils.js.map +0 -1
  360. package/src/lib/utils.ts +0 -10
@@ -1,255 +1,186 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
5
- import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
6
-
7
- import { cn } from "@/lib/utils";
8
-
9
- function ContextMenu({
10
- ...props
11
- }: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
12
- return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />;
13
- }
14
-
15
- function ContextMenuTrigger({
16
- ...props
17
- }: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
18
- return (
19
- <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />
20
- );
21
- }
22
-
23
- function ContextMenuGroup({
24
- ...props
25
- }: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
26
- return (
27
- <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
28
- );
29
- }
30
-
31
- function ContextMenuPortal({
32
- ...props
33
- }: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
34
- return (
35
- <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
36
- );
37
- }
38
-
39
- function ContextMenuSub({
40
- ...props
41
- }: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
42
- return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />;
43
- }
44
-
45
- function ContextMenuRadioGroup({
46
- ...props
47
- }: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {
48
- return (
49
- <ContextMenuPrimitive.RadioGroup
50
- data-slot="context-menu-radio-group"
51
- {...props}
52
- />
53
- );
54
- }
55
-
56
- function ContextMenuSubTrigger({
57
- className,
58
- inset,
59
- children,
60
- ...props
61
- }: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
62
- inset?: boolean;
63
- }) {
64
- return (
65
- <ContextMenuPrimitive.SubTrigger
66
- data-slot="context-menu-sub-trigger"
67
- data-inset={inset}
68
- className={cn(
69
- "focus:bg-neutral-100 focus:text-neutral-900 data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-900 flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:focus:bg-neutral-800 dark:focus:text-neutral-50 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-50",
70
- className,
71
- )}
72
- {...props}
73
- >
74
- {children}
75
- <ChevronRightIcon className="ml-auto" />
76
- </ContextMenuPrimitive.SubTrigger>
77
- );
78
- }
79
-
80
- function ContextMenuSubContent({
81
- className,
82
- ...props
83
- }: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
84
- return (
85
- <ContextMenuPrimitive.SubContent
86
- data-slot="context-menu-sub-content"
87
- className={cn(
88
- "bg-white text-neutral-950 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-md border border-neutral-200 p-1 shadow-lg dark:bg-neutral-950 dark:text-neutral-50 dark:border-neutral-800",
89
- className,
90
- )}
91
- {...props}
92
- />
93
- );
94
- }
95
-
96
- function ContextMenuContent({
97
- className,
98
- ...props
99
- }: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {
100
- return (
101
- <ContextMenuPrimitive.Portal>
102
- <ContextMenuPrimitive.Content
103
- data-slot="context-menu-content"
104
- className={cn(
105
- "bg-white text-neutral-950 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 z-50 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border border-neutral-200 p-1 shadow-md dark:bg-neutral-950 dark:text-neutral-50 dark:border-neutral-800",
106
- className,
107
- )}
108
- {...props}
109
- />
110
- </ContextMenuPrimitive.Portal>
111
- );
112
- }
113
-
114
- function ContextMenuItem({
115
- className,
116
- inset,
117
- variant = "default",
118
- ...props
119
- }: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
120
- inset?: boolean;
121
- variant?: "default" | "destructive";
122
- }) {
123
- return (
124
- <ContextMenuPrimitive.Item
125
- data-slot="context-menu-item"
126
- data-inset={inset}
127
- data-variant={variant}
128
- className={cn(
129
- "focus:bg-neutral-100 focus:text-neutral-900 data-[variant=destructive]:text-red-500 data-[variant=destructive]:focus:bg-red-500/10 dark:data-[variant=destructive]:focus:bg-red-500/20 data-[variant=destructive]:focus:text-red-500 data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-neutral-500 relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:focus:bg-neutral-800 dark:focus:text-neutral-50 dark:data-[variant=destructive]:text-red-900 dark:data-[variant=destructive]:focus:bg-red-900/10 dark:dark:data-[variant=destructive]:focus:bg-red-900/20 dark:data-[variant=destructive]:focus:text-red-900 dark:[&_svg:not([class*='text-'])]:text-neutral-400",
130
- className,
131
- )}
132
- {...props}
133
- />
134
- );
135
- }
136
-
137
- function ContextMenuCheckboxItem({
138
- className,
139
- children,
140
- checked,
141
- ...props
142
- }: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {
143
- return (
144
- <ContextMenuPrimitive.CheckboxItem
145
- data-slot="context-menu-checkbox-item"
146
- className={cn(
147
- "focus:bg-neutral-100 focus:text-neutral-900 relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
148
- className,
149
- )}
150
- checked={checked}
151
- {...props}
152
- >
153
- <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
154
- <ContextMenuPrimitive.ItemIndicator>
155
- <CheckIcon className="size-4" />
156
- </ContextMenuPrimitive.ItemIndicator>
157
- </span>
158
- {children}
159
- </ContextMenuPrimitive.CheckboxItem>
160
- );
161
- }
162
-
163
- function ContextMenuRadioItem({
164
- className,
165
- children,
166
- ...props
167
- }: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {
168
- return (
169
- <ContextMenuPrimitive.RadioItem
170
- data-slot="context-menu-radio-item"
171
- className={cn(
172
- "focus:bg-neutral-100 focus:text-neutral-900 relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
173
- className,
174
- )}
175
- {...props}
176
- >
177
- <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
178
- <ContextMenuPrimitive.ItemIndicator>
179
- <CircleIcon className="size-2 fill-current" />
180
- </ContextMenuPrimitive.ItemIndicator>
181
- </span>
182
- {children}
183
- </ContextMenuPrimitive.RadioItem>
184
- );
185
- }
186
-
187
- function ContextMenuLabel({
188
- className,
189
- inset,
190
- ...props
191
- }: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
192
- inset?: boolean;
193
- }) {
194
- return (
195
- <ContextMenuPrimitive.Label
196
- data-slot="context-menu-label"
197
- data-inset={inset}
198
- className={cn(
199
- "text-neutral-950 px-2 py-1.5 text-sm font-medium data-[inset]:pl-8 dark:text-neutral-50",
200
- className,
201
- )}
202
- {...props}
203
- />
204
- );
205
- }
206
-
207
- function ContextMenuSeparator({
208
- className,
209
- ...props
210
- }: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
211
- return (
212
- <ContextMenuPrimitive.Separator
213
- data-slot="context-menu-separator"
214
- className={cn(
215
- "bg-neutral-200 -mx-1 my-1 h-px dark:bg-neutral-800",
216
- className,
217
- )}
218
- {...props}
219
- />
220
- );
221
- }
222
-
223
- function ContextMenuShortcut({
224
- className,
225
- ...props
226
- }: React.ComponentProps<"span">) {
227
- return (
228
- <span
229
- data-slot="context-menu-shortcut"
230
- className={cn(
231
- "text-neutral-500 ml-auto text-xs tracking-widest dark:text-neutral-400",
232
- className,
233
- )}
234
- {...props}
235
- />
236
- );
237
- }
238
-
239
- export {
240
- ContextMenu,
241
- ContextMenuTrigger,
242
- ContextMenuContent,
243
- ContextMenuItem,
244
- ContextMenuCheckboxItem,
245
- ContextMenuRadioItem,
246
- ContextMenuLabel,
247
- ContextMenuSeparator,
248
- ContextMenuShortcut,
249
- ContextMenuGroup,
250
- ContextMenuPortal,
251
- ContextMenuSub,
252
- ContextMenuSubContent,
253
- ContextMenuSubTrigger,
254
- ContextMenuRadioGroup,
255
- };
1
+ "use client";
2
+
3
+ import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
4
+ import {Check, ChevronRight, Circle} from "lucide-react";
5
+ import * as React from "react";
6
+
7
+ import {cn} from "@/lib/utilities";
8
+
9
+ const ContextMenu = ContextMenuPrimitive.Root;
10
+
11
+ const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
12
+
13
+ const ContextMenuGroup = ContextMenuPrimitive.Group;
14
+
15
+ const ContextMenuPortal = ContextMenuPrimitive.Portal;
16
+
17
+ const ContextMenuSub = ContextMenuPrimitive.Sub;
18
+
19
+ const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
20
+
21
+ const ContextMenuSubTrigger = React.forwardRef<
22
+ React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
23
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
24
+ inset?: boolean;
25
+ }
26
+ >(({className, inset, children, ...props}, ref) => (
27
+ <ContextMenuPrimitive.SubTrigger
28
+ ref={ref}
29
+ className={cn(
30
+ "flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none focus:bg-neutral-100 focus:text-neutral-900 data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-900 dark:focus:bg-neutral-800 dark:focus:text-neutral-50 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-50",
31
+ inset && "pl-8",
32
+ className,
33
+ )}
34
+ {...props}>
35
+ {children}
36
+ <ChevronRight className='ml-auto h-4 w-4' />
37
+ </ContextMenuPrimitive.SubTrigger>
38
+ ));
39
+ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
40
+
41
+ const ContextMenuSubContent = React.forwardRef<
42
+ React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
43
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
44
+ >(({className, ...props}, ref) => (
45
+ <ContextMenuPrimitive.SubContent
46
+ ref={ref}
47
+ className={cn(
48
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 z-50 min-w-[8rem] origin-[--radix-context-menu-content-transform-origin] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-lg dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
49
+ className,
50
+ )}
51
+ {...props}
52
+ />
53
+ ));
54
+ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
55
+
56
+ const ContextMenuContent = React.forwardRef<
57
+ React.ElementRef<typeof ContextMenuPrimitive.Content>,
58
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
59
+ >(({className, ...props}, ref) => (
60
+ <ContextMenuPrimitive.Portal>
61
+ <ContextMenuPrimitive.Content
62
+ ref={ref}
63
+ className={cn(
64
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 z-50 max-h-[--radix-context-menu-content-available-height] min-w-[8rem] origin-[--radix-context-menu-content-transform-origin] overflow-x-hidden overflow-y-auto rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-md dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
65
+ className,
66
+ )}
67
+ {...props}
68
+ />
69
+ </ContextMenuPrimitive.Portal>
70
+ ));
71
+ ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
72
+
73
+ const ContextMenuItem = React.forwardRef<
74
+ React.ElementRef<typeof ContextMenuPrimitive.Item>,
75
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
76
+ inset?: boolean;
77
+ }
78
+ >(({className, inset, ...props}, ref) => (
79
+ <ContextMenuPrimitive.Item
80
+ ref={ref}
81
+ className={cn(
82
+ "relative flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
83
+ inset && "pl-8",
84
+ className,
85
+ )}
86
+ {...props}
87
+ />
88
+ ));
89
+ ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
90
+
91
+ const ContextMenuCheckboxItem = React.forwardRef<
92
+ React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
93
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
94
+ >(({className, children, checked, ...props}, ref) => (
95
+ <ContextMenuPrimitive.CheckboxItem
96
+ ref={ref}
97
+ className={cn(
98
+ "relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
99
+ className,
100
+ )}
101
+ checked={checked}
102
+ {...props}>
103
+ <span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
104
+ <ContextMenuPrimitive.ItemIndicator>
105
+ <Check className='h-4 w-4' />
106
+ </ContextMenuPrimitive.ItemIndicator>
107
+ </span>
108
+ {children}
109
+ </ContextMenuPrimitive.CheckboxItem>
110
+ ));
111
+ ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
112
+
113
+ const ContextMenuRadioItem = React.forwardRef<
114
+ React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
115
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
116
+ >(({className, children, ...props}, ref) => (
117
+ <ContextMenuPrimitive.RadioItem
118
+ ref={ref}
119
+ className={cn(
120
+ "relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
121
+ className,
122
+ )}
123
+ {...props}>
124
+ <span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
125
+ <ContextMenuPrimitive.ItemIndicator>
126
+ <Circle className='h-4 w-4 fill-current' />
127
+ </ContextMenuPrimitive.ItemIndicator>
128
+ </span>
129
+ {children}
130
+ </ContextMenuPrimitive.RadioItem>
131
+ ));
132
+ ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
133
+
134
+ const ContextMenuLabel = React.forwardRef<
135
+ React.ElementRef<typeof ContextMenuPrimitive.Label>,
136
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
137
+ inset?: boolean;
138
+ }
139
+ >(({className, inset, ...props}, ref) => (
140
+ <ContextMenuPrimitive.Label
141
+ ref={ref}
142
+ className={cn("px-2 py-1.5 text-sm font-semibold text-neutral-950 dark:text-neutral-50", inset && "pl-8", className)}
143
+ {...props}
144
+ />
145
+ ));
146
+ ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
147
+
148
+ const ContextMenuSeparator = React.forwardRef<
149
+ React.ElementRef<typeof ContextMenuPrimitive.Separator>,
150
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
151
+ >(({className, ...props}, ref) => (
152
+ <ContextMenuPrimitive.Separator
153
+ ref={ref}
154
+ className={cn("-mx-1 my-1 h-px bg-neutral-200 dark:bg-neutral-800", className)}
155
+ {...props}
156
+ />
157
+ ));
158
+ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
159
+
160
+ const ContextMenuShortcut = ({className, ...props}: React.HTMLAttributes<HTMLSpanElement>) => {
161
+ return (
162
+ <span
163
+ className={cn("ml-auto text-xs tracking-widest text-neutral-500 dark:text-neutral-400", className)}
164
+ {...props}
165
+ />
166
+ );
167
+ };
168
+ ContextMenuShortcut.displayName = "ContextMenuShortcut";
169
+
170
+ export {
171
+ ContextMenu,
172
+ ContextMenuCheckboxItem,
173
+ ContextMenuContent,
174
+ ContextMenuGroup,
175
+ ContextMenuItem,
176
+ ContextMenuLabel,
177
+ ContextMenuPortal,
178
+ ContextMenuRadioGroup,
179
+ ContextMenuRadioItem,
180
+ ContextMenuSeparator,
181
+ ContextMenuShortcut,
182
+ ContextMenuSub,
183
+ ContextMenuSubContent,
184
+ ContextMenuSubTrigger,
185
+ ContextMenuTrigger,
186
+ };
@@ -1,108 +1,92 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import {
5
- type SpringOptions,
6
- type UseInViewOptions,
7
- useInView,
8
- useMotionValue,
9
- useSpring,
10
- } from "motion/react";
11
-
12
- interface CountingNumberProps extends React.HTMLAttributes<HTMLSpanElement> {
13
- number: number;
14
- fromNumber?: number;
15
- padStart?: boolean;
16
- inView?: boolean;
17
- inViewMargin?: UseInViewOptions["margin"];
18
- inViewOnce?: boolean;
19
- decimalSeparator?: string;
20
- transition?: SpringOptions;
21
- decimalPlaces?: number;
22
- }
23
-
24
- const CountingNumber = React.forwardRef<HTMLSpanElement, CountingNumberProps>(
25
- (
26
- {
27
- number,
28
- fromNumber = 0,
29
- padStart = false,
30
- inView = false,
31
- inViewMargin = "0px",
32
- inViewOnce = true,
33
- decimalSeparator = ".",
34
- transition = { stiffness: 90, damping: 50 },
35
- decimalPlaces = 0,
36
- className,
37
- ...props
38
- },
39
- ref,
40
- ) => {
41
- const localRef = React.useRef<HTMLSpanElement>(null);
42
- React.useImperativeHandle(ref, () => localRef.current as HTMLSpanElement);
43
-
44
- const numberStr = number.toString();
45
- const decimals =
46
- typeof decimalPlaces === "number"
47
- ? decimalPlaces
48
- : numberStr.includes(".")
49
- ? numberStr.split(".")[1].length
50
- : 0;
51
-
52
- const motionVal = useMotionValue(fromNumber);
53
- const springVal = useSpring(motionVal, transition);
54
- const inViewResult = useInView(localRef, {
55
- once: inViewOnce,
56
- margin: inViewMargin,
57
- });
58
- const isInView = !inView || inViewResult;
59
-
60
- React.useEffect(() => {
61
- if (isInView) motionVal.set(number);
62
- }, [isInView, number, motionVal]);
63
-
64
- React.useEffect(() => {
65
- const unsubscribe = springVal.on("change", (latest) => {
66
- if (localRef.current) {
67
- let formatted =
68
- decimals > 0
69
- ? latest.toFixed(decimals)
70
- : Math.round(latest).toString();
71
-
72
- if (decimals > 0) {
73
- formatted = formatted.replace(".", decimalSeparator);
74
- }
75
-
76
- if (padStart) {
77
- const finalIntLength = Math.floor(Math.abs(number)).toString()
78
- .length;
79
- const [intPart, fracPart] = formatted.split(decimalSeparator);
80
- const paddedInt = intPart.padStart(finalIntLength, "0");
81
- formatted = fracPart
82
- ? `${paddedInt}${decimalSeparator}${fracPart}`
83
- : paddedInt;
84
- }
85
-
86
- localRef.current.textContent = formatted;
87
- }
88
- });
89
- return () => unsubscribe();
90
- }, [springVal, decimals, padStart, number, decimalSeparator]);
91
-
92
- const finalIntLength = Math.floor(Math.abs(number)).toString().length;
93
- const initialText = padStart
94
- ? "0".padStart(finalIntLength, "0") +
95
- (decimals > 0 ? decimalSeparator + "0".repeat(decimals) : "")
96
- : "0" + (decimals > 0 ? decimalSeparator + "0".repeat(decimals) : "");
97
-
98
- return (
99
- <span ref={localRef} className={className} {...props}>
100
- {initialText}
101
- </span>
102
- );
103
- },
104
- );
105
-
106
- CountingNumber.displayName = "CountingNumber";
107
-
108
- export { CountingNumber, type CountingNumberProps };
1
+ "use client";
2
+
3
+ import {type SpringOptions, type UseInViewOptions, useInView, useMotionValue, useSpring} from "motion/react";
4
+ import * as React from "react";
5
+
6
+ interface CountingNumberProps extends React.HTMLAttributes<HTMLSpanElement> {
7
+ number: number;
8
+ fromNumber?: number;
9
+ padStart?: boolean;
10
+ inView?: boolean;
11
+ inViewMargin?: UseInViewOptions["margin"];
12
+ inViewOnce?: boolean;
13
+ decimalSeparator?: string;
14
+ transition?: SpringOptions;
15
+ decimalPlaces?: number;
16
+ }
17
+
18
+ const CountingNumber = React.forwardRef<HTMLSpanElement, CountingNumberProps>(
19
+ (
20
+ {
21
+ number,
22
+ fromNumber = 0,
23
+ padStart = false,
24
+ inView = false,
25
+ inViewMargin = "0px",
26
+ inViewOnce = true,
27
+ decimalSeparator = ".",
28
+ transition = {stiffness: 90, damping: 50},
29
+ decimalPlaces = 0,
30
+ className,
31
+ ...props
32
+ },
33
+ ref,
34
+ ) => {
35
+ const localRef = React.useRef<HTMLSpanElement>(null);
36
+ React.useImperativeHandle(ref, () => localRef.current as HTMLSpanElement);
37
+
38
+ const numberStr = number.toString();
39
+ const decimals = typeof decimalPlaces === "number" ? decimalPlaces : numberStr.includes(".") ? numberStr?.split(".")[1].length : 0;
40
+
41
+ const motionVal = useMotionValue(fromNumber);
42
+ const springVal = useSpring(motionVal, transition);
43
+ const inViewResult = useInView(localRef, {
44
+ once: inViewOnce,
45
+ margin: inViewMargin,
46
+ });
47
+ const isInView = !inView || inViewResult;
48
+
49
+ React.useEffect(() => {
50
+ if (isInView) motionVal.set(number);
51
+ }, [isInView, number, motionVal]);
52
+
53
+ React.useEffect(() => {
54
+ const unsubscribe = springVal.on("change", (latest) => {
55
+ if (localRef.current) {
56
+ let formatted = decimals > 0 ? latest.toFixed(decimals) : Math.round(latest).toString();
57
+
58
+ if (decimals > 0) {
59
+ formatted = formatted.replace(".", decimalSeparator);
60
+ }
61
+
62
+ if (padStart) {
63
+ const finalIntLength = Math.floor(Math.abs(number)).toString().length;
64
+ const [intPart, fracPart] = formatted.split(decimalSeparator);
65
+ const paddedInt = intPart.padStart(finalIntLength, "0");
66
+ formatted = fracPart ? `${paddedInt}${decimalSeparator}${fracPart}` : paddedInt;
67
+ }
68
+
69
+ localRef.current.textContent = formatted;
70
+ }
71
+ });
72
+ return () => unsubscribe();
73
+ }, [springVal, decimals, padStart, number, decimalSeparator]);
74
+
75
+ const finalIntLength = Math.floor(Math.abs(number)).toString().length;
76
+ const suffix = decimals > 0 ? `${decimalSeparator}${"0".repeat(decimals)}` : "";
77
+ const initialText = padStart ? `${"0".padStart(finalIntLength, "0")}${suffix}` : `0${suffix}`;
78
+
79
+ return (
80
+ <span
81
+ ref={localRef}
82
+ className={className}
83
+ {...props}>
84
+ {initialText}
85
+ </span>
86
+ );
87
+ },
88
+ );
89
+
90
+ CountingNumber.displayName = "CountingNumber";
91
+
92
+ export {CountingNumber, type CountingNumberProps};