@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,100 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import {
3
+ Select,
4
+ SelectTrigger,
5
+ SelectValue,
6
+ SelectContent,
7
+ SelectGroup,
8
+ SelectLabel,
9
+ SelectItem,
10
+ SelectSeparator,
11
+ } from './select';
12
+
13
+ const meta: Meta<typeof SelectTrigger> = {
14
+ title: '表单与输入 · Form/Select',
15
+ component: SelectTrigger,
16
+ tags: ['autodocs'],
17
+ parameters: {
18
+ docs: {
19
+ description: {
20
+ component:
21
+ '下拉选择 — 从预置选项中选中一个值,由按钮触发弹出选项列表。Radix Select 实现 + antd Select 的并集能力:支持 `SelectGroup` / `SelectLabel` / `SelectSeparator` 组合出分组下拉,`size`(sm / default / lg)可调,默认带键盘导航与文本检索。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/design`,无 mock。',
22
+ },
23
+ },
24
+ },
25
+ argTypes: {
26
+ size: { control: 'inline-radio', options: ['sm', 'default', 'lg'] },
27
+ disabled: { control: 'boolean' },
28
+ },
29
+ args: { size: 'default' },
30
+ decorators: [
31
+ (Story) => (
32
+ <div className="w-64">
33
+ <Story />
34
+ </div>
35
+ ),
36
+ ],
37
+ };
38
+
39
+ export default meta;
40
+ type Story = StoryObj<typeof SelectTrigger>;
41
+
42
+ export const Playground: Story = {
43
+ render: (args) => (
44
+ <Select>
45
+ <SelectTrigger {...args}>
46
+ <SelectValue placeholder="选择城市" />
47
+ </SelectTrigger>
48
+ <SelectContent>
49
+ <SelectItem value="bj">北京</SelectItem>
50
+ <SelectItem value="sh">上海</SelectItem>
51
+ <SelectItem value="hz">杭州</SelectItem>
52
+ <SelectItem value="sz">深圳</SelectItem>
53
+ </SelectContent>
54
+ </Select>
55
+ ),
56
+ };
57
+
58
+ export const Grouped: Story = {
59
+ parameters: { controls: { disable: true } },
60
+ render: () => (
61
+ <Select>
62
+ <SelectTrigger>
63
+ <SelectValue placeholder="选择时区" />
64
+ </SelectTrigger>
65
+ <SelectContent>
66
+ <SelectGroup>
67
+ <SelectLabel>亚洲</SelectLabel>
68
+ <SelectItem value="cn">北京时间 (UTC+8)</SelectItem>
69
+ <SelectItem value="jp">东京时间 (UTC+9)</SelectItem>
70
+ <SelectItem value="sg">新加坡时间 (UTC+8)</SelectItem>
71
+ </SelectGroup>
72
+ <SelectSeparator />
73
+ <SelectGroup>
74
+ <SelectLabel>欧洲</SelectLabel>
75
+ <SelectItem value="uk">伦敦时间 (UTC+0)</SelectItem>
76
+ <SelectItem value="de">柏林时间 (UTC+1)</SelectItem>
77
+ </SelectGroup>
78
+ </SelectContent>
79
+ </Select>
80
+ ),
81
+ };
82
+
83
+ export const Sizes: Story = {
84
+ parameters: { controls: { disable: true } },
85
+ render: () => (
86
+ <div className="flex flex-col gap-3">
87
+ {(['sm', 'default', 'lg'] as const).map((s) => (
88
+ <Select key={s}>
89
+ <SelectTrigger size={s}>
90
+ <SelectValue placeholder={`size = ${s}`} />
91
+ </SelectTrigger>
92
+ <SelectContent>
93
+ <SelectItem value="a">选项 A</SelectItem>
94
+ <SelectItem value="b">选项 B</SelectItem>
95
+ </SelectContent>
96
+ </Select>
97
+ ))}
98
+ </div>
99
+ ),
100
+ };
@@ -0,0 +1,188 @@
1
+ import * as React from 'react';
2
+ import * as SelectPrimitive from '@radix-ui/react-select';
3
+ import { Check, ChevronDown, ChevronUp } from 'lucide-react';
4
+
5
+ import { cn } from '@/utils/cn';
6
+
7
+ const Select = SelectPrimitive.Root;
8
+ const SelectGroup = SelectPrimitive.Group;
9
+ const SelectValue = SelectPrimitive.Value;
10
+
11
+ export interface SelectTriggerProps
12
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> {
13
+ /**
14
+ * 触发器尺寸。
15
+ * @default "default"
16
+ */
17
+ size?: 'sm' | 'default' | 'lg';
18
+ }
19
+
20
+ const SelectTrigger = React.forwardRef<
21
+ React.ElementRef<typeof SelectPrimitive.Trigger>,
22
+ SelectTriggerProps
23
+ >(({ className, children, size = 'default', ...props }, ref) => {
24
+ const h =
25
+ size === 'sm'
26
+ ? 'h-8 px-2 text-xs'
27
+ : size === 'lg'
28
+ ? 'h-10 px-4'
29
+ : 'h-9 px-3 text-sm';
30
+ return (
31
+ <SelectPrimitive.Trigger
32
+ ref={ref}
33
+ className={cn(
34
+ 'flex w-full items-center justify-between rounded-md border border-input bg-background py-2 shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
35
+ h,
36
+ className,
37
+ )}
38
+ {...props}
39
+ >
40
+ {children}
41
+ <SelectPrimitive.Icon asChild>
42
+ <ChevronDown className="size-4 opacity-50" />
43
+ </SelectPrimitive.Icon>
44
+ </SelectPrimitive.Trigger>
45
+ );
46
+ });
47
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
48
+
49
+ const SelectScrollUpButton = React.forwardRef<
50
+ React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
51
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
52
+ >(({ className, ...props }, ref) => (
53
+ <SelectPrimitive.ScrollUpButton
54
+ ref={ref}
55
+ className={cn(
56
+ 'flex cursor-default items-center justify-center py-1',
57
+ className,
58
+ )}
59
+ {...props}
60
+ >
61
+ <ChevronUp className="size-4" />
62
+ </SelectPrimitive.ScrollUpButton>
63
+ ));
64
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
65
+
66
+ const SelectScrollDownButton = React.forwardRef<
67
+ React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
68
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
69
+ >(({ className, ...props }, ref) => (
70
+ <SelectPrimitive.ScrollDownButton
71
+ ref={ref}
72
+ className={cn(
73
+ 'flex cursor-default items-center justify-center py-1',
74
+ className,
75
+ )}
76
+ {...props}
77
+ >
78
+ <ChevronDown className="size-4" />
79
+ </SelectPrimitive.ScrollDownButton>
80
+ ));
81
+ SelectScrollDownButton.displayName =
82
+ SelectPrimitive.ScrollDownButton.displayName;
83
+
84
+ export interface SelectContentProps
85
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> {
86
+ /**
87
+ * 浮层定位策略。`popper` 跟随 trigger 并自动避让边界;`item-aligned` 把当前选中项与
88
+ * trigger 对齐(类似原生 `<select>`)。默认 `popper` 与 antd Select 行为一致。
89
+ * @default "popper"
90
+ */
91
+ position?: React.ComponentPropsWithoutRef<
92
+ typeof SelectPrimitive.Content
93
+ >['position'];
94
+ }
95
+
96
+ const SelectContent = React.forwardRef<
97
+ React.ElementRef<typeof SelectPrimitive.Content>,
98
+ SelectContentProps
99
+ >(({ className, children, position = 'popper', ...props }, ref) => (
100
+ <SelectPrimitive.Portal>
101
+ <SelectPrimitive.Content
102
+ ref={ref}
103
+ className={cn(
104
+ 'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
105
+ position === 'popper' &&
106
+ 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
107
+ className,
108
+ )}
109
+ position={position}
110
+ {...props}
111
+ >
112
+ <SelectScrollUpButton />
113
+ <SelectPrimitive.Viewport
114
+ className={cn(
115
+ 'p-1',
116
+ position === 'popper' &&
117
+ 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
118
+ )}
119
+ >
120
+ {children}
121
+ </SelectPrimitive.Viewport>
122
+ <SelectScrollDownButton />
123
+ </SelectPrimitive.Content>
124
+ </SelectPrimitive.Portal>
125
+ ));
126
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
127
+
128
+ const SelectLabel = React.forwardRef<
129
+ React.ElementRef<typeof SelectPrimitive.Label>,
130
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
131
+ >(({ className, ...props }, ref) => (
132
+ <SelectPrimitive.Label
133
+ ref={ref}
134
+ className={cn(
135
+ 'px-2 py-1.5 text-xs font-semibold text-muted-foreground',
136
+ className,
137
+ )}
138
+ {...props}
139
+ />
140
+ ));
141
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
142
+
143
+ const SelectItem = React.forwardRef<
144
+ React.ElementRef<typeof SelectPrimitive.Item>,
145
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
146
+ >(({ className, children, ...props }, ref) => (
147
+ <SelectPrimitive.Item
148
+ ref={ref}
149
+ className={cn(
150
+ 'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
151
+ className,
152
+ )}
153
+ {...props}
154
+ >
155
+ <span className="absolute right-2 flex size-3.5 items-center justify-center">
156
+ <SelectPrimitive.ItemIndicator>
157
+ <Check className="size-4" />
158
+ </SelectPrimitive.ItemIndicator>
159
+ </span>
160
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
161
+ </SelectPrimitive.Item>
162
+ ));
163
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
164
+
165
+ const SelectSeparator = React.forwardRef<
166
+ React.ElementRef<typeof SelectPrimitive.Separator>,
167
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
168
+ >(({ className, ...props }, ref) => (
169
+ <SelectPrimitive.Separator
170
+ ref={ref}
171
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
172
+ {...props}
173
+ />
174
+ ));
175
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
176
+
177
+ export {
178
+ Select,
179
+ SelectGroup,
180
+ SelectValue,
181
+ SelectTrigger,
182
+ SelectContent,
183
+ SelectLabel,
184
+ SelectItem,
185
+ SelectSeparator,
186
+ SelectScrollUpButton,
187
+ SelectScrollDownButton,
188
+ };
@@ -0,0 +1,74 @@
1
+ ---
2
+ id: separator
3
+ name: Separator
4
+ type: component
5
+ category: foundation
6
+ since: 0.1.0
7
+ package: "@teamix-evo/ui"
8
+ ---
9
+
10
+ # Separator
11
+
12
+ 分隔线 — Radix Separator(语义层)+ antd Divider 的 `dashed` 与中间装饰文本(`children`)。
13
+
14
+ ## When to use
15
+
16
+ - 横向 / 纵向分隔语义不同的内容块
17
+ - 列表项之间、Card 内的子区域分隔
18
+ - 需要文字装饰的"区段标题分隔"(用 `children`)
19
+
20
+ ## When NOT to use
21
+
22
+ - 仅作视觉留白 → 用 `margin / padding`
23
+ - 强调分组语义且需要交互 → 用 `Accordion` / `Tabs`
24
+
25
+ ## Props
26
+
27
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。
28
+
29
+ <!-- auto:props:begin -->
30
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
31
+ | --- | --- | --- | --- | --- |
32
+ | `orientation` | `'horizontal' \| 'vertical'` | `"horizontal"` | – | 分隔方向。 |
33
+ | `decorative` | `boolean` | `true` | – | `true` 时不参与无障碍树(语义上仅装饰性)。 |
34
+ | `dashed` | `boolean` | `false` | – | 虚线样式(antd Divider 并集)。 |
35
+ | `children` | `React.ReactNode` | – | – | 中间装饰文本(antd Divider 并集)。提供时改用"两端线段 + 中间文本"布局, Radix Separator 不再使用,但通过 `role="separator"` 保留无障碍语义。 |
36
+ <!-- auto:props:end -->
37
+
38
+ ## 依赖
39
+
40
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`manifest.json`](../../../manifest.json)。**手工编辑 marker 之间的内容会在下次生成时被覆盖**。
41
+
42
+ <!-- auto:deps:begin -->
43
+ ### 同库依赖
44
+
45
+ > `teamix-evo ui add separator` 时,以下 entry 会被自动连带安装(无需手动 add)。
46
+
47
+ | Entry | 类型 | 描述 |
48
+ | --- | --- | --- |
49
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
50
+
51
+ ### npm 依赖
52
+
53
+ > 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
54
+
55
+ ```bash
56
+ pnpm add @radix-ui/react-separator@^1.1.0
57
+ ```
58
+ <!-- auto:deps:end -->
59
+
60
+ ## AI 生成纪律
61
+
62
+ - **`orientation="vertical"` 父容器要有高度**:Radix Vertical Separator 不撑开父容器,需父级 `h-*` 显式高度
63
+ - **`children` 模式仅 horizontal**:vertical 配合 `children` 会被忽略(语义不通)
64
+ - **`decorative={false}` 时必须配合语义边界**:用于真正的内容分隔(如目录标题之间),不要在装饰场景滥用
65
+
66
+ ## Examples
67
+
68
+ ```tsx
69
+ <Separator />
70
+ <Separator orientation="vertical" className="h-4" />
71
+ <Separator dashed />
72
+ <Separator>OR</Separator>
73
+ <Separator dashed>更多内容</Separator>
74
+ ```
@@ -0,0 +1,71 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Separator } from './separator';
3
+
4
+ const meta: Meta<typeof Separator> = {
5
+ title: '基础原语 · Foundation/Separator',
6
+ component: Separator,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component:
12
+ '分隔线 — 在视觉上或语义上区隔内容。Radix Separator 实现 + antd Divider 的并集能力:支持水平 / 垂直两种 `orientation`,可传 `dashed` 虚线样式,中间可嵌入 `children` 为文字分隔(antd `Divider` 中部文字能力)。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/design`,无 mock。',
13
+ },
14
+ },
15
+ },
16
+ argTypes: {
17
+ orientation: {
18
+ control: 'inline-radio',
19
+ options: ['horizontal', 'vertical'],
20
+ },
21
+ decorative: { control: 'boolean' },
22
+ dashed: { control: 'boolean' },
23
+ children: { control: 'text' },
24
+ },
25
+ args: { orientation: 'horizontal', decorative: true, dashed: false },
26
+ };
27
+
28
+ export default meta;
29
+ type Story = StoryObj<typeof Separator>;
30
+
31
+ export const Playground: Story = {
32
+ render: (args) => (
33
+ <div className="w-72">
34
+ <p className="text-sm">区域 A</p>
35
+ <Separator {...args} className="my-3" />
36
+ <p className="text-sm">区域 B</p>
37
+ </div>
38
+ ),
39
+ };
40
+
41
+ export const Vertical: Story = {
42
+ parameters: { controls: { disable: true } },
43
+ render: () => (
44
+ <div className="flex h-6 items-center gap-3 text-sm">
45
+ <span>Docs</span>
46
+ <Separator orientation="vertical" />
47
+ <span>Source</span>
48
+ <Separator orientation="vertical" />
49
+ <span>API</span>
50
+ </div>
51
+ ),
52
+ };
53
+
54
+ export const Dashed: Story = {
55
+ parameters: { controls: { disable: true } },
56
+ render: () => (
57
+ <div className="w-72">
58
+ <Separator dashed />
59
+ </div>
60
+ ),
61
+ };
62
+
63
+ export const WithText: Story = {
64
+ parameters: { controls: { disable: true } },
65
+ render: () => (
66
+ <div className="flex w-72 flex-col gap-3">
67
+ <Separator>OR</Separator>
68
+ <Separator dashed>更多设置</Separator>
69
+ </div>
70
+ ),
71
+ };
@@ -0,0 +1,104 @@
1
+ import * as React from 'react';
2
+ import * as SeparatorPrimitive from '@radix-ui/react-separator';
3
+
4
+ import { cn } from '@/utils/cn';
5
+
6
+ export interface SeparatorProps
7
+ extends Omit<
8
+ React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>,
9
+ 'children'
10
+ > {
11
+ /**
12
+ * 分隔方向。
13
+ * @default "horizontal"
14
+ */
15
+ orientation?: 'horizontal' | 'vertical';
16
+ /**
17
+ * `true` 时不参与无障碍树(语义上仅装饰性)。
18
+ * @default true
19
+ */
20
+ decorative?: boolean;
21
+ /**
22
+ * 虚线样式(antd Divider 并集)。
23
+ * @default false
24
+ */
25
+ dashed?: boolean;
26
+ /**
27
+ * 中间装饰文本(antd Divider 并集)。提供时改用"两端线段 + 中间文本"布局,
28
+ * Radix Separator 不再使用,但通过 `role="separator"` 保留无障碍语义。
29
+ */
30
+ children?: React.ReactNode;
31
+ }
32
+
33
+ const Separator = React.forwardRef<
34
+ React.ElementRef<typeof SeparatorPrimitive.Root>,
35
+ SeparatorProps
36
+ >(
37
+ (
38
+ {
39
+ className,
40
+ orientation = 'horizontal',
41
+ decorative = true,
42
+ dashed = false,
43
+ children,
44
+ ...props
45
+ },
46
+ ref,
47
+ ) => {
48
+ // Children mode (antd Divider with text): only meaningful for horizontal.
49
+ if (children && orientation === 'horizontal') {
50
+ return (
51
+ <div
52
+ ref={ref as React.Ref<HTMLDivElement>}
53
+ role={decorative ? 'none' : 'separator'}
54
+ aria-orientation={decorative ? undefined : 'horizontal'}
55
+ className={cn(
56
+ 'flex w-full items-center gap-3 text-sm text-muted-foreground',
57
+ className,
58
+ )}
59
+ {...(props as React.HTMLAttributes<HTMLDivElement>)}
60
+ >
61
+ <span
62
+ className={cn(
63
+ 'h-px flex-1',
64
+ dashed
65
+ ? 'border-t border-dashed border-border'
66
+ : 'bg-border',
67
+ )}
68
+ />
69
+ <span className="shrink-0">{children}</span>
70
+ <span
71
+ className={cn(
72
+ 'h-px flex-1',
73
+ dashed
74
+ ? 'border-t border-dashed border-border'
75
+ : 'bg-border',
76
+ )}
77
+ />
78
+ </div>
79
+ );
80
+ }
81
+
82
+ // Plain mode: delegate to Radix.
83
+ return (
84
+ <SeparatorPrimitive.Root
85
+ ref={ref}
86
+ decorative={decorative}
87
+ orientation={orientation}
88
+ className={cn(
89
+ dashed
90
+ ? orientation === 'horizontal'
91
+ ? 'border-t border-dashed border-border bg-transparent'
92
+ : 'border-l border-dashed border-border bg-transparent'
93
+ : 'shrink-0 bg-border',
94
+ orientation === 'horizontal' ? 'h-px w-full' : 'h-full w-px',
95
+ className,
96
+ )}
97
+ {...props}
98
+ />
99
+ );
100
+ },
101
+ );
102
+ Separator.displayName = 'Separator';
103
+
104
+ export { Separator };
@@ -0,0 +1,97 @@
1
+ ---
2
+ id: sheet
3
+ name: Sheet
4
+ type: component
5
+ category: feedback
6
+ since: 0.1.0
7
+ package: "@teamix-evo/ui"
8
+ ---
9
+
10
+ # Sheet
11
+
12
+ 侧边滑出面板 — Radix Dialog 底座 + side 方向变体(left / right / top / bottom)+ antd Drawer `placement` 并集。
13
+ **与 Dialog 的关键差异**:Sheet 从屏幕边缘滑入,模态阻断同样;`Drawer` 是底部可拖拽抽屉(iOS 风格,移动端体验)。
14
+
15
+ ## When to use
16
+
17
+ - 设置面板 / 详情查看(从右侧滑入,主区域保留可见)
18
+ - 移动端导航(从左侧滑入)
19
+ - 编辑面板(主操作仍在画面内)
20
+
21
+ ## When NOT to use
22
+
23
+ - 短交互 → `Popover`
24
+ - 阻断式确认 → `AlertDialog`
25
+ - 移动端可拖拽 → `Drawer`
26
+ - 普通模态 → `Dialog`
27
+
28
+ ## Props
29
+
30
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。下表是 `SheetContent` 的 props;`Sheet`(Root)透传 Radix `open / defaultOpen / onOpenChange / modal`。
31
+
32
+ <!-- auto:props:begin -->
33
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
34
+ | --- | --- | --- | --- | --- |
35
+ | `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `"right"` | – | 弹出方向(antd Drawer `placement` 并集)。 |
36
+ <!-- auto:props:end -->
37
+
38
+ ## 依赖
39
+
40
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`manifest.json`](../../../manifest.json)。**手工编辑 marker 之间的内容会在下次生成时被覆盖**。
41
+
42
+ <!-- auto:deps:begin -->
43
+ ### 同库依赖
44
+
45
+ > `teamix-evo ui add sheet` 时,以下 entry 会被自动连带安装(无需手动 add)。
46
+
47
+ | Entry | 类型 | 描述 |
48
+ | --- | --- | --- |
49
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
50
+
51
+ ### npm 依赖
52
+
53
+ > 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
54
+
55
+ ```bash
56
+ pnpm add @radix-ui/react-dialog@^1.1.0 class-variance-authority@^0.7.0 lucide-react@^0.460.0
57
+ ```
58
+ <!-- auto:deps:end -->
59
+
60
+ > 子组件:`Sheet` / `SheetTrigger` / `SheetContent`(`side` 在此)/ `SheetHeader` / `SheetFooter` / `SheetTitle` / `SheetDescription` / `SheetClose` / `SheetOverlay` / `SheetPortal`。
61
+
62
+ ## AI 生成纪律
63
+
64
+ - **side 默认 right**:右侧是详情类滑出的工业惯例(Email / 设置 / 通知)
65
+ - **side="left" 仅用于全局导航**(响应式抽屉);避免在桌面端把内容也用 left side
66
+ - **Sheet 内表单 Footer 居底**:用 `flex-1` + 滚动区让表单可滚动,Footer 固定底部
67
+ - **`SheetTitle` 必有**(无障碍)
68
+ - **Sheet 与 Drawer 混用**:同一应用内只挑一个,响应式断点切换由设计层决定
69
+
70
+ ## Examples
71
+
72
+ ```tsx
73
+ import {
74
+ Sheet, SheetTrigger, SheetContent, SheetHeader,
75
+ SheetTitle, SheetDescription, SheetFooter, SheetClose,
76
+ } from '@/components/ui/sheet';
77
+ import { Button } from '@/components/ui/button';
78
+
79
+ <Sheet>
80
+ <SheetTrigger asChild>
81
+ <Button variant="outline">查看详情</Button>
82
+ </SheetTrigger>
83
+ <SheetContent side="right" className="sm:max-w-md">
84
+ <SheetHeader>
85
+ <SheetTitle>用户详情</SheetTitle>
86
+ <SheetDescription>查看与编辑用户基本信息</SheetDescription>
87
+ </SheetHeader>
88
+ {/* content */}
89
+ <SheetFooter>
90
+ <SheetClose asChild>
91
+ <Button variant="outline">关闭</Button>
92
+ </SheetClose>
93
+ <Button>保存</Button>
94
+ </SheetFooter>
95
+ </SheetContent>
96
+ </Sheet>
97
+ ```