@teamix-evo/ui 0.2.0 → 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 +15 -9
- package/src/components/accordion/accordion.meta.md +5 -9
- package/src/components/accordion/accordion.stories.tsx +3 -3
- package/src/components/accordion/accordion.tsx +104 -8
- package/src/components/affix/affix.meta.md +21 -12
- package/src/components/affix/affix.stories.tsx +101 -26
- package/src/components/affix/affix.tsx +79 -9
- package/src/components/alert/alert.meta.md +52 -26
- 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 +48 -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 +10 -14
- package/src/components/anchor/anchor.stories.tsx +3 -3
- package/src/components/anchor/anchor.tsx +2 -2
- package/src/components/app/app.meta.md +10 -14
- package/src/components/app/app.stories.tsx +6 -6
- package/src/components/aspect-ratio/aspect-ratio.meta.md +4 -8
- package/src/components/aspect-ratio/aspect-ratio.stories.tsx +3 -3
- package/src/components/auto-complete/auto-complete.meta.md +19 -20
- package/src/components/auto-complete/auto-complete.stories.tsx +44 -3
- package/src/components/auto-complete/auto-complete.tsx +119 -71
- package/src/components/avatar/avatar.meta.md +9 -22
- package/src/components/avatar/avatar.stories.tsx +21 -3
- package/src/components/avatar/avatar.tsx +24 -23
- package/src/components/badge/badge.meta.md +14 -18
- package/src/components/badge/badge.stories.tsx +2 -2
- package/src/components/badge/badge.tsx +2 -2
- package/src/components/breadcrumb/breadcrumb.meta.md +29 -20
- package/src/components/breadcrumb/breadcrumb.stories.tsx +120 -5
- package/src/components/breadcrumb/breadcrumb.tsx +22 -8
- package/src/components/button/button.meta.md +261 -29
- package/src/components/button/button.stories.tsx +549 -41
- package/src/components/button/button.tsx +335 -33
- package/src/components/calendar/calendar.meta.md +19 -14
- package/src/components/calendar/calendar.stories.tsx +5 -5
- package/src/components/calendar/calendar.tsx +73 -8
- package/src/components/card/card.meta.md +31 -34
- package/src/components/card/card.stories.tsx +34 -3
- package/src/components/card/card.tsx +146 -63
- package/src/components/carousel/carousel.meta.md +10 -14
- package/src/components/carousel/carousel.stories.tsx +1 -1
- package/src/components/cascader/cascader.meta.md +43 -22
- package/src/components/cascader/cascader.stories.tsx +13 -2
- package/src/components/cascader/cascader.tsx +427 -84
- package/src/components/checkbox/checkbox.meta.md +74 -24
- package/src/components/checkbox/checkbox.stories.tsx +160 -2
- package/src/components/checkbox/checkbox.tsx +77 -9
- package/src/components/collapsible/collapsible.meta.md +7 -6
- package/src/components/collapsible/collapsible.stories.tsx +2 -2
- package/src/components/collapsible/collapsible.tsx +93 -6
- package/src/components/color-picker/color-picker.meta.md +16 -20
- package/src/components/color-picker/color-picker.stories.tsx +86 -7
- package/src/components/color-picker/color-picker.tsx +19 -9
- package/src/components/command/command.meta.md +7 -11
- package/src/components/command/command.stories.tsx +4 -4
- package/src/components/command/command.tsx +18 -7
- package/src/components/context-menu/context-menu.meta.md +5 -25
- package/src/components/context-menu/context-menu.stories.tsx +4 -4
- package/src/components/context-menu/context-menu.tsx +21 -8
- package/src/components/data-table/data-table.meta.md +14 -18
- package/src/components/data-table/data-table.stories.tsx +1 -1
- package/src/components/data-table/data-table.tsx +2 -2
- package/src/components/date-picker/date-picker.meta.md +90 -41
- 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 +12 -16
- package/src/components/descriptions/descriptions.stories.tsx +2 -2
- package/src/components/descriptions/descriptions.tsx +22 -14
- package/src/components/dialog/dialog.meta.md +67 -17
- 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 +27 -39
- package/src/components/drawer/drawer.stories.tsx +29 -12
- package/src/components/drawer/drawer.tsx +22 -114
- package/src/components/dropdown-menu/dropdown-menu.meta.md +64 -24
- package/src/components/dropdown-menu/dropdown-menu.stories.tsx +81 -3
- 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 +10 -14
- package/src/components/empty/empty.stories.tsx +3 -3
- package/src/components/empty/empty.tsx +10 -3
- package/src/components/field/field.meta.md +46 -25
- package/src/components/field/field.stories.tsx +380 -3
- 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 +59 -20
- package/src/components/flex/flex.stories.tsx +65 -10
- package/src/components/flex/flex.tsx +27 -4
- package/src/components/float-button/float-button.meta.md +10 -29
- package/src/components/float-button/float-button.stories.tsx +6 -6
- package/src/components/form/form.meta.md +31 -52
- package/src/components/form/form.stories.tsx +350 -3
- package/src/components/form/form.tsx +101 -35
- package/src/components/grid/grid.meta.md +4 -24
- package/src/components/grid/grid.stories.tsx +2 -2
- package/src/components/hover-card/hover-card.meta.md +9 -10
- package/src/components/hover-card/hover-card.stories.tsx +29 -4
- 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 +14 -18
- package/src/components/image/image.stories.tsx +3 -3
- package/src/components/image/image.tsx +2 -0
- package/src/components/input/demo/sizes.tsx +2 -2
- package/src/components/input/input.meta.md +44 -43
- package/src/components/input/input.stories.tsx +62 -35
- package/src/components/input/input.tsx +96 -101
- package/src/components/input-group/input-group.meta.md +53 -39
- package/src/components/input-group/input-group.stories.tsx +49 -16
- package/src/components/input-group/input-group.tsx +43 -8
- package/src/components/input-number/input-number.meta.md +68 -20
- package/src/components/input-number/input-number.stories.tsx +33 -6
- package/src/components/input-number/input-number.tsx +79 -20
- package/src/components/input-otp/input-otp.meta.md +8 -20
- 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 -26
- package/src/components/item/item.stories.tsx +3 -3
- package/src/components/item/item.tsx +7 -6
- package/src/components/kbd/kbd.meta.md +7 -19
- package/src/components/kbd/kbd.stories.tsx +4 -4
- package/src/components/kbd/kbd.tsx +8 -4
- package/src/components/label/label.meta.md +21 -18
- 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 -12
- package/src/components/masonry/masonry.stories.tsx +4 -4
- package/src/components/mentions/mentions.meta.md +42 -21
- package/src/components/mentions/mentions.stories.tsx +120 -6
- package/src/components/mentions/mentions.tsx +10 -5
- package/src/components/menubar/menubar.meta.md +4 -8
- package/src/components/menubar/menubar.stories.tsx +55 -3
- package/src/components/menubar/menubar.tsx +9 -9
- package/src/components/native-select/native-select.meta.md +7 -11
- package/src/components/native-select/native-select.stories.tsx +4 -4
- package/src/components/native-select/native-select.tsx +1 -1
- package/src/components/navigation-menu/navigation-menu.meta.md +4 -8
- package/src/components/navigation-menu/navigation-menu.stories.tsx +106 -3
- package/src/components/navigation-menu/navigation-menu.tsx +6 -3
- package/src/components/notification/notification.meta.md +41 -8
- package/src/components/notification/notification.stories.tsx +9 -9
- package/src/components/notification/notification.tsx +34 -19
- 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 +122 -50
- package/src/components/pagination/pagination.stories.tsx +227 -11
- package/src/components/pagination/pagination.tsx +355 -63
- package/src/components/popconfirm/popconfirm.meta.md +19 -23
- package/src/components/popconfirm/popconfirm.stories.tsx +2 -2
- package/src/components/popconfirm/popconfirm.tsx +1 -1
- package/src/components/popover/popover.meta.md +64 -12
- package/src/components/popover/popover.stories.tsx +83 -7
- package/src/components/popover/popover.tsx +77 -28
- package/src/components/progress/progress.meta.md +43 -26
- package/src/components/progress/progress.stories.tsx +2 -2
- package/src/components/progress/progress.tsx +19 -11
- package/src/components/radio-group/radio-group.meta.md +78 -11
- package/src/components/radio-group/radio-group.stories.tsx +38 -2
- package/src/components/radio-group/radio-group.tsx +149 -18
- package/src/components/rate/rate.meta.md +41 -19
- package/src/components/rate/rate.stories.tsx +2 -2
- package/src/components/rate/rate.tsx +37 -10
- package/src/components/resizable/resizable.meta.md +4 -12
- package/src/components/resizable/resizable.stories.tsx +5 -5
- package/src/components/resizable/resizable.tsx +1 -1
- package/src/components/result/result.meta.md +10 -14
- package/src/components/result/result.stories.tsx +2 -2
- package/src/components/result/result.tsx +21 -12
- package/src/components/scroll-area/scroll-area.meta.md +4 -8
- package/src/components/scroll-area/scroll-area.stories.tsx +5 -5
- package/src/components/segmented/segmented.meta.md +15 -17
- package/src/components/segmented/segmented.stories.tsx +3 -3
- package/src/components/segmented/segmented.tsx +15 -7
- package/src/components/select/select.meta.md +199 -67
- package/src/components/select/select.stories.tsx +238 -63
- package/src/components/select/select.tsx +718 -171
- package/src/components/separator/separator.meta.md +10 -14
- package/src/components/separator/separator.stories.tsx +2 -2
- package/src/components/separator/separator.tsx +3 -7
- package/src/components/sheet/sheet.meta.md +26 -21
- package/src/components/sheet/sheet.stories.tsx +116 -10
- package/src/components/sheet/sheet.tsx +116 -29
- package/src/components/sidebar/sidebar.meta.md +28 -38
- package/src/components/sidebar/sidebar.stories.tsx +696 -29
- package/src/components/sidebar/sidebar.tsx +615 -142
- package/src/components/skeleton/skeleton.meta.md +7 -31
- package/src/components/skeleton/skeleton.stories.tsx +3 -3
- package/src/components/skeleton/skeleton.tsx +7 -7
- package/src/components/slider/slider.meta.md +60 -13
- package/src/components/slider/slider.stories.tsx +58 -6
- package/src/components/slider/slider.tsx +154 -13
- package/src/components/sonner/sonner.meta.md +54 -8
- package/src/components/sonner/sonner.stories.tsx +79 -11
- package/src/components/sonner/sonner.tsx +137 -8
- package/src/components/spinner/spinner.meta.md +57 -21
- package/src/components/spinner/spinner.stories.tsx +66 -14
- package/src/components/spinner/spinner.tsx +111 -9
- package/src/components/statistic/statistic.meta.md +14 -30
- package/src/components/statistic/statistic.stories.tsx +1 -1
- package/src/components/statistic/statistic.tsx +4 -5
- package/src/components/steps/steps.meta.md +20 -15
- package/src/components/steps/steps.stories.tsx +37 -2
- package/src/components/steps/steps.tsx +15 -12
- package/src/components/switch/switch.meta.md +56 -15
- package/src/components/switch/switch.stories.tsx +5 -5
- package/src/components/switch/switch.tsx +59 -13
- package/src/components/table/table.meta.md +3 -7
- package/src/components/table/table.stories.tsx +1 -1
- package/src/components/table/table.tsx +4 -4
- package/src/components/tabs/tabs.meta.md +40 -32
- package/src/components/tabs/tabs.stories.tsx +104 -26
- package/src/components/tabs/tabs.tsx +125 -54
- package/src/components/tag/tag.meta.md +104 -68
- package/src/components/tag/tag.stories.tsx +183 -15
- package/src/components/tag/tag.tsx +222 -21
- package/src/components/textarea/textarea.meta.md +42 -31
- package/src/components/textarea/textarea.stories.tsx +32 -6
- package/src/components/textarea/textarea.tsx +32 -8
- package/src/components/time-picker/time-picker.meta.md +119 -50
- package/src/components/time-picker/time-picker.stories.tsx +65 -33
- package/src/components/time-picker/time-picker.tsx +889 -101
- package/src/components/timeline/timeline.meta.md +16 -17
- package/src/components/timeline/timeline.stories.tsx +24 -4
- package/src/components/timeline/timeline.tsx +32 -12
- package/src/components/toggle/toggle.meta.md +8 -12
- 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 +10 -14
- 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 +63 -18
- package/src/components/tooltip/tooltip.stories.tsx +42 -5
- package/src/components/tooltip/tooltip.tsx +81 -21
- package/src/components/tour/tour.meta.md +16 -20
- package/src/components/tour/tour.stories.tsx +3 -3
- package/src/components/tour/tour.tsx +3 -3
- package/src/components/transfer/transfer.meta.md +18 -22
- package/src/components/transfer/transfer.stories.tsx +2 -2
- package/src/components/transfer/transfer.tsx +28 -21
- package/src/components/tree/tree.meta.md +67 -22
- package/src/components/tree/tree.stories.tsx +1 -1
- package/src/components/tree/tree.tsx +9 -8
- package/src/components/tree-select/tree-select.meta.md +59 -23
- package/src/components/tree-select/tree-select.stories.tsx +2 -2
- package/src/components/tree-select/tree-select.tsx +42 -7
- package/src/components/typography/typography.meta.md +61 -39
- package/src/components/typography/typography.stories.tsx +14 -9
- package/src/components/typography/typography.tsx +38 -25
- package/src/components/upload/upload.meta.md +61 -25
- package/src/components/upload/upload.stories.tsx +69 -3
- package/src/components/upload/upload.tsx +170 -37
- package/src/components/watermark/watermark.meta.md +15 -19
- package/src/components/watermark/watermark.stories.tsx +98 -8
- 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 -101
- package/src/components/button-group/button-group.stories.tsx +0 -93
- package/src/components/button-group/button-group.tsx +0 -75
- package/src/components/combobox/combobox.meta.md +0 -102
- package/src/components/combobox/combobox.stories.tsx +0 -55
- package/src/components/combobox/combobox.tsx +0 -130
- package/src/components/input/demo/addon.tsx +0 -15
- package/src/components/input/demo/with-prefix-suffix.tsx +0 -19
- package/src/components/space/space.meta.md +0 -103
- package/src/components/space/space.stories.tsx +0 -108
- package/src/components/space/space.tsx +0 -106
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
4
|
import { X } from 'lucide-react';
|
|
4
5
|
|
|
5
6
|
import { cn } from '@/utils/cn';
|
|
6
7
|
|
|
7
8
|
const Dialog = DialogPrimitive.Root;
|
|
8
|
-
const DialogTrigger = DialogPrimitive.Trigger;
|
|
9
9
|
const DialogPortal = DialogPrimitive.Portal;
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
const DialogTrigger = React.forwardRef<
|
|
12
|
+
React.ElementRef<typeof DialogPrimitive.Trigger>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>
|
|
14
|
+
>(({ className, ...props }, ref) => (
|
|
15
|
+
<DialogPrimitive.Trigger
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={cn('cursor-pointer', className)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
));
|
|
21
|
+
DialogTrigger.displayName = DialogPrimitive.Trigger.displayName;
|
|
22
|
+
|
|
23
|
+
const DialogClose = React.forwardRef<
|
|
24
|
+
React.ElementRef<typeof DialogPrimitive.Close>,
|
|
25
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>
|
|
26
|
+
>(({ className, ...props }, ref) => (
|
|
27
|
+
<DialogPrimitive.Close
|
|
28
|
+
ref={ref}
|
|
29
|
+
className={cn('cursor-pointer', className)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
));
|
|
33
|
+
DialogClose.displayName = DialogPrimitive.Close.displayName;
|
|
11
34
|
|
|
12
35
|
const DialogOverlay = React.forwardRef<
|
|
13
36
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
|
@@ -24,32 +47,62 @@ const DialogOverlay = React.forwardRef<
|
|
|
24
47
|
));
|
|
25
48
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
26
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Dialog content 变体。
|
|
52
|
+
* - 圆角统一绑定 `--radius-dialog`(16px,OpenTrek)
|
|
53
|
+
* - 移除 border,纯白 + shadow 作为视觉分界
|
|
54
|
+
* - size 绑定 `--layout-dialog-{sm|md|lg|xl}` tokens
|
|
55
|
+
*/
|
|
56
|
+
const dialogContentVariants = cva(
|
|
57
|
+
'fixed left-1/2 top-1/2 z-50 grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 border-0 bg-background p-6 shadow-lg duration-200 rounded-[var(--radius-dialog)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
|
|
58
|
+
{
|
|
59
|
+
variants: {
|
|
60
|
+
size: {
|
|
61
|
+
sm: 'max-w-[var(--layout-dialog-sm)]',
|
|
62
|
+
md: 'max-w-[var(--layout-dialog-md)]',
|
|
63
|
+
lg: 'max-w-[var(--layout-dialog-lg)]',
|
|
64
|
+
xl: 'max-w-[var(--layout-dialog-xl)]',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
defaultVariants: { size: 'md' },
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
export type DialogSize = NonNullable<
|
|
72
|
+
VariantProps<typeof dialogContentVariants>['size']
|
|
73
|
+
>;
|
|
74
|
+
|
|
27
75
|
export interface DialogContentProps
|
|
28
|
-
extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content
|
|
76
|
+
extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,
|
|
77
|
+
VariantProps<typeof dialogContentVariants> {
|
|
29
78
|
/**
|
|
30
|
-
*
|
|
79
|
+
* 是否在标题区右侧显示默认关闭按钮(antd Modal 默认行为)。
|
|
31
80
|
* @default true
|
|
32
81
|
*/
|
|
33
82
|
showClose?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* 对话框尺寸 — 绑定 design tokens `--layout-dialog-{sm|md|lg|xl}`。
|
|
85
|
+
* OpenTrek 基准:sm=400 / md=600 / lg=800 / xl=1200。
|
|
86
|
+
* @default "md"
|
|
87
|
+
*/
|
|
88
|
+
size?: DialogSize;
|
|
34
89
|
}
|
|
35
90
|
|
|
36
91
|
const DialogContent = React.forwardRef<
|
|
37
92
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
38
93
|
DialogContentProps
|
|
39
|
-
>(({ className, children, showClose = true, ...props }, ref) => (
|
|
94
|
+
>(({ className, children, showClose = true, size = 'md', ...props }, ref) => (
|
|
40
95
|
<DialogPortal>
|
|
41
96
|
<DialogOverlay />
|
|
42
97
|
<DialogPrimitive.Content
|
|
43
98
|
ref={ref}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
className,
|
|
47
|
-
)}
|
|
99
|
+
data-slot="dialog-content"
|
|
100
|
+
className={cn(dialogContentVariants({ size }), className)}
|
|
48
101
|
{...props}
|
|
49
102
|
>
|
|
50
103
|
{children}
|
|
51
104
|
{showClose ? (
|
|
52
|
-
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none">
|
|
105
|
+
<DialogPrimitive.Close className="absolute right-4 top-4 inline-flex size-6 cursor-pointer items-center justify-center rounded-sm text-muted-foreground opacity-70 ring-offset-background transition-opacity hover:bg-accent hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none">
|
|
53
106
|
<X className="size-4" />
|
|
54
107
|
<span className="sr-only">Close</span>
|
|
55
108
|
</DialogPrimitive.Close>
|
|
@@ -64,10 +117,7 @@ const DialogHeader = ({
|
|
|
64
117
|
...props
|
|
65
118
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
66
119
|
<div
|
|
67
|
-
className={cn(
|
|
68
|
-
'flex flex-col space-y-1.5 text-center sm:text-left',
|
|
69
|
-
className,
|
|
70
|
-
)}
|
|
120
|
+
className={cn('flex flex-col gap-1.5 text-center sm:text-left', className)}
|
|
71
121
|
{...props}
|
|
72
122
|
/>
|
|
73
123
|
);
|
|
@@ -93,6 +143,7 @@ const DialogTitle = React.forwardRef<
|
|
|
93
143
|
>(({ className, ...props }, ref) => (
|
|
94
144
|
<DialogPrimitive.Title
|
|
95
145
|
ref={ref}
|
|
146
|
+
data-slot="dialog-title"
|
|
96
147
|
className={cn(
|
|
97
148
|
'text-lg font-semibold leading-none tracking-tight',
|
|
98
149
|
className,
|
|
@@ -108,7 +159,7 @@ const DialogDescription = React.forwardRef<
|
|
|
108
159
|
>(({ className, ...props }, ref) => (
|
|
109
160
|
<DialogPrimitive.Description
|
|
110
161
|
ref={ref}
|
|
111
|
-
className={cn('text-
|
|
162
|
+
className={cn('text-xs text-muted-foreground', className)}
|
|
112
163
|
{...props}
|
|
113
164
|
/>
|
|
114
165
|
));
|
|
@@ -125,4 +176,5 @@ export {
|
|
|
125
176
|
DialogFooter,
|
|
126
177
|
DialogTitle,
|
|
127
178
|
DialogDescription,
|
|
179
|
+
dialogContentVariants,
|
|
128
180
|
};
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialog 命令式 API — 对齐 antd `Modal.confirm` / `Modal.alert` 的函数式调用范式。
|
|
3
|
+
*
|
|
4
|
+
* 使用方式:
|
|
5
|
+
* ```tsx
|
|
6
|
+
* import { confirm, alert } from '@/components/ui/dialog/imperative';
|
|
7
|
+
*
|
|
8
|
+
* // confirm — 双按钮(取消 + 确认),返回 Promise<boolean>
|
|
9
|
+
* const ok = await confirm({ title: '确认删除?', content: '不可撤销' });
|
|
10
|
+
*
|
|
11
|
+
* // alert — 单按钮(知道了),返回 Promise<void>
|
|
12
|
+
* await alert({ title: '操作完成', content: '已保存成功。' });
|
|
13
|
+
*
|
|
14
|
+
* // tone — 等价 cd `Dialog.confirm({ type: 'error' / 'warning' / 'success' })`
|
|
15
|
+
* await confirm({ tone: 'warning', title: '即将停止服务?', content: '...' });
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* 底层通过 `createRoot` 挂载临时 React 节点,关闭后自动卸载 + 清理 DOM。
|
|
19
|
+
*/
|
|
20
|
+
import * as React from 'react';
|
|
21
|
+
import { createRoot } from 'react-dom/client';
|
|
22
|
+
import {
|
|
23
|
+
AlertCircle,
|
|
24
|
+
AlertTriangle,
|
|
25
|
+
CheckCircle2,
|
|
26
|
+
Info,
|
|
27
|
+
XCircle,
|
|
28
|
+
} from 'lucide-react';
|
|
29
|
+
|
|
30
|
+
import { cn } from '@/utils/cn';
|
|
31
|
+
import { buttonVariants } from '@/components/button/button';
|
|
32
|
+
|
|
33
|
+
// ─── Types ─────────────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 弹窗语气(对齐 cd `Dialog.confirm/alert` 的 `type` preset):
|
|
37
|
+
* - `'info'` — 蓝色 Info icon(默认无 icon 时的"中性提示")
|
|
38
|
+
* - `'success'` — 绿色 CheckCircle2 icon
|
|
39
|
+
* - `'warning'` — 黄色 AlertTriangle icon
|
|
40
|
+
* - `'error'` — 红色 XCircle icon
|
|
41
|
+
*
|
|
42
|
+
* 不传时无 icon,仅纯文字(简化模式)。
|
|
43
|
+
*/
|
|
44
|
+
export type DialogTone = 'info' | 'success' | 'warning' | 'error';
|
|
45
|
+
|
|
46
|
+
export interface ConfirmOptions {
|
|
47
|
+
/** 标题(必填)。 */
|
|
48
|
+
title: React.ReactNode;
|
|
49
|
+
/** 描述内容。 */
|
|
50
|
+
content?: React.ReactNode;
|
|
51
|
+
/** 确认按钮文案。@default "确认" */
|
|
52
|
+
okText?: string;
|
|
53
|
+
/** 取消按钮文案。@default "取消" */
|
|
54
|
+
cancelText?: string;
|
|
55
|
+
/** 确认按钮样式变体。@default "default" */
|
|
56
|
+
variant?: 'default' | 'destructive';
|
|
57
|
+
/**
|
|
58
|
+
* 语气 — 控制左侧 icon + icon 色(`tone='error'` 同时把 `variant` 默认为 `destructive`)。
|
|
59
|
+
* 等价 cd `Dialog.confirm({ type: 'error' })`。
|
|
60
|
+
* @default 无(简化模式,无 icon)
|
|
61
|
+
*/
|
|
62
|
+
tone?: DialogTone;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface AlertOptions {
|
|
66
|
+
/** 标题(必填)。 */
|
|
67
|
+
title: React.ReactNode;
|
|
68
|
+
/** 描述内容。 */
|
|
69
|
+
content?: React.ReactNode;
|
|
70
|
+
/** 按钮文案。@default "知道了" */
|
|
71
|
+
okText?: string;
|
|
72
|
+
/**
|
|
73
|
+
* 语气 — 控制左侧 icon + icon 色。等价 cd `Dialog.alert({ type: 'success' })`。
|
|
74
|
+
* @default 无(简化模式,无 icon)
|
|
75
|
+
*/
|
|
76
|
+
tone?: DialogTone;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ─── 内部渲染组件 ──────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
// 不引入 AlertDialog 组件(避免循环依赖 + 减少打包体积),
|
|
82
|
+
// 直接使用相同的视觉类名构建最小化 modal。
|
|
83
|
+
|
|
84
|
+
const overlayClass = 'fixed inset-0 z-50 bg-black/80 animate-in fade-in-0';
|
|
85
|
+
const contentClass =
|
|
86
|
+
'fixed left-1/2 top-1/2 z-50 grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 border-0 bg-background p-6 shadow-lg animate-in fade-in-0 zoom-in-95';
|
|
87
|
+
/** maxWidth / borderRadius 使用 CSS 变量,不能写 arbitrary value(ADR 0008)。 */
|
|
88
|
+
const contentStyle: React.CSSProperties = {
|
|
89
|
+
maxWidth: 'var(--layout-dialog-sm)',
|
|
90
|
+
borderRadius: 'var(--radius-dialog)',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// tone → icon + 颜色 token 映射
|
|
94
|
+
const TONE_META: Record<
|
|
95
|
+
DialogTone,
|
|
96
|
+
{ Icon: React.ComponentType<{ className?: string }>; colorClass: string }
|
|
97
|
+
> = {
|
|
98
|
+
info: { Icon: Info, colorClass: 'text-primary' },
|
|
99
|
+
success: { Icon: CheckCircle2, colorClass: 'text-success' },
|
|
100
|
+
warning: { Icon: AlertTriangle, colorClass: 'text-warning' },
|
|
101
|
+
error: { Icon: XCircle, colorClass: 'text-destructive' },
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
function ToneIcon({ tone }: { tone?: DialogTone }) {
|
|
105
|
+
if (!tone) return null;
|
|
106
|
+
const meta = TONE_META[tone] ?? { Icon: AlertCircle, colorClass: '' };
|
|
107
|
+
const { Icon, colorClass } = meta;
|
|
108
|
+
return (
|
|
109
|
+
<Icon className={cn('mt-0.5 size-5 shrink-0', colorClass)} aria-hidden />
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function ConfirmDialog({
|
|
114
|
+
title,
|
|
115
|
+
content,
|
|
116
|
+
okText = '确认',
|
|
117
|
+
cancelText = '取消',
|
|
118
|
+
variant,
|
|
119
|
+
tone,
|
|
120
|
+
onResult,
|
|
121
|
+
}: ConfirmOptions & { onResult: (ok: boolean) => void }) {
|
|
122
|
+
// tone='error' 时默认确认按钮也是 destructive(危险动作语义)
|
|
123
|
+
const effectiveVariant: 'default' | 'destructive' =
|
|
124
|
+
variant ?? (tone === 'error' ? 'destructive' : 'default');
|
|
125
|
+
return (
|
|
126
|
+
<div role="alertdialog" aria-modal="true" aria-labelledby="__imp_title">
|
|
127
|
+
<div className={overlayClass} onClick={() => onResult(false)} />
|
|
128
|
+
<div className={contentClass} style={contentStyle}>
|
|
129
|
+
<div className="flex gap-3">
|
|
130
|
+
<ToneIcon tone={tone} />
|
|
131
|
+
<div className="flex flex-1 flex-col gap-2 text-left">
|
|
132
|
+
<h2 id="__imp_title" className="text-lg font-semibold">
|
|
133
|
+
{title}
|
|
134
|
+
</h2>
|
|
135
|
+
{content && (
|
|
136
|
+
<p className="text-xs text-muted-foreground">{content}</p>
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
<div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:gap-2">
|
|
141
|
+
<button
|
|
142
|
+
type="button"
|
|
143
|
+
className={cn(
|
|
144
|
+
buttonVariants({ variant: 'outline' }),
|
|
145
|
+
'mt-2 sm:mt-0',
|
|
146
|
+
)}
|
|
147
|
+
onClick={() => onResult(false)}
|
|
148
|
+
>
|
|
149
|
+
{cancelText}
|
|
150
|
+
</button>
|
|
151
|
+
<button
|
|
152
|
+
type="button"
|
|
153
|
+
className={cn(buttonVariants({ variant: effectiveVariant }))}
|
|
154
|
+
onClick={() => onResult(true)}
|
|
155
|
+
>
|
|
156
|
+
{okText}
|
|
157
|
+
</button>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function AlertDialog({
|
|
165
|
+
title,
|
|
166
|
+
content,
|
|
167
|
+
okText = '知道了',
|
|
168
|
+
tone,
|
|
169
|
+
onResult,
|
|
170
|
+
}: AlertOptions & { onResult: () => void }) {
|
|
171
|
+
return (
|
|
172
|
+
<div role="alertdialog" aria-modal="true" aria-labelledby="__imp_title">
|
|
173
|
+
<div className={overlayClass} />
|
|
174
|
+
<div className={contentClass} style={contentStyle}>
|
|
175
|
+
<div className="flex gap-3">
|
|
176
|
+
<ToneIcon tone={tone} />
|
|
177
|
+
<div className="flex flex-1 flex-col gap-2 text-left">
|
|
178
|
+
<h2 id="__imp_title" className="text-lg font-semibold">
|
|
179
|
+
{title}
|
|
180
|
+
</h2>
|
|
181
|
+
{content && (
|
|
182
|
+
<p className="text-xs text-muted-foreground">{content}</p>
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
<div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:gap-2">
|
|
187
|
+
<button
|
|
188
|
+
type="button"
|
|
189
|
+
className={cn(buttonVariants())}
|
|
190
|
+
onClick={() => onResult()}
|
|
191
|
+
>
|
|
192
|
+
{okText}
|
|
193
|
+
</button>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ─── 挂载 / 卸载工具 ───────────────────────────────────────────────────────
|
|
201
|
+
|
|
202
|
+
function mount(element: React.ReactElement): () => void {
|
|
203
|
+
const container = document.createElement('div');
|
|
204
|
+
container.setAttribute('data-dialog-imperative', '');
|
|
205
|
+
document.body.appendChild(container);
|
|
206
|
+
const root = createRoot(container);
|
|
207
|
+
root.render(element);
|
|
208
|
+
return () => {
|
|
209
|
+
// 延迟卸载,确保 state 回调完成后再清理
|
|
210
|
+
setTimeout(() => {
|
|
211
|
+
root.unmount();
|
|
212
|
+
container.remove();
|
|
213
|
+
}, 0);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ─── 公开 API ───────────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 命令式确认弹窗 — 返回 `Promise<boolean>`:
|
|
221
|
+
* - 用户点击确认 → `true`
|
|
222
|
+
* - 用户点击取消 / 点击遮罩 → `false`
|
|
223
|
+
*
|
|
224
|
+
* 等价 cd `Dialog.confirm({ ... })` / antd `Modal.confirm({ ... })`。
|
|
225
|
+
*/
|
|
226
|
+
export function confirm(options: ConfirmOptions): Promise<boolean> {
|
|
227
|
+
return new Promise<boolean>((resolve) => {
|
|
228
|
+
let cleanup: (() => void) | undefined;
|
|
229
|
+
const handleResult = (ok: boolean) => {
|
|
230
|
+
cleanup?.();
|
|
231
|
+
resolve(ok);
|
|
232
|
+
};
|
|
233
|
+
cleanup = mount(<ConfirmDialog {...options} onResult={handleResult} />);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* 命令式 alert 弹窗 — 返回 `Promise<void>`:
|
|
239
|
+
* 用户点击确认按钮后 resolve。
|
|
240
|
+
*
|
|
241
|
+
* 等价 cd `Dialog.alert({ ... })` / antd `Modal.info|success|warning|error({ ... })`。
|
|
242
|
+
*/
|
|
243
|
+
export function alert(options: AlertOptions): Promise<void> {
|
|
244
|
+
return new Promise<void>((resolve) => {
|
|
245
|
+
let cleanup: (() => void) | undefined;
|
|
246
|
+
const handleResult = () => {
|
|
247
|
+
cleanup?.();
|
|
248
|
+
resolve();
|
|
249
|
+
};
|
|
250
|
+
cleanup = mount(<AlertDialog {...options} onResult={handleResult} />);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
@@ -1,40 +1,35 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: drawer
|
|
3
3
|
name: Drawer
|
|
4
|
-
displayName:
|
|
4
|
+
displayName: 抽屉(Sheet 别名)
|
|
5
5
|
type: component
|
|
6
6
|
category: feedback
|
|
7
7
|
since: 0.1.0
|
|
8
8
|
package: '@teamix-evo/ui'
|
|
9
|
+
alias: sheet
|
|
9
10
|
---
|
|
10
11
|
|
|
11
|
-
# Drawer
|
|
12
|
+
# Drawer 抽屉(Sheet 别名)
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
Drawer 现在是 Sheet 的 re-export 别名。所有能力(side / size / header / body / footer / 圆角)与 Sheet 完全一致。
|
|
15
|
+
保留本 entry 仅为向后兼容 — 已有的 `import { Drawer, DrawerContent } from '...'` 不会断裂。
|
|
16
|
+
|
|
17
|
+
> **新代码推荐直接使用 Sheet。**
|
|
15
18
|
|
|
16
19
|
## When to use
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
- 触屏可拖拽 dismiss 的临时面板
|
|
20
|
-
- 需要 iOS / 现代移动 OS 视觉一致性的场景
|
|
21
|
+
与 Sheet 相同 — 参见 [Sheet](../sheet/sheet.meta.md)。
|
|
21
22
|
|
|
22
23
|
## When NOT to use
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
- 阻断式确认 → `AlertDialog`
|
|
26
|
-
- 普通模态 → `Dialog`
|
|
27
|
-
|
|
28
|
-
> 实际项目通常**响应式切换**:`md` 以下用 Drawer,`md` 以上用 Sheet/Dialog。
|
|
25
|
+
与 Sheet 相同 — 参见 [Sheet](../sheet/sheet.meta.md)。
|
|
29
26
|
|
|
30
27
|
## Props
|
|
31
28
|
|
|
32
|
-
>
|
|
29
|
+
> DrawerContent 的 props 与 SheetContent 完全一致(类型别名)。
|
|
33
30
|
|
|
34
31
|
<!-- auto:props:begin -->
|
|
35
|
-
|
|
36
|
-
_(no props)_
|
|
37
|
-
|
|
32
|
+
_(组件无 `<Name>Props` interface — props 详见 [`drawer.tsx`](./drawer.tsx))_
|
|
38
33
|
<!-- auto:props:end -->
|
|
39
34
|
|
|
40
35
|
## 依赖
|
|
@@ -42,45 +37,39 @@ _(no props)_
|
|
|
42
37
|
> 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`manifest.json`](../../../manifest.json)。**手工编辑 marker 之间的内容会在下次生成时被覆盖**。
|
|
43
38
|
|
|
44
39
|
<!-- auto:deps:begin -->
|
|
45
|
-
|
|
46
40
|
### 同库依赖
|
|
47
41
|
|
|
48
42
|
> `teamix-evo ui add drawer` 时,以下 entry 会被自动连带安装(无需手动 add)。
|
|
49
43
|
|
|
50
|
-
| Entry | 类型 | 描述
|
|
51
|
-
|
|
|
52
|
-
| `
|
|
44
|
+
| Entry | 类型 | 描述 |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `sheet` | component | 侧边面板 — Radix Dialog + side(left/right/top/bottom) + size(sm/md/lg/xl) + --radius-dialog 圆角,对齐 antd Drawer 全能力集 |
|
|
47
|
+
| `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
|
|
53
48
|
|
|
54
49
|
### npm 依赖
|
|
55
50
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
pnpm add vaul@^1.0.0
|
|
60
|
-
```
|
|
61
|
-
|
|
51
|
+
_无 — 本组件不依赖任何 npm 包。_
|
|
62
52
|
<!-- auto:deps:end -->
|
|
63
53
|
|
|
64
|
-
>
|
|
54
|
+
> 导出映射:`Drawer=Sheet` / `DrawerContent=SheetContent` / `DrawerHeader=SheetHeader` / `DrawerBody=SheetBody` / `DrawerFooter=SheetFooter` / `DrawerTitle=SheetTitle` / `DrawerDescription=SheetDescription` / `DrawerClose=SheetClose`。
|
|
65
55
|
|
|
66
56
|
## AI 生成纪律
|
|
67
57
|
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
- **`snapPoints`**:支持半屏 / 全屏阶段(如 `['148px', '300px', 1]`),vaul 原生
|
|
72
|
-
- **不要在 Drawer 内放 Drawer**:嵌套抽屉是反模式
|
|
58
|
+
- **新代码不要使用 Drawer**:统一用 Sheet,Drawer 仅保持已有代码兼容
|
|
59
|
+
- **Drawer 与 Sheet 能力完全等价**:side / size / header / body / footer 行为一致
|
|
60
|
+
- 其余纪律参见 [Sheet meta](../sheet/sheet.meta.md)
|
|
73
61
|
|
|
74
62
|
## Examples
|
|
75
63
|
|
|
76
64
|
```tsx
|
|
65
|
+
// 向后兼容写法(不推荐新代码使用)
|
|
77
66
|
import {
|
|
78
67
|
Drawer,
|
|
79
68
|
DrawerTrigger,
|
|
80
69
|
DrawerContent,
|
|
81
70
|
DrawerHeader,
|
|
71
|
+
DrawerBody,
|
|
82
72
|
DrawerTitle,
|
|
83
|
-
DrawerDescription,
|
|
84
73
|
DrawerFooter,
|
|
85
74
|
DrawerClose,
|
|
86
75
|
} from '@/components/ui/drawer';
|
|
@@ -88,19 +77,18 @@ import { Button } from '@/components/ui/button';
|
|
|
88
77
|
|
|
89
78
|
<Drawer>
|
|
90
79
|
<DrawerTrigger asChild>
|
|
91
|
-
<Button variant="outline"
|
|
80
|
+
<Button variant="outline">打开</Button>
|
|
92
81
|
</DrawerTrigger>
|
|
93
|
-
<DrawerContent>
|
|
82
|
+
<DrawerContent side="right" size="md">
|
|
94
83
|
<DrawerHeader>
|
|
95
|
-
<DrawerTitle
|
|
96
|
-
<DrawerDescription>讨论将通知到该项目所有成员。</DrawerDescription>
|
|
84
|
+
<DrawerTitle>编辑</DrawerTitle>
|
|
97
85
|
</DrawerHeader>
|
|
98
|
-
<
|
|
86
|
+
<DrawerBody>{/* content */}</DrawerBody>
|
|
99
87
|
<DrawerFooter>
|
|
100
|
-
<Button>提交</Button>
|
|
101
88
|
<DrawerClose asChild>
|
|
102
89
|
<Button variant="outline">取消</Button>
|
|
103
90
|
</DrawerClose>
|
|
91
|
+
<Button>确定</Button>
|
|
104
92
|
</DrawerFooter>
|
|
105
93
|
</DrawerContent>
|
|
106
94
|
</Drawer>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
2
|
import {
|
|
3
3
|
Drawer,
|
|
4
4
|
DrawerTrigger,
|
|
5
5
|
DrawerContent,
|
|
6
6
|
DrawerHeader,
|
|
7
|
+
DrawerBody,
|
|
7
8
|
DrawerTitle,
|
|
8
9
|
DrawerDescription,
|
|
9
10
|
DrawerFooter,
|
|
@@ -12,41 +13,57 @@ import {
|
|
|
12
13
|
import { Button } from '@/components/button/button';
|
|
13
14
|
|
|
14
15
|
const meta: Meta<typeof DrawerContent> = {
|
|
15
|
-
title: '
|
|
16
|
+
title: '反馈 · Feedback/Drawer (alias)',
|
|
16
17
|
component: DrawerContent,
|
|
17
18
|
tags: ['autodocs'],
|
|
18
19
|
parameters: {
|
|
19
20
|
docs: {
|
|
20
21
|
description: {
|
|
21
22
|
component:
|
|
22
|
-
'
|
|
23
|
+
'抽屉(Sheet 别名) —— Drawer 现为 Sheet 的 re-export 别名,保持向后兼容。所有能力(`side`/`size`/header/body/footer/圆角)与 Sheet 完全一致,新代码推荐直接使用 Sheet。Radix Dialog 内核 + cva side/size 双变体,对齐 antd `Drawer`:`side`、`size`、`showClose`。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/tokens`,无 mock。',
|
|
23
24
|
},
|
|
24
25
|
},
|
|
25
26
|
},
|
|
27
|
+
argTypes: {
|
|
28
|
+
side: {
|
|
29
|
+
control: 'inline-radio',
|
|
30
|
+
options: ['top', 'right', 'bottom', 'left'],
|
|
31
|
+
},
|
|
32
|
+
size: {
|
|
33
|
+
control: 'inline-radio',
|
|
34
|
+
options: ['sm', 'md', 'lg', 'xl'],
|
|
35
|
+
},
|
|
36
|
+
showClose: {
|
|
37
|
+
control: 'boolean',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
args: { side: 'right', size: 'md', showClose: true },
|
|
26
41
|
};
|
|
27
42
|
|
|
28
43
|
export default meta;
|
|
29
44
|
type Story = StoryObj<typeof DrawerContent>;
|
|
30
45
|
|
|
31
46
|
export const Playground: Story = {
|
|
32
|
-
render: () => (
|
|
47
|
+
render: (args) => (
|
|
33
48
|
<Drawer>
|
|
34
49
|
<DrawerTrigger asChild>
|
|
35
|
-
<Button variant="outline">打开 Drawer</Button>
|
|
50
|
+
<Button variant="outline">打开 Drawer (alias)</Button>
|
|
36
51
|
</DrawerTrigger>
|
|
37
|
-
<DrawerContent>
|
|
52
|
+
<DrawerContent {...args}>
|
|
38
53
|
<DrawerHeader>
|
|
39
|
-
<DrawerTitle
|
|
40
|
-
<DrawerDescription>讨论将通知到该项目所有成员。</DrawerDescription>
|
|
54
|
+
<DrawerTitle>编辑资料</DrawerTitle>
|
|
41
55
|
</DrawerHeader>
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
<DrawerBody>
|
|
57
|
+
<DrawerDescription>Drawer 现在等同于 Sheet。</DrawerDescription>
|
|
58
|
+
<div className="py-4 text-sm text-muted-foreground">
|
|
59
|
+
内容区域...
|
|
60
|
+
</div>
|
|
61
|
+
</DrawerBody>
|
|
45
62
|
<DrawerFooter>
|
|
46
|
-
<Button>提交</Button>
|
|
47
63
|
<DrawerClose asChild>
|
|
48
64
|
<Button variant="outline">取消</Button>
|
|
49
65
|
</DrawerClose>
|
|
66
|
+
<Button>确定</Button>
|
|
50
67
|
</DrawerFooter>
|
|
51
68
|
</DrawerContent>
|
|
52
69
|
</Drawer>
|