@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,90 @@
1
+ ---
2
+ id: toggle-group
3
+ name: ToggleGroup
4
+ type: component
5
+ category: form
6
+ since: 0.1.0
7
+ package: "@teamix-evo/ui"
8
+ ---
9
+
10
+ # ToggleGroup
11
+
12
+ 切换按钮组 — Radix ToggleGroup,**单选(`type="single"`)+ 多选(`type="multiple"`)**。复用 Toggle 的 cva variants(default / outline)与 size。
13
+
14
+ ## When to use
15
+
16
+ - 工具栏(Bold / Italic / Underline)— `type="multiple"`
17
+ - 视图切换(Grid / List / Card)— `type="single"`
18
+ - 段落对齐(Left / Center / Right / Justify)— `type="single"`
19
+
20
+ ## When NOT to use
21
+
22
+ - 表单选择 → `RadioGroup`(单选)/ `Checkbox`(多选)
23
+ - 选项数 > 5 → `Select` / `Combobox`
24
+ - 单个二元开关 → `Switch` / `Toggle`
25
+
26
+ ## Props
27
+
28
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。
29
+
30
+ <!-- auto:props:begin -->
31
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
32
+ | --- | --- | --- | --- | --- |
33
+ | `variant` | `'default' \| 'outline'` | `"default"` | – | 视觉风格,与同源的 [`Toggle`](../toggle/toggle.tsx) 保持一致。 |
34
+ | `size` | `'sm' \| 'default' \| 'lg'` | `"default"` | – | 尺寸,与同源的 [`Toggle`](../toggle/toggle.tsx) 保持一致。 |
35
+ | `className` | `string` | – | – | 容器 className,会与默认布局类合并。 |
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 toggle-group` 时,以下 entry 会被自动连带安装(无需手动 add)。
46
+
47
+ | Entry | 类型 | 描述 |
48
+ | --- | --- | --- |
49
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
50
+ | `toggle` | component | 二元状态按钮 — Radix Toggle 包装,工具栏图标级开关 |
51
+
52
+ ### npm 依赖
53
+
54
+ > 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
55
+
56
+ ```bash
57
+ pnpm add @radix-ui/react-toggle-group@^1.1.0 class-variance-authority@^0.7.0
58
+ ```
59
+ <!-- auto:deps:end -->
60
+
61
+ > 透传 Radix ToggleGroup.Root 所有 props(`type` / `value` / `defaultValue` / `onValueChange` / `disabled` / `loop` / `orientation` 等)。
62
+ > `ToggleGroupItem` 接受 `value` 等 Radix 标准 props。
63
+
64
+ ## AI 生成纪律
65
+
66
+ - **`type` 必传**:`type="single"` 与 `type="multiple"` value 类型不同(string vs string[])
67
+ - **每项 value 唯一**:不要用 index
68
+ - **`size` / `variant` 在 Group 上设置**:Item 自动继承,不要逐项设置
69
+ - **图标按钮配 `aria-label`**
70
+
71
+ ## Examples
72
+
73
+ ```tsx
74
+ import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
75
+ import { AlignLeft, AlignCenter, AlignRight } from 'lucide-react';
76
+
77
+ // 单选(对齐方式)
78
+ <ToggleGroup type="single" defaultValue="left">
79
+ <ToggleGroupItem value="left" aria-label="左对齐"><AlignLeft /></ToggleGroupItem>
80
+ <ToggleGroupItem value="center" aria-label="居中"><AlignCenter /></ToggleGroupItem>
81
+ <ToggleGroupItem value="right" aria-label="右对齐"><AlignRight /></ToggleGroupItem>
82
+ </ToggleGroup>
83
+
84
+ // 多选(文本格式)
85
+ <ToggleGroup type="multiple" variant="outline">
86
+ <ToggleGroupItem value="bold">B</ToggleGroupItem>
87
+ <ToggleGroupItem value="italic">I</ToggleGroupItem>
88
+ <ToggleGroupItem value="underline">U</ToggleGroupItem>
89
+ </ToggleGroup>
90
+ ```
@@ -0,0 +1,83 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import {
3
+ AlignLeft,
4
+ AlignCenter,
5
+ AlignRight,
6
+ AlignJustify,
7
+ Bold,
8
+ Italic,
9
+ Underline,
10
+ } from 'lucide-react';
11
+ import { ToggleGroup, ToggleGroupItem } from './toggle-group';
12
+
13
+ const meta: Meta<typeof ToggleGroup> = {
14
+ title: '表单与输入 · Form/ToggleGroup',
15
+ component: ToggleGroup,
16
+ tags: ['autodocs'],
17
+ parameters: {
18
+ docs: {
19
+ description: {
20
+ component:
21
+ '切换按钮组 — 一组二状态按钮的集合,可选单选 (`type="single"`) 或多选 (`type="multiple"`),常用于对齐方式 / 字体样式等工具栏场景。Radix ToggleGroup 实现,shadcn 专有(antd 以 `Radio.Group` + `Radio.Button` 表达单选、以菜单多选表达多选);`variant` / `size` 与 `Toggle` 保持一致。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/design`,无 mock。',
22
+ },
23
+ },
24
+ },
25
+ argTypes: {
26
+ variant: { control: 'inline-radio', options: ['default', 'outline'] },
27
+ size: { control: 'inline-radio', options: ['sm', 'default', 'lg'] },
28
+ disabled: { control: 'boolean' },
29
+ },
30
+ args: { variant: 'default', size: 'default' },
31
+ };
32
+
33
+ export default meta;
34
+ type Story = StoryObj<typeof ToggleGroup>;
35
+
36
+ export const SingleAlign: Story = {
37
+ args: { type: 'single', defaultValue: 'left' },
38
+ render: (args) => (
39
+ <ToggleGroup {...args}>
40
+ <ToggleGroupItem value="left" aria-label="左对齐">
41
+ <AlignLeft />
42
+ </ToggleGroupItem>
43
+ <ToggleGroupItem value="center" aria-label="居中">
44
+ <AlignCenter />
45
+ </ToggleGroupItem>
46
+ <ToggleGroupItem value="right" aria-label="右对齐">
47
+ <AlignRight />
48
+ </ToggleGroupItem>
49
+ <ToggleGroupItem value="justify" aria-label="两端对齐">
50
+ <AlignJustify />
51
+ </ToggleGroupItem>
52
+ </ToggleGroup>
53
+ ),
54
+ };
55
+
56
+ export const MultipleFormat: Story = {
57
+ args: { type: 'multiple', variant: 'outline' },
58
+ parameters: { controls: { disable: true } },
59
+ render: (args) => (
60
+ <ToggleGroup {...args}>
61
+ <ToggleGroupItem value="bold" aria-label="加粗">
62
+ <Bold />
63
+ </ToggleGroupItem>
64
+ <ToggleGroupItem value="italic" aria-label="斜体">
65
+ <Italic />
66
+ </ToggleGroupItem>
67
+ <ToggleGroupItem value="underline" aria-label="下划线">
68
+ <Underline />
69
+ </ToggleGroupItem>
70
+ </ToggleGroup>
71
+ ),
72
+ };
73
+
74
+ export const TextItems: Story = {
75
+ parameters: { controls: { disable: true } },
76
+ render: () => (
77
+ <ToggleGroup type="single" defaultValue="grid" variant="outline">
78
+ <ToggleGroupItem value="grid">网格</ToggleGroupItem>
79
+ <ToggleGroupItem value="list">列表</ToggleGroupItem>
80
+ <ToggleGroupItem value="card">卡片</ToggleGroupItem>
81
+ </ToggleGroup>
82
+ ),
83
+ };
@@ -0,0 +1,78 @@
1
+ import * as React from 'react';
2
+ import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';
3
+ import { type VariantProps } from 'class-variance-authority';
4
+
5
+ import { cn } from '@/utils/cn';
6
+ import { toggleVariants } from '@/components/toggle/toggle';
7
+
8
+ const ToggleGroupContext = React.createContext<
9
+ VariantProps<typeof toggleVariants>
10
+ >({ size: 'default', variant: 'default' });
11
+
12
+ /**
13
+ * ToggleGroup 自身的可定制属性。底层 type=`single`|`multiple` 与对应的
14
+ * `value` / `onValueChange` 等由 Radix 的 union props 透传。
15
+ */
16
+ export interface ToggleGroupProps {
17
+ /**
18
+ * 视觉风格,与同源的 [`Toggle`](../toggle/toggle.tsx) 保持一致。
19
+ * @default "default"
20
+ */
21
+ variant?: 'default' | 'outline';
22
+ /**
23
+ * 尺寸,与同源的 [`Toggle`](../toggle/toggle.tsx) 保持一致。
24
+ * @default "default"
25
+ */
26
+ size?: 'sm' | 'default' | 'lg';
27
+ /**
28
+ * 容器 className,会与默认布局类合并。
29
+ */
30
+ className?: string;
31
+ }
32
+
33
+ function ToggleGroup({
34
+ className,
35
+ variant,
36
+ size,
37
+ children,
38
+ ...props
39
+ }: ToggleGroupProps &
40
+ React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root>) {
41
+ return (
42
+ <ToggleGroupPrimitive.Root
43
+ className={cn('flex items-center justify-center gap-1', className)}
44
+ {...props}
45
+ >
46
+ <ToggleGroupContext.Provider value={{ variant, size }}>
47
+ {children}
48
+ </ToggleGroupContext.Provider>
49
+ </ToggleGroupPrimitive.Root>
50
+ );
51
+ }
52
+ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
53
+
54
+ const ToggleGroupItem = React.forwardRef<
55
+ React.ElementRef<typeof ToggleGroupPrimitive.Item>,
56
+ React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
57
+ VariantProps<typeof toggleVariants>
58
+ >(({ className, children, variant, size, ...props }, ref) => {
59
+ const ctx = React.useContext(ToggleGroupContext);
60
+ return (
61
+ <ToggleGroupPrimitive.Item
62
+ ref={ref}
63
+ className={cn(
64
+ toggleVariants({
65
+ variant: ctx.variant ?? variant,
66
+ size: ctx.size ?? size,
67
+ }),
68
+ className,
69
+ )}
70
+ {...props}
71
+ >
72
+ {children}
73
+ </ToggleGroupPrimitive.Item>
74
+ );
75
+ });
76
+ ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
77
+
78
+ export { ToggleGroup, ToggleGroupItem };
@@ -0,0 +1,99 @@
1
+ ---
2
+ id: tooltip
3
+ name: Tooltip
4
+ type: component
5
+ category: feedback
6
+ since: 0.1.0
7
+ package: "@teamix-evo/ui"
8
+ ---
9
+
10
+ # Tooltip
11
+
12
+ 文字提示气泡 — Radix Tooltip + antd `arrow / placement(side)` 并集。
13
+ **两种用法**:`<Tooltip title="...">{trigger}</Tooltip>` 一行包装,或拆分原子组件(`TooltipRoot/Trigger/Content`)精细控制。
14
+
15
+ > **必须用 `<TooltipProvider>` 包裹**(通常在应用根),或在单 Tooltip 上传 `withProvider`。
16
+
17
+ ## When to use
18
+
19
+ - 图标按钮的文字解释(无障碍 + 视觉提示)
20
+ - 表单字段的辅助说明(替代占空间的描述文字)
21
+ - 数据列的列宽不足导致截断时的完整内容
22
+
23
+ ## When NOT to use
24
+
25
+ - 包含交互的内容 → 用 `Popover` 或 `HoverCard`
26
+ - 长文本(超过 1 行)→ 用 `HoverCard` 或对话框
27
+ - 移动端首要功能 → 触屏不易触发 hover,改用按钮 + 弹窗
28
+
29
+ ## Props
30
+
31
+ > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。
32
+
33
+ <!-- auto:props:begin -->
34
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
35
+ | --- | --- | --- | --- | --- |
36
+ | `children` | `React.ReactElement` | – | ✓ | 触发器(单个 ReactElement,asChild 透传)。 |
37
+ | `title` | `React.ReactNode` | – | ✓ | 提示内容。 |
38
+ | `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `"top"` | – | 弹出方向。 |
39
+ | `arrow` | `boolean` | `true` | – | 是否显示三角形箭头。 |
40
+ | `delayDuration` | `number` | – | – | 显示延迟(ms),默认沿用 Provider 的 delayDuration。 |
41
+ | `withProvider` | `boolean` | – | – | 强制传给 Provider 的 delayDuration(便于不挂 Provider 的场景)。 |
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 tooltip` 时,以下 entry 会被自动连带安装(无需手动 add)。
52
+
53
+ | Entry | 类型 | 描述 |
54
+ | --- | --- | --- |
55
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
56
+
57
+ ### npm 依赖
58
+
59
+ > 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
60
+
61
+ ```bash
62
+ pnpm add @radix-ui/react-tooltip@^1.1.0
63
+ ```
64
+ <!-- auto:deps:end -->
65
+
66
+ > 子组件 `TooltipProvider / TooltipRoot / TooltipTrigger / TooltipContent` 用于精细控制,见 [`tooltip.tsx`](./tooltip.tsx)。
67
+
68
+ ## AI 生成纪律
69
+
70
+ - **必有 Provider**:不挂 Provider 直接用 Tooltip 会报错或不工作。**应用根**统一挂 `<TooltipProvider delayDuration={300}>`
71
+ - **`title` 用文本不放交互**:Tooltip 内放 button / link 在键盘焦点流转上是反模式
72
+ - **`title` ≤ 1 行**:超过 1 行换 `HoverCard`
73
+ - **图标按钮必配 Tooltip + aria-label**:不能只靠 Tooltip 而省略 aria-label,屏幕阅读器不一定触发
74
+ - **`side` 选 `top` 通常最稳**:避免被屏幕边缘截断;Radix 自带翻转回避能力,但标注首选语义
75
+
76
+ ## Examples
77
+
78
+ ```tsx
79
+ import { Tooltip, TooltipProvider } from '@/components/ui/tooltip';
80
+ import { Button } from '@/components/ui/button';
81
+ import { Settings } from 'lucide-react';
82
+
83
+ // 应用根挂 Provider
84
+ <TooltipProvider delayDuration={300}>
85
+ <App />
86
+ </TooltipProvider>
87
+
88
+ // 简洁用法
89
+ <Tooltip title="设置">
90
+ <Button size="icon" variant="ghost" aria-label="设置">
91
+ <Settings />
92
+ </Button>
93
+ </Tooltip>
94
+
95
+ // 自定义方向 + 无箭头
96
+ <Tooltip title="向右弹出" side="right" arrow={false}>
97
+ <Button variant="outline">悬浮我</Button>
98
+ </Tooltip>
99
+ ```
@@ -0,0 +1,71 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Settings } from 'lucide-react';
3
+ import { Tooltip, TooltipProvider } from './tooltip';
4
+ import { Button } from '@/components/button/button';
5
+
6
+ const meta: Meta<typeof Tooltip> = {
7
+ title: '反馈与浮层 · Feedback/Tooltip',
8
+ component: Tooltip,
9
+ tags: ['autodocs'],
10
+ parameters: {
11
+ docs: {
12
+ description: {
13
+ component:
14
+ '文字气泡提示 — 鼠标悬停或键盘聚焦元素时弹出的简短提示。Radix Tooltip 实现 + antd Tooltip 的并集能力:需 `TooltipProvider` 包裹(可设 `delayDuration`),通过 `side` / `arrow` / `title` 调整方位与尖角;适用于纯文本辅助说明,丰富交互请选 `Popover`。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/design`,无 mock。',
15
+ },
16
+ },
17
+ },
18
+ argTypes: {
19
+ side: {
20
+ control: 'inline-radio',
21
+ options: ['top', 'right', 'bottom', 'left'],
22
+ },
23
+ arrow: { control: 'boolean' },
24
+ title: { control: 'text' },
25
+ },
26
+ args: { side: 'top', arrow: true, title: '设置' },
27
+ decorators: [
28
+ (Story) => (
29
+ <TooltipProvider delayDuration={200}>
30
+ <div className="flex h-32 items-center justify-center">
31
+ <Story />
32
+ </div>
33
+ </TooltipProvider>
34
+ ),
35
+ ],
36
+ };
37
+
38
+ export default meta;
39
+ type Story = StoryObj<typeof Tooltip>;
40
+
41
+ export const Playground: Story = {
42
+ render: (args) => (
43
+ <Tooltip {...args}>
44
+ <Button size="icon" variant="ghost" aria-label="设置">
45
+ <Settings />
46
+ </Button>
47
+ </Tooltip>
48
+ ),
49
+ };
50
+
51
+ export const Sides: Story = {
52
+ parameters: { controls: { disable: true } },
53
+ render: () => (
54
+ <div className="flex items-center gap-3">
55
+ {(['top', 'right', 'bottom', 'left'] as const).map((s) => (
56
+ <Tooltip key={s} title={s} side={s}>
57
+ <Button variant="outline">{s}</Button>
58
+ </Tooltip>
59
+ ))}
60
+ </div>
61
+ ),
62
+ };
63
+
64
+ export const NoArrow: Story = {
65
+ parameters: { controls: { disable: true } },
66
+ render: () => (
67
+ <Tooltip title="无箭头" arrow={false}>
68
+ <Button variant="outline">悬浮</Button>
69
+ </Tooltip>
70
+ ),
71
+ };
@@ -0,0 +1,93 @@
1
+ import * as React from 'react';
2
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
3
+
4
+ import { cn } from '@/utils/cn';
5
+
6
+ const TooltipProvider = TooltipPrimitive.Provider;
7
+ const TooltipRoot = TooltipPrimitive.Root;
8
+ const TooltipTrigger = TooltipPrimitive.Trigger;
9
+
10
+ export interface TooltipContentProps
11
+ extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {
12
+ /**
13
+ * 是否显示三角形箭头(antd `arrow` 并集)。
14
+ * @default true
15
+ */
16
+ arrow?: boolean;
17
+ }
18
+
19
+ const TooltipContent = React.forwardRef<
20
+ React.ElementRef<typeof TooltipPrimitive.Content>,
21
+ TooltipContentProps
22
+ >(({ className, sideOffset = 4, arrow = true, children, ...props }, ref) => (
23
+ <TooltipPrimitive.Portal>
24
+ <TooltipPrimitive.Content
25
+ ref={ref}
26
+ sideOffset={sideOffset}
27
+ className={cn(
28
+ 'z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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',
29
+ className,
30
+ )}
31
+ {...props}
32
+ >
33
+ {children}
34
+ {arrow ? (
35
+ <TooltipPrimitive.Arrow className="fill-primary" width={8} height={4} />
36
+ ) : null}
37
+ </TooltipPrimitive.Content>
38
+ </TooltipPrimitive.Portal>
39
+ ));
40
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
41
+
42
+ // ─── Convenience wrapper(antd-style 一行调用)──────────────────────────────
43
+
44
+ export interface TooltipProps
45
+ extends Omit<
46
+ React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root>,
47
+ 'children'
48
+ > {
49
+ /** 触发器(单个 ReactElement,asChild 透传)。 */
50
+ children: React.ReactElement;
51
+ /** 提示内容。 */
52
+ title: React.ReactNode;
53
+ /** 弹出方向。 @default "top" */
54
+ side?: 'top' | 'right' | 'bottom' | 'left';
55
+ /** 是否显示三角形箭头。 @default true */
56
+ arrow?: boolean;
57
+ /** 显示延迟(ms),默认沿用 Provider 的 delayDuration。 */
58
+ delayDuration?: number;
59
+ /** 强制传给 Provider 的 delayDuration(便于不挂 Provider 的场景)。 */
60
+ withProvider?: boolean;
61
+ }
62
+
63
+ const Tooltip: React.FC<TooltipProps> = ({
64
+ children,
65
+ title,
66
+ side = 'top',
67
+ arrow = true,
68
+ delayDuration,
69
+ withProvider = false,
70
+ ...rootProps
71
+ }) => {
72
+ const inner = (
73
+ <TooltipRoot delayDuration={delayDuration} {...rootProps}>
74
+ <TooltipTrigger asChild>{children}</TooltipTrigger>
75
+ <TooltipContent side={side} arrow={arrow}>
76
+ {title}
77
+ </TooltipContent>
78
+ </TooltipRoot>
79
+ );
80
+ return withProvider ? (
81
+ <TooltipProvider delayDuration={delayDuration}>{inner}</TooltipProvider>
82
+ ) : (
83
+ inner
84
+ );
85
+ };
86
+
87
+ export {
88
+ Tooltip,
89
+ TooltipProvider,
90
+ TooltipRoot,
91
+ TooltipTrigger,
92
+ TooltipContent,
93
+ };
@@ -0,0 +1,116 @@
1
+ ---
2
+ id: tour
3
+ name: Tour
4
+ type: component
5
+ category: feedback
6
+ since: 0.1.0
7
+ package: "@teamix-evo/ui"
8
+ ---
9
+
10
+ # Tour
11
+
12
+ 新手引导 — antd 独有补足。**等价 antd `Tour`**(v5.0+)。多步骤引导(spotlight + 卡片 + 步进按钮 + 可关闭),帮助新用户首次进入页面时了解关键功能位置。
13
+
14
+ ## When to use
15
+
16
+ - 首次进入新功能页(关键功能位置说明)
17
+ - 重大改版后的迁移引导(指出新位置)
18
+ - 工具型应用的快速入门(画板 / 编辑器)
19
+
20
+ ## When NOT to use
21
+
22
+ - 静态帮助文档 → 用 Anchor + 长文档
23
+ - 单一提示 → `Tooltip` / `Popover`
24
+ - 表单字段说明 → `FieldDescription`
25
+ - 错误反馈 → `Alert` / `notification`
26
+
27
+ <!-- auto:props:begin -->
28
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
29
+ | --- | --- | --- | --- | --- |
30
+ | `steps` | `TourStep[]` | – | ✓ | 步骤列表(antd `steps` 并集)。 |
31
+ | `open` | `boolean` | – | – | 受控 open 状态。 |
32
+ | `defaultOpen` | `boolean` | `false` | – | uncontrolled 初值。 |
33
+ | `onOpenChange` | `(open: boolean) => void` | – | – | open 变化回调。 |
34
+ | `current` | `number` | – | – | 当前步骤索引(受控)。 |
35
+ | `onChange` | `(current: number) => void` | – | – | 步骤变化回调。 |
36
+ | `onFinish` | `() => void` | – | – | 完成时回调(走到最后一步且点击"完成")。 |
37
+ | `onClose` | `() => void` | – | – | 关闭回调(任意时刻点 X / mask)。 |
38
+ | `mask` | `boolean` | `true` | – | 是否显示遮罩(antd `mask` 并集)。 |
39
+ <!-- auto:props:end -->
40
+
41
+ <!-- auto:deps:begin -->
42
+ ### 同库依赖
43
+
44
+ > `teamix-evo ui add tour` 时,以下 entry 会被自动连带安装(无需手动 add)。
45
+
46
+ | Entry | 类型 | 描述 |
47
+ | --- | --- | --- |
48
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
49
+ | `button` | component | 通用按钮 — shadcn 实现 + antd 功能扩展(loading / icon / shape / block / dashed variant) |
50
+
51
+ ### npm 依赖
52
+
53
+ > 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
54
+
55
+ ```bash
56
+ pnpm add lucide-react@^0.460.0
57
+ ```
58
+ <!-- auto:deps:end -->
59
+
60
+ ## AI 生成纪律
61
+
62
+ - **业务侧自管"是否首次访问"** — 通常配 localStorage `tour:onboarding` 标记;**不要**期望本组件持久化
63
+ - **`target` 必须是已挂载的元素**:用 `useRef` 绑定到 DOM 节点;Tour 用 `getBoundingClientRect()` 定位 spotlight
64
+ - **`target` 不传 = 居中无 spotlight 模式**:用于"欢迎语" / "总结结束语"等无指向步骤
65
+ - **步骤 ≤ 5**:再多用户会跳过 — 太长的引导改用文档 / 视频
66
+ - **`onFinish` 应同时 set localStorage** 标记完成,避免再次弹出
67
+ - **不要在 Tour 内放复杂表单 / 长文本** — 它是定位提示,不是阅读容器
68
+ - **`mask=false`** 仅在用户需要边引导边操作时关闭;默认遮罩聚焦更强
69
+
70
+ ## Examples
71
+
72
+ ```tsx
73
+ import { Tour } from '@/components/ui/tour';
74
+ import * as React from 'react';
75
+
76
+ function Page() {
77
+ const newBtnRef = React.useRef<HTMLButtonElement>(null);
78
+ const settingsRef = React.useRef<HTMLDivElement>(null);
79
+ const [open, setOpen] = React.useState(false);
80
+
81
+ React.useEffect(() => {
82
+ if (!localStorage.getItem('tour:v1')) setOpen(true);
83
+ }, []);
84
+
85
+ return (
86
+ <>
87
+ <button ref={newBtnRef}>新建</button>
88
+ <div ref={settingsRef}>设置</div>
89
+
90
+ <Tour
91
+ open={open}
92
+ onOpenChange={setOpen}
93
+ onFinish={() => localStorage.setItem('tour:v1', '1')}
94
+ steps={[
95
+ {
96
+ target: newBtnRef,
97
+ title: '从这里新建',
98
+ description: '点击「新建」按钮即可创建新的项目',
99
+ placement: 'bottom',
100
+ },
101
+ {
102
+ target: settingsRef,
103
+ title: '个性化设置',
104
+ description: '在此处调整主题 / 通知偏好',
105
+ placement: 'left',
106
+ },
107
+ {
108
+ title: '完成!',
109
+ description: '开始使用吧 🎉',
110
+ },
111
+ ]}
112
+ />
113
+ </>
114
+ );
115
+ }
116
+ ```