@teamix-evo/ui 0.7.0 → 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.
Files changed (121) hide show
  1. package/manifest.json +16 -7
  2. package/package.json +4 -4
  3. package/src/_design-system/theme-tokens/stories.tsx +2 -2
  4. package/src/components/accordion/index.tsx +1 -1
  5. package/src/components/affix/meta.md +26 -0
  6. package/src/components/alert/index.tsx +2 -2
  7. package/src/components/alert-dialog/index.tsx +3 -3
  8. package/src/components/alert-dialog/meta.md +52 -0
  9. package/src/components/alert-dialog/stories.tsx +45 -48
  10. package/src/components/avatar/index.tsx +1 -1
  11. package/src/components/badge/index.tsx +2 -2
  12. package/src/components/badge/meta.md +48 -0
  13. package/src/components/button/index.tsx +2 -2
  14. package/src/components/button/meta.md +15 -0
  15. package/src/components/button/stories.tsx +1 -1
  16. package/src/components/calendar/index.tsx +2 -2
  17. package/src/components/card/index.tsx +1 -1
  18. package/src/components/carousel/index.tsx +2 -2
  19. package/src/components/carousel/meta.md +34 -2
  20. package/src/components/carousel/stories.tsx +2 -2
  21. package/src/components/cascader-select/index.tsx +2 -1
  22. package/src/components/cascader-select/meta.md +46 -0
  23. package/src/components/checkbox/meta.md +47 -0
  24. package/src/components/color-picker/index.tsx +3 -3
  25. package/src/components/color-picker/meta.md +80 -0
  26. package/src/components/combobox/index.tsx +2 -2
  27. package/src/components/combobox/meta.md +130 -0
  28. package/src/components/data-table/index.tsx +3 -3
  29. package/src/components/data-table/meta.md +419 -0
  30. package/src/components/data-table/stories.tsx +4 -4
  31. package/src/components/date-picker/meta.md +91 -0
  32. package/src/components/descriptions/index.tsx +1 -1
  33. package/src/components/descriptions/meta.md +245 -0
  34. package/src/components/dialog/index.tsx +4 -4
  35. package/src/components/dialog/meta.md +47 -1
  36. package/src/components/dialog/stories.tsx +38 -41
  37. package/src/components/dropdown-menu/index.tsx +5 -5
  38. package/src/components/empty/index.tsx +2 -2
  39. package/src/components/field/index.tsx +4 -4
  40. package/src/components/filter-bar/index.tsx +6 -6
  41. package/src/components/filter-bar/meta.md +323 -0
  42. package/src/components/float-button/index.tsx +2 -2
  43. package/src/components/form/index.tsx +1 -1
  44. package/src/components/form/meta.md +119 -0
  45. package/src/components/hover-card/index.tsx +1 -1
  46. package/src/components/hover-card/meta.md +21 -0
  47. package/src/components/input/meta.md +16 -0
  48. package/src/components/input-group/index.tsx +1 -1
  49. package/src/components/input-group/meta.md +118 -0
  50. package/src/components/input-group/stories.tsx +6 -6
  51. package/src/components/input-ip/index.tsx +2 -2
  52. package/src/components/input-ip/meta.md +30 -0
  53. package/src/components/input-ip/stories.tsx +2 -2
  54. package/src/components/input-number/index.tsx +3 -2
  55. package/src/components/input-number/meta.md +67 -0
  56. package/src/components/input-number/stories.tsx +2 -2
  57. package/src/components/item/index.tsx +4 -4
  58. package/src/components/label/meta.md +8 -0
  59. package/src/components/mentions/meta.md +15 -0
  60. package/src/components/menubar/index.tsx +4 -4
  61. package/src/components/navigation-menu/index.tsx +4 -4
  62. package/src/components/page-header/index.tsx +2 -2
  63. package/src/components/page-header/meta.md +145 -0
  64. package/src/components/page-shell/index.tsx +3 -3
  65. package/src/components/pagination/index.tsx +1 -1
  66. package/src/components/pagination/meta.md +203 -0
  67. package/src/components/popconfirm/meta.md +45 -0
  68. package/src/components/popover/index.tsx +2 -2
  69. package/src/components/popover/meta.md +47 -0
  70. package/src/components/progress/index.tsx +1 -1
  71. package/src/components/progress/meta.md +36 -0
  72. package/src/components/progress/stories.tsx +1 -1
  73. package/src/components/radio-group/meta.md +69 -0
  74. package/src/components/rate/index.tsx +1 -1
  75. package/src/components/rate/meta.md +50 -0
  76. package/src/components/resizable/index.tsx +1 -1
  77. package/src/components/select/index.tsx +2 -2
  78. package/src/components/select/meta.md +20 -0
  79. package/src/components/separator/index.tsx +1 -1
  80. package/src/components/sheet/index.tsx +13 -14
  81. package/src/components/sheet/meta.md +124 -0
  82. package/src/components/sheet/stories.tsx +110 -119
  83. package/src/components/sidebar/index.tsx +5 -5
  84. package/src/components/sidebar/meta.md +383 -0
  85. package/src/components/skeleton/meta.md +13 -0
  86. package/src/components/slider/index.tsx +2 -2
  87. package/src/components/sonner/meta.md +86 -0
  88. package/src/components/spinner/meta.md +46 -0
  89. package/src/components/spinner/stories.tsx +2 -2
  90. package/src/components/steps/meta.md +20 -0
  91. package/src/components/steps/stories.tsx +1 -1
  92. package/src/components/switch/index.tsx +2 -2
  93. package/src/components/switch/meta.md +33 -0
  94. package/src/components/table/index.tsx +4 -4
  95. package/src/components/table/meta.md +11 -0
  96. package/src/components/tabs/index.tsx +7 -7
  97. package/src/components/tabs/meta.md +52 -0
  98. package/src/components/tag/index.tsx +8 -8
  99. package/src/components/tag/meta.md +194 -0
  100. package/src/components/textarea/index.tsx +1 -1
  101. package/src/components/textarea/meta.md +27 -0
  102. package/src/components/textarea/stories.tsx +1 -1
  103. package/src/components/time-picker/index.tsx +3 -3
  104. package/src/components/time-picker/meta.md +76 -0
  105. package/src/components/timeline/index.tsx +1 -0
  106. package/src/components/toggle/index.tsx +1 -1
  107. package/src/components/toggle-group/index.tsx +1 -1
  108. package/src/components/tooltip/index.tsx +1 -1
  109. package/src/components/tooltip/meta.md +23 -0
  110. package/src/components/transfer/index.tsx +2 -2
  111. package/src/components/transfer/meta.md +97 -0
  112. package/src/components/tree/index.tsx +245 -15
  113. package/src/components/tree/meta.md +151 -0
  114. package/src/components/tree-select/index.tsx +16 -2
  115. package/src/components/tree-select/meta.md +150 -0
  116. package/src/components/typography/index.tsx +3 -3
  117. package/src/components/upload/index.tsx +3 -3
  118. package/src/components/upload/meta.md +82 -0
  119. package/src/components/tree/utils.ts +0 -269
  120. package/src/examples/built-in-assets/stories.tsx +0 -572
  121. 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=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
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 right-2 top-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:outline-none focus-visible:ring-1 focus-visible:ring-ring',
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 tabular-nums text-muted-foreground"
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: function ControlledRender() {
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:outline-none focus-visible:ring-1 focus-visible:ring-ring',
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 h-full w-full aria-[orientation=vertical]:flex-col',
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 data-[state=open]:border-ring 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=sm]:h-7 data-[size=lg]:h-9 data-[size=lg]:text-sm *: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 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
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-[state=checked]:text-primary data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
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]:py-0.5 data-[orientation=vertical]:bg-clip-content',
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}