@teamix-evo/ui 0.7.1 → 0.7.2
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/manifest.json +16 -7
- package/package.json +4 -4
- package/src/_design-system/theme-tokens/stories.tsx +2 -2
- package/src/components/accordion/index.tsx +1 -1
- package/src/components/affix/meta.md +26 -0
- package/src/components/alert/index.tsx +2 -2
- package/src/components/alert-dialog/index.tsx +3 -3
- package/src/components/alert-dialog/meta.md +52 -0
- package/src/components/alert-dialog/stories.tsx +45 -48
- package/src/components/avatar/index.tsx +1 -1
- package/src/components/badge/index.tsx +2 -2
- package/src/components/badge/meta.md +48 -0
- package/src/components/button/index.tsx +2 -2
- package/src/components/button/meta.md +15 -0
- package/src/components/button/stories.tsx +1 -1
- package/src/components/calendar/index.tsx +2 -2
- package/src/components/card/index.tsx +1 -1
- package/src/components/carousel/index.tsx +2 -2
- package/src/components/carousel/meta.md +34 -2
- package/src/components/carousel/stories.tsx +2 -2
- package/src/components/cascader-select/index.tsx +2 -1
- package/src/components/cascader-select/meta.md +46 -0
- package/src/components/checkbox/meta.md +47 -0
- package/src/components/color-picker/index.tsx +3 -3
- package/src/components/color-picker/meta.md +80 -0
- package/src/components/combobox/index.tsx +2 -2
- package/src/components/combobox/meta.md +130 -0
- package/src/components/data-table/index.tsx +2 -2
- package/src/components/data-table/meta.md +419 -0
- package/src/components/date-picker/meta.md +91 -0
- package/src/components/descriptions/index.tsx +1 -1
- package/src/components/descriptions/meta.md +245 -0
- package/src/components/dialog/index.tsx +4 -4
- package/src/components/dialog/meta.md +47 -1
- package/src/components/dialog/stories.tsx +38 -41
- package/src/components/dropdown-menu/index.tsx +5 -5
- package/src/components/empty/index.tsx +2 -2
- package/src/components/field/index.tsx +4 -4
- package/src/components/filter-bar/index.tsx +6 -6
- package/src/components/filter-bar/meta.md +323 -0
- package/src/components/float-button/index.tsx +2 -2
- package/src/components/form/index.tsx +1 -1
- package/src/components/form/meta.md +119 -0
- package/src/components/hover-card/index.tsx +1 -1
- package/src/components/hover-card/meta.md +21 -0
- package/src/components/input/meta.md +16 -0
- package/src/components/input-group/index.tsx +1 -1
- package/src/components/input-group/meta.md +118 -0
- package/src/components/input-group/stories.tsx +6 -6
- package/src/components/input-ip/index.tsx +2 -2
- package/src/components/input-ip/meta.md +30 -0
- package/src/components/input-ip/stories.tsx +2 -2
- package/src/components/input-number/index.tsx +3 -2
- package/src/components/input-number/meta.md +67 -0
- package/src/components/input-number/stories.tsx +2 -2
- package/src/components/item/index.tsx +4 -4
- package/src/components/label/meta.md +8 -0
- package/src/components/mentions/meta.md +15 -0
- package/src/components/menubar/index.tsx +4 -4
- package/src/components/navigation-menu/index.tsx +4 -4
- package/src/components/page-header/index.tsx +1 -1
- package/src/components/page-header/meta.md +145 -0
- package/src/components/page-shell/index.tsx +2 -2
- package/src/components/pagination/index.tsx +1 -1
- package/src/components/pagination/meta.md +203 -0
- package/src/components/popconfirm/meta.md +45 -0
- package/src/components/popover/index.tsx +2 -2
- package/src/components/popover/meta.md +47 -0
- package/src/components/progress/index.tsx +1 -1
- package/src/components/progress/meta.md +36 -0
- package/src/components/progress/stories.tsx +1 -1
- package/src/components/radio-group/meta.md +69 -0
- package/src/components/rate/index.tsx +1 -1
- package/src/components/rate/meta.md +50 -0
- package/src/components/resizable/index.tsx +1 -1
- package/src/components/select/index.tsx +2 -2
- package/src/components/select/meta.md +20 -0
- package/src/components/separator/index.tsx +1 -1
- package/src/components/sheet/index.tsx +13 -14
- package/src/components/sheet/meta.md +124 -0
- package/src/components/sheet/stories.tsx +110 -119
- package/src/components/sidebar/index.tsx +5 -5
- package/src/components/sidebar/meta.md +383 -0
- package/src/components/skeleton/meta.md +13 -0
- package/src/components/slider/index.tsx +2 -2
- package/src/components/sonner/meta.md +86 -0
- package/src/components/spinner/meta.md +46 -0
- package/src/components/spinner/stories.tsx +2 -2
- package/src/components/steps/meta.md +20 -0
- package/src/components/steps/stories.tsx +1 -1
- package/src/components/switch/index.tsx +2 -2
- package/src/components/switch/meta.md +33 -0
- package/src/components/table/index.tsx +2 -2
- package/src/components/table/meta.md +11 -0
- package/src/components/tabs/index.tsx +7 -7
- package/src/components/tabs/meta.md +52 -0
- package/src/components/tag/index.tsx +8 -8
- package/src/components/tag/meta.md +194 -0
- package/src/components/textarea/index.tsx +1 -1
- package/src/components/textarea/meta.md +27 -0
- package/src/components/textarea/stories.tsx +1 -1
- package/src/components/time-picker/index.tsx +3 -3
- package/src/components/time-picker/meta.md +76 -0
- package/src/components/timeline/index.tsx +1 -0
- package/src/components/toggle/index.tsx +1 -1
- package/src/components/toggle-group/index.tsx +1 -1
- package/src/components/tooltip/index.tsx +1 -1
- package/src/components/tooltip/meta.md +23 -0
- package/src/components/transfer/index.tsx +2 -2
- package/src/components/transfer/meta.md +97 -0
- package/src/components/tree/index.tsx +245 -15
- package/src/components/tree/meta.md +151 -0
- package/src/components/tree-select/index.tsx +16 -2
- package/src/components/tree-select/meta.md +150 -0
- package/src/components/typography/index.tsx +3 -3
- package/src/components/upload/index.tsx +3 -3
- package/src/components/upload/meta.md +82 -0
- package/src/components/tree/utils.ts +0 -269
- package/src/examples/built-in-assets/stories.tsx +0 -572
- package/src/examples/evaluators/stories.tsx +0 -502
|
@@ -37,3 +37,206 @@
|
|
|
37
37
|
| `showQuickJumper` | `boolean` | `false` | – | normal 类型下显示快速跳转输入框。 |
|
|
38
38
|
| `siblingCount` | `number` | `5` | – | 中间显示几个页号(建议奇数)。 |
|
|
39
39
|
| `className` | `string` | – | – | 容器 className。 |
|
|
40
|
+
|
|
41
|
+
## 示例
|
|
42
|
+
|
|
43
|
+
### Playground
|
|
44
|
+
|
|
45
|
+
完全可交互的受控分页,可通过 Controls 面板调整所有参数。
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
<Pagination
|
|
49
|
+
{...args}
|
|
50
|
+
current={page}
|
|
51
|
+
showQuickJumper
|
|
52
|
+
onChange={(p) => setPage(p)}
|
|
53
|
+
/>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Uncontrolled
|
|
57
|
+
|
|
58
|
+
非受控模式,组件自行管理当前页状态。
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
<Pagination total={245} defaultCurrent={2} />
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Types
|
|
65
|
+
|
|
66
|
+
三种类型对比:normal(完整)/ simple(简化)/ mini(极简)。
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
<div className="flex flex-col gap-6">
|
|
70
|
+
<div className="flex flex-col gap-1">
|
|
71
|
+
<span className="text-xs text-muted-foreground">normal</span>
|
|
72
|
+
<Pagination
|
|
73
|
+
total={245}
|
|
74
|
+
type="normal"
|
|
75
|
+
current={p1}
|
|
76
|
+
onChange={(p) => setP1(p)}
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
<div className="flex flex-col gap-1">
|
|
80
|
+
<span className="text-xs text-muted-foreground">simple</span>
|
|
81
|
+
<Pagination
|
|
82
|
+
total={245}
|
|
83
|
+
type="simple"
|
|
84
|
+
current={p2}
|
|
85
|
+
onChange={(p) => setP2(p)}
|
|
86
|
+
/>
|
|
87
|
+
</div>
|
|
88
|
+
<div className="flex flex-col gap-1">
|
|
89
|
+
<span className="text-xs text-muted-foreground">mini</span>
|
|
90
|
+
<Pagination
|
|
91
|
+
total={245}
|
|
92
|
+
type="mini"
|
|
93
|
+
current={p3}
|
|
94
|
+
onChange={(p) => setP3(p)}
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Sizes
|
|
101
|
+
|
|
102
|
+
三档尺寸对比:sm(h-6) / md(h-8) / lg(h-9)。
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<div className="flex flex-col gap-6">
|
|
106
|
+
<div className="flex flex-col gap-1">
|
|
107
|
+
<span className="text-xs text-muted-foreground">sm</span>
|
|
108
|
+
<Pagination
|
|
109
|
+
total={245}
|
|
110
|
+
size="sm"
|
|
111
|
+
current={p1}
|
|
112
|
+
onChange={(p) => setP1(p)}
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
<div className="flex flex-col gap-1">
|
|
116
|
+
<span className="text-xs text-muted-foreground">md</span>
|
|
117
|
+
<Pagination
|
|
118
|
+
total={245}
|
|
119
|
+
size="md"
|
|
120
|
+
current={p2}
|
|
121
|
+
onChange={(p) => setP2(p)}
|
|
122
|
+
/>
|
|
123
|
+
</div>
|
|
124
|
+
<div className="flex flex-col gap-1">
|
|
125
|
+
<span className="text-xs text-muted-foreground">lg</span>
|
|
126
|
+
<Pagination
|
|
127
|
+
total={245}
|
|
128
|
+
size="lg"
|
|
129
|
+
current={p3}
|
|
130
|
+
onChange={(p) => setP3(p)}
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Matrix
|
|
137
|
+
|
|
138
|
+
type × size 的完整矩阵(9 个组合),用于一眼比对视觉密度。
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
<div className="flex flex-col gap-6">
|
|
142
|
+
{types.map((t) => (
|
|
143
|
+
<div key={t} className="flex flex-col gap-3">
|
|
144
|
+
<div className="text-sm font-medium text-muted-foreground">
|
|
145
|
+
type = {t}
|
|
146
|
+
</div>
|
|
147
|
+
{sizes.map((s) => (
|
|
148
|
+
<MatrixRow key={`${t}-${s}`} type={t} size={s} />
|
|
149
|
+
))}
|
|
150
|
+
</div>
|
|
151
|
+
))}
|
|
152
|
+
</div>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### WithPageSizeSelector
|
|
156
|
+
|
|
157
|
+
启用 showSizeChanger,用户可切换每页显示条数。
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
<Pagination
|
|
161
|
+
total={1234}
|
|
162
|
+
current={page}
|
|
163
|
+
pageSize={size}
|
|
164
|
+
showSizeChanger
|
|
165
|
+
pageSizeOptions={[10, 20, 50, 100]}
|
|
166
|
+
onChange={(p, s) => {
|
|
167
|
+
setPage(p);
|
|
168
|
+
setSize(s);
|
|
169
|
+
}}
|
|
170
|
+
onPageSizeChange={(s) => setSize(s)}
|
|
171
|
+
/>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### WithJumpAndFirstLast
|
|
175
|
+
|
|
176
|
+
启用跳转输入框 + 首末页快捷按钮 + showSizeChanger 的完整形态。
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
<Pagination
|
|
180
|
+
total={1234}
|
|
181
|
+
current={page}
|
|
182
|
+
showFirstLast
|
|
183
|
+
showQuickJumper
|
|
184
|
+
showSizeChanger
|
|
185
|
+
onChange={(p) => setPage(p)}
|
|
186
|
+
/>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### CustomTotal
|
|
190
|
+
|
|
191
|
+
自定义 totalRender 函数,展示 "1-10 of 245" 格式。
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
<Pagination
|
|
195
|
+
total={245}
|
|
196
|
+
current={page}
|
|
197
|
+
onChange={(p) => setPage(p)}
|
|
198
|
+
totalRender={(t, [s, e]) => `${s}–${e} of ${t}`}
|
|
199
|
+
/>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### HideJump
|
|
203
|
+
|
|
204
|
+
showQuickJumper=false 时强制隐藏跳转框(即使页数较多)。
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
<Pagination
|
|
208
|
+
total={500}
|
|
209
|
+
current={page}
|
|
210
|
+
showQuickJumper={false}
|
|
211
|
+
onChange={(p) => setPage(p)}
|
|
212
|
+
/>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### FewItems
|
|
216
|
+
|
|
217
|
+
数据少于一页时的展示效果(仅 1 页)。
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
const [page, setPage] = React.useState(1);
|
|
221
|
+
return <Pagination total={5} current={page} onChange={(p) => setPage(p)} />;
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### LargeDataset
|
|
225
|
+
|
|
226
|
+
大数据量(10000 条)带 showSizeChanger 和跳转。
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
<Pagination
|
|
230
|
+
total={10000}
|
|
231
|
+
current={page}
|
|
232
|
+
pageSize={size}
|
|
233
|
+
showSizeChanger
|
|
234
|
+
showQuickJumper
|
|
235
|
+
showFirstLast
|
|
236
|
+
onChange={(p, s) => {
|
|
237
|
+
setPage(p);
|
|
238
|
+
setSize(s);
|
|
239
|
+
}}
|
|
240
|
+
onPageSizeChange={(s) => setSize(s)}
|
|
241
|
+
/>
|
|
242
|
+
```
|
|
@@ -98,6 +98,31 @@
|
|
|
98
98
|
</Popconfirm>
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
### Controlled
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
const ControlledDemo = () => {
|
|
105
|
+
const [open, setOpen] = React.useState(false);
|
|
106
|
+
return (
|
|
107
|
+
<div className="flex items-center gap-4">
|
|
108
|
+
<Popconfirm
|
|
109
|
+
open={open}
|
|
110
|
+
onOpenChange={setOpen}
|
|
111
|
+
title="受控确认"
|
|
112
|
+
description="open / onOpenChange 受外部驱动。"
|
|
113
|
+
onConfirm={() => console.log('confirmed')}
|
|
114
|
+
>
|
|
115
|
+
<Button>触发</Button>
|
|
116
|
+
</Popconfirm>
|
|
117
|
+
<span className="text-xs text-muted-foreground">
|
|
118
|
+
当前:{open ? '打开' : '关闭'}
|
|
119
|
+
</span>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
return <ControlledDemo />;
|
|
124
|
+
```
|
|
125
|
+
|
|
101
126
|
### CustomButtons
|
|
102
127
|
|
|
103
128
|
```tsx
|
|
@@ -125,6 +150,26 @@
|
|
|
125
150
|
</div>
|
|
126
151
|
```
|
|
127
152
|
|
|
153
|
+
### Placement
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
<div className="grid grid-cols-3 gap-4">
|
|
157
|
+
{sides.flatMap((side) =>
|
|
158
|
+
aligns.map((align) => (
|
|
159
|
+
<Popconfirm
|
|
160
|
+
key={`${side}-${align}`}
|
|
161
|
+
title={`${side} / ${align}`}
|
|
162
|
+
side={side}
|
|
163
|
+
align={align}
|
|
164
|
+
onConfirm={() => {}}
|
|
165
|
+
>
|
|
166
|
+
<Button>{`${side}-${align}`}</Button>
|
|
167
|
+
</Popconfirm>
|
|
168
|
+
)),
|
|
169
|
+
)}
|
|
170
|
+
</div>
|
|
171
|
+
```
|
|
172
|
+
|
|
128
173
|
### Disabled
|
|
129
174
|
|
|
130
175
|
```tsx
|
|
@@ -67,7 +67,7 @@ function PopoverContent({
|
|
|
67
67
|
align={align}
|
|
68
68
|
sideOffset={sideOffset}
|
|
69
69
|
className={cn(
|
|
70
|
-
'group/popover-content relative z-50 flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-2.5 rounded-md bg-popover p-2.5 text-xs text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=
|
|
70
|
+
'group/popover-content relative z-50 flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-2.5 rounded-md bg-popover p-2.5 text-xs text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
|
|
71
71
|
className,
|
|
72
72
|
)}
|
|
73
73
|
{...props}
|
|
@@ -132,7 +132,7 @@ function PopoverClose({
|
|
|
132
132
|
<Comp
|
|
133
133
|
data-slot="popover-close"
|
|
134
134
|
className={cn(
|
|
135
|
-
'absolute
|
|
135
|
+
'absolute top-2 right-2 inline-flex size-6 cursor-pointer items-center justify-center rounded-sm text-muted-foreground opacity-70 transition-opacity hover:opacity-100 focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none',
|
|
136
136
|
className,
|
|
137
137
|
)}
|
|
138
138
|
{...props}
|
|
@@ -60,6 +60,32 @@
|
|
|
60
60
|
</div>
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
### Controlled
|
|
64
|
+
|
|
65
|
+
受控显示,点击内部按钮可程序化关闭。
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
69
|
+
<PopoverTrigger asChild>
|
|
70
|
+
<Button>{open ? '收起' : '打开'}</Button>
|
|
71
|
+
</PopoverTrigger>
|
|
72
|
+
<PopoverContent>
|
|
73
|
+
<PopoverHeader>
|
|
74
|
+
<PopoverTitle>受控示例</PopoverTitle>
|
|
75
|
+
<PopoverDescription>open / onOpenChange 受控</PopoverDescription>
|
|
76
|
+
</PopoverHeader>
|
|
77
|
+
<div className="flex justify-end gap-2">
|
|
78
|
+
<Button size="sm" onClick={() => setOpen(false)}>
|
|
79
|
+
取消
|
|
80
|
+
</Button>
|
|
81
|
+
<Button size="sm" onClick={() => setOpen(false)}>
|
|
82
|
+
确认
|
|
83
|
+
</Button>
|
|
84
|
+
</div>
|
|
85
|
+
</PopoverContent>
|
|
86
|
+
</Popover>
|
|
87
|
+
```
|
|
88
|
+
|
|
63
89
|
### WithCloseButton
|
|
64
90
|
|
|
65
91
|
显示关闭按钮,覆盖 Balloon `closable` 行为。
|
|
@@ -80,6 +106,27 @@
|
|
|
80
106
|
</Popover>
|
|
81
107
|
```
|
|
82
108
|
|
|
109
|
+
### AllPositions
|
|
110
|
+
|
|
111
|
+
12 方向矩阵:side × align 组合。
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
<div className="grid grid-cols-3 gap-4">
|
|
115
|
+
{sides.flatMap((side) =>
|
|
116
|
+
aligns.map((align) => (
|
|
117
|
+
<Popover key={`${side}-${align}`}>
|
|
118
|
+
<PopoverTrigger asChild>
|
|
119
|
+
<Button>{`${side}-${align}`}</Button>
|
|
120
|
+
</PopoverTrigger>
|
|
121
|
+
<PopoverContent side={side} align={align}>
|
|
122
|
+
<p className="text-muted-foreground">{`${side} / ${align}`}</p>
|
|
123
|
+
</PopoverContent>
|
|
124
|
+
</Popover>
|
|
125
|
+
)),
|
|
126
|
+
)}
|
|
127
|
+
</div>
|
|
128
|
+
```
|
|
129
|
+
|
|
83
130
|
### WithArrow
|
|
84
131
|
|
|
85
132
|
显示尖角箭头。
|
|
@@ -165,7 +165,7 @@ function Progress({
|
|
|
165
165
|
{track}
|
|
166
166
|
<span
|
|
167
167
|
data-slot="progress-info"
|
|
168
|
-
className="min-w-9 shrink-0 text-right text-xs
|
|
168
|
+
className="min-w-9 shrink-0 text-right text-xs text-muted-foreground tabular-nums"
|
|
169
169
|
>
|
|
170
170
|
{format ? format(safeValue, max) : `${Math.floor(pct)}%`}
|
|
171
171
|
</span>
|
|
@@ -93,3 +93,39 @@ size / 语义色 / 渐进色 / 百分比文本 / 自定义渲染等业界流行
|
|
|
93
93
|
/>
|
|
94
94
|
</div>
|
|
95
95
|
```
|
|
96
|
+
|
|
97
|
+
### Indeterminate
|
|
98
|
+
|
|
99
|
+
不确定态:value={null} 时展示常驻动画,不显示百分比文本。
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
<Progress value={null} className="w-64" />
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Controlled
|
|
106
|
+
|
|
107
|
+
受控加减:模拟实时进度更新,搭配 progressive 颜色自动切换。
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
<div className="flex w-80 flex-col gap-3">
|
|
111
|
+
<div className="flex gap-2">
|
|
112
|
+
<Button
|
|
113
|
+
size="sm"
|
|
114
|
+
variant="outline"
|
|
115
|
+
disabled={value === 0}
|
|
116
|
+
onClick={() => setValue((v) => Math.max(0, v - 10))}
|
|
117
|
+
>
|
|
118
|
+
-10
|
|
119
|
+
</Button>
|
|
120
|
+
<Button
|
|
121
|
+
size="sm"
|
|
122
|
+
variant="outline"
|
|
123
|
+
disabled={value === 100}
|
|
124
|
+
onClick={() => setValue((v) => Math.min(100, v + 10))}
|
|
125
|
+
>
|
|
126
|
+
+10
|
|
127
|
+
</Button>
|
|
128
|
+
</div>
|
|
129
|
+
<Progress value={value} progressive showInfo size="lg" />
|
|
130
|
+
</div>
|
|
131
|
+
```
|
|
@@ -86,7 +86,7 @@ export const Indeterminate: Story = {
|
|
|
86
86
|
|
|
87
87
|
/** 受控加减:模拟实时进度更新,搭配 progressive 颜色自动切换。 */
|
|
88
88
|
export const Controlled: Story = {
|
|
89
|
-
render:
|
|
89
|
+
render: () => {
|
|
90
90
|
const [value, setValue] = React.useState(0);
|
|
91
91
|
return (
|
|
92
92
|
<div className="flex w-80 flex-col gap-3">
|
|
@@ -85,6 +85,28 @@
|
|
|
85
85
|
</div>
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
### Controlled
|
|
89
|
+
|
|
90
|
+
受控用法 + `onValueChange` 回调。
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<div className="flex flex-col gap-3">
|
|
94
|
+
<RadioGroup value={value} onValueChange={setValue}>
|
|
95
|
+
{FRUITS.map((opt) => (
|
|
96
|
+
<div key={opt.value} className="flex items-center gap-2">
|
|
97
|
+
<RadioGroupItem value={opt.value} id={`c-${opt.value}`} />
|
|
98
|
+
<label htmlFor={`c-${opt.value}`} className="text-xs">
|
|
99
|
+
{opt.label}
|
|
100
|
+
</label>
|
|
101
|
+
</div>
|
|
102
|
+
))}
|
|
103
|
+
</RadioGroup>
|
|
104
|
+
<div className="text-xs text-muted-foreground">
|
|
105
|
+
已选:{value || '无'}
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
```
|
|
109
|
+
|
|
88
110
|
### WithList
|
|
89
111
|
|
|
90
112
|
数据驱动写法:业务侧用 `.map` 渲染,无需内置 `dataSource`。
|
|
@@ -135,3 +157,50 @@
|
|
|
135
157
|
</RadioGroup>
|
|
136
158
|
</div>
|
|
137
159
|
```
|
|
160
|
+
|
|
161
|
+
### InsideForm
|
|
162
|
+
|
|
163
|
+
与 react-hook-form Form 集成:`FormField` 接管 value / onChange / aria。
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
<Form {...form}>
|
|
167
|
+
<form
|
|
168
|
+
onSubmit={form.handleSubmit((data) => console.log(data))}
|
|
169
|
+
className="flex w-72 flex-col gap-4"
|
|
170
|
+
>
|
|
171
|
+
<FormField
|
|
172
|
+
name="plan"
|
|
173
|
+
rules={{ required: '请选择套餐' }}
|
|
174
|
+
render={({ field }) => (
|
|
175
|
+
<FormItem>
|
|
176
|
+
<FormLabel>套餐</FormLabel>
|
|
177
|
+
<FormControl>
|
|
178
|
+
<RadioGroup
|
|
179
|
+
value={field.value}
|
|
180
|
+
onValueChange={field.onChange}
|
|
181
|
+
>
|
|
182
|
+
{[
|
|
183
|
+
{ value: 'free', label: '免费版' },
|
|
184
|
+
{ value: 'pro', label: '专业版' },
|
|
185
|
+
{ value: 'enterprise', label: '企业版' },
|
|
186
|
+
].map((opt) => (
|
|
187
|
+
<div key={opt.value} className="flex items-center gap-2">
|
|
188
|
+
<RadioGroupItem
|
|
189
|
+
value={opt.value}
|
|
190
|
+
id={`f-${opt.value}`}
|
|
191
|
+
/>
|
|
192
|
+
<label htmlFor={`f-${opt.value}`} className="text-xs">
|
|
193
|
+
{opt.label}
|
|
194
|
+
</label>
|
|
195
|
+
</div>
|
|
196
|
+
))}
|
|
197
|
+
</RadioGroup>
|
|
198
|
+
</FormControl>
|
|
199
|
+
<FormMessage />
|
|
200
|
+
</FormItem>
|
|
201
|
+
)}
|
|
202
|
+
/>
|
|
203
|
+
<Button type="submit">提交</Button>
|
|
204
|
+
</form>
|
|
205
|
+
</Form>
|
|
206
|
+
```
|
|
@@ -177,7 +177,7 @@ function Rate({
|
|
|
177
177
|
aria-readonly={readOnly || undefined}
|
|
178
178
|
tabIndex={interactive ? 0 : -1}
|
|
179
179
|
className={cn(
|
|
180
|
-
'inline-flex items-center gap-0.5 rounded-sm focus-visible:
|
|
180
|
+
'inline-flex items-center gap-0.5 rounded-sm focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none',
|
|
181
181
|
disabled && 'pointer-events-none opacity-50',
|
|
182
182
|
readOnly && 'pointer-events-none',
|
|
183
183
|
className,
|
|
@@ -31,6 +31,30 @@
|
|
|
31
31
|
|
|
32
32
|
## 示例
|
|
33
33
|
|
|
34
|
+
### Basic
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
<Rate defaultValue={3} />
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### HalfStar
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<Rate allowHalf defaultValue={2.5} />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Disabled
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<Rate value={3} disabled />
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### ReadOnly
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
<Rate value={4} readOnly />
|
|
56
|
+
```
|
|
57
|
+
|
|
34
58
|
### Sizes
|
|
35
59
|
|
|
36
60
|
```tsx
|
|
@@ -41,6 +65,32 @@
|
|
|
41
65
|
</div>
|
|
42
66
|
```
|
|
43
67
|
|
|
68
|
+
### CustomCount
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<Rate count={8} defaultValue={5} />
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Controlled
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
<div className="flex items-center gap-3">
|
|
78
|
+
<Rate value={value} onValueChange={setValue} />
|
|
79
|
+
<span className="text-sm text-muted-foreground">{value} / 5</span>
|
|
80
|
+
</div>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### WithLabel
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
<div className="flex items-center gap-3">
|
|
87
|
+
<Rate value={value} onValueChange={setValue} />
|
|
88
|
+
<span className="text-sm text-foreground">
|
|
89
|
+
{grades[value - 1] ?? '未评分'}
|
|
90
|
+
</span>
|
|
91
|
+
</div>
|
|
92
|
+
```
|
|
93
|
+
|
|
44
94
|
### CustomCharacter
|
|
45
95
|
|
|
46
96
|
```tsx
|
|
@@ -84,7 +84,7 @@ function ResizablePanelGroup({
|
|
|
84
84
|
<ResizablePrimitive.Group
|
|
85
85
|
data-slot="resizable-panel-group"
|
|
86
86
|
className={cn(
|
|
87
|
-
'flex
|
|
87
|
+
'flex size-full aria-[orientation=vertical]:flex-col',
|
|
88
88
|
className,
|
|
89
89
|
)}
|
|
90
90
|
{...props}
|
|
@@ -112,7 +112,7 @@ function SelectTrigger({
|
|
|
112
112
|
data-size={size}
|
|
113
113
|
data-loading={loading ? 'true' : undefined}
|
|
114
114
|
className={cn(
|
|
115
|
-
"flex w-fit cursor-pointer items-center justify-between gap-1.5 rounded-md border border-input bg-transparent py-2 pr-2 pl-2.5 text-xs whitespace-nowrap transition-colors outline-none select-none focus:border-ring focus:ring-ring/20
|
|
115
|
+
"flex w-fit cursor-pointer items-center justify-between gap-1.5 rounded-md border border-input bg-transparent py-2 pr-2 pl-2.5 text-xs whitespace-nowrap transition-colors outline-none select-none focus:border-ring focus:ring-ring/20 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=lg]:h-9 data-[size=lg]:text-sm data-[size=sm]:h-7 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 data-[state=open]:border-ring [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
116
116
|
className,
|
|
117
117
|
)}
|
|
118
118
|
{...props}
|
|
@@ -244,7 +244,7 @@ function SelectItem({
|
|
|
244
244
|
<SelectPrimitive.Item
|
|
245
245
|
data-slot="select-item"
|
|
246
246
|
className={cn(
|
|
247
|
-
"relative flex h-8 w-full cursor-pointer items-center gap-1.5 rounded-md py-1 pr-2 pl-7 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-
|
|
247
|
+
"relative flex h-8 w-full cursor-pointer items-center gap-1.5 rounded-md py-1 pr-2 pl-7 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 data-[state=checked]:text-primary [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
248
248
|
className,
|
|
249
249
|
)}
|
|
250
250
|
{...props}
|
|
@@ -150,6 +150,26 @@
|
|
|
150
150
|
</Select>
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
+
### WithClear
|
|
154
|
+
|
|
155
|
+
已选时右侧 chevron 切为 ×,点击清空 value;chevron 与 × 占同一位置、互斥。
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
<Select value={value} onValueChange={setValue}>
|
|
159
|
+
<SelectTrigger
|
|
160
|
+
className="w-56"
|
|
161
|
+
onClear={value ? () => setValue('') : undefined}
|
|
162
|
+
>
|
|
163
|
+
<SelectValue placeholder="请选择水果" />
|
|
164
|
+
</SelectTrigger>
|
|
165
|
+
<SelectContent>
|
|
166
|
+
<SelectItem value="apple">苹果</SelectItem>
|
|
167
|
+
<SelectItem value="banana">香蕉</SelectItem>
|
|
168
|
+
<SelectItem value="orange">橙子</SelectItem>
|
|
169
|
+
</SelectContent>
|
|
170
|
+
</Select>
|
|
171
|
+
```
|
|
172
|
+
|
|
153
173
|
### Loading
|
|
154
174
|
|
|
155
175
|
加载态:`<SelectTrigger loading>` 把 chevron 替换为旋转 spinner。
|
|
@@ -40,7 +40,7 @@ function Separator({
|
|
|
40
40
|
// 任何对齐上下文(items-center / items-stretch)都能看到分隔线比容器短 4px。需要全高可用 className="py-0" 覆盖。
|
|
41
41
|
'shrink-0 bg-border',
|
|
42
42
|
'data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full',
|
|
43
|
-
'data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px data-[orientation=vertical]:
|
|
43
|
+
'data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px data-[orientation=vertical]:bg-clip-content data-[orientation=vertical]:py-0.5',
|
|
44
44
|
className,
|
|
45
45
|
)}
|
|
46
46
|
{...props}
|