@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,361 +1,326 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { motion } from "motion/react";
5
-
6
- import { cn } from "@/lib/utils";
7
-
8
- interface HoleBackgroundProps extends React.HTMLAttributes<HTMLCanvasElement> {
9
- strokeColor?: string;
10
- numberOfLines?: number;
11
- numberOfDiscs?: number;
12
- particleRGBColor?: [number, number, number];
13
- }
14
-
15
- const HoleBackground = React.forwardRef<HTMLCanvasElement, HoleBackgroundProps>(
16
- (
17
- {
18
- strokeColor = "#737373",
19
- numberOfLines = 50,
20
- numberOfDiscs = 50,
21
- particleRGBColor = [255, 255, 255],
22
- className,
23
- children,
24
- ...props
25
- },
26
- ref,
27
- ) => {
28
- const canvasRef = React.useRef<HTMLCanvasElement>(null);
29
- React.useImperativeHandle(
30
- ref,
31
- () => canvasRef.current as HTMLCanvasElement,
32
- );
33
-
34
- const animationFrameIdRef = React.useRef<number>(0);
35
- const stateRef = React.useRef<any>({
36
- discs: [] as any[],
37
- lines: [] as any[],
38
- particles: [] as any[],
39
- clip: {},
40
- startDisc: {},
41
- endDisc: {},
42
- rect: { width: 0, height: 0 },
43
- render: { width: 0, height: 0, dpi: 1 },
44
- particleArea: {},
45
- linesCanvas: null,
46
- });
47
-
48
- const linear = (p: number) => p;
49
- const easeInExpo = (p: number) => (p === 0 ? 0 : Math.pow(2, 10 * (p - 1)));
50
-
51
- const tweenValue = React.useCallback(
52
- (start: number, end: number, p: number, ease: "inExpo" | null = null) => {
53
- const delta = end - start;
54
- const easeFn = ease === "inExpo" ? easeInExpo : linear;
55
- return start + delta * easeFn(p);
56
- },
57
- [],
58
- );
59
-
60
- const tweenDisc = React.useCallback(
61
- (disc: any) => {
62
- const { startDisc, endDisc } = stateRef.current;
63
- disc.x = tweenValue(startDisc.x, endDisc.x, disc.p);
64
- disc.y = tweenValue(startDisc.y, endDisc.y, disc.p, "inExpo");
65
- disc.w = tweenValue(startDisc.w, endDisc.w, disc.p);
66
- disc.h = tweenValue(startDisc.h, endDisc.h, disc.p);
67
- },
68
- [tweenValue],
69
- );
70
-
71
- const setSize = React.useCallback(() => {
72
- const canvas = canvasRef.current;
73
- if (!canvas) return;
74
- const rect = canvas.getBoundingClientRect();
75
- stateRef.current.rect = { width: rect.width, height: rect.height };
76
- stateRef.current.render = {
77
- width: rect.width,
78
- height: rect.height,
79
- dpi: window.devicePixelRatio || 1,
80
- };
81
- canvas.width =
82
- stateRef.current.render.width * stateRef.current.render.dpi;
83
- canvas.height =
84
- stateRef.current.render.height * stateRef.current.render.dpi;
85
- }, []);
86
-
87
- const setDiscs = React.useCallback(() => {
88
- const { width, height } = stateRef.current.rect;
89
- stateRef.current.discs = [];
90
- stateRef.current.startDisc = {
91
- x: width * 0.5,
92
- y: height * 0.45,
93
- w: width * 0.75,
94
- h: height * 0.7,
95
- };
96
- stateRef.current.endDisc = {
97
- x: width * 0.5,
98
- y: height * 0.95,
99
- w: 0,
100
- h: 0,
101
- };
102
- let prevBottom = height;
103
- stateRef.current.clip = {};
104
- for (let i = 0; i < numberOfDiscs; i++) {
105
- const p = i / numberOfDiscs;
106
- const disc = { p, x: 0, y: 0, w: 0, h: 0 };
107
- tweenDisc(disc);
108
- const bottom = disc.y + disc.h;
109
- if (bottom <= prevBottom) {
110
- stateRef.current.clip = { disc: { ...disc }, i };
111
- }
112
- prevBottom = bottom;
113
- stateRef.current.discs.push(disc);
114
- }
115
- const clipPath = new Path2D();
116
- const disc = stateRef.current.clip.disc;
117
- clipPath.ellipse(disc.x, disc.y, disc.w, disc.h, 0, 0, Math.PI * 2);
118
- clipPath.rect(disc.x - disc.w, 0, disc.w * 2, disc.y);
119
- stateRef.current.clip.path = clipPath;
120
- }, [tweenDisc]);
121
-
122
- const setLines = React.useCallback(() => {
123
- const { width, height } = stateRef.current.rect;
124
- stateRef.current.lines = [];
125
- const linesAngle = (Math.PI * 2) / numberOfLines;
126
- for (let i = 0; i < numberOfLines; i++) {
127
- stateRef.current.lines.push([]);
128
- }
129
- stateRef.current.discs.forEach((disc: any) => {
130
- for (let i = 0; i < numberOfLines; i++) {
131
- const angle = i * linesAngle;
132
- const p = {
133
- x: disc.x + Math.cos(angle) * disc.w,
134
- y: disc.y + Math.sin(angle) * disc.h,
135
- };
136
- stateRef.current.lines[i].push(p);
137
- }
138
- });
139
- const offCanvas = document.createElement("canvas");
140
- offCanvas.width = width;
141
- offCanvas.height = height;
142
- const ctx = offCanvas.getContext("2d");
143
- if (!ctx) return;
144
- stateRef.current.lines.forEach((line: any) => {
145
- ctx.save();
146
- let lineIsIn = false;
147
- line.forEach((p1: any, j: number) => {
148
- if (j === 0) return;
149
- const p0 = line[j - 1];
150
- if (
151
- !lineIsIn &&
152
- (ctx.isPointInPath(stateRef.current.clip.path, p1.x, p1.y) ||
153
- ctx.isPointInStroke(stateRef.current.clip.path, p1.x, p1.y))
154
- ) {
155
- lineIsIn = true;
156
- } else if (lineIsIn) {
157
- ctx.clip(stateRef.current.clip.path);
158
- }
159
- ctx.beginPath();
160
- ctx.moveTo(p0.x, p0.y);
161
- ctx.lineTo(p1.x, p1.y);
162
- ctx.strokeStyle = strokeColor;
163
- ctx.lineWidth = 2;
164
- ctx.stroke();
165
- ctx.closePath();
166
- });
167
- ctx.restore();
168
- });
169
- stateRef.current.linesCanvas = offCanvas;
170
- }, [strokeColor]);
171
-
172
- const initParticle = React.useCallback((start: boolean = false) => {
173
- const sx =
174
- stateRef.current.particleArea.sx +
175
- stateRef.current.particleArea.sw * Math.random();
176
- const ex =
177
- stateRef.current.particleArea.ex +
178
- stateRef.current.particleArea.ew * Math.random();
179
- const dx = ex - sx;
180
- const y = start
181
- ? stateRef.current.particleArea.h * Math.random()
182
- : stateRef.current.particleArea.h;
183
- const r = 0.5 + Math.random() * 4;
184
- const vy = 0.5 + Math.random();
185
- return {
186
- x: sx,
187
- sx,
188
- dx,
189
- y,
190
- vy,
191
- p: 0,
192
- r,
193
- c: `rgba(${particleRGBColor[0]}, ${particleRGBColor[1]}, ${
194
- particleRGBColor[2]
195
- }, ${Math.random()})`,
196
- };
197
- }, []);
198
-
199
- const setParticles = React.useCallback(() => {
200
- const { width, height } = stateRef.current.rect;
201
- stateRef.current.particles = [];
202
- const disc = stateRef.current.clip.disc;
203
- stateRef.current.particleArea = {
204
- sw: disc.w * 0.5,
205
- ew: disc.w * 2,
206
- h: height * 0.85,
207
- };
208
- stateRef.current.particleArea.sx =
209
- (width - stateRef.current.particleArea.sw) / 2;
210
- stateRef.current.particleArea.ex =
211
- (width - stateRef.current.particleArea.ew) / 2;
212
- const totalParticles = 100;
213
- for (let i = 0; i < totalParticles; i++) {
214
- stateRef.current.particles.push(initParticle(true));
215
- }
216
- }, [initParticle]);
217
-
218
- const drawDiscs = React.useCallback(
219
- (ctx: CanvasRenderingContext2D) => {
220
- ctx.strokeStyle = strokeColor;
221
- ctx.lineWidth = 2;
222
- const outerDisc = stateRef.current.startDisc;
223
- ctx.beginPath();
224
- ctx.ellipse(
225
- outerDisc.x,
226
- outerDisc.y,
227
- outerDisc.w,
228
- outerDisc.h,
229
- 0,
230
- 0,
231
- Math.PI * 2,
232
- );
233
- ctx.stroke();
234
- ctx.closePath();
235
- stateRef.current.discs.forEach((disc: any, i: number) => {
236
- if (i % 5 !== 0) return;
237
- if (disc.w < stateRef.current.clip.disc.w - 5) {
238
- ctx.save();
239
- ctx.clip(stateRef.current.clip.path);
240
- }
241
- ctx.beginPath();
242
- ctx.ellipse(disc.x, disc.y, disc.w, disc.h, 0, 0, Math.PI * 2);
243
- ctx.stroke();
244
- ctx.closePath();
245
- if (disc.w < stateRef.current.clip.disc.w - 5) {
246
- ctx.restore();
247
- }
248
- });
249
- },
250
- [strokeColor],
251
- );
252
-
253
- const drawLines = React.useCallback((ctx: CanvasRenderingContext2D) => {
254
- if (stateRef.current.linesCanvas) {
255
- ctx.drawImage(stateRef.current.linesCanvas, 0, 0);
256
- }
257
- }, []);
258
-
259
- const drawParticles = React.useCallback((ctx: CanvasRenderingContext2D) => {
260
- ctx.save();
261
- ctx.clip(stateRef.current.clip.path);
262
- stateRef.current.particles.forEach((particle: any) => {
263
- ctx.fillStyle = particle.c;
264
- ctx.beginPath();
265
- ctx.rect(particle.x, particle.y, particle.r, particle.r);
266
- ctx.closePath();
267
- ctx.fill();
268
- });
269
- ctx.restore();
270
- }, []);
271
-
272
- const moveDiscs = React.useCallback(() => {
273
- stateRef.current.discs.forEach((disc: any) => {
274
- disc.p = (disc.p + 0.001) % 1;
275
- tweenDisc(disc);
276
- });
277
- }, [tweenDisc]);
278
-
279
- const moveParticles = React.useCallback(() => {
280
- stateRef.current.particles.forEach((particle: any, idx: number) => {
281
- particle.p = 1 - particle.y / stateRef.current.particleArea.h;
282
- particle.x = particle.sx + particle.dx * particle.p;
283
- particle.y -= particle.vy;
284
- if (particle.y < 0) {
285
- stateRef.current.particles[idx] = initParticle();
286
- }
287
- });
288
- }, [initParticle]);
289
-
290
- const tick = React.useCallback(() => {
291
- const canvas = canvasRef.current;
292
- if (!canvas) return;
293
- const ctx = canvas.getContext("2d");
294
- if (!ctx) return;
295
- ctx.clearRect(0, 0, canvas.width, canvas.height);
296
- ctx.save();
297
- ctx.scale(stateRef.current.render.dpi, stateRef.current.render.dpi);
298
- moveDiscs();
299
- moveParticles();
300
- drawDiscs(ctx);
301
- drawLines(ctx);
302
- drawParticles(ctx);
303
- ctx.restore();
304
- animationFrameIdRef.current = requestAnimationFrame(tick);
305
- }, [moveDiscs, moveParticles, drawDiscs, drawLines, drawParticles]);
306
-
307
- const init = React.useCallback(() => {
308
- setSize();
309
- setDiscs();
310
- setLines();
311
- setParticles();
312
- }, [setSize, setDiscs, setLines, setParticles]);
313
-
314
- React.useEffect(() => {
315
- const canvas = canvasRef.current;
316
- if (!canvas) return;
317
- init();
318
- tick();
319
- const handleResize = () => {
320
- setSize();
321
- setDiscs();
322
- setLines();
323
- setParticles();
324
- };
325
- window.addEventListener("resize", handleResize);
326
- return () => {
327
- window.removeEventListener("resize", handleResize);
328
- cancelAnimationFrame(animationFrameIdRef.current);
329
- };
330
- }, [init, tick, setSize, setDiscs, setLines, setParticles]);
331
-
332
- return (
333
- <div
334
- className={cn(
335
- "relative size-full overflow-hidden",
336
- 'before:content-[""] before:absolute before:top-1/2 before:left-1/2 before:block before:size-[140%] dark:before:[background:radial-gradient(ellipse_at_50%_55%,transparent_10%,black_50%)] before:[background:radial-gradient(ellipse_at_50%_55%,transparent_10%,white_50%)] before:[transform:translate3d(-50%,-50%,0)]',
337
- 'after:content-[""] after:absolute after:z-[5] after:top-1/2 after:left-1/2 after:block after:size-full after:[background:radial-gradient(ellipse_at_50%_75%,#a900ff_20%,transparent_75%)] after:[transform:translate3d(-50%,-50%,0)] after:mix-blend-overlay',
338
- className,
339
- )}
340
- >
341
- {children}
342
- <canvas
343
- ref={canvasRef}
344
- className="absolute inset-0 block size-full dark:opacity-20 opacity-10"
345
- {...props}
346
- />
347
- <motion.div
348
- className={cn(
349
- "absolute top-[-71.5%] left-1/2 z-[3] w-[30%] h-[140%] rounded-b-full blur-3xl opacity-75 dark:mix-blend-plus-lighter mix-blend-plus-darker [transform:translate3d(-50%,0,0)] [background-position:0%_100%] [background-size:100%_200%]",
350
- "dark:[background:linear-gradient(20deg,#00f8f1,#ffbd1e20_16.5%,#fe848f_33%,#fe848f20_49.5%,#00f8f1_66%,#00f8f160_85.5%,#ffbd1e_100%)_0_100%_/_100%_200%] [background:linear-gradient(20deg,#00f8f1,#ffbd1e40_16.5%,#fe848f_33%,#fe848f40_49.5%,#00f8f1_66%,#00f8f180_85.5%,#ffbd1e_100%)_0_100%_/_100%_200%]",
351
- )}
352
- animate={{ backgroundPosition: "0% 300%" }}
353
- transition={{ duration: 5, ease: "linear", repeat: Infinity }}
354
- />
355
- <div className="absolute top-0 left-0 z-[7] size-full dark:[background:repeating-linear-gradient(transparent,transparent_1px,white_1px,white_2px)] mix-blend-overlay opacity-50" />
356
- </div>
357
- );
358
- },
359
- );
360
-
361
- export { HoleBackground, type HoleBackgroundProps };
1
+ "use client";
2
+
3
+ import {motion} from "motion/react";
4
+ import * as React from "react";
5
+
6
+ import {cn} from "@/lib/utilities";
7
+
8
+ interface HoleBackgroundProps extends React.HTMLAttributes<HTMLCanvasElement> {
9
+ strokeColor?: string;
10
+ numberOfLines?: number;
11
+ numberOfDiscs?: number;
12
+ particleRGBColor?: [number, number, number];
13
+ }
14
+
15
+ const linear = (p: number) => p;
16
+ const easeInExpo = (p: number) => (p === 0 ? 0 : 2 ** (10 * (p - 1)));
17
+
18
+ const HoleBackground = React.forwardRef<HTMLCanvasElement, HoleBackgroundProps>(
19
+ (
20
+ {strokeColor = "#737373", numberOfLines = 50, numberOfDiscs = 50, particleRGBColor = [255, 255, 255], className, children, ...props},
21
+ ref,
22
+ ) => {
23
+ const canvasRef = React.useRef<HTMLCanvasElement>(null);
24
+ React.useImperativeHandle(ref, () => canvasRef.current as HTMLCanvasElement);
25
+
26
+ const animationFrameIdRef = React.useRef<number>(0);
27
+ const stateRef = React.useRef<any>({
28
+ discs: [] as any[],
29
+ lines: [] as any[],
30
+ particles: [] as any[],
31
+ clip: {},
32
+ startDisc: {},
33
+ endDisc: {},
34
+ rect: {width: 0, height: 0},
35
+ render: {width: 0, height: 0, dpi: 1},
36
+ particleArea: {},
37
+ linesCanvas: null,
38
+ });
39
+
40
+ const tweenValue = React.useCallback((start: number, end: number, p: number, ease: "inExpo" | null = null) => {
41
+ const delta = end - start;
42
+ const easeFn = ease === "inExpo" ? easeInExpo : linear;
43
+ return start + delta * easeFn(p);
44
+ }, []);
45
+
46
+ const tweenDisc = React.useCallback(
47
+ (disc: any) => {
48
+ const {startDisc, endDisc} = stateRef.current;
49
+ disc.x = tweenValue(startDisc.x, endDisc.x, disc.p);
50
+ disc.y = tweenValue(startDisc.y, endDisc.y, disc.p, "inExpo");
51
+ disc.w = tweenValue(startDisc.w, endDisc.w, disc.p);
52
+ disc.h = tweenValue(startDisc.h, endDisc.h, disc.p);
53
+ },
54
+ [tweenValue],
55
+ );
56
+
57
+ const setSize = React.useCallback(() => {
58
+ const canvas = canvasRef.current;
59
+ if (!canvas) return;
60
+ const rect = canvas.getBoundingClientRect();
61
+ stateRef.current.rect = {width: rect.width, height: rect.height};
62
+ stateRef.current.render = {
63
+ width: rect.width,
64
+ height: rect.height,
65
+ dpi: window.devicePixelRatio || 1,
66
+ };
67
+ canvas.width = stateRef.current.render.width * stateRef.current.render.dpi;
68
+ canvas.height = stateRef.current.render.height * stateRef.current.render.dpi;
69
+ }, []);
70
+
71
+ const setDiscs = React.useCallback(() => {
72
+ const {width, height} = stateRef.current.rect;
73
+ stateRef.current.discs = [];
74
+ stateRef.current.startDisc = {
75
+ x: width * 0.5,
76
+ y: height * 0.45,
77
+ w: width * 0.75,
78
+ h: height * 0.7,
79
+ };
80
+ stateRef.current.endDisc = {
81
+ x: width * 0.5,
82
+ y: height * 0.95,
83
+ w: 0,
84
+ h: 0,
85
+ };
86
+ let prevBottom = height;
87
+ stateRef.current.clip = {};
88
+ for (let i = 0; i < numberOfDiscs; i++) {
89
+ const p = i / numberOfDiscs;
90
+ const disc = {p, x: 0, y: 0, w: 0, h: 0};
91
+ tweenDisc(disc);
92
+ const bottom = disc.y + disc.h;
93
+ if (bottom <= prevBottom) {
94
+ stateRef.current.clip = {disc: {...disc}, i};
95
+ }
96
+ prevBottom = bottom;
97
+ stateRef.current.discs.push(disc);
98
+ }
99
+ const clipPath = new Path2D();
100
+ const {disc} = stateRef.current.clip;
101
+ clipPath.ellipse(disc.x, disc.y, disc.w, disc.h, 0, 0, Math.PI * 2);
102
+ clipPath.rect(disc.x - disc.w, 0, disc.w * 2, disc.y);
103
+ stateRef.current.clip.path = clipPath;
104
+ }, [tweenDisc]);
105
+
106
+ const setLines = React.useCallback(() => {
107
+ const {width, height} = stateRef.current.rect;
108
+ stateRef.current.lines = [];
109
+ const linesAngle = (Math.PI * 2) / numberOfLines;
110
+ for (let i = 0; i < numberOfLines; i++) {
111
+ stateRef.current.lines.push([]);
112
+ }
113
+ stateRef.current.discs.forEach((disc: any) => {
114
+ for (let i = 0; i < numberOfLines; i++) {
115
+ const angle = i * linesAngle;
116
+ const p = {
117
+ x: disc.x + Math.cos(angle) * disc.w,
118
+ y: disc.y + Math.sin(angle) * disc.h,
119
+ };
120
+ stateRef.current.lines[i].push(p);
121
+ }
122
+ });
123
+ const offCanvas = document.createElement("canvas");
124
+ offCanvas.width = width;
125
+ offCanvas.height = height;
126
+ const ctx = offCanvas.getContext("2d");
127
+ if (!ctx) return;
128
+ stateRef.current.lines.forEach((line: any) => {
129
+ ctx.save();
130
+ let lineIsIn = false;
131
+ line.forEach((p1: any, j: number) => {
132
+ if (j === 0) return;
133
+ const p0 = line[j - 1];
134
+ if (
135
+ !lineIsIn
136
+ && (ctx.isPointInPath(stateRef.current.clip.path, p1.x, p1.y) || ctx.isPointInStroke(stateRef.current.clip.path, p1.x, p1.y))
137
+ ) {
138
+ lineIsIn = true;
139
+ } else if (lineIsIn) {
140
+ ctx.clip(stateRef.current.clip.path);
141
+ }
142
+ ctx.beginPath();
143
+ ctx.moveTo(p0.x, p0.y);
144
+ ctx.lineTo(p1.x, p1.y);
145
+ ctx.strokeStyle = strokeColor;
146
+ ctx.lineWidth = 2;
147
+ ctx.stroke();
148
+ ctx.closePath();
149
+ });
150
+ ctx.restore();
151
+ });
152
+ stateRef.current.linesCanvas = offCanvas;
153
+ }, [strokeColor]);
154
+
155
+ const initParticle = React.useCallback((start: boolean = false) => {
156
+ const sx = stateRef.current.particleArea.sx + stateRef.current.particleArea.sw * Math.random();
157
+ const ex = stateRef.current.particleArea.ex + stateRef.current.particleArea.ew * Math.random();
158
+ const dx = ex - sx;
159
+ const y = start ? stateRef.current.particleArea.h * Math.random() : stateRef.current.particleArea.h;
160
+ const r = 0.5 + Math.random() * 4;
161
+ const vy = 0.5 + Math.random();
162
+ return {
163
+ x: sx,
164
+ sx,
165
+ dx,
166
+ y,
167
+ vy,
168
+ p: 0,
169
+ r,
170
+ c: `rgba(${particleRGBColor[0]}, ${particleRGBColor[1]}, ${particleRGBColor[2]}, ${Math.random()})`,
171
+ };
172
+ }, []);
173
+
174
+ const setParticles = React.useCallback(() => {
175
+ const {width, height} = stateRef.current.rect;
176
+ stateRef.current.particles = [];
177
+ const {disc} = stateRef.current.clip;
178
+ stateRef.current.particleArea = {
179
+ sw: disc.w * 0.5,
180
+ ew: disc.w * 2,
181
+ h: height * 0.85,
182
+ };
183
+ stateRef.current.particleArea.sx = (width - stateRef.current.particleArea.sw) / 2;
184
+ stateRef.current.particleArea.ex = (width - stateRef.current.particleArea.ew) / 2;
185
+ const totalParticles = 100;
186
+ for (let i = 0; i < totalParticles; i++) {
187
+ stateRef.current.particles.push(initParticle(true));
188
+ }
189
+ }, [initParticle]);
190
+
191
+ const drawDiscs = React.useCallback(
192
+ (ctx: CanvasRenderingContext2D) => {
193
+ ctx.strokeStyle = strokeColor;
194
+ ctx.lineWidth = 2;
195
+ const outerDisc = stateRef.current.startDisc;
196
+ ctx.beginPath();
197
+ ctx.ellipse(outerDisc.x, outerDisc.y, outerDisc.w, outerDisc.h, 0, 0, Math.PI * 2);
198
+ ctx.stroke();
199
+ ctx.closePath();
200
+ stateRef.current.discs.forEach((disc: any, i: number) => {
201
+ if (i % 5 !== 0) return;
202
+ if (disc.w < stateRef.current.clip.disc.w - 5) {
203
+ ctx.save();
204
+ ctx.clip(stateRef.current.clip.path);
205
+ }
206
+ ctx.beginPath();
207
+ ctx.ellipse(disc.x, disc.y, disc.w, disc.h, 0, 0, Math.PI * 2);
208
+ ctx.stroke();
209
+ ctx.closePath();
210
+ if (disc.w < stateRef.current.clip.disc.w - 5) {
211
+ ctx.restore();
212
+ }
213
+ });
214
+ },
215
+ [strokeColor],
216
+ );
217
+
218
+ const drawLines = React.useCallback((ctx: CanvasRenderingContext2D) => {
219
+ if (stateRef.current.linesCanvas) {
220
+ ctx.drawImage(stateRef.current.linesCanvas, 0, 0);
221
+ }
222
+ }, []);
223
+
224
+ const drawParticles = React.useCallback((ctx: CanvasRenderingContext2D) => {
225
+ ctx.save();
226
+ ctx.clip(stateRef.current.clip.path);
227
+ stateRef.current.particles.forEach((particle: any) => {
228
+ ctx.fillStyle = particle.c;
229
+ ctx.beginPath();
230
+ ctx.rect(particle.x, particle.y, particle.r, particle.r);
231
+ ctx.closePath();
232
+ ctx.fill();
233
+ });
234
+ ctx.restore();
235
+ }, []);
236
+
237
+ const moveDiscs = React.useCallback(() => {
238
+ stateRef.current.discs.forEach((disc: any) => {
239
+ disc.p = (disc.p + 0.001) % 1;
240
+ tweenDisc(disc);
241
+ });
242
+ }, [tweenDisc]);
243
+
244
+ const moveParticles = React.useCallback(() => {
245
+ stateRef.current.particles.forEach((particle: any, idx: number) => {
246
+ particle.p = 1 - particle.y / stateRef.current.particleArea.h;
247
+ particle.x = particle.sx + particle.dx * particle.p;
248
+ particle.y -= particle.vy;
249
+ if (particle.y < 0) {
250
+ stateRef.current.particles[idx] = initParticle();
251
+ }
252
+ });
253
+ }, [initParticle]);
254
+
255
+ const tick = React.useCallback(() => {
256
+ const canvas = canvasRef.current;
257
+ if (!canvas) return;
258
+ const ctx = canvas.getContext("2d");
259
+ if (!ctx) return;
260
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
261
+ ctx.save();
262
+ ctx.scale(stateRef.current.render.dpi, stateRef.current.render.dpi);
263
+ moveDiscs();
264
+ moveParticles();
265
+ drawDiscs(ctx);
266
+ drawLines(ctx);
267
+ drawParticles(ctx);
268
+ ctx.restore();
269
+ animationFrameIdRef.current = requestAnimationFrame(tick);
270
+ }, [moveDiscs, moveParticles, drawDiscs, drawLines, drawParticles]);
271
+
272
+ const init = React.useCallback(() => {
273
+ setSize();
274
+ setDiscs();
275
+ setLines();
276
+ setParticles();
277
+ }, [setSize, setDiscs, setLines, setParticles]);
278
+
279
+ React.useEffect(() => {
280
+ const canvas = canvasRef.current;
281
+ if (!canvas) return;
282
+ init();
283
+ tick();
284
+ const handleResize = () => {
285
+ setSize();
286
+ setDiscs();
287
+ setLines();
288
+ setParticles();
289
+ };
290
+ window.addEventListener("resize", handleResize);
291
+ return () => {
292
+ window.removeEventListener("resize", handleResize);
293
+ cancelAnimationFrame(animationFrameIdRef.current);
294
+ };
295
+ }, [init, tick, setSize, setDiscs, setLines, setParticles]);
296
+
297
+ return (
298
+ <div
299
+ className={cn(
300
+ "relative size-full overflow-hidden",
301
+ 'before:absolute before:top-1/2 before:left-1/2 before:block before:size-[140%] before:[transform:translate3d(-50%,-50%,0)] before:content-[""] before:[background:radial-gradient(ellipse_at_50%_55%,transparent_10%,white_50%)] dark:before:[background:radial-gradient(ellipse_at_50%_55%,transparent_10%,black_50%)]',
302
+ 'after:absolute after:top-1/2 after:left-1/2 after:z-[5] after:block after:size-full after:[transform:translate3d(-50%,-50%,0)] after:mix-blend-overlay after:content-[""] after:[background:radial-gradient(ellipse_at_50%_75%,#a900ff_20%,transparent_75%)]',
303
+ className,
304
+ )}>
305
+ {children}
306
+ <canvas
307
+ ref={canvasRef}
308
+ className='absolute inset-0 block size-full opacity-10 dark:opacity-20'
309
+ {...props}
310
+ />
311
+ <motion.div
312
+ className={cn(
313
+ "absolute top-[-71.5%] left-1/2 z-[3] h-[140%] w-[30%] [transform:translate3d(-50%,0,0)] rounded-b-full [background-size:100%_200%] [background-position:0%_100%] opacity-75 mix-blend-plus-darker blur-3xl dark:mix-blend-plus-lighter",
314
+ "[background:linear-gradient(20deg,#00f8f1,#ffbd1e40_16.5%,#fe848f_33%,#fe848f40_49.5%,#00f8f1_66%,#00f8f180_85.5%,#ffbd1e_100%)_0_100%_/_100%_200%] dark:[background:linear-gradient(20deg,#00f8f1,#ffbd1e20_16.5%,#fe848f_33%,#fe848f20_49.5%,#00f8f1_66%,#00f8f160_85.5%,#ffbd1e_100%)_0_100%_/_100%_200%]",
315
+ )}
316
+ animate={{backgroundPosition: "0% 300%"}}
317
+ transition={{duration: 5, ease: "linear", repeat: Infinity}}
318
+ />
319
+ <div className='absolute top-0 left-0 z-[7] size-full opacity-50 mix-blend-overlay dark:[background:repeating-linear-gradient(transparent,transparent_1px,white_1px,white_2px)]' />
320
+ </div>
321
+ );
322
+ },
323
+ );
324
+
325
+ HoleBackground.displayName = "HoleBackground";
326
+ export {HoleBackground, type HoleBackgroundProps};