@teamix-evo/ui 0.1.1 → 0.3.0

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 (295) hide show
  1. package/README.md +184 -184
  2. package/manifest.json +680 -492
  3. package/package.json +20 -10
  4. package/src/components/accordion/accordion.meta.md +5 -4
  5. package/src/components/accordion/accordion.stories.tsx +14 -9
  6. package/src/components/accordion/accordion.tsx +104 -8
  7. package/src/components/affix/affix.meta.md +20 -2
  8. package/src/components/affix/affix.stories.tsx +102 -25
  9. package/src/components/affix/affix.tsx +79 -9
  10. package/src/components/alert/alert.meta.md +44 -13
  11. package/src/components/alert/alert.stories.tsx +66 -21
  12. package/src/components/alert/alert.tsx +81 -34
  13. package/src/components/alert-dialog/alert-dialog.meta.md +61 -16
  14. package/src/components/alert-dialog/alert-dialog.stories.tsx +145 -3
  15. package/src/components/alert-dialog/alert-dialog.tsx +60 -13
  16. package/src/components/anchor/anchor.meta.md +8 -3
  17. package/src/components/anchor/anchor.stories.tsx +3 -3
  18. package/src/components/anchor/anchor.tsx +2 -2
  19. package/src/components/app/app.meta.md +9 -4
  20. package/src/components/app/app.stories.tsx +9 -7
  21. package/src/components/aspect-ratio/aspect-ratio.meta.md +4 -3
  22. package/src/components/aspect-ratio/aspect-ratio.stories.tsx +3 -3
  23. package/src/components/auto-complete/auto-complete.meta.md +14 -6
  24. package/src/components/auto-complete/auto-complete.stories.tsx +47 -4
  25. package/src/components/auto-complete/auto-complete.tsx +119 -71
  26. package/src/components/avatar/avatar.meta.md +6 -7
  27. package/src/components/avatar/avatar.stories.tsx +21 -3
  28. package/src/components/avatar/avatar.tsx +24 -23
  29. package/src/components/badge/badge.meta.md +10 -9
  30. package/src/components/badge/badge.stories.tsx +2 -2
  31. package/src/components/badge/badge.tsx +9 -15
  32. package/src/components/breadcrumb/breadcrumb.meta.md +27 -7
  33. package/src/components/breadcrumb/breadcrumb.stories.tsx +127 -4
  34. package/src/components/breadcrumb/breadcrumb.tsx +22 -8
  35. package/src/components/button/button.meta.md +258 -21
  36. package/src/components/button/button.stories.tsx +549 -41
  37. package/src/components/button/button.tsx +335 -33
  38. package/src/components/button/demo/as-child.tsx +24 -0
  39. package/src/components/button/demo/basic.tsx +8 -0
  40. package/src/components/button/demo/block.tsx +16 -0
  41. package/src/components/button/demo/loading.tsx +19 -0
  42. package/src/components/button/demo/shapes.tsx +18 -0
  43. package/src/components/button/demo/sizes.tsx +19 -0
  44. package/src/components/button/demo/variants.tsx +19 -0
  45. package/src/components/button/demo/with-icon.tsx +20 -0
  46. package/src/components/calendar/calendar.meta.md +13 -3
  47. package/src/components/calendar/calendar.stories.tsx +6 -6
  48. package/src/components/calendar/calendar.tsx +73 -8
  49. package/src/components/card/card.meta.md +27 -5
  50. package/src/components/card/card.stories.tsx +42 -3
  51. package/src/components/card/card.tsx +146 -63
  52. package/src/components/carousel/carousel.meta.md +4 -3
  53. package/src/components/carousel/carousel.stories.tsx +11 -6
  54. package/src/components/cascader/cascader.meta.md +47 -17
  55. package/src/components/cascader/cascader.stories.tsx +22 -10
  56. package/src/components/cascader/cascader.tsx +428 -85
  57. package/src/components/checkbox/checkbox.meta.md +75 -7
  58. package/src/components/checkbox/checkbox.stories.tsx +161 -3
  59. package/src/components/checkbox/checkbox.tsx +77 -9
  60. package/src/components/collapsible/collapsible.meta.md +14 -6
  61. package/src/components/collapsible/collapsible.stories.tsx +10 -2
  62. package/src/components/collapsible/collapsible.tsx +93 -6
  63. package/src/components/color-picker/color-picker.meta.md +12 -7
  64. package/src/components/color-picker/color-picker.stories.tsx +86 -7
  65. package/src/components/color-picker/color-picker.tsx +20 -9
  66. package/src/components/command/command.meta.md +29 -13
  67. package/src/components/command/command.stories.tsx +4 -4
  68. package/src/components/command/command.tsx +19 -8
  69. package/src/components/context-menu/context-menu.meta.md +11 -8
  70. package/src/components/context-menu/context-menu.stories.tsx +11 -3
  71. package/src/components/context-menu/context-menu.tsx +21 -8
  72. package/src/components/data-table/data-table.meta.md +6 -5
  73. package/src/components/data-table/data-table.stories.tsx +13 -6
  74. package/src/components/data-table/data-table.tsx +2 -2
  75. package/src/components/date-picker/date-picker.meta.md +88 -19
  76. package/src/components/date-picker/date-picker.stories.tsx +55 -5
  77. package/src/components/date-picker/date-picker.tsx +1489 -91
  78. package/src/components/descriptions/descriptions.meta.md +10 -5
  79. package/src/components/descriptions/descriptions.stories.tsx +3 -3
  80. package/src/components/descriptions/descriptions.tsx +22 -14
  81. package/src/components/dialog/dialog.meta.md +76 -13
  82. package/src/components/dialog/dialog.stories.tsx +182 -20
  83. package/src/components/dialog/dialog.tsx +67 -15
  84. package/src/components/dialog/imperative.tsx +252 -0
  85. package/src/components/drawer/drawer.meta.md +33 -34
  86. package/src/components/drawer/drawer.stories.tsx +29 -12
  87. package/src/components/drawer/drawer.tsx +22 -113
  88. package/src/components/dropdown-menu/dropdown-menu.meta.md +78 -10
  89. package/src/components/dropdown-menu/dropdown-menu.stories.tsx +88 -2
  90. package/src/components/dropdown-menu/dropdown-menu.tsx +24 -10
  91. package/src/components/ellipsis/ellipsis.meta.md +87 -0
  92. package/src/components/ellipsis/ellipsis.stories.tsx +72 -0
  93. package/src/components/ellipsis/ellipsis.tsx +153 -0
  94. package/src/components/empty/empty.meta.md +9 -4
  95. package/src/components/empty/empty.stories.tsx +4 -4
  96. package/src/components/empty/empty.tsx +10 -3
  97. package/src/components/field/field.meta.md +47 -9
  98. package/src/components/field/field.stories.tsx +385 -5
  99. package/src/components/field/field.tsx +263 -35
  100. package/src/components/filter-bar/filter-bar.meta.md +92 -0
  101. package/src/components/filter-bar/filter-bar.stories.tsx +1083 -0
  102. package/src/components/filter-bar/filter-bar.tsx +568 -0
  103. package/src/components/flex/flex.meta.md +54 -6
  104. package/src/components/flex/flex.stories.tsx +107 -20
  105. package/src/components/flex/flex.tsx +27 -4
  106. package/src/components/float-button/float-button.meta.md +8 -3
  107. package/src/components/float-button/float-button.stories.tsx +9 -7
  108. package/src/components/float-button/float-button.tsx +1 -1
  109. package/src/components/form/form.meta.md +39 -17
  110. package/src/components/form/form.stories.tsx +350 -3
  111. package/src/components/form/form.tsx +101 -35
  112. package/src/components/grid/grid.meta.md +7 -2
  113. package/src/components/grid/grid.stories.tsx +6 -4
  114. package/src/components/hover-card/hover-card.meta.md +20 -9
  115. package/src/components/hover-card/hover-card.stories.tsx +34 -5
  116. package/src/components/hover-card/hover-card.tsx +51 -13
  117. package/src/components/icon/DEVELOPMENT.md +809 -0
  118. package/src/components/icon/icon.meta.md +170 -0
  119. package/src/components/icon/icon.stories.tsx +344 -0
  120. package/src/components/icon/icon.tsx +248 -0
  121. package/src/components/image/image.meta.md +9 -4
  122. package/src/components/image/image.stories.tsx +3 -3
  123. package/src/components/image/image.tsx +6 -4
  124. package/src/components/input/demo/basic.tsx +12 -0
  125. package/src/components/input/demo/clearable.tsx +21 -0
  126. package/src/components/input/demo/show-count.tsx +18 -0
  127. package/src/components/input/demo/sizes.tsx +15 -0
  128. package/src/components/input/input.meta.md +39 -33
  129. package/src/components/input/input.stories.tsx +62 -35
  130. package/src/components/input/input.tsx +97 -98
  131. package/src/components/input-group/input-group.meta.md +54 -22
  132. package/src/components/input-group/input-group.stories.tsx +49 -16
  133. package/src/components/input-group/input-group.tsx +44 -8
  134. package/src/components/input-number/input-number.meta.md +64 -7
  135. package/src/components/input-number/input-number.stories.tsx +46 -8
  136. package/src/components/input-number/input-number.tsx +99 -26
  137. package/src/components/input-otp/input-otp.meta.md +4 -3
  138. package/src/components/input-otp/input-otp.stories.tsx +3 -3
  139. package/src/components/input-otp/input-otp.tsx +1 -1
  140. package/src/components/item/item.meta.md +8 -3
  141. package/src/components/item/item.stories.tsx +8 -5
  142. package/src/components/item/item.tsx +7 -6
  143. package/src/components/kbd/kbd.meta.md +13 -4
  144. package/src/components/kbd/kbd.stories.tsx +4 -4
  145. package/src/components/kbd/kbd.tsx +10 -5
  146. package/src/components/label/label.meta.md +18 -10
  147. package/src/components/label/label.stories.tsx +64 -6
  148. package/src/components/label/label.tsx +91 -19
  149. package/src/components/masonry/masonry.meta.md +8 -3
  150. package/src/components/masonry/masonry.stories.tsx +7 -5
  151. package/src/components/masonry/masonry.tsx +1 -0
  152. package/src/components/mentions/mentions.meta.md +36 -6
  153. package/src/components/mentions/mentions.stories.tsx +120 -6
  154. package/src/components/mentions/mentions.tsx +11 -5
  155. package/src/components/menubar/menubar.meta.md +30 -12
  156. package/src/components/menubar/menubar.stories.tsx +62 -2
  157. package/src/components/menubar/menubar.tsx +9 -9
  158. package/src/components/native-select/native-select.meta.md +8 -3
  159. package/src/components/native-select/native-select.stories.tsx +8 -5
  160. package/src/components/native-select/native-select.tsx +1 -1
  161. package/src/components/navigation-menu/navigation-menu.meta.md +19 -9
  162. package/src/components/navigation-menu/navigation-menu.stories.tsx +112 -9
  163. package/src/components/navigation-menu/navigation-menu.tsx +8 -4
  164. package/src/components/notification/notification.meta.md +52 -10
  165. package/src/components/notification/notification.stories.tsx +11 -9
  166. package/src/components/notification/notification.tsx +36 -21
  167. package/src/components/page-header/DEVELOPMENT.md +842 -0
  168. package/src/components/page-header/page-header.meta.md +208 -0
  169. package/src/components/page-header/page-header.stories.tsx +421 -0
  170. package/src/components/page-header/page-header.tsx +281 -0
  171. package/src/components/pagination/pagination.meta.md +140 -37
  172. package/src/components/pagination/pagination.stories.tsx +232 -10
  173. package/src/components/pagination/pagination.tsx +355 -63
  174. package/src/components/popconfirm/popconfirm.meta.md +9 -4
  175. package/src/components/popconfirm/popconfirm.stories.tsx +3 -4
  176. package/src/components/popconfirm/popconfirm.tsx +2 -2
  177. package/src/components/popover/popover.meta.md +62 -5
  178. package/src/components/popover/popover.stories.tsx +83 -7
  179. package/src/components/popover/popover.tsx +77 -28
  180. package/src/components/progress/progress.meta.md +38 -6
  181. package/src/components/progress/progress.stories.tsx +3 -3
  182. package/src/components/progress/progress.tsx +24 -16
  183. package/src/components/radio-group/radio-group.meta.md +79 -7
  184. package/src/components/radio-group/radio-group.stories.tsx +39 -3
  185. package/src/components/radio-group/radio-group.tsx +149 -18
  186. package/src/components/rate/rate.meta.md +35 -4
  187. package/src/components/rate/rate.stories.tsx +13 -5
  188. package/src/components/rate/rate.tsx +37 -10
  189. package/src/components/resizable/resizable.meta.md +7 -4
  190. package/src/components/resizable/resizable.stories.tsx +6 -6
  191. package/src/components/resizable/resizable.tsx +1 -1
  192. package/src/components/result/result.meta.md +7 -2
  193. package/src/components/result/result.stories.tsx +4 -8
  194. package/src/components/result/result.tsx +24 -15
  195. package/src/components/scroll-area/scroll-area.meta.md +4 -3
  196. package/src/components/scroll-area/scroll-area.stories.tsx +12 -4
  197. package/src/components/scroll-area/scroll-area.tsx +3 -3
  198. package/src/components/segmented/segmented.meta.md +7 -4
  199. package/src/components/segmented/segmented.stories.tsx +37 -8
  200. package/src/components/segmented/segmented.tsx +15 -7
  201. package/src/components/select/select.meta.md +197 -52
  202. package/src/components/select/select.stories.tsx +238 -63
  203. package/src/components/select/select.tsx +718 -171
  204. package/src/components/separator/separator.meta.md +4 -3
  205. package/src/components/separator/separator.stories.tsx +3 -3
  206. package/src/components/separator/separator.tsx +3 -7
  207. package/src/components/sheet/sheet.meta.md +32 -16
  208. package/src/components/sheet/sheet.stories.tsx +116 -10
  209. package/src/components/sheet/sheet.tsx +116 -29
  210. package/src/components/sidebar/sidebar.meta.md +37 -18
  211. package/src/components/sidebar/sidebar.stories.tsx +701 -29
  212. package/src/components/sidebar/sidebar.tsx +615 -142
  213. package/src/components/skeleton/skeleton.meta.md +4 -5
  214. package/src/components/skeleton/skeleton.stories.tsx +4 -4
  215. package/src/components/skeleton/skeleton.tsx +7 -7
  216. package/src/components/slider/slider.meta.md +57 -5
  217. package/src/components/slider/slider.stories.tsx +58 -6
  218. package/src/components/slider/slider.tsx +154 -13
  219. package/src/components/sonner/sonner.meta.md +58 -7
  220. package/src/components/sonner/sonner.stories.tsx +78 -5
  221. package/src/components/sonner/sonner.tsx +137 -8
  222. package/src/components/spinner/spinner.meta.md +62 -13
  223. package/src/components/spinner/spinner.stories.tsx +66 -14
  224. package/src/components/spinner/spinner.tsx +111 -9
  225. package/src/components/statistic/statistic.meta.md +7 -2
  226. package/src/components/statistic/statistic.stories.tsx +3 -7
  227. package/src/components/statistic/statistic.tsx +5 -6
  228. package/src/components/steps/steps.meta.md +18 -4
  229. package/src/components/steps/steps.stories.tsx +43 -3
  230. package/src/components/steps/steps.tsx +15 -12
  231. package/src/components/switch/switch.meta.md +51 -5
  232. package/src/components/switch/switch.stories.tsx +6 -6
  233. package/src/components/switch/switch.tsx +109 -41
  234. package/src/components/table/table.meta.md +17 -6
  235. package/src/components/table/table.stories.tsx +10 -5
  236. package/src/components/table/table.tsx +4 -4
  237. package/src/components/tabs/tabs.meta.md +38 -25
  238. package/src/components/tabs/tabs.stories.tsx +111 -25
  239. package/src/components/tabs/tabs.tsx +125 -54
  240. package/src/components/tag/tag.meta.md +105 -40
  241. package/src/components/tag/tag.stories.tsx +189 -16
  242. package/src/components/tag/tag.tsx +222 -21
  243. package/src/components/textarea/textarea.meta.md +35 -19
  244. package/src/components/textarea/textarea.stories.tsx +32 -6
  245. package/src/components/textarea/textarea.tsx +33 -9
  246. package/src/components/time-picker/time-picker.meta.md +124 -32
  247. package/src/components/time-picker/time-picker.stories.tsx +85 -15
  248. package/src/components/time-picker/time-picker.tsx +913 -61
  249. package/src/components/timeline/timeline.meta.md +14 -6
  250. package/src/components/timeline/timeline.stories.tsx +37 -7
  251. package/src/components/timeline/timeline.tsx +35 -14
  252. package/src/components/toggle/toggle.meta.md +5 -4
  253. package/src/components/toggle/toggle.stories.tsx +4 -4
  254. package/src/components/toggle/toggle.tsx +4 -3
  255. package/src/components/toggle-group/toggle-group.meta.md +5 -4
  256. package/src/components/toggle-group/toggle-group.stories.tsx +3 -3
  257. package/src/components/toggle-group/toggle-group.tsx +2 -2
  258. package/src/components/tooltip/tooltip.meta.md +55 -5
  259. package/src/components/tooltip/tooltip.stories.tsx +42 -5
  260. package/src/components/tooltip/tooltip.tsx +81 -21
  261. package/src/components/tour/tour.meta.md +9 -4
  262. package/src/components/tour/tour.stories.tsx +3 -3
  263. package/src/components/tour/tour.tsx +4 -4
  264. package/src/components/transfer/transfer.meta.md +11 -6
  265. package/src/components/transfer/transfer.stories.tsx +4 -8
  266. package/src/components/transfer/transfer.tsx +28 -21
  267. package/src/components/tree/tree.meta.md +63 -5
  268. package/src/components/tree/tree.stories.tsx +31 -12
  269. package/src/components/tree/tree.tsx +9 -8
  270. package/src/components/tree-select/tree-select.meta.md +59 -8
  271. package/src/components/tree-select/tree-select.stories.tsx +3 -3
  272. package/src/components/tree-select/tree-select.tsx +42 -7
  273. package/src/components/typography/typography.meta.md +61 -14
  274. package/src/components/typography/typography.stories.tsx +12 -11
  275. package/src/components/typography/typography.tsx +43 -28
  276. package/src/components/upload/upload.meta.md +49 -4
  277. package/src/components/upload/upload.stories.tsx +72 -12
  278. package/src/components/upload/upload.tsx +170 -37
  279. package/src/components/watermark/watermark.meta.md +7 -2
  280. package/src/components/watermark/watermark.stories.tsx +101 -9
  281. package/src/components/watermark/watermark.tsx +1 -0
  282. package/src/hooks/use-breakpoint.ts +117 -0
  283. package/src/hooks/use-debounce-callback.ts +52 -0
  284. package/src/hooks/use-mobile.ts +23 -0
  285. package/src/stories/theme-tokens.stories.tsx +747 -0
  286. package/src/utils/trigger-input.ts +53 -0
  287. package/src/components/button-group/button-group.meta.md +0 -92
  288. package/src/components/button-group/button-group.stories.tsx +0 -90
  289. package/src/components/button-group/button-group.tsx +0 -75
  290. package/src/components/combobox/combobox.meta.md +0 -93
  291. package/src/components/combobox/combobox.stories.tsx +0 -55
  292. package/src/components/combobox/combobox.tsx +0 -130
  293. package/src/components/space/space.meta.md +0 -94
  294. package/src/components/space/space.stories.tsx +0 -94
  295. package/src/components/space/space.tsx +0 -106
@@ -1,13 +1,14 @@
1
1
  ---
2
2
  id: skeleton
3
3
  name: Skeleton
4
+ displayName: 骨架屏
4
5
  type: component
5
- category: foundation
6
+ category: feedback
6
7
  since: 0.1.0
7
- package: "@teamix-evo/ui"
8
+ package: '@teamix-evo/ui'
8
9
  ---
9
10
 
10
- # Skeleton
11
+ # Skeleton 骨架屏
11
12
 
12
13
  骨架屏占位 — shadcn 单元素 pulse + antd 子组件家族(`SkeletonAvatar / SkeletonImage / SkeletonButton / SkeletonInput / SkeletonParagraph`)。
13
14
 
@@ -56,8 +57,6 @@ pnpm add class-variance-authority@^0.7.0
56
57
  ```
57
58
  <!-- auto:deps:end -->
58
59
 
59
- > 子组件 `SkeletonAvatar / SkeletonImage / SkeletonButton / SkeletonInput / SkeletonParagraph` 各自的 Props 可在 [`skeleton.tsx`](./skeleton.tsx) 查看。
60
-
61
60
  ## AI 生成纪律
62
61
 
63
62
  - **形状要与最终内容匹配**:文本用 `shape="line"`,头像用 `<SkeletonAvatar />`,图片用 `<SkeletonImage />`,**不要**全用矩形糊弄
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import {
3
3
  Skeleton,
4
4
  SkeletonAvatar,
@@ -9,14 +9,14 @@ import {
9
9
  } from './skeleton';
10
10
 
11
11
  const meta: Meta<typeof Skeleton> = {
12
- title: '基础原语 · Foundation/Skeleton',
12
+ title: '反馈 · Feedback/Skeleton',
13
13
  component: Skeleton,
14
14
  tags: ['autodocs'],
15
15
  parameters: {
16
16
  docs: {
17
17
  description: {
18
18
  component:
19
- '骨架屏 — 在内容加载过程中呈现占位图形,减少加载期间的视觉跳动。shadcn `Skeleton` 原子 + antd `Skeleton` 的能力并集:除原子 `Skeleton`(支持 `shape: rect | circle | line`)外,同时提供预设组合 `SkeletonAvatar` / `SkeletonImage` / `SkeletonButton` / `SkeletonInput` / `SkeletonParagraph`。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/design`,无 mock。',
19
+ '骨架屏 — 在内容加载过程中呈现占位图形,减少加载期间的视觉跳动。shadcn `Skeleton` 原子 + antd 能力并集:支持 `shape: rect | circle | line`,同时提供预设组合 `SkeletonAvatar` / `SkeletonImage` / `SkeletonButton` / `SkeletonInput` / `SkeletonParagraph`。',
20
20
  },
21
21
  },
22
22
  },
@@ -58,7 +58,7 @@ export const Family: Story = {
58
58
  export const Card: Story = {
59
59
  parameters: { controls: { disable: true } },
60
60
  render: () => (
61
- <div className="w-80 rounded-lg border p-4">
61
+ <div className="w-80 rounded-lg border border-border p-4">
62
62
  <SkeletonImage />
63
63
  <SkeletonParagraph rows={3} className="mt-3" />
64
64
  </div>
@@ -43,11 +43,12 @@ Skeleton.displayName = 'Skeleton';
43
43
 
44
44
  export interface SkeletonAvatarProps extends Omit<SkeletonProps, 'shape'> {
45
45
  /** 尺寸:小 32 / 默认 40 / 大 64。 @default "default" */
46
- size?: 'sm' | 'default' | 'lg';
46
+ size?: 'sm' | 'md' | 'default' | 'lg';
47
47
  }
48
48
  const SkeletonAvatar = React.forwardRef<HTMLDivElement, SkeletonAvatarProps>(
49
- ({ size = 'default', className, ...props }, ref) => {
50
- const dim = size === 'sm' ? 'size-8' : size === 'lg' ? 'size-16' : 'size-10';
49
+ ({ size = 'md', className, ...props }, ref) => {
50
+ const dim =
51
+ size === 'sm' ? 'size-8' : size === 'lg' ? 'size-16' : 'size-10';
51
52
  return (
52
53
  <Skeleton
53
54
  ref={ref}
@@ -74,10 +75,10 @@ const SkeletonImage = React.forwardRef<HTMLDivElement, SkeletonImageProps>(
74
75
  SkeletonImage.displayName = 'SkeletonImage';
75
76
 
76
77
  export interface SkeletonButtonProps extends Omit<SkeletonProps, 'shape'> {
77
- size?: 'sm' | 'default' | 'lg';
78
+ size?: 'sm' | 'md' | 'default' | 'lg';
78
79
  }
79
80
  const SkeletonButton = React.forwardRef<HTMLDivElement, SkeletonButtonProps>(
80
- ({ size = 'default', className, ...props }, ref) => {
81
+ ({ size = 'md', className, ...props }, ref) => {
81
82
  const h = size === 'sm' ? 'h-8' : size === 'lg' ? 'h-10' : 'h-9';
82
83
  return (
83
84
  <Skeleton
@@ -104,8 +105,7 @@ const SkeletonInput = React.forwardRef<HTMLDivElement, SkeletonInputProps>(
104
105
  );
105
106
  SkeletonInput.displayName = 'SkeletonInput';
106
107
 
107
- export interface SkeletonParagraphProps
108
- extends Omit<SkeletonProps, 'shape'> {
108
+ export interface SkeletonParagraphProps extends Omit<SkeletonProps, 'shape'> {
109
109
  /**
110
110
  * 段落行数。最后一行宽度自动收窄至 60%,模拟自然段尾。
111
111
  * @default 3
@@ -1,13 +1,14 @@
1
1
  ---
2
2
  id: slider
3
3
  name: Slider
4
+ displayName: 滑块
4
5
  type: component
5
- category: form
6
+ category: data-entry
6
7
  since: 0.1.0
7
8
  package: '@teamix-evo/ui'
8
9
  ---
9
10
 
10
- # Slider
11
+ # Slider 滑块
11
12
 
12
13
  滑块 — Radix Slider + antd 的 `marks` 刻度标签。**单 / 双滑块由 `value`/`defaultValue` 数组长度决定**(传 `[lo, hi]` 自动变范围滑块)。
13
14
 
@@ -30,7 +31,21 @@ package: '@teamix-evo/ui'
30
31
  <!-- auto:props:begin -->
31
32
  | 名称 | 类型 | 默认值 | 必填 | 说明 |
32
33
  | --- | --- | --- | --- | --- |
33
- | `marks` | `Record<number, React.ReactNode>` | – | – | 刻度标记(antd `marks` 并集)。键为 0~max 的数值,值为标签文本。 渲染时小标记点 + 文字标签出现在轨道下方。 |
34
+ | `value` | `number[]` | – | – | 受控 value — **必为数组**,单滑块 `[v]`,范围滑块 `[lo, hi]`(单/双由数组长度决定) `defaultValue` 二选一。 |
35
+ | `defaultValue` | `number[]` | – | – | 非受控初始值。同样数组形态(单/双由长度决定)。 |
36
+ | `onValueChange` | `(value: number[]) => void` | – | – | 滑块拖动 / 步进时触发(实时,频率高)。 业务表单层用 `onValueCommit` 拿到最终值更省心。 |
37
+ | `onValueCommit` | `(value: number[]) => void` | – | – | 拖动结束(mouse up / key up)时触发一次,适合"提交"语义。 |
38
+ | `min` | `number` | `0` | – | 最小值。 |
39
+ | `max` | `number` | `100` | – | 最大值。 |
40
+ | `step` | `number` | `1` | – | 步进单位(键盘 ←→ / 拖动吸附)。 |
41
+ | `disabled` | `boolean` | `false` | – | 禁用整个 Slider(灰化 + 不响应交互)。 |
42
+ | `orientation` | `'horizontal' \| 'vertical'` | `"horizontal"` | – | 排列方向(键盘导航方向跟随)。 |
43
+ | `inverted` | `boolean` | `false` | – | 反向滚动(从右往左 / 从下往上)。 |
44
+ | `name` | `string` | – | – | 表单字段名(原生 `<input name>`)。 |
45
+ | `marks` | `Record<number, React.ReactNode>` | – | – | 刻度标记(antd `marks` 并集)。键为 0~max 的数值,值为标签文本。 渲染时小标记点 + 文字标签出现在轨道下方(默认)或上方(`marksPosition="above"`)。 |
46
+ | `marksPosition` | `'above' \| 'below'` | `"below"` | – | 刻度文字位置(cloud-design `marksPosition` 并集) — `"below"` 在轨道下方,`"above"` 在轨道上方。 |
47
+ | `tooltipVisible` | `boolean` | `false` | – | 是否常驻显示当前值的 tooltip(cloud-design `tooltipVisible` 并集) — `true` 时所有 thumb 都会持续显示数值气泡;`false` 时仅在 hover / drag 时显示(默认)。 |
48
+ | `tipRender` | `(value: number) => React.ReactNode` | – | – | 自定义 tooltip 渲染函数(cloud-design `tipRender` 并集)。 不传时直接渲染数值。 |
34
49
  <!-- auto:props:end -->
35
50
 
36
51
  ## 依赖
@@ -66,8 +81,10 @@ pnpm add @radix-ui/react-slider@^1.2.0
66
81
  - **`step` 跨度的可访问性**:键盘 Page Up/Down 步进 = step × 10,设计 step 时考虑这一点
67
82
  - **marks 的"圆点"和"文字"必须分两层渲染,不要打包成一个 box**:
68
83
  - **圆点**:`absolute top-1/2 -translate-x-1/2 -translate-y-1/2` 居中压在 track 中线上,渲染在 `<SliderPrimitive.Root>` 内、`<Track>` 之外(放进 Track 内会被 `overflow-hidden` 裁掉或被 `Range` 高亮覆盖)
69
- - **文字**:独立放在父容器 `bottom-0` 处,通过父容器 `pb-6` 留出 ~14px 间距;不要用 `mt-1` 把文字直接挂在圆点下方,会出现"点和文字粘在一起"的视觉 bug(对照 antd 标准:点压 track、文字距 track ~12px)
84
+ - **文字**:独立放在父容器 `bottom-0`(默认)或 `top-0`(`marksPosition="above"`)处,通过父容器 `pb-6` / `pt-6` 留出 ~14px 间距;不要用 `mt-1` 把文字直接挂在圆点下方,会出现"点和文字粘在一起"的视觉 bug
70
85
  - **`<Thumb>` 必须加 `relative z-10`**:让滑块视觉层级高于 marks 圆点,避免拖动时圆点突兀露在 thumb 之上
86
+ - **`tooltipVisible` 为展示能力**:常驻气泡不要氪加在表单表中使用(气泡会遮住上方行);需要 `tipRender` 定制显示内容时请传函数而非 ReactNode
87
+ - **`marksPosition="above"` 与拖拽 tooltip 会重叠**:同时开启 `marksPosition="above"` 和 `tooltipVisible=true` 时,拖拽气泡会与上方 marks 文字压在一起 — 建议二者选一
71
88
 
72
89
  ## Examples
73
90
 
@@ -80,7 +97,7 @@ import { Slider } from '@/components/ui/slider';
80
97
  // 范围滑块
81
98
  <Slider defaultValue={[20, 80]} max={100} step={1} />
82
99
 
83
- // 带刻度标签
100
+ // 带刻度标签(下方)
84
101
  <Slider
85
102
  defaultValue={[40]}
86
103
  max={100}
@@ -88,7 +105,42 @@ import { Slider } from '@/components/ui/slider';
88
105
  marks={{ 0: '0°C', 20: '20', 40: '40', 60: '60', 80: '80', 100: '100°C' }}
89
106
  />
90
107
 
108
+ // 刻度上方
109
+ <Slider defaultValue={[40]} marksPosition="above" marks={{ 0: '0', 50: '50', 100: '100' }} />
110
+
111
+ // 常驻数值气泡
112
+ <Slider defaultValue={[42]} tooltipVisible />
113
+
114
+ // 自定义 tooltip
115
+ <Slider defaultValue={[1500]} max={5000} tooltipVisible tipRender={(v) => `¥${v}`} />
116
+
91
117
  // 受控
92
118
  const [v, setV] = React.useState([50]);
93
119
  <Slider value={v} onValueChange={setV} max={100} />
94
120
  ```
121
+
122
+ ## Range 形态 — 旧库 API → 新库映射
123
+
124
+ > 旧库(Teamix 1.0 / `@alifd/next.Range`)→ 新库 `Slider`(Radix `@radix-ui/react-slider` 底层 + antd `marks` 并集)。新库**单/双滑块由数据形态决定** — 不再有独立的 `slider="single|double"` prop。
125
+
126
+ | 旧库 API | 新库 API | 备注 |
127
+ | --- | --- | --- |
128
+ | 组件名 `Range` | `Slider` | 对齐 shadcn / Radix 命名 |
129
+ | `slider="single"` | `defaultValue={[v]}` | 数据决定 — 数组长度 = 1 即单滑块 |
130
+ | `slider="double"` | `defaultValue={[lo, hi]}` | 数组长度 = 2 即范围滑块 |
131
+ | `onChange(number \| [n,n])` | `onValueChange(number[])` | 始终数组,Radix 命名 |
132
+ | `onProcess` 实时触发 | `onValueChange` | 同一回调,实时触发(Radix 内部) |
133
+ | `reverse` | `inverted`(透传 Radix Root) | Radix 命名 |
134
+ | `marks={5}` 数字密度 | 不修复 — 仅支持 `Record<number, ReactNode>` | 业务自构造 marks 对象 |
135
+ | `marks=true` boolean | 不修复 — 同上 | 业务自构造 |
136
+ | `marks=[5, 50, 100]` array | 不修复 — 同上 | 业务自构造 |
137
+ | `tooltipVisible` | `tooltipVisible` | 同名 |
138
+ | `tipRender` | `tipRender` | 同名 |
139
+ | `fixedWidth` 固定宽度拖动 | 不修复 | 极少使用,P3 |
140
+ | `pure` 纯渲染 | 不修复 | `React.memo` 由消费方按需包裹 |
141
+
142
+ ### 不修复 / 后续工序清单
143
+
144
+ - **`slider` prop**:不修复 — 数组形态本身已是更直观的 API
145
+ - **`marks` 多类型签名**:仅保留 Object 形式,boolean / number / Array 由业务侧自行构造 marks 对象
146
+ - **`fixedWidth`** / **`pure`**:报告 §5 已列入"保留新库优势",**不修复**
@@ -1,15 +1,15 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import { Slider } from './slider';
3
3
 
4
4
  const meta: Meta<typeof Slider> = {
5
- title: '表单与输入 · Form/Slider',
5
+ title: '数据录入 · Data Entry/Slider',
6
6
  component: Slider,
7
7
  tags: ['autodocs'],
8
8
  parameters: {
9
9
  docs: {
10
10
  description: {
11
11
  component:
12
- '滑块 — 在给定范围内选取一个数值或一段区间。Radix Slider 实现 + antd `marks` 刻度能力:`value` / `defaultValue` 为数组,长度为 1 时为单滑块、为 2 时自动切换为区间滑块;可配 `marks` 渲染轨道下方的刻度点与标签。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/design`,无 mock。',
12
+ '滑块 — 在给定范围内选取一个数值或一段区间。Radix Slider 实现 + antd `marks` 刻度 ∪ cloud-design `marksPosition` / `tooltipVisible` / `tipRender` 并集能力:`value` / `defaultValue` 为数组,长度为 1 时为单滑块、为 2 时自动切换为区间滑块;可配 `marks` 渲染轨道下方(默认)或上方(`marksPosition="above"`)的刻度点与标签,`tooltipVisible` 控制数值气泡是否常驻。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/tokens`,无 mock。',
13
13
  },
14
14
  },
15
15
  },
@@ -18,11 +18,20 @@ const meta: Meta<typeof Slider> = {
18
18
  max: { control: 'number' },
19
19
  step: { control: 'number' },
20
20
  disabled: { control: 'boolean' },
21
+ tooltipVisible: { control: 'boolean' },
22
+ marksPosition: { control: 'inline-radio', options: ['below', 'above'] },
23
+ },
24
+ args: {
25
+ defaultValue: [42],
26
+ min: 0,
27
+ max: 100,
28
+ step: 1,
29
+ tooltipVisible: false,
30
+ marksPosition: 'below',
21
31
  },
22
- args: { defaultValue: [42], min: 0, max: 100, step: 1 },
23
32
  decorators: [
24
33
  (Story) => (
25
- <div className="w-80">
34
+ <div className="w-80 px-2">
26
35
  <Story />
27
36
  </div>
28
37
  ),
@@ -39,7 +48,7 @@ export const Range: Story = {
39
48
  render: () => <Slider defaultValue={[20, 80]} max={100} />,
40
49
  };
41
50
 
42
- export const WithMarks: Story = {
51
+ export const WithMarksBelow: Story = {
43
52
  parameters: { controls: { disable: true } },
44
53
  render: () => (
45
54
  <Slider
@@ -58,6 +67,49 @@ export const WithMarks: Story = {
58
67
  ),
59
68
  };
60
69
 
70
+ export const WithMarksAbove: Story = {
71
+ parameters: { controls: { disable: true } },
72
+ render: () => (
73
+ <Slider
74
+ defaultValue={[40]}
75
+ max={100}
76
+ step={20}
77
+ marksPosition="above"
78
+ marks={{
79
+ 0: '0',
80
+ 20: '20',
81
+ 40: '40',
82
+ 60: '60',
83
+ 80: '80',
84
+ 100: '100',
85
+ }}
86
+ />
87
+ ),
88
+ };
89
+
90
+ export const TooltipAlwaysVisible: Story = {
91
+ parameters: { controls: { disable: true } },
92
+ render: () => (
93
+ <div className="flex flex-col gap-10">
94
+ <Slider defaultValue={[42]} tooltipVisible />
95
+ <Slider defaultValue={[20, 80]} tooltipVisible />
96
+ </div>
97
+ ),
98
+ };
99
+
100
+ export const TooltipWithRender: Story = {
101
+ parameters: { controls: { disable: true } },
102
+ render: () => (
103
+ <Slider
104
+ defaultValue={[1500]}
105
+ max={5000}
106
+ step={100}
107
+ tooltipVisible
108
+ tipRender={(v) => `¥${v.toLocaleString()}`}
109
+ />
110
+ ),
111
+ };
112
+
61
113
  export const Disabled: Story = {
62
114
  parameters: { controls: { disable: true } },
63
115
  render: () => (
@@ -4,12 +4,89 @@ import * as SliderPrimitive from '@radix-ui/react-slider';
4
4
  import { cn } from '@/utils/cn';
5
5
 
6
6
  export interface SliderProps
7
- extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {
7
+ extends Omit<
8
+ React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,
9
+ | 'value'
10
+ | 'defaultValue'
11
+ | 'onValueChange'
12
+ | 'onValueCommit'
13
+ | 'min'
14
+ | 'max'
15
+ | 'step'
16
+ | 'disabled'
17
+ | 'orientation'
18
+ | 'inverted'
19
+ | 'name'
20
+ > {
21
+ /**
22
+ * 受控 value — **必为数组**,单滑块 `[v]`,范围滑块 `[lo, hi]`(单/双由数组长度决定)。
23
+ * 与 `defaultValue` 二选一。
24
+ */
25
+ value?: number[];
26
+ /** 非受控初始值。同样数组形态(单/双由长度决定)。 */
27
+ defaultValue?: number[];
28
+ /**
29
+ * 滑块拖动 / 步进时触发(实时,频率高)。
30
+ * 业务表单层用 `onValueCommit` 拿到最终值更省心。
31
+ */
32
+ onValueChange?: (value: number[]) => void;
33
+ /**
34
+ * 拖动结束(mouse up / key up)时触发一次,适合"提交"语义。
35
+ */
36
+ onValueCommit?: (value: number[]) => void;
37
+ /**
38
+ * 最小值。
39
+ * @default 0
40
+ */
41
+ min?: number;
42
+ /**
43
+ * 最大值。
44
+ * @default 100
45
+ */
46
+ max?: number;
47
+ /**
48
+ * 步进单位(键盘 ←→ / 拖动吸附)。
49
+ * @default 1
50
+ */
51
+ step?: number;
52
+ /**
53
+ * 禁用整个 Slider(灰化 + 不响应交互)。
54
+ * @default false
55
+ */
56
+ disabled?: boolean;
57
+ /**
58
+ * 排列方向(键盘导航方向跟随)。
59
+ * @default "horizontal"
60
+ */
61
+ orientation?: 'horizontal' | 'vertical';
62
+ /**
63
+ * 反向滚动(从右往左 / 从下往上)。
64
+ * @default false
65
+ */
66
+ inverted?: boolean;
67
+ /** 表单字段名(原生 `<input name>`)。 */
68
+ name?: string;
8
69
  /**
9
70
  * 刻度标记(antd `marks` 并集)。键为 0~max 的数值,值为标签文本。
10
- * 渲染时小标记点 + 文字标签出现在轨道下方。
71
+ * 渲染时小标记点 + 文字标签出现在轨道下方(默认)或上方(`marksPosition="above"`)。
11
72
  */
12
73
  marks?: Record<number, React.ReactNode>;
74
+ /**
75
+ * 刻度文字位置(cloud-design `marksPosition` 并集) — `"below"` 在轨道下方,`"above"` 在轨道上方。
76
+ * @default "below"
77
+ */
78
+ marksPosition?: 'above' | 'below';
79
+ /**
80
+ * 是否常驻显示当前值的 tooltip(cloud-design `tooltipVisible` 并集) —
81
+ * `true` 时所有 thumb 都会持续显示数值气泡;`false` 时仅在 hover / drag 时显示(默认)。
82
+ * @default false
83
+ */
84
+ tooltipVisible?: boolean;
85
+ /**
86
+ * 自定义 tooltip 渲染函数(cloud-design `tipRender` 并集)。
87
+ * 不传时直接渲染数值。
88
+ */
89
+ tipRender?: (value: number) => React.ReactNode;
13
90
  }
14
91
 
15
92
  const Slider = React.forwardRef<
@@ -17,19 +94,51 @@ const Slider = React.forwardRef<
17
94
  SliderProps
18
95
  >(
19
96
  (
20
- { className, marks, value, defaultValue, min = 0, max = 100, ...props },
97
+ {
98
+ className,
99
+ marks,
100
+ marksPosition = 'below',
101
+ tooltipVisible = false,
102
+ tipRender,
103
+ value,
104
+ defaultValue,
105
+ min = 0,
106
+ max = 100,
107
+ onValueChange,
108
+ ...props
109
+ },
21
110
  ref,
22
111
  ) => {
23
- // Radix Slider supports range natively when `value` / `defaultValue` is array of length 2.
24
- const thumbCount = (value ?? defaultValue ?? [0]).length;
112
+ // / 双滑块由 value/defaultValue 数组长度决定
113
+ const initial = (value ?? defaultValue ?? [0]) as number[];
114
+ const [internal, setInternal] = React.useState<number[]>(initial);
115
+ const isControlled = value !== undefined;
116
+ const current = isControlled ? (value as number[]) : internal;
117
+
118
+ const handleValueChange = (next: number[]) => {
119
+ if (!isControlled) setInternal(next);
120
+ onValueChange?.(next);
121
+ };
122
+
123
+ const thumbCount = current.length;
124
+ const showAboveMarks = marks && marksPosition === 'above';
125
+ const showBelowMarks = marks && marksPosition === 'below';
126
+
25
127
  return (
26
- <div className={cn('relative w-full', marks ? 'pb-6' : '')}>
128
+ <div
129
+ className={cn(
130
+ 'relative w-full',
131
+ showBelowMarks && 'pb-6',
132
+ showAboveMarks && 'pt-6',
133
+ )}
134
+ >
27
135
  <SliderPrimitive.Root
28
136
  ref={ref}
29
137
  value={value}
30
138
  defaultValue={defaultValue}
31
139
  min={min}
32
140
  max={max}
141
+ onValueChange={handleValueChange}
33
142
  className={cn(
34
143
  'relative flex w-full touch-none select-none items-center',
35
144
  className,
@@ -53,15 +162,47 @@ const Slider = React.forwardRef<
53
162
  );
54
163
  })
55
164
  : null}
56
- {Array.from({ length: thumbCount }).map((_, i) => (
57
- <SliderPrimitive.Thumb
58
- key={i}
59
- className="relative z-10 block size-4 rounded-full border-2 border-primary bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
60
- />
61
- ))}
165
+ {Array.from({ length: thumbCount }).map((_, i) => {
166
+ const v = current[i] ?? 0;
167
+ const display = tipRender ? tipRender(v) : v;
168
+ return (
169
+ <SliderPrimitive.Thumb
170
+ key={i}
171
+ className="group relative z-10 block size-4 rounded-full border-2 border-primary bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
172
+ >
173
+ {tooltipVisible ? (
174
+ <span
175
+ className={cn(
176
+ // 常驻气泡:thumb 上方 ~8px,带轻微小三角效果(用 box-shadow 做箭头有点冗余,简化为圆角矩形)
177
+ 'pointer-events-none absolute -top-8 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md bg-foreground px-2 py-0.5 text-xs font-medium text-background shadow-md',
178
+ )}
179
+ aria-hidden
180
+ >
181
+ {display}
182
+ </span>
183
+ ) : (
184
+ <span
185
+ className={cn(
186
+ // 仅 hover / focus / active 时显示
187
+ 'pointer-events-none absolute -top-8 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md bg-foreground px-2 py-0.5 text-xs font-medium text-background opacity-0 shadow-md transition-opacity',
188
+ 'group-hover:opacity-100 group-focus-visible:opacity-100 group-data-[state=active]:opacity-100',
189
+ )}
190
+ aria-hidden
191
+ >
192
+ {display}
193
+ </span>
194
+ )}
195
+ </SliderPrimitive.Thumb>
196
+ );
197
+ })}
62
198
  </SliderPrimitive.Root>
63
199
  {marks ? (
64
- <div className="pointer-events-none absolute inset-x-0 bottom-0 h-4">
200
+ <div
201
+ className={cn(
202
+ 'pointer-events-none absolute inset-x-0 h-4',
203
+ marksPosition === 'above' ? 'top-0' : 'bottom-0',
204
+ )}
205
+ >
65
206
  {Object.entries(marks).map(([k, label]) => {
66
207
  const num = Number(k);
67
208
  const pct = ((num - min) / (max - min)) * 100;
@@ -4,14 +4,15 @@ name: Sonner
4
4
  type: component
5
5
  category: feedback
6
6
  since: 0.1.0
7
- package: "@teamix-evo/ui"
7
+ package: '@teamix-evo/ui'
8
+ displayName: 轻提示
8
9
  ---
9
10
 
10
- # Sonner
11
+ # Sonner 轻提示
11
12
 
12
13
  Toast 通知 — 基于 [`sonner`](https://sonner.emilkowal.ski/),已**同时覆盖** antd `message`(行内简短)+ `notification`(标题 + 描述 + 行动)的并集。
13
14
 
14
- **应用根挂 `<Toaster />` 一次**,在任意地方 `import { toast } from '@/components/ui/sonner'` 触发。
15
+ **应用根挂 `<Toaster />` 一次**,在任意地方 `import { toast } from '@/components/ui/sonner'` 触发。视觉走 OpenTrek tokens —— **无边框、纯 shadow 分界、面性(filled)状态图标**;`success` / `error` / `warning` / `info` / `loading` 五种状态各有对应配色与实心图标。
15
16
 
16
17
  ## When to use
17
18
 
@@ -31,7 +32,16 @@ Toast 通知 — 基于 [`sonner`](https://sonner.emilkowal.ski/),已**同时覆
31
32
  > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。下表是 `<Toaster />` 的 props。`toast()` 函数式 API 见下方 Examples。
32
33
 
33
34
  <!-- auto:props:begin -->
34
- _(no props)_
35
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
36
+ | --- | --- | --- | --- | --- |
37
+ | `position` | `SonnerProps['position']` | `"top-right"` | – | Toast 弹出位置(对齐 antd `message.config.placement`)。 |
38
+ | `duration` | `number` | `4000` | – | 自动消失时长(ms)— 0 表示常驻不自动关闭。 |
39
+ | `visibleToasts` | `number` | `3` | – | 同屏最大可见 toast 数(超出旧的自动收起)。 |
40
+ | `expand` | `boolean` | `false` | – | 鼠标 hover 时是否展开堆叠的 toast(否则保持折叠堆叠状)。 |
41
+ | `richColors` | `boolean` | `false` | – | 启用 sonner 自带的"丰富配色"(更高对比度的状态色背景); 关闭则走我们的视觉(对齐 OpenTrek tokens)。 |
42
+ | `closeButton` | `boolean` | `false` | – | 每张 toast 是否显示关闭按钮(右上角 ×)。 |
43
+ | `theme` | `SonnerProps['theme']` | – | – | 主题 — `'light'` / `'dark'` / `'system'`(跟随 OS 偏好)。 通常无需手传,组件会跟随 `<html>` 上的 `.dark` class 自动切换。 |
44
+ | `dir` | `SonnerProps['dir']` | `"auto"` | – | 文字方向 — `'ltr'` / `'rtl'` / `'auto'`。 |
35
45
  <!-- auto:props:end -->
36
46
 
37
47
  ## 依赖
@@ -41,14 +51,18 @@ _(no props)_
41
51
  <!-- auto:deps:begin -->
42
52
  ### 同库依赖
43
53
 
44
- _无 本组件不依赖其他 ui entry。_
54
+ > `teamix-evo ui add sonner` 时,以下 entry 会被自动连带安装(无需手动 add)
55
+
56
+ | Entry | 类型 | 描述 |
57
+ | --- | --- | --- |
58
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
45
59
 
46
60
  ### npm 依赖
47
61
 
48
62
  > 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
49
63
 
50
64
  ```bash
51
- pnpm add sonner@^1.5.0
65
+ pnpm add sonner@^1.5.0 lucide-react@^0.460.0
52
66
  ```
53
67
  <!-- auto:deps:end -->
54
68
 
@@ -61,6 +75,8 @@ pnpm add sonner@^1.5.0
61
75
  - **错误用 `toast.error()`**:语义化方法比 `toast({ type: 'error' })` 优先
62
76
  - **长任务用 `toast.promise()`**:自动显示 loading → success / error,避免手写状态切换
63
77
  - **Action 按钮用一个就够**:不要塞多个,过载
78
+ - **不要覆盖 `icons` / `richColors`**:本组件已用面性 lucide 图标 + OpenTrek tokens 处理 5 种状态配色,自行传 `richColors` 会与既有样式冲突;如需自定义图标,通过传入的 `toastOptions.classNames.icon` / `icons` 在外层精细覆盖
79
+ - **禁用边框样式**:卡片默认 `border-0 + shadow-lg`,不要再加 `border` —— 与轻提示克制美学冲突
64
80
 
65
81
  ## Examples
66
82
 
@@ -68,7 +84,7 @@ pnpm add sonner@^1.5.0
68
84
  import { Toaster, toast } from '@/components/ui/sonner';
69
85
 
70
86
  // 应用根
71
- <Toaster position="top-right" richColors />
87
+ <Toaster position="top-right" richColors />;
72
88
 
73
89
  // 简单消息(等价 antd message)
74
90
  toast('已复制到剪贴板');
@@ -94,3 +110,38 @@ toast('文件已删除', {
94
110
  action: { label: '撤销', onClick: () => undo() },
95
111
  });
96
112
  ```
113
+
114
+ ---
115
+
116
+ ## Message 形态 — 旧库 API → 新映射
117
+
118
+ > 旧库 `Message`(hybridcloud,含 show/success/error/confirm 等命令式) → 新库 `toast()`(命令式) + `Alert`(内联常驻)。
119
+ > 新库用 [sonner](https://sonner.emilkowal.ski/) 三方库,已自定义视觉(OpenTrek tokens + 面性图标)。
120
+
121
+ ### 命名 & 结构映射
122
+
123
+ | 旧库 | 新库 | 说明 |
124
+ | ------------------------------ | ----------------------------------------------- | ------------------------------- |
125
+ | `Message shape='toast'` | `toast()` | 命令式轻提示 |
126
+ | `Message shape='inline'` | `Alert` 组件 | 内联常驻提示(独立 entry) |
127
+ | `Message.success(msg)` | `toast.success(msg)` | 直接映射 |
128
+ | `Message.error(msg)` | `toast.error(msg)` | 直接映射 |
129
+ | `Message.warning(msg)` | `toast.warning(msg)` | 直接映射 |
130
+ | `Message.notice(msg)` | `toast.info(msg)` | notice → info |
131
+ | `Message.loading(msg)` | `toast.loading(msg)` | 直接映射 |
132
+ | `Message.hide()` | `toast.dismiss()` | 全局关闭 |
133
+ | `Message.config({ duration })` | `<Toaster duration={...} />` | 声明式配置 |
134
+ | `closeable` | `closeButton`(Toaster prop) | 拼写变更 |
135
+ | `type='help'` | `toast.info()` | 映射到 info |
136
+ | Promise 自动切换 | `toast.promise(p, { loading, success, error })` | 新增能力(P0) |
137
+ | `title + content` | `toast.success(title, { description })` | title 第一参,description 第二参 |
138
+ | `action` | `toast(msg, { action: { label, onClick } })` | 行动按钮 |
139
+
140
+ ### 迁移 FAQ
141
+
142
+ | 问题 | 回答 |
143
+ | -------------------------- | -------------------------------------------------- |
144
+ | 内联提示怎么做? | 用 `Alert` 组件(非 toast),常驻在页面上 |
145
+ | Toaster 放哪? | 应用根组件放一次即可,如 `layout.tsx` |
146
+ | 怎么控制位置? | `<Toaster position="top-right" />` |
147
+ | Message.hide(id) 关闭指定? | `const id = toast.loading(...); toast.dismiss(id)` |