@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
@@ -0,0 +1,153 @@
1
+ import * as React from 'react';
2
+
3
+ import { cn } from '@/utils/cn';
4
+ import {
5
+ TooltipContent,
6
+ TooltipProvider,
7
+ TooltipRoot,
8
+ TooltipTrigger,
9
+ } from '@/components/tooltip/tooltip';
10
+
11
+ export interface EllipsisProps
12
+ extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'title'> {
13
+ /**
14
+ * 超长时显示的 tooltip 文本 — 不传时自动用 children 的纯文本(优先)或 `title` 属性。
15
+ * 显示规则:仅当实际渲染时检测到溢出(scrollWidth > clientWidth 或 scrollHeight > clientHeight)才挂载 Tooltip。
16
+ */
17
+ tooltip?: React.ReactNode;
18
+ /**
19
+ * 多行截断行数。传入数字 >1 时走 `-webkit-line-clamp` 多行模式;否则单行 truncate。
20
+ * @default 1
21
+ */
22
+ lines?: number;
23
+ /**
24
+ * 是否在文本右侧叠加渐变遮罩(对齐《Teamix UI 表单设计规范》§八 "截断 + 渐变遮罩 + hover tooltip 三件套")。
25
+ * 默认开启;在容器无溢出时 mask 自动隐藏(scrollWidth ≤ clientWidth)。
26
+ * @default true
27
+ */
28
+ fade?: boolean;
29
+ /**
30
+ * Tooltip 弹出方向。
31
+ * @default 'top'
32
+ */
33
+ tooltipSide?: 'top' | 'right' | 'bottom' | 'left';
34
+ }
35
+
36
+ /**
37
+ * `Ellipsis` 单行 / 多行文本截断 + 渐变遮罩 + 溢出时自动 tooltip 提示。
38
+ *
39
+ * 对齐《Teamix UI 表单设计规范》§八 "内容显示不完全 — 截断 + 渐变遮罩 + hover tooltip 三件套"。
40
+ *
41
+ * @example
42
+ * <Ellipsis>这一段超长文本会自动截断、右侧带渐变遮罩,hover 弹 tooltip 看全文</Ellipsis>
43
+ *
44
+ * @example // 多行
45
+ * <Ellipsis lines={2}>...</Ellipsis>
46
+ *
47
+ * @example // 显式 tooltip 内容
48
+ * <Ellipsis tooltip="完整内容...">概要</Ellipsis>
49
+ */
50
+ const Ellipsis = React.forwardRef<HTMLSpanElement, EllipsisProps>(
51
+ (
52
+ {
53
+ children,
54
+ tooltip,
55
+ lines = 1,
56
+ fade = true,
57
+ tooltipSide = 'top',
58
+ className,
59
+ style,
60
+ ...props
61
+ },
62
+ ref,
63
+ ) => {
64
+ const innerRef = React.useRef<HTMLSpanElement | null>(null);
65
+ const [overflowing, setOverflowing] = React.useState(false);
66
+
67
+ // 把外部 ref 与内部 ref 合并
68
+ const setRef = React.useCallback(
69
+ (node: HTMLSpanElement | null) => {
70
+ innerRef.current = node;
71
+ if (typeof ref === 'function') ref(node);
72
+ else if (ref) (ref as React.MutableRefObject<HTMLSpanElement | null>).current = node;
73
+ },
74
+ [ref],
75
+ );
76
+
77
+ // 监听容器尺寸变化,实时计算是否溢出
78
+ React.useEffect(() => {
79
+ const el = innerRef.current;
80
+ if (!el) return;
81
+ const check = () => {
82
+ setOverflowing(
83
+ el.scrollWidth > el.clientWidth ||
84
+ el.scrollHeight > el.clientHeight,
85
+ );
86
+ };
87
+ check();
88
+ const ro = new ResizeObserver(check);
89
+ ro.observe(el);
90
+ return () => ro.disconnect();
91
+ }, [children, lines]);
92
+
93
+ const isMulti = lines > 1;
94
+
95
+ const baseStyle: React.CSSProperties = isMulti
96
+ ? {
97
+ display: '-webkit-box',
98
+ WebkitLineClamp: lines,
99
+ WebkitBoxOrient: 'vertical',
100
+ overflow: 'hidden',
101
+ }
102
+ : {
103
+ display: 'block',
104
+ overflow: 'hidden',
105
+ whiteSpace: 'nowrap',
106
+ textOverflow: 'ellipsis',
107
+ };
108
+
109
+ // 渐变遮罩:仅在溢出时挂(避免短文本也带 mask)。
110
+ // mask 只用 alpha 通道,颜色字面量 black 是 CSS 关键字、非语义色,等价于 alpha=1。
111
+ const fadeStyle: React.CSSProperties =
112
+ fade && overflowing
113
+ ? {
114
+ maskImage:
115
+ 'linear-gradient(to right, black calc(100% - 2rem), transparent)',
116
+ WebkitMaskImage:
117
+ 'linear-gradient(to right, black calc(100% - 2rem), transparent)',
118
+ }
119
+ : {};
120
+
121
+ const node = (
122
+ <span
123
+ ref={setRef}
124
+ data-overflowing={overflowing ? '' : undefined}
125
+ style={{ ...baseStyle, ...fadeStyle, ...style }}
126
+ className={cn('min-w-0 max-w-full', className)}
127
+ {...props}
128
+ >
129
+ {children}
130
+ </span>
131
+ );
132
+
133
+ if (!overflowing) return node;
134
+
135
+ const tooltipBody = tooltip ?? children;
136
+
137
+ return (
138
+ <TooltipProvider delayDuration={200}>
139
+ <TooltipRoot>
140
+ <TooltipTrigger asChild>{node}</TooltipTrigger>
141
+ <TooltipContent side={tooltipSide}>
142
+ <div className="max-w-xs whitespace-normal break-words text-xs">
143
+ {tooltipBody}
144
+ </div>
145
+ </TooltipContent>
146
+ </TooltipRoot>
147
+ </TooltipProvider>
148
+ );
149
+ },
150
+ );
151
+ Ellipsis.displayName = 'Ellipsis';
152
+
153
+ export { Ellipsis };
@@ -2,12 +2,13 @@
2
2
  id: empty
3
3
  name: Empty
4
4
  type: component
5
- category: feedback
5
+ category: data-display
6
6
  since: 0.1.0
7
- package: "@teamix-evo/ui"
7
+ package: '@teamix-evo/ui'
8
+ displayName: 空状态
8
9
  ---
9
10
 
10
- # Empty
11
+ # Empty 空状态
11
12
 
12
13
  空状态 — antd 独有补足。**列表 / 表格 / 搜索结果为空**时的占位提示,提供引导动作鼓励用户创建首条数据。
13
14
 
@@ -23,15 +24,19 @@ package: "@teamix-evo/ui"
23
24
  - 错误 / 失败 → `Result` 或 `Alert`
24
25
  - 表单字段空 → 直接 placeholder
25
26
 
27
+ ## Props
28
+
26
29
  <!-- auto:props:begin -->
27
30
  | 名称 | 类型 | 默认值 | 必填 | 说明 |
28
31
  | --- | --- | --- | --- | --- |
29
32
  | `image` | `React.ReactNode` | – | – | 自定义图标(覆盖默认 Inbox)。 |
30
33
  | `description` | `React.ReactNode` | `"暂无数据"` | – | 描述文本。 |
31
34
  | `extra` | `React.ReactNode` | – | – | 操作区(放 Button 引导用户创建首条数据)。 |
32
- | `size` | `'sm' \| 'default'` | `"default"` | – | 尺寸 — `sm` 用于卡片内 / 表格空态;`default` 用于整区。 |
35
+ | `size` | `'sm' \| 'md' \| 'default'` | `"default"` | – | 尺寸 — `sm` 用于卡片内 / 表格空态;`default` 用于整区。 |
33
36
  <!-- auto:props:end -->
34
37
 
38
+ ## 依赖
39
+
35
40
  <!-- auto:deps:begin -->
36
41
  ### 同库依赖
37
42
 
@@ -1,17 +1,17 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import { Plus } from 'lucide-react';
3
3
  import { Empty } from './empty';
4
4
  import { Button } from '@/components/button/button';
5
5
 
6
6
  const meta: Meta<typeof Empty> = {
7
- title: '反馈与浮层 · Feedback/Empty',
7
+ title: '数据展示 · Data Display/Empty',
8
8
  component: Empty,
9
9
  tags: ['autodocs'],
10
10
  parameters: {
11
11
  docs: {
12
12
  description: {
13
13
  component:
14
- '空状态 — 列表 / 表格 / 搜索结果为空时的占位提示。提供 description 引导文案 + extra 主操作,鼓励用户创建首条数据。OpenTrek tokens 适配,等价 antd Empty。',
14
+ '空状态 — 列表 / 表格 / 搜索结果为空时的占位提示。提供 description 引导文案 + extra 主操作,鼓励用户创建首条数据。等价 antd Empty。',
15
15
  },
16
16
  },
17
17
  },
@@ -39,7 +39,7 @@ export const WithAction: Story = {
39
39
  export const Small: Story = {
40
40
  parameters: { controls: { disable: true } },
41
41
  render: () => (
42
- <div className="rounded-md border">
42
+ <div className="rounded-md border border-border">
43
43
  <Empty size="sm" description="无匹配的搜索结果" />
44
44
  </div>
45
45
  ),
@@ -14,12 +14,19 @@ export interface EmptyProps extends React.HTMLAttributes<HTMLDivElement> {
14
14
  * 尺寸 — `sm` 用于卡片内 / 表格空态;`default` 用于整区。
15
15
  * @default "default"
16
16
  */
17
- size?: 'sm' | 'default';
17
+ size?: 'sm' | 'md' | 'default';
18
18
  }
19
19
 
20
20
  const Empty = React.forwardRef<HTMLDivElement, EmptyProps>(
21
21
  (
22
- { image, description = '暂无数据', extra, size = 'default', className, ...props },
22
+ {
23
+ image,
24
+ description = '暂无数据',
25
+ extra,
26
+ size = 'md',
27
+ className,
28
+ ...props
29
+ },
23
30
  ref,
24
31
  ) => {
25
32
  const isSm = size === 'sm';
@@ -36,7 +43,7 @@ const Empty = React.forwardRef<HTMLDivElement, EmptyProps>(
36
43
  <div className={cn('opacity-40', isSm ? 'text-3xl' : 'text-5xl')}>
37
44
  {image ?? <Inbox className={isSm ? 'size-8' : 'size-16'} />}
38
45
  </div>
39
- <div className={cn(isSm ? 'text-xs' : 'text-sm')}>{description}</div>
46
+ <div className="text-xs">{description}</div>
40
47
  {extra ? <div className="mt-1">{extra}</div> : null}
41
48
  </div>
42
49
  );
@@ -1,13 +1,14 @@
1
1
  ---
2
2
  id: field
3
3
  name: Field
4
+ displayName: 表单字段
4
5
  type: component
5
- category: form
6
+ category: data-entry
6
7
  since: 0.1.0
7
- package: "@teamix-evo/ui"
8
+ package: '@teamix-evo/ui'
8
9
  ---
9
10
 
10
- # Field
11
+ # Field 表单字段
11
12
 
12
13
  通用表单字段抽象 — shadcn 2025-10 新增。**比 `Form` 更通用**:Form 强绑定 RHF + zod;Field 是纯 UI 抽象,跟任何状态管理(Server Actions / RHF / TanStack Form / 原生 form)都能搭。提供 7 个语义槽:`Field` 容器 / `FieldLabel` 标签 / `FieldDescription` 帮助文案 / `FieldError` 错误提示 / `FieldGroup` 多字段纵向容器 / `FieldSet` 带边框分组 / `FieldLegend` 分组标题。
13
14
 
@@ -22,13 +23,19 @@ package: "@teamix-evo/ui"
22
23
  - 已用 `Form`(RHF)并接受其约定 → 优先 `FormItem / FormLabel / FormMessage`(更紧)
23
24
  - 控件本身没有 label / description → 直接用 `Input` / `Select` 自由布局
24
25
 
26
+ ## Props
27
+
25
28
  <!-- auto:props:begin -->
26
29
  | 名称 | 类型 | 默认值 | 必填 | 说明 |
27
30
  | --- | --- | --- | --- | --- |
28
- | `orientation` | `'vertical' \| 'horizontal'` | `"vertical"` | – | 字段方向 — `vertical`(默认)Label 在控件上;`horizontal` Label 在控件左侧(配长表单)。 |
31
+ | `orientation` | `ResponsiveValue<FieldOrientation>` | `"vertical"` | – | 字段方向 — 标量或 5 档断点响应式映射: - `vertical`(默认)Label 在控件上; - `horizontal` Label 在控件左侧(配长表单); - 响应式对象 `{ base, xs, s, m, l, xl }` 按视口断点自动切换 (对齐设计规范 §4.2:单栏表单 < 432 应改上下结构)。 |
29
32
  | `invalid` | `boolean` | `false` | – | 标记字段为 invalid — 子组件的 ring / 文字色会跟随;同时把内部 `<FieldError>` 渲染为可见。 |
33
+ | `inputWidth` | `InputWidth` | – | – | 输入域宽度档位 — 5 档系统,对应 104 / 216 / 328 / 440 / 552 px。 通过 Context 下发,并在 Field 容器上注入 CSS 变量 `--field-input-width`,子组件可消费。 |
34
+ | `children` | `React.ReactNode` | – | – | – |
30
35
  <!-- auto:props:end -->
31
36
 
37
+ ## 依赖
38
+
32
39
  <!-- auto:deps:begin -->
33
40
  ### 同库依赖
34
41
 
@@ -38,6 +45,7 @@ package: "@teamix-evo/ui"
38
45
  | --- | --- | --- |
39
46
  | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
40
47
  | `label` | component | 表单字段标签 — Radix Label 包装,补 antd Form.Item 风格的 required / disabled 显式视觉 |
48
+ | `use-breakpoint` | hook | 响应式断点 hook + pickByBreakpoint 工具 — 5 档断点(432/672/944/1200/1600,对齐《Teamix UI 表单设计规范》§4.1),给 Field 响应式 orientation / FilterBarPanel 响应式列数共用 |
41
49
 
42
50
  ### npm 依赖
43
51
 
@@ -48,14 +56,44 @@ pnpm add class-variance-authority@^0.7.0
48
56
  ```
49
57
  <!-- auto:deps:end -->
50
58
 
59
+ ## 子组件
60
+
61
+ 除上表中的核心 Field 外,本包还提供以下表单骨架子组件:
62
+
63
+ - **`FieldGroup`**:多个 Field 的纵向容器。
64
+ - `density?: 'normal' | 'detail'`(默认 `normal`):
65
+ - `normal` → 20px 行距(`gap-5`,标准表单与混合详情)
66
+ - `detail` → 12px 行距(`gap-3`,纯详情页,对齐规范 §3.5)
67
+ - **`FieldSection`**:表单字段分组容器。
68
+ - `title`:组标题(14px medium),有值时渲染标题行。
69
+ - `columns?: 1 | 2 | 3 | 4`:多栏 grid 列数(留空走单列 `flex-col`),列内 `gap-x-4`(16px)/ 行间 `gap-y-5`(20px,对齐规范 §3.1 规则 4)。
70
+ - 多个 FieldSection 之间由父容器提供 `gap-8`(32px)。是 "账号信息 / 联系方式" 这种小节划分的首选(不要用裸 div + space-y-*)。
71
+ - **`FieldActions`**:表单操作按钮容器。
72
+ - `container?: 'page' | 'page-stepper' | 'modal' | 'drawer'`:容器场景预设(对齐规范 §六),一次性配齐 position/align/alignWithInput:
73
+ - `page` → inline + start + 基线对齐(页面基础/分组表单)
74
+ - `page-stepper` → sticky + start(页面分步表单)
75
+ - `modal` → inline + end(弹窗)
76
+ - `drawer` → sticky + start(抽屉)
77
+ - `position`:`'inline'` 底部跟随 / `'sticky'` 底部吸顶。未设时由 `container` 推导。
78
+ - `align`:`'start'` / `'end'`(默认 `end`)。未设时由 `container` 推导。
79
+ - `alignWithInput?: boolean`:水平表单(Field `orientation="horizontal"`)时让按钮起点对齐输入框左边界(规范 §六 "基础/分组表单按钮跟随基线对齐");通过 CSS 变量 `--form-label-width` 读取列宽,默认 `33.333%`。未设时由 `container` 推导。
80
+ - 代替裸 div + flex 手写。
81
+
51
82
  ## AI 生成纪律
52
83
 
53
- - **`invalid` 是单一真值**:置于 `<Field>`,内部 `FieldLabel` 会变红、`FieldError` 才可见;**不要**同时给控件再传 `aria-invalid`,重复
54
- - **`FieldError` children 为空时不渲染** 直接传可空字符串 / `errors?.email` 即可,无需条件渲染
55
- - **`FieldLabel required`** 仅视觉(红 *);**业务层必填**仍要在 schema / submit handler 校验
56
- - **`FieldSet disabled`** 利用原生 fieldset 的级联禁用 内部所有原生 input 都会失能;**不要**手动给每个控件传 disabled
84
+ - **`orientation` 支持响应式**:传 `ResponsiveValue<'vertical' | 'horizontal'>`,如 `{ base: 'vertical', xs: 'horizontal' }`(<432 上下、≥432 左右,对齐规范 §4.2 单栏自动切换)。底层走 `useBreakpoint`,SSR 首屏取 `base` 兜底。**不要**手写 `useMediaQuery` + 条件渲染。
85
+ - **`invalid` 是单一真值**:置于 `<Field>`,内部 `FieldLabel` 会变红、`FieldError` 才可见;**不要**同时给控件再传 `aria-invalid`,重复
86
+ - **`FieldError` children 为空时不渲染** 直接传可空字符串 / `errors?.email` 即可,无需条件渲染
87
+ - **`FieldLabel required`** 仅视觉(红 `*` **后置**在文字和 tooltip icon 右侧,顺序为 `文字 ⓘ *`);**业务层必填**仍要在 schema / submit handler 校验
88
+ - **`FieldSet disabled`** 利用原生 fieldset 的级联禁用 — 内部所有原生 input 都会失能;**不要**手动给每个控件传 disabled
57
89
  - **不要嵌套 `Field` in `Field`** — 那是 FieldGroup 的活
58
- - **与 `Form` 共存**:在 RHF 流程外的小表单(登录、邮件订阅)直接用 Field;复杂业务表单仍走 Form
90
+ - **与 `Form` 共存**:在 RHF 流程外的小表单(登录、邮件订阅)直接用 Field;复杂业务表单仍走 Form
91
+ - ✅ 使用 `inputWidth` 档位代替硬编码宽度值(不要手写 `w-[328px]` 或 `style={{ width: 328 }}`)
92
+ - ✅ 多字段分组必须使用 `FieldSection`(不要用裸 div + space-y-*)
93
+ - ✅ 操作按钮必须使用 `FieldActions`(不要用裸 div + flex);**根据所处容器优先用 `container` prop**(`page` / `page-stepper` / `modal` / `drawer`)而不是手设 position/align/alignWithInput,对齐规范 §六
94
+ - ✅ 多个 `FieldSection` 的父容器必须用 `gap-8`(32px 组间距)
95
+ - ✅ `orientation="horizontal"` 模式 Label 与 Input 间距固定为 **16px**(`gap-4`,组件内置);不要手动加 `gap-3` / `gap-5` 等覆盖
96
+ - ✅ horizontal 模式下 FieldLabel 自动 `max-width = ⅓ 输入域宽`(对齐规范 §七),超长 truncate;**显式 `maxWidth` 仍优先**。需要更长 label 时显式传 `maxWidth={数字 | 'XX%'}`
59
97
 
60
98
  ## Examples
61
99