@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.
- package/README.md +184 -184
- package/manifest.json +680 -492
- package/package.json +20 -10
- package/src/components/accordion/accordion.meta.md +5 -4
- package/src/components/accordion/accordion.stories.tsx +14 -9
- package/src/components/accordion/accordion.tsx +104 -8
- package/src/components/affix/affix.meta.md +20 -2
- package/src/components/affix/affix.stories.tsx +102 -25
- package/src/components/affix/affix.tsx +79 -9
- package/src/components/alert/alert.meta.md +44 -13
- package/src/components/alert/alert.stories.tsx +66 -21
- package/src/components/alert/alert.tsx +81 -34
- package/src/components/alert-dialog/alert-dialog.meta.md +61 -16
- package/src/components/alert-dialog/alert-dialog.stories.tsx +145 -3
- package/src/components/alert-dialog/alert-dialog.tsx +60 -13
- package/src/components/anchor/anchor.meta.md +8 -3
- package/src/components/anchor/anchor.stories.tsx +3 -3
- package/src/components/anchor/anchor.tsx +2 -2
- package/src/components/app/app.meta.md +9 -4
- package/src/components/app/app.stories.tsx +9 -7
- package/src/components/aspect-ratio/aspect-ratio.meta.md +4 -3
- package/src/components/aspect-ratio/aspect-ratio.stories.tsx +3 -3
- package/src/components/auto-complete/auto-complete.meta.md +14 -6
- package/src/components/auto-complete/auto-complete.stories.tsx +47 -4
- package/src/components/auto-complete/auto-complete.tsx +119 -71
- package/src/components/avatar/avatar.meta.md +6 -7
- package/src/components/avatar/avatar.stories.tsx +21 -3
- package/src/components/avatar/avatar.tsx +24 -23
- package/src/components/badge/badge.meta.md +10 -9
- package/src/components/badge/badge.stories.tsx +2 -2
- package/src/components/badge/badge.tsx +9 -15
- package/src/components/breadcrumb/breadcrumb.meta.md +27 -7
- package/src/components/breadcrumb/breadcrumb.stories.tsx +127 -4
- package/src/components/breadcrumb/breadcrumb.tsx +22 -8
- package/src/components/button/button.meta.md +258 -21
- package/src/components/button/button.stories.tsx +549 -41
- package/src/components/button/button.tsx +335 -33
- package/src/components/button/demo/as-child.tsx +24 -0
- package/src/components/button/demo/basic.tsx +8 -0
- package/src/components/button/demo/block.tsx +16 -0
- package/src/components/button/demo/loading.tsx +19 -0
- package/src/components/button/demo/shapes.tsx +18 -0
- package/src/components/button/demo/sizes.tsx +19 -0
- package/src/components/button/demo/variants.tsx +19 -0
- package/src/components/button/demo/with-icon.tsx +20 -0
- package/src/components/calendar/calendar.meta.md +13 -3
- package/src/components/calendar/calendar.stories.tsx +6 -6
- package/src/components/calendar/calendar.tsx +73 -8
- package/src/components/card/card.meta.md +27 -5
- package/src/components/card/card.stories.tsx +42 -3
- package/src/components/card/card.tsx +146 -63
- package/src/components/carousel/carousel.meta.md +4 -3
- package/src/components/carousel/carousel.stories.tsx +11 -6
- package/src/components/cascader/cascader.meta.md +47 -17
- package/src/components/cascader/cascader.stories.tsx +22 -10
- package/src/components/cascader/cascader.tsx +428 -85
- package/src/components/checkbox/checkbox.meta.md +75 -7
- package/src/components/checkbox/checkbox.stories.tsx +161 -3
- package/src/components/checkbox/checkbox.tsx +77 -9
- package/src/components/collapsible/collapsible.meta.md +14 -6
- package/src/components/collapsible/collapsible.stories.tsx +10 -2
- package/src/components/collapsible/collapsible.tsx +93 -6
- package/src/components/color-picker/color-picker.meta.md +12 -7
- package/src/components/color-picker/color-picker.stories.tsx +86 -7
- package/src/components/color-picker/color-picker.tsx +20 -9
- package/src/components/command/command.meta.md +29 -13
- package/src/components/command/command.stories.tsx +4 -4
- package/src/components/command/command.tsx +19 -8
- package/src/components/context-menu/context-menu.meta.md +11 -8
- package/src/components/context-menu/context-menu.stories.tsx +11 -3
- package/src/components/context-menu/context-menu.tsx +21 -8
- package/src/components/data-table/data-table.meta.md +6 -5
- package/src/components/data-table/data-table.stories.tsx +13 -6
- package/src/components/data-table/data-table.tsx +2 -2
- package/src/components/date-picker/date-picker.meta.md +88 -19
- package/src/components/date-picker/date-picker.stories.tsx +55 -5
- package/src/components/date-picker/date-picker.tsx +1489 -91
- package/src/components/descriptions/descriptions.meta.md +10 -5
- package/src/components/descriptions/descriptions.stories.tsx +3 -3
- package/src/components/descriptions/descriptions.tsx +22 -14
- package/src/components/dialog/dialog.meta.md +76 -13
- package/src/components/dialog/dialog.stories.tsx +182 -20
- package/src/components/dialog/dialog.tsx +67 -15
- package/src/components/dialog/imperative.tsx +252 -0
- package/src/components/drawer/drawer.meta.md +33 -34
- package/src/components/drawer/drawer.stories.tsx +29 -12
- package/src/components/drawer/drawer.tsx +22 -113
- package/src/components/dropdown-menu/dropdown-menu.meta.md +78 -10
- package/src/components/dropdown-menu/dropdown-menu.stories.tsx +88 -2
- package/src/components/dropdown-menu/dropdown-menu.tsx +24 -10
- package/src/components/ellipsis/ellipsis.meta.md +87 -0
- package/src/components/ellipsis/ellipsis.stories.tsx +72 -0
- package/src/components/ellipsis/ellipsis.tsx +153 -0
- package/src/components/empty/empty.meta.md +9 -4
- package/src/components/empty/empty.stories.tsx +4 -4
- package/src/components/empty/empty.tsx +10 -3
- package/src/components/field/field.meta.md +47 -9
- package/src/components/field/field.stories.tsx +385 -5
- package/src/components/field/field.tsx +263 -35
- package/src/components/filter-bar/filter-bar.meta.md +92 -0
- package/src/components/filter-bar/filter-bar.stories.tsx +1083 -0
- package/src/components/filter-bar/filter-bar.tsx +568 -0
- package/src/components/flex/flex.meta.md +54 -6
- package/src/components/flex/flex.stories.tsx +107 -20
- package/src/components/flex/flex.tsx +27 -4
- package/src/components/float-button/float-button.meta.md +8 -3
- package/src/components/float-button/float-button.stories.tsx +9 -7
- package/src/components/float-button/float-button.tsx +1 -1
- package/src/components/form/form.meta.md +39 -17
- package/src/components/form/form.stories.tsx +350 -3
- package/src/components/form/form.tsx +101 -35
- package/src/components/grid/grid.meta.md +7 -2
- package/src/components/grid/grid.stories.tsx +6 -4
- package/src/components/hover-card/hover-card.meta.md +20 -9
- package/src/components/hover-card/hover-card.stories.tsx +34 -5
- package/src/components/hover-card/hover-card.tsx +51 -13
- package/src/components/icon/DEVELOPMENT.md +809 -0
- package/src/components/icon/icon.meta.md +170 -0
- package/src/components/icon/icon.stories.tsx +344 -0
- package/src/components/icon/icon.tsx +248 -0
- package/src/components/image/image.meta.md +9 -4
- package/src/components/image/image.stories.tsx +3 -3
- package/src/components/image/image.tsx +6 -4
- package/src/components/input/demo/basic.tsx +12 -0
- package/src/components/input/demo/clearable.tsx +21 -0
- package/src/components/input/demo/show-count.tsx +18 -0
- package/src/components/input/demo/sizes.tsx +15 -0
- package/src/components/input/input.meta.md +39 -33
- package/src/components/input/input.stories.tsx +62 -35
- package/src/components/input/input.tsx +97 -98
- package/src/components/input-group/input-group.meta.md +54 -22
- package/src/components/input-group/input-group.stories.tsx +49 -16
- package/src/components/input-group/input-group.tsx +44 -8
- package/src/components/input-number/input-number.meta.md +64 -7
- package/src/components/input-number/input-number.stories.tsx +46 -8
- package/src/components/input-number/input-number.tsx +99 -26
- package/src/components/input-otp/input-otp.meta.md +4 -3
- package/src/components/input-otp/input-otp.stories.tsx +3 -3
- package/src/components/input-otp/input-otp.tsx +1 -1
- package/src/components/item/item.meta.md +8 -3
- package/src/components/item/item.stories.tsx +8 -5
- package/src/components/item/item.tsx +7 -6
- package/src/components/kbd/kbd.meta.md +13 -4
- package/src/components/kbd/kbd.stories.tsx +4 -4
- package/src/components/kbd/kbd.tsx +10 -5
- package/src/components/label/label.meta.md +18 -10
- package/src/components/label/label.stories.tsx +64 -6
- package/src/components/label/label.tsx +91 -19
- package/src/components/masonry/masonry.meta.md +8 -3
- package/src/components/masonry/masonry.stories.tsx +7 -5
- package/src/components/masonry/masonry.tsx +1 -0
- package/src/components/mentions/mentions.meta.md +36 -6
- package/src/components/mentions/mentions.stories.tsx +120 -6
- package/src/components/mentions/mentions.tsx +11 -5
- package/src/components/menubar/menubar.meta.md +30 -12
- package/src/components/menubar/menubar.stories.tsx +62 -2
- package/src/components/menubar/menubar.tsx +9 -9
- package/src/components/native-select/native-select.meta.md +8 -3
- package/src/components/native-select/native-select.stories.tsx +8 -5
- package/src/components/native-select/native-select.tsx +1 -1
- package/src/components/navigation-menu/navigation-menu.meta.md +19 -9
- package/src/components/navigation-menu/navigation-menu.stories.tsx +112 -9
- package/src/components/navigation-menu/navigation-menu.tsx +8 -4
- package/src/components/notification/notification.meta.md +52 -10
- package/src/components/notification/notification.stories.tsx +11 -9
- package/src/components/notification/notification.tsx +36 -21
- package/src/components/page-header/DEVELOPMENT.md +842 -0
- package/src/components/page-header/page-header.meta.md +208 -0
- package/src/components/page-header/page-header.stories.tsx +421 -0
- package/src/components/page-header/page-header.tsx +281 -0
- package/src/components/pagination/pagination.meta.md +140 -37
- package/src/components/pagination/pagination.stories.tsx +232 -10
- package/src/components/pagination/pagination.tsx +355 -63
- package/src/components/popconfirm/popconfirm.meta.md +9 -4
- package/src/components/popconfirm/popconfirm.stories.tsx +3 -4
- package/src/components/popconfirm/popconfirm.tsx +2 -2
- package/src/components/popover/popover.meta.md +62 -5
- package/src/components/popover/popover.stories.tsx +83 -7
- package/src/components/popover/popover.tsx +77 -28
- package/src/components/progress/progress.meta.md +38 -6
- package/src/components/progress/progress.stories.tsx +3 -3
- package/src/components/progress/progress.tsx +24 -16
- package/src/components/radio-group/radio-group.meta.md +79 -7
- package/src/components/radio-group/radio-group.stories.tsx +39 -3
- package/src/components/radio-group/radio-group.tsx +149 -18
- package/src/components/rate/rate.meta.md +35 -4
- package/src/components/rate/rate.stories.tsx +13 -5
- package/src/components/rate/rate.tsx +37 -10
- package/src/components/resizable/resizable.meta.md +7 -4
- package/src/components/resizable/resizable.stories.tsx +6 -6
- package/src/components/resizable/resizable.tsx +1 -1
- package/src/components/result/result.meta.md +7 -2
- package/src/components/result/result.stories.tsx +4 -8
- package/src/components/result/result.tsx +24 -15
- package/src/components/scroll-area/scroll-area.meta.md +4 -3
- package/src/components/scroll-area/scroll-area.stories.tsx +12 -4
- package/src/components/scroll-area/scroll-area.tsx +3 -3
- package/src/components/segmented/segmented.meta.md +7 -4
- package/src/components/segmented/segmented.stories.tsx +37 -8
- package/src/components/segmented/segmented.tsx +15 -7
- package/src/components/select/select.meta.md +197 -52
- package/src/components/select/select.stories.tsx +238 -63
- package/src/components/select/select.tsx +718 -171
- package/src/components/separator/separator.meta.md +4 -3
- package/src/components/separator/separator.stories.tsx +3 -3
- package/src/components/separator/separator.tsx +3 -7
- package/src/components/sheet/sheet.meta.md +32 -16
- package/src/components/sheet/sheet.stories.tsx +116 -10
- package/src/components/sheet/sheet.tsx +116 -29
- package/src/components/sidebar/sidebar.meta.md +37 -18
- package/src/components/sidebar/sidebar.stories.tsx +701 -29
- package/src/components/sidebar/sidebar.tsx +615 -142
- package/src/components/skeleton/skeleton.meta.md +4 -5
- package/src/components/skeleton/skeleton.stories.tsx +4 -4
- package/src/components/skeleton/skeleton.tsx +7 -7
- package/src/components/slider/slider.meta.md +57 -5
- package/src/components/slider/slider.stories.tsx +58 -6
- package/src/components/slider/slider.tsx +154 -13
- package/src/components/sonner/sonner.meta.md +58 -7
- package/src/components/sonner/sonner.stories.tsx +78 -5
- package/src/components/sonner/sonner.tsx +137 -8
- package/src/components/spinner/spinner.meta.md +62 -13
- package/src/components/spinner/spinner.stories.tsx +66 -14
- package/src/components/spinner/spinner.tsx +111 -9
- package/src/components/statistic/statistic.meta.md +7 -2
- package/src/components/statistic/statistic.stories.tsx +3 -7
- package/src/components/statistic/statistic.tsx +5 -6
- package/src/components/steps/steps.meta.md +18 -4
- package/src/components/steps/steps.stories.tsx +43 -3
- package/src/components/steps/steps.tsx +15 -12
- package/src/components/switch/switch.meta.md +51 -5
- package/src/components/switch/switch.stories.tsx +6 -6
- package/src/components/switch/switch.tsx +109 -41
- package/src/components/table/table.meta.md +17 -6
- package/src/components/table/table.stories.tsx +10 -5
- package/src/components/table/table.tsx +4 -4
- package/src/components/tabs/tabs.meta.md +38 -25
- package/src/components/tabs/tabs.stories.tsx +111 -25
- package/src/components/tabs/tabs.tsx +125 -54
- package/src/components/tag/tag.meta.md +105 -40
- package/src/components/tag/tag.stories.tsx +189 -16
- package/src/components/tag/tag.tsx +222 -21
- package/src/components/textarea/textarea.meta.md +35 -19
- package/src/components/textarea/textarea.stories.tsx +32 -6
- package/src/components/textarea/textarea.tsx +33 -9
- package/src/components/time-picker/time-picker.meta.md +124 -32
- package/src/components/time-picker/time-picker.stories.tsx +85 -15
- package/src/components/time-picker/time-picker.tsx +913 -61
- package/src/components/timeline/timeline.meta.md +14 -6
- package/src/components/timeline/timeline.stories.tsx +37 -7
- package/src/components/timeline/timeline.tsx +35 -14
- package/src/components/toggle/toggle.meta.md +5 -4
- package/src/components/toggle/toggle.stories.tsx +4 -4
- package/src/components/toggle/toggle.tsx +4 -3
- package/src/components/toggle-group/toggle-group.meta.md +5 -4
- package/src/components/toggle-group/toggle-group.stories.tsx +3 -3
- package/src/components/toggle-group/toggle-group.tsx +2 -2
- package/src/components/tooltip/tooltip.meta.md +55 -5
- package/src/components/tooltip/tooltip.stories.tsx +42 -5
- package/src/components/tooltip/tooltip.tsx +81 -21
- package/src/components/tour/tour.meta.md +9 -4
- package/src/components/tour/tour.stories.tsx +3 -3
- package/src/components/tour/tour.tsx +4 -4
- package/src/components/transfer/transfer.meta.md +11 -6
- package/src/components/transfer/transfer.stories.tsx +4 -8
- package/src/components/transfer/transfer.tsx +28 -21
- package/src/components/tree/tree.meta.md +63 -5
- package/src/components/tree/tree.stories.tsx +31 -12
- package/src/components/tree/tree.tsx +9 -8
- package/src/components/tree-select/tree-select.meta.md +59 -8
- package/src/components/tree-select/tree-select.stories.tsx +3 -3
- package/src/components/tree-select/tree-select.tsx +42 -7
- package/src/components/typography/typography.meta.md +61 -14
- package/src/components/typography/typography.stories.tsx +12 -11
- package/src/components/typography/typography.tsx +43 -28
- package/src/components/upload/upload.meta.md +49 -4
- package/src/components/upload/upload.stories.tsx +72 -12
- package/src/components/upload/upload.tsx +170 -37
- package/src/components/watermark/watermark.meta.md +7 -2
- package/src/components/watermark/watermark.stories.tsx +101 -9
- package/src/components/watermark/watermark.tsx +1 -0
- package/src/hooks/use-breakpoint.ts +117 -0
- package/src/hooks/use-debounce-callback.ts +52 -0
- package/src/hooks/use-mobile.ts +23 -0
- package/src/stories/theme-tokens.stories.tsx +747 -0
- package/src/utils/trigger-input.ts +53 -0
- package/src/components/button-group/button-group.meta.md +0 -92
- package/src/components/button-group/button-group.stories.tsx +0 -90
- package/src/components/button-group/button-group.tsx +0 -75
- package/src/components/combobox/combobox.meta.md +0 -93
- package/src/components/combobox/combobox.stories.tsx +0 -55
- package/src/components/combobox/combobox.tsx +0 -130
- package/src/components/space/space.meta.md +0 -94
- package/src/components/space/space.stories.tsx +0 -94
- 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:
|
|
5
|
+
category: data-display
|
|
6
6
|
since: 0.1.0
|
|
7
|
-
package:
|
|
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: '
|
|
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
|
|
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
|
-
{
|
|
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=
|
|
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:
|
|
6
|
+
category: data-entry
|
|
6
7
|
since: 0.1.0
|
|
7
|
-
package:
|
|
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` | `
|
|
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
|
-
- **`
|
|
54
|
-
- **`
|
|
55
|
-
- **`
|
|
56
|
-
- **`
|
|
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`
|
|
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
|
|