@vuer-ai/vuer-uikit 0.0.11 → 0.0.13

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 (153) hide show
  1. package/dist/{chunk-CP7QYV4N.mjs → chunk-44KW6PTD.mjs} +1 -0
  2. package/dist/{chunk-KQAHAGUG.js → chunk-AOUGWGQR.js} +2 -2
  3. package/dist/{chunk-J7PTSP4Q.mjs → chunk-EAZQH4IX.mjs} +8 -0
  4. package/dist/chunk-EOFYA6CS.js +53 -0
  5. package/dist/{chunk-O4TK3AKI.mjs → chunk-EYIFKSU2.mjs} +1 -1
  6. package/dist/{chunk-WMXX2UMD.mjs → chunk-FEOONYZ2.mjs} +2 -2
  7. package/dist/{chunk-66DYOZI3.js → chunk-FORVP7XH.js} +6 -5
  8. package/dist/{chunk-7X6N54LX.mjs → chunk-G5KMD72J.mjs} +6 -5
  9. package/dist/{chunk-5MZCQW4U.js → chunk-IXHMIR5P.js} +4 -4
  10. package/dist/{chunk-CCGUGCCV.js → chunk-JAJNLRY5.js} +9 -9
  11. package/dist/{chunk-WOZWC6KO.mjs → chunk-JMPVDU2C.mjs} +35 -4
  12. package/dist/{chunk-E5KWKBH3.mjs → chunk-LEPXSM36.mjs} +10 -24
  13. package/dist/{chunk-3XVIJY3H.mjs → chunk-MRVMXKZO.mjs} +1 -1
  14. package/dist/{chunk-UMIQYHO6.mjs → chunk-OOI3SJDU.mjs} +10 -4
  15. package/dist/{chunk-B5EMQBVL.js → chunk-OTPUWWEB.js} +8 -3
  16. package/dist/{chunk-FSMKJAZT.js → chunk-PVRQNCSJ.js} +9 -23
  17. package/dist/chunk-Q5KEB4UK.mjs +51 -0
  18. package/dist/{chunk-XUQ5A7ZA.js → chunk-QEY7BWIR.js} +10 -4
  19. package/dist/{chunk-QZASHJNJ.js → chunk-QJR6MCTR.js} +8 -0
  20. package/dist/{chunk-IOI3YFTY.js → chunk-U2ZLDPOE.js} +8 -8
  21. package/dist/{chunk-ZJXBC33M.js → chunk-UFHMEEGL.js} +1 -0
  22. package/dist/{chunk-5P3KAS53.js → chunk-WJ7T7FAH.js} +34 -3
  23. package/dist/{chunk-6L4KPPOD.mjs → chunk-XMG3IVGZ.mjs} +8 -3
  24. package/dist/{chunk-XCCC7HVN.mjs → chunk-ZVG2UKKC.mjs} +1 -1
  25. package/dist/highlight-cursor/cursor-provider.js +2 -2
  26. package/dist/highlight-cursor/cursor-provider.mjs +1 -1
  27. package/dist/highlight-cursor/enhanced-components.js +11 -10
  28. package/dist/highlight-cursor/enhanced-components.mjs +6 -5
  29. package/dist/highlight-cursor/index.js +15 -14
  30. package/dist/highlight-cursor/index.mjs +7 -6
  31. package/dist/highlight-cursor/tabs-cursor-context.js +3 -3
  32. package/dist/highlight-cursor/tabs-cursor-context.mjs +1 -1
  33. package/dist/highlight-cursor/with-cursor.js +2 -2
  34. package/dist/highlight-cursor/with-cursor.mjs +1 -1
  35. package/dist/index.d.mts +1 -0
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +64 -59
  38. package/dist/index.mjs +15 -14
  39. package/dist/ui/avatar.js +2 -1
  40. package/dist/ui/avatar.mjs +2 -1
  41. package/dist/ui/badge.js +2 -1
  42. package/dist/ui/badge.mjs +2 -1
  43. package/dist/ui/button.js +2 -1
  44. package/dist/ui/button.mjs +2 -1
  45. package/dist/ui/card.js +2 -1
  46. package/dist/ui/card.mjs +2 -1
  47. package/dist/ui/checkbox.js +2 -1
  48. package/dist/ui/checkbox.mjs +2 -1
  49. package/dist/ui/collapsible.js +2 -1
  50. package/dist/ui/collapsible.mjs +2 -1
  51. package/dist/ui/dropdown.js +2 -1
  52. package/dist/ui/dropdown.mjs +2 -1
  53. package/dist/ui/index.js +49 -48
  54. package/dist/ui/index.mjs +12 -11
  55. package/dist/ui/input-numbers.js +4 -3
  56. package/dist/ui/input-numbers.mjs +3 -2
  57. package/dist/ui/input.js +2 -1
  58. package/dist/ui/input.mjs +2 -1
  59. package/dist/ui/layout.js +2 -1
  60. package/dist/ui/layout.mjs +2 -1
  61. package/dist/ui/modal.js +2 -1
  62. package/dist/ui/modal.mjs +2 -1
  63. package/dist/ui/popover.js +2 -1
  64. package/dist/ui/popover.mjs +2 -1
  65. package/dist/ui/radio-group.js +2 -1
  66. package/dist/ui/radio-group.mjs +2 -1
  67. package/dist/ui/select.js +2 -1
  68. package/dist/ui/select.mjs +2 -1
  69. package/dist/ui/slider.js +2 -1
  70. package/dist/ui/slider.mjs +2 -1
  71. package/dist/ui/switch.js +2 -1
  72. package/dist/ui/switch.mjs +2 -1
  73. package/dist/ui/tabs.js +8 -7
  74. package/dist/ui/tabs.mjs +4 -3
  75. package/dist/ui/textarea.js +2 -1
  76. package/dist/ui/textarea.mjs +2 -1
  77. package/dist/ui/theme-context.js +6 -3
  78. package/dist/ui/theme-context.mjs +4 -1
  79. package/dist/ui/timeline.js +6 -5
  80. package/dist/ui/timeline.mjs +5 -4
  81. package/dist/ui/toast.d.mts +1 -1
  82. package/dist/ui/toast.d.ts +1 -1
  83. package/dist/ui/toast.js +3 -3
  84. package/dist/ui/toast.mjs +1 -1
  85. package/dist/ui/toggle-group.js +2 -1
  86. package/dist/ui/toggle-group.mjs +2 -1
  87. package/dist/ui/toggle.js +2 -1
  88. package/dist/ui/toggle.mjs +2 -1
  89. package/dist/ui/tooltip.d.mts +3 -3
  90. package/dist/ui/tooltip.d.ts +3 -3
  91. package/dist/ui/tooltip.js +7 -6
  92. package/dist/ui/tooltip.mjs +3 -2
  93. package/dist/ui/tree-view-v2.js +5 -4
  94. package/dist/ui/tree-view-v2.mjs +4 -3
  95. package/dist/ui/version-badge.js +2 -1
  96. package/dist/ui/version-badge.mjs +2 -1
  97. package/dist/utils/index.d.mts +1 -0
  98. package/dist/utils/index.d.ts +1 -0
  99. package/dist/utils/index.js +6 -1
  100. package/dist/utils/index.mjs +2 -1
  101. package/dist/utils/use-local-storage.d.mts +3 -0
  102. package/dist/utils/use-local-storage.d.ts +3 -0
  103. package/dist/utils/use-local-storage.js +10 -0
  104. package/dist/utils/use-local-storage.mjs +1 -0
  105. package/package.json +6 -4
  106. package/src/highlight-cursor/cursor-context.tsx +23 -0
  107. package/src/highlight-cursor/cursor-provider.tsx +264 -0
  108. package/src/highlight-cursor/enhanced-components.tsx +16 -0
  109. package/src/highlight-cursor/index.ts +21 -0
  110. package/src/highlight-cursor/tabs-cursor-context.tsx +121 -0
  111. package/src/highlight-cursor/types.ts +40 -0
  112. package/src/highlight-cursor/with-cursor.tsx +144 -0
  113. package/src/index.css +5 -0
  114. package/src/index.ts +5 -0
  115. package/src/styles/theme.css +80 -0
  116. package/src/styles/toast.css +64 -0
  117. package/src/styles/variables.css +194 -0
  118. package/src/ui/avatar.tsx +92 -0
  119. package/src/ui/badge.tsx +68 -0
  120. package/src/ui/button.tsx +100 -0
  121. package/src/ui/card.tsx +88 -0
  122. package/src/ui/checkbox.tsx +76 -0
  123. package/src/ui/collapsible.tsx +36 -0
  124. package/src/ui/dropdown.tsx +375 -0
  125. package/src/ui/index.ts +31 -0
  126. package/src/ui/input-numbers.tsx +201 -0
  127. package/src/ui/input.tsx +141 -0
  128. package/src/ui/layout.tsx +41 -0
  129. package/src/ui/modal.tsx +198 -0
  130. package/src/ui/popover.tsx +59 -0
  131. package/src/ui/radio-group.tsx +56 -0
  132. package/src/ui/select.tsx +292 -0
  133. package/src/ui/sheet.tsx +131 -0
  134. package/src/ui/slider.tsx +189 -0
  135. package/src/ui/switch.tsx +43 -0
  136. package/src/ui/tabs.tsx +128 -0
  137. package/src/ui/textarea.tsx +52 -0
  138. package/src/ui/theme-context.tsx +80 -0
  139. package/src/ui/timeline.tsx +717 -0
  140. package/src/ui/toast.tsx +27 -0
  141. package/src/ui/toggle-group.tsx +82 -0
  142. package/src/ui/toggle.tsx +88 -0
  143. package/src/ui/tooltip.tsx +132 -0
  144. package/src/ui/tree-view-v2.tsx +300 -0
  145. package/src/ui/tree-view.tsx +550 -0
  146. package/src/ui/version-badge.tsx +65 -0
  147. package/src/utils/cn.ts +21 -0
  148. package/src/utils/index.ts +2 -0
  149. package/src/utils/use-local-storage.ts +59 -0
  150. package/dist/chunk-OBWGRG45.js +0 -21
  151. package/dist/chunk-Z6XRPTIQ.mjs +0 -15
  152. /package/dist/{chunk-QS7WS6DD.mjs → chunk-M4IVLZIH.mjs} +0 -0
  153. /package/dist/{chunk-ST4P6AN6.js → chunk-XWS4SIB5.js} +0 -0
@@ -0,0 +1,550 @@
1
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
2
+ import { cva } from "class-variance-authority";
3
+ import { ChevronRight, ChevronDown, Folder, File } from "lucide-react";
4
+ import {
5
+ forwardRef,
6
+ HTMLAttributes,
7
+ useCallback,
8
+ useMemo,
9
+ useState,
10
+ type ReactNode,
11
+ type ElementRef,
12
+ type ComponentPropsWithoutRef,
13
+ type DragEvent,
14
+ type ComponentType,
15
+ type SVGProps,
16
+ } from "react";
17
+
18
+ import { cn } from "../utils/cn";
19
+
20
+ type IconComponent = ComponentType<SVGProps<SVGSVGElement>>;
21
+
22
+ const treeVariants = cva(
23
+ "text-uk-md group py-1 h-9 text-text-primary rounded transition-colors cursor-pointer text-left relative z-20",
24
+ );
25
+
26
+ const selectedTreeVariants = cva("");
27
+
28
+ const dragOverVariants = cva("bg-primary/20 text-primary-foreground");
29
+
30
+ interface TreeDataItem {
31
+ id: string;
32
+ name: string;
33
+ icon?: IconComponent;
34
+ selectedIcon?: IconComponent;
35
+ openIcon?: IconComponent;
36
+ children?: TreeDataItem[];
37
+ actions?: ReactNode;
38
+ onClick?: () => void;
39
+ draggable?: boolean;
40
+ droppable?: boolean;
41
+ disabled?: boolean;
42
+ }
43
+
44
+ type TreeProps = HTMLAttributes<HTMLDivElement> & {
45
+ data: TreeDataItem[] | TreeDataItem;
46
+ initialSelectedItemId?: string;
47
+ onSelectChange?: (item: TreeDataItem | undefined) => void;
48
+ expandAll?: boolean;
49
+ defaultNodeIcon?: IconComponent;
50
+ defaultLeafIcon?: IconComponent;
51
+ onDocumentDrag?: (sourceItem: TreeDataItem, targetItem: TreeDataItem) => void;
52
+ };
53
+
54
+ const TreeView = forwardRef<HTMLDivElement, TreeProps>(
55
+ (
56
+ {
57
+ data,
58
+ initialSelectedItemId,
59
+ onSelectChange,
60
+ expandAll,
61
+ defaultLeafIcon,
62
+ defaultNodeIcon,
63
+ className,
64
+ onDocumentDrag,
65
+ ...props
66
+ },
67
+ ref,
68
+ ) => {
69
+ const [selectedItemId, setSelectedItemId] = useState<string | undefined>(initialSelectedItemId);
70
+
71
+ const [draggedItem, setDraggedItem] = useState<TreeDataItem | null>(null);
72
+
73
+ const [hoverBackgroundStyle, setHoverBackgroundStyle] = useState<{
74
+ display: "block" | "none";
75
+ top: number;
76
+ height: number;
77
+ }>({ display: "none", top: 0, height: 0 });
78
+
79
+ const handleSelectChange = useCallback(
80
+ (item: TreeDataItem | undefined) => {
81
+ setSelectedItemId(item?.id);
82
+ if (onSelectChange) {
83
+ onSelectChange(item);
84
+ }
85
+ },
86
+ [onSelectChange],
87
+ );
88
+
89
+ const handleDragStart = useCallback((item: TreeDataItem) => {
90
+ setDraggedItem(item);
91
+ }, []);
92
+
93
+ const handleDrop = useCallback(
94
+ (targetItem: TreeDataItem) => {
95
+ if (draggedItem && onDocumentDrag && draggedItem.id !== targetItem.id) {
96
+ onDocumentDrag(draggedItem, targetItem);
97
+ }
98
+ setDraggedItem(null);
99
+ },
100
+ [draggedItem, onDocumentDrag],
101
+ );
102
+
103
+ const handleItemHover = useCallback((element: HTMLElement | null) => {
104
+ if (element) {
105
+ const rect = element.getBoundingClientRect();
106
+ const containerRect = element.closest("[data-tree-container]")?.getBoundingClientRect();
107
+ if (containerRect) {
108
+ setHoverBackgroundStyle({
109
+ display: "block",
110
+ top: rect.top - containerRect.top,
111
+ height: rect.height,
112
+ });
113
+ }
114
+ } else {
115
+ setHoverBackgroundStyle({ display: "none", top: 0, height: 0 });
116
+ }
117
+ }, []);
118
+
119
+ const expandedItemIds = useMemo(() => {
120
+ if (!initialSelectedItemId) {
121
+ return [] as string[];
122
+ }
123
+
124
+ const ids: string[] = [];
125
+
126
+ function walkTreeItems(items: TreeDataItem[] | TreeDataItem, targetId: string) {
127
+ if (items instanceof Array) {
128
+ for (let i = 0; i < items.length; i++) {
129
+ ids.push(items[i]!.id);
130
+ if (walkTreeItems(items[i]!, targetId) && !expandAll) {
131
+ return true;
132
+ }
133
+ if (!expandAll) ids.pop();
134
+ }
135
+ } else if (!expandAll && items.id === targetId) {
136
+ return true;
137
+ } else if (items.children) {
138
+ return walkTreeItems(items.children, targetId);
139
+ }
140
+ }
141
+
142
+ walkTreeItems(data, initialSelectedItemId);
143
+ return ids;
144
+ }, [data, expandAll, initialSelectedItemId]);
145
+
146
+ return (
147
+ <div
148
+ className={cn(
149
+ "bg-bg-primary rounded-uk-md relative max-w-[300px] min-w-[240px] overflow-hidden p-2",
150
+ className,
151
+ )}
152
+ data-tree-container
153
+ >
154
+ <div
155
+ className="bg-bg-tertiary rounded-uk-sm pointer-events-none absolute right-2 left-2 z-10 transition-all duration-150"
156
+ style={{
157
+ display: hoverBackgroundStyle.display,
158
+ top: hoverBackgroundStyle.top,
159
+ height: hoverBackgroundStyle.height,
160
+ }}
161
+ />
162
+ <TreeItem
163
+ data={data}
164
+ ref={ref}
165
+ selectedItemId={selectedItemId}
166
+ handleSelectChange={handleSelectChange}
167
+ expandedItemIds={expandedItemIds}
168
+ defaultLeafIcon={defaultLeafIcon}
169
+ defaultNodeIcon={defaultNodeIcon}
170
+ handleDragStart={handleDragStart}
171
+ handleDrop={handleDrop}
172
+ draggedItem={draggedItem}
173
+ onItemHover={handleItemHover}
174
+ {...props}
175
+ />
176
+ <div
177
+ className="h-[48px] w-full"
178
+ onDrop={() => {
179
+ handleDrop({ id: "", name: "parent_div" });
180
+ }}
181
+ ></div>
182
+ </div>
183
+ );
184
+ },
185
+ );
186
+ TreeView.displayName = "TreeView";
187
+
188
+ type TreeItemProps = TreeProps & {
189
+ selectedItemId?: string;
190
+ handleSelectChange: (item: TreeDataItem | undefined) => void;
191
+ expandedItemIds: string[];
192
+ defaultNodeIcon?: IconComponent;
193
+ defaultLeafIcon?: IconComponent;
194
+ handleDragStart?: (item: TreeDataItem) => void;
195
+ handleDrop?: (item: TreeDataItem) => void;
196
+ draggedItem: TreeDataItem | null;
197
+ onItemHover?: (element: HTMLElement | null) => void;
198
+ };
199
+
200
+ const TreeItem = forwardRef<HTMLDivElement, TreeItemProps>(
201
+ (
202
+ {
203
+ className,
204
+ data,
205
+ selectedItemId,
206
+ handleSelectChange,
207
+ expandedItemIds,
208
+ defaultLeafIcon,
209
+ defaultNodeIcon,
210
+ handleDragStart,
211
+ handleDrop,
212
+ draggedItem,
213
+ onItemHover,
214
+ ...props
215
+ },
216
+ ref,
217
+ ) => {
218
+ if (!(data instanceof Array)) {
219
+ data = [data];
220
+ }
221
+ return (
222
+ <div ref={ref} role="tree" className={className} {...props}>
223
+ <ul style={{ margin: 0, paddingLeft: "1rem" }}>
224
+ {data.map((item) => (
225
+ <li key={item.id} style={{ margin: 0 }}>
226
+ {item.children ? (
227
+ <TreeNode
228
+ item={item}
229
+ handleSelectChange={handleSelectChange}
230
+ expandedItemIds={expandedItemIds}
231
+ selectedItemId={selectedItemId}
232
+ defaultNodeIcon={defaultNodeIcon}
233
+ defaultLeafIcon={defaultLeafIcon}
234
+ handleDragStart={handleDragStart}
235
+ handleDrop={handleDrop}
236
+ draggedItem={draggedItem}
237
+ onItemHover={onItemHover}
238
+ />
239
+ ) : (
240
+ <TreeLeaf
241
+ item={item}
242
+ selectedItemId={selectedItemId}
243
+ handleSelectChange={handleSelectChange}
244
+ defaultLeafIcon={defaultLeafIcon}
245
+ handleDragStart={handleDragStart}
246
+ handleDrop={handleDrop}
247
+ draggedItem={draggedItem}
248
+ onItemHover={onItemHover}
249
+ />
250
+ )}
251
+ </li>
252
+ ))}
253
+ </ul>
254
+ </div>
255
+ );
256
+ },
257
+ );
258
+ TreeItem.displayName = "TreeItem";
259
+
260
+ const TreeNode = ({
261
+ item,
262
+ handleSelectChange,
263
+ expandedItemIds,
264
+ selectedItemId,
265
+ defaultNodeIcon,
266
+ defaultLeafIcon,
267
+ handleDragStart,
268
+ handleDrop,
269
+ draggedItem,
270
+ onItemHover,
271
+ }: {
272
+ item: TreeDataItem;
273
+ handleSelectChange: (item: TreeDataItem | undefined) => void;
274
+ expandedItemIds: string[];
275
+ selectedItemId?: string;
276
+ defaultNodeIcon?: IconComponent;
277
+ defaultLeafIcon?: IconComponent;
278
+ handleDragStart?: (item: TreeDataItem) => void;
279
+ handleDrop?: (item: TreeDataItem) => void;
280
+ draggedItem: TreeDataItem | null;
281
+ onItemHover?: (element: HTMLElement | null) => void;
282
+ }) => {
283
+ const [value, setValue] = useState(expandedItemIds.includes(item.id) ? [item.id] : []);
284
+ const [isDragOver, setIsDragOver] = useState(false);
285
+ const [isHovered, setIsHovered] = useState(false);
286
+
287
+ const onDragStart = (e: DragEvent) => {
288
+ if (!item.draggable) {
289
+ e.preventDefault();
290
+ return;
291
+ }
292
+ e.dataTransfer.setData("text/plain", item.id);
293
+ handleDragStart?.(item);
294
+ };
295
+
296
+ const onDragOver = (e: DragEvent) => {
297
+ if (item.droppable !== false && draggedItem && draggedItem.id !== item.id) {
298
+ e.preventDefault();
299
+ setIsDragOver(true);
300
+ }
301
+ };
302
+
303
+ const onDragLeave = () => {
304
+ setIsDragOver(false);
305
+ };
306
+
307
+ const onDrop = (e: DragEvent) => {
308
+ e.preventDefault();
309
+ setIsDragOver(false);
310
+ handleDrop?.(item);
311
+ };
312
+
313
+ return (
314
+ <AccordionPrimitive.Root type="multiple" value={value} onValueChange={(s) => setValue(s)}>
315
+ <AccordionPrimitive.Item value={item.id} className="m-0">
316
+ <AccordionTrigger
317
+ style={{ margin: 0 }}
318
+ className={cn(
319
+ treeVariants(),
320
+ selectedItemId === item.id && selectedTreeVariants(),
321
+ isDragOver && dragOverVariants(),
322
+ item.disabled &&
323
+ "hover:bg-bg-primary pointer-events-none cursor-not-allowed opacity-50",
324
+ )}
325
+ onClick={() => {
326
+ if (item.disabled) return;
327
+ handleSelectChange(item);
328
+ item.onClick?.();
329
+ }}
330
+ onMouseEnter={(e) => {
331
+ setIsHovered(true);
332
+ onItemHover?.(e.currentTarget);
333
+ }}
334
+ onMouseLeave={() => {
335
+ setIsHovered(false);
336
+ onItemHover?.(null);
337
+ }}
338
+ draggable={!!item.draggable && !item.disabled}
339
+ onDragStart={onDragStart}
340
+ onDragOver={onDragOver}
341
+ onDragLeave={onDragLeave}
342
+ onDrop={onDrop}
343
+ >
344
+ {isHovered ? (
345
+ value.includes(item.id) ? (
346
+ <ChevronDown className="text-text-primary mr-2 h-4 w-4 shrink-0 transition-transform duration-200" />
347
+ ) : (
348
+ <ChevronRight className="text-text-primary mr-2 h-4 w-4 shrink-0 transition-transform duration-200" />
349
+ )
350
+ ) : (
351
+ <TreeIcon
352
+ item={item}
353
+ isSelected={selectedItemId === item.id}
354
+ isOpen={value.includes(item.id)}
355
+ default={defaultNodeIcon}
356
+ />
357
+ )}
358
+ <span className="text-text-primary text-uk-md flex-grow truncate text-left">
359
+ {item.name}
360
+ </span>
361
+ <TreeActions isSelected={selectedItemId === item.id && !item.disabled}>
362
+ {item.actions}
363
+ </TreeActions>
364
+ </AccordionTrigger>
365
+ <AccordionContent>
366
+ <TreeItem
367
+ data={item.children ? item.children : item}
368
+ selectedItemId={selectedItemId}
369
+ handleSelectChange={handleSelectChange}
370
+ expandedItemIds={expandedItemIds}
371
+ defaultLeafIcon={defaultLeafIcon}
372
+ defaultNodeIcon={defaultNodeIcon}
373
+ handleDragStart={handleDragStart}
374
+ handleDrop={handleDrop}
375
+ draggedItem={draggedItem}
376
+ onItemHover={onItemHover}
377
+ />
378
+ </AccordionContent>
379
+ </AccordionPrimitive.Item>
380
+ </AccordionPrimitive.Root>
381
+ );
382
+ };
383
+
384
+ const TreeLeaf = forwardRef<
385
+ HTMLDivElement,
386
+ HTMLAttributes<HTMLDivElement> & {
387
+ item: TreeDataItem;
388
+ selectedItemId?: string;
389
+ handleSelectChange: (item: TreeDataItem | undefined) => void;
390
+ defaultLeafIcon?: IconComponent;
391
+ handleDragStart?: (item: TreeDataItem) => void;
392
+ handleDrop?: (item: TreeDataItem) => void;
393
+ draggedItem: TreeDataItem | null;
394
+ onItemHover?: (element: HTMLElement | null) => void;
395
+ }
396
+ >(
397
+ (
398
+ {
399
+ className,
400
+ item,
401
+ selectedItemId,
402
+ handleSelectChange,
403
+ defaultLeafIcon,
404
+ handleDragStart,
405
+ handleDrop,
406
+ draggedItem,
407
+ onItemHover,
408
+ ...props
409
+ },
410
+ ref,
411
+ ) => {
412
+ const [isDragOver, setIsDragOver] = useState(false);
413
+
414
+ const onDragStart = (e: DragEvent) => {
415
+ if (!item.draggable || item.disabled) {
416
+ e.preventDefault();
417
+ return;
418
+ }
419
+ e.dataTransfer.setData("text/plain", item.id);
420
+ handleDragStart?.(item);
421
+ };
422
+
423
+ const onDragOver = (e: DragEvent) => {
424
+ if (item.droppable !== false && !item.disabled && draggedItem && draggedItem.id !== item.id) {
425
+ e.preventDefault();
426
+ setIsDragOver(true);
427
+ }
428
+ };
429
+
430
+ const onDragLeave = () => {
431
+ setIsDragOver(false);
432
+ };
433
+
434
+ const onDrop = (e: DragEvent) => {
435
+ if (item.disabled) return;
436
+ e.preventDefault();
437
+ setIsDragOver(false);
438
+ handleDrop?.(item);
439
+ };
440
+
441
+ return (
442
+ <div
443
+ ref={ref}
444
+ className={cn(
445
+ "relative flex items-center",
446
+ treeVariants(),
447
+ className,
448
+ selectedItemId === item.id && selectedTreeVariants(),
449
+ isDragOver && dragOverVariants(),
450
+ item.disabled && "hover:bg-bg-primary pointer-events-none cursor-not-allowed opacity-50",
451
+ )}
452
+ onClick={() => {
453
+ if (item.disabled) return;
454
+ handleSelectChange(item);
455
+ item.onClick?.();
456
+ }}
457
+ onMouseEnter={(e) => onItemHover?.(e.currentTarget)}
458
+ onMouseLeave={() => onItemHover?.(null)}
459
+ draggable={!!item.draggable && !item.disabled}
460
+ onDragStart={onDragStart}
461
+ onDragOver={onDragOver}
462
+ onDragLeave={onDragLeave}
463
+ onDrop={onDrop}
464
+ {...props}
465
+ >
466
+ <TreeIcon item={item} isSelected={selectedItemId === item.id} default={defaultLeafIcon} />
467
+ <span className="text-text-primary text-uk-md flex-grow truncate text-left">
468
+ {item.name}
469
+ </span>
470
+ <TreeActions isSelected={selectedItemId === item.id && !item.disabled}>
471
+ {item.actions}
472
+ </TreeActions>
473
+ </div>
474
+ );
475
+ },
476
+ );
477
+ TreeLeaf.displayName = "TreeLeaf";
478
+
479
+ const AccordionTrigger = forwardRef<
480
+ ElementRef<typeof AccordionPrimitive.Trigger>,
481
+ ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
482
+ >(({ className, children, ...props }, ref) => (
483
+ <AccordionPrimitive.Header style={{ margin: 0 }}>
484
+ <AccordionPrimitive.Trigger
485
+ ref={ref}
486
+ className={cn(
487
+ "relative flex w-full flex-1 items-center justify-between text-left font-medium transition-all",
488
+ className,
489
+ )}
490
+ {...props}
491
+ >
492
+ {children}
493
+ </AccordionPrimitive.Trigger>
494
+ </AccordionPrimitive.Header>
495
+ ));
496
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
497
+
498
+ const AccordionContent = forwardRef<
499
+ ElementRef<typeof AccordionPrimitive.Content>,
500
+ ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
501
+ >(({ className, children, ...props }, ref) => (
502
+ <AccordionPrimitive.Content
503
+ ref={ref}
504
+ className={cn(
505
+ "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down text-uk-md overflow-hidden transition-all",
506
+ className,
507
+ )}
508
+ {...props}
509
+ >
510
+ <div className="pt-0 pb-0">{children}</div>
511
+ </AccordionPrimitive.Content>
512
+ ));
513
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName;
514
+
515
+ const TreeIcon = ({
516
+ item,
517
+ isOpen,
518
+ isSelected,
519
+ default: defaultIcon,
520
+ }: {
521
+ item: TreeDataItem;
522
+ isOpen?: boolean;
523
+ isSelected?: boolean;
524
+ default?: IconComponent;
525
+ }) => {
526
+ let Icon = defaultIcon;
527
+ if (isSelected && item.selectedIcon) {
528
+ Icon = item.selectedIcon;
529
+ } else if (isOpen && item.openIcon) {
530
+ Icon = item.openIcon;
531
+ } else if (item.icon) {
532
+ Icon = item.icon;
533
+ }
534
+
535
+ if (!Icon) {
536
+ Icon = item.children && item.children.length > 0 ? Folder : File;
537
+ }
538
+
539
+ return Icon ? <Icon className="text-text-primary mr-2 h-4 w-4 shrink-0" /> : <></>;
540
+ };
541
+
542
+ const TreeActions = ({ children, isSelected }: { children: ReactNode; isSelected: boolean }) => {
543
+ return (
544
+ <div className={cn(isSelected ? "block" : "hidden", "absolute right-3 group-hover:block")}>
545
+ {children}
546
+ </div>
547
+ );
548
+ };
549
+
550
+ export { TreeView, type TreeDataItem };
@@ -0,0 +1,65 @@
1
+ import React from "react";
2
+
3
+ import { Badge } from "./badge";
4
+
5
+ // Version info embedded at build time - safe for production
6
+ const PACKAGE_VERSION = "0.0.11";
7
+ const PACKAGE_NAME = "@vuer-ai/vuer-uikit";
8
+
9
+ interface VersionBadgeProps {
10
+ /**
11
+ * Additional CSS classes to apply to the badge
12
+ */
13
+ className?: string;
14
+ /**
15
+ * Whether to show just the version or include "v" prefix
16
+ */
17
+ showPrefix?: boolean;
18
+ /**
19
+ * Whether the badge should be clickable (links to npm)
20
+ */
21
+ linkable?: boolean;
22
+ /**
23
+ * Override the version display (useful for testing)
24
+ */
25
+ version?: string;
26
+ }
27
+
28
+ /**
29
+ * A badge component that displays the current package version and optionally links to npm
30
+ */
31
+ export function VersionBadge({
32
+ className,
33
+ showPrefix = true,
34
+ linkable = true,
35
+ version: overrideVersion,
36
+ }: VersionBadgeProps) {
37
+ const currentVersion = overrideVersion || PACKAGE_VERSION;
38
+ const displayVersion = showPrefix ? `v${currentVersion}` : currentVersion;
39
+ const npmUrl = `https://www.npmjs.com/package/${PACKAGE_NAME}/v/${currentVersion}`;
40
+
41
+ const badge = (
42
+ <Badge
43
+ variant="accent"
44
+ className={className}
45
+ style={linkable ? { cursor: "pointer" } : undefined}
46
+ >
47
+ {displayVersion}
48
+ </Badge>
49
+ );
50
+
51
+ if (linkable) {
52
+ return (
53
+ <a
54
+ href={npmUrl}
55
+ target="_blank"
56
+ rel="noopener noreferrer"
57
+ className="no-underline hover:no-underline"
58
+ >
59
+ {badge}
60
+ </a>
61
+ );
62
+ }
63
+
64
+ return badge;
65
+ }
@@ -0,0 +1,21 @@
1
+ import { type ClassValue, clsx } from "clsx";
2
+ import { extendTailwindMerge } from "tailwind-merge";
3
+
4
+ const twMerge = extendTailwindMerge({
5
+ override: {
6
+ classGroups: {
7
+ "font-size": [
8
+ "text-uk-xs",
9
+ "text-uk-sm",
10
+ "text-uk-md",
11
+ "text-uk-lg",
12
+ "text-uk-xl",
13
+ "text-uk-xxl",
14
+ ],
15
+ },
16
+ },
17
+ });
18
+
19
+ export function cn(...inputs: ClassValue[]) {
20
+ return twMerge(clsx(inputs));
21
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./cn";
2
+ export * from "./use-local-storage";
@@ -0,0 +1,59 @@
1
+ import { useCallback, useState } from "react";
2
+
3
+ export function useLocalStorage<T>(
4
+ key: string,
5
+ initialValue: T,
6
+ ): [T, (value: T | ((val: T) => T)) => void] {
7
+ const [storedValue, setStoredValue] = useState<T>(() => {
8
+ if (typeof window === "undefined") {
9
+ return initialValue;
10
+ }
11
+ try {
12
+ const item = window.localStorage.getItem(key);
13
+ if (item === null) return initialValue;
14
+
15
+ // Handle different data types
16
+ if (typeof initialValue === "string") {
17
+ return item as T;
18
+ } else if (typeof initialValue === "number") {
19
+ return (parseFloat(item) || initialValue) as T;
20
+ } else if (typeof initialValue === "boolean") {
21
+ return (item === "true") as T;
22
+ } else {
23
+ // For objects and arrays, parse JSON
24
+ return JSON.parse(item);
25
+ }
26
+ } catch (error) {
27
+ console.warn(`Error reading localStorage key "${key}":`, error);
28
+ return initialValue;
29
+ }
30
+ });
31
+
32
+ const setValue = useCallback(
33
+ (value: T | ((val: T) => T)) => {
34
+ try {
35
+ // Allow value to be a function for functional updates
36
+ const valueToStore = value instanceof Function ? value(storedValue) : value;
37
+ setStoredValue(valueToStore);
38
+
39
+ // Save to localStorage only on client
40
+ if (typeof window !== "undefined") {
41
+ let stringValue: string;
42
+ if (typeof valueToStore === "string") {
43
+ stringValue = valueToStore;
44
+ } else if (typeof valueToStore === "number" || typeof valueToStore === "boolean") {
45
+ stringValue = valueToStore.toString();
46
+ } else {
47
+ stringValue = JSON.stringify(valueToStore);
48
+ }
49
+ window.localStorage.setItem(key, stringValue);
50
+ }
51
+ } catch (error) {
52
+ console.warn(`Error setting localStorage key "${key}":`, error);
53
+ }
54
+ },
55
+ [key, storedValue],
56
+ );
57
+
58
+ return [storedValue, setValue];
59
+ }