@_tc/template-core 0.1.4 → 0.1.6
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/.skills/tc-component-usage-skills/SKILL.md +110 -0
- package/.skills/tc-component-usage-skills/reference/component-api.md +774 -0
- package/.skills/tc-component-usage-skills/reference/examples.md +425 -0
- package/.skills/tc-component-usage-skills/reference/patterns.md +357 -0
- package/README.md +12 -5
- package/cjs/bundler/utils.js +1 -1
- package/esm/bundler/utils.js +34 -9
- package/fe/packages/ui/react/components/testPage/index.js +114 -19
- package/package.json +2 -2
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
# Component API Reference
|
|
2
|
+
|
|
3
|
+
Complete props for every `@tc/ui/react` component.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Button
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
interface ButtonProps {
|
|
11
|
+
variant?: 'default' | 'primary' | 'dashed' | 'text' | 'link'
|
|
12
|
+
size?: 'sm' | 'md' | 'lg'
|
|
13
|
+
state?: 'danger' | 'ghost'
|
|
14
|
+
loading?: boolean
|
|
15
|
+
disabled?: boolean
|
|
16
|
+
leftIcon?: ReactNode
|
|
17
|
+
rightIcon?: ReactNode
|
|
18
|
+
noUnderline?: boolean // only for link variant
|
|
19
|
+
className?: string
|
|
20
|
+
children?: ReactNode
|
|
21
|
+
onClick?: (e: MouseEvent) => void | Promise<void>
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`variant='link'` renders `<a>` tag. `SubmitButton` / `AsynchronousButton` auto-manage loading state on async onClick.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Input
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'size'> {
|
|
33
|
+
value?: string
|
|
34
|
+
defaultValue?: string
|
|
35
|
+
onChange?: (value: string, event: ChangeEvent<HTMLInputElement>) => void
|
|
36
|
+
allowClear?: boolean | { clearIcon: ReactNode }
|
|
37
|
+
addonAfter?: ReactNode
|
|
38
|
+
className?: string
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Note: `onChange` callback receives `(stringValue, event)` — two arguments, not one.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## InputNumber
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
interface InputNumberProps {
|
|
50
|
+
value?: number | null
|
|
51
|
+
defaultValue?: number
|
|
52
|
+
onChange?: (value: number | null) => void
|
|
53
|
+
min?: number
|
|
54
|
+
max?: number
|
|
55
|
+
precision?: number // decimal places
|
|
56
|
+
step?: number // default: 1
|
|
57
|
+
allowStep?: boolean // show stepper buttons
|
|
58
|
+
disabled?: boolean
|
|
59
|
+
className?: string
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Invalid/empty input becomes `null`. Raw during focus, formatted on blur.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Textarea
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
interface TextareaProps {
|
|
71
|
+
value?: string
|
|
72
|
+
defaultValue?: string
|
|
73
|
+
onChange?: (value: string, event: ChangeEvent) => void
|
|
74
|
+
maxLength?: number // default: 500
|
|
75
|
+
showCount?: boolean // default: true
|
|
76
|
+
rows?: number
|
|
77
|
+
disabled?: boolean
|
|
78
|
+
className?: string
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Character counter overlays bottom-right.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Select
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
interface SelectOption {
|
|
90
|
+
label: ReactNode
|
|
91
|
+
value: string | number
|
|
92
|
+
searchText?: string // optional separate search text
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface SelectProps {
|
|
96
|
+
options: SelectOption[]
|
|
97
|
+
value?: string | number
|
|
98
|
+
defaultValue?: string | number
|
|
99
|
+
placeholder?: string
|
|
100
|
+
onChange?: (value: string | number | undefined) => void
|
|
101
|
+
className?: string
|
|
102
|
+
disabled?: boolean
|
|
103
|
+
clearable?: boolean // default: true
|
|
104
|
+
searchable?: boolean // default: true
|
|
105
|
+
getPopupContainer?: 'parent' | (() => HTMLElement)
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`onChange` receives `undefined` on clear. When `getPopupContainer='parent'`, parent must be non-static positioned.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Checkbox
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
interface CheckboxProps {
|
|
117
|
+
checked?: boolean
|
|
118
|
+
defaultChecked?: boolean
|
|
119
|
+
indeterminate?: boolean
|
|
120
|
+
value?: boolean // controlled alias for checked
|
|
121
|
+
onChange?: (checked: boolean) => void
|
|
122
|
+
disabled?: boolean
|
|
123
|
+
className?: string
|
|
124
|
+
children?: ReactNode
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Switch
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
interface SwitchProps {
|
|
134
|
+
checked?: boolean
|
|
135
|
+
defaultChecked?: boolean
|
|
136
|
+
onChange?: (checked: boolean) => void
|
|
137
|
+
disabled?: boolean
|
|
138
|
+
className?: string
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Radio / RadioGroup
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
interface RadioGroupProps {
|
|
148
|
+
value?: string | number
|
|
149
|
+
defaultValue?: string | number
|
|
150
|
+
onChange?: (value: string | number) => void
|
|
151
|
+
direction?: 'horizontal' | 'vertical'
|
|
152
|
+
className?: string
|
|
153
|
+
children?: ReactNode
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
interface RadioProps {
|
|
157
|
+
value: string | number
|
|
158
|
+
disabled?: boolean
|
|
159
|
+
className?: string
|
|
160
|
+
children?: ReactNode
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Compound components: `<Radio.Group>` + `<Radio>`. Radio auto-detects parent context.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## DatePicker
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
type ModeType = 'single' | 'range'
|
|
172
|
+
|
|
173
|
+
interface DatePickerProps {
|
|
174
|
+
mode?: ModeType // default: 'single'
|
|
175
|
+
value?: Date | DateRange | [string, string] | string
|
|
176
|
+
defaultValue?: DateValue
|
|
177
|
+
format?: string // default: 'yyyy-MM-dd' (adds 'HH:mm' when showTime)
|
|
178
|
+
placeholder?: string
|
|
179
|
+
disabled?: boolean
|
|
180
|
+
allowClear?: boolean // default: true
|
|
181
|
+
showTime?: boolean // default: false
|
|
182
|
+
onChange?: (value?: DateChangeStrValue, date?: Dates) => void
|
|
183
|
+
disabledDate?: (current: Date) => boolean
|
|
184
|
+
className?: string
|
|
185
|
+
locale?: Partial<DateLocaleConfig>
|
|
186
|
+
quickRanges?: QuickRangePreset[]
|
|
187
|
+
getPopupContainer?: () => HTMLElement
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Accepts flexible value formats (Date, DateRange, string tuples, YYYY-MM-DD strings). Range mode has read-only input.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## TreeSelect
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
interface TreeNode {
|
|
199
|
+
id: string | number
|
|
200
|
+
name: string
|
|
201
|
+
desctext?: string
|
|
202
|
+
children?: TreeNode[]
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
interface TreeSelectProps {
|
|
206
|
+
data: TreeNode[]
|
|
207
|
+
value?: (string | number)[] // controlled checked keys
|
|
208
|
+
onChange?: (keys: { checked: (string | number)[], indeterminate: (string | number)[] }) => void
|
|
209
|
+
labelField?: 'name' | 'desctext'
|
|
210
|
+
checkable?: boolean // default: true
|
|
211
|
+
className?: string
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Tri-state checkboxes with cascading selection (parent ↔ children).
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Upload
|
|
220
|
+
|
|
221
|
+
### FileUpload
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
interface FileUploadProps {
|
|
225
|
+
inputRef?: RefObject<HTMLInputElement | null>
|
|
226
|
+
accept?: string // default: '*'
|
|
227
|
+
multiple?: boolean
|
|
228
|
+
onChange?: (event: ChangeEvent<HTMLInputElement>) => void
|
|
229
|
+
selectLabel: ReactNode
|
|
230
|
+
labelClassName?: string
|
|
231
|
+
showClear?: boolean
|
|
232
|
+
onClear?: () => void
|
|
233
|
+
clearLabel?: ReactNode
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### ImageUpload
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
interface ImageUploadProps {
|
|
241
|
+
accept?: string // default: '.jpg,.png'
|
|
242
|
+
maxCount?: number // default: 1
|
|
243
|
+
value?: string[] // controlled URLs
|
|
244
|
+
onChange?: (urls: string[]) => void
|
|
245
|
+
beforeChange?: (file: File) => boolean | void
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Uses `URL.createObjectURL` for previews; revokes on remove/unmount.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Form / FormItem / SchemaForm
|
|
254
|
+
|
|
255
|
+
### Form
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
interface FormProps<T> extends Omit<RcFormProps<T>, 'component'> {
|
|
259
|
+
className?: string
|
|
260
|
+
children?: ReactNode
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Thin wrapper around rc-field-form's `RcForm` with `component="form"`.
|
|
265
|
+
|
|
266
|
+
### FormItem
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
interface FormItemProps<T> extends Omit<FieldProps, 'children'> {
|
|
270
|
+
className?: string
|
|
271
|
+
label?: ReactNode
|
|
272
|
+
labelClassName?: string
|
|
273
|
+
required?: boolean // display indicator only
|
|
274
|
+
children?: ReactNode | ((value: T, onChange: (v: T) => void, meta: {...}) => ReactNode)
|
|
275
|
+
errorClassName?: string
|
|
276
|
+
showError?: boolean
|
|
277
|
+
layout?: 'vertical' | 'horizontal'
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Children can be a render function. Auto-clones children to inject `value`/`onChange`.
|
|
282
|
+
|
|
283
|
+
### SchemaForm
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
interface SchemaFormProps<T> {
|
|
287
|
+
form?: FormInstance<T>
|
|
288
|
+
getForm?: (formInstance: FormInstance<T>) => void
|
|
289
|
+
schemas: FormFieldSchema<T>[]
|
|
290
|
+
className?: string
|
|
291
|
+
onFinish?: (values: T) => void
|
|
292
|
+
onFinishFailed?: (errorInfo: any) => void
|
|
293
|
+
initialValues?: T
|
|
294
|
+
layout?: 'vertical' | 'horizontal' // default: 'vertical'
|
|
295
|
+
fieldLayout?: 'vertical' | 'horizontal' // default: 'vertical'
|
|
296
|
+
footerButtons?: boolean | ReactNode // default: true
|
|
297
|
+
submitText?: ReactNode
|
|
298
|
+
cancelText?: ReactNode
|
|
299
|
+
onCancel?: () => void // default: form.resetFields()
|
|
300
|
+
buttonClassName?: string
|
|
301
|
+
submitButtonProps?: Omit<ButtonElementProps, 'type' | 'onClick' | 'children'>
|
|
302
|
+
cancelButtonProps?: Omit<ButtonElementProps, 'onClick' | 'children'>
|
|
303
|
+
preserve?: boolean // default: false
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Important:** In `horizontal` layout, `footerButtons` are NOT auto-rendered. Built-in types: `input`, `inputNumber`, `select`, `textarea`, `switch`, `date`, `checkbox`. Extensible via `@tc/scalability/SchemaForm/data`.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## DataTable (generic `<T>`)
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
interface DataTableProps<T> {
|
|
315
|
+
columns: TableColumnDef<T>[]
|
|
316
|
+
data: T[]
|
|
317
|
+
rowKey?: keyof T | ((record: T, index: number) => string | number) // default: 'id'
|
|
318
|
+
rowSelection?: RowSelection<T>
|
|
319
|
+
pagination?: PaginationProps
|
|
320
|
+
loading?: boolean
|
|
321
|
+
defaultColumnWidth?: number // default: 100
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Internal pagination (pageSize: 10) when no external pagination prop. Action columns are auto-sticky right. Loading shows skeleton overlay. Empty state shows no-result image.
|
|
326
|
+
|
|
327
|
+
### TableColumnDef
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// ColumnDefForKey: maps to a data key
|
|
331
|
+
// ColumnDefAction: defines action column with actions: DropdownItem[]
|
|
332
|
+
|
|
333
|
+
// Key fields on column definition:
|
|
334
|
+
{
|
|
335
|
+
key: string
|
|
336
|
+
title: string
|
|
337
|
+
dataIndex: string
|
|
338
|
+
width?: number
|
|
339
|
+
minWidth?: number
|
|
340
|
+
maxWidth?: number
|
|
341
|
+
fixed?: 'left' | 'right'
|
|
342
|
+
sortable?: boolean
|
|
343
|
+
filterable?: boolean
|
|
344
|
+
render?: (value, record, index) => ReactNode
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Action columns render via `ActionBtn` component which supports `'auto'` | `'dropdown'` | `'inline'` overflow modes.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## TableSearch (generic `<T>`)
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
interface TableSearchProps<T> {
|
|
356
|
+
schemas: TableSearchSchema<T>[] // FormFieldSchema[] with optional isPermanent
|
|
357
|
+
onSearch?: (values: T) => void
|
|
358
|
+
onReset?: () => void
|
|
359
|
+
exportMenuItems?: DropdownItem[]
|
|
360
|
+
onExport?: (exportType: ExportType, searchData: T) => void
|
|
361
|
+
renderActionBtnArea?: () => ReactNode
|
|
362
|
+
additionalButtons?: ReactNode
|
|
363
|
+
btnConfig?: Partial<{ export, collapse, expandIcon, expand, reset, search }>
|
|
364
|
+
expandBoundaries?: number // default: 4
|
|
365
|
+
defaultExpand?: boolean // default: true
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Fields not marked `isPermanent` are hidden when collapsed. Uses `Search` internally.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Modal
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
interface ModalProps {
|
|
377
|
+
open?: boolean // default: false
|
|
378
|
+
onClose?: () => void
|
|
379
|
+
title?: ReactNode
|
|
380
|
+
children?: ReactNode
|
|
381
|
+
footer?: ReactNode
|
|
382
|
+
className?: string
|
|
383
|
+
contentClassName?: string
|
|
384
|
+
mask?: boolean // default: true
|
|
385
|
+
maskClosable?: boolean // default: true
|
|
386
|
+
lockScroll?: boolean // default: true
|
|
387
|
+
closable?: boolean // default: true
|
|
388
|
+
width?: number | string // default: 520
|
|
389
|
+
centered?: boolean // default: true (false → mt-[10vh])
|
|
390
|
+
zIndex?: number // default: 1000
|
|
391
|
+
renderNode?: HTMLElement | (() => HTMLElement)
|
|
392
|
+
keyboard?: boolean // default: true
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### ModalManager (imperative)
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
modalManager.open(config: ModalConfig): string // returns id
|
|
400
|
+
modalManager.confirm(config: ConfirmConfig): void // async onOk supported
|
|
401
|
+
modalManager.close(id: string): void
|
|
402
|
+
modalManager.closeAll(): void
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## Drawer
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
type DrawerPlacement = 'top' | 'right' | 'bottom' | 'left'
|
|
411
|
+
|
|
412
|
+
interface DrawerProps {
|
|
413
|
+
open?: boolean
|
|
414
|
+
onClose?: () => void
|
|
415
|
+
title?: ReactNode
|
|
416
|
+
children?: ReactNode
|
|
417
|
+
footer?: ReactNode
|
|
418
|
+
className?: string
|
|
419
|
+
contentClassName?: string
|
|
420
|
+
mask?: boolean // default: true
|
|
421
|
+
maskClosable?: boolean // default: true
|
|
422
|
+
lockScroll?: boolean // default: true
|
|
423
|
+
closable?: boolean // default: true
|
|
424
|
+
placement?: DrawerPlacement // default: 'right'
|
|
425
|
+
width?: number | string // default: 420 (for left/right)
|
|
426
|
+
height?: number | string // default: 360 (for top/bottom)
|
|
427
|
+
zIndex?: number // default: 1000
|
|
428
|
+
renderNode?: HTMLElement | (() => HTMLElement)
|
|
429
|
+
keyboard?: boolean // default: true
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Uses `requestAnimationFrame` for mount/unmount animation lifecycle (320ms).
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## ConfirmDialog
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
interface ConfirmDialogProps {
|
|
441
|
+
open: boolean
|
|
442
|
+
title?: string
|
|
443
|
+
content: string
|
|
444
|
+
okText?: string
|
|
445
|
+
cancelText?: string
|
|
446
|
+
loading?: boolean
|
|
447
|
+
onOk: () => void | Promise<void>
|
|
448
|
+
onCancel: () => void
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Wraps `Modal` with width: 450 and auto async-supporting ok button.
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## Popup
|
|
457
|
+
|
|
458
|
+
```typescript
|
|
459
|
+
interface PopupProps {
|
|
460
|
+
content: ReactNode
|
|
461
|
+
children: ReactElement // single child, acts as trigger
|
|
462
|
+
placement?: Placement
|
|
463
|
+
visible?: boolean // controlled
|
|
464
|
+
defaultVisible?: boolean
|
|
465
|
+
onVisibleChange?: (visible: boolean) => void
|
|
466
|
+
trigger?: 'hover' | 'click'
|
|
467
|
+
mouseEnterDelay?: number
|
|
468
|
+
mouseLeaveDelay?: number
|
|
469
|
+
keepMounted?: boolean
|
|
470
|
+
hoverBridge?: boolean
|
|
471
|
+
className?: string
|
|
472
|
+
getContainer?: HTMLElement | (() => HTMLElement)
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
Auto-positioned. `hoverBridge` provides safe mouse movement gap.
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Dropdown
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
interface DropdownItem {
|
|
484
|
+
key: string
|
|
485
|
+
label?: ReactNode
|
|
486
|
+
icon?: ReactNode
|
|
487
|
+
danger?: boolean
|
|
488
|
+
onClick?: () => void
|
|
489
|
+
// Or custom render:
|
|
490
|
+
render?: () => ReactNode
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
interface DropdownProps {
|
|
494
|
+
items: DropdownItem[]
|
|
495
|
+
children: ReactElement
|
|
496
|
+
placement?: Placement
|
|
497
|
+
// ... other Popup props
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## Tooltip
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
interface TooltipProps {
|
|
507
|
+
content: ReactNode
|
|
508
|
+
children: ReactElement
|
|
509
|
+
placement?: Placement
|
|
510
|
+
visible?: boolean
|
|
511
|
+
// ... other Popup-like props
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## Menu
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
interface MenuProps {
|
|
521
|
+
mode?: 'top' | 'left' // default: 'left'
|
|
522
|
+
expandTrigger?: 'hover' | 'click' // default: 'click'
|
|
523
|
+
expandMode?: 'accordion' | 'multiple' // default: 'accordion'
|
|
524
|
+
selectedKey?: string
|
|
525
|
+
defaultSelectedKey?: string
|
|
526
|
+
onSelect?: (key: string) => void
|
|
527
|
+
items?: MenuItemData[] // declarative API (alternative to children)
|
|
528
|
+
children?: ReactNode
|
|
529
|
+
className?: string
|
|
530
|
+
collapsed?: boolean
|
|
531
|
+
defaultCollapsed?: boolean
|
|
532
|
+
onCollapse?: (collapsed: boolean) => void
|
|
533
|
+
collapsedWidth?: number // default: 64
|
|
534
|
+
collapsedLabelTooltip?: boolean // default: true
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
Compound: `<Menu>` + `<Menu.Item>` + `<Menu.SubMenu>` + `<Menu.CollapseToggle>`.
|
|
539
|
+
|
|
540
|
+
### MenuItem
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
interface MenuItemProps {
|
|
544
|
+
eventKey: string
|
|
545
|
+
icon?: ReactNode
|
|
546
|
+
disabled?: boolean
|
|
547
|
+
danger?: boolean
|
|
548
|
+
onClick?: () => void
|
|
549
|
+
children?: ReactNode
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### SubMenu
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
interface SubMenuProps {
|
|
557
|
+
eventKey: string
|
|
558
|
+
label: ReactNode
|
|
559
|
+
icon?: ReactNode
|
|
560
|
+
disabled?: boolean
|
|
561
|
+
popup?: boolean
|
|
562
|
+
children?: ReactNode
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## Layout
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
interface LayoutProps {
|
|
572
|
+
header?: ReactNode
|
|
573
|
+
sidebar?: ReactNode
|
|
574
|
+
children?: ReactNode
|
|
575
|
+
footer?: ReactNode
|
|
576
|
+
className?: string
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
Flexbox: header/footer shrink-0, sidebar w-60 shrink-0, main flex-1 overflow-y-auto.
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## Tabs
|
|
585
|
+
|
|
586
|
+
```typescript
|
|
587
|
+
interface TabItem {
|
|
588
|
+
key: string
|
|
589
|
+
label: ReactNode
|
|
590
|
+
disabled?: boolean
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
interface TabsProps {
|
|
594
|
+
items: TabItem[]
|
|
595
|
+
activeKey?: string
|
|
596
|
+
defaultActiveKey?: string
|
|
597
|
+
onChange?: (key: string) => void
|
|
598
|
+
className?: string
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
Tab bar only — no built-in tab panels. Active tab has bottom border accent.
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## Breadcrumb
|
|
607
|
+
|
|
608
|
+
Compound: `<Breadcrumb>`, `<BreadcrumbList>`, `<BreadcrumbItem>`, `<BreadcrumbLink>`, `<BreadcrumbPage>`, `<BreadcrumbSeparator>`, `<BreadcrumbEllipsis>`.
|
|
609
|
+
|
|
610
|
+
`SimpleBreadcrumb`: Application-level wrapper with router navigate and closable tabs.
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
## Pagination
|
|
615
|
+
|
|
616
|
+
```typescript
|
|
617
|
+
interface PaginationProps {
|
|
618
|
+
current: number
|
|
619
|
+
pageSize: number
|
|
620
|
+
total: number
|
|
621
|
+
onChange: (page: number, pageSize: number) => void
|
|
622
|
+
onPageSizeChange?: (pageSize: number) => void
|
|
623
|
+
pageSizeOptions?: number[] // default: [10, 20, 50, 100]
|
|
624
|
+
className?: string
|
|
625
|
+
}
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
Smart ellipsis (max 7 pages shown), page size selector via Select.
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
## ImagePreview
|
|
633
|
+
|
|
634
|
+
### ImagePreviewController
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
interface ImagePreviewControllerProps {
|
|
638
|
+
open: boolean
|
|
639
|
+
images: string[]
|
|
640
|
+
initialIndex?: number // default: 0
|
|
641
|
+
onClose: () => void
|
|
642
|
+
}
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
Features: zoom (0.2x–5x), drag-to-pan, rotate, flip, keyboard nav.
|
|
646
|
+
|
|
647
|
+
### PreviewImage
|
|
648
|
+
|
|
649
|
+
```typescript
|
|
650
|
+
interface PreviewImageProps extends MOmit<ImagePreviewControllerProps, 'open' | 'onClose'> {
|
|
651
|
+
onClose?: () => void
|
|
652
|
+
thumbSize?: number | string // default: 80
|
|
653
|
+
direction?: 'horizontal' | 'vertical'
|
|
654
|
+
}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
Thumbnail grid → click to open full controller.
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
## Card
|
|
662
|
+
|
|
663
|
+
```typescript
|
|
664
|
+
interface CardProps {
|
|
665
|
+
header?: ReactNode
|
|
666
|
+
footer?: ReactNode
|
|
667
|
+
children?: ReactNode
|
|
668
|
+
className?: string
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
## Message (Function API)
|
|
675
|
+
|
|
676
|
+
```typescript
|
|
677
|
+
message.success(content: ReactNode, config?: MessageConfig): void
|
|
678
|
+
message.error(content: ReactNode, config?: MessageConfig): void
|
|
679
|
+
message.warning(content: ReactNode, config?: MessageConfig): void
|
|
680
|
+
message.info(content: ReactNode, config?: MessageConfig): void
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
Max 5 visible messages.
|
|
684
|
+
|
|
685
|
+
---
|
|
686
|
+
|
|
687
|
+
## Notification
|
|
688
|
+
|
|
689
|
+
```typescript
|
|
690
|
+
interface NotificationProps {
|
|
691
|
+
type: 'info' | 'success' | 'warning' | 'error'
|
|
692
|
+
title: ReactNode
|
|
693
|
+
message?: ReactNode
|
|
694
|
+
duration?: number
|
|
695
|
+
closable?: boolean
|
|
696
|
+
}
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
---
|
|
700
|
+
|
|
701
|
+
## Loading
|
|
702
|
+
|
|
703
|
+
```typescript
|
|
704
|
+
interface LoadingProps {
|
|
705
|
+
size?: 'sm' | 'md' | 'lg'
|
|
706
|
+
text?: ReactNode
|
|
707
|
+
}
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
Spinning circle with optional text.
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
## Skeleton
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
interface SkeletonProps {
|
|
718
|
+
mode?: 'pageloading' | 'tableloading' | 'componentsloading'
|
|
719
|
+
rows?: number
|
|
720
|
+
showTitle?: boolean
|
|
721
|
+
showActions?: boolean
|
|
722
|
+
}
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
---
|
|
726
|
+
|
|
727
|
+
## Label
|
|
728
|
+
|
|
729
|
+
```typescript
|
|
730
|
+
interface LabelProps {
|
|
731
|
+
layout?: 'vertical' | 'horizontal'
|
|
732
|
+
labelWidth?: number | string
|
|
733
|
+
labelAlign?: 'left' | 'right' | 'center'
|
|
734
|
+
required?: boolean
|
|
735
|
+
children?: ReactNode
|
|
736
|
+
}
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
---
|
|
740
|
+
|
|
741
|
+
## Overlay (internal, used by Modal/Drawer)
|
|
742
|
+
|
|
743
|
+
```typescript
|
|
744
|
+
interface OverlayProps {
|
|
745
|
+
visible: boolean
|
|
746
|
+
mask?: boolean
|
|
747
|
+
maskClosable?: boolean
|
|
748
|
+
lockScroll?: boolean
|
|
749
|
+
keyboard?: boolean
|
|
750
|
+
zIndex?: number
|
|
751
|
+
children?: ReactNode
|
|
752
|
+
renderNode?: HTMLElement | (() => HTMLElement)
|
|
753
|
+
onClose?: () => void
|
|
754
|
+
className?: string
|
|
755
|
+
}
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
Reference-counted body scroll lock across multiple overlays.
|
|
759
|
+
|
|
760
|
+
---
|
|
761
|
+
|
|
762
|
+
## Search (internal)
|
|
763
|
+
|
|
764
|
+
```typescript
|
|
765
|
+
interface SearchProps<T> {
|
|
766
|
+
schemas: FormFieldSchema<T>[]
|
|
767
|
+
getForm?: (formInstance: FormInstance<T>) => void
|
|
768
|
+
onSearch?: (values: T) => void
|
|
769
|
+
className?: string
|
|
770
|
+
// ... other SchemaForm props
|
|
771
|
+
}
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
Wraps `SchemaForm` with `layout='horizontal'`, `preserve=true`, `footerButtons={false}`.
|