@vuer-ai/vuer-uikit 0.0.96 → 0.0.98

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 (341) hide show
  1. package/README.md +106 -7
  2. package/cli/dial-cli.js +49 -7
  3. package/dist/SyncScroll/SyncScroll.cjs +10 -10
  4. package/dist/SyncScroll/SyncScroll.mjs +3 -3
  5. package/dist/SyncScroll/index.cjs +10 -10
  6. package/dist/SyncScroll/index.mjs +3 -3
  7. package/dist/chunk-3HEZVWRW.mjs +62 -0
  8. package/dist/chunk-4KWGGESI.cjs +494 -0
  9. package/dist/{chunk-CCMKL2OA.cjs → chunk-7GWDO25E.cjs} +2 -2
  10. package/dist/chunk-A5LCX2UQ.cjs +208 -0
  11. package/dist/chunk-BEJIZ56L.mjs +300 -0
  12. package/dist/chunk-C7VGRU3O.mjs +283 -0
  13. package/dist/{chunk-LONOMMFA.cjs → chunk-LJMNHTTG.cjs} +21 -21
  14. package/dist/chunk-O66RESRR.cjs +285 -0
  15. package/dist/{chunk-RINTUFYQ.cjs → chunk-RMK6W774.cjs} +24 -19
  16. package/dist/{chunk-BFQ2WL5U.mjs → chunk-TTYSYGVE.mjs} +2 -2
  17. package/dist/chunk-VA3PEYFM.mjs +489 -0
  18. package/dist/chunk-VBBJSIY7.cjs +308 -0
  19. package/dist/{chunk-AIINOWEH.mjs → chunk-W4JCKCW7.mjs} +5 -5
  20. package/dist/chunk-WWGF6TBZ.mjs +206 -0
  21. package/dist/chunk-ZGN4UEJR.cjs +679 -0
  22. package/dist/chunk-ZQLRMOUW.mjs +661 -0
  23. package/dist/dial/DialPanel.cjs +24 -24
  24. package/dist/dial/DialPanel.mjs +23 -23
  25. package/dist/dial/DialProvider.cjs +3 -3
  26. package/dist/dial/DialProvider.d.cts +1 -0
  27. package/dist/dial/DialProvider.d.ts +1 -0
  28. package/dist/dial/DialProvider.example.cjs +72 -0
  29. package/dist/dial/DialProvider.example.d.cts +7 -0
  30. package/dist/dial/DialProvider.example.d.ts +7 -0
  31. package/dist/dial/DialProvider.example.mjs +68 -0
  32. package/dist/dial/DialProvider.mjs +1 -1
  33. package/dist/dial/index.cjs +42 -42
  34. package/dist/dial/index.mjs +23 -23
  35. package/dist/dial/wrapped-inputs/ControlledInputs.cjs +27 -27
  36. package/dist/dial/wrapped-inputs/ControlledInputs.mjs +23 -23
  37. package/dist/dial/wrapped-inputs/DialInputs.cjs +34 -34
  38. package/dist/dial/wrapped-inputs/DialInputs.mjs +23 -23
  39. package/dist/dial/wrapped-inputs/DialVectorInput.cjs +24 -24
  40. package/dist/dial/wrapped-inputs/DialVectorInput.mjs +23 -23
  41. package/dist/dial/wrapped-inputs/index.cjs +39 -39
  42. package/dist/dial/wrapped-inputs/index.mjs +23 -23
  43. package/dist/highlight-cursor/cursor-provider.cjs +3 -3
  44. package/dist/highlight-cursor/cursor-provider.mjs +2 -2
  45. package/dist/highlight-cursor/enhanced-components.cjs +10 -10
  46. package/dist/highlight-cursor/enhanced-components.mjs +5 -5
  47. package/dist/highlight-cursor/index.cjs +16 -16
  48. package/dist/highlight-cursor/index.mjs +6 -6
  49. package/dist/hooks/index.cjs +5 -5
  50. package/dist/hooks/index.mjs +1 -1
  51. package/dist/index.cjs +190 -190
  52. package/dist/index.mjs +23 -23
  53. package/dist/ui/UIKitBadge.cjs +6 -6
  54. package/dist/ui/UIKitBadge.mjs +2 -2
  55. package/dist/ui/avatar.cjs +1 -1
  56. package/dist/ui/avatar.mjs +1 -1
  57. package/dist/ui/badge.cjs +1 -1
  58. package/dist/ui/badge.d.cts +1 -1
  59. package/dist/ui/badge.d.ts +1 -1
  60. package/dist/ui/badge.mjs +1 -1
  61. package/dist/ui/button.cjs +1 -1
  62. package/dist/ui/button.mjs +1 -1
  63. package/dist/ui/card.cjs +1 -1
  64. package/dist/ui/card.mjs +1 -1
  65. package/dist/ui/checkbox.cjs +1 -1
  66. package/dist/ui/checkbox.mjs +1 -1
  67. package/dist/ui/collapsible.cjs +1 -1
  68. package/dist/ui/collapsible.mjs +1 -1
  69. package/dist/ui/drawer.cjs +1 -1
  70. package/dist/ui/drawer.mjs +1 -1
  71. package/dist/ui/dropdown.cjs +1 -1
  72. package/dist/ui/dropdown.mjs +1 -1
  73. package/dist/ui/index.cjs +107 -107
  74. package/dist/ui/index.mjs +17 -17
  75. package/dist/ui/inputs/color-input.cjs +1 -1
  76. package/dist/ui/inputs/color-input.mjs +1 -1
  77. package/dist/ui/inputs/index.cjs +11 -11
  78. package/dist/ui/inputs/index.mjs +3 -3
  79. package/dist/ui/inputs/input-numbers.cjs +1 -1
  80. package/dist/ui/inputs/input-numbers.mjs +1 -1
  81. package/dist/ui/inputs/input.cjs +1 -1
  82. package/dist/ui/inputs/input.d.cts +1 -1
  83. package/dist/ui/inputs/input.d.ts +1 -1
  84. package/dist/ui/inputs/input.mjs +1 -1
  85. package/dist/ui/inputs/number-inputs/CmInput.cjs +1 -1
  86. package/dist/ui/inputs/number-inputs/CmInput.mjs +1 -1
  87. package/dist/ui/inputs/number-inputs/DegInput.cjs +1 -1
  88. package/dist/ui/inputs/number-inputs/DegInput.mjs +1 -1
  89. package/dist/ui/inputs/number-inputs/EulerDegInput.cjs +1 -1
  90. package/dist/ui/inputs/number-inputs/EulerDegInput.mjs +1 -1
  91. package/dist/ui/inputs/number-inputs/EulerInput.cjs +1 -1
  92. package/dist/ui/inputs/number-inputs/EulerInput.mjs +1 -1
  93. package/dist/ui/inputs/number-inputs/EulerRadInput.cjs +1 -1
  94. package/dist/ui/inputs/number-inputs/EulerRadInput.mjs +1 -1
  95. package/dist/ui/inputs/number-inputs/InchInput.cjs +1 -1
  96. package/dist/ui/inputs/number-inputs/InchInput.mjs +1 -1
  97. package/dist/ui/inputs/number-inputs/IntInput.cjs +1 -1
  98. package/dist/ui/inputs/number-inputs/IntInput.mjs +1 -1
  99. package/dist/ui/inputs/number-inputs/KVectorInput.cjs +1 -1
  100. package/dist/ui/inputs/number-inputs/KVectorInput.mjs +1 -1
  101. package/dist/ui/inputs/number-inputs/QuaternionInput.cjs +1 -1
  102. package/dist/ui/inputs/number-inputs/QuaternionInput.mjs +1 -1
  103. package/dist/ui/inputs/number-inputs/RadInput.cjs +1 -1
  104. package/dist/ui/inputs/number-inputs/RadInput.mjs +1 -1
  105. package/dist/ui/inputs/number-inputs/TimeInput.cjs +1 -1
  106. package/dist/ui/inputs/number-inputs/TimeInput.mjs +1 -1
  107. package/dist/ui/inputs/number-inputs/Vec3Input.cjs +1 -1
  108. package/dist/ui/inputs/number-inputs/Vec3Input.mjs +1 -1
  109. package/dist/ui/inputs/number-inputs/VectorInput.cjs +1 -1
  110. package/dist/ui/inputs/number-inputs/VectorInput.mjs +1 -1
  111. package/dist/ui/inputs/number-inputs/index.cjs +11 -11
  112. package/dist/ui/inputs/number-inputs/index.mjs +3 -3
  113. package/dist/ui/inputs/presets-input.cjs +1 -1
  114. package/dist/ui/inputs/presets-input.mjs +1 -1
  115. package/dist/ui/label.cjs +1 -1
  116. package/dist/ui/label.mjs +1 -1
  117. package/dist/ui/layout.cjs +1 -1
  118. package/dist/ui/layout.mjs +1 -1
  119. package/dist/ui/layouts/dock-layout/DockLayoutView.cjs +1 -1
  120. package/dist/ui/layouts/dock-layout/DockLayoutView.mjs +1 -1
  121. package/dist/ui/layouts/dock-layout/LayoutSlots.cjs +1 -1
  122. package/dist/ui/layouts/dock-layout/LayoutSlots.mjs +1 -1
  123. package/dist/ui/layouts/dock-layout/index.cjs +1 -1
  124. package/dist/ui/layouts/dock-layout/index.mjs +1 -1
  125. package/dist/ui/layouts/index.cjs +2 -2
  126. package/dist/ui/layouts/index.mjs +2 -2
  127. package/dist/ui/layouts/liquid-layout/LayoutSlots.cjs +1 -1
  128. package/dist/ui/layouts/liquid-layout/LayoutSlots.mjs +1 -1
  129. package/dist/ui/layouts/liquid-layout/LiquidLayoutView.cjs +1 -1
  130. package/dist/ui/layouts/liquid-layout/LiquidLayoutView.mjs +1 -1
  131. package/dist/ui/layouts/liquid-layout/index.cjs +1 -1
  132. package/dist/ui/layouts/liquid-layout/index.mjs +1 -1
  133. package/dist/ui/modal.cjs +1 -1
  134. package/dist/ui/modal.mjs +1 -1
  135. package/dist/ui/navigation.cjs +1 -1
  136. package/dist/ui/navigation.mjs +1 -1
  137. package/dist/ui/pagination.cjs +1 -1
  138. package/dist/ui/pagination.mjs +1 -1
  139. package/dist/ui/panel.cjs +1 -1
  140. package/dist/ui/panel.mjs +1 -1
  141. package/dist/ui/popover.cjs +1 -1
  142. package/dist/ui/popover.mjs +1 -1
  143. package/dist/ui/radio-group.cjs +1 -1
  144. package/dist/ui/radio-group.mjs +1 -1
  145. package/dist/ui/resizable.cjs +1 -1
  146. package/dist/ui/resizable.mjs +1 -1
  147. package/dist/ui/select.cjs +1 -1
  148. package/dist/ui/select.d.cts +1 -1
  149. package/dist/ui/select.d.ts +1 -1
  150. package/dist/ui/select.mjs +1 -1
  151. package/dist/ui/separator.cjs +1 -1
  152. package/dist/ui/separator.mjs +1 -1
  153. package/dist/ui/sheet.cjs +1 -1
  154. package/dist/ui/sheet.mjs +1 -1
  155. package/dist/ui/sidebar.cjs +26 -26
  156. package/dist/ui/sidebar.mjs +2 -2
  157. package/dist/ui/simple-tree-view.cjs +1 -1
  158. package/dist/ui/simple-tree-view.mjs +1 -1
  159. package/dist/ui/skeleton.cjs +1 -1
  160. package/dist/ui/skeleton.mjs +1 -1
  161. package/dist/ui/slider.cjs +1 -1
  162. package/dist/ui/slider.mjs +1 -1
  163. package/dist/ui/switch.cjs +1 -1
  164. package/dist/ui/switch.mjs +1 -1
  165. package/dist/ui/table.cjs +1 -1
  166. package/dist/ui/table.mjs +1 -1
  167. package/dist/ui/tabs.cjs +1 -1
  168. package/dist/ui/tabs.mjs +1 -1
  169. package/dist/ui/textarea.cjs +1 -1
  170. package/dist/ui/textarea.d.cts +1 -1
  171. package/dist/ui/textarea.d.ts +1 -1
  172. package/dist/ui/textarea.mjs +1 -1
  173. package/dist/ui/theme/ThemeToggles.cjs +1 -1
  174. package/dist/ui/theme/ThemeToggles.mjs +1 -1
  175. package/dist/ui/theme/index.cjs +1 -1
  176. package/dist/ui/theme/index.mjs +1 -1
  177. package/dist/ui/toggle-buttons.cjs +1 -1
  178. package/dist/ui/toggle-buttons.mjs +1 -1
  179. package/dist/ui/toggle-group.cjs +1 -1
  180. package/dist/ui/toggle-group.mjs +1 -1
  181. package/dist/ui/toggle.cjs +1 -1
  182. package/dist/ui/toggle.mjs +1 -1
  183. package/dist/ui/toolbar.cjs +1 -1
  184. package/dist/ui/toolbar.mjs +1 -1
  185. package/dist/ui/tooltip.cjs +1 -1
  186. package/dist/ui/tooltip.mjs +1 -1
  187. package/dist/ui/tree-view/TreeSearchBar.cjs +1 -1
  188. package/dist/ui/tree-view/TreeSearchBar.mjs +1 -1
  189. package/dist/ui/tree-view/TreeView.cjs +1 -1
  190. package/dist/ui/tree-view/TreeView.mjs +1 -1
  191. package/dist/ui/tree-view/index.cjs +6 -6
  192. package/dist/ui/tree-view/index.mjs +2 -2
  193. package/dist/ui/tree-view-legacy.cjs +9 -9
  194. package/dist/ui/tree-view-legacy.mjs +5 -5
  195. package/dist/ui/waterfall/CursorOverlay.cjs +1 -1
  196. package/dist/ui/waterfall/CursorOverlay.mjs +1 -1
  197. package/dist/ui/waterfall/TimelineEvent.cjs +1 -1
  198. package/dist/ui/waterfall/TimelineEvent.mjs +1 -1
  199. package/dist/ui/waterfall/TimelineProcessBar.cjs +1 -1
  200. package/dist/ui/waterfall/TimelineProcessBar.mjs +1 -1
  201. package/dist/ui/waterfall/Wedges.cjs +1 -1
  202. package/dist/ui/waterfall/Wedges.mjs +1 -1
  203. package/dist/ui/waterfall/index.cjs +8 -8
  204. package/dist/ui/waterfall/index.mjs +7 -7
  205. package/package.json +28 -2
  206. package/src/SyncScroll/README.md +283 -0
  207. package/src/SyncScroll/SyncScroll.tsx +361 -0
  208. package/src/SyncScroll/index.ts +22 -0
  209. package/src/SyncScroll/useSyncScroll.tsx +226 -0
  210. package/src/cli/dial-cli.ts +1133 -0
  211. package/src/dial/DialPanel.tsx +208 -0
  212. package/src/dial/DialProvider.example.tsx +80 -0
  213. package/src/dial/DialProvider.tsx +138 -0
  214. package/src/dial/index.ts +26 -0
  215. package/src/dial/wrapped-inputs/ControlledInputs.tsx +176 -0
  216. package/src/dial/wrapped-inputs/DialInputs.tsx +401 -0
  217. package/src/dial/wrapped-inputs/DialVectorInput.tsx +125 -0
  218. package/src/dial/wrapped-inputs/index.ts +25 -0
  219. package/src/highlight-cursor/cursor-context.tsx +23 -0
  220. package/src/highlight-cursor/cursor-provider.tsx +264 -0
  221. package/src/highlight-cursor/enhanced-components.tsx +16 -0
  222. package/src/highlight-cursor/index.ts +21 -0
  223. package/src/highlight-cursor/tabs-cursor-context.tsx +121 -0
  224. package/src/highlight-cursor/types.ts +40 -0
  225. package/src/highlight-cursor/with-cursor.tsx +144 -0
  226. package/src/hooks/clientOnly.tsx +54 -0
  227. package/src/hooks/cn.ts +33 -0
  228. package/src/hooks/index.ts +9 -0
  229. package/src/hooks/useDocument.tsx +18 -0
  230. package/src/hooks/useDragSelect.ts +116 -0
  231. package/src/hooks/useIsMobile.ts +35 -0
  232. package/src/hooks/useLocalStorage.ts +122 -0
  233. package/src/hooks/useLocation.tsx +95 -0
  234. package/src/hooks/useQueryParams.tsx +31 -0
  235. package/src/hooks/useWindow.tsx +18 -0
  236. package/src/index.css +5 -0
  237. package/src/index.ts +5 -0
  238. package/src/styles/.editorconfig +0 -0
  239. package/src/styles/theme.css +152 -0
  240. package/src/styles/toast.css +67 -0
  241. package/src/styles/variables.css +229 -0
  242. package/src/ui/UIKitBadge.tsx +171 -0
  243. package/src/ui/avatar.tsx +221 -0
  244. package/src/ui/badge.tsx +74 -0
  245. package/src/ui/button.tsx +143 -0
  246. package/src/ui/card.tsx +146 -0
  247. package/src/ui/checkbox.tsx +78 -0
  248. package/src/ui/collapsible.tsx +43 -0
  249. package/src/ui/drag-selectable/DragSelectProvider.tsx +178 -0
  250. package/src/ui/drag-selectable/createSelectable.tsx +43 -0
  251. package/src/ui/drag-selectable/index.ts +2 -0
  252. package/src/ui/drawer.tsx +137 -0
  253. package/src/ui/dropdown.tsx +707 -0
  254. package/src/ui/icons/MouseCursorIcons.tsx +39 -0
  255. package/src/ui/icons/cursor.tsx +38 -0
  256. package/src/ui/icons/index.ts +2 -0
  257. package/src/ui/index.ts +45 -0
  258. package/src/ui/inputs/color-input.tsx +61 -0
  259. package/src/ui/inputs/index.tsx +5 -0
  260. package/src/ui/inputs/input-numbers.tsx +394 -0
  261. package/src/ui/inputs/input.tsx +155 -0
  262. package/src/ui/inputs/number-inputs/CmInput.tsx +26 -0
  263. package/src/ui/inputs/number-inputs/DegInput.tsx +26 -0
  264. package/src/ui/inputs/number-inputs/EulerDegInput.tsx +14 -0
  265. package/src/ui/inputs/number-inputs/EulerInput.tsx +30 -0
  266. package/src/ui/inputs/number-inputs/EulerRadInput.tsx +14 -0
  267. package/src/ui/inputs/number-inputs/InchInput.tsx +26 -0
  268. package/src/ui/inputs/number-inputs/IntInput.tsx +46 -0
  269. package/src/ui/inputs/number-inputs/KVectorInput.tsx +20 -0
  270. package/src/ui/inputs/number-inputs/QuaternionInput.tsx +27 -0
  271. package/src/ui/inputs/number-inputs/RadInput.tsx +26 -0
  272. package/src/ui/inputs/number-inputs/TimeInput.tsx +26 -0
  273. package/src/ui/inputs/number-inputs/Vec3Input.tsx +26 -0
  274. package/src/ui/inputs/number-inputs/VectorInput.tsx +38 -0
  275. package/src/ui/inputs/number-inputs/index.ts +38 -0
  276. package/src/ui/inputs/presets-input.tsx +59 -0
  277. package/src/ui/label.tsx +35 -0
  278. package/src/ui/layout.tsx +43 -0
  279. package/src/ui/layouts/dock-layout/DockLayoutView.tsx +128 -0
  280. package/src/ui/layouts/dock-layout/LayoutSlots.tsx +85 -0
  281. package/src/ui/layouts/dock-layout/index.tsx +2 -0
  282. package/src/ui/layouts/index.ts +2 -0
  283. package/src/ui/layouts/liquid-layout/LayoutSlots.tsx +82 -0
  284. package/src/ui/layouts/liquid-layout/LiquidLayoutView.tsx +76 -0
  285. package/src/ui/layouts/liquid-layout/index.ts +1 -0
  286. package/src/ui/modal.tsx +211 -0
  287. package/src/ui/navigation.tsx +86 -0
  288. package/src/ui/pagination.tsx +129 -0
  289. package/src/ui/panel.tsx +146 -0
  290. package/src/ui/popover.tsx +112 -0
  291. package/src/ui/radio-group.tsx +63 -0
  292. package/src/ui/resizable.tsx +52 -0
  293. package/src/ui/select.tsx +365 -0
  294. package/src/ui/separator.tsx +26 -0
  295. package/src/ui/sheet.tsx +257 -0
  296. package/src/ui/sidebar.tsx +695 -0
  297. package/src/ui/simple-tree-view.tsx +604 -0
  298. package/src/ui/skeleton.tsx +15 -0
  299. package/src/ui/slider.tsx +204 -0
  300. package/src/ui/switch.tsx +45 -0
  301. package/src/ui/table.tsx +99 -0
  302. package/src/ui/tabs.tsx +192 -0
  303. package/src/ui/textarea.tsx +55 -0
  304. package/src/ui/theme/ThemeProvider.tsx +319 -0
  305. package/src/ui/theme/ThemeToggles.tsx +84 -0
  306. package/src/ui/theme/index.ts +21 -0
  307. package/src/ui/theme/themeScript.tsx +179 -0
  308. package/src/ui/theme/types.ts +61 -0
  309. package/src/ui/toast.tsx +30 -0
  310. package/src/ui/toggle-buttons.tsx +290 -0
  311. package/src/ui/toggle-group.tsx +236 -0
  312. package/src/ui/toggle.tsx +94 -0
  313. package/src/ui/toolbar.tsx +54 -0
  314. package/src/ui/tooltip.tsx +171 -0
  315. package/src/ui/tree-view/TreeSearchBar.tsx +88 -0
  316. package/src/ui/tree-view/TreeView.tsx +232 -0
  317. package/src/ui/tree-view/hooks.tsx +289 -0
  318. package/src/ui/tree-view/index.ts +4 -0
  319. package/src/ui/tree-view/types.ts +23 -0
  320. package/src/ui/tree-view-legacy.tsx +644 -0
  321. package/src/ui/version-badge.tsx +0 -0
  322. package/src/ui/waterfall/CursorOverlay.tsx +96 -0
  323. package/src/ui/waterfall/NavigationControls.tsx +42 -0
  324. package/src/ui/waterfall/Tick.tsx +51 -0
  325. package/src/ui/waterfall/TimeRuleEventDot.tsx +19 -0
  326. package/src/ui/waterfall/TimelineEvent.tsx +60 -0
  327. package/src/ui/waterfall/TimelineProcessBar.tsx +207 -0
  328. package/src/ui/waterfall/Wedges.tsx +67 -0
  329. package/src/ui/waterfall/WheelZoomContext.tsx +128 -0
  330. package/src/ui/waterfall/hooks/useTimelineState.tsx +134 -0
  331. package/src/ui/waterfall/hooks/useViewport.tsx +293 -0
  332. package/src/ui/waterfall/index.tsx +326 -0
  333. package/src/ui/waterfall/types.ts +20 -0
  334. package/src/ui/waterfall/utils.ts +91 -0
  335. package/dist/chunk-W2YAQV5N.mjs +0 -57
  336. package/dist/{chunk-QLCEHV4Q.mjs → chunk-2OZK5DY5.mjs} +2 -2
  337. package/dist/{chunk-Z35DNFRZ.cjs → chunk-7IS37C3P.cjs} +2 -2
  338. package/dist/{chunk-4AOAH77D.mjs → chunk-A2PCEL5S.mjs} +2 -2
  339. package/dist/{chunk-K4VD5PPY.mjs → chunk-BIUDC66P.mjs} +1 -1
  340. package/dist/{chunk-RKJR6RZU.cjs → chunk-OYNLQTHW.cjs} +1 -1
  341. package/dist/{chunk-VE3XLQLO.cjs → chunk-QUFZWF4E.cjs} +2 -2
@@ -0,0 +1,264 @@
1
+ import { useCallback, useEffect, useMemo, useState, useRef } from "react";
2
+ import { createPortal } from "react-dom";
3
+
4
+ import { CursorContext } from "./cursor-context";
5
+ import type { CursorProviderProps } from "./types";
6
+ import { cn } from "../hooks/cn";
7
+
8
+ export const CursorProvider = ({
9
+ children,
10
+ maxOffsetX = 5,
11
+ maxOffsetY = 20,
12
+ cursorSize = 20,
13
+ transitionDuration = 100,
14
+ cursorClassName,
15
+ className,
16
+ as: Component = "div",
17
+ ...props
18
+ }: CursorProviderProps) => {
19
+ // Check if we're in a browser environment
20
+ const [isClient, setIsClient] = useState(false);
21
+ const [isMouseInside, setIsMouseInside] = useState(false);
22
+ const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
23
+ const [hoveredElementId, setHoveredElementId] = useState<string | null>(null);
24
+ const [elementDimensions, setElementDimensions] = useState({
25
+ width: 0,
26
+ height: 0,
27
+ x: 0,
28
+ y: 0,
29
+ right: 0,
30
+ bottom: 0,
31
+ });
32
+
33
+ const hoveredElementRef = useRef<HTMLElement | null>(null);
34
+
35
+ // Set isClient to true after component mounts (client-side only)
36
+ useEffect(() => {
37
+ setIsClient(true);
38
+ }, []);
39
+
40
+ useEffect(() => {
41
+ if (!isClient) return;
42
+
43
+ const handleMouseMove = (e: MouseEvent) => {
44
+ setMousePosition({ x: e.clientX, y: e.clientY });
45
+ };
46
+
47
+ document.addEventListener("mousemove", handleMouseMove);
48
+ return () => document.removeEventListener("mousemove", handleMouseMove);
49
+ }, [isClient]);
50
+
51
+ const handleMouseEnter = useCallback(() => {
52
+ setIsMouseInside(true);
53
+ }, []);
54
+
55
+ const handleMouseLeave = useCallback(() => {
56
+ setIsMouseInside(false);
57
+ setHoveredElementId(null);
58
+ hoveredElementRef.current = null;
59
+ }, []);
60
+
61
+ const checkMouseInElement = useCallback(() => {
62
+ if (!hoveredElementRef.current || !hoveredElementId) {
63
+ return;
64
+ }
65
+
66
+ const rect = hoveredElementRef.current.getBoundingClientRect();
67
+
68
+ setElementDimensions({
69
+ width: rect.width,
70
+ height: rect.height,
71
+ x: rect.left,
72
+ y: rect.top,
73
+ right: rect.right,
74
+ bottom: rect.bottom,
75
+ });
76
+
77
+ const isInside =
78
+ mousePosition.x >= rect.left &&
79
+ mousePosition.x <= rect.right &&
80
+ mousePosition.y >= rect.top &&
81
+ mousePosition.y <= rect.bottom;
82
+
83
+ if (!isInside) {
84
+ setHoveredElementId(null);
85
+ hoveredElementRef.current = null;
86
+ }
87
+ }, [mousePosition, hoveredElementId]);
88
+
89
+ useEffect(() => {
90
+ if (!isClient) return;
91
+
92
+ const handleScroll = () => {
93
+ checkMouseInElement();
94
+ };
95
+
96
+ document.addEventListener("scroll", handleScroll, { passive: true, capture: true });
97
+
98
+ return () => {
99
+ document.removeEventListener("scroll", handleScroll, { capture: true });
100
+ };
101
+ }, [checkMouseInElement, isClient]);
102
+
103
+ const registerHoveredElement = useCallback(
104
+ (id: string, dimensions: DOMRect, element?: HTMLElement) => {
105
+ setHoveredElementId(id);
106
+ setElementDimensions({
107
+ width: dimensions.width,
108
+ height: dimensions.height,
109
+ x: dimensions.left,
110
+ y: dimensions.top,
111
+ right: dimensions.right,
112
+ bottom: dimensions.bottom,
113
+ });
114
+
115
+ if (element) {
116
+ hoveredElementRef.current = element;
117
+ }
118
+ },
119
+ [],
120
+ );
121
+
122
+ const unregisterHoveredElement = useCallback(() => {
123
+ setHoveredElementId(null);
124
+ hoveredElementRef.current = null;
125
+ }, []);
126
+
127
+ const updateElementDimensions = useCallback(
128
+ (dimensions: DOMRect) => {
129
+ if (hoveredElementId) {
130
+ setElementDimensions({
131
+ width: dimensions.width,
132
+ height: dimensions.height,
133
+ x: dimensions.left,
134
+ y: dimensions.top,
135
+ right: dimensions.right,
136
+ bottom: dimensions.bottom,
137
+ });
138
+ }
139
+ },
140
+ [hoveredElementId],
141
+ );
142
+
143
+ const getCursorPosition = () => {
144
+ if (!hoveredElementId) {
145
+ return {
146
+ x: mousePosition.x - cursorSize / 2,
147
+ y: mousePosition.y - cursorSize / 2,
148
+ };
149
+ }
150
+
151
+ // Calculate the center of the element
152
+ const elementCenterX = elementDimensions.x + elementDimensions.width / 2;
153
+ const elementCenterY = elementDimensions.y + elementDimensions.height / 2;
154
+
155
+ // Calculate offset from center (with some dampening for smoothness)
156
+ const offsetX = (mousePosition.x - elementCenterX) * 0.1;
157
+ const offsetY = (mousePosition.y - elementCenterY) * 0.1;
158
+
159
+ // Apply bounds to keep cursor within reasonable limits
160
+ const boundedOffsetX = Math.max(-maxOffsetX, Math.min(maxOffsetX, offsetX));
161
+ const boundedOffsetY = Math.max(-maxOffsetY, Math.min(maxOffsetY, offsetY));
162
+
163
+ return {
164
+ x: elementDimensions.x + boundedOffsetX,
165
+ y: elementDimensions.y + boundedOffsetY,
166
+ };
167
+ };
168
+
169
+ const contextValue = useMemo(
170
+ () => ({
171
+ // State values that change during component lifecycle
172
+ mousePosition,
173
+ hoveredElementId,
174
+ elementDimensions,
175
+
176
+ // Callbacks that should be stable references
177
+ registerHoveredElement,
178
+ unregisterHoveredElement,
179
+ updateElementDimensions,
180
+ }),
181
+ [
182
+ mousePosition,
183
+ hoveredElementId,
184
+ elementDimensions,
185
+ registerHoveredElement,
186
+ unregisterHoveredElement,
187
+ updateElementDimensions,
188
+ ],
189
+ );
190
+
191
+ const cursorPosition = getCursorPosition();
192
+
193
+ const cursorStyleObject = useMemo(
194
+ () => ({
195
+ left: cursorPosition.x,
196
+ top: cursorPosition.y,
197
+ width: hoveredElementId
198
+ ? elementDimensions.width > 0
199
+ ? elementDimensions.width
200
+ : cursorSize
201
+ : cursorSize,
202
+ height: hoveredElementId
203
+ ? elementDimensions.height > 0
204
+ ? elementDimensions.height
205
+ : cursorSize
206
+ : cursorSize,
207
+ willChange: "transform, width, height",
208
+ }),
209
+ [
210
+ cursorPosition.x,
211
+ cursorPosition.y,
212
+ hoveredElementId,
213
+ elementDimensions.width,
214
+ elementDimensions.height,
215
+ cursorSize,
216
+ ],
217
+ );
218
+
219
+ let styleClass;
220
+ if (hoveredElementId) {
221
+ styleClass = `opacity-[0.05] rounded-uk-md transition-[width,height,left,top] duration-${transitionDuration} ease-out`;
222
+ } else {
223
+ styleClass = `opacity-90 rounded-full z-10 transition-[width,height,left,top] duration-${transitionDuration} ease-out transition-opacity duration-${transitionDuration}`;
224
+ }
225
+
226
+ // Create cursor element to be portaled
227
+ const cursorElement = isClient && isMouseInside && (
228
+ <div
229
+ className={`pointer-events-none fixed ${styleClass} ${hoveredElementId ? "" : cursorClassName || ""}`}
230
+ style={{
231
+ ...cursorStyleObject,
232
+ backgroundColor: "var(--shadow-tertiary)",
233
+ }}
234
+ />
235
+ );
236
+
237
+ // Use React.Fragment at the top level to avoid any DOM structure that might affect layout
238
+ return (
239
+ <>
240
+ {/* Portal the cursor overlay to document.body to completely avoid layout impact */}
241
+ {isClient &&
242
+ typeof document !== "undefined" &&
243
+ document.body &&
244
+ cursorElement &&
245
+ createPortal(cursorElement, document.body)}
246
+ {/* Context provider with no DOM element */}
247
+ <CursorContext.Provider value={contextValue}>
248
+ {/* Use the Component directly with no extra wrappers */}
249
+ <Component
250
+ {...props}
251
+ className={cn(className)}
252
+ style={{
253
+ cursor: isMouseInside && !hoveredElementId ? "none" : "auto",
254
+ ...props.style,
255
+ }}
256
+ onMouseEnter={handleMouseEnter}
257
+ onMouseLeave={handleMouseLeave}
258
+ >
259
+ {children}
260
+ </Component>
261
+ </CursorContext.Provider>
262
+ </>
263
+ );
264
+ };
@@ -0,0 +1,16 @@
1
+ import { withCursor } from "./with-cursor";
2
+ import { Button } from "../ui/button";
3
+ import { InputRoot } from "../ui/inputs/input";
4
+ import { SelectTrigger } from "../ui/select";
5
+ import { Tabs } from "../ui/tabs";
6
+ import { Textarea } from "../ui/textarea";
7
+
8
+ export const CursorButton = withCursor(Button);
9
+
10
+ export const CursorTabs = withCursor(Tabs);
11
+
12
+ export const CursorInputRoot = withCursor(InputRoot);
13
+
14
+ export const CursorSelectTrigger = withCursor(SelectTrigger) as typeof SelectTrigger;
15
+
16
+ export const CursorTextarea = withCursor(Textarea) as typeof Textarea;
@@ -0,0 +1,21 @@
1
+ import { CursorProvider } from "./cursor-provider";
2
+ import {
3
+ CursorButton,
4
+ CursorTabs,
5
+ CursorInputRoot,
6
+ CursorSelectTrigger,
7
+ CursorTextarea,
8
+ } from "./enhanced-components";
9
+ import { TabsCursorProvider } from "./tabs-cursor-context";
10
+ import { withCursor } from "./with-cursor";
11
+
12
+ export {
13
+ CursorProvider,
14
+ TabsCursorProvider,
15
+ withCursor,
16
+ CursorButton,
17
+ CursorTabs,
18
+ CursorInputRoot,
19
+ CursorSelectTrigger,
20
+ CursorTextarea,
21
+ };
@@ -0,0 +1,121 @@
1
+ import { motion } from "framer-motion";
2
+ import {
3
+ createContext,
4
+ useState,
5
+ useEffect,
6
+ useContext,
7
+ useCallback,
8
+ type ReactNode,
9
+ type CSSProperties,
10
+ } from "react";
11
+ import { createPortal } from "react-dom";
12
+
13
+ interface TabsCursorContextType {
14
+ setCursorTarget: (el: HTMLElement | null) => void;
15
+ }
16
+
17
+ const TabsCursorContext = createContext<TabsCursorContextType | null>(null);
18
+
19
+ export const TabsCursorProvider = ({
20
+ children,
21
+ className,
22
+ ...props
23
+ }: {
24
+ children: ReactNode;
25
+ className?: string;
26
+ style?: CSSProperties;
27
+ }) => {
28
+ const [isClient, setIsClient] = useState(false);
29
+ const [cursorTarget, setCursorTarget] = useState<HTMLElement | null>(null);
30
+ const [targetRect, setTargetRect] = useState<DOMRect | null>(null);
31
+ const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
32
+ const [isMouseInside, setIsMouseInside] = useState(false);
33
+
34
+ useEffect(() => {
35
+ setIsClient(true);
36
+ }, []);
37
+
38
+ useEffect(() => {
39
+ if (!isClient) return;
40
+
41
+ const handleMouseMove = (e: MouseEvent) => {
42
+ setMousePosition({ x: e.clientX, y: e.clientY });
43
+ };
44
+
45
+ document.addEventListener("mousemove", handleMouseMove);
46
+ return () => document.removeEventListener("mousemove", handleMouseMove);
47
+ }, [isClient]);
48
+
49
+ useEffect(() => {
50
+ if (cursorTarget) {
51
+ setTargetRect(cursorTarget.getBoundingClientRect());
52
+ } else {
53
+ setTargetRect(null);
54
+ }
55
+ }, [cursorTarget]);
56
+
57
+ const handleMouseEnter = useCallback(() => {
58
+ setIsMouseInside(true);
59
+ }, []);
60
+
61
+ const handleMouseLeave = useCallback(() => {
62
+ setIsMouseInside(false);
63
+ setCursorTarget(null);
64
+ }, []);
65
+
66
+ const contextValue = { setCursorTarget };
67
+
68
+ return (
69
+ <div
70
+ {...props}
71
+ className={className}
72
+ style={{
73
+ cursor: isMouseInside && !cursorTarget ? "none" : "auto",
74
+ ...props.style,
75
+ }}
76
+ onMouseEnter={handleMouseEnter}
77
+ onMouseLeave={handleMouseLeave}
78
+ >
79
+ <TabsCursorContext.Provider value={contextValue}>
80
+ {children}
81
+ {isClient &&
82
+ isMouseInside &&
83
+ typeof document !== "undefined" &&
84
+ document.body &&
85
+ createPortal(
86
+ <motion.div
87
+ className="pointer-events-none"
88
+ initial={false}
89
+ animate={{
90
+ x: targetRect ? targetRect.left : mousePosition.x - 8,
91
+ y: targetRect ? targetRect.top : mousePosition.y - 8,
92
+ width: targetRect ? targetRect.width : 16,
93
+ height: targetRect ? targetRect.height : 16,
94
+ borderRadius:
95
+ targetRect && cursorTarget && typeof window !== "undefined"
96
+ ? getComputedStyle(cursorTarget).borderRadius
97
+ : "50%",
98
+ }}
99
+ transition={{ type: "spring", stiffness: 1000, damping: 60, mass: 1 }}
100
+ style={{
101
+ position: "fixed",
102
+ top: 0,
103
+ left: 0,
104
+ backgroundColor: "var(--shadow-tertiary)",
105
+ zIndex: 9999,
106
+ }}
107
+ />,
108
+ document.body,
109
+ )}
110
+ </TabsCursorContext.Provider>
111
+ </div>
112
+ );
113
+ };
114
+
115
+ export const useTabsCursor = () => {
116
+ const context = useContext(TabsCursorContext);
117
+ if (!context) {
118
+ return { setCursorTarget: () => {} };
119
+ }
120
+ return context;
121
+ };
@@ -0,0 +1,40 @@
1
+ import type { ReactNode, ComponentType, HTMLAttributes, ElementType, MouseEvent } from "react";
2
+
3
+ export interface CursorContextType {
4
+ mousePosition: { x: number; y: number };
5
+ hoveredElementId: string | null;
6
+ elementDimensions: {
7
+ width: number;
8
+ height: number;
9
+ x: number;
10
+ y: number;
11
+ right?: number;
12
+ bottom?: number;
13
+ };
14
+ registerHoveredElement: (id: string, dimensions: DOMRect, element?: HTMLElement) => void;
15
+ unregisterHoveredElement: () => void;
16
+ updateElementDimensions: (dimensions: DOMRect) => void;
17
+ }
18
+
19
+ export interface CursorProviderProps extends HTMLAttributes<HTMLDivElement> {
20
+ children: ReactNode;
21
+ maxOffsetX?: number;
22
+ maxOffsetY?: number;
23
+ cursorSize?: number;
24
+ transitionDuration?: number;
25
+ cursorClassName?: string;
26
+ as?: ElementType;
27
+ }
28
+
29
+ export interface WithCursorProps {
30
+ id?: string;
31
+ onMouseEnter?: (event: MouseEvent<HTMLElement>) => void;
32
+ onMouseMove?: (event: MouseEvent<HTMLElement>) => void;
33
+ onMouseLeave?: (event: MouseEvent<HTMLElement>) => void;
34
+ }
35
+
36
+ export type EnhancedComponentProps<P> = P & WithCursorProps;
37
+
38
+ export type EnhancedComponent<P = Record<string, unknown>> = ComponentType<
39
+ EnhancedComponentProps<P>
40
+ >;
@@ -0,0 +1,144 @@
1
+ import { forwardRef, useRef, useId, type ComponentType } from "react";
2
+
3
+ import { useCursor } from "./cursor-context";
4
+ import type { EnhancedComponentProps } from "./types";
5
+
6
+ /**
7
+ * Helper function to determine the visible portion of an element within scrollable containers
8
+ * @param element The DOM element we want to check visibility for
9
+ * @param elementRect The original bounding client rect of the element
10
+ * @returns A DOMRect representing only the visible portion of the element
11
+ */
12
+ const getVisibleRect = (element: HTMLElement, elementRect: DOMRect): DOMRect => {
13
+ // Find all scrollable parent containers
14
+ let parent = element.parentElement;
15
+ let visibleRect = {
16
+ ...elementRect,
17
+ left: elementRect.left,
18
+ right: elementRect.right,
19
+ top: elementRect.top,
20
+ bottom: elementRect.bottom,
21
+ width: elementRect.width,
22
+ height: elementRect.height,
23
+ x: elementRect.x,
24
+ y: elementRect.y,
25
+ };
26
+
27
+ // Traverse up through parent elements to find scrollable containers
28
+ while (parent) {
29
+ if (typeof window === "undefined") break;
30
+
31
+ const style = window.getComputedStyle(parent);
32
+ const hasOverflow = [style.overflowY, style.overflowX].some((overflow) =>
33
+ ["auto", "scroll", "hidden"].includes(overflow),
34
+ );
35
+
36
+ if (hasOverflow) {
37
+ const parentRect = parent.getBoundingClientRect();
38
+
39
+ // Calculate the intersection between the element and its scrollable parent
40
+ const newLeft = Math.max(visibleRect.left, parentRect.left);
41
+ const newTop = Math.max(visibleRect.top, parentRect.top);
42
+ const newRight = Math.min(visibleRect.right, parentRect.right);
43
+ const newBottom = Math.min(visibleRect.bottom, parentRect.bottom);
44
+
45
+ // Update the visible rect dimensions
46
+ visibleRect = {
47
+ ...visibleRect,
48
+ left: newLeft,
49
+ top: newTop,
50
+ right: newRight,
51
+ bottom: newBottom,
52
+ width: Math.max(0, newRight - newLeft),
53
+ height: Math.max(0, newBottom - newTop),
54
+ x: newLeft,
55
+ y: newTop,
56
+ };
57
+
58
+ // If element is completely outside the viewport of the parent, return empty rect
59
+ if (visibleRect.width <= 0 || visibleRect.height <= 0) {
60
+ return new DOMRect(0, 0, 0, 0);
61
+ }
62
+ }
63
+
64
+ parent = parent.parentElement;
65
+ }
66
+
67
+ return DOMRect.fromRect(visibleRect);
68
+ };
69
+
70
+ export function withCursor<P extends object>(Component: ComponentType<P>) {
71
+ // Create a display name for the enhanced component
72
+ const displayName = Component.displayName || Component.name || "Component";
73
+
74
+ const EnhancedComponent = forwardRef<HTMLElement, EnhancedComponentProps<P>>(
75
+ ({ id: propId, onMouseEnter, onMouseMove, onMouseLeave, ...props }, ref) => {
76
+ const { registerHoveredElement, unregisterHoveredElement, updateElementDimensions } =
77
+ useCursor();
78
+
79
+ const generatedId = useId();
80
+ const id = propId || `cursor-element-${generatedId}`;
81
+ const elementRef = useRef<HTMLElement>(null);
82
+
83
+ const handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {
84
+ if (elementRef.current) {
85
+ const elementRect = elementRef.current.getBoundingClientRect();
86
+ const visibleRect = getVisibleRect(elementRef.current, elementRect);
87
+ registerHoveredElement(id, visibleRect, elementRef.current);
88
+ }
89
+ onMouseEnter?.(event);
90
+ };
91
+
92
+ const handleMouseMove = (event: React.MouseEvent<HTMLElement>) => {
93
+ if (elementRef.current) {
94
+ const elementRect = elementRef.current.getBoundingClientRect();
95
+ const visibleRect = getVisibleRect(elementRef.current, elementRect);
96
+ updateElementDimensions(visibleRect);
97
+ }
98
+ onMouseMove?.(event);
99
+ };
100
+
101
+ const handleMouseOut = (event: React.MouseEvent<HTMLElement>) => {
102
+ const rect = elementRef.current?.getBoundingClientRect();
103
+ if (rect) {
104
+ const { clientX, clientY } = event;
105
+ const isOutside =
106
+ clientX < rect.left ||
107
+ clientX > rect.right ||
108
+ clientY < rect.top ||
109
+ clientY > rect.bottom;
110
+
111
+ if (isOutside) {
112
+ unregisterHoveredElement();
113
+ }
114
+ } else {
115
+ unregisterHoveredElement();
116
+ }
117
+ onMouseLeave?.(event);
118
+ };
119
+
120
+ return (
121
+ <Component
122
+ {...(props as P)}
123
+ id={id}
124
+ ref={(node: HTMLElement) => {
125
+ // Handle both function and object refs
126
+ if (typeof ref === "function") {
127
+ ref(node);
128
+ } else if (ref) {
129
+ ref.current = node;
130
+ }
131
+ elementRef.current = node;
132
+ }}
133
+ onMouseEnter={handleMouseEnter}
134
+ onMouseMove={handleMouseMove}
135
+ onMouseOut={handleMouseOut}
136
+ />
137
+ );
138
+ },
139
+ );
140
+
141
+ EnhancedComponent.displayName = `withCursor(${displayName})`;
142
+
143
+ return EnhancedComponent;
144
+ }
@@ -0,0 +1,54 @@
1
+ import React from "react";
2
+
3
+ /**
4
+ * Executes a function only on the client side (when window is defined)
5
+ * @param fn - Function to execute on client side
6
+ * @returns Result of the function or undefined if on server side
7
+ */
8
+ export function clientOnly<T>(fn: () => T): T | undefined {
9
+ if (typeof window !== "undefined") {
10
+ return fn();
11
+ }
12
+ return undefined;
13
+ }
14
+
15
+ /**
16
+ * Creates a React component that only renders on the client side after hydration
17
+ * @param Component - The component to render client-side
18
+ * @param fallback - Optional fallback to render server-side
19
+ * @returns A component that avoids hydration mismatches
20
+ */
21
+ export function createClientOnlyComponent<P extends object = Record<string, unknown>>(
22
+ Component: React.ComponentType<P>,
23
+ fallback?: React.ComponentType<P>,
24
+ ): React.ComponentType<P> {
25
+ return function ClientOnlyWrapper(props: P) {
26
+ const [isClient, setIsClient] = React.useState(false);
27
+
28
+ React.useEffect(() => {
29
+ setIsClient(true);
30
+ }, []);
31
+
32
+ if (!isClient) {
33
+ return fallback ? React.createElement(fallback, props) : null;
34
+ }
35
+
36
+ return React.createElement(Component, props);
37
+ } as React.ComponentType<P>;
38
+ }
39
+
40
+ /**
41
+ * Checks if code is running on the client side
42
+ * @returns true if running on client, false if on server
43
+ */
44
+ export function isClient(): boolean {
45
+ return typeof window !== "undefined";
46
+ }
47
+
48
+ /**
49
+ * Checks if code is running on the server side
50
+ * @returns true if running on server, false if on client
51
+ */
52
+ export function isServer(): boolean {
53
+ return typeof window === "undefined";
54
+ }
@@ -0,0 +1,33 @@
1
+ import { type ClassValue, clsx } from "clsx";
2
+ import { extendTailwindMerge } from "tailwind-merge";
3
+
4
+ const twMerge = extendTailwindMerge({
5
+ extend: {
6
+ classGroups: {
7
+ rounded: [
8
+ "rounded-uk-xs",
9
+ "rounded-uk-sm",
10
+ "rounded-uk-md",
11
+ "rounded-uk-lg",
12
+ "rounded-uk-xl",
13
+ ],
14
+ p: ["p-xxs", "p-xs", "p-sm", "p-md", "p-lg", "p-xl"],
15
+ },
16
+ },
17
+ override: {
18
+ classGroups: {
19
+ "font-size": [
20
+ "text-uk-xs",
21
+ "text-uk-sm",
22
+ "text-uk-md",
23
+ "text-uk-lg",
24
+ "text-uk-xl",
25
+ "text-uk-xxl",
26
+ ],
27
+ },
28
+ },
29
+ });
30
+
31
+ export function cn(...inputs: ClassValue[]) {
32
+ return twMerge(clsx(inputs));
33
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./cn";
2
+ export * from "./useLocalStorage";
3
+ export * from "./clientOnly";
4
+ export * from "./useIsMobile";
5
+ export * from "./useWindow";
6
+ export * from "./useDocument";
7
+ export * from "./useLocation";
8
+ export * from "./useQueryParams";
9
+ export * from "./useDragSelect";