@teamix-evo/ui 0.1.1

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 (270) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +336 -0
  3. package/_data.json +12 -0
  4. package/manifest.json +1688 -0
  5. package/package.json +90 -0
  6. package/src/components/accordion/accordion.meta.md +87 -0
  7. package/src/components/accordion/accordion.stories.tsx +67 -0
  8. package/src/components/accordion/accordion.tsx +58 -0
  9. package/src/components/affix/affix.meta.md +80 -0
  10. package/src/components/affix/affix.stories.tsx +57 -0
  11. package/src/components/affix/affix.tsx +97 -0
  12. package/src/components/alert/alert.meta.md +101 -0
  13. package/src/components/alert/alert.stories.tsx +93 -0
  14. package/src/components/alert/alert.tsx +132 -0
  15. package/src/components/alert-dialog/alert-dialog.meta.md +107 -0
  16. package/src/components/alert-dialog/alert-dialog.stories.tsx +81 -0
  17. package/src/components/alert-dialog/alert-dialog.tsx +136 -0
  18. package/src/components/anchor/anchor.meta.md +87 -0
  19. package/src/components/anchor/anchor.stories.tsx +74 -0
  20. package/src/components/anchor/anchor.tsx +130 -0
  21. package/src/components/app/app.meta.md +86 -0
  22. package/src/components/app/app.stories.tsx +62 -0
  23. package/src/components/app/app.tsx +58 -0
  24. package/src/components/aspect-ratio/aspect-ratio.meta.md +81 -0
  25. package/src/components/aspect-ratio/aspect-ratio.stories.tsx +59 -0
  26. package/src/components/aspect-ratio/aspect-ratio.tsx +22 -0
  27. package/src/components/auto-complete/auto-complete.meta.md +102 -0
  28. package/src/components/auto-complete/auto-complete.stories.tsx +93 -0
  29. package/src/components/auto-complete/auto-complete.tsx +205 -0
  30. package/src/components/avatar/avatar.meta.md +94 -0
  31. package/src/components/avatar/avatar.stories.tsx +80 -0
  32. package/src/components/avatar/avatar.tsx +126 -0
  33. package/src/components/badge/badge.meta.md +119 -0
  34. package/src/components/badge/badge.stories.tsx +153 -0
  35. package/src/components/badge/badge.tsx +210 -0
  36. package/src/components/breadcrumb/breadcrumb.meta.md +107 -0
  37. package/src/components/breadcrumb/breadcrumb.stories.tsx +84 -0
  38. package/src/components/breadcrumb/breadcrumb.tsx +122 -0
  39. package/src/components/button/button.meta.md +98 -0
  40. package/src/components/button/button.stories.tsx +235 -0
  41. package/src/components/button/button.tsx +160 -0
  42. package/src/components/button-group/button-group.meta.md +92 -0
  43. package/src/components/button-group/button-group.stories.tsx +90 -0
  44. package/src/components/button-group/button-group.tsx +75 -0
  45. package/src/components/calendar/calendar.meta.md +118 -0
  46. package/src/components/calendar/calendar.stories.tsx +68 -0
  47. package/src/components/calendar/calendar.tsx +107 -0
  48. package/src/components/card/card.meta.md +117 -0
  49. package/src/components/card/card.stories.tsx +112 -0
  50. package/src/components/card/card.tsx +222 -0
  51. package/src/components/carousel/carousel.meta.md +117 -0
  52. package/src/components/carousel/carousel.stories.tsx +84 -0
  53. package/src/components/carousel/carousel.tsx +224 -0
  54. package/src/components/cascader/cascader.meta.md +110 -0
  55. package/src/components/cascader/cascader.stories.tsx +108 -0
  56. package/src/components/cascader/cascader.tsx +198 -0
  57. package/src/components/checkbox/checkbox.meta.md +99 -0
  58. package/src/components/checkbox/checkbox.stories.tsx +130 -0
  59. package/src/components/checkbox/checkbox.tsx +125 -0
  60. package/src/components/collapsible/collapsible.meta.md +80 -0
  61. package/src/components/collapsible/collapsible.stories.tsx +35 -0
  62. package/src/components/collapsible/collapsible.tsx +18 -0
  63. package/src/components/color-picker/color-picker.meta.md +84 -0
  64. package/src/components/color-picker/color-picker.stories.tsx +80 -0
  65. package/src/components/color-picker/color-picker.tsx +160 -0
  66. package/src/components/combobox/combobox.meta.md +93 -0
  67. package/src/components/combobox/combobox.stories.tsx +55 -0
  68. package/src/components/combobox/combobox.tsx +130 -0
  69. package/src/components/command/command.meta.md +104 -0
  70. package/src/components/command/command.stories.tsx +59 -0
  71. package/src/components/command/command.tsx +147 -0
  72. package/src/components/context-menu/context-menu.meta.md +90 -0
  73. package/src/components/context-menu/context-menu.stories.tsx +46 -0
  74. package/src/components/context-menu/context-menu.tsx +191 -0
  75. package/src/components/data-table/data-table.meta.md +149 -0
  76. package/src/components/data-table/data-table.stories.tsx +125 -0
  77. package/src/components/data-table/data-table.tsx +185 -0
  78. package/src/components/date-picker/date-picker.meta.md +106 -0
  79. package/src/components/date-picker/date-picker.stories.tsx +58 -0
  80. package/src/components/date-picker/date-picker.tsx +156 -0
  81. package/src/components/descriptions/descriptions.meta.md +78 -0
  82. package/src/components/descriptions/descriptions.stories.tsx +60 -0
  83. package/src/components/descriptions/descriptions.tsx +129 -0
  84. package/src/components/dialog/dialog.meta.md +105 -0
  85. package/src/components/dialog/dialog.stories.tsx +93 -0
  86. package/src/components/dialog/dialog.tsx +128 -0
  87. package/src/components/drawer/drawer.meta.md +96 -0
  88. package/src/components/drawer/drawer.stories.tsx +54 -0
  89. package/src/components/drawer/drawer.tsx +114 -0
  90. package/src/components/dropdown-menu/dropdown-menu.meta.md +103 -0
  91. package/src/components/dropdown-menu/dropdown-menu.stories.tsx +112 -0
  92. package/src/components/dropdown-menu/dropdown-menu.tsx +195 -0
  93. package/src/components/empty/empty.meta.md +81 -0
  94. package/src/components/empty/empty.stories.tsx +46 -0
  95. package/src/components/empty/empty.tsx +47 -0
  96. package/src/components/field/field.meta.md +116 -0
  97. package/src/components/field/field.stories.tsx +117 -0
  98. package/src/components/field/field.tsx +164 -0
  99. package/src/components/flex/flex.meta.md +94 -0
  100. package/src/components/flex/flex.stories.tsx +112 -0
  101. package/src/components/flex/flex.tsx +122 -0
  102. package/src/components/float-button/float-button.meta.md +87 -0
  103. package/src/components/float-button/float-button.stories.tsx +78 -0
  104. package/src/components/float-button/float-button.tsx +143 -0
  105. package/src/components/form/form.meta.md +131 -0
  106. package/src/components/form/form.stories.tsx +122 -0
  107. package/src/components/form/form.tsx +194 -0
  108. package/src/components/grid/grid.meta.md +87 -0
  109. package/src/components/grid/grid.stories.tsx +99 -0
  110. package/src/components/grid/grid.tsx +130 -0
  111. package/src/components/hover-card/hover-card.meta.md +92 -0
  112. package/src/components/hover-card/hover-card.stories.tsx +68 -0
  113. package/src/components/hover-card/hover-card.tsx +29 -0
  114. package/src/components/image/image.meta.md +94 -0
  115. package/src/components/image/image.stories.tsx +55 -0
  116. package/src/components/image/image.tsx +138 -0
  117. package/src/components/input/input.meta.md +109 -0
  118. package/src/components/input/input.stories.tsx +117 -0
  119. package/src/components/input/input.tsx +213 -0
  120. package/src/components/input-group/input-group.meta.md +92 -0
  121. package/src/components/input-group/input-group.stories.tsx +88 -0
  122. package/src/components/input-group/input-group.tsx +107 -0
  123. package/src/components/input-number/input-number.meta.md +91 -0
  124. package/src/components/input-number/input-number.stories.tsx +87 -0
  125. package/src/components/input-number/input-number.tsx +210 -0
  126. package/src/components/input-otp/input-otp.meta.md +105 -0
  127. package/src/components/input-otp/input-otp.stories.tsx +65 -0
  128. package/src/components/input-otp/input-otp.tsx +97 -0
  129. package/src/components/item/item.meta.md +116 -0
  130. package/src/components/item/item.stories.tsx +113 -0
  131. package/src/components/item/item.tsx +171 -0
  132. package/src/components/kbd/kbd.meta.md +85 -0
  133. package/src/components/kbd/kbd.stories.tsx +70 -0
  134. package/src/components/kbd/kbd.tsx +81 -0
  135. package/src/components/label/label.meta.md +91 -0
  136. package/src/components/label/label.stories.tsx +87 -0
  137. package/src/components/label/label.tsx +66 -0
  138. package/src/components/masonry/masonry.meta.md +85 -0
  139. package/src/components/masonry/masonry.stories.tsx +66 -0
  140. package/src/components/masonry/masonry.tsx +59 -0
  141. package/src/components/mentions/mentions.meta.md +89 -0
  142. package/src/components/mentions/mentions.stories.tsx +75 -0
  143. package/src/components/mentions/mentions.tsx +237 -0
  144. package/src/components/menubar/menubar.meta.md +100 -0
  145. package/src/components/menubar/menubar.stories.tsx +81 -0
  146. package/src/components/menubar/menubar.tsx +232 -0
  147. package/src/components/native-select/native-select.meta.md +88 -0
  148. package/src/components/native-select/native-select.stories.tsx +80 -0
  149. package/src/components/native-select/native-select.tsx +54 -0
  150. package/src/components/navigation-menu/navigation-menu.meta.md +108 -0
  151. package/src/components/navigation-menu/navigation-menu.stories.tsx +112 -0
  152. package/src/components/navigation-menu/navigation-menu.tsx +125 -0
  153. package/src/components/notification/notification.meta.md +91 -0
  154. package/src/components/notification/notification.stories.tsx +96 -0
  155. package/src/components/notification/notification.tsx +84 -0
  156. package/src/components/pagination/pagination.meta.md +127 -0
  157. package/src/components/pagination/pagination.stories.tsx +62 -0
  158. package/src/components/pagination/pagination.tsx +285 -0
  159. package/src/components/popconfirm/popconfirm.meta.md +109 -0
  160. package/src/components/popconfirm/popconfirm.stories.tsx +76 -0
  161. package/src/components/popconfirm/popconfirm.tsx +134 -0
  162. package/src/components/popover/popover.meta.md +97 -0
  163. package/src/components/popover/popover.stories.tsx +82 -0
  164. package/src/components/popover/popover.tsx +55 -0
  165. package/src/components/progress/progress.meta.md +86 -0
  166. package/src/components/progress/progress.stories.tsx +75 -0
  167. package/src/components/progress/progress.tsx +195 -0
  168. package/src/components/radio-group/radio-group.meta.md +103 -0
  169. package/src/components/radio-group/radio-group.stories.tsx +77 -0
  170. package/src/components/radio-group/radio-group.tsx +78 -0
  171. package/src/components/rate/rate.meta.md +87 -0
  172. package/src/components/rate/rate.stories.tsx +81 -0
  173. package/src/components/rate/rate.tsx +153 -0
  174. package/src/components/resizable/resizable.meta.md +92 -0
  175. package/src/components/resizable/resizable.stories.tsx +104 -0
  176. package/src/components/resizable/resizable.tsx +56 -0
  177. package/src/components/result/result.meta.md +90 -0
  178. package/src/components/result/result.stories.tsx +71 -0
  179. package/src/components/result/result.tsx +91 -0
  180. package/src/components/scroll-area/scroll-area.meta.md +84 -0
  181. package/src/components/scroll-area/scroll-area.stories.tsx +41 -0
  182. package/src/components/scroll-area/scroll-area.tsx +51 -0
  183. package/src/components/segmented/segmented.meta.md +103 -0
  184. package/src/components/segmented/segmented.stories.tsx +101 -0
  185. package/src/components/segmented/segmented.tsx +138 -0
  186. package/src/components/select/select.meta.md +110 -0
  187. package/src/components/select/select.stories.tsx +100 -0
  188. package/src/components/select/select.tsx +188 -0
  189. package/src/components/separator/separator.meta.md +74 -0
  190. package/src/components/separator/separator.stories.tsx +71 -0
  191. package/src/components/separator/separator.tsx +104 -0
  192. package/src/components/sheet/sheet.meta.md +97 -0
  193. package/src/components/sheet/sheet.stories.tsx +82 -0
  194. package/src/components/sheet/sheet.tsx +139 -0
  195. package/src/components/sidebar/sidebar.meta.md +131 -0
  196. package/src/components/sidebar/sidebar.stories.tsx +82 -0
  197. package/src/components/sidebar/sidebar.tsx +351 -0
  198. package/src/components/skeleton/skeleton.meta.md +95 -0
  199. package/src/components/skeleton/skeleton.stories.tsx +79 -0
  200. package/src/components/skeleton/skeleton.tsx +144 -0
  201. package/src/components/slider/slider.meta.md +94 -0
  202. package/src/components/slider/slider.stories.tsx +69 -0
  203. package/src/components/slider/slider.tsx +86 -0
  204. package/src/components/sonner/sonner.meta.md +96 -0
  205. package/src/components/sonner/sonner.stories.tsx +91 -0
  206. package/src/components/sonner/sonner.tsx +40 -0
  207. package/src/components/space/space.meta.md +94 -0
  208. package/src/components/space/space.stories.tsx +94 -0
  209. package/src/components/space/space.tsx +106 -0
  210. package/src/components/spinner/spinner.meta.md +76 -0
  211. package/src/components/spinner/spinner.stories.tsx +71 -0
  212. package/src/components/spinner/spinner.tsx +64 -0
  213. package/src/components/statistic/statistic.meta.md +99 -0
  214. package/src/components/statistic/statistic.stories.tsx +71 -0
  215. package/src/components/statistic/statistic.tsx +197 -0
  216. package/src/components/steps/steps.meta.md +102 -0
  217. package/src/components/steps/steps.stories.tsx +75 -0
  218. package/src/components/steps/steps.tsx +170 -0
  219. package/src/components/switch/switch.meta.md +92 -0
  220. package/src/components/switch/switch.stories.tsx +75 -0
  221. package/src/components/switch/switch.tsx +101 -0
  222. package/src/components/table/table.meta.md +95 -0
  223. package/src/components/table/table.stories.tsx +75 -0
  224. package/src/components/table/table.tsx +122 -0
  225. package/src/components/tabs/tabs.meta.md +98 -0
  226. package/src/components/tabs/tabs.stories.tsx +70 -0
  227. package/src/components/tabs/tabs.tsx +119 -0
  228. package/src/components/tag/tag.meta.md +94 -0
  229. package/src/components/tag/tag.stories.tsx +77 -0
  230. package/src/components/tag/tag.tsx +185 -0
  231. package/src/components/textarea/textarea.meta.md +83 -0
  232. package/src/components/textarea/textarea.stories.tsx +63 -0
  233. package/src/components/textarea/textarea.tsx +113 -0
  234. package/src/components/time-picker/time-picker.meta.md +83 -0
  235. package/src/components/time-picker/time-picker.stories.tsx +59 -0
  236. package/src/components/time-picker/time-picker.tsx +94 -0
  237. package/src/components/timeline/timeline.meta.md +102 -0
  238. package/src/components/timeline/timeline.stories.tsx +104 -0
  239. package/src/components/timeline/timeline.tsx +147 -0
  240. package/src/components/toggle/toggle.meta.md +88 -0
  241. package/src/components/toggle/toggle.stories.tsx +66 -0
  242. package/src/components/toggle/toggle.tsx +53 -0
  243. package/src/components/toggle-group/toggle-group.meta.md +90 -0
  244. package/src/components/toggle-group/toggle-group.stories.tsx +83 -0
  245. package/src/components/toggle-group/toggle-group.tsx +78 -0
  246. package/src/components/tooltip/tooltip.meta.md +99 -0
  247. package/src/components/tooltip/tooltip.stories.tsx +71 -0
  248. package/src/components/tooltip/tooltip.tsx +93 -0
  249. package/src/components/tour/tour.meta.md +116 -0
  250. package/src/components/tour/tour.stories.tsx +66 -0
  251. package/src/components/tour/tour.tsx +242 -0
  252. package/src/components/transfer/transfer.meta.md +90 -0
  253. package/src/components/transfer/transfer.stories.tsx +68 -0
  254. package/src/components/transfer/transfer.tsx +251 -0
  255. package/src/components/tree/tree.meta.md +111 -0
  256. package/src/components/tree/tree.stories.tsx +109 -0
  257. package/src/components/tree/tree.tsx +367 -0
  258. package/src/components/tree-select/tree-select.meta.md +100 -0
  259. package/src/components/tree-select/tree-select.stories.tsx +80 -0
  260. package/src/components/tree-select/tree-select.tsx +171 -0
  261. package/src/components/typography/typography.meta.md +102 -0
  262. package/src/components/typography/typography.stories.tsx +115 -0
  263. package/src/components/typography/typography.tsx +245 -0
  264. package/src/components/upload/upload.meta.md +111 -0
  265. package/src/components/upload/upload.stories.tsx +75 -0
  266. package/src/components/upload/upload.tsx +265 -0
  267. package/src/components/watermark/watermark.meta.md +95 -0
  268. package/src/components/watermark/watermark.stories.tsx +78 -0
  269. package/src/components/watermark/watermark.tsx +165 -0
  270. package/src/utils/cn.ts +6 -0
@@ -0,0 +1,147 @@
1
+ import * as React from 'react';
2
+ import { Command as CommandPrimitive } from 'cmdk';
3
+ import { Search } from 'lucide-react';
4
+
5
+ import { cn } from '@/utils/cn';
6
+ import { Dialog, DialogContent } from '@/components/dialog/dialog';
7
+
8
+ export interface CommandProps
9
+ extends React.ComponentPropsWithoutRef<typeof CommandPrimitive> {}
10
+
11
+ const Command = React.forwardRef<
12
+ React.ElementRef<typeof CommandPrimitive>,
13
+ CommandProps
14
+ >(({ className, ...props }, ref) => (
15
+ <CommandPrimitive
16
+ ref={ref}
17
+ className={cn(
18
+ 'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
19
+ className,
20
+ )}
21
+ {...props}
22
+ />
23
+ ));
24
+ Command.displayName = CommandPrimitive.displayName;
25
+
26
+ interface CommandDialogProps
27
+ extends React.ComponentPropsWithoutRef<typeof Dialog> {}
28
+
29
+ const CommandDialog = ({ children, ...props }: CommandDialogProps) => (
30
+ <Dialog {...props}>
31
+ <DialogContent className="overflow-hidden p-0">
32
+ <Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:size-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:size-5">
33
+ {children}
34
+ </Command>
35
+ </DialogContent>
36
+ </Dialog>
37
+ );
38
+
39
+ const CommandInput = React.forwardRef<
40
+ React.ElementRef<typeof CommandPrimitive.Input>,
41
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
42
+ >(({ className, ...props }, ref) => (
43
+ <div className="flex items-center border-b px-3" cmdk-input-wrapper="">
44
+ <Search className="mr-2 size-4 shrink-0 opacity-50" />
45
+ <CommandPrimitive.Input
46
+ ref={ref}
47
+ className={cn(
48
+ 'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
49
+ className,
50
+ )}
51
+ {...props}
52
+ />
53
+ </div>
54
+ ));
55
+ CommandInput.displayName = CommandPrimitive.Input.displayName;
56
+
57
+ const CommandList = React.forwardRef<
58
+ React.ElementRef<typeof CommandPrimitive.List>,
59
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
60
+ >(({ className, ...props }, ref) => (
61
+ <CommandPrimitive.List
62
+ ref={ref}
63
+ className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
64
+ {...props}
65
+ />
66
+ ));
67
+ CommandList.displayName = CommandPrimitive.List.displayName;
68
+
69
+ const CommandEmpty = React.forwardRef<
70
+ React.ElementRef<typeof CommandPrimitive.Empty>,
71
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
72
+ >((props, ref) => (
73
+ <CommandPrimitive.Empty
74
+ ref={ref}
75
+ className="py-6 text-center text-sm text-muted-foreground"
76
+ {...props}
77
+ />
78
+ ));
79
+ CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
80
+
81
+ const CommandGroup = React.forwardRef<
82
+ React.ElementRef<typeof CommandPrimitive.Group>,
83
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
84
+ >(({ className, ...props }, ref) => (
85
+ <CommandPrimitive.Group
86
+ ref={ref}
87
+ className={cn(
88
+ 'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
89
+ className,
90
+ )}
91
+ {...props}
92
+ />
93
+ ));
94
+ CommandGroup.displayName = CommandPrimitive.Group.displayName;
95
+
96
+ const CommandSeparator = React.forwardRef<
97
+ React.ElementRef<typeof CommandPrimitive.Separator>,
98
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
99
+ >(({ className, ...props }, ref) => (
100
+ <CommandPrimitive.Separator
101
+ ref={ref}
102
+ className={cn('-mx-1 h-px bg-border', className)}
103
+ {...props}
104
+ />
105
+ ));
106
+ CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
107
+
108
+ const CommandItem = React.forwardRef<
109
+ React.ElementRef<typeof CommandPrimitive.Item>,
110
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
111
+ >(({ className, ...props }, ref) => (
112
+ <CommandPrimitive.Item
113
+ ref={ref}
114
+ className={cn(
115
+ "relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
116
+ className,
117
+ )}
118
+ {...props}
119
+ />
120
+ ));
121
+ CommandItem.displayName = CommandPrimitive.Item.displayName;
122
+
123
+ const CommandShortcut = ({
124
+ className,
125
+ ...props
126
+ }: React.HTMLAttributes<HTMLSpanElement>) => (
127
+ <span
128
+ className={cn(
129
+ 'ml-auto text-xs tracking-widest text-muted-foreground',
130
+ className,
131
+ )}
132
+ {...props}
133
+ />
134
+ );
135
+ CommandShortcut.displayName = 'CommandShortcut';
136
+
137
+ export {
138
+ Command,
139
+ CommandDialog,
140
+ CommandInput,
141
+ CommandList,
142
+ CommandEmpty,
143
+ CommandGroup,
144
+ CommandItem,
145
+ CommandShortcut,
146
+ CommandSeparator,
147
+ };
@@ -0,0 +1,90 @@
1
+ ---
2
+ id: context-menu
3
+ name: ContextMenu
4
+ type: component
5
+ category: navigation
6
+ since: 0.1.0
7
+ package: "@teamix-evo/ui"
8
+ ---
9
+
10
+ # ContextMenu
11
+
12
+ 右键菜单 — Radix ContextMenu 完整实现。**与 DropdownMenu 形态一致**(Item / CheckboxItem / RadioItem / Sub / Label / Separator / Shortcut),仅触发方式不同(右键 vs click)。
13
+ shadcn 显式版,antd 用 Dropdown 模拟同样可达。
14
+
15
+ ## When to use
16
+
17
+ - 文件 / 资源列表的右键操作(重命名 / 复制路径 / 删除)
18
+ - 编辑器内的右键(剪切 / 复制 / 粘贴)
19
+ - 富内容区的二级操作(替代行内按钮)
20
+
21
+ ## When NOT to use
22
+
23
+ - 主操作 → 行内 Button
24
+ - 移动端首要场景 → 触屏不易触发右键,改 `DropdownMenu` + 长按
25
+ - 选择类下拉 → `Select`
26
+
27
+ ## Props
28
+
29
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。下表是 `ContextMenuContent` 的 props。
30
+
31
+ <!-- auto:props:begin -->
32
+ _(组件无 `<Name>Props` interface — props 详见 [`context-menu.tsx`](./context-menu.tsx))_
33
+ <!-- auto:props:end -->
34
+
35
+ ## 依赖
36
+
37
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`manifest.json`](../../../manifest.json)。**手工编辑 marker 之间的内容会在下次生成时被覆盖**。
38
+
39
+ <!-- auto:deps:begin -->
40
+ ### 同库依赖
41
+
42
+ > `teamix-evo ui add context-menu` 时,以下 entry 会被自动连带安装(无需手动 add)。
43
+
44
+ | Entry | 类型 | 描述 |
45
+ | --- | --- | --- |
46
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
47
+
48
+ ### npm 依赖
49
+
50
+ > 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
51
+
52
+ ```bash
53
+ pnpm add @radix-ui/react-context-menu@^2.2.0 lucide-react@^0.460.0
54
+ ```
55
+ <!-- auto:deps:end -->
56
+
57
+ > 子组件与 DropdownMenu 完全一致(只差名称前缀):`ContextMenu / Trigger / Content / Item / CheckboxItem / RadioItem / Label / Separator / Shortcut / Sub / SubTrigger / SubContent / Group / RadioGroup / Portal`。
58
+
59
+ ## AI 生成纪律
60
+
61
+ - **Trigger 必有可见区域**:不能是空区域,否则无右键目标 — 通常 wrap 一个文本块 / 图片 / 卡片
62
+ - **桌面专属**:移动端默认无右键;移动端要等价能力时改用 `DropdownMenu` 触发
63
+ - **危险动作配色**:`<ContextMenuItem className="text-destructive focus:text-destructive">删除</ContextMenuItem>`
64
+ - **不嵌套 ContextMenu**:嵌套右键反模式
65
+
66
+ ## Examples
67
+
68
+ ```tsx
69
+ import {
70
+ ContextMenu, ContextMenuTrigger, ContextMenuContent,
71
+ ContextMenuItem, ContextMenuSeparator, ContextMenuShortcut,
72
+ } from '@/components/ui/context-menu';
73
+
74
+ <ContextMenu>
75
+ <ContextMenuTrigger className="flex h-32 w-64 items-center justify-center rounded-md border border-dashed">
76
+ 右键这里
77
+ </ContextMenuTrigger>
78
+ <ContextMenuContent className="w-56">
79
+ <ContextMenuItem>
80
+ 复制 <ContextMenuShortcut>⌘C</ContextMenuShortcut>
81
+ </ContextMenuItem>
82
+ <ContextMenuItem>剪切</ContextMenuItem>
83
+ <ContextMenuItem>粘贴</ContextMenuItem>
84
+ <ContextMenuSeparator />
85
+ <ContextMenuItem className="text-destructive focus:text-destructive">
86
+ 删除 <ContextMenuShortcut>⌫</ContextMenuShortcut>
87
+ </ContextMenuItem>
88
+ </ContextMenuContent>
89
+ </ContextMenu>
90
+ ```
@@ -0,0 +1,46 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import {
3
+ ContextMenu,
4
+ ContextMenuTrigger,
5
+ ContextMenuContent,
6
+ ContextMenuItem,
7
+ ContextMenuSeparator,
8
+ ContextMenuShortcut,
9
+ } from './context-menu';
10
+
11
+ const meta: Meta<typeof ContextMenuContent> = {
12
+ title: '导航 · Navigation/ContextMenu',
13
+ component: ContextMenuContent,
14
+ tags: ['autodocs'],
15
+ };
16
+
17
+ export default meta;
18
+ type Story = StoryObj<typeof ContextMenuContent>;
19
+
20
+ export const Default: Story = {
21
+ render: () => (
22
+ <ContextMenu>
23
+ <ContextMenuTrigger className="flex h-32 w-72 items-center justify-center rounded-md border border-dashed text-sm text-muted-foreground">
24
+ 在此处右键(或长按)打开菜单
25
+ </ContextMenuTrigger>
26
+ <ContextMenuContent className="w-56">
27
+ <ContextMenuItem>
28
+ 复制 <ContextMenuShortcut>⌘C</ContextMenuShortcut>
29
+ </ContextMenuItem>
30
+ <ContextMenuItem>
31
+ 剪切 <ContextMenuShortcut>⌘X</ContextMenuShortcut>
32
+ </ContextMenuItem>
33
+ <ContextMenuItem>
34
+ 粘贴 <ContextMenuShortcut>⌘V</ContextMenuShortcut>
35
+ </ContextMenuItem>
36
+ <ContextMenuSeparator />
37
+ <ContextMenuItem>重命名</ContextMenuItem>
38
+ <ContextMenuItem>复制路径</ContextMenuItem>
39
+ <ContextMenuSeparator />
40
+ <ContextMenuItem className="text-destructive focus:text-destructive">
41
+ 删除 <ContextMenuShortcut>⌫</ContextMenuShortcut>
42
+ </ContextMenuItem>
43
+ </ContextMenuContent>
44
+ </ContextMenu>
45
+ ),
46
+ };
@@ -0,0 +1,191 @@
1
+ import * as React from 'react';
2
+ import * as ContextMenuPrimitive from '@radix-ui/react-context-menu';
3
+ import { Check, ChevronRight, Circle } from 'lucide-react';
4
+
5
+ import { cn } from '@/utils/cn';
6
+
7
+ const ContextMenu = ContextMenuPrimitive.Root;
8
+ const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
9
+ const ContextMenuGroup = ContextMenuPrimitive.Group;
10
+ const ContextMenuPortal = ContextMenuPrimitive.Portal;
11
+ const ContextMenuSub = ContextMenuPrimitive.Sub;
12
+ const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
13
+
14
+ const ContextMenuSubTrigger = React.forwardRef<
15
+ React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
16
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
17
+ inset?: boolean;
18
+ }
19
+ >(({ className, inset, children, ...props }, ref) => (
20
+ <ContextMenuPrimitive.SubTrigger
21
+ ref={ref}
22
+ className={cn(
23
+ 'flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
24
+ inset && 'pl-8',
25
+ className,
26
+ )}
27
+ {...props}
28
+ >
29
+ {children}
30
+ <ChevronRight className="ml-auto" />
31
+ </ContextMenuPrimitive.SubTrigger>
32
+ ));
33
+ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
34
+
35
+ const ContextMenuSubContent = React.forwardRef<
36
+ React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
37
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
38
+ >(({ className, ...props }, ref) => (
39
+ <ContextMenuPrimitive.SubContent
40
+ ref={ref}
41
+ className={cn(
42
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
43
+ className,
44
+ )}
45
+ {...props}
46
+ />
47
+ ));
48
+ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
49
+
50
+ const ContextMenuContent = React.forwardRef<
51
+ React.ElementRef<typeof ContextMenuPrimitive.Content>,
52
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
53
+ >(({ className, ...props }, ref) => (
54
+ <ContextMenuPrimitive.Portal>
55
+ <ContextMenuPrimitive.Content
56
+ ref={ref}
57
+ className={cn(
58
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
59
+ className,
60
+ )}
61
+ {...props}
62
+ />
63
+ </ContextMenuPrimitive.Portal>
64
+ ));
65
+ ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
66
+
67
+ const ContextMenuItem = React.forwardRef<
68
+ React.ElementRef<typeof ContextMenuPrimitive.Item>,
69
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
70
+ inset?: boolean;
71
+ }
72
+ >(({ className, inset, ...props }, ref) => (
73
+ <ContextMenuPrimitive.Item
74
+ ref={ref}
75
+ className={cn(
76
+ 'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
77
+ inset && 'pl-8',
78
+ className,
79
+ )}
80
+ {...props}
81
+ />
82
+ ));
83
+ ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
84
+
85
+ const ContextMenuCheckboxItem = React.forwardRef<
86
+ React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
87
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
88
+ >(({ className, children, checked, ...props }, ref) => (
89
+ <ContextMenuPrimitive.CheckboxItem
90
+ ref={ref}
91
+ className={cn(
92
+ 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
93
+ className,
94
+ )}
95
+ checked={checked}
96
+ {...props}
97
+ >
98
+ <span className="absolute left-2 flex size-3.5 items-center justify-center">
99
+ <ContextMenuPrimitive.ItemIndicator>
100
+ <Check className="size-4" />
101
+ </ContextMenuPrimitive.ItemIndicator>
102
+ </span>
103
+ {children}
104
+ </ContextMenuPrimitive.CheckboxItem>
105
+ ));
106
+ ContextMenuCheckboxItem.displayName =
107
+ ContextMenuPrimitive.CheckboxItem.displayName;
108
+
109
+ const ContextMenuRadioItem = React.forwardRef<
110
+ React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
111
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
112
+ >(({ className, children, ...props }, ref) => (
113
+ <ContextMenuPrimitive.RadioItem
114
+ ref={ref}
115
+ className={cn(
116
+ 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
117
+ className,
118
+ )}
119
+ {...props}
120
+ >
121
+ <span className="absolute left-2 flex size-3.5 items-center justify-center">
122
+ <ContextMenuPrimitive.ItemIndicator>
123
+ <Circle className="size-2 fill-current" />
124
+ </ContextMenuPrimitive.ItemIndicator>
125
+ </span>
126
+ {children}
127
+ </ContextMenuPrimitive.RadioItem>
128
+ ));
129
+ ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
130
+
131
+ const ContextMenuLabel = React.forwardRef<
132
+ React.ElementRef<typeof ContextMenuPrimitive.Label>,
133
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
134
+ inset?: boolean;
135
+ }
136
+ >(({ className, inset, ...props }, ref) => (
137
+ <ContextMenuPrimitive.Label
138
+ ref={ref}
139
+ className={cn(
140
+ 'px-2 py-1.5 text-sm font-semibold text-foreground',
141
+ inset && 'pl-8',
142
+ className,
143
+ )}
144
+ {...props}
145
+ />
146
+ ));
147
+ ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
148
+
149
+ const ContextMenuSeparator = React.forwardRef<
150
+ React.ElementRef<typeof ContextMenuPrimitive.Separator>,
151
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
152
+ >(({ className, ...props }, ref) => (
153
+ <ContextMenuPrimitive.Separator
154
+ ref={ref}
155
+ className={cn('-mx-1 my-1 h-px bg-border', className)}
156
+ {...props}
157
+ />
158
+ ));
159
+ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
160
+
161
+ const ContextMenuShortcut = ({
162
+ className,
163
+ ...props
164
+ }: React.HTMLAttributes<HTMLSpanElement>) => (
165
+ <span
166
+ className={cn(
167
+ 'ml-auto text-xs tracking-widest text-muted-foreground',
168
+ className,
169
+ )}
170
+ {...props}
171
+ />
172
+ );
173
+ ContextMenuShortcut.displayName = 'ContextMenuShortcut';
174
+
175
+ export {
176
+ ContextMenu,
177
+ ContextMenuTrigger,
178
+ ContextMenuContent,
179
+ ContextMenuItem,
180
+ ContextMenuCheckboxItem,
181
+ ContextMenuRadioItem,
182
+ ContextMenuLabel,
183
+ ContextMenuSeparator,
184
+ ContextMenuShortcut,
185
+ ContextMenuGroup,
186
+ ContextMenuPortal,
187
+ ContextMenuSub,
188
+ ContextMenuSubContent,
189
+ ContextMenuSubTrigger,
190
+ ContextMenuRadioGroup,
191
+ };
@@ -0,0 +1,149 @@
1
+ ---
2
+ id: data-table
3
+ name: DataTable
4
+ type: component
5
+ category: data-display
6
+ since: 0.1.0
7
+ package: "@teamix-evo/ui"
8
+ ---
9
+
10
+ # DataTable
11
+
12
+ 数据表 — 基于 [`@tanstack/react-table`](https://tanstack.com/table) + 基础 `Table` primitives + `SimplePagination`。
13
+ **等价 antd `Table` 的核心交互合集**:`sorter` + `filter` + `pagination` + `rowSelection`,声明式 `columns + data` 即可。
14
+
15
+ ## When to use
16
+
17
+ - 需要排序 / 筛选 / 分页 / 多选的列表(用户管理 / 订单 / 资源)
18
+ - 大数据量(配 TanStack 的 virtualizer 可接百万行,本组件目前未集成)
19
+ - 需要复杂列(多列分组、可拖拽列宽、嵌套行)— 用户可在 columns 里自由扩展
20
+
21
+ ## When NOT to use
22
+
23
+ - 简单静态展示 → 基础 `Table`
24
+ - 键值对详情 → `Descriptions`(v0.x)
25
+ - 树结构 → `Tree`(v0.x)
26
+
27
+ ## Props
28
+
29
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。
30
+
31
+ <!-- auto:props:begin -->
32
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
33
+ | --- | --- | --- | --- | --- |
34
+ | `columns` | `ColumnDef<TData, TValue>[]` | – | ✓ | 列定义(TanStack ColumnDef)。 |
35
+ | `data` | `TData[]` | – | ✓ | 行数据。 |
36
+ | `pagination` | `boolean \| { pageSize?: number; siblingCount?: number }` | `true` | – | 是否启用分页(antd `pagination` 并集)。 传 `true` 用默认配置;传对象自定义 pageSize / siblingCount。 |
37
+ | `sorting` | `boolean` | `true` | – | 是否启用排序(列定义里的 `enableSorting` 也要打开;默认列已开)。 |
38
+ | `filtering` | `boolean` | `true` | – | 是否启用列过滤(每列 `header` 配 input 单独使用;此 flag 控制 columnFilters 状态)。 |
39
+ | `onRowSelectionChange` | `(selectedRows: TData[]) => void` | – | – | 行选择回调(antd `rowSelection.onChange` 并集)。传入即启用 selection。 Selected rows 的原始 data 通过 `getRowId(row)` 推断,默认是 row.index。 |
40
+ | `emptyText` | `React.ReactNode` | – | – | 空数据时显示的内容。 |
41
+ | `className` | `string` | – | – | 容器 className。 |
42
+ <!-- auto:props:end -->
43
+
44
+ ## 依赖
45
+
46
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`manifest.json`](../../../manifest.json)。**手工编辑 marker 之间的内容会在下次生成时被覆盖**。
47
+
48
+ <!-- auto:deps:begin -->
49
+ ### 同库依赖
50
+
51
+ > `teamix-evo ui add data-table` 时,以下 entry 会被自动连带安装(无需手动 add)。
52
+
53
+ | Entry | 类型 | 描述 |
54
+ | --- | --- | --- |
55
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
56
+ | `table` | component | 基础表格 — 原生 HTML 元素薄包装(视觉骨架,无交互,交互见 DataTable) |
57
+ | `pagination` | component | 分页 — shadcn primitives + 高阶 SimplePagination(antd 风格 total/pageSize/current/onChange,自动页码窗口 + 折叠) |
58
+
59
+ ### npm 依赖
60
+
61
+ > 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
62
+
63
+ ```bash
64
+ pnpm add @tanstack/react-table@^8.0.0
65
+ ```
66
+ <!-- auto:deps:end -->
67
+
68
+ > 透传 TanStack Table 的核心能力。需要更精细控制(可控 state、virtualizer、column visibility / resizing 等),请直接用 `useReactTable` + 基础 `Table` primitives 自行拼装。
69
+
70
+ ## AI 生成纪律
71
+
72
+ - **`columns` 用 `ColumnDef<TData>` 类型**:从本模块 re-export,业务侧 `import { type ColumnDef }`
73
+ - **`accessorKey` 必稳定**:用对象的字段名,不要 index
74
+ - **排序触发器**:`header: ({ column }) => <Button onClick={() => column.toggleSorting()}>...</Button>`
75
+ - **筛选**:在 column header 里渲染 Input 调 `column.setFilterValue`
76
+ - **rowSelection 用 `<Checkbox>`**:第一列加 `<Checkbox checked={row.getIsSelected()} onCheckedChange={(v) => row.toggleSelected(!!v)} />`
77
+ - **不要在每个 cell 内独立请求数据**:在父组件聚合后传 `data`
78
+ - **大数据量 → virtualizer**:本组件未集成,> 1000 行需自行加 `@tanstack/react-virtual`
79
+
80
+ ## Examples
81
+
82
+ ```tsx
83
+ import { DataTable, type ColumnDef } from '@/components/ui/data-table';
84
+ import { Button } from '@/components/ui/button';
85
+ import { Checkbox } from '@/components/ui/checkbox';
86
+ import { Badge } from '@/components/ui/badge';
87
+ import { ArrowUpDown } from 'lucide-react';
88
+
89
+ interface User {
90
+ id: string;
91
+ name: string;
92
+ email: string;
93
+ status: 'active' | 'invited';
94
+ }
95
+
96
+ const columns: ColumnDef<User>[] = [
97
+ {
98
+ id: 'select',
99
+ header: ({ table }) => (
100
+ <Checkbox
101
+ checked={
102
+ table.getIsAllPageRowsSelected()
103
+ ? true
104
+ : table.getIsSomePageRowsSelected()
105
+ ? 'indeterminate'
106
+ : false
107
+ }
108
+ onCheckedChange={(v) => table.toggleAllPageRowsSelected(!!v)}
109
+ />
110
+ ),
111
+ cell: ({ row }) => (
112
+ <Checkbox
113
+ checked={row.getIsSelected()}
114
+ onCheckedChange={(v) => row.toggleSelected(!!v)}
115
+ />
116
+ ),
117
+ },
118
+ { accessorKey: 'name', header: '姓名' },
119
+ {
120
+ accessorKey: 'email',
121
+ header: ({ column }) => (
122
+ <Button
123
+ variant="ghost"
124
+ size="sm"
125
+ onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
126
+ >
127
+ 邮箱 <ArrowUpDown className="ml-1" />
128
+ </Button>
129
+ ),
130
+ },
131
+ {
132
+ accessorKey: 'status',
133
+ header: '状态',
134
+ cell: ({ row }) =>
135
+ row.original.status === 'active' ? (
136
+ <Badge variant="success">活跃</Badge>
137
+ ) : (
138
+ <Badge>已邀请</Badge>
139
+ ),
140
+ },
141
+ ];
142
+
143
+ <DataTable
144
+ columns={columns}
145
+ data={users}
146
+ pagination={{ pageSize: 10 }}
147
+ onRowSelectionChange={(selected) => console.log(selected)}
148
+ />
149
+ ```