@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,604 @@
1
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
2
+ import { cva } from "class-variance-authority";
3
+ import { ChevronRight } from "lucide-react";
4
+ import {
5
+ forwardRef,
6
+ HTMLAttributes,
7
+ useCallback,
8
+ useMemo,
9
+ useState,
10
+ type ComponentType,
11
+ type SVGProps,
12
+ type ReactNode,
13
+ type ElementRef,
14
+ type ComponentPropsWithoutRef,
15
+ type DragEvent,
16
+ type MouseEvent as ReactMouseEvent,
17
+ } from "react";
18
+
19
+ import { cn, createClientOnlyComponent } from "../hooks";
20
+
21
+ /**
22
+ * Base CSS variants for tree row visuals.
23
+ */
24
+ const treeVariants = cva(
25
+ "text-text-primary group hover:before:opacity-100 before:absolute before:rounded-uk-sm before:left-0 before:w-full before:opacity-0 before:bg-bg-secondary before:h-[28px] before:z-0",
26
+ );
27
+
28
+ /** Highlight styling when a row is selected. */
29
+ const selectedTreeVariants = cva("before:opacity-100 before:bg-brand-primary text-text-withbg");
30
+
31
+ /** Visual style while an item is a drag-over target. */
32
+ const dragOverVariants = cva("before:opacity-100 before:bg-brand-primary/20 text-text-withbg");
33
+
34
+ type IconComponent = ComponentType<SVGProps<SVGSVGElement>>;
35
+ /**
36
+ * Tree node data used by `TreeView`.
37
+ */
38
+ interface TreeDataItem {
39
+ id: string;
40
+ name: string;
41
+ icon?: IconComponent;
42
+ selectedIcon?: IconComponent;
43
+ openIcon?: IconComponent;
44
+ children?: TreeDataItem[];
45
+ actions?: ReactNode;
46
+ onClick?: () => void;
47
+ draggable?: boolean;
48
+ droppable?: boolean;
49
+ disabled?: boolean;
50
+ }
51
+
52
+ /**
53
+ * Props for the hierarchical tree view component.
54
+ */
55
+ type TreeProps = HTMLAttributes<HTMLDivElement> & {
56
+ data: TreeDataItem[] | TreeDataItem;
57
+ initialSelectedItemId?: string;
58
+ onSelectChange?: (item: TreeDataItem | undefined) => void;
59
+ expandAll?: boolean;
60
+ defaultNodeIcon?: IconComponent;
61
+ defaultLeafIcon?: IconComponent;
62
+ onDocumentDrag?: (sourceItem: TreeDataItem, targetItem: TreeDataItem) => void;
63
+ };
64
+
65
+ /**
66
+ * Interactive tree view supporting expand/collapse and drag-and-drop.
67
+ */
68
+ const TreeViewRoot = forwardRef<HTMLDivElement, TreeProps>(
69
+ (
70
+ {
71
+ data,
72
+ initialSelectedItemId,
73
+ onSelectChange,
74
+ expandAll,
75
+ defaultLeafIcon,
76
+ defaultNodeIcon,
77
+ className,
78
+ onDocumentDrag,
79
+ ...props
80
+ },
81
+ ref,
82
+ ) => {
83
+ const [selectedItemId, setSelectedItemId] = useState<string | undefined>(initialSelectedItemId);
84
+
85
+ const [draggedItem, setDraggedItem] = useState<TreeDataItem | null>(null);
86
+
87
+ const handleSelectChange = useCallback(
88
+ (item: TreeDataItem | undefined) => {
89
+ setSelectedItemId(item?.id);
90
+ if (onSelectChange) {
91
+ onSelectChange(item);
92
+ }
93
+ },
94
+ [onSelectChange],
95
+ );
96
+
97
+ const handleDragStart = useCallback((item: TreeDataItem) => {
98
+ setDraggedItem(item);
99
+ }, []);
100
+
101
+ const handleDrop = useCallback(
102
+ (targetItem: TreeDataItem) => {
103
+ if (draggedItem && onDocumentDrag && draggedItem.id !== targetItem.id) {
104
+ onDocumentDrag(draggedItem, targetItem);
105
+ }
106
+ setDraggedItem(null);
107
+ },
108
+ [draggedItem, onDocumentDrag],
109
+ );
110
+
111
+ const expandedItemIds = useMemo(() => {
112
+ if (!initialSelectedItemId) {
113
+ return [] as string[];
114
+ }
115
+
116
+ const ids: string[] = [];
117
+
118
+ function walkTreeItems(items: TreeDataItem[] | TreeDataItem, targetId: string) {
119
+ if (items instanceof Array) {
120
+ for (let i = 0; i < items.length; i++) {
121
+ ids.push(items[i]!.id);
122
+ if (walkTreeItems(items[i]!, targetId) && !expandAll) {
123
+ return true;
124
+ }
125
+ if (!expandAll) ids.pop();
126
+ }
127
+ } else if (!expandAll && items.id === targetId) {
128
+ return true;
129
+ } else if (items.children) {
130
+ return walkTreeItems(items.children, targetId);
131
+ }
132
+ }
133
+
134
+ walkTreeItems(data, initialSelectedItemId);
135
+ return ids;
136
+ }, [data, expandAll, initialSelectedItemId]);
137
+
138
+ return (
139
+ <div
140
+ className={cn(
141
+ "px-sm relative w-[300px] w-full overflow-x-auto overflow-y-hidden",
142
+ className,
143
+ )}
144
+ >
145
+ <TreeItem
146
+ data={data}
147
+ ref={ref}
148
+ selectedItemId={selectedItemId}
149
+ handleSelectChange={handleSelectChange}
150
+ expandedItemIds={expandedItemIds}
151
+ defaultLeafIcon={defaultLeafIcon}
152
+ defaultNodeIcon={defaultNodeIcon}
153
+ handleDragStart={handleDragStart}
154
+ handleDrop={handleDrop}
155
+ draggedItem={draggedItem}
156
+ {...props}
157
+ />
158
+ <div
159
+ className="h-[0px] w-full"
160
+ onDrop={() => {
161
+ handleDrop({ id: "", name: "parent_div" });
162
+ }}
163
+ ></div>
164
+ </div>
165
+ );
166
+ },
167
+ );
168
+ TreeViewRoot.displayName = "TreeViewRoot";
169
+
170
+ /** SSR fallback rendering for the tree view. */
171
+ const TreeViewFallback = forwardRef<HTMLDivElement, TreeProps>(
172
+ ({ data, initialSelectedItemId, onSelectChange, className, ...props }, ref) => {
173
+ const [selectedItemId, setSelectedItemId] = useState<string | undefined>(initialSelectedItemId);
174
+
175
+ const dataArray = Array.isArray(data) ? data : [data];
176
+
177
+ return (
178
+ <div
179
+ ref={ref}
180
+ className={cn("px-sm relative w-[300px] overflow-hidden", className)}
181
+ {...props}
182
+ >
183
+ <div role="tree">
184
+ <ul style={{ margin: 0, padding: 0 }}>
185
+ {dataArray.map((item) => (
186
+ <li key={item.id} style={{ margin: 0 }}>
187
+ <div
188
+ className={cn(
189
+ "py-sm flex items-center pl-[20px] text-left",
190
+ treeVariants(),
191
+ selectedItemId === item.id && selectedTreeVariants(),
192
+ )}
193
+ onClick={() => {
194
+ setSelectedItemId(item.id);
195
+ onSelectChange?.(item);
196
+ item.onClick?.();
197
+ }}
198
+ >
199
+ <span className="text-uk-sm leading-uk-sm z-10 flex-grow truncate">
200
+ {item.name}
201
+ </span>
202
+ </div>
203
+ </li>
204
+ ))}
205
+ </ul>
206
+ </div>
207
+ </div>
208
+ );
209
+ },
210
+ );
211
+ TreeViewFallback.displayName = "TreeViewFallback";
212
+
213
+ const TreeView = createClientOnlyComponent(TreeViewRoot, TreeViewFallback);
214
+
215
+ type TreeItemProps = TreeProps & {
216
+ selectedItemId?: string;
217
+ handleSelectChange: (item: TreeDataItem | undefined) => void;
218
+ expandedItemIds: string[];
219
+ defaultNodeIcon?: IconComponent;
220
+ defaultLeafIcon?: IconComponent;
221
+ handleDragStart?: (item: TreeDataItem) => void;
222
+ handleDrop?: (item: TreeDataItem) => void;
223
+ draggedItem: TreeDataItem | null;
224
+ };
225
+
226
+ /**
227
+ * Internal renderer that maps an item or array into nodes/leaves.
228
+ */
229
+ const TreeItem = forwardRef<HTMLDivElement, TreeItemProps>(
230
+ (
231
+ {
232
+ className,
233
+ data,
234
+ selectedItemId,
235
+ handleSelectChange,
236
+ expandedItemIds,
237
+ defaultNodeIcon,
238
+ defaultLeafIcon,
239
+ handleDragStart,
240
+ handleDrop,
241
+ draggedItem,
242
+ ...props
243
+ },
244
+ ref,
245
+ ) => {
246
+ if (!(data instanceof Array)) {
247
+ data = [data];
248
+ }
249
+ return (
250
+ <div ref={ref} role="tree" className={className} {...props}>
251
+ <ul style={{ margin: 0, padding: 0 }}>
252
+ {data.map((item) => (
253
+ <li key={item.id} style={{ margin: 0 }}>
254
+ {item.children ? (
255
+ <TreeNode
256
+ item={item}
257
+ selectedItemId={selectedItemId}
258
+ expandedItemIds={expandedItemIds}
259
+ handleSelectChange={handleSelectChange}
260
+ defaultNodeIcon={defaultNodeIcon}
261
+ defaultLeafIcon={defaultLeafIcon}
262
+ handleDragStart={handleDragStart}
263
+ handleDrop={handleDrop}
264
+ draggedItem={draggedItem}
265
+ />
266
+ ) : (
267
+ <TreeLeaf
268
+ item={item}
269
+ selectedItemId={selectedItemId}
270
+ handleSelectChange={handleSelectChange}
271
+ defaultLeafIcon={defaultLeafIcon}
272
+ handleDragStart={handleDragStart}
273
+ handleDrop={handleDrop}
274
+ draggedItem={draggedItem}
275
+ />
276
+ )}
277
+ </li>
278
+ ))}
279
+ </ul>
280
+ </div>
281
+ );
282
+ },
283
+ );
284
+ TreeItem.displayName = "TreeItem";
285
+
286
+ /**
287
+ * A node item that can expand to show children.
288
+ */
289
+ const TreeNode = ({
290
+ item,
291
+ handleSelectChange,
292
+ expandedItemIds,
293
+ selectedItemId,
294
+ defaultNodeIcon,
295
+ defaultLeafIcon,
296
+ handleDragStart,
297
+ handleDrop,
298
+ draggedItem,
299
+ }: {
300
+ item: TreeDataItem;
301
+ handleSelectChange: (item: TreeDataItem | undefined) => void;
302
+ expandedItemIds: string[];
303
+ selectedItemId?: string;
304
+ defaultNodeIcon?: IconComponent;
305
+ defaultLeafIcon?: IconComponent;
306
+ handleDragStart?: (item: TreeDataItem) => void;
307
+ handleDrop?: (item: TreeDataItem) => void;
308
+ draggedItem: TreeDataItem | null;
309
+ }) => {
310
+ const [value, setValue] = useState(expandedItemIds.includes(item.id) ? [item.id] : []);
311
+ const [isDragOver, setIsDragOver] = useState(false);
312
+
313
+ const onDragStart = (e: DragEvent) => {
314
+ if (!item.draggable) {
315
+ e.preventDefault();
316
+ return;
317
+ }
318
+ e.dataTransfer.setData("text/plain", item.id);
319
+ handleDragStart?.(item);
320
+ };
321
+
322
+ const onDragOver = (e: DragEvent) => {
323
+ if (item.droppable !== false && draggedItem && draggedItem.id !== item.id) {
324
+ e.preventDefault();
325
+ setIsDragOver(true);
326
+ }
327
+ };
328
+
329
+ const onDragLeave = () => {
330
+ setIsDragOver(false);
331
+ };
332
+
333
+ const onDrop = (e: DragEvent) => {
334
+ e.preventDefault();
335
+ setIsDragOver(false);
336
+ handleDrop?.(item);
337
+ };
338
+
339
+ const handleSelect = () => {
340
+ handleSelectChange(item);
341
+ item.onClick?.();
342
+ };
343
+
344
+ return (
345
+ <AccordionPrimitive.Root type="multiple" value={value} onValueChange={(s) => setValue(s)}>
346
+ <AccordionPrimitive.Item value={item.id}>
347
+ <div
348
+ className={cn(
349
+ treeVariants(),
350
+ selectedItemId === item.id && selectedTreeVariants(),
351
+ isDragOver && dragOverVariants(),
352
+ )}
353
+ onClick={handleSelect}
354
+ draggable={!!item.draggable}
355
+ onDragStart={onDragStart}
356
+ onDragOver={onDragOver}
357
+ onDragLeave={onDragLeave}
358
+ onDrop={onDrop}
359
+ >
360
+ <AccordionTrigger
361
+ className={cn(
362
+ "flex-1",
363
+ selectedItemId === item.id && "text-text-withbg",
364
+ isDragOver && "text-text-withbg",
365
+ )}
366
+ onClick={(e: ReactMouseEvent) => {
367
+ e.stopPropagation();
368
+ }}
369
+ >
370
+ <TreeIcon
371
+ onClick={(e: ReactMouseEvent) => {
372
+ e.stopPropagation();
373
+ handleSelect();
374
+ }}
375
+ item={item}
376
+ isSelected={selectedItemId === item.id}
377
+ isOpen={value.includes(item.id)}
378
+ default={defaultNodeIcon}
379
+ />
380
+ <span
381
+ className="text-uk-sm leading-uk-sm z-10 truncate"
382
+ onClick={(e: ReactMouseEvent) => {
383
+ e.stopPropagation();
384
+ handleSelect();
385
+ }}
386
+ >
387
+ {item.name}
388
+ </span>
389
+ <TreeActions
390
+ isSelected={selectedItemId === item.id}
391
+ onClick={(e: ReactMouseEvent) => {
392
+ e.stopPropagation();
393
+ }}
394
+ >
395
+ {item.actions}
396
+ </TreeActions>
397
+ </AccordionTrigger>
398
+ </div>
399
+ <AccordionContent className="pl-[20px]">
400
+ <TreeItem
401
+ data={item.children ? item.children : item}
402
+ selectedItemId={selectedItemId}
403
+ handleSelectChange={handleSelectChange}
404
+ expandedItemIds={expandedItemIds}
405
+ defaultLeafIcon={defaultLeafIcon}
406
+ defaultNodeIcon={defaultNodeIcon}
407
+ handleDragStart={handleDragStart}
408
+ handleDrop={handleDrop}
409
+ draggedItem={draggedItem}
410
+ />
411
+ </AccordionContent>
412
+ </AccordionPrimitive.Item>
413
+ </AccordionPrimitive.Root>
414
+ );
415
+ };
416
+
417
+ /**
418
+ * A leaf item without children.
419
+ */
420
+ const TreeLeaf = forwardRef<
421
+ HTMLDivElement,
422
+ HTMLAttributes<HTMLDivElement> & {
423
+ item: TreeDataItem;
424
+ selectedItemId?: string;
425
+ handleSelectChange: (item: TreeDataItem | undefined) => void;
426
+ defaultLeafIcon?: IconComponent;
427
+ handleDragStart?: (item: TreeDataItem) => void;
428
+ handleDrop?: (item: TreeDataItem) => void;
429
+ draggedItem: TreeDataItem | null;
430
+ }
431
+ >(
432
+ (
433
+ {
434
+ className,
435
+ item,
436
+ selectedItemId,
437
+ handleSelectChange,
438
+ defaultLeafIcon,
439
+ handleDragStart,
440
+ handleDrop,
441
+ draggedItem,
442
+ ...props
443
+ },
444
+ ref,
445
+ ) => {
446
+ const [isDragOver, setIsDragOver] = useState(false);
447
+
448
+ const onDragStart = (e: DragEvent) => {
449
+ if (!item.draggable || item.disabled) {
450
+ e.preventDefault();
451
+ return;
452
+ }
453
+ e.dataTransfer.setData("text/plain", item.id);
454
+ handleDragStart?.(item);
455
+ };
456
+
457
+ const onDragOver = (e: DragEvent) => {
458
+ if (item.droppable !== false && !item.disabled && draggedItem && draggedItem.id !== item.id) {
459
+ e.preventDefault();
460
+ setIsDragOver(true);
461
+ }
462
+ };
463
+
464
+ const onDragLeave = () => {
465
+ setIsDragOver(false);
466
+ };
467
+
468
+ const onDrop = (e: DragEvent) => {
469
+ if (item.disabled) return;
470
+ e.preventDefault();
471
+ setIsDragOver(false);
472
+ handleDrop?.(item);
473
+ };
474
+
475
+ return (
476
+ <div
477
+ ref={ref}
478
+ className={cn(
479
+ "py-sm flex items-center pl-[20px] text-left before:right-1",
480
+ treeVariants(),
481
+ className,
482
+ selectedItemId === item.id && selectedTreeVariants(),
483
+ isDragOver && dragOverVariants(),
484
+ item.disabled && "text-text-tertiary pointer-events-none cursor-not-allowed",
485
+ )}
486
+ onClick={() => {
487
+ if (item.disabled) return;
488
+ handleSelectChange(item);
489
+ item.onClick?.();
490
+ }}
491
+ draggable={!!item.draggable && !item.disabled}
492
+ onDragStart={onDragStart}
493
+ onDragOver={onDragOver}
494
+ onDragLeave={onDragLeave}
495
+ onDrop={onDrop}
496
+ {...props}
497
+ >
498
+ <TreeIcon item={item} isSelected={selectedItemId === item.id} default={defaultLeafIcon} />
499
+ <span className="text-uk-sm leading-uk-sm z-10 flex-grow truncate">{item.name}</span>
500
+ <TreeActions isSelected={selectedItemId === item.id && !item.disabled}>
501
+ {item.actions}
502
+ </TreeActions>
503
+ </div>
504
+ );
505
+ },
506
+ );
507
+ TreeLeaf.displayName = "TreeLeaf";
508
+
509
+ /**
510
+ * Styled trigger for collapsible node rows.
511
+ */
512
+ const AccordionTrigger = forwardRef<
513
+ ElementRef<typeof AccordionPrimitive.Trigger>,
514
+ ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
515
+ >(({ className, children, ...props }, ref) => (
516
+ <AccordionPrimitive.Header style={{ margin: 0, fontWeight: 400 }}>
517
+ <AccordionPrimitive.Trigger
518
+ ref={ref}
519
+ className={cn(
520
+ "py-sm flex w-full flex-1 items-center transition-all first:[&[data-state=open]>svg]:rotate-90",
521
+ className,
522
+ )}
523
+ {...props}
524
+ >
525
+ <ChevronRight className="z-10 mr-[6px] size-[14px] shrink-0 cursor-pointer transition-transform duration-200" />
526
+ {children}
527
+ </AccordionPrimitive.Trigger>
528
+ </AccordionPrimitive.Header>
529
+ ));
530
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
531
+
532
+ /**
533
+ * Styled content area for nested children.
534
+ */
535
+ const AccordionContent = forwardRef<
536
+ ElementRef<typeof AccordionPrimitive.Content>,
537
+ ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
538
+ >(({ className, children, ...props }, ref) => (
539
+ <AccordionPrimitive.Content
540
+ ref={ref}
541
+ className={cn(
542
+ "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down text-uk-sm text-text-primary leading-uk-sm z-10 overflow-hidden transition-all",
543
+ className,
544
+ )}
545
+ {...props}
546
+ >
547
+ <div>{children}</div>
548
+ </AccordionPrimitive.Content>
549
+ ));
550
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName;
551
+
552
+ /**
553
+ * Chooses the most appropriate icon based on selection/open state.
554
+ */
555
+ const TreeIcon = ({
556
+ item,
557
+ isOpen,
558
+ isSelected,
559
+ default: defaultIcon,
560
+ onClick,
561
+ }: {
562
+ item: TreeDataItem;
563
+ isOpen?: boolean;
564
+ isSelected?: boolean;
565
+ default?: IconComponent;
566
+ onClick?: (e: ReactMouseEvent) => void;
567
+ }) => {
568
+ let Icon = defaultIcon;
569
+ if (isSelected && item.selectedIcon) {
570
+ Icon = item.selectedIcon;
571
+ } else if (isOpen && item.openIcon) {
572
+ Icon = item.openIcon;
573
+ } else if (item.icon) {
574
+ Icon = item.icon;
575
+ }
576
+ return Icon ? <Icon className="z-10 mr-[6px] size-[14px] shrink-0" onClick={onClick} /> : <></>;
577
+ };
578
+
579
+ /**
580
+ * Right-aligned action slot shown when row is active/selected.
581
+ */
582
+ const TreeActions = ({
583
+ children,
584
+ isSelected,
585
+ onClick,
586
+ }: {
587
+ children: ReactNode;
588
+ isSelected: boolean;
589
+ onClick?: (e: ReactMouseEvent) => void;
590
+ }) => {
591
+ return (
592
+ <div
593
+ className={cn(
594
+ isSelected ? "block" : "hidden",
595
+ "absolute right-[10px] z-10 group-hover:block",
596
+ )}
597
+ onClick={onClick}
598
+ >
599
+ {children}
600
+ </div>
601
+ );
602
+ };
603
+
604
+ export { TreeView as SimpleTreeView, type TreeDataItem as SimpleTreeDataItem };
@@ -0,0 +1,15 @@
1
+ import { ComponentProps } from "react";
2
+
3
+ import { cn } from "../hooks";
4
+
5
+ function Skeleton({ className, ...props }: ComponentProps<"div">) {
6
+ return (
7
+ <div
8
+ data-slot="skeleton"
9
+ className={cn("bg-bg-secondary rounded-uk-sm animate-pulse", className)}
10
+ {...props}
11
+ />
12
+ );
13
+ }
14
+
15
+ export { Skeleton };