@_tc/template-core 0.1.4 → 0.1.5

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.
@@ -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}`.