@stcn52/pro 0.0.0-stage → 0.2.1

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 (163) hide show
  1. package/CHANGELOG.md +621 -0
  2. package/CONVENTIONS.md +152 -0
  3. package/LICENSE +21 -0
  4. package/README.md +226 -2
  5. package/RELEASING.md +51 -0
  6. package/THIRD_PARTY_NOTICES.md +52 -0
  7. package/dist/index.cjs +23272 -0
  8. package/dist/index.cjs.map +1 -0
  9. package/dist/index.d.cts +5068 -0
  10. package/dist/index.d.ts +5068 -0
  11. package/dist/index.js +23060 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/styles.css +10485 -0
  14. package/dist/tokens.css +322 -0
  15. package/docs/antd-alignment-plan.md +983 -0
  16. package/docs/api.md +3669 -0
  17. package/docs/components.md +1706 -0
  18. package/docs/measurements.md +152 -0
  19. package/docs/qa/README.md +50 -0
  20. package/docs/qa/browser-checks.json +394 -0
  21. package/docs/qa/d-chrome-checklist-dark.png +0 -0
  22. package/docs/qa/d-chrome-checks.json +234 -0
  23. package/docs/qa/d-chrome-detail-dark.png +0 -0
  24. package/docs/qa/d-chrome-filters-dark.png +0 -0
  25. package/docs/qa/d-chrome-shell-dark.png +0 -0
  26. package/docs/qa/d-detail-checks.json +222 -0
  27. package/docs/qa/d-detail-comments-failed-dark.png +0 -0
  28. package/docs/qa/d-detail-preview-dark.png +0 -0
  29. package/docs/qa/d-entity-checks.json +294 -0
  30. package/docs/qa/d-entity-failed-dark.png +0 -0
  31. package/docs/qa/d-workbench-canvas-dark.png +0 -0
  32. package/docs/qa/d-workbench-checks.json +338 -0
  33. package/docs/qa/d-workbench-edit-failed-dark.png +0 -0
  34. package/docs/qa/d-workbench-roadmap-dark.png +0 -0
  35. package/docs/qa/d-workbench-wizard-failed-dark.png +0 -0
  36. package/docs/qa/date-range-mobile-dark.jpg +0 -0
  37. package/docs/qa/p0-cascader-checks.json +228 -0
  38. package/docs/qa/p0-cascader-multiple-dark.png +0 -0
  39. package/docs/qa/p0-config-checks.json +430 -0
  40. package/docs/qa/p0-config-nested-dark.png +0 -0
  41. package/docs/qa/p0-date-checks.json +595 -0
  42. package/docs/qa/p0-date-time-dark.png +0 -0
  43. package/docs/qa/p0-form-lifecycle-checks.json +30 -0
  44. package/docs/qa/p0-form-lifecycle.png +0 -0
  45. package/docs/qa/p0-select-checks.json +378 -0
  46. package/docs/qa/p0-select-virtual-dark.png +0 -0
  47. package/docs/qa/p0-table-checks.json +290 -0
  48. package/docs/qa/p0-table-virtual-dark.png +0 -0
  49. package/docs/qa/p0-transfer-checks.json +322 -0
  50. package/docs/qa/p0-transfer-pagination-dark.png +0 -0
  51. package/docs/qa/p0-tree-checks.json +242 -0
  52. package/docs/qa/p0-tree-range-dark.png +0 -0
  53. package/docs/qa/p1-app-browser-checks.json +34 -0
  54. package/docs/qa/p1-app-feedback-dark.png +0 -0
  55. package/docs/qa/p1-avatar-checks.json +370 -0
  56. package/docs/qa/p1-avatar-dark.png +0 -0
  57. package/docs/qa/p1-browser-checks.json +218 -0
  58. package/docs/qa/p1-card-checks.json +262 -0
  59. package/docs/qa/p1-card-dark.png +0 -0
  60. package/docs/qa/p1-content-navigation-browser-checks.json +114 -0
  61. package/docs/qa/p1-controls-browser-checks.json +86 -0
  62. package/docs/qa/p1-controls-desktop-dark.png +0 -0
  63. package/docs/qa/p1-dialog-nested-dark.png +0 -0
  64. package/docs/qa/p1-display-browser-checks.json +114 -0
  65. package/docs/qa/p1-display-desktop-dark.png +0 -0
  66. package/docs/qa/p1-divider-dark.png +0 -0
  67. package/docs/qa/p1-drawer-browser-checks.json +302 -0
  68. package/docs/qa/p1-drawer-rtl-dark.png +0 -0
  69. package/docs/qa/p1-general-input-browser-checks.json +114 -0
  70. package/docs/qa/p1-general-input-desktop-dark.png +0 -0
  71. package/docs/qa/p1-image-browser-checks.json +38 -0
  72. package/docs/qa/p1-image-preview-dark.png +0 -0
  73. package/docs/qa/p1-inline-browser-checks.json +58 -0
  74. package/docs/qa/p1-inline-desktop-dark.png +0 -0
  75. package/docs/qa/p1-layout-browser-checks.json +114 -0
  76. package/docs/qa/p1-layout-desktop-dark.png +0 -0
  77. package/docs/qa/p1-menu-checks.json +357 -0
  78. package/docs/qa/p1-menu-long-dark.png +0 -0
  79. package/docs/qa/p1-nav-dark.png +0 -0
  80. package/docs/qa/p1-nav-sidebar-checks.json +218 -0
  81. package/docs/qa/p1-navigation-browser-checks.json +114 -0
  82. package/docs/qa/p1-navigation-mobile-dark.png +0 -0
  83. package/docs/qa/p1-pagination-checks.json +309 -0
  84. package/docs/qa/p1-pagination-dark.png +0 -0
  85. package/docs/qa/p1-pagination-mobile-dark.png +0 -0
  86. package/docs/qa/p1-popup-actions-browser-checks.json +58 -0
  87. package/docs/qa/p1-popup-actions-desktop-dark.png +0 -0
  88. package/docs/qa/p1-progress-browser-checks.json +30 -0
  89. package/docs/qa/p1-progress-desktop-dark.png +0 -0
  90. package/docs/qa/p1-rate-half-desktop-dark.png +0 -0
  91. package/docs/qa/p1-segment-checks.json +426 -0
  92. package/docs/qa/p1-segment-dark.png +0 -0
  93. package/docs/qa/p1-sidebar-dark.png +0 -0
  94. package/docs/qa/p1-slider-rate-browser-checks.json +114 -0
  95. package/docs/qa/p1-states-browser-checks.json +34 -0
  96. package/docs/qa/p1-states-checks.json +342 -0
  97. package/docs/qa/p1-states-dark.png +0 -0
  98. package/docs/qa/p1-states-mobile-dark.png +0 -0
  99. package/docs/qa/p1-tabs-editable-dark.png +0 -0
  100. package/docs/qa/p1-tag-dark.png +0 -0
  101. package/docs/qa/p1-tag-divider-checks.json +330 -0
  102. package/docs/qa/p1-upload-browser-checks.json +30 -0
  103. package/docs/qa/p1-upload-list-dark.png +0 -0
  104. package/docs/qa/p2-ai-panel-checks.json +401 -0
  105. package/docs/qa/p2-ai-panel-dark.png +0 -0
  106. package/docs/qa/p2-alert-dark.png +0 -0
  107. package/docs/qa/p2-app-final-checks.json +309 -0
  108. package/docs/qa/p2-app-final-dark.png +0 -0
  109. package/docs/qa/p2-badge-alert-checks.json +466 -0
  110. package/docs/qa/p2-beam-motion-checks.json +58 -0
  111. package/docs/qa/p2-calendar-dark.png +0 -0
  112. package/docs/qa/p2-calendar-timeline-checks.json +254 -0
  113. package/docs/qa/p2-charts-checks.json +242 -0
  114. package/docs/qa/p2-charts-dark.png +0 -0
  115. package/docs/qa/p2-color-gradient-dark.png +0 -0
  116. package/docs/qa/p2-content-navigation-checks.json +794 -0
  117. package/docs/qa/p2-dialog-popover-dark.png +0 -0
  118. package/docs/qa/p2-display-checks.json +128 -0
  119. package/docs/qa/p2-display-dark.png +0 -0
  120. package/docs/qa/p2-drawer-final-dark.png +0 -0
  121. package/docs/qa/p2-extras-checks.json +482 -0
  122. package/docs/qa/p2-general-inputs-checks.json +154 -0
  123. package/docs/qa/p2-general-inputs-dark.png +0 -0
  124. package/docs/qa/p2-icon-checks.json +466 -0
  125. package/docs/qa/p2-icon-dark.png +0 -0
  126. package/docs/qa/p2-image-dark.png +0 -0
  127. package/docs/qa/p2-inline-editors-checks.json +199 -0
  128. package/docs/qa/p2-input-button-checks.json +778 -0
  129. package/docs/qa/p2-input-dark.png +0 -0
  130. package/docs/qa/p2-layout-final-checks.json +136 -0
  131. package/docs/qa/p2-layout-final-dark.png +0 -0
  132. package/docs/qa/p2-lists-checks.json +290 -0
  133. package/docs/qa/p2-masonry-dark.png +0 -0
  134. package/docs/qa/p2-media-checks.json +212 -0
  135. package/docs/qa/p2-mentions-color-checks.json +362 -0
  136. package/docs/qa/p2-overlay-checks.json +370 -0
  137. package/docs/qa/p2-people-picker-dark.png +0 -0
  138. package/docs/qa/p2-popconfirm-final-dark.png +0 -0
  139. package/docs/qa/p2-popup-final-checks.json +223 -0
  140. package/docs/qa/p2-qr-browser-decode.json +30 -0
  141. package/docs/qa/p2-quick-select-dark.png +0 -0
  142. package/docs/qa/p2-quick-text-dark.png +0 -0
  143. package/docs/qa/p2-rate-dark.png +0 -0
  144. package/docs/qa/p2-scroll-navigation-checks.json +198 -0
  145. package/docs/qa/p2-scroll-navigation-dark.png +0 -0
  146. package/docs/qa/p2-selection-bar-checks.json +302 -0
  147. package/docs/qa/p2-selection-bar-dark.png +0 -0
  148. package/docs/qa/p2-slider-rate-checks.json +262 -0
  149. package/docs/qa/p2-switch-dark.png +0 -0
  150. package/docs/qa/p2-tabs-dark.png +0 -0
  151. package/docs/qa/p2-timeline-dark.png +0 -0
  152. package/docs/qa/p2-toast-dark.png +0 -0
  153. package/docs/qa/p2-toggle-checks.json +834 -0
  154. package/docs/qa/p2-tour-dark.png +0 -0
  155. package/docs/qa/p2-upload-dark.png +0 -0
  156. package/docs/qa/table-details.md +26 -0
  157. package/docs/qa/table-mobile-dark.jpg +0 -0
  158. package/docs/qa/transfer-mobile-light.jpg +0 -0
  159. package/docs/qa/tree-browser-checks.json +226 -0
  160. package/docs/qa/tree-details.md +25 -0
  161. package/docs/qa/tree-directory-mobile-dark.jpg +0 -0
  162. package/docs/tokens.md +255 -0
  163. package/package.json +95 -4
package/docs/api.md ADDED
@@ -0,0 +1,3669 @@
1
+ # API reference
2
+
3
+ <!-- Generated by `pnpm gen:docs` from the source. Do not edit by hand. -->
4
+
5
+ Every runtime export of `@stcn52/pro`, with the props table of its props type.
6
+ Descriptions are the JSDoc the component carries in `src/` — the same text a
7
+ caller sees in their editor, which is why this file is generated rather than
8
+ written: it cannot drift from the code it documents.
9
+
10
+ ## Components
11
+
12
+ <sub>`src/components/ActionButton.tsx`</sub>
13
+
14
+ ### `ActionButton`
15
+
16
+ The bare icon button PingCode uses throughout chrome, toolbars and rows.
17
+
18
+ Also accepts: `ButtonHTMLAttributes<HTMLButtonElement>`.
19
+
20
+ | Prop | Type | Notes |
21
+ | ----------- | ----------------------- | ----------------------------------- |
22
+ | `active?` | `boolean` | |
23
+ | `children?` | `ReactNode` | |
24
+ | `icon` | `IconName \| string` | |
25
+ | `label` | `string` | Required: the control is icon-only. |
26
+ | `loading?` | `boolean` | |
27
+ | `size?` | `'sm' \| 'md' \| 'lg'` | |
28
+ | `tone?` | `'default' \| 'accent'` | |
29
+
30
+ <sub>`src/components/Affix.tsx`</sub>
31
+
32
+ ### `Affix`
33
+
34
+ Preserve layout while fixing the same child DOM to a scrolling viewport edge.
35
+
36
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>`.
37
+
38
+ | Prop | Type | Notes |
39
+ | --------------- | ------------------------------------- | ----- |
40
+ | `children` | `ReactNode` | |
41
+ | `offsetBottom?` | `number` | |
42
+ | `offsetTop?` | `number` | |
43
+ | `onChange?` | `(affixed: boolean) => void` | |
44
+ | `target?` | `() => Window \| HTMLElement \| null` | |
45
+
46
+ <sub>`src/components/AiPanel.tsx`</sub>
47
+
48
+ ### `AiMessage`
49
+
50
+ One line of the transcript.
51
+
52
+ _Type._
53
+
54
+ ### `AiPanel`
55
+
56
+ Ping — the AI assistant side panel captured from PingCode's workbench.
57
+
58
+ | Prop | Type | Notes |
59
+ | ------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
60
+ | `'aria-label'?` | `string` | |
61
+ | `className?` | `string` | |
62
+ | `disabled?` | `boolean` | |
63
+ | `error?` | `ReactNode` | |
64
+ | `greeting?` | `ReactNode` | Card at the top of the scroll body. Defaults to a short welcome line. |
65
+ | `inputPlaceholder?` | `string` | |
66
+ | `messages?` | `AiMessage[]` | |
67
+ | `open` | `boolean` | |
68
+ | `pending?` | `boolean` | Host-driven "thinking" state. The panel never invents a reply: it only echoes the transcript the host hands it and, while `pending` is true, shows a labelled waiting row. |
69
+ | `quickChips?` | `AiQuickChip[]` | |
70
+ | `suggestions?` | `AiSuggestion[]` | |
71
+ | `title?` | `string` | Header title beside the product mark. |
72
+
73
+ ### `AiQuickChip`
74
+
75
+ _Type._
76
+
77
+ ### `AiSuggestion`
78
+
79
+ One starter prompt under "Try asking me".
80
+
81
+ _Type._
82
+
83
+ ### `PingMark`
84
+
85
+ PingCode's Ping mark: the coral + accent pair of rounded blades that the live product renders in the panel header, the floating trigger and the 16px product glyphs.
86
+
87
+ | Prop | Type | Notes |
88
+ | ------------ | -------- | ----- |
89
+ | `className?` | `string` | |
90
+ | `size?` | `number` | |
91
+
92
+ <sub>`src/components/Alert.tsx`</sub>
93
+
94
+ ### `Alert`
95
+
96
+ Persistent inline feedback; errors interrupt, other messages announce politely.
97
+
98
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'title'>`.
99
+
100
+ | Prop | Type | Notes |
101
+ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
102
+ | `action?` | `ReactNode` | |
103
+ | `afterClose?` | `() => void` | Runs after removal, including a controlled close; no exit animation is applied. |
104
+ | `banner?` | `boolean` | |
105
+ | `closable?` | `\| boolean \| { closeIcon?: ReactNode; disabled?: boolean; onClose?: MouseEventHandler<HTMLButtonElement>; afterClose?: () => void; }` | |
106
+ | `closeLabel?` | `string` | |
107
+ | `defaultOpen?` | `boolean` | |
108
+ | `description?` | `ReactNode` | |
109
+ | `icon?` | `ReactNode` | |
110
+ | `message?` | `ReactNode` | |
111
+ | `onClose?` | `() => void` | |
112
+ | `onOpenChange?` | `(open: boolean) => void` | |
113
+ | `open?` | `boolean` | |
114
+ | `showIcon?` | `boolean` | |
115
+ | `title?` | `ReactNode` | |
116
+ | `type?` | `'info' \| 'success' \| 'warning' \| 'error'` | |
117
+ | `variant?` | `'outlined' \| 'filled'` | |
118
+
119
+ <sub>`src/components/Anchor.tsx`</sub>
120
+
121
+ ### `Anchor`
122
+
123
+ Same-page navigation with native links, scroll observation and safe ID lookup.
124
+
125
+ Also accepts: `Omit<HTMLAttributes<HTMLElement>, 'onChange' | 'onClick' | 'children'>`.
126
+
127
+ | Prop | Type | Notes |
128
+ | ------------------- | ------------------------------------------------------------------ | ----- |
129
+ | `affix?` | `boolean` | |
130
+ | `bounds?` | `number` | |
131
+ | `direction?` | `'vertical' \| 'horizontal'` | |
132
+ | `disabled?` | `boolean` | |
133
+ | `getContainer?` | `() => Window \| HTMLElement \| null` | |
134
+ | `getCurrentAnchor?` | `(active: string) => string` | |
135
+ | `items?` | `AnchorItem[]` | |
136
+ | `offsetTop?` | `number` | |
137
+ | `onChange?` | `(href: string) => void` | |
138
+ | `onClick?` | `(event: MouseEvent<HTMLAnchorElement>, item: AnchorItem) => void` | |
139
+ | `replace?` | `boolean` | |
140
+ | `targetOffset?` | `number` | |
141
+
142
+ <sub>`src/components/App.tsx`</sub>
143
+
144
+ ### `App`
145
+
146
+ | Prop | Type | Notes |
147
+ | --------------- | ---------------------------------------------- | ----- |
148
+ | `children` | `ReactNode` | |
149
+ | `message?` | `{ placement?: ToastPlacement; max?: number }` | |
150
+ | `notification?` | `{ placement?: ToastPlacement; max?: number }` | |
151
+
152
+ <sub>`src/components/AutoComplete.tsx`</sub>
153
+
154
+ ### `AutoComplete`
155
+
156
+ Editable suggestions; input focus is retained while navigating the listbox.
157
+
158
+ Also accepts: `Omit<InputProps, 'value' | 'defaultValue' | 'onChange'>`.
159
+
160
+ | Prop | Type | Notes |
161
+ | --------------- | --------------------------------------------------------------------- | ----- |
162
+ | `defaultOpen?` | `boolean` | |
163
+ | `defaultValue?` | `string` | |
164
+ | `filterOption?` | `boolean \| ((input: string, option: AutoCompleteOption) => boolean)` | |
165
+ | `onChange?` | `(value: string) => void` | |
166
+ | `onOpenChange?` | `(open: boolean) => void` | |
167
+ | `onSearch?` | `(value: string) => void` | |
168
+ | `onSelect?` | `(value: string, option: AutoCompleteOption) => void` | |
169
+ | `open?` | `boolean` | |
170
+ | `options?` | `AutoCompleteOption[]` | |
171
+ | `value?` | `string` | |
172
+
173
+ ### `AutoCompleteOption`
174
+
175
+ _Type._
176
+
177
+ <sub>`src/components/Avatar.tsx`</sub>
178
+
179
+ ### `Avatar`
180
+
181
+ Also accepts: `Omit<HTMLAttributes<HTMLSpanElement>, 'onError'>`.
182
+
183
+ | Prop | Type | Notes |
184
+ | -------------- | ---------------------------------------------------- | ----- |
185
+ | `alt?` | `string` | |
186
+ | `className?` | `string` | |
187
+ | `crossOrigin?` | `ImgHTMLAttributes<HTMLImageElement>['crossOrigin']` | |
188
+ | `gap?` | `number` | |
189
+ | `icon?` | `ReactNode` | |
190
+ | `loading?` | `ImgHTMLAttributes<HTMLImageElement>['loading']` | |
191
+ | `name?` | `string` | |
192
+ | `onError?` | `() => boolean \| void` | |
193
+ | `shape?` | `'circle' \| 'square'` | |
194
+ | `size?` | `'xs' \| 'sm' \| 'md' \| 'lg' \| number` | |
195
+ | `src?` | `string` | |
196
+ | `srcSet?` | `string` | |
197
+ | `title?` | `string` | |
198
+
199
+ ### `avatarColor`
200
+
201
+ _No props type — see the source._
202
+
203
+ ### `AvatarPlaceholder`
204
+
205
+ The dashed add-assignee circle, with native button attributes and global disabled state.
206
+
207
+ Also accepts: `ButtonHTMLAttributes<HTMLButtonElement>`.
208
+
209
+ | Prop | Type | Notes |
210
+ | ------- | -------- | ----- |
211
+ | `label` | `string` | |
212
+
213
+ ### `AvatarStack`
214
+
215
+ | Prop | Type | Notes |
216
+ | --------------- | --------------------------------------- | ----- |
217
+ | `'aria-label'?` | `string` | |
218
+ | `className?` | `string` | |
219
+ | `max?` | `number` | |
220
+ | `people` | `Array<{ name: string; src?: string }>` | |
221
+ | `shape?` | `AvatarProps['shape']` | |
222
+ | `size?` | `AvatarProps['size']` | |
223
+
224
+ ### `IconAvatar`
225
+
226
+ The avatar shell carrying a glyph instead of initials — the grid's leading mark for a row whose title belongs to a kind of record (the live Customer grid opens each name with a filled circle holding its department mark).
227
+
228
+ Also accepts: `HTMLAttributes<HTMLSpanElement>`.
229
+
230
+ | Prop | Type | Notes |
231
+ | -------- | --------------------- | ------------------------------------------------------------------------- |
232
+ | `icon` | `IconName \| string` | |
233
+ | `label?` | `string` | Exposed to assistive tech only when the glyph carries meaning of its own. |
234
+ | `size?` | `AvatarProps['size']` | |
235
+ | `tone?` | `'accent' \| 'muted'` | |
236
+
237
+ ### `initials`
238
+
239
+ _No props type — see the source._
240
+
241
+ <sub>`src/components/Badge.tsx`</sub>
242
+
243
+ ### `Badge`
244
+
245
+ Also accepts: `Omit<HTMLAttributes<HTMLSpanElement>, 'title'>`.
246
+
247
+ | Prop | Type | Notes |
248
+ | ---------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------ |
249
+ | `color?` | `string` | |
250
+ | `count?` | `ReactNode` | |
251
+ | `dot?` | `boolean` | |
252
+ | `label?` | `string` | Accessible description; count badges default to the full count. |
253
+ | `offset?` | `[number, number]` | Horizontal and vertical pixel offsets; horizontal is logical inline-end. |
254
+ | `overflowCount?` | `number` | |
255
+ | `showZero?` | `boolean` | |
256
+ | `size?` | `'sm' \| 'md'` | |
257
+ | `status?` | `'success' \| 'processing' \| 'default' \| 'error' \| 'warning'` | |
258
+ | `text?` | `ReactNode` | |
259
+ | `title?` | `string \| null \| false` | |
260
+
261
+ <sub>`src/components/BorderBeam.tsx`</sub>
262
+
263
+ ### `BorderBeam`
264
+
265
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'color'>`.
266
+
267
+ | Prop | Type | Notes |
268
+ | ------------ | ----------------- | ----- |
269
+ | `color?` | `BorderBeamColor` | |
270
+ | `count?` | `number` | |
271
+ | `duration?` | `number` | |
272
+ | `lineWidth?` | `number` | |
273
+ | `outset?` | `number` | |
274
+ | `size?` | `number` | |
275
+
276
+ ### `BorderBeamColor`
277
+
278
+ _Type._
279
+
280
+ <sub>`src/components/Breadcrumb.tsx`</sub>
281
+
282
+ ### `Breadcrumb`
283
+
284
+ Semantic navigation trail; links remain native and the last item marks the current page.
285
+
286
+ Also accepts: `Omit<HTMLAttributes<HTMLElement>, 'children'>`.
287
+
288
+ | Prop | Type | Notes |
289
+ | ------------- | ----------------------------------------------------------------------------- | ----- |
290
+ | `itemRender?` | `(item: BreadcrumbItem, index: number, items: BreadcrumbItem[]) => ReactNode` | |
291
+ | `items` | `BreadcrumbItem[]` | |
292
+ | `separator?` | `ReactNode` | |
293
+
294
+ ### `BreadcrumbItem`
295
+
296
+ _Type._
297
+
298
+ <sub>`src/components/Button.tsx`</sub>
299
+
300
+ ### `Button`
301
+
302
+ Also accepts: `ButtonHTMLAttributes<HTMLButtonElement>`.
303
+
304
+ | Prop | Type | Notes |
305
+ | ------------ | ---------------------------------- | ------------------------------------------------------------------------ |
306
+ | `block?` | `boolean` | |
307
+ | `children?` | `ReactNode` | |
308
+ | `danger?` | `boolean` | |
309
+ | `ghost?` | `boolean` | |
310
+ | `icon?` | `IconName \| string` | |
311
+ | `iconAfter?` | `IconName \| string` | |
312
+ | `loading?` | `boolean` | Toggles a spinner and blocks interaction without losing the label width. |
313
+ | `shape?` | `'default' \| 'round' \| 'circle'` | |
314
+ | `size?` | `ButtonSize` | |
315
+ | `variant?` | `ButtonVariant` | |
316
+
317
+ ### `ButtonSize`
318
+
319
+ _Type._
320
+
321
+ ### `ButtonVariant`
322
+
323
+ _Type._
324
+
325
+ ### `SplitButton`
326
+
327
+ PingCode fuses the primary action and its "more" caret into one control.
328
+
329
+ | Prop | Type | Notes |
330
+ | --------------- | -------------------- | ------------------------------------------------------------------------- |
331
+ | `className?` | `string` | |
332
+ | `disabled?` | `boolean` | |
333
+ | `icon?` | `IconName \| string` | |
334
+ | `label` | `ReactNode` | |
335
+ | `menuItems?` | `MenuItemSpec[]` | Items for the caret menu. Without them the caret only calls onToggleMenu. |
336
+ | `menuLabel` | `string` | |
337
+ | `menuOpen?` | `boolean` | |
338
+ | `onPrimary` | `() => void` | |
339
+ | `onToggleMenu?` | `() => void` | |
340
+ | `size?` | `ButtonSize` | |
341
+ | `variant?` | `ButtonVariant` | |
342
+
343
+ <sub>`src/components/Calendar.tsx`</sub>
344
+
345
+ ### `Calendar`
346
+
347
+ Standalone event calendar, using the same date contract as DatePicker.
348
+
349
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'onSelect'>`.
350
+
351
+ | Prop | Type | Notes |
352
+ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
353
+ | `cellRender?` | `(date: string, info: { type: 'date' \| 'month' }) => ReactNode` | |
354
+ | `defaultMode?` | `'month' \| 'year'` | |
355
+ | `defaultValue?` | `string` | |
356
+ | `disabled?` | `boolean` | |
357
+ | `disabledDate?` | `(date: string) => boolean` | |
358
+ | `fullCellRender?` | `(date: string, info: { type: 'date' \| 'month' }) => ReactNode` | |
359
+ | `fullscreen?` | `boolean` | |
360
+ | `headerRender?` | `(info: { value: string; type: 'month' \| 'year'; onChange: (date: string) => void; onTypeChange: (mode: 'month' \| 'year') => void; }) => ReactNode` | |
361
+ | `mode?` | `'month' \| 'year'` | |
362
+ | `onChange?` | `(date: string) => void` | |
363
+ | `onPanelChange?` | `(date: string, mode: 'month' \| 'year') => void` | |
364
+ | `onSelect?` | `(date: string, info: { source: 'date' \| 'month' \| 'year' \| 'customize' }) => void` | |
365
+ | `validRange?` | `[string, string]` | |
366
+ | `value?` | `string` | ISO date, shared with DatePicker; no date-library dependency. |
367
+
368
+ <sub>`src/components/Card.tsx`</sub>
369
+
370
+ ### `Card`
371
+
372
+ Tabs can be composed in extra/body; Grid and Meta share the card shell's geometry.
373
+
374
+ Also accepts: `Omit<HTMLAttributes<HTMLElement>, 'title'>`.
375
+
376
+ | Prop | Type | Notes |
377
+ | ------------ | ---------------------------- | ----- |
378
+ | `actions?` | `ReactNode[]` | |
379
+ | `bordered?` | `boolean` | |
380
+ | `cover?` | `ReactNode` | |
381
+ | `extra?` | `ReactNode` | |
382
+ | `flush?` | `boolean` | |
383
+ | `hoverable?` | `boolean` | |
384
+ | `loading?` | `boolean` | |
385
+ | `size?` | `'medium' \| 'small'` | |
386
+ | `title?` | `ReactNode` | |
387
+ | `type?` | `'inner'` | |
388
+ | `variant?` | `'outlined' \| 'borderless'` | |
389
+
390
+ ### `CardGrid`
391
+
392
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
393
+
394
+ | Prop | Type | Notes |
395
+ | ------------ | --------- | ----- |
396
+ | `hoverable?` | `boolean` | |
397
+
398
+ ### `CardMeta`
399
+
400
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'title'>`.
401
+
402
+ | Prop | Type | Notes |
403
+ | -------------- | ----------- | ----- |
404
+ | `avatar?` | `ReactNode` | |
405
+ | `description?` | `ReactNode` | |
406
+ | `title?` | `ReactNode` | |
407
+
408
+ ### `KeyValue`
409
+
410
+ Definition list used by the detail panels and the report summaries.
411
+
412
+ | Prop | Type | Notes |
413
+ | ------------ | ---------------- | ----- |
414
+ | `className?` | `string` | |
415
+ | `items` | `KeyValueItem[]` | |
416
+
417
+ ### `KeyValueItem`
418
+
419
+ _Type._
420
+
421
+ ### `Metric`
422
+
423
+ Headline number plus its comparison line — used across the report tab.
424
+
425
+ | Prop | Type | Notes |
426
+ | -------- | -------------------- | ----- |
427
+ | `delta?` | `ReactNode` | |
428
+ | `icon?` | `IconName \| string` | |
429
+ | `label` | `ReactNode` | |
430
+ | `trend?` | `StatTrend` | |
431
+ | `value` | `ReactNode` | |
432
+
433
+ ### `Progress`
434
+
435
+ | Prop | Type | Notes |
436
+ | -------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------ |
437
+ | `'aria-label'?` | `string` | |
438
+ | `'aria-labelledby'?` | `string` | |
439
+ | `className?` | `string` | |
440
+ | `format?` | `(percent: number, successPercent: number) => ReactNode` | |
441
+ | `gapDegree?` | `number` | |
442
+ | `gapPlacement?` | `'top' \| 'bottom' \| 'start' \| 'end'` | |
443
+ | `label?` | `ReactNode` | |
444
+ | `percent?` | `number` | |
445
+ | `railColor?` | `string` | |
446
+ | `showInfo?` | `boolean` | |
447
+ | `showValue?` | `boolean` | |
448
+ | `size?` | `number` | |
449
+ | `status?` | `'normal' \| 'active' \| 'success' \| 'exception'` | |
450
+ | `steps?` | `number` | |
451
+ | `strokeColor?` | `string` | |
452
+ | `strokeLinecap?` | `'round' \| 'butt' \| 'square'` | |
453
+ | `strokeWidth?` | `number` | |
454
+ | `style?` | `CSSProperties` | |
455
+ | `success?` | `{ percent?: number; strokeColor?: string }` | |
456
+ | `tone?` | `'accent' \| 'success' \| 'warning' \| 'danger'` | |
457
+ | `type?` | `'line' \| 'circle' \| 'dashboard'` | |
458
+ | `value?` | `number` | Existing Klun 0–1 contract; takes precedence over percent when supplied. |
459
+
460
+ ### `StatTrend`
461
+
462
+ _Type._
463
+
464
+ <sub>`src/components/Carousel.tsx`</sub>
465
+
466
+ ### `Carousel`
467
+
468
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'children'>`.
469
+
470
+ | Prop | Type | Notes |
471
+ | ---------------- | --------------------------------------- | ----- |
472
+ | `afterChange?` | `(slide: number) => void` | |
473
+ | `arrows?` | `boolean` | |
474
+ | `autoplay?` | `boolean` | |
475
+ | `autoplaySpeed?` | `number` | |
476
+ | `beforeChange?` | `(from: number, to: number) => void` | |
477
+ | `children` | `ReactNode` | |
478
+ | `current?` | `number` | |
479
+ | `disabled?` | `boolean` | |
480
+ | `dotPlacement?` | `'top' \| 'bottom' \| 'start' \| 'end'` | |
481
+ | `dots?` | `boolean` | |
482
+ | `draggable?` | `boolean` | |
483
+ | `effect?` | `'scrollx' \| 'fade'` | |
484
+ | `infinite?` | `boolean` | |
485
+ | `initialSlide?` | `number` | |
486
+ | `onChange?` | `(slide: number) => void` | |
487
+ | `speed?` | `number` | |
488
+ | `vertical?` | `boolean` | |
489
+
490
+ ### `CarouselRef`
491
+
492
+ _Type._
493
+
494
+ <sub>`src/components/Cascader.tsx`</sub>
495
+
496
+ ### `Cascader`
497
+
498
+ Existing menu selection plus Tree-backed multiple/intermediate/lazy hierarchy.
499
+
500
+ Also accepts: `Omit< ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'defaultValue' | 'onChange' | 'children' >`, `( | { multiple?: false; value?: string[]; defaultValue?: string[]; onChange?: (path: string[]) => void } | { multiple: true; value?: string[][]; defaultValue?: string[][]; onChange?: (paths: string[][]) => void } )`.
501
+
502
+ | Prop | Type | Notes |
503
+ | ---------------------- | ------------------------------------------------------------------------------------------------------- | ----- |
504
+ | `'aria-label'` | `string` | |
505
+ | `allowClear?` | `boolean` | |
506
+ | `changeOnSelect?` | `boolean` | |
507
+ | `defaultOpen?` | `boolean` | |
508
+ | `displayRender?` | `(labels: ReactNode[], selectedOptions: CascaderOption[]) => ReactNode` | |
509
+ | `fieldNames?` | `{ value?: string; label?: string; children?: string }` | |
510
+ | `filterOption?` | `(query: string, path: CascaderOption[]) => boolean` | |
511
+ | `invalid?` | `boolean` | |
512
+ | `loadData?` | `(selectedOptions: CascaderOption[]) => Promise<CascaderOption[] \| Record<string, unknown>[] \| void>` | |
513
+ | `loading?` | `boolean` | |
514
+ | `notFoundContent?` | `ReactNode` | |
515
+ | `onLoadError?` | `(error: unknown, selectedOptions: CascaderOption[]) => void` | |
516
+ | `onOpenChange?` | `(open: boolean) => void` | |
517
+ | `onSearch?` | `(query: string) => void` | |
518
+ | `open?` | `boolean` | |
519
+ | `optionRender?` | `(option: CascaderOption) => ReactNode` | |
520
+ | `options` | `CascaderOption[] \| Record<string, unknown>[]` | |
521
+ | `placeholder?` | `string` | |
522
+ | `searchable?` | `boolean` | |
523
+ | `searchValue?` | `string` | |
524
+ | `showCheckedStrategy?` | `'SHOW_PARENT' \| 'SHOW_CHILD'` | |
525
+
526
+ ### `CascaderOption`
527
+
528
+ _Type._
529
+
530
+ <sub>`src/components/Charts.tsx`</sub>
531
+
532
+ ### `BarChart`
533
+
534
+ Horizontal-free column chart: values are relative to the largest bucket.
535
+
536
+ | Prop | Type | Notes |
537
+ | --------------- | -------------- | ----- |
538
+ | `'aria-label'?` | `string` | |
539
+ | `className?` | `string` | |
540
+ | `data` | `ChartDatum[]` | |
541
+ | `height?` | `number` | |
542
+
543
+ ### `ChartDatum`
544
+
545
+ _Type._
546
+
547
+ ### `CrumbItem`
548
+
549
+ _Type._
550
+
551
+ ### `Crumbs`
552
+
553
+ Breadcrumb used above detail pages ("Ship / Example Product / SLC-1").
554
+
555
+ | Prop | Type | Notes |
556
+ | ------------ | ------------- | ----- |
557
+ | `className?` | `string` | |
558
+ | `items` | `CrumbItem[]` | |
559
+
560
+ ### `Donut`
561
+
562
+ Donut built from a conic-gradient rather than an SVG path: the segment sizes are data-driven and it stays crisp at any size without a chart dependency.
563
+
564
+ | Prop | Type | Notes |
565
+ | --------------- | -------------- | ----- |
566
+ | `'aria-label'?` | `string` | |
567
+ | `centerLabel?` | `ReactNode` | |
568
+ | `centerValue?` | `ReactNode` | |
569
+ | `className?` | `string` | |
570
+ | `data` | `ChartDatum[]` | |
571
+ | `size?` | `number` | |
572
+ | `thickness?` | `number` | |
573
+
574
+ ### `ScatterPlot`
575
+
576
+ Score against effort, drawn as positioned points inside a grid — the Plan matrix.
577
+
578
+ | Prop | Type | Notes |
579
+ | --------------- | ---------------------- | ----------------------------------------------------------------------------------- |
580
+ | `'aria-label'?` | `string` | |
581
+ | `className?` | `string` | |
582
+ | `disabled?` | `boolean` | |
583
+ | `emptyState?` | `ReactNode` | Shown instead of the plot when there is nothing to place. |
584
+ | `extra?` | `ReactNode` | Card's right-hand slot: the formula, a legend, a count. |
585
+ | `height?` | `number` | |
586
+ | `onSelect?` | `(id: string) => void` | Called with the point id when one is activated. Points are buttons only when given. |
587
+ | `points` | `ScatterPoint[]` | |
588
+ | `title?` | `ReactNode` | |
589
+ | `xLabel` | `string` | Horizontal axis title. |
590
+ | `yLabel` | `string` | Vertical axis title (rotated). |
591
+
592
+ ### `ScatterPoint`
593
+
594
+ _Type._
595
+
596
+ ### `Sparkline`
597
+
598
+ Single-line sparkline for the "trend" widgets in the report tab.
599
+
600
+ | Prop | Type | Notes |
601
+ | --------------- | ---------- | ----- |
602
+ | `'aria-label'?` | `string` | |
603
+ | `className?` | `string` | |
604
+ | `data` | `number[]` | |
605
+ | `height?` | `number` | |
606
+ | `width?` | `number` | |
607
+
608
+ <sub>`src/components/Checkbox.tsx`</sub>
609
+
610
+ ### `Checkbox`
611
+
612
+ Also accepts: `Omit<InputHTMLAttributes<HTMLInputElement>, 'type'>`.
613
+
614
+ | Prop | Type | Notes |
615
+ | ---------------- | ----------- | ------------------------------------------------------------------------- |
616
+ | `compact?` | `boolean` | Wraps the label in the shared 16px hit-extension used inside table cells. |
617
+ | `indeterminate?` | `boolean` | |
618
+ | `label?` | `ReactNode` | |
619
+
620
+ <sub>`src/components/CheckboxGroup.tsx`</sub>
621
+
622
+ ### `CheckboxGroup`
623
+
624
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'>`.
625
+
626
+ | Prop | Type | Notes |
627
+ | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
628
+ | `'aria-label'` | `string` | |
629
+ | `className?` | `string` | |
630
+ | `defaultValue?` | `string[]` | |
631
+ | `disabled?` | `boolean` | |
632
+ | `name?` | `string` | |
633
+ | `onChange?` | `(value: string[]) => void` | |
634
+ | `options` | `Array<{ value: string; label: ReactNode; disabled?: boolean; id?: string; title?: string; required?: boolean; className?: string; style?: CSSProperties; onChange?: ChangeEventHandler<HTMLInputElement>; }>` | |
635
+ | `orientation?` | `'horizontal' \| 'vertical'` | |
636
+ | `value?` | `string[]` | |
637
+
638
+ <sub>`src/components/Collapse.tsx`</sub>
639
+
640
+ ### `Collapse`
641
+
642
+ | Prop | Type | Notes |
643
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ----- |
644
+ | `accordion?` | `boolean` | |
645
+ | `activeKeys?` | `string[]` | |
646
+ | `bordered?` | `boolean` | |
647
+ | `className?` | `string` | |
648
+ | `defaultActiveKeys?` | `string[]` | |
649
+ | `disabled?` | `boolean` | |
650
+ | `ghost?` | `boolean` | |
651
+ | `items` | `Array<{ key: string; label: ReactNode; children: ReactNode; disabled?: boolean; extra?: ReactNode; forceRender?: boolean; }>` | |
652
+ | `keepMounted?` | `boolean` | |
653
+ | `onChange?` | `(keys: string[]) => void` | |
654
+
655
+ <sub>`src/components/ColorPicker.tsx`</sub>
656
+
657
+ ### `ColorGradientStop`
658
+
659
+ _Type._
660
+
661
+ ### `ColorPicker`
662
+
663
+ Also accepts: `Omit<ButtonProps, 'value' | 'defaultValue' | 'onChange' | 'children'>`.
664
+
665
+ | Prop | Type | Notes |
666
+ | ------------------- | ----------------------------------------------------------------- | ----- |
667
+ | `allowClear?` | `boolean` | |
668
+ | `children?` | `ReactNode` | |
669
+ | `defaultFormat?` | `ColorFormat` | |
670
+ | `defaultOpen?` | `boolean` | |
671
+ | `defaultValue?` | `ColorPickerValue` | |
672
+ | `disabledAlpha?` | `boolean` | |
673
+ | `disabledFormat?` | `boolean` | |
674
+ | `format?` | `ColorFormat` | |
675
+ | `mode?` | `'single' \| 'gradient' \| ('single' \| 'gradient')[]` | |
676
+ | `onChange?` | `(value: ColorPickerValue) => void` | |
677
+ | `onChangeComplete?` | `(value: ColorPickerValue) => void` | |
678
+ | `onClear?` | `() => void` | |
679
+ | `onFormatChange?` | `(format: ColorFormat) => void` | |
680
+ | `onOpenChange?` | `(open: boolean) => void` | |
681
+ | `open?` | `boolean` | |
682
+ | `panelRender?` | `(panel: ReactNode) => ReactNode` | |
683
+ | `presets?` | `{ label: ReactNode; colors: string[]; defaultOpen?: boolean }[]` | |
684
+ | `showText?` | `boolean \| ((value: ColorPickerValue) => ReactNode)` | |
685
+ | `value?` | `ColorPickerValue` | |
686
+
687
+ ### `ColorPickerValue`
688
+
689
+ _Type._
690
+
691
+ <sub>`src/components/ConfigProvider.tsx`</sub>
692
+
693
+ ### `ConfigProvider`
694
+
695
+ Nested providers inherit omitted options; explicit control props take precedence.
696
+
697
+ Also accepts: `Partial<ProConfig>`.
698
+
699
+ | Prop | Type | Notes |
700
+ | ------------ | ----------- | ----- |
701
+ | `children` | `ReactNode` | |
702
+ | `className?` | `string` | |
703
+
704
+ ### `ProConfig`
705
+
706
+ _Type._
707
+
708
+ ### `ProTokens`
709
+
710
+ _Type._
711
+
712
+ ### `useComponentDisabled`
713
+
714
+ _No props type — see the source._
715
+
716
+ ### `useProConfig`
717
+
718
+ _No props type — see the source._
719
+
720
+ <sub>`src/components/ContextMenu.tsx`</sub>
721
+
722
+ ### `ContextMenu`
723
+
724
+ A right-click menu for any surface.
725
+
726
+ | Prop | Type | Notes |
727
+ | --------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
728
+ | `'aria-label'?` | `string` | |
729
+ | `children` | `(props: { onContextMenu: (event: ReactMouseEvent) => void }) => ReactNode` | Render prop; the returned element gets `onContextMenu` wired automatically. |
730
+ | `disabled?` | `boolean` | |
731
+ | `items` | `ContextMenuItem[]` | |
732
+ | `onOpen?` | `(event: ReactMouseEvent) => void` | Called with the trigger point before opening (use it to set the selection). |
733
+
734
+ ### `ContextMenuItem`
735
+
736
+ _Type._
737
+
738
+ ### `ContextMenuList`
739
+
740
+ The menu body, shared by the pointer-anchored context menu and by any click-opened panel (the grid row's ⋯) that wants the same commands.
741
+
742
+ | Prop | Type | Notes |
743
+ | --------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
744
+ | `'aria-label'?` | `string` | |
745
+ | `className?` | `string` | |
746
+ | `context?` | `unknown` | Handed to every `onSelect`, as the pointer menu does with its own. |
747
+ | `disabled?` | `boolean` | |
748
+ | `items` | `ContextMenuItem[]` | |
749
+ | `onBack?` | `() => void` | Nested lists get this so ← hands focus back to the item that opened them. |
750
+ | `onDismiss?` | `() => void` | Runs after a leaf command, so the caller can close its own layer. |
751
+ | `variant?` | `'menu' \| 'quick'` | `menu` is `Menu`'s own markup (36px rows, 15px icons). `quick` draws the Ship grid's quick panel: a 16px icon strip on top and 40px command rows. Passing a strip item selects `quick` by itself. |
752
+
753
+ ### `useContextMenu`
754
+
755
+ Imperative twin for "right-click a row": `openAt` from the row's handler.
756
+
757
+ _No props type — see the source._
758
+
759
+ <sub>`src/components/DatePicker.tsx`</sub>
760
+
761
+ ### `DatePicker`
762
+
763
+ ISO value picker with native entry, themed period panels and optional local time.
764
+
765
+ Also accepts: `(SingleDatePickerProps | MultipleDatePickerProps)`.
766
+
767
+ | Prop | Type | Notes |
768
+ | --------------- | -------------------------------------------------------------------------- | ----- |
769
+ | `'aria-label'` | `string` | |
770
+ | `className?` | `string` | |
771
+ | `defaultOpen?` | `boolean` | |
772
+ | `disabled?` | `boolean` | |
773
+ | `disabledDate?` | `(date: string, info: { type: DatePickerMode; from?: string }) => boolean` | |
774
+ | `disabledTime?` | `(value: string) => boolean` | |
775
+ | `format?` | `DateValueFormat` | |
776
+ | `id?` | `string` | |
777
+ | `invalid?` | `boolean` | |
778
+ | `locale?` | `string` | |
779
+ | `max?` | `string` | |
780
+ | `min?` | `string` | |
781
+ | `name?` | `string` | |
782
+ | `needConfirm?` | `boolean` | |
783
+ | `onOk?` | `(value: string \| string[]) => void` | |
784
+ | `onOpenChange?` | `(open: boolean) => void` | |
785
+ | `open?` | `boolean` | |
786
+ | `picker?` | `DatePickerMode` | |
787
+ | `presets?` | `DatePreset[]` | |
788
+ | `readOnly?` | `boolean` | |
789
+ | `required?` | `boolean` | |
790
+
791
+ ### `DatePickerShared`
792
+
793
+ _Type._
794
+
795
+ ### `DatePreset`
796
+
797
+ _Type._
798
+
799
+ ### `DateRangePicker`
800
+
801
+ Partial ISO ranges with shared period, date/time constraints and optional presets.
802
+
803
+ Also accepts: `Omit< SingleDatePickerProps, | 'value' | 'defaultValue' | 'onChange' | 'name' | 'id' | 'required' | 'multiple' | 'presets' | 'disabledDate' | 'disabledTime' | 'open' | 'defaultOpen' | 'onOpenChange' | 'onOk' >`.
804
+
805
+ | Prop | Type | Notes |
806
+ | --------------- | --------------------------------------------------------------------------------------------------- | ----- |
807
+ | `defaultValue?` | `[string, string]` | |
808
+ | `disabledDate?` | `(date: string, info: { type: DatePickerMode; from?: string; range: 'start' \| 'end' }) => boolean` | |
809
+ | `disabledTime?` | `(value: string, info: { from?: string; range: 'start' \| 'end' }) => boolean` | |
810
+ | `names?` | `[string, string]` | |
811
+ | `onChange?` | `(value: [string, string]) => void` | |
812
+ | `onOpenChange?` | `(open: 'start' \| 'end' \| null) => void` | |
813
+ | `open?` | `'start' \| 'end' \| null` | |
814
+ | `presets?` | `DateRangePreset[]` | |
815
+ | `value?` | `[string, string]` | |
816
+
817
+ ### `DateRangePreset`
818
+
819
+ _Type._
820
+
821
+ <sub>`src/components/Descriptions.tsx`</sub>
822
+
823
+ ### `Descriptions`
824
+
825
+ Responsive definition list with per-item spans and native label/value semantics.
826
+
827
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'children'>`.
828
+
829
+ | Prop | Type | Notes |
830
+ | ----------- | ----------------------------------------------- | ----- |
831
+ | `bordered?` | `boolean` | |
832
+ | `colon?` | `boolean` | |
833
+ | `column?` | `number \| Partial<Record<Breakpoint, number>>` | |
834
+ | `extra?` | `ReactNode` | |
835
+ | `items` | `DescriptionsItem[]` | |
836
+ | `layout?` | `'horizontal' \| 'vertical'` | |
837
+ | `size?` | `'sm' \| 'md' \| 'lg'` | |
838
+ | `title?` | `ReactNode` | |
839
+
840
+ ### `DescriptionsItem`
841
+
842
+ _Type._
843
+
844
+ <sub>`src/components/Dialog.tsx`</sub>
845
+
846
+ ### `Dialog`
847
+
848
+ Ship's "New …" dialogs are a wide, near-full-height sheet, not a centred card — `size="xl"` reproduces that.
849
+
850
+ | Prop | Type | Notes |
851
+ | ---------------- | ---------------------------------------- | -------------------------------------------------------- |
852
+ | `bodyClassName?` | `string` | |
853
+ | `children` | `ReactNode` | |
854
+ | `className?` | `string` | |
855
+ | `closable?` | `boolean` | |
856
+ | `closeLabel?` | `string` | |
857
+ | `dismissable?` | `boolean` | Prevents the scrim / Esc from discarding a dirty form. |
858
+ | `footer?` | `ReactNode` | |
859
+ | `keyboard?` | `boolean` | |
860
+ | `maskClosable?` | `boolean` | |
861
+ | `maskContent?` | `ReactNode` | |
862
+ | `maskStyle?` | `CSSProperties` | |
863
+ | `onClose` | `() => void` | |
864
+ | `open` | `boolean` | |
865
+ | `placement?` | `'top' \| 'right' \| 'bottom' \| 'left'` | |
866
+ | `size?` | `'sm' \| 'md' \| 'lg' \| 'xl'` | |
867
+ | `style?` | `CSSProperties` | |
868
+ | `title` | `ReactNode` | |
869
+ | `tools?` | `ReactNode` | Extra header controls rendered left of the close button. |
870
+
871
+ <sub>`src/components/Divider.tsx`</sub>
872
+
873
+ ### `Divider`
874
+
875
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
876
+
877
+ | Prop | Type | Notes |
878
+ | ----------------- | --------------------------------- | ----- |
879
+ | `className?` | `string` | |
880
+ | `dashed?` | `boolean` | |
881
+ | `orientation?` | `'horizontal' \| 'vertical'` | |
882
+ | `plain?` | `boolean` | |
883
+ | `titlePlacement?` | `'start' \| 'center' \| 'end'` | |
884
+ | `variant?` | `'solid' \| 'dashed' \| 'dotted'` | |
885
+
886
+ <sub>`src/components/Drawer.tsx`</sub>
887
+
888
+ ### `Drawer`
889
+
890
+ Shares modal focus, stacking and scroll-lock behavior with Dialog.
891
+
892
+ Also accepts: `Omit<DialogProps, 'size' | 'placement'>`.
893
+
894
+ | Prop | Type | Notes |
895
+ | ------------ | ---------------------------------------- | ----- |
896
+ | `height?` | `number \| string` | |
897
+ | `placement?` | `'top' \| 'right' \| 'bottom' \| 'left'` | |
898
+ | `width?` | `number \| string` | |
899
+
900
+ <sub>`src/components/Dropdown.tsx`</sub>
901
+
902
+ ### `Dropdown`
903
+
904
+ A native button trigger using the existing Menu keyboard and submenu behavior.
905
+
906
+ Also accepts: `Omit<ButtonProps, 'onSelect'>`.
907
+
908
+ | Prop | Type | Notes |
909
+ | --------------- | ------------------------- | ----- |
910
+ | `defaultOpen?` | `boolean` | |
911
+ | `menu` | `MenuProps` | |
912
+ | `onOpenChange?` | `(open: boolean) => void` | |
913
+ | `open?` | `boolean` | |
914
+ | `placement?` | `Placement` | |
915
+
916
+ <sub>`src/components/Flex.tsx`</sub>
917
+
918
+ ### `Flex`
919
+
920
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
921
+
922
+ | Prop | Type | Notes |
923
+ | ----------- | -------------------------------------- | ----- |
924
+ | `align?` | `CSSProperties['alignItems']` | |
925
+ | `flex?` | `CSSProperties['flex']` | |
926
+ | `gap?` | `number \| string` | |
927
+ | `justify?` | `CSSProperties['justifyContent']` | |
928
+ | `vertical?` | `boolean` | |
929
+ | `wrap?` | `boolean \| CSSProperties['flexWrap']` | |
930
+
931
+ ### `Space`
932
+
933
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
934
+
935
+ | Prop | Type | Notes |
936
+ | ------------ | ---------------------------------------------------------------------------------------------------- | ----- |
937
+ | `align?` | `'start' \| 'end' \| 'center' \| 'baseline'` | |
938
+ | `direction?` | `'horizontal' \| 'vertical'` | |
939
+ | `separator?` | `ReactNode` | |
940
+ | `size?` | `number \| 'sm' \| 'md' \| 'lg' \| [number \| 'sm' \| 'md' \| 'lg', number \| 'sm' \| 'md' \| 'lg']` | |
941
+ | `wrap?` | `boolean` | |
942
+
943
+ <sub>`src/components/FloatButton.tsx`</sub>
944
+
945
+ ### `BackTop`
946
+
947
+ Compatibility BackTop entry also exposed as FloatButton.BackTop.
948
+
949
+ Also accepts: `Omit<ButtonProps, 'icon' | 'iconAfter' | 'shape' | 'content'>`.
950
+
951
+ | Prop | Type | Notes |
952
+ | ------------------- | -------------------------------------------------------------------------------- | ----- |
953
+ | `badge?` | `Pick<BadgeProps, 'count' \| 'dot' \| 'overflowCount' \| 'showZero' \| 'label'>` | |
954
+ | `behavior?` | `ScrollBehavior` | |
955
+ | `content?` | `ReactNode` | |
956
+ | `description?` | `ReactNode` | |
957
+ | `icon?` | `ReactNode` | |
958
+ | `shape?` | `'circle' \| 'square'` | |
959
+ | `showProgress?` | `boolean` | |
960
+ | `target?` | `() => ScrollTarget \| null` | |
961
+ | `tooltip?` | `ReactNode` | |
962
+ | `visibilityHeight?` | `number` | |
963
+
964
+ ### `FloatButton`
965
+
966
+ Also accepts: `Omit<ButtonProps, 'icon' | 'iconAfter' | 'shape' | 'content'>`.
967
+
968
+ | Prop | Type | Notes |
969
+ | -------------- | -------------------------------------------------------------------------------- | ----- |
970
+ | `badge?` | `Pick<BadgeProps, 'count' \| 'dot' \| 'overflowCount' \| 'showZero' \| 'label'>` | |
971
+ | `content?` | `ReactNode` | |
972
+ | `description?` | `ReactNode` | |
973
+ | `icon?` | `ReactNode` | |
974
+ | `shape?` | `'circle' \| 'square'` | |
975
+ | `tooltip?` | `ReactNode` | |
976
+
977
+ ### `FloatButtonGroup`
978
+
979
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
980
+
981
+ | Prop | Type | Notes |
982
+ | --------------- | ------------------------- | ----- |
983
+ | `'aria-label'` | `string` | |
984
+ | `closeIcon?` | `ReactNode` | |
985
+ | `defaultOpen?` | `boolean` | |
986
+ | `disabled?` | `boolean` | |
987
+ | `icon?` | `ReactNode` | |
988
+ | `onOpenChange?` | `(open: boolean) => void` | |
989
+ | `open?` | `boolean` | |
990
+ | `trigger?` | `'click' \| 'hover'` | |
991
+
992
+ <sub>`src/components/Form.tsx`</sub>
993
+
994
+ ### `Form`
995
+
996
+ Standalone exports and Ant-style compound names share the same implementation.
997
+
998
+ Also accepts: `Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit' | 'onChange'>`.
999
+
1000
+ | Prop | Type | Notes |
1001
+ | --------------------- | ------------------------------------------------------------------------------------------ | ----- |
1002
+ | `disabled?` | `boolean` | |
1003
+ | `form?` | `FormInstance` | |
1004
+ | `initialValues?` | `FormValues` | |
1005
+ | `onFinish?` | `(values: FormValues) => void \| Promise<void>` | |
1006
+ | `onFinishFailed?` | `(error: FormValidationError) => void` | |
1007
+ | `onSubmitError?` | `(error: unknown) => void` | |
1008
+ | `onValuesChange?` | `(changed: FormValues, values: FormValues) => void` | |
1009
+ | `preserve?` | `boolean` | |
1010
+ | `scrollToFirstError?` | `boolean \| { focus?: boolean; block?: ScrollLogicalPosition; behavior?: ScrollBehavior }` | |
1011
+ | `validateTrigger?` | `ValidationTrigger` | |
1012
+
1013
+ ### `FormError`
1014
+
1015
+ _Type._
1016
+
1017
+ ### `FormInstance`
1018
+
1019
+ _Type._
1020
+
1021
+ ### `FormItem`
1022
+
1023
+ | Prop | Type | Notes |
1024
+ | -------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------- |
1025
+ | `children` | `ReactElement \| ((form: FormInstance) => ReactNode)` | |
1026
+ | `className?` | `string` | |
1027
+ | `dependencies?` | `NamePath[]` | Absolute form paths, including the complete Form.List prefix and index. |
1028
+ | `emptyValue?` | `unknown` | |
1029
+ | `getValueFromEvent?` | `(...args: unknown[]) => unknown` | |
1030
+ | `hint?` | `ReactNode` | |
1031
+ | `label?` | `ReactNode` | |
1032
+ | `name?` | `NamePath` | |
1033
+ | `noStyle?` | `boolean` | |
1034
+ | `preserve?` | `boolean` | |
1035
+ | `required?` | `boolean` | |
1036
+ | `rules?` | `FormRule[]` | |
1037
+ | `shouldUpdate?` | `boolean \| ((previous: FormValues, next: FormValues) => boolean)` | |
1038
+ | `validateTrigger?` | `ValidationTrigger` | |
1039
+ | `valuePropName?` | `string` | |
1040
+
1041
+ ### `FormList`
1042
+
1043
+ Dynamic array fields.
1044
+
1045
+ | Prop | Type | Notes |
1046
+ | ------------ | ---------------------------------------------------------------------------------------------------- | ----- |
1047
+ | `children` | `(fields: FormListField[], operations: FormListOperations, meta: { errors: string[] }) => ReactNode` | |
1048
+ | `className?` | `string` | |
1049
+ | `name` | `NamePath` | |
1050
+ | `rules?` | `FormRule[]` | |
1051
+
1052
+ ### `FormListField`
1053
+
1054
+ _Type._
1055
+
1056
+ ### `FormListOperations`
1057
+
1058
+ _Type._
1059
+
1060
+ ### `FormRule`
1061
+
1062
+ _Type._
1063
+
1064
+ ### `FormValidationError`
1065
+
1066
+ _Type._
1067
+
1068
+ ### `FormValues`
1069
+
1070
+ Strings are literal keys; array name paths describe nested object/array values.
1071
+
1072
+ _Type._
1073
+
1074
+ ### `useForm`
1075
+
1076
+ _No props type — see the source._
1077
+
1078
+ ### `useFormInstance`
1079
+
1080
+ _No props type — see the source._
1081
+
1082
+ ### `useWatch`
1083
+
1084
+ _No props type — see the source._
1085
+
1086
+ <sub>`src/components/Grid.tsx`</sub>
1087
+
1088
+ ### `Col`
1089
+
1090
+ Also accepts: `HTMLAttributes<HTMLDivElement>`, `Partial<Record<Breakpoint, number | ColSize>>`.
1091
+
1092
+ | Prop | Type | Notes |
1093
+ | --------- | ------------------ | ----- |
1094
+ | `flex?` | `number \| string` | |
1095
+ | `offset?` | `number` | |
1096
+ | `order?` | `number` | |
1097
+ | `pull?` | `number` | |
1098
+ | `push?` | `number` | |
1099
+ | `span?` | `number` | |
1100
+
1101
+ ### `ColSize`
1102
+
1103
+ _Type._
1104
+
1105
+ ### `Grid`
1106
+
1107
+ _No props type — see the source._
1108
+
1109
+ ### `Row`
1110
+
1111
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
1112
+
1113
+ | Prop | Type | Notes |
1114
+ | ---------- | ------------------------------------------------------------------------------------------------- | ----- |
1115
+ | `align?` | `Responsive<'top' \| 'middle' \| 'bottom' \| 'stretch'>` | |
1116
+ | `gutter?` | `Gutter \| [Gutter, Gutter]` | |
1117
+ | `justify?` | `Responsive<'start' \| 'end' \| 'center' \| 'space-around' \| 'space-between' \| 'space-evenly'>` | |
1118
+ | `wrap?` | `boolean` | |
1119
+
1120
+ <sub>`src/components/Icon.tsx`</sub>
1121
+
1122
+ ### `Icon`
1123
+
1124
+ Renders PingCode's icon geometry inline.
1125
+
1126
+ Also accepts: `Omit<HTMLAttributes<HTMLSpanElement>, 'children'>`.
1127
+
1128
+ | Prop | Type | Notes |
1129
+ | ------------ | --------------------- | -------------------------------------------------------------------- |
1130
+ | `className?` | `string` | |
1131
+ | `label?` | `string` | Decorative by default; pass a label to expose it to assistive tech. |
1132
+ | `name` | `IconName \| string` | Sprite name, e.g. `house-fill`. Unknown names preserve an empty box. |
1133
+ | `size?` | `number \| string` | Font-size in px; the glyph is a 1em square. |
1134
+ | `style?` | `React.CSSProperties` | |
1135
+
1136
+ <sub>`src/components/Image.tsx`</sub>
1137
+
1138
+ ### `Image`
1139
+
1140
+ Also accepts: `Omit<ImgHTMLAttributes<HTMLImageElement>, 'placeholder'>`.
1141
+
1142
+ | Prop | Type | Notes |
1143
+ | -------------- | ------------------------------- | ----- |
1144
+ | `alt` | `string` | |
1145
+ | `disabled?` | `boolean` | |
1146
+ | `fallback?` | `string` | |
1147
+ | `placeholder?` | `ReactNode` | |
1148
+ | `preview?` | `boolean \| ImagePreviewConfig` | |
1149
+
1150
+ <sub>`src/components/Input.tsx`</sub>
1151
+
1152
+ ### `Field`
1153
+
1154
+ | Prop | Type | Notes |
1155
+ | ------------ | ----------- | ----- |
1156
+ | `children` | `ReactNode` | |
1157
+ | `className?` | `string` | |
1158
+ | `error?` | `ReactNode` | |
1159
+ | `hint?` | `ReactNode` | |
1160
+ | `htmlFor?` | `string` | |
1161
+ | `label?` | `ReactNode` | |
1162
+ | `required?` | `boolean` | |
1163
+
1164
+ ### `Input`
1165
+
1166
+ Also accepts: `Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'>`.
1167
+
1168
+ | Prop | Type | Notes |
1169
+ | --------------- | ----------------------------------------------------------------------------------------------------- | ----- |
1170
+ | `allowClear?` | `boolean` | |
1171
+ | `clearLabel?` | `string` | |
1172
+ | `invalid?` | `boolean` | |
1173
+ | `onClear?` | `() => void` | |
1174
+ | `onPressEnter?` | `KeyboardEventHandler<HTMLInputElement>` | |
1175
+ | `prefix?` | `ReactNode` | |
1176
+ | `showCount?` | `boolean \| { formatter: (info: { value: string; count: number; maxLength?: number }) => ReactNode }` | |
1177
+ | `size?` | `'sm' \| 'md' \| 'lg'` | |
1178
+ | `status?` | `'warning' \| 'error'` | |
1179
+ | `suffix?` | `ReactNode` | |
1180
+ | `variant?` | `'outlined' \| 'borderless' \| 'filled' \| 'underlined'` | |
1181
+
1182
+ ### `SearchInput`
1183
+
1184
+ Also accepts: `Omit<InputHTMLAttributes<HTMLInputElement>, 'size'>`.
1185
+
1186
+ | Prop | Type | Notes |
1187
+ | --------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
1188
+ | `shape?` | `'header' \| 'field'` | `header` = the 16px top-bar pill-less box; `field` = the 4.8px borderless page/toolbar field that only rings on focus (both measured from the live DOM). |
1189
+ | `size?` | `'sm' \| 'md'` | |
1190
+ | `suffix?` | `ReactNode` | Rendered after the field, e.g. a shortcut hint or a filter caret. |
1191
+ | `width?` | `number \| string` | |
1192
+
1193
+ ### `Textarea`
1194
+
1195
+ Also accepts: `TextareaHTMLAttributes<HTMLTextAreaElement>`.
1196
+
1197
+ | Prop | Type | Notes |
1198
+ | ---------- | --------- | ----- |
1199
+ | `invalid?` | `boolean` | |
1200
+
1201
+ <sub>`src/components/InputNumber.tsx`</sub>
1202
+
1203
+ ### `InputNumber`
1204
+
1205
+ Numeric entry with editing drafts, bounded stepping and a native input ref.
1206
+
1207
+ Also accepts: `Omit< InputProps, 'type' | 'value' | 'defaultValue' | 'onChange' | 'min' | 'max' | 'step' | 'allowClear' >`.
1208
+
1209
+ | Prop | Type | Notes |
1210
+ | --------------- | --------------------------------------------------------------------------------- | ----- |
1211
+ | `controls?` | `boolean` | |
1212
+ | `defaultValue?` | `number \| null` | |
1213
+ | `formatter?` | `(value: number \| null, info: { userTyping: boolean; input: string }) => string` | |
1214
+ | `keyboard?` | `boolean` | |
1215
+ | `max?` | `number` | |
1216
+ | `min?` | `number` | |
1217
+ | `onChange?` | `(value: number \| null) => void` | |
1218
+ | `onStep?` | `(value: number, info: { offset: number; type: 'up' \| 'down' }) => void` | |
1219
+ | `parser?` | `(input: string) => number \| null` | |
1220
+ | `precision?` | `number` | |
1221
+ | `step?` | `number` | |
1222
+ | `value?` | `number \| null` | |
1223
+
1224
+ <sub>`src/components/Layout.tsx`</sub>
1225
+
1226
+ ### `Layout`
1227
+
1228
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
1229
+
1230
+ | Prop | Type | Notes |
1231
+ | ----------- | --------- | ----- |
1232
+ | `hasSider?` | `boolean` | |
1233
+
1234
+ <sub>`src/components/List.tsx`</sub>
1235
+
1236
+ ### `List`
1237
+
1238
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'children'>`.
1239
+
1240
+ | Prop | Type | Notes |
1241
+ | ------------- | ---------------------------------------------------------------------------- | ----- |
1242
+ | `bordered?` | `boolean` | |
1243
+ | `children?` | `ReactNode` | |
1244
+ | `dataSource?` | `T[]` | |
1245
+ | `emptyText?` | `ReactNode` | |
1246
+ | `footer?` | `ReactNode` | |
1247
+ | `grid?` | `{ column?: number; gutter?: number } & Partial<Record<Breakpoint, number>>` | |
1248
+ | `header?` | `ReactNode` | |
1249
+ | `itemLayout?` | `'horizontal' \| 'vertical'` | |
1250
+ | `loading?` | `boolean` | |
1251
+ | `loadMore?` | `ReactNode` | |
1252
+ | `pagination?` | `false \| Omit<PaginationProps, 'total' \| 'left' \| 'children'>` | |
1253
+ | `renderItem?` | `(item: T, index: number) => ReactNode` | |
1254
+ | `rowKey?` | `keyof T \| ((item: T) => Key)` | |
1255
+ | `size?` | `'small' \| 'default' \| 'large'` | |
1256
+ | `split?` | `boolean` | |
1257
+
1258
+ ### `ListItem`
1259
+
1260
+ Also accepts: `HTMLAttributes<HTMLLIElement>`.
1261
+
1262
+ | Prop | Type | Notes |
1263
+ | ---------- | ------------- | ----- |
1264
+ | `actions?` | `ReactNode[]` | |
1265
+ | `extra?` | `ReactNode` | |
1266
+
1267
+ ### `ListItemMeta`
1268
+
1269
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'title'>`.
1270
+
1271
+ | Prop | Type | Notes |
1272
+ | -------------- | ----------- | ----- |
1273
+ | `avatar?` | `ReactNode` | |
1274
+ | `description?` | `ReactNode` | |
1275
+ | `title?` | `ReactNode` | |
1276
+
1277
+ <sub>`src/components/Listy.tsx`</sub>
1278
+
1279
+ ### `Listy`
1280
+
1281
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'children'>`.
1282
+
1283
+ | Prop | Type | Notes |
1284
+ | ------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------- |
1285
+ | `group?` | `{ key: (item: T) => Key; title: (key: Key, items: T[]) => ReactNode }` | |
1286
+ | `height?` | `number` | |
1287
+ | `itemHeight?` | `number` | Virtual lists use fixed-height rows (including group headers). |
1288
+ | `itemRender` | `(item: T, index: number) => ReactNode` | |
1289
+ | `items?` | `T[]` | |
1290
+ | `rowKey` | `keyof T \| ((item: T) => Key)` | |
1291
+ | `sticky?` | `boolean` | |
1292
+ | `virtual?` | `boolean` | |
1293
+
1294
+ <sub>`src/components/Masonry.tsx`</sub>
1295
+
1296
+ ### `Masonry`
1297
+
1298
+ Measured shortest-column layout; DOM and reading order stay in source order.
1299
+
1300
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'children'>`.
1301
+
1302
+ | Prop | Type | Notes |
1303
+ | ----------------- | ------------------------------------------------------------------------- | ----- |
1304
+ | `columns?` | `number \| Partial<Record<Breakpoint, number>>` | |
1305
+ | `gutter?` | `number \| [number, number]` | |
1306
+ | `itemRender?` | `(item: MasonryItem<T> & { index: number; column: number }) => ReactNode` | |
1307
+ | `items?` | `MasonryItem<T>[]` | |
1308
+ | `onLayoutChange?` | `(layout: { key: Key; column: number }[]) => void` | |
1309
+
1310
+ <sub>`src/components/Mentions.tsx`</sub>
1311
+
1312
+ ### `MentionOption`
1313
+
1314
+ _Type._
1315
+
1316
+ ### `Mentions`
1317
+
1318
+ Also accepts: `Omit< TextareaHTMLAttributes<HTMLTextAreaElement>, 'value' | 'defaultValue' | 'onChange' | 'onSelect' | 'prefix' | 'children' >`.
1319
+
1320
+ | Prop | Type | Notes |
1321
+ | ------------------ | -------------------------------------------------------------- | ----- |
1322
+ | `defaultValue?` | `string` | |
1323
+ | `filterOption?` | `false \| ((query: string, option: MentionOption) => boolean)` | |
1324
+ | `invalid?` | `boolean` | |
1325
+ | `loading?` | `boolean` | |
1326
+ | `notFoundContent?` | `ReactNode` | |
1327
+ | `onChange?` | `(value: string) => void` | |
1328
+ | `onSearch?` | `(query: string, prefix: string) => void` | |
1329
+ | `onSelect?` | `(option: MentionOption, prefix: string) => void` | |
1330
+ | `options` | `MentionOption[]` | |
1331
+ | `placement?` | `'top' \| 'bottom'` | |
1332
+ | `prefix?` | `string \| string[]` | |
1333
+ | `split?` | `string` | |
1334
+ | `validateSearch?` | `(query: string, split: string) => boolean` | |
1335
+ | `value?` | `string` | |
1336
+
1337
+ ### `MentionsConfig`
1338
+
1339
+ _Type._
1340
+
1341
+ ### `MentionsEntity`
1342
+
1343
+ _Type._
1344
+
1345
+ <sub>`src/components/Menu.tsx`</sub>
1346
+
1347
+ ### `Menu`
1348
+
1349
+ | Prop | Type | Notes |
1350
+ | ----------------------- | ---------------------------------------- | --------------------------------------------------------------- |
1351
+ | `'aria-label'?` | `string` | |
1352
+ | `className?` | `string` | |
1353
+ | `closeOnSelect?` | `boolean` | Let a host own dismissal; defaults to false for multiple menus. |
1354
+ | `defaultOpenKeys?` | `string[]` | |
1355
+ | `defaultSelectedKeys?` | `string[]` | |
1356
+ | `disabled?` | `boolean` | |
1357
+ | `items` | `MenuItemSpec[]` | |
1358
+ | `mode?` | `'vertical' \| 'horizontal' \| 'inline'` | |
1359
+ | `multiple?` | `boolean` | |
1360
+ | `onOpenChange?` | `(keys: string[]) => void` | |
1361
+ | `onSelect?` | `(id: string) => void` | |
1362
+ | `onSelectedKeysChange?` | `(keys: string[]) => void` | |
1363
+ | `openKeys?` | `string[]` | |
1364
+ | `searchable?` | `boolean` | Renders a filter field above the items once the list gets long. |
1365
+ | `searchPlaceholder?` | `string` | |
1366
+ | `selectable?` | `boolean` | |
1367
+ | `selectedKeys?` | `string[]` | |
1368
+
1369
+ ### `MenuItemSpec`
1370
+
1371
+ _Type._
1372
+
1373
+ <sub>`src/components/Nav.tsx`</sub>
1374
+
1375
+ ### `Nav`
1376
+
1377
+ PingCode's top-level product tabs: a text row with a 2px accent "ink" bar that slides under the active tab.
1378
+
1379
+ Also accepts: `Omit<HTMLAttributes<HTMLElement>, 'onChange'>`.
1380
+
1381
+ | Prop | Type | Notes |
1382
+ | ------------------ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1383
+ | `'aria-label'?` | `string` | |
1384
+ | `className?` | `string` | |
1385
+ | `disabled?` | `boolean` | |
1386
+ | `itemContextMenu?` | `(item: NavItemSpec) => ContextMenuItem[]` | Right-click commands for a tab; each must also be reachable another way. |
1387
+ | `items` | `NavItemSpec[]` | |
1388
+ | `onChange` | `(id: string) => void` | |
1389
+ | `overflowItems?` | `NavItemSpec[]` | Extra destinations folded into a "More" menu, as the product does. |
1390
+ | `size?` | `NavSize` | Height and side padding of the strip. `md` (the default) is the 52px top strip; `sm` is the 48px second-level strip the Admin console nests under it — the only two measured differences. Everything else (ink bar, overflow, ←→ keyboard, context menu) is shared. |
1391
+ | `value` | `string` | The current tab. Controlled — routing owns the selection. |
1392
+
1393
+ ### `NavItemSpec`
1394
+
1395
+ _Type._
1396
+
1397
+ ### `NavSize`
1398
+
1399
+ `md` is the 52px / 16px product strip; `sm` the 48px / 8px second-level one.
1400
+
1401
+ _Type._
1402
+
1403
+ <sub>`src/components/Pagination.tsx`</sub>
1404
+
1405
+ ### `Pagination`
1406
+
1407
+ Ship's footer pager: page-size menu on the left, numbered pages in the middle, and an explicit "Go to" field for long lists.
1408
+
1409
+ | Prop | Type | Notes |
1410
+ | ------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------ |
1411
+ | `children?` | `ReactNode` | Extra controls pinned to the right of the pager (column settings, etc.). |
1412
+ | `className?` | `string` | |
1413
+ | `defaultPage?` | `number` | |
1414
+ | `defaultPageSize?` | `number` | |
1415
+ | `disabled?` | `boolean` | |
1416
+ | `hideOnSinglePage?` | `boolean` | |
1417
+ | `left?` | `ReactNode` | View controls pinned to the left of the row count (Ship's list footer). |
1418
+ | `onChange?` | `(page: number, pageSize: number) => void` | |
1419
+ | `onPageChange?` | `(page: number) => void` | |
1420
+ | `onPageSizeChange?` | `(size: number) => void` | |
1421
+ | `page?` | `number` | |
1422
+ | `pageSize?` | `number` | |
1423
+ | `pageSizeOptions?` | `number[]` | |
1424
+ | `showQuickJumper?` | `boolean` | |
1425
+ | `showSizeChanger?` | `boolean` | |
1426
+ | `showTotal?` | `(total: number, range: [number, number]) => ReactNode` | |
1427
+ | `total` | `number` | |
1428
+
1429
+ <sub>`src/components/PasswordInput.tsx`</sub>
1430
+
1431
+ ### `PasswordInput`
1432
+
1433
+ Password field with an explicit, keyboard-accessible visibility toggle.
1434
+
1435
+ Also accepts: `Omit<InputProps, 'type'>`.
1436
+
1437
+ | Prop | Type | Notes |
1438
+ | ------------------ | ---------------------------- | ----- |
1439
+ | `defaultVisible?` | `boolean` | |
1440
+ | `hideLabel?` | `string` | |
1441
+ | `onVisibleChange?` | `(visible: boolean) => void` | |
1442
+ | `showLabel?` | `string` | |
1443
+ | `visible?` | `boolean` | |
1444
+
1445
+ <sub>`src/components/PeoplePicker.tsx`</sub>
1446
+
1447
+ ### `PeoplePicker`
1448
+
1449
+ The inline assignee quick editor: the panel the Ship grid opens when an Assignee cell is clicked — a search field, a Members / Dept / Group segment and the people of the active tab, with `Unassigned` pinned to the top.
1450
+
1451
+ | Prop | Type | Notes |
1452
+ | -------------------- | ------------------- | ----- |
1453
+ | `'aria-label'?` | `string` | |
1454
+ | `disabled?` | `boolean` | |
1455
+ | `emptyHint?` | `string` | |
1456
+ | `error?` | `ReactNode` | |
1457
+ | `loading?` | `boolean` | |
1458
+ | `onRetry?` | `() => void` | |
1459
+ | `searchPlaceholder?` | `string` | |
1460
+ | `tabs` | `PeoplePickerTab[]` | |
1461
+ | `value?` | `string \| null` | |
1462
+
1463
+ ### `PeoplePickerPerson`
1464
+
1465
+ One selectable person.
1466
+
1467
+ _Type._
1468
+
1469
+ ### `PeoplePickerTab`
1470
+
1471
+ _Type._
1472
+
1473
+ <sub>`src/components/Popconfirm.tsx`</sub>
1474
+
1475
+ ### `Popconfirm`
1476
+
1477
+ Also accepts: `ButtonProps`.
1478
+
1479
+ | Prop | Type | Notes |
1480
+ | --------------- | --------------------------------------------------- | ----- |
1481
+ | `cancelText?` | `ReactNode` | |
1482
+ | `defaultOpen?` | `boolean` | |
1483
+ | `description?` | `ReactNode` | |
1484
+ | `okText?` | `ReactNode` | |
1485
+ | `onCancel?` | `() => void` | |
1486
+ | `onConfirm?` | `() => void \| boolean \| Promise<void \| boolean>` | |
1487
+ | `onError?` | `(error: unknown) => void` | |
1488
+ | `onOpenChange?` | `(open: boolean) => void` | |
1489
+ | `open?` | `boolean` | |
1490
+ | `placement?` | `Placement` | |
1491
+ | `showCancel?` | `boolean` | |
1492
+ | `title` | `string` | |
1493
+
1494
+ <sub>`src/components/Popover.tsx`</sub>
1495
+
1496
+ ### `Placement`
1497
+
1498
+ _Type._
1499
+
1500
+ ### `Popover`
1501
+
1502
+ A single floating layer: positioned against its anchor, portalled to <body> so it escapes the table's overflow context, dismissed on Esc / outside click.
1503
+
1504
+ | Prop | Type | Notes |
1505
+ | ------------------------ | --------------------- | --------------------------------------------------------------------- |
1506
+ | `'aria-label'?` | `string` | |
1507
+ | `anchor` | `HTMLElement \| null` | The element the layer is anchored to — usually the trigger itself. |
1508
+ | `autoFocus?` | `boolean` | Moves focus into the layer when it was opened from the keyboard. |
1509
+ | `children` | `ReactNode` | |
1510
+ | `className?` | `string` | |
1511
+ | `dismissOnOutsideClick?` | `boolean` | Skips outside-click dismissal (used for menus that manage their own). |
1512
+ | `matchAnchorWidth?` | `boolean` | |
1513
+ | `onClose` | `() => void` | |
1514
+ | `open` | `boolean` | |
1515
+ | `placement?` | `Placement` | |
1516
+
1517
+ ### `useAnchorRef`
1518
+
1519
+ Keeps `ref` in state so an anchored layer can measure it after mount.
1520
+
1521
+ _No props type — see the source._
1522
+
1523
+ ### `usePopoverClose`
1524
+
1525
+ _No props type — see the source._
1526
+
1527
+ <sub>`src/components/QRCode.tsx`</sub>
1528
+
1529
+ ### `QRCode`
1530
+
1531
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
1532
+
1533
+ | Prop | Type | Notes |
1534
+ | ---------------- | ---------------------------------------------------------------------------------------------- | ----- |
1535
+ | `bgColor?` | `string` | |
1536
+ | `boostLevel?` | `boolean` | |
1537
+ | `bordered?` | `boolean` | |
1538
+ | `color?` | `string` | |
1539
+ | `errorLevel?` | `QRCodeErrorLevel` | |
1540
+ | `icon?` | `string` | |
1541
+ | `iconSize?` | `number \| { width: number; height: number }` | |
1542
+ | `imageSettings?` | `QRCodeImageSettings` | |
1543
+ | `marginSize?` | `number` | |
1544
+ | `onRefresh?` | `() => void` | |
1545
+ | `size?` | `number` | |
1546
+ | `status?` | `'active' \| 'loading' \| 'expired' \| 'scanned'` | |
1547
+ | `statusRender?` | `(info: { status: 'loading' \| 'expired' \| 'scanned'; onRefresh?: () => void }) => ReactNode` | |
1548
+ | `type?` | `'svg' \| 'canvas'` | |
1549
+ | `value` | `string \| string[]` | |
1550
+
1551
+ ### `QRCodeErrorLevel`
1552
+
1553
+ _Type._
1554
+
1555
+ ### `QRCodeImageSettings`
1556
+
1557
+ _Type._
1558
+
1559
+ <sub>`src/components/QuickSelect.tsx`</sub>
1560
+
1561
+ ### `QuickSelect`
1562
+
1563
+ The grid's inline enum quick editor: the cell _is_ the field — a box holding the current value and a caret — and the list it opens is portalled, so a table can never clip it.
1564
+
1565
+ | Prop | Type | Notes |
1566
+ | --------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1567
+ | `'aria-label'?` | `string` | |
1568
+ | `allowClear?` | `boolean` | Adds a `Clear` row, for a field the record may leave empty. |
1569
+ | `className?` | `string` | Extra class on the field itself, so a grid cell can widen its hit area. |
1570
+ | `disabled?` | `boolean` | |
1571
+ | `display?` | `ReactNode` | The node the field shows for its current value while it is not being typed in — normally the very node the cell already renders, so opening the editor never changes what the cell looks like. |
1572
+ | `options` | `QuickSelectOption[]` | |
1573
+ | `placeholder?` | `string` | |
1574
+ | `readOnly?` | `boolean` | |
1575
+ | `renderOption?` | `(option: QuickSelectOption) => ReactNode` | Draws an option — in the list rows and, when the field has no `display` of its own, in the field box. The host supplies it for enums that carry a visual representation (`LevelTag`, `StatusTag`, the category pill); the library never re-implements a palette. |
1576
+ | `value` | `string \| null` | |
1577
+
1578
+ ### `QuickSelectOption`
1579
+
1580
+ _Type._
1581
+
1582
+ <sub>`src/components/QuickText.tsx`</sub>
1583
+
1584
+ ### `QuickText`
1585
+
1586
+ The grid's inline text editor: the cell itself becomes a bordered input holding the current value, selected, so the first keystroke replaces it.
1587
+
1588
+ | Prop | Type | Notes |
1589
+ | --------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1590
+ | `'aria-label'?` | `string` | |
1591
+ | `disabled?` | `boolean` | |
1592
+ | `display?` | `ReactNode` | What the cell shows while the field is at rest — normally the very node the column already draws (its `TitleCell`), so opening the editor changes nothing about the cell but the input itself. |
1593
+ | `maxLength?` | `number` | |
1594
+ | `nullable?` | `boolean` | Lets a commit write an empty value. A title is not blankable by default. |
1595
+ | `placeholder?` | `string` | |
1596
+ | `readOnly?` | `boolean` | |
1597
+ | `selectOnOpen?` | `boolean` | |
1598
+ | `trigger?` | `'click' \| 'dblclick'` | The gesture that swaps the cell for the input. `click` by default, so the three inline editors answer to the same gesture — the live cell is a `*-quick-editor`, and its column carries no other click of its own. A host whose cell already navigates on click can pass `dblclick`, in which case `onActivate` keeps that navigation alive. |
1599
+ | `value` | `string` | |
1600
+
1601
+ <sub>`src/components/Radio.tsx`</sub>
1602
+
1603
+ ### `Radio`
1604
+
1605
+ Also accepts: `Omit<InputHTMLAttributes<HTMLInputElement>, 'type'>`.
1606
+
1607
+ | Prop | Type | Notes |
1608
+ | -------- | ----------- | ----- |
1609
+ | `label?` | `ReactNode` | |
1610
+
1611
+ ### `RadioGroup`
1612
+
1613
+ Native same-name radios provide arrow navigation and form submission.
1614
+
1615
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'>`.
1616
+
1617
+ | Prop | Type | Notes |
1618
+ | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
1619
+ | `'aria-label'` | `string` | |
1620
+ | `className?` | `string` | |
1621
+ | `defaultValue?` | `string` | |
1622
+ | `disabled?` | `boolean` | |
1623
+ | `name?` | `string` | |
1624
+ | `onChange?` | `(value: string) => void` | |
1625
+ | `options` | `Array<{ value: string; label: ReactNode; disabled?: boolean; id?: string; title?: string; required?: boolean; className?: string; style?: CSSProperties; onChange?: ChangeEventHandler<HTMLInputElement>; }>` | |
1626
+ | `orientation?` | `'horizontal' \| 'vertical'` | |
1627
+ | `required?` | `boolean` | |
1628
+ | `value?` | `string` | |
1629
+
1630
+ <sub>`src/components/Rate.tsx`</sub>
1631
+
1632
+ ### `Rate`
1633
+
1634
+ Native radios provide discrete ratings, form values and arrow navigation.
1635
+
1636
+ | Prop | Type | Notes |
1637
+ | ---------------- | ------------------------- | ------------------------------------------------------ |
1638
+ | `'aria-label'` | `string` | |
1639
+ | `allowClear?` | `boolean` | |
1640
+ | `allowHalf?` | `boolean` | |
1641
+ | `character?` | `ReactNode` | |
1642
+ | `className?` | `string` | |
1643
+ | `clearLabel?` | `string` | |
1644
+ | `count?` | `number` | Rating from 0 to count, optionally in half-star steps. |
1645
+ | `defaultValue?` | `number` | |
1646
+ | `disabled?` | `boolean` | |
1647
+ | `name?` | `string` | |
1648
+ | `onChange?` | `(value: number) => void` | |
1649
+ | `onHoverChange?` | `(value: number) => void` | |
1650
+ | `readOnly?` | `boolean` | |
1651
+ | `tooltips?` | `string[]` | |
1652
+ | `value?` | `number` | |
1653
+
1654
+ <sub>`src/components/Segment.tsx`</sub>
1655
+
1656
+ ### `Chip`
1657
+
1658
+ Filter pills in the products toolbar (All / Starred / Recent).
1659
+
1660
+ Also accepts: `ButtonHTMLAttributes<HTMLButtonElement>`.
1661
+
1662
+ | Prop | Type | Notes |
1663
+ | ---------- | -------------------- | ----- |
1664
+ | `children` | `ReactNode` | |
1665
+ | `icon?` | `IconName \| string` | |
1666
+ | `pressed?` | `boolean` | |
1667
+
1668
+ ### `Segment`
1669
+
1670
+ Compact view switcher (List / Board / Table) used above entity grids.
1671
+
1672
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>`.
1673
+
1674
+ | Prop | Type | Notes |
1675
+ | --------------- | ---------------------------- | ----- |
1676
+ | `'aria-label'?` | `string` | |
1677
+ | `block?` | `boolean` | |
1678
+ | `className?` | `string` | |
1679
+ | `defaultValue?` | `string` | |
1680
+ | `disabled?` | `boolean` | |
1681
+ | `onChange?` | `(value: string) => void` | |
1682
+ | `options` | `SegmentOption[]` | |
1683
+ | `orientation?` | `'horizontal' \| 'vertical'` | |
1684
+ | `value?` | `string` | |
1685
+
1686
+ ### `SegmentOption`
1687
+
1688
+ _Type._
1689
+
1690
+ <sub>`src/components/Select.tsx`</sub>
1691
+
1692
+ ### `MultiSelect`
1693
+
1694
+ Also accepts: `Omit< ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'defaultValue' | 'onChange' | 'children' | 'size' >`, `( | { labelInValue?: false; values?: string[]; defaultValues?: string[]; onChange?: (values: string[]) => void } | { labelInValue: true; values?: SelectLabelValue[]; defaultValues?: SelectLabelValue[]; onChange?: (values: SelectLabelValue[]) => void; } )`.
1695
+
1696
+ | Prop | Type | Notes |
1697
+ | -------------------- | --------------------------------------------------------------- | ----- |
1698
+ | `allowClear?` | `boolean` | |
1699
+ | `clearLabel?` | `string` | |
1700
+ | `defaultOpen?` | `boolean` | |
1701
+ | `error?` | `ReactNode` | |
1702
+ | `filterOption?` | `boolean \| ((query: string, option: SelectOption) => boolean)` | |
1703
+ | `filterSort?` | `(a: SelectOption, b: SelectOption) => number` | |
1704
+ | `invalid?` | `boolean` | |
1705
+ | `itemHeight?` | `number` | |
1706
+ | `label?` | `ReactNode` | |
1707
+ | `listHeight?` | `number` | |
1708
+ | `loading?` | `boolean` | |
1709
+ | `maxCount?` | `number` | |
1710
+ | `mode?` | `'multiple' \| 'tags'` | |
1711
+ | `notFoundContent?` | `ReactNode` | |
1712
+ | `onClear?` | `() => void` | |
1713
+ | `onOpenChange?` | `(open: boolean) => void` | |
1714
+ | `onSearch?` | `(query: string) => void` | |
1715
+ | `open?` | `boolean` | |
1716
+ | `optionRender?` | `(option: SelectOption, info: { index: number }) => ReactNode` | |
1717
+ | `options` | `(SelectOption \| SelectOptionGroup)[]` | |
1718
+ | `placeholder?` | `string` | |
1719
+ | `searchable?` | `boolean` | |
1720
+ | `searchPlaceholder?` | `string` | |
1721
+ | `searchValue?` | `string` | |
1722
+ | `size?` | `'md' \| 'lg'` | |
1723
+ | `tagRender?` | `(props: SelectTagRenderProps) => ReactNode` | |
1724
+ | `tokenSeparators?` | `string[]` | |
1725
+ | `virtual?` | `boolean` | |
1726
+
1727
+ ### `Select`
1728
+
1729
+ Also accepts: `Omit< ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'defaultValue' | 'onChange' | 'children' | 'size' >`, `( | { labelInValue?: false; allowClear?: false; value?: string | null; defaultValue?: string | null; onChange?: (value: string) => void; } | { labelInValue?: false; allowClear: true; value?: string | null; defaultValue?: string | null; onChange?: (value: string | null) => void; } | { labelInValue: true; allowClear?: boolean; value?: SelectLabelValue | null; defaultValue?: SelectLabelValue | null; onChange?: (value: SelectLabelValue | null) => void; } )`.
1730
+
1731
+ | Prop | Type | Notes |
1732
+ | -------------------- | --------------------------------------------------------------- | ----- |
1733
+ | `clearLabel?` | `string` | |
1734
+ | `defaultOpen?` | `boolean` | |
1735
+ | `error?` | `ReactNode` | |
1736
+ | `filterOption?` | `boolean \| ((query: string, option: SelectOption) => boolean)` | |
1737
+ | `filterSort?` | `(a: SelectOption, b: SelectOption) => number` | |
1738
+ | `invalid?` | `boolean` | |
1739
+ | `itemHeight?` | `number` | |
1740
+ | `labelRender?` | `(value: SelectLabelValue) => ReactNode` | |
1741
+ | `listHeight?` | `number` | |
1742
+ | `loading?` | `boolean` | |
1743
+ | `notFoundContent?` | `ReactNode` | |
1744
+ | `onClear?` | `() => void` | |
1745
+ | `onOpenChange?` | `(open: boolean) => void` | |
1746
+ | `onSearch?` | `(query: string) => void` | |
1747
+ | `open?` | `boolean` | |
1748
+ | `optionRender?` | `(option: SelectOption, info: { index: number }) => ReactNode` | |
1749
+ | `options` | `(SelectOption \| SelectOptionGroup)[]` | |
1750
+ | `placeholder?` | `string` | |
1751
+ | `searchable?` | `boolean` | |
1752
+ | `searchPlaceholder?` | `string` | |
1753
+ | `searchValue?` | `string` | |
1754
+ | `size?` | `'md' \| 'lg'` | |
1755
+ | `virtual?` | `boolean` | |
1756
+
1757
+ ### `SelectLabelValue`
1758
+
1759
+ _Type._
1760
+
1761
+ ### `SelectOption`
1762
+
1763
+ _Type._
1764
+
1765
+ ### `SelectOptionGroup`
1766
+
1767
+ _Type._
1768
+
1769
+ ### `useSelectAnchor`
1770
+
1771
+ Imperative helper used by toolbars that need "sorted by X" labels.
1772
+
1773
+ _No props type — see the source._
1774
+
1775
+ <sub>`src/components/SelectionBar.tsx`</sub>
1776
+
1777
+ ### `BulkActions`
1778
+
1779
+ The standard bulk commands, as data: the component builds the bar, the submenus, the round-robin spread and the messages; a page supplies the choices and the write.
1780
+
1781
+ _Type._
1782
+
1783
+ ### `SelectionBar`
1784
+
1785
+ "N selected" strip that stands in for the grid's header row while rows are selected: a select-all box, the count, a divider, the commands and Cancel.
1786
+
1787
+ | Prop | Type | Notes |
1788
+ | --------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
1789
+ | `actions?` | `Array<MenuItemSpec & { items?: MenuItemSpec[]; group?: string; groupIcon?: string }>` | Inline icon commands. An item may carry `items` to become a submenu. |
1790
+ | `allSelected?` | `boolean` | |
1791
+ | `clearLabel?` | `string` | The product labels this action "Cancel" while a selection is active. |
1792
+ | `count` | `number` | |
1793
+ | `disabled?` | `boolean` | |
1794
+ | `loading?` | `boolean` | Locks selection and commands while the host has a request in progress. |
1795
+ | `more?` | `MenuItemSpec[]` | |
1796
+ | `onClear` | `() => void` | |
1797
+ | `onError?` | `(error: unknown) => void` | |
1798
+ | `onToggleAll?` | `() => void` | |
1799
+ | `overlay?` | `boolean` | `false` puts the bar in the flow instead of over a header row (a board). |
1800
+ | `someSelected?` | `boolean` | Some, but not all: the bar's box reads the same as the header's did. |
1801
+ | `withPick?` | `boolean` | The grid has a 44px pick column: the bar's own box sits inside it. |
1802
+
1803
+ <sub>`src/components/Sidebar.tsx`</sub>
1804
+
1805
+ ### `Sidebar`
1806
+
1807
+ The category column that sits under the product header — 300px by default, the width measured on the live product.
1808
+
1809
+ Also accepts: `Omit<HTMLAttributes<HTMLElement>, 'title'>`.
1810
+
1811
+ | Prop | Type | Notes |
1812
+ | ---------------- | ------------------------- | ------------------------------------------------------------- |
1813
+ | `'aria-label'?` | `string` | |
1814
+ | `children` | `ReactNode` | |
1815
+ | `className?` | `string` | |
1816
+ | `collapsed?` | `boolean` | |
1817
+ | `defaultWidth?` | `number` | Width in px; the resizer clamps it to the token bounds. |
1818
+ | `footer?` | `ReactNode` | |
1819
+ | `maxWidth?` | `number` | |
1820
+ | `minWidth?` | `number` | |
1821
+ | `onWidthChange?` | `(width: number) => void` | |
1822
+ | `operations?` | `ReactNode` | Header controls — the product puts "add" and "collapse" here. |
1823
+ | `title` | `ReactNode` | |
1824
+ | `width?` | `number` | |
1825
+
1826
+ ### `SidebarCollapseProvider`
1827
+
1828
+ | Prop | Type | Notes |
1829
+ | ------------ | ----------- | ----- |
1830
+ | `children` | `ReactNode` | |
1831
+ | `collapsed?` | `boolean` | |
1832
+
1833
+ ### `useSidebarCollapsed`
1834
+
1835
+ The state the surrounding shell asked for, if it asked for anything.
1836
+
1837
+ _No props type — see the source._
1838
+
1839
+ <sub>`src/components/Slider.tsx`</sub>
1840
+
1841
+ ### `Slider`
1842
+
1843
+ Native ranges retain step rounding, keyboard interaction and form values.
1844
+
1845
+ | Prop | Type | Notes |
1846
+ | ----------- | ------------------------------------------------------ | ----- |
1847
+ | `marks?` | `SliderMarks` | |
1848
+ | `tooltip?` | `boolean \| { formatter?: (value: number) => string }` | |
1849
+ | `vertical?` | `boolean` | |
1850
+
1851
+ ### `SliderMarks`
1852
+
1853
+ _Type._
1854
+
1855
+ <sub>`src/components/Splitter.tsx`</sub>
1856
+
1857
+ ### `Splitter`
1858
+
1859
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
1860
+
1861
+ | Prop | Type | Notes |
1862
+ | ------------------ | ------------------------------------------------- | ----- |
1863
+ | `destroyOnHidden?` | `boolean` | |
1864
+ | `disabled?` | `boolean` | |
1865
+ | `onCollapse?` | `(collapsed: boolean[], sizes: number[]) => void` | |
1866
+ | `onResize?` | `(sizes: number[]) => void` | |
1867
+ | `onResizeEnd?` | `(sizes: number[]) => void` | |
1868
+ | `onResizeStart?` | `(sizes: number[]) => void` | |
1869
+ | `orientation?` | `'horizontal' \| 'vertical'` | |
1870
+
1871
+ <sub>`src/components/States.tsx`</sub>
1872
+
1873
+ ### `Banner`
1874
+
1875
+ | Prop | Type | Notes |
1876
+ | ---------- | --------------------------------- | ----- |
1877
+ | `action?` | `ReactNode` | |
1878
+ | `children` | `ReactNode` | |
1879
+ | `icon?` | `string` | |
1880
+ | `tone?` | `'warning' \| 'info' \| 'danger'` | |
1881
+
1882
+ ### `Empty`
1883
+
1884
+ General empty state; string images are URLs, React nodes allow custom art.
1885
+
1886
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'children'>`.
1887
+
1888
+ | Prop | Type | Notes |
1889
+ | -------------- | ----------- | ----- |
1890
+ | `children?` | `ReactNode` | |
1891
+ | `compact?` | `boolean` | |
1892
+ | `description?` | `ReactNode` | |
1893
+ | `image?` | `ReactNode` | |
1894
+
1895
+ ### `EmptyArt`
1896
+
1897
+ PingCode's empty illustration: the "no results" code card with a figure standing beside it.
1898
+
1899
+ | Prop | Type | Notes |
1900
+ | ------------ | --------------------------------- | ----- |
1901
+ | `className?` | `string` | |
1902
+ | `variant?` | `'empty' \| 'error' \| 'offline'` | |
1903
+
1904
+ ### `EmptyState`
1905
+
1906
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'title'>`.
1907
+
1908
+ | Prop | Type | Notes |
1909
+ | ------------ | --------------------------------- | ------------------------------------------------------------------ |
1910
+ | `action?` | `ReactNode` | |
1911
+ | `className?` | `string` | |
1912
+ | `compact?` | `boolean` | |
1913
+ | `hint?` | `ReactNode` | The "why" and "what now" — always render both when they are known. |
1914
+ | `title?` | `ReactNode` | |
1915
+ | `variant?` | `'empty' \| 'error' \| 'offline'` | What the operator sees when nothing came back. |
1916
+
1917
+ ### `ErrorState`
1918
+
1919
+ Error block that always answers: what happened / why / what to do now.
1920
+
1921
+ | Prop | Type | Notes |
1922
+ | ------------- | ------------ | ----- |
1923
+ | `action?` | `ReactNode` | |
1924
+ | `onRetry?` | `() => void` | |
1925
+ | `retryLabel?` | `string` | |
1926
+ | `what?` | `ReactNode` | |
1927
+ | `why?` | `ReactNode` | |
1928
+
1929
+ ### `InlineSpinner`
1930
+
1931
+ | Prop | Type | Notes |
1932
+ | -------- | -------- | ----- |
1933
+ | `label?` | `string` | |
1934
+
1935
+ ### `LoadingBlock`
1936
+
1937
+ | Prop | Type | Notes |
1938
+ | -------- | -------- | ----- |
1939
+ | `label?` | `string` | |
1940
+
1941
+ ### `Result`
1942
+
1943
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'title'>`.
1944
+
1945
+ | Prop | Type | Notes |
1946
+ | ----------- | --------------------------------------------------------------------------------------------- | ----- |
1947
+ | `extra?` | `ReactNode` | |
1948
+ | `icon?` | `ReactNode` | |
1949
+ | `status?` | `'success' \| 'error' \| 'info' \| 'warning' \| '403' \| '404' \| '500' \| 403 \| 404 \| 500` | |
1950
+ | `subTitle?` | `ReactNode` | |
1951
+ | `title?` | `ReactNode` | |
1952
+
1953
+ ### `Skeleton`
1954
+
1955
+ | Prop | Type | Notes |
1956
+ | ------------ | -------------------------------------------------------------------------------- | ----- |
1957
+ | `active?` | `boolean` | |
1958
+ | `avatar?` | `boolean` | |
1959
+ | `children?` | `ReactNode` | |
1960
+ | `className?` | `string` | |
1961
+ | `height?` | `number \| string` | |
1962
+ | `loading?` | `boolean` | |
1963
+ | `paragraph?` | `boolean \| { rows?: number; width?: number \| string \| (number \| string)[] }` | |
1964
+ | `radius?` | `number` | |
1965
+ | `title?` | `boolean` | |
1966
+ | `width?` | `number \| string` | |
1967
+
1968
+ ### `Spin`
1969
+
1970
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'children'>`.
1971
+
1972
+ | Prop | Type | Notes |
1973
+ | -------------- | -------------------------------- | ----- |
1974
+ | `children?` | `ReactNode` | |
1975
+ | `delay?` | `number` | |
1976
+ | `description?` | `ReactNode` | |
1977
+ | `fullscreen?` | `boolean` | |
1978
+ | `indicator?` | `ReactNode` | |
1979
+ | `size?` | `'small' \| 'medium' \| 'large'` | |
1980
+ | `spinning?` | `boolean` | |
1981
+
1982
+ ### `TableSkeleton`
1983
+
1984
+ Row skeletons matching the 45px grid rhythm, so loading doesn't jump.
1985
+
1986
+ | Prop | Type | Notes |
1987
+ | ---------- | ---------- | ----- |
1988
+ | `columns?` | `number[]` | |
1989
+ | `rows?` | `number` | |
1990
+
1991
+ <sub>`src/components/Statistic.tsx`</sub>
1992
+
1993
+ ### `Statistic`
1994
+
1995
+ Formatted headline value, preserving string digits without coercing large integers.
1996
+
1997
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'prefix'>`.
1998
+
1999
+ | Prop | Type | Notes |
2000
+ | ------------------- | ---------------------------------------- | ----- |
2001
+ | `decimalSeparator?` | `string` | |
2002
+ | `formatter?` | `(value: number \| string) => ReactNode` | |
2003
+ | `groupSeparator?` | `string` | |
2004
+ | `loading?` | `boolean` | |
2005
+ | `precision?` | `number` | |
2006
+ | `prefix?` | `ReactNode` | |
2007
+ | `suffix?` | `ReactNode` | |
2008
+ | `title?` | `ReactNode` | |
2009
+ | `value?` | `number \| string` | |
2010
+ | `valueStyle?` | `CSSProperties` | |
2011
+
2012
+ <sub>`src/components/Steps.tsx`</sub>
2013
+
2014
+ ### `Steps`
2015
+
2016
+ | Prop | Type | Notes |
2017
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
2018
+ | `'aria-label'` | `string` | |
2019
+ | `className?` | `string` | |
2020
+ | `current?` | `number` | Active step number (offset by initial); initial + items.length marks all steps complete. |
2021
+ | `disabled?` | `boolean` | |
2022
+ | `initial?` | `number` | |
2023
+ | `items` | `Array<{ key: string; title: ReactNode; description?: ReactNode; disabled?: boolean; status?: 'wait' \| 'process' \| 'finish' \| 'error'; icon?: ReactNode; subTitle?: ReactNode; }>` | |
2024
+ | `onChange?` | `(index: number) => void` | Optional step navigation; without it the steps are a read-only list. |
2025
+ | `orientation?` | `'horizontal' \| 'vertical'` | |
2026
+ | `status?` | `'wait' \| 'process' \| 'finish' \| 'error'` | |
2027
+
2028
+ <sub>`src/components/Switch.tsx`</sub>
2029
+
2030
+ ### `Switch`
2031
+
2032
+ PingCode's 36×20 primary switch (20×16 in the sidebar footer's small form).
2033
+
2034
+ Also accepts: `Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'size'>`.
2035
+
2036
+ | Prop | Type | Notes |
2037
+ | -------------------- | -------------- | ----- |
2038
+ | `checkedChildren?` | `ReactNode` | |
2039
+ | `label` | `string` | |
2040
+ | `loading?` | `boolean` | |
2041
+ | `size?` | `'sm' \| 'md'` | |
2042
+ | `unCheckedChildren?` | `ReactNode` | |
2043
+
2044
+ <sub>`src/components/table/DataTable.tsx`</sub>
2045
+
2046
+ ### `DataTable`
2047
+
2048
+ The entity grid shared by every Ship tab: hover checkboxes, a row-number column, sortable headers, optional group headers and per-row actions.
2049
+
2050
+ | Prop | Type | Notes |
2051
+ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2052
+ | `ariaLabel?` | `string` | |
2053
+ | `bulk?` | `BulkActions` | What the selection bar offers while rows are selected. The bar, its submenus, the round-robin spread and the messages are the table's; the host supplies the choices and the write. |
2054
+ | `bulkActions?` | `(keys: string[]) => MenuItemSpec[]` | Extra commands appended after the standard ones. |
2055
+ | `className?` | `string` | |
2056
+ | `columns` | `Array<ColumnDefinition<T>>` | |
2057
+ | `cursor?` | `boolean` | The product's cursor: the grid is **one** tab stop, its unit is the **cell** — ← → walk the columns, ↑ ↓ walk the rows, Home / End jump to the ends of the row, Enter opens the record and Space toggles its selection when the host can write one. Focus rides with the cursor. A key a widget inside the cell owns (an editor, a button, a link) stays with it. Without a cursor every row that has an `onRowClick` is its own tab stop — fine for three rows, 16 presses at 16. |
2058
+ | `defaultExpandedGroups?` | `string[]` | |
2059
+ | `defaultExpandedRowKeys?` | `string[]` | |
2060
+ | `defaultFilters?` | `Record<string, string[]>` | |
2061
+ | `defaultSort?` | `SortState` | |
2062
+ | `defaultSorts?` | `Exclude<SortState, null>[]` | |
2063
+ | `density?` | `'default' \| 'compact'` | `compact` is the 36px row the product uses where space is tight (a preview panel, a comparison table). It also reserves the actions column instead of floating the commands over the last data column. |
2064
+ | `disabled?` | `boolean` | |
2065
+ | `emptyState?` | `ReactNode` | |
2066
+ | `errorState?` | `ReactNode` | |
2067
+ | `expandedGroups?` | `string[]` | Which group headers are open. Uncontrolled (every group open) unless `expandedGroups` is given; `onExpandedGroupsChange` reports every toggle. |
2068
+ | `expandedRowKeys?` | `string[]` | |
2069
+ | `expandedRowRender?` | `(row: T, index: number) => ReactNode` | |
2070
+ | `filters?` | `Record<string, string[]>` | |
2071
+ | `footer?` | `ReactNode` | |
2072
+ | `getChildren?` | `(row: T) => T[] \| undefined` | Opt into hierarchical rows; root records are paginated before expansion. |
2073
+ | `groupBy?` | `(row: T) => string` | Renders collapsible group headers; rows keep their original order. |
2074
+ | `headerTools?` | `ReactNode` | Rendered in a trailing sticky header cell — the product puts its column settings gear there. |
2075
+ | `indentSize?` | `number` | |
2076
+ | `isRowSelectable?` | `(row: T) => boolean` | |
2077
+ | `loadingColumns?` | `Array<number \| string>` | |
2078
+ | `loadingRows?` | `number` | |
2079
+ | `onChange?` | `(change: TableChange<T>) => void` | |
2080
+ | `onColumnCommand?` | `(command: ColumnCommand) => void` | Renders the ⋯ menu in every data column's header and reports what it asked for: sort, move left/right, insert left/right, freeze/unfreeze, remove. Nothing happens inside the table — the host applies it to `columns`. |
2081
+ | `onDelete?` | `(keys: string[]) => void` | |
2082
+ | `onEditProperties?` | `() => void` | Opens whatever dialog the host uses to edit the selection's properties. |
2083
+ | `onExpandedGroupsChange?` | `(labels: string[]) => void` | |
2084
+ | `onExpandedRowKeysChange?` | `(keys: string[]) => void` | |
2085
+ | `onExportSelection?` | `(keys: string[]) => void` | The bar's "More" entries: the host writes the CSV, the host deletes. |
2086
+ | `onFiltersChange?` | `(filters: Record<string, string[]>) => void` | |
2087
+ | `onNotify?` | `(message: string) => void` | Where the bar's confirmations go; the library raises no toasts of its own. |
2088
+ | `onRowClick?` | `(row: T) => void` | |
2089
+ | `onSelectedKeysChange?` | `(keys: string[]) => void` | |
2090
+ | `onSortChange?` | `(sort: SortState) => void` | |
2091
+ | `onSortsChange?` | `(sorts: Exclude<SortState, null>[]) => void` | |
2092
+ | `pagination?` | `Omit<PaginationProps, 'className'> & Required<Pick<PaginationProps, 'page' \| 'pageSize' \| 'onPageChange'>> & { mode?: 'local' \| 'remote' }` | Local slicing by default; remote mode expects already paged rows. |
2093
+ | `rowActions?` | `(row: T) => ReactNode` | |
2094
+ | `rowClassName?` | `(row: T, index: number) => string` | |
2095
+ | `rowContextMenu?` | `(row: T) => ContextMenuItem[]` | Right-click commands for a row. The same commands must also exist in `rowActions` — a context menu is never the only entry point. |
2096
+ | `rowExpandable?` | `(row: T) => boolean` | |
2097
+ | `rowKey` | `(row: T) => string` | |
2098
+ | `rows` | `T[]` | |
2099
+ | `scroll?` | `{ x?: number \| string; y?: number \| string }` | |
2100
+ | `selectable?` | `boolean` | |
2101
+ | `selectedKeys?` | `string[]` | |
2102
+ | `selectionMode?` | `'multiple' \| 'single'` | |
2103
+ | `selectionNoun?` | `BulkNoun` | How the bar names its rows, e.g. `{ one: 'idea', many: 'ideas' }`. |
2104
+ | `showHeader?` | `boolean` | |
2105
+ | `showIndex?` | `boolean` | Row numbers, exactly as the product prints them in the `#` column. |
2106
+ | `sort?` | `SortState` | |
2107
+ | `sorts?` | `Exclude<SortState, null>[]` | |
2108
+ | `status?` | `'loading' \| 'error' \| 'ready'` | The five states: loading / error / empty / populated / edge. |
2109
+ | `stickyHeader?` | `boolean` | |
2110
+ | `summary?` | `(rows: T[]) => ReactNode` | Render summary cells/rows here; the component supplies tfoot. |
2111
+ | `title?` | `ReactNode` | |
2112
+ | `virtual?` | `boolean \| { rowHeight?: number; overscan?: number }` | Fixed-height windowing. Spanning cells, groups and expanded detail rows use the full body. |
2113
+
2114
+ <sub>`src/components/table/types.ts`</sub>
2115
+
2116
+ ### `CellAction`
2117
+
2118
+ One command that lives _inside_ a cell and appears while the pointer is on it — the product's copy-the-identifier and quick-edit affordances.
2119
+
2120
+ _Type._
2121
+
2122
+ ### `Column`
2123
+
2124
+ _Type._
2125
+
2126
+ ### `ColumnCommand`
2127
+
2128
+ What the header's ⋯ menu asks the host to do.
2129
+
2130
+ _Type._
2131
+
2132
+ ### `ColumnDefinition`
2133
+
2134
+ _Type._
2135
+
2136
+ ### `ColumnGroup`
2137
+
2138
+ _Type._
2139
+
2140
+ ### `SortState`
2141
+
2142
+ _Type._
2143
+
2144
+ ### `TableChange`
2145
+
2146
+ _Type._
2147
+
2148
+ <sub>`src/components/Tabs.tsx`</sub>
2149
+
2150
+ ### `TabItem`
2151
+
2152
+ _Type._
2153
+
2154
+ ### `Tabs`
2155
+
2156
+ Content tabs with automatic activation and a single roving tab stop.
2157
+
2158
+ | Prop | Type | Notes |
2159
+ | ------------------- | --------------------------------------------------- | ------------------------------------------------- |
2160
+ | `'aria-label'` | `string` | |
2161
+ | `activeKey?` | `string` | |
2162
+ | `className?` | `string` | |
2163
+ | `defaultActiveKey?` | `string` | |
2164
+ | `disabled?` | `boolean` | |
2165
+ | `extra?` | `ReactNode` | |
2166
+ | `hideAdd?` | `boolean` | |
2167
+ | `items` | `TabItem[]` | |
2168
+ | `keepMounted?` | `boolean` | Preserve mounted panel state when switching tabs. |
2169
+ | `onChange?` | `(key: string) => void` | |
2170
+ | `onEdit?` | `(action: 'add' \| 'remove', key?: string) => void` | |
2171
+ | `placement?` | `'top' \| 'bottom' \| 'start' \| 'end'` | |
2172
+ | `type?` | `'line' \| 'card' \| 'editable-card'` | |
2173
+
2174
+ <sub>`src/components/Tag.tsx`</sub>
2175
+
2176
+ ### `CountTag`
2177
+
2178
+ | Prop | Type | Notes |
2179
+ | ------- | ----------------------- | ----- |
2180
+ | `count` | `number` | |
2181
+ | `tone?` | `'neutral' \| 'accent'` | |
2182
+
2183
+ ### `LevelTag`
2184
+
2185
+ | Prop | Type | Notes |
2186
+ | ------------ | -------- | ----- |
2187
+ | `className?` | `string` | |
2188
+ | `level` | `string` | |
2189
+
2190
+ ### `statusColor`
2191
+
2192
+ _No props type — see the source._
2193
+
2194
+ ### `StatusTag`
2195
+
2196
+ | Prop | Type | Notes |
2197
+ | ------------ | ----------- | ----- |
2198
+ | `className?` | `string` | |
2199
+ | `label?` | `ReactNode` | |
2200
+ | `status` | `string` | |
2201
+
2202
+ ### `Tag`
2203
+
2204
+ Also accepts: `Omit<HTMLAttributes<HTMLSpanElement>, 'onChange'>`.
2205
+
2206
+ | Prop | Type | Notes |
2207
+ | ----------------- | ------------------------------------------------ | -------------------------------------------------------------------- |
2208
+ | `checkable?` | `boolean` | |
2209
+ | `checked?` | `boolean` | |
2210
+ | `children` | `ReactNode` | |
2211
+ | `className?` | `string` | |
2212
+ | `closable?` | `boolean` | |
2213
+ | `closeLabel?` | `string` | |
2214
+ | `color?` | `string` | Explicit colour; defaults to the neutral surface. |
2215
+ | `defaultChecked?` | `boolean` | |
2216
+ | `disabled?` | `boolean` | |
2217
+ | `icon?` | `ReactNode` | |
2218
+ | `onChange?` | `(checked: boolean) => void` | |
2219
+ | `onClose?` | `(event: MouseEvent<HTMLButtonElement>) => void` | |
2220
+ | `pill?` | `boolean` | The fully-rounded shape. The default is the button's radius. |
2221
+ | `size?` | `'md' \| 'sm'` | `sm` is the 22px chip the property strips print. |
2222
+ | `title?` | `string` | |
2223
+ | `tone?` | `'neutral' \| 'accent'` | The neutral surface, or the accent wash a classifying chip uses. |
2224
+ | `variant?` | `'solid' \| 'soft' \| 'outline'` | Solid pills carry state (status, level); soft/outline tags classify. |
2225
+
2226
+ <sub>`src/components/Timeline.tsx`</sub>
2227
+
2228
+ ### `Timeline`
2229
+
2230
+ A semantic chronological list; hosts own timestamps and activity meanings.
2231
+
2232
+ Also accepts: `HTMLAttributes<HTMLOListElement>`.
2233
+
2234
+ | Prop | Type | Notes |
2235
+ | -------------- | ------------------------------------------------------ | ----- |
2236
+ | `items?` | `TimelineItem[]` | |
2237
+ | `mode?` | `'start' \| 'end' \| 'alternate' \| 'left' \| 'right'` | |
2238
+ | `orientation?` | `'vertical' \| 'horizontal'` | |
2239
+ | `pending?` | `ReactNode` | |
2240
+ | `pendingDot?` | `ReactNode` | |
2241
+ | `reverse?` | `boolean` | |
2242
+
2243
+ <sub>`src/components/TimePicker.tsx`</sub>
2244
+
2245
+ ### `TimePicker`
2246
+
2247
+ Native accessible clock picker with Form/config integration and validation.
2248
+
2249
+ Also accepts: `Omit< InputProps, 'type' | 'value' | 'defaultValue' | 'onChange' | 'step' | 'min' | 'max' >`.
2250
+
2251
+ | Prop | Type | Notes |
2252
+ | --------------- | ---------------------------- | -------------------------------------------------------------------------------- |
2253
+ | `defaultValue?` | `string` | |
2254
+ | `disabledTime?` | `(value: string) => boolean` | |
2255
+ | `max?` | `string` | |
2256
+ | `min?` | `string` | |
2257
+ | `onChange?` | `(value: string) => void` | |
2258
+ | `step?` | `number` | Seconds between native choices; 60 by default, use 1 to expose seconds. |
2259
+ | `value?` | `string` | Local clock time HH:mm or HH:mm:ss; no timezone conversion. Empty string clears. |
2260
+
2261
+ <sub>`src/components/Toast.tsx`</sub>
2262
+
2263
+ ### `ToastAction`
2264
+
2265
+ _Type._
2266
+
2267
+ ### `ToastPlacement`
2268
+
2269
+ Where the stack is pinned: the six corners and edges of the viewport.
2270
+
2271
+ _Type._
2272
+
2273
+ ### `ToastProvider`
2274
+
2275
+ Toast host: a single live region that exists before any content arrives.
2276
+
2277
+ | Prop | Type | Notes |
2278
+ | ------------ | ---------------- | --------------------------------------------------------------------- |
2279
+ | `children` | `ReactNode` | |
2280
+ | `className?` | `string` | |
2281
+ | `max?` | `number` | Caps the stack; the oldest toast leaves first. Unlimited by default. |
2282
+ | `placement?` | `ToastPlacement` | Default `top-center`, which is where the product raises its messages. |
2283
+
2284
+ ### `ToastSpec`
2285
+
2286
+ _Type._
2287
+
2288
+ ### `ToastTone`
2289
+
2290
+ _Type._
2291
+
2292
+ ### `ToastVariant`
2293
+
2294
+ `surface` is the white card the product raises (a toned hairline and icon); `filled` puts the same message on the tone's own colour, for a host that wants the confirmation to be unmissable.
2295
+
2296
+ _Type._
2297
+
2298
+ ### `useToast`
2299
+
2300
+ _No props type — see the source._
2301
+
2302
+ <sub>`src/components/Tooltip.tsx`</sub>
2303
+
2304
+ ### `Tooltip`
2305
+
2306
+ Lightweight text tooltip; the anchor keeps its own semantics.
2307
+
2308
+ | Prop | Type | Notes |
2309
+ | ------------ | ------------------- | ------------------------------------------------------------------------- |
2310
+ | `children` | `ReactNode` | |
2311
+ | `delay?` | `number` | Milliseconds before the tooltip appears; keyboard focus shows it at once. |
2312
+ | `label` | `ReactNode` | |
2313
+ | `placement?` | `'top' \| 'bottom'` | |
2314
+
2315
+ <sub>`src/components/Tour.tsx`</sub>
2316
+
2317
+ ### `Tour`
2318
+
2319
+ | Prop | Type | Notes |
2320
+ | ------------------------ | ----------------------------------------------------------------------------- | ----- |
2321
+ | `actionsRender?` | `(actions: ReactNode, info: { current: number; total: number }) => ReactNode` | |
2322
+ | `className?` | `string` | |
2323
+ | `closable?` | `boolean` | |
2324
+ | `current?` | `number` | |
2325
+ | `defaultCurrent?` | `number` | |
2326
+ | `defaultOpen?` | `boolean` | |
2327
+ | `disabled?` | `boolean` | |
2328
+ | `gap?` | `number` | |
2329
+ | `indicatorsRender?` | `(current: number, total: number) => ReactNode` | |
2330
+ | `keyboard?` | `boolean` | |
2331
+ | `mask?` | `boolean` | |
2332
+ | `maskColor?` | `string` | |
2333
+ | `onChange?` | `(current: number) => void` | |
2334
+ | `onClose?` | `(current: number) => void` | |
2335
+ | `onFinish?` | `() => void` | |
2336
+ | `onOpenChange?` | `(open: boolean) => void` | |
2337
+ | `open?` | `boolean` | |
2338
+ | `placement?` | `TourStep['placement']` | |
2339
+ | `scrollIntoViewOptions?` | `false \| ScrollIntoViewOptions` | |
2340
+ | `steps` | `TourStep[]` | |
2341
+ | `style?` | `CSSProperties` | |
2342
+ | `type?` | `'default' \| 'primary'` | |
2343
+
2344
+ ### `TourStep`
2345
+
2346
+ _Type._
2347
+
2348
+ <sub>`src/components/Transfer.tsx`</sub>
2349
+
2350
+ ### `Transfer`
2351
+
2352
+ Both selection states remain host-owned when controlled; moves preserve unknown targets.
2353
+
2354
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'children'>`.
2355
+
2356
+ | Prop | Type | Notes |
2357
+ | ---------------------- | ----------------------------------------------------------------------------------------- | ----- |
2358
+ | `'aria-label'` | `string` | |
2359
+ | `children?` | `(props: TransferListProps) => ReactNode` | |
2360
+ | `defaultSelectedKeys?` | `string[]` | |
2361
+ | `defaultTargetKeys?` | `string[]` | |
2362
+ | `disabled?` | `boolean` | |
2363
+ | `emptyState?` | `ReactNode` | |
2364
+ | `errorState?` | `ReactNode` | |
2365
+ | `filterOption?` | `(query: string, item: TransferItem, direction: TransferDirection) => boolean` | |
2366
+ | `footer?` | `(props: TransferListProps) => ReactNode` | |
2367
+ | `items` | `TransferItem[]` | |
2368
+ | `onChange?` | `(keys: string[], direction: TransferDirection, moveKeys: string[]) => void` | |
2369
+ | `onSearch?` | `(direction: TransferDirection, query: string) => void` | |
2370
+ | `onSelectChange?` | `(sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void` | |
2371
+ | `pagination?` | `boolean \| { pageSize?: number; showSizeChanger?: boolean; pageSizeOptions?: number[] }` | |
2372
+ | `render?` | `(item: TransferItem) => ReactNode` | |
2373
+ | `searchable?` | `boolean` | |
2374
+ | `selectedKeys?` | `string[]` | |
2375
+ | `showSelectAll?` | `boolean` | |
2376
+ | `status?` | `'ready' \| 'loading' \| 'error'` | |
2377
+ | `targetKeys?` | `string[]` | |
2378
+ | `titles?` | `[string, string]` | |
2379
+
2380
+ ### `TransferDirection`
2381
+
2382
+ _Type._
2383
+
2384
+ ### `TransferItem`
2385
+
2386
+ _Type._
2387
+
2388
+ <sub>`src/components/Tree.tsx`</sub>
2389
+
2390
+ ### `DirectoryTree`
2391
+
2392
+ File-browser selection with Ctrl/Meta toggles and Shift ranges.
2393
+
2394
+ | Prop | Type | Notes |
2395
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------ |
2396
+ | `'aria-label'?` | `string` | |
2397
+ | `allowDrop?` | `(info: { dropNode: TreeNode \| null; dragNode: TreeNode; dropPosition: -1 \| 0 \| 1 }) => boolean` | |
2398
+ | `autoExpandParent?` | `boolean` | |
2399
+ | `blockNode?` | `boolean` | |
2400
+ | `checkable?` | `boolean` | |
2401
+ | `checkedKeys?` | `TreeCheckedKeys` | |
2402
+ | `checkStrictly?` | `boolean` | |
2403
+ | `className?` | `string` | |
2404
+ | `classNames?` | `Partial<Record<TreeSemantic, string>>` | |
2405
+ | `defaultCheckedKeys?` | `string[]` | |
2406
+ | `defaultExpandAll?` | `boolean` | |
2407
+ | `defaultExpanded?` | `string[]` | |
2408
+ | `defaultExpandedKeys?` | `string[]` | |
2409
+ | `defaultExpandParent?` | `boolean` | |
2410
+ | `defaultLoadedKeys?` | `string[]` | |
2411
+ | `defaultSelectedKeys?` | `string[]` | |
2412
+ | `disabled?` | `boolean` | |
2413
+ | `draggable?` | `boolean \| ((node: TreeNode) => boolean) \| { icon?: ReactNode \| false; nodeDraggable?: (node: TreeNode) => boolean }` | |
2414
+ | `expandAction?` | `false \| 'click' \| 'doubleClick'` | Directory behavior; the regular Tree expands from its caret by default. |
2415
+ | `expandedKeys?` | `string[]` | |
2416
+ | `fieldNames?` | `{ key?: string; title?: string; children?: string }` | |
2417
+ | `filterTreeNode?` | `(node: TreeNode) => boolean` | |
2418
+ | `height?` | `number` | Fixed row height virtualization; virtual defaults on when height is set. |
2419
+ | `icon?` | `ReactNode \| ((state: TreeNodeState) => ReactNode)` | |
2420
+ | `indent?` | `number` | |
2421
+ | `itemHeight?` | `number` | |
2422
+ | `loadData?` | `(node: TreeNode) => Promise<TreeNode[] \| void>` | May return children, or update host-owned data and resolve void. |
2423
+ | `loadedKeys?` | `string[]` | |
2424
+ | `motion?` | `boolean` | CSS transitions; false disables them (reduced motion is respected). |
2425
+ | `movable?` | `(node: TreeNode) => boolean` | |
2426
+ | `multiple?` | `boolean` | |
2427
+ | `nodeActions?` | `(node: TreeNode) => ReactNode` | |
2428
+ | `nodeContextMenu?` | `(node: TreeNode) => ContextMenuItem[]` | |
2429
+ | `nodes?` | `TreeNode[]` | Existing Klun data contract. Use either nodes or treeData. |
2430
+ | `onCheck?` | `(keys: TreeCheckedKeys, info: TreeCheckInfo) => void` | |
2431
+ | `onDoubleClick?` | `(event: MouseEvent, node: TreeNode) => void` | |
2432
+ | `onDragEnd?` | `(info: TreeDragInfo) => void` | |
2433
+ | `onDragEnter?` | `(info: TreeDragInfo & { expandedKeys: string[] }) => void` | |
2434
+ | `onDragLeave?` | `(info: TreeDragInfo) => void` | |
2435
+ | `onDragOver?` | `(info: TreeDragInfo) => void` | |
2436
+ | `onDragStart?` | `(info: TreeDragInfo) => void` | |
2437
+ | `onDrop?` | `(info: TreeDropInfo) => void` | |
2438
+ | `onExpand?` | `(keys: string[], info: { expanded: boolean; node: TreeNode }) => void` | |
2439
+ | `onLoad?` | `(keys: string[], info: { node: TreeNode }) => void` | |
2440
+ | `onLoadError?` | `(error: unknown, node: TreeNode) => void` | |
2441
+ | `onMove?` | `TreeMoveHandler` | |
2442
+ | `onRightClick?` | `(info: { event: MouseEvent; node: TreeNode }) => void` | |
2443
+ | `onSelect?` | `(node: TreeNode) => void` | |
2444
+ | `onSelectionChange?` | `(keys: string[], info: TreeSelectionInfo) => void` | |
2445
+ | `searchValue?` | `string` | Highlights matches and reveals ancestors without discarding nodes. |
2446
+ | `selectable?` | `boolean` | |
2447
+ | `selectedKeys?` | `string[]` | |
2448
+ | `showIcon?` | `boolean` | |
2449
+ | `showLine?` | `boolean \| { showLeafIcon?: ReactNode \| ((state: TreeNodeState) => ReactNode) }` | |
2450
+ | `style?` | `CSSProperties` | |
2451
+ | `styles?` | `Partial<Record<TreeSemantic, CSSProperties>>` | |
2452
+ | `switcherIcon?` | `ReactNode \| ((state: TreeNodeState) => ReactNode)` | |
2453
+ | `switcherLoadingIcon?` | `ReactNode` | |
2454
+ | `titleRender?` | `(node: TreeNode) => ReactNode` | |
2455
+ | `treeData?` | `TreeDataNode[] \| Record<string, unknown>[]` | |
2456
+ | `value?` | `string \| null` | Legacy route selection and callback remain compatible. |
2457
+ | `virtual?` | `boolean` | |
2458
+
2459
+ ### `Tree`
2460
+
2461
+ | Prop | Type | Notes |
2462
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------ |
2463
+ | `'aria-label'?` | `string` | |
2464
+ | `allowDrop?` | `(info: { dropNode: TreeNode \| null; dragNode: TreeNode; dropPosition: -1 \| 0 \| 1 }) => boolean` | |
2465
+ | `autoExpandParent?` | `boolean` | |
2466
+ | `blockNode?` | `boolean` | |
2467
+ | `checkable?` | `boolean` | |
2468
+ | `checkedKeys?` | `TreeCheckedKeys` | |
2469
+ | `checkStrictly?` | `boolean` | |
2470
+ | `className?` | `string` | |
2471
+ | `classNames?` | `Partial<Record<TreeSemantic, string>>` | |
2472
+ | `defaultCheckedKeys?` | `string[]` | |
2473
+ | `defaultExpandAll?` | `boolean` | |
2474
+ | `defaultExpanded?` | `string[]` | |
2475
+ | `defaultExpandedKeys?` | `string[]` | |
2476
+ | `defaultExpandParent?` | `boolean` | |
2477
+ | `defaultLoadedKeys?` | `string[]` | |
2478
+ | `defaultSelectedKeys?` | `string[]` | |
2479
+ | `disabled?` | `boolean` | |
2480
+ | `draggable?` | `boolean \| ((node: TreeNode) => boolean) \| { icon?: ReactNode \| false; nodeDraggable?: (node: TreeNode) => boolean }` | |
2481
+ | `expandAction?` | `false \| 'click' \| 'doubleClick'` | Directory behavior; the regular Tree expands from its caret by default. |
2482
+ | `expandedKeys?` | `string[]` | |
2483
+ | `fieldNames?` | `{ key?: string; title?: string; children?: string }` | |
2484
+ | `filterTreeNode?` | `(node: TreeNode) => boolean` | |
2485
+ | `height?` | `number` | Fixed row height virtualization; virtual defaults on when height is set. |
2486
+ | `icon?` | `ReactNode \| ((state: TreeNodeState) => ReactNode)` | |
2487
+ | `indent?` | `number` | |
2488
+ | `itemHeight?` | `number` | |
2489
+ | `loadData?` | `(node: TreeNode) => Promise<TreeNode[] \| void>` | May return children, or update host-owned data and resolve void. |
2490
+ | `loadedKeys?` | `string[]` | |
2491
+ | `motion?` | `boolean` | CSS transitions; false disables them (reduced motion is respected). |
2492
+ | `movable?` | `(node: TreeNode) => boolean` | |
2493
+ | `multiple?` | `boolean` | |
2494
+ | `nodeActions?` | `(node: TreeNode) => ReactNode` | |
2495
+ | `nodeContextMenu?` | `(node: TreeNode) => ContextMenuItem[]` | |
2496
+ | `nodes?` | `TreeNode[]` | Existing Klun data contract. Use either nodes or treeData. |
2497
+ | `onCheck?` | `(keys: TreeCheckedKeys, info: TreeCheckInfo) => void` | |
2498
+ | `onDoubleClick?` | `(event: MouseEvent, node: TreeNode) => void` | |
2499
+ | `onDragEnd?` | `(info: TreeDragInfo) => void` | |
2500
+ | `onDragEnter?` | `(info: TreeDragInfo & { expandedKeys: string[] }) => void` | |
2501
+ | `onDragLeave?` | `(info: TreeDragInfo) => void` | |
2502
+ | `onDragOver?` | `(info: TreeDragInfo) => void` | |
2503
+ | `onDragStart?` | `(info: TreeDragInfo) => void` | |
2504
+ | `onDrop?` | `(info: TreeDropInfo) => void` | |
2505
+ | `onExpand?` | `(keys: string[], info: { expanded: boolean; node: TreeNode }) => void` | |
2506
+ | `onLoad?` | `(keys: string[], info: { node: TreeNode }) => void` | |
2507
+ | `onLoadError?` | `(error: unknown, node: TreeNode) => void` | |
2508
+ | `onMove?` | `TreeMoveHandler` | |
2509
+ | `onRightClick?` | `(info: { event: MouseEvent; node: TreeNode }) => void` | |
2510
+ | `onSelect?` | `(node: TreeNode) => void` | |
2511
+ | `onSelectionChange?` | `(keys: string[], info: TreeSelectionInfo) => void` | |
2512
+ | `searchValue?` | `string` | Highlights matches and reveals ancestors without discarding nodes. |
2513
+ | `selectable?` | `boolean` | |
2514
+ | `selectedKeys?` | `string[]` | |
2515
+ | `showIcon?` | `boolean` | |
2516
+ | `showLine?` | `boolean \| { showLeafIcon?: ReactNode \| ((state: TreeNodeState) => ReactNode) }` | |
2517
+ | `style?` | `CSSProperties` | |
2518
+ | `styles?` | `Partial<Record<TreeSemantic, CSSProperties>>` | |
2519
+ | `switcherIcon?` | `ReactNode \| ((state: TreeNodeState) => ReactNode)` | |
2520
+ | `switcherLoadingIcon?` | `ReactNode` | |
2521
+ | `titleRender?` | `(node: TreeNode) => ReactNode` | |
2522
+ | `treeData?` | `TreeDataNode[] \| Record<string, unknown>[]` | |
2523
+ | `value?` | `string \| null` | Legacy route selection and callback remain compatible. |
2524
+ | `virtual?` | `boolean` | |
2525
+
2526
+ ### `TreeCheckedKeys`
2527
+
2528
+ _Type._
2529
+
2530
+ ### `TreeCheckInfo`
2531
+
2532
+ _Type._
2533
+
2534
+ ### `TreeDataNode`
2535
+
2536
+ _Type._
2537
+
2538
+ ### `TreeDragInfo`
2539
+
2540
+ _Type._
2541
+
2542
+ ### `TreeDropInfo`
2543
+
2544
+ _Type._
2545
+
2546
+ ### `TreeGroup`
2547
+
2548
+ Small caps section label between tree groups.
2549
+
2550
+ | Prop | Type | Notes |
2551
+ | --------- | ----------- | ----- |
2552
+ | `action?` | `ReactNode` | |
2553
+ | `label` | `ReactNode` | |
2554
+
2555
+ ### `TreeMoveHandler`
2556
+
2557
+ _Type._
2558
+
2559
+ ### `TreeMovePosition`
2560
+
2561
+ _Type._
2562
+
2563
+ ### `TreeNode`
2564
+
2565
+ _Type._
2566
+
2567
+ ### `TreeNodeState`
2568
+
2569
+ _Type._
2570
+
2571
+ ### `TreeRef`
2572
+
2573
+ _Type._
2574
+
2575
+ ### `TreeSelectionInfo`
2576
+
2577
+ _Type._
2578
+
2579
+ ### `TreeSemantic`
2580
+
2581
+ _Type._
2582
+
2583
+ <sub>`src/components/TreeSelect.tsx`</sub>
2584
+
2585
+ ### `TreeSelect`
2586
+
2587
+ Hierarchical selection reuses Tree's check conduction, keyboard and lazy loading.
2588
+
2589
+ Also accepts: `AriaAttributes`, `( | { multiple?: false; treeCheckable?: false; value?: string | null; defaultValue?: string | null; onChange?: (value: string | null, labels: ReactNode[]) => void; } | { multiple: true; value?: string[]; defaultValue?: string[]; onChange?: (value: string[], labels: ReactNode[]) => void; } | { treeCheckable: true; multiple?: boolean; value?: string[]; defaultValue?: string[]; onChange?: (value: string[], labels: ReactNode[]) => void; } )`.
2590
+
2591
+ | Prop | Type | Notes |
2592
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
2593
+ | `allowClear?` | `boolean` | |
2594
+ | `className?` | `string` | |
2595
+ | `clearLabel?` | `string` | |
2596
+ | `defaultOpen?` | `boolean` | |
2597
+ | `disabled?` | `boolean` | |
2598
+ | `id?` | `string` | |
2599
+ | `name?` | `string` | |
2600
+ | `onBlur?` | `FocusEventHandler<HTMLDivElement>` | |
2601
+ | `onFocus?` | `FocusEventHandler<HTMLDivElement>` | |
2602
+ | `onOpenChange?` | `(open: boolean) => void` | |
2603
+ | `open?` | `boolean` | |
2604
+ | `placeholder?` | `ReactNode` | |
2605
+ | `placement?` | `Placement` | |
2606
+ | `showSearch?` | `boolean` | |
2607
+ | `style?` | `CSSProperties` | |
2608
+ | `treeCheckable?` | `boolean` | |
2609
+ | `treeCheckStrictly?` | `boolean` | |
2610
+ | `treeData` | `TreeSelectNode[]` | |
2611
+ | `treeProps?` | `Omit< TreeProps, \| 'nodes' \| 'treeData' \| 'value' \| 'onSelect' \| 'selectedKeys' \| 'defaultSelectedKeys' \| 'onSelectionChange' \| 'multiple' \| 'checkable' \| 'checkStrictly' \| 'checkedKeys' \| 'defaultCheckedKeys' \| 'onCheck' \| 'disabled' \| 'searchValue' >` | Reuse Tree expansion, loading, filtering and virtual scrolling contracts. |
2612
+
2613
+ ### `TreeSelectNode`
2614
+
2615
+ _Type._
2616
+
2617
+ <sub>`src/components/Typography.tsx`</sub>
2618
+
2619
+ ### `Typography`
2620
+
2621
+ Also accepts: `HTMLAttributes<HTMLElement>`.
2622
+
2623
+ | Prop | Type | Notes |
2624
+ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
2625
+ | `as?` | `'div' \| 'span' \| 'p' \| 'h1' \| 'h2' \| 'h3' \| 'h4' \| 'h5'` | |
2626
+ | `code?` | `boolean` | |
2627
+ | `copyable?` | `\| boolean \| { text?: string \| (() => string \| Promise<string>); onCopy?: () => void; onError?: (error: unknown) => void }` | |
2628
+ | `delete?` | `boolean` | |
2629
+ | `disabled?` | `boolean` | |
2630
+ | `editable?` | `\| boolean \| { text?: string; editing?: boolean; onEditingChange?: (editing: boolean) => void; onStart?: () => void; onChange?: (text: string) => void; onCancel?: () => void; maxLength?: number; }` | |
2631
+ | `ellipsis?` | `\| boolean \| { rows?: number; expandable?: boolean; expanded?: boolean; defaultExpanded?: boolean; onExpand?: (expanded: boolean) => void; }` | |
2632
+ | `italic?` | `boolean` | |
2633
+ | `keyboard?` | `boolean` | |
2634
+ | `mark?` | `boolean` | |
2635
+ | `strong?` | `boolean` | |
2636
+ | `type?` | `'secondary' \| 'success' \| 'warning' \| 'danger'` | |
2637
+ | `underline?` | `boolean` | |
2638
+
2639
+ <sub>`src/components/Upload.tsx`</sub>
2640
+
2641
+ ### `Upload`
2642
+
2643
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'onError'>`.
2644
+
2645
+ | Prop | Type | Notes |
2646
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
2647
+ | `accept?` | `string` | |
2648
+ | `action?` | `string` | |
2649
+ | `beforeUpload?` | `( file: File, files: File[], ) => boolean \| void \| File \| Blob \| typeof LIST_IGNORE \| Promise<boolean \| void \| File \| Blob \| typeof LIST_IGNORE>` | |
2650
+ | `children?` | `ReactNode` | |
2651
+ | `customRequest?` | `(options: UploadRequestOptions) => void \| { abort: () => void }` | |
2652
+ | `data?` | `Record<string, string>` | |
2653
+ | `defaultFileList?` | `UploadFile[]` | |
2654
+ | `disabled?` | `boolean` | |
2655
+ | `drag?` | `boolean` | |
2656
+ | `fileList?` | `UploadFile[]` | |
2657
+ | `headers?` | `Record<string, string>` | |
2658
+ | `maxCount?` | `number` | |
2659
+ | `multiple?` | `boolean` | |
2660
+ | `name?` | `string` | |
2661
+ | `onChange?` | `(info: UploadChange) => void` | |
2662
+ | `onRemove?` | `(file: UploadFile) => boolean \| void \| Promise<boolean \| void>` | |
2663
+ | `showUploadList?` | `boolean` | |
2664
+ | `withCredentials?` | `boolean` | |
2665
+
2666
+ <sub>`src/components/Watermark.tsx`</sub>
2667
+
2668
+ ### `Watermark`
2669
+
2670
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'content'>`.
2671
+
2672
+ | Prop | Type | Notes |
2673
+ | ----------- | -------------------------------------------------------- | ----- |
2674
+ | `content?` | `string \| WatermarkText \| (string \| WatermarkText)[]` | |
2675
+ | `font?` | `WatermarkFont` | |
2676
+ | `gap?` | `[number, number]` | |
2677
+ | `height?` | `number` | |
2678
+ | `image?` | `string` | |
2679
+ | `offset?` | `[number, number]` | |
2680
+ | `onRemove?` | `() => void` | |
2681
+ | `rotate?` | `number` | |
2682
+ | `width?` | `number` | |
2683
+ | `zIndex?` | `number` | |
2684
+
2685
+ ### `WatermarkFont`
2686
+
2687
+ _Type._
2688
+
2689
+ ### `WatermarkText`
2690
+
2691
+ _Type._
2692
+
2693
+ ## Ship surface
2694
+
2695
+ <sub>`src/ship/AttachmentUpload.tsx`</sub>
2696
+
2697
+ ### `AttachmentUpload`
2698
+
2699
+ The detail sheet's attachment tool: a drop zone that also opens the file picker, a real per-file read with a progress bar, and the list of files already linked to this record with a confirmed unlink.
2700
+
2701
+ | Prop | Type | Notes |
2702
+ | ------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------ |
2703
+ | `currentUser` | `string` | The signed-in author — the host attributes the upload when it stores it. |
2704
+ | `entityId?` | `string` | Record identity: changing it cancels pending reads and resets attachment dialogs. |
2705
+ | `files` | `Array<{ relationId: string; file: Attachment }>` | Files already linked to the record, in the order the list should show them. |
2706
+ | `label?` | `string` | Rendered at the right of the drop zone header. |
2707
+ | `maxSizeMb?` | `number` | Hard limit per file; anything larger is refused before a byte is read. |
2708
+ | `onNotify?` | `Notify` | Raised for the two failures no callback can carry: a refused file and a broken read. |
2709
+
2710
+ <sub>`src/ship/Bits.tsx`</sub>
2711
+
2712
+ ### `EntityKind`
2713
+
2714
+ Entity kinds Ship renders with a coloured badge in front of the title.
2715
+
2716
+ _Type._
2717
+
2718
+ ### `ProductCell`
2719
+
2720
+ Product row in the products table: module icon, name, private lock.
2721
+
2722
+ | Prop | Type | Notes |
2723
+ | ---------- | ------------ | ----- |
2724
+ | `locked?` | `boolean` | |
2725
+ | `name` | `string` | |
2726
+ | `onClick?` | `() => void` | |
2727
+
2728
+ ### `QuickStart`
2729
+
2730
+ The floating "Quick start" pill anchored to the bottom-right of the shell.
2731
+
2732
+ | Prop | Type | Notes |
2733
+ | ---------- | ------------ | ------------------------------------------------------ |
2734
+ | `done?` | `number` | Steps completed; shown only when `total` is given too. |
2735
+ | `label?` | `string` | |
2736
+ | `onClick?` | `() => void` | |
2737
+ | `total?` | `number` | |
2738
+
2739
+ ### `StarButton`
2740
+
2741
+ | Prop | Type | Notes |
2742
+ | ---------- | ------------ | ----- |
2743
+ | `on` | `boolean` | |
2744
+ | `onToggle` | `() => void` | |
2745
+
2746
+ ### `TableBanner`
2747
+
2748
+ | Prop | Type | Notes |
2749
+ | -------------- | -------------------- | ----- |
2750
+ | `actionLabel?` | `string` | |
2751
+ | `children` | `ReactNode` | |
2752
+ | `icon?` | `IconName \| string` | |
2753
+ | `onAction?` | `() => void` | |
2754
+
2755
+ ### `TitleCell`
2756
+
2757
+ Title cell: type badge + truncated title, struck through when completed.
2758
+
2759
+ | Prop | Type | Notes |
2760
+ | ---------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2761
+ | `done?` | `boolean` | |
2762
+ | `kind` | `EntityKind` | |
2763
+ | `leading?` | `ReactNode` | Replaces the type badge with the mark the live grid uses for this kind — the Customer grid opens every name with a filled circle carrying the record's glyph. Pass an `IconAvatar`; the cell keeps its own layout either way. |
2764
+ | `onClick?` | `() => void` | |
2765
+ | `onEdit?` | `(next: string) => void` | Double-click the title to rename it in place; Enter commits, Esc cancels. |
2766
+ | `suffix?` | `ReactNode` | |
2767
+ | `title` | `string` | |
2768
+
2769
+ ### `TypeBadge`
2770
+
2771
+ | Prop | Type | Notes |
2772
+ | ------- | ------------ | ----- |
2773
+ | `kind` | `EntityKind` | |
2774
+ | `size?` | `number` | |
2775
+
2776
+ ### `VoteCount`
2777
+
2778
+ The vote counter a ticket row and a ticket sheet show.
2779
+
2780
+ | Prop | Type | Notes |
2781
+ | ------------ | -------- | ----- |
2782
+ | `className?` | `string` | |
2783
+ | `count` | `number` | |
2784
+
2785
+ <sub>`src/ship/CommentThread.tsx`</sub>
2786
+
2787
+ ### `CommentThread`
2788
+
2789
+ The editable comment area from the detail sheet: the thread oldest → newest with replies indented under their parent, inline edit, confirmed delete, reactions and the composer.
2790
+
2791
+ | Prop | Type | Notes |
2792
+ | ------------- | ------------ | -------------------------------------------------------------------------- |
2793
+ | `activities?` | `Activity[]` | The record's activity rows, accepted so a host can hand over one feed. |
2794
+ | `comments` | `Comment[]` | Every comment of the record, replies included — the thread orders them. |
2795
+ | `currentUser` | `string` | The signed-in author: owns the edit and delete actions and the reactions. |
2796
+ | `emptyHint?` | `string` | Explanation under the `No data available` title while the thread is empty. |
2797
+ | `onNotify?` | `Notify` | Raised for the one command no other callback carries: "Copy text". |
2798
+
2799
+ <sub>`src/ship/DetailBlock.tsx`</sub>
2800
+
2801
+ ### `DetailBlock`
2802
+
2803
+ | Prop | Type | Notes |
2804
+ | ------------ | ----------- | ---------------------------------------------------------------------- |
2805
+ | `actions?` | `ReactNode` | Right-aligned controls in the head: an edit button, a counter, a menu. |
2806
+ | `children` | `ReactNode` | |
2807
+ | `className?` | `string` | |
2808
+ | `title?` | `ReactNode` | |
2809
+
2810
+ ### `DetailTool`
2811
+
2812
+ | Prop | Type | Notes |
2813
+ | ------------ | -------------------- | ------------------------------------------------------ |
2814
+ | `children?` | `ReactNode` | |
2815
+ | `className?` | `string` | |
2816
+ | `icon?` | `IconName \| string` | |
2817
+ | `label?` | `string` | `aria-label`; required when there is no visible label. |
2818
+ | `onClick?` | `() => void` | |
2819
+
2820
+ <sub>`src/ship/DetailSheet.tsx`</sub>
2821
+
2822
+ ### `CommentComposer`
2823
+
2824
+ The comment composer from the live detail sheet: the author's avatar, a bordered field whose toolbar sits inside its bottom edge, the character counter and a labelled Send.
2825
+
2826
+ | Prop | Type | Notes |
2827
+ | ----------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
2828
+ | `author?` | `string` | The signed-in user, shown on the avatar left of the field. |
2829
+ | `className?` | `string` | |
2830
+ | `disabled?` | `boolean` | |
2831
+ | `maxLength?` | `number` | Character budget the field enforces; the live caps a comment at 4096. |
2832
+ | `onAttachFile?` | `(file: File) => void` | `+` → Attach file, handed the picked file. Without a handler the composer still does something honest with the pick: it names the file in the draft. |
2833
+ | `onChange` | `(value: string) => void` | |
2834
+ | `onLinkWorkItem?` | `() => void` | `+` → Link work item. Defaults to dropping a `#` at the caret. |
2835
+ | `onSubmit` | `() => void \| boolean \| Promise<void \| boolean>` | |
2836
+ | `placeholder?` | `string` | |
2837
+ | `readOnly?` | `boolean` | |
2838
+ | `value` | `string` | |
2839
+
2840
+ ### `DetailField`
2841
+
2842
+ One `label — value` line inside a section or the property strip.
2843
+
2844
+ | Prop | Type | Notes |
2845
+ | ---------- | -------------------- | ----- |
2846
+ | `children` | `ReactNode` | |
2847
+ | `icon?` | `IconName \| string` | |
2848
+ | `label` | `ReactNode` | |
2849
+ | `onEdit?` | `() => void` | |
2850
+
2851
+ ### `DetailProperty`
2852
+
2853
+ _Type._
2854
+
2855
+ ### `DetailSection`
2856
+
2857
+ Collapsible metadata group in the right rail.
2858
+
2859
+ | Prop | Type | Notes |
2860
+ | -------------- | ----------- | ----- |
2861
+ | `actions?` | `ReactNode` | |
2862
+ | `children` | `ReactNode` | |
2863
+ | `defaultOpen?` | `boolean` | |
2864
+ | `title` | `ReactNode` | |
2865
+
2866
+ ### `DetailSheet`
2867
+
2868
+ The entity sheet PingCode opens over the grid: identity bar, title, the property strip, tabs, the main column and the metadata rail.
2869
+
2870
+ | Prop | Type | Notes |
2871
+ | ------------- | -------------------------------------- | ---------------------------------------------- |
2872
+ | `activeTab` | `string` | |
2873
+ | `aside` | `ReactNode` | |
2874
+ | `children` | `ReactNode` | |
2875
+ | `className?` | `string` | |
2876
+ | `code` | `ReactNode` | The human key, e.g. `SLC-T1`. |
2877
+ | `composer?` | `ReactNode` | |
2878
+ | `kind` | `EntityKind` | |
2879
+ | `onClose` | `() => void` | |
2880
+ | `onTabChange` | `(id: string) => void` | |
2881
+ | `properties?` | `DetailProperty[]` | |
2882
+ | `tabs` | `Array<{ id: string; label: string }>` | |
2883
+ | `title` | `ReactNode` | |
2884
+ | `tools?` | `ReactNode` | Header tools (attachments, links, font size…). |
2885
+
2886
+ ### `Feed`
2887
+
2888
+ Comments / activities / transitions share one timeline.
2889
+
2890
+ | Prop | Type | Notes |
2891
+ | --------- | ------------- | ----- |
2892
+ | `empty?` | `ReactNode` | |
2893
+ | `entries` | `FeedEntry[]` | |
2894
+
2895
+ ### `FeedEntry`
2896
+
2897
+ _Type._
2898
+
2899
+ ### `FeedFilter`
2900
+
2901
+ Segmented filter above the feed (Comments / Activities / Transitions).
2902
+
2903
+ | Prop | Type | Notes |
2904
+ | ---------- | -------------------------------------- | ----- |
2905
+ | `onChange` | `(value: string) => void` | |
2906
+ | `options` | `Array<{ id: string; label: string }>` | |
2907
+ | `right?` | `ReactNode` | |
2908
+ | `value` | `string` | |
2909
+
2910
+ <sub>`src/ship/EditableText.tsx`</sub>
2911
+
2912
+ ### `EditableText`
2913
+
2914
+ | Prop | Type | Notes |
2915
+ | ------------------ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
2916
+ | `className?` | `string` | |
2917
+ | `defaultDraft?` | `string` | |
2918
+ | `defaultEditing?` | `boolean` | |
2919
+ | `disabled?` | `boolean` | |
2920
+ | `draft?` | `string` | Controlled draft. |
2921
+ | `editing?` | `boolean` | Controlled editing state. |
2922
+ | `editSeed?` | `string` | Text the editor starts from when it differs from the read view — an entity whose stored copy is a template the product prints differently. |
2923
+ | `label?` | `string` | Accessible name for the editor and the edit button; defaults to `title`. |
2924
+ | `note?` | `ReactNode` | Extra node under the body — a provenance note, a hint, a counter. |
2925
+ | `onDraftChange?` | `(draft: string) => void` | |
2926
+ | `onEditingChange?` | `(editing: boolean) => void` | |
2927
+ | `onSave?` | `(next: string) => void` | Called with the committed value when the host presses Save. |
2928
+ | `paragraphs?` | `boolean` | Render blank-line-separated paragraphs instead of one block of text. |
2929
+ | `readOnly?` | `boolean` | Hides the edit affordance: a released or derived block cannot be edited. |
2930
+ | `rows?` | `number` | Editor height in rows. |
2931
+ | `text` | `string` | |
2932
+ | `title` | `ReactNode` | |
2933
+
2934
+ <sub>`src/ship/EntityDialog.tsx`</sub>
2935
+
2936
+ ### `DialogField`
2937
+
2938
+ _Type._
2939
+
2940
+ ### `EntityDialog`
2941
+
2942
+ The "New …" sheet: near-full-height, a form column and a metadata column, a dirty guard on close, and validation that waits for the first blur instead of shouting on the first keystroke.
2943
+
2944
+ | Prop | Type | Notes |
2945
+ | ---------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------- |
2946
+ | `asideFields?` | `DialogField[]` | |
2947
+ | `fields` | `DialogField[]` | |
2948
+ | `initialValues?` | `Record<string, string>` | Prefills the form and switches the footer to "Save" (edit, not create). |
2949
+ | `kind` | `EntityKind` | |
2950
+ | `onClose` | `() => void` | |
2951
+ | `onSubmit` | `(values: Record<string, string>) => void \| Promise<void>` | |
2952
+ | `open` | `boolean` | |
2953
+ | `submitLabel?` | `string` | |
2954
+ | `title` | `string` | Dialog title, e.g. "New idea". |
2955
+
2956
+ <sub>`src/ship/EntityPicker.tsx`</sub>
2957
+
2958
+ ### `EntityPicker`
2959
+
2960
+ | Prop | Type | Notes |
2961
+ | ---------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
2962
+ | `columns?` | `Array<Column<T>>` | `table` only: the columns. |
2963
+ | `confirmLabel?` | `(state: EntityPickerState) => string` | Confirm button copy for the current counts. |
2964
+ | `count?` | `ReactNode` | |
2965
+ | `emptyState?` | `ReactNode` | |
2966
+ | `fields?` | `FilterField[]` | |
2967
+ | `hint?` | `(state: EntityPickerState) => ReactNode` | Footer copy for the current counts. |
2968
+ | `linked?` | `string[]` | Ids already related — the baseline the link/unlink counts are measured against. |
2969
+ | `onChange` | `(next: string[]) => void` | |
2970
+ | `onClose` | `() => void` | |
2971
+ | `onConfirm` | `(selected: string[]) => void \| Promise<void>` | Confirmed with the ticked ids; the host writes the relations. |
2972
+ | `onRulesChange?` | `(rules: FilterRule[]) => void` | |
2973
+ | `onSortChange?` | `(sort: SortState) => void` | |
2974
+ | `renderLabel?` | `(row: T) => ReactNode` | `list` only: what each row shows next to its tick. |
2975
+ | `renderMeta?` | `(row: T) => ReactNode` | `list` only: the trailing cell of a row (a status pill, a count). |
2976
+ | `rowKey` | `(row: T) => string` | |
2977
+ | `rows` | `T[]` | The candidates the host offers; the picker never fetches. |
2978
+ | `rules?` | `FilterRule[]` | |
2979
+ | `scopes?` | `{ nodes: TreeNode[]; value: string; onChange: (id: string) => void; defaultExpanded?: string[]; ariaLabel?: string; }` | Optional scope tree down the left side. |
2980
+ | `search?` | `{ value: string; onChange: (value: string) => void; placeholder?: string; ariaLabel?: string; }` | `table` only: search box. Its presence shows the search/filter/sort toolbar. |
2981
+ | `size?` | `'md' \| 'lg' \| 'xl'` | |
2982
+ | `sort?` | `SortState` | |
2983
+ | `sortFields?` | `Array<{ id: string; label: string }>` | |
2984
+ | `tableLabel?` | `string` | Table's accessible name. |
2985
+ | `title` | `string` | |
2986
+ | `value` | `string[]` | Ticked ids, in the host's order. |
2987
+ | `variant?` | `'list' \| 'table'` | `list` is the compact form the product uses inside a record sheet (a tick and a label per row); `table` is the workbench form. |
2988
+
2989
+ ### `EntityPickerState`
2990
+
2991
+ "Select ideas" — the dialog that links records to another record.
2992
+
2993
+ _Type._
2994
+
2995
+ <sub>`src/ship/FilePreview.tsx`</sub>
2996
+
2997
+ ### `downloadAttachment`
2998
+
2999
+ Hands the stand-in bytes for `file` to the browser and reports it.
3000
+
3001
+ _No props type — see the source._
3002
+
3003
+ ### `FilePreview`
3004
+
3005
+ The preview sheet behind a document or attachment: a labelled stand-in body chosen from the extension, header metadata, a zoom that moves the body itself, and a download built from exactly the content on screen.
3006
+
3007
+ | Prop | Type | Notes |
3008
+ | ----------- | ------------- | ---------------------------------------------------------------------------- |
3009
+ | `file` | `PreviewFile` | The attachment (or document page) to show. |
3010
+ | `onClose` | `() => void` | |
3011
+ | `onNotify?` | `Notify` | Raised when a download is handed to the browser, so the host can confirm it. |
3012
+ | `open` | `boolean` | |
3013
+
3014
+ <sub>`src/ship/Header.tsx`</sub>
3015
+
3016
+ ### `AppHeader`
3017
+
3018
+ The products-level header: brand + global search + account actions.
3019
+
3020
+ | Prop | Type | Notes |
3021
+ | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
3022
+ | `actions` | `ReactNode` | |
3023
+ | `className?` | `string` | |
3024
+ | `onBrandClick?` | `() => void` | |
3025
+ | `product?` | `string` | Product name shown next to the brand mark ("Ship"). |
3026
+ | `search?` | `{ value: string; onChange: (value: string) => void; /** Enter in the field — the product jumps to the full search page. */ onSubmit?: () => void; placeholder?: string; shortcut?: string; }` | |
3027
+ | `searchRef?` | `RefObject<HTMLInputElement \| null>` | Focus target for the ⌘K shortcut the placeholder advertises. |
3028
+
3029
+ ### `BrandMark`
3030
+
3031
+ PingCode's four-dot product mark.
3032
+
3033
+ | Prop | Type | Notes |
3034
+ | ------------ | -------- | ----- |
3035
+ | `className?` | `string` | |
3036
+ | `size?` | `number` | |
3037
+
3038
+ ### `HeaderActions`
3039
+
3040
+ | Prop | Type | Notes |
3041
+ | ------------------ | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
3042
+ | `className?` | `string` | |
3043
+ | `onCreate?` | `() => void` | |
3044
+ | `onHelp?` | `() => void` | |
3045
+ | `onNotifications?` | `() => void` | |
3046
+ | `onPing?` | `() => void` | Opens Ping, the AI assistant side panel. The button is additive: when the prop is omitted nothing is rendered, so existing headers are unchanged. |
3047
+ | `pingOpen?` | `boolean` | Whether the Ping drawer is open; drives `aria-expanded` and the active tint. |
3048
+ | `unread?` | `number` | Unread count; renders the dot badge when > 0. |
3049
+ | `user` | `{ name: string; src?: string; onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void }` | |
3050
+
3051
+ ### `ProductHeader`
3052
+
3053
+ The workbench header: product identity, the star / collapse tools, the category tabs with their ink bar, and the same account cluster as the shell.
3054
+
3055
+ | Prop | Type | Notes |
3056
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
3057
+ | `actions` | `ReactNode` | |
3058
+ | `activeTab` | `string` | |
3059
+ | `className?` | `string` | |
3060
+ | `onCollapseSidebar?` | `() => void` | Collapses the tab sidebar; the header shows the outdent control. |
3061
+ | `onHome?` | `() => void` | |
3062
+ | `onSelectProduct?` | `(id: string) => void` | |
3063
+ | `onTabChange` | `(id: string) => void` | |
3064
+ | `onToggleStar?` | `() => void` | |
3065
+ | `overflowTabs?` | `NavItemSpec[]` | |
3066
+ | `product` | `{ name: string; onClick?: () => void }` | |
3067
+ | `products?` | `Array<{ id: string; name: string; hint?: string }>` | Other products, shown as a switcher menu on the product name. |
3068
+ | `search?` | `{ value: string; onChange: (value: string) => void; onSubmit?: () => void; placeholder?: string; shortcut?: string; }` | |
3069
+ | `searchRef?` | `RefObject<HTMLInputElement \| null>` | |
3070
+ | `sidebarCollapsed?` | `boolean` | |
3071
+ | `starred?` | `boolean` | |
3072
+ | `tabContextMenu?` | `(tab: NavItemSpec) => ContextMenuItem[]` | Right-click commands for a product tab (never the only entry point). |
3073
+ | `tabs` | `NavItemSpec[]` | |
3074
+
3075
+ <sub>`src/ship/LinkPicker.tsx`</sub>
3076
+
3077
+ ### `LinkCandidate`
3078
+
3079
+ A row the picker can offer: the record's id and the label its list would show.
3080
+
3081
+ _Type._
3082
+
3083
+ ### `LinkPicker`
3084
+
3085
+ The generic relation picker: link this record to rows of any target kind and manage the links that already exist.
3086
+
3087
+ | Prop | Type | Notes |
3088
+ | ----------- | --------------------------------- | ------------------------------------------------------------------------ |
3089
+ | `children?` | `(open: () => void) => ReactNode` | Render prop for the trigger; defaults to a "Links" button. |
3090
+ | `fromId?` | `string` | The record the links belong to; only names it in the copy. |
3091
+ | `onNotify?` | `Notify` | Raised for the batched "Linked N …" confirmation the picker itself owns. |
3092
+ | `selected` | `LinkSelection[]` | The links that already exist, grouped by kind inside the panel. |
3093
+ | `targets` | `LinkTarget[]` | Which kinds can be linked from here. |
3094
+ | `title?` | `string` | Optional heading; defaults to `Link <target label>`. |
3095
+
3096
+ ### `LinkSelection`
3097
+
3098
+ A link that already exists, resolved by the host.
3099
+
3100
+ _Type._
3101
+
3102
+ ### `LinkTarget`
3103
+
3104
+ One kind the picker can link to; `kind` is the host's own collection name.
3105
+
3106
+ _Type._
3107
+
3108
+ <sub>`src/ship/ListWorkbench.tsx`</sub>
3109
+
3110
+ ### `AssigneeField`
3111
+
3112
+ The grid's inline assignee quick editor, in the one shape the library can carry without owning a store: the host supplies the people and the write, the workbench renders the cell and anchors the picker to it.
3113
+
3114
+ _Type._
3115
+
3116
+ ### `BulkCapabilities`
3117
+
3118
+ The product's standard bulk commands.
3119
+
3120
+ _Type._
3121
+
3122
+ ### `EnumField`
3123
+
3124
+ One enum column the grid edits in place.
3125
+
3126
+ _Type._
3127
+
3128
+ ### `exportRowsToCsv`
3129
+
3130
+ Writes rows to a CSV download with the very writer the list's own export uses, so a host can back a single-row "Export as CSV" quick command without copying the format.
3131
+
3132
+ _No props type — see the source._
3133
+
3134
+ ### `ListView`
3135
+
3136
+ _Type._
3137
+
3138
+ ### `ListWorkbench`
3139
+
3140
+ One list, wired end to end and owned by nobody: search, filter rules, sort, grouping, column visibility, the five states, selection + bulk actions, CSV import/export, pagination, the create/edit sheet and the per-row commands.
3141
+
3142
+ | Prop | Type | Notes |
3143
+ | ----------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3144
+ | `assigneeField?` | `AssigneeField<T>` | Opt-in: turns the Assignee column into the inline quick editor. |
3145
+ | `banner?` | `ReactNode` | |
3146
+ | `boardView?` | `(rows: T[]) => ReactNode` | |
3147
+ | `bulk?` | `BulkCapabilities<T>` | The standard commands, in the product's order, above whatever `bulkActions` adds. Nothing here needs a page: freezing, statuses, baselines, schedules, distributing and the bulk edit dialog all belong to the component. |
3148
+ | `columns` | `Array<Column<T>>` | |
3149
+ | `compare?` | `Record<string, (a: T, b: T) => number>` | |
3150
+ | `countLabel?` | `(count: number) => ReactNode` | |
3151
+ | `detailTemplate?` | `string` | `/ship/products/slc/ideas/{key}` — fills "Copy link" / "Open in a new tab". |
3152
+ | `editFields?` | `DialogField[]` | |
3153
+ | `editTitle?` | `string` | |
3154
+ | `empty?` | `ReactNode` | Replace the built-in empty / error states outright, or tune their copy. |
3155
+ | `emptyAction?` | `ReactNode` | |
3156
+ | `emptyBoardText?` | `string` | |
3157
+ | `emptyHint?` | `ReactNode` | |
3158
+ | `entityKind?` | `EntityKind` | |
3159
+ | `enumFields?` | `Array<EnumField<T>>` | Opt-in: turns the listed enum columns into inline quick selects. |
3160
+ | `errorState?` | `ReactNode` | |
3161
+ | `filterFields?` | `FilterField[]` | |
3162
+ | `footerLeft?` | `ReactNode` | |
3163
+ | `forceEmpty?` | `boolean` | The demo's `?state=empty`: empties the rows, keeps the count's real value. |
3164
+ | `groupFields?` | `Array<{ id: string; label: string }>` | |
3165
+ | `headerExtras?` | `ReactNode` | |
3166
+ | `identity?` | `string` | |
3167
+ | `importable?` | `boolean` | |
3168
+ | `matches?` | `(row: T, rule: FilterRule) => boolean` | Tests one filter rule; a rule with an empty value always passes. |
3169
+ | `newLabel?` | `string` | |
3170
+ | `newMenu?` | `MenuItemSpec[]` | |
3171
+ | `noun` | `{ one: string; many: string }` | |
3172
+ | `onNotify?` | `Notify` | |
3173
+ | `rowKey` | `(row: T) => string` | |
3174
+ | `rows` | `T[]` | |
3175
+ | `searchText?` | `(row: T) => string` | Text the search box matches; without it a search matches nothing. |
3176
+ | `selection` | `string[]` | |
3177
+ | `sortFields?` | `Array<{ id: string; label: string }>` | |
3178
+ | `status?` | `'loading' \| 'error' \| 'ready'` | |
3179
+ | `textFields?` | `Array<TextField<T>>` | Opt-in: turns the listed title / name columns into inline text editors. |
3180
+ | `title` | `string` | |
3181
+ | `titleIcon?` | `IconName \| string` | |
3182
+ | `toolbarExtras?` | `ReactNode` | |
3183
+ | `view` | `ListView` | |
3184
+ | `views?` | `ViewMode[]` | |
3185
+
3186
+ ### `PreviewState`
3187
+
3188
+ Lets a host show each of the five grid states without a backend.
3189
+
3190
+ _Type._
3191
+
3192
+ ### `TextField`
3193
+
3194
+ One text column the grid edits in place — a title or a name.
3195
+
3196
+ _Type._
3197
+
3198
+ ### `ViewMode`
3199
+
3200
+ How the workbench arranges its rows.
3201
+
3202
+ _Type._
3203
+
3204
+ <sub>`src/ship/ProjectWizard.tsx`</sub>
3205
+
3206
+ ### `componentLine`
3207
+
3208
+ One line of the type's component list, as the preview pane prints it.
3209
+
3210
+ | Prop | Type | Notes |
3211
+ | ------------- | -------------------- | ------------------------------------------------------------------------ |
3212
+ | `color?` | `string` | Icon-tile colour, from the semantic token palette. |
3213
+ | `components` | `string[]` | The components the type installs, in the order the tab strip shows them. |
3214
+ | `description` | `string` | The card's grey line, verbatim from the product capture. |
3215
+ | `icon` | `IconName \| string` | |
3216
+ | `id` | `string` | |
3217
+
3218
+ ### `primaryComponents`
3219
+
3220
+ The tabs a type shows before its "More" menu.
3221
+
3222
+ | Prop | Type | Notes |
3223
+ | ------------- | -------------------- | ------------------------------------------------------------------------ |
3224
+ | `color?` | `string` | Icon-tile colour, from the semantic token palette. |
3225
+ | `components` | `string[]` | The components the type installs, in the order the tab strip shows them. |
3226
+ | `description` | `string` | The card's grey line, verbatim from the product capture. |
3227
+ | `icon` | `IconName \| string` | |
3228
+ | `id` | `string` | |
3229
+
3230
+ ### `ProjectDraft`
3231
+
3232
+ _Type._
3233
+
3234
+ ### `ProjectMemberOption`
3235
+
3236
+ _Type._
3237
+
3238
+ ### `ProjectTypeOption`
3239
+
3240
+ The three-step `New project` dialog: a fixed left pane that previews the chosen type, and a right pane that walks Project type → Details → Members.
3241
+
3242
+ _Type._
3243
+
3244
+ ### `ProjectWizard`
3245
+
3246
+ Step 1 and step 3 are the capture's; the details step validates on blur, keeps everything typed, and only unlocks `Next step` once the name and the key are valid.
3247
+
3248
+ | Prop | Type | Notes |
3249
+ | ------------------- | ------------------------------------------------ | ------------------------------------------------------------ |
3250
+ | `belongsToOptions?` | `string[]` | |
3251
+ | `categoryOptions?` | `string[]` | |
3252
+ | `defaults?` | `Partial<ProjectDraft>` | Overrides for the initial values. |
3253
+ | `existingKeys?` | `Array<{ key: string; name: string }>` | Keys already in use, so the key field can refuse them. |
3254
+ | `members` | `ProjectMemberOption[]` | Everyone the member step can add. |
3255
+ | `onClose` | `() => void` | |
3256
+ | `onSubmit` | `(draft: ProjectDraft) => void \| Promise<void>` | The draft is complete and valid; the host writes it. |
3257
+ | `owner` | `string` | The project owner: pre-selected on step 3 and not removable. |
3258
+ | `types` | `ProjectTypeOption[]` | The types step 1 offers; the first one is the default. |
3259
+
3260
+ <sub>`src/ship/Rail.tsx`</sub>
3261
+
3262
+ ### `AppRail`
3263
+
3264
+ The 60px product rail.
3265
+
3266
+ | Prop | Type | Notes |
3267
+ | -------------- | ---------------- | --------------------------------------------------- |
3268
+ | `activeId?` | `string` | |
3269
+ | `className?` | `string` | |
3270
+ | `footerItems?` | `RailItemSpec[]` | Rendered under the spacer, at the foot of the rail. |
3271
+ | `items` | `RailItemSpec[]` | |
3272
+
3273
+ ### `RailItemSpec`
3274
+
3275
+ _Type._
3276
+
3277
+ <sub>`src/ship/ReportCanvas.tsx`</sub>
3278
+
3279
+ ### `CanvasData`
3280
+
3281
+ The dataset projection.
3282
+
3283
+ _Type._
3284
+
3285
+ ### `CanvasRecord`
3286
+
3287
+ One flattened record of the dataset a canvas is bound to.
3288
+
3289
+ _Type._
3290
+
3291
+ ### `CanvasWidget`
3292
+
3293
+ One canvas widget.
3294
+
3295
+ _Type._
3296
+
3297
+ ### `CanvasWidgetData`
3298
+
3299
+ Per-kind configuration the widget bodies need: metric — which measure of the dataset to show text — the note body Every other kind draws the host's `data` directly.
3300
+
3301
+ _Type._
3302
+
3303
+ ### `CanvasWidgetSpan`
3304
+
3305
+ Width of a widget in the 12-column grid.
3306
+
3307
+ _Type._
3308
+
3309
+ ### `defaultCanvasWidgets`
3310
+
3311
+ The seed a fresh canvas starts from: a Metric, a Donut and a Bar.
3312
+
3313
+ _No props type — see the source._
3314
+
3315
+ ### `isCanvasWidgetSpan`
3316
+
3317
+ The persisted-layout guard the hosts run over a stored `span`.
3318
+
3319
+ _No props type — see the source._
3320
+
3321
+ ### `ReportCanvas`
3322
+
3323
+ The report canvas: a 12-column grid of widgets that can be added, resized, reordered by mouse drag or by the ▲/▼ buttons, and removed behind a confirm.
3324
+
3325
+ | Prop | Type | Notes |
3326
+ | ---------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3327
+ | `chartTypes?` | `string[]` | Widget kinds the "Add widget" dialog offers; all five by default. |
3328
+ | `data?` | `CanvasData` | Dataset the widgets read, for the bodies and the title suggestions. |
3329
+ | `emptyHint?` | `string` | |
3330
+ | `loading?` | `boolean` | |
3331
+ | `renderActions?` | `(openAddDialog: () => void) => ReactNode` | The host's own controls for the canvas. `openAddDialog` is the library's "Add widget" trigger, so the host's header button opens the same dialog (with its type picker, suggestion and Enter-to-submit) as the empty state. |
3332
+ | `renderBody?` | `(widget: CanvasWidget) => ReactNode` | Renders the widget body instead of the built-in one. |
3333
+ | `widgets` | `CanvasWidget[]` | |
3334
+
3335
+ ### `WidgetType`
3336
+
3337
+ The five widget bodies the canvas can draw.
3338
+
3339
+ _Type._
3340
+
3341
+ <sub>`src/ship/RichTextToolbar.tsx`</sub>
3342
+
3343
+ ### `RichTextToolbar`
3344
+
3345
+ Rich-text toolbar strip; the editor itself is intentionally inert.
3346
+
3347
+ _No props type — see the source._
3348
+
3349
+ <sub>`src/ship/RoadmapEditor.tsx`</sub>
3350
+
3351
+ ### `quarterWeekendDays`
3352
+
3353
+ Weekend days inside one quarter.
3354
+
3355
+ _No props type — see the source._
3356
+
3357
+ ### `RoadmapBar`
3358
+
3359
+ One draggable bar: a single initiative sitting in one period of a lane.
3360
+
3361
+ _Type._
3362
+
3363
+ ### `RoadmapEditor`
3364
+
3365
+ The roadmap timeline: lane rows across a quarter grid, with bars that move by mouse drag or ← / →, rename inline on blur, recolour, and delete behind a confirm.
3366
+
3367
+ | Prop | Type | Notes |
3368
+ | ---------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
3369
+ | `bars` | `RoadmapBar[]` | |
3370
+ | `barsLabel?` | `string` | Which dataset style name the bars use, e.g. "initiatives". |
3371
+ | `colors?` | `string[]` | |
3372
+ | `lanes` | `string[]` | |
3373
+ | `periods` | `string[]` | Columns of the grid, e.g. ['Q1 2026', 'Q2 2026', 'Q3 2026', 'Q4 2026']. |
3374
+ | `renderActions?` | `(openAddDialog: () => void) => ReactNode` | The host's own controls for the timeline. `openAddDialog` is the library's "Add initiative" trigger, so a header button opens the same dialog (with its lane / quarter / colour fields and the empty-name error) as the empty state. |
3375
+ | `showWeekends?` | `boolean` | |
3376
+ | `weekendGrid?` | `RoadmapWeekendGrid` | Overrides the weekend day counts (the built-in ones assume quarters). |
3377
+ | `zoom?` | `RoadmapZoom` | |
3378
+
3379
+ ### `RoadmapWeekendGrid`
3380
+
3381
+ Bounded weekend counts, keyed by period, for hosts that do not use quarters.
3382
+
3383
+ _Type._
3384
+
3385
+ ### `RoadmapZoom`
3386
+
3387
+ Timeline granularity of the quarter header.
3388
+
3389
+ _Type._
3390
+
3391
+ <sub>`src/ship/ShareDialog.tsx`</sub>
3392
+
3393
+ ### `DEFAULT_SHARING`
3394
+
3395
+ _No props type — see the source._
3396
+
3397
+ ### `ReportSharing`
3398
+
3399
+ _Type._
3400
+
3401
+ ### `ShareDialog`
3402
+
3403
+ Share + scheduled export for a report: the visibility select, the copyable link, the expiry menu and the scheduled-export half (cadence → hour, validated recipients, CSV/XLSX/PDF).
3404
+
3405
+ | Prop | Type | Notes |
3406
+ | ------------ | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
3407
+ | `onChange` | `(next: ReportSharing) => void` | |
3408
+ | `onClose` | `() => void` | |
3409
+ | `onCopy?` | `(link: string) => void \| Promise<void>` | The host writes the clipboard; Copied is shown only after this callback succeeds. |
3410
+ | `onSave?` | `(next: ReportSharing) => void \| Promise<void>` | Fired after the dialog validated and handed the caller the next value. Purely a notification hook for host side effects; the dialog itself never toasts. |
3411
+ | `open` | `boolean` | |
3412
+ | `reportName` | `string` | |
3413
+ | `value` | `ReportSharing` | |
3414
+
3415
+ <sub>`src/ship/ShellSurfaces.tsx`</sub>
3416
+
3417
+ ### `AccountMenu`
3418
+
3419
+ | Prop | Type | Notes |
3420
+ | -------- | ---------------------------------- | ---------------------------- |
3421
+ | `items` | `MenuItemSpec[]` | |
3422
+ | `label?` | `string` | Accessible name of the menu. |
3423
+ | `user` | `{ name: string; email?: string }` | |
3424
+
3425
+ ### `QuickStartDialog`
3426
+
3427
+ The getting-started checklist: a progress bar, one tickable row per step and a shortcut into the product for the steps that have somewhere to go.
3428
+
3429
+ | Prop | Type | Notes |
3430
+ | ---------- | ------------------------------------- | -------------------------------------------------------------- |
3431
+ | `checked` | `Record<string, boolean>` | |
3432
+ | `intro?` | `ReactNode` | |
3433
+ | `onClose` | `() => void` | |
3434
+ | `onGo?` | `(step: QuickStartStep) => void` | "Go to …": the host navigates and usually marks the step done. |
3435
+ | `onReset?` | `() => void` | |
3436
+ | `onToggle` | `(id: string, next: boolean) => void` | |
3437
+ | `open` | `boolean` | |
3438
+ | `steps` | `QuickStartStep[]` | |
3439
+
3440
+ ### `QuickStartStep`
3441
+
3442
+ _Type._
3443
+
3444
+ ### `ShortcutsDialog`
3445
+
3446
+ The keyboard help sheet: `<kbd>` on the left, what it does on the right.
3447
+
3448
+ | Prop | Type | Notes |
3449
+ | ----------- | ---------------- | ----- |
3450
+ | `onClose` | `() => void` | |
3451
+ | `open` | `boolean` | |
3452
+ | `shortcuts` | `ShortcutSpec[]` | |
3453
+ | `title?` | `string` | |
3454
+
3455
+ ### `ShortcutSpec`
3456
+
3457
+ _Type._
3458
+
3459
+ <sub>`src/ship/Toolbar.tsx`</sub>
3460
+
3461
+ ### `FilterChip`
3462
+
3463
+ Removable chip summarising one active condition.
3464
+
3465
+ | Prop | Type | Notes |
3466
+ | ---------- | ------------ | ----- |
3467
+ | `label` | `ReactNode` | |
3468
+ | `onRemove` | `() => void` | |
3469
+ | `value?` | `ReactNode` | |
3470
+
3471
+ ### `FilterField`
3472
+
3473
+ _Type._
3474
+
3475
+ ### `FilterPanel`
3476
+
3477
+ The filter builder: one row per condition, AND-ed together.
3478
+
3479
+ | Prop | Type | Notes |
3480
+ | --------------- | ------------------------------- | ----- |
3481
+ | `fields` | `FilterField[]` | |
3482
+ | `onClose` | `() => void` | |
3483
+ | `onRulesChange` | `(rules: FilterRule[]) => void` | |
3484
+ | `rules` | `FilterRule[]` | |
3485
+
3486
+ ### `FilterRule`
3487
+
3488
+ _Type._
3489
+
3490
+ ### `ListHeader`
3491
+
3492
+ The 48px strip above a grid: view name on the left, primary actions right.
3493
+
3494
+ | Prop | Type | Notes |
3495
+ | ------------ | -------------------- | ----- |
3496
+ | `actions?` | `ReactNode` | |
3497
+ | `className?` | `string` | |
3498
+ | `title` | `ReactNode` | |
3499
+ | `titleIcon?` | `IconName \| string` | |
3500
+
3501
+ ### `ListToolbar`
3502
+
3503
+ The entity toolbar: search, then Filter / Sort / Group / More, with the result count pinned to the right — the same order and wording as the product.
3504
+
3505
+ | Prop | Type | Notes |
3506
+ | ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
3507
+ | `className?` | `string` | |
3508
+ | `count?` | `ReactNode` | |
3509
+ | `expanded?` | `boolean` | |
3510
+ | `extraControls?` | `ReactNode` | |
3511
+ | `fields?` | `FilterField[]` | |
3512
+ | `group?` | `string \| null` | |
3513
+ | `groupFields?` | `Array<{ id: string; label: string }>` | |
3514
+ | `onGroupChange?` | `(id: string \| null) => void` | |
3515
+ | `onRulesChange?` | `(rules: FilterRule[]) => void` | |
3516
+ | `onSortChange?` | `(sort: SortState) => void` | |
3517
+ | `onToggleExpand?` | `() => void` | Collapses the filter bar (Ship's chevron next to the search field). |
3518
+ | `rules?` | `FilterRule[]` | |
3519
+ | `search` | `{ value: string; onChange: (value: string) => void; placeholder?: string; ariaLabel?: string; id?: string }` | |
3520
+ | `sort?` | `SortState` | |
3521
+ | `sortFields?` | `Array<{ id: string; label: string }>` | |
3522
+
3523
+ <sub>`src/ship/TransitionsTimeline.tsx`</sub>
3524
+
3525
+ ### `TransitionsTimeline`
3526
+
3527
+ The record's workflow history as a vertical timeline — newest first, one dot per status move, with the configured flow above the rail.
3528
+
3529
+ | Prop | Type | Notes |
3530
+ | ---------------- | ------------ | -------------------------------------------------------------------------------------------------- |
3531
+ | `currentStatus?` | `string` | The status the record sits at right now, when the host knows it. |
3532
+ | `emptyHint?` | `string` | Explanation under `No transitions yet` while nothing qualifies. |
3533
+ | `entries` | `Activity[]` | The record's activity rows; the timeline picks the status changes out of them. |
3534
+ | `statuses?` | `string[]` | Optional: the statuses to order the flow by, e.g. ['Pending','Planned','In progress','Completed']. |
3535
+
3536
+ <sub>`src/ship/Views.tsx`</sub>
3537
+
3538
+ ### `BoardCard`
3539
+
3540
+ _Type._
3541
+
3542
+ ### `BoardColumn`
3543
+
3544
+ _Type._
3545
+
3546
+ ### `BoardView`
3547
+
3548
+ Kanban view: fixed 288px columns, cards carry their own status pill.
3549
+
3550
+ | Prop | Type | Notes |
3551
+ | ------------ | --------------- | ----- |
3552
+ | `className?` | `string` | |
3553
+ | `columns` | `BoardColumn[]` | |
3554
+
3555
+ ### `DocSplit`
3556
+
3557
+ Documents tab: page tree on the left, rendered document on the right.
3558
+
3559
+ | Prop | Type | Notes |
3560
+ | ---------- | ------------ | ----- |
3561
+ | `children` | `ReactNode` | |
3562
+ | `tree` | `TreeNode[]` | |
3563
+
3564
+ ### `RoadmapLane`
3565
+
3566
+ _Type._
3567
+
3568
+ ### `RoadmapView`
3569
+
3570
+ Quarter-grid roadmap: one lane per product line, bars per initiative.
3571
+
3572
+ | Prop | Type | Notes |
3573
+ | ------------ | --------------- | ----- |
3574
+ | `className?` | `string` | |
3575
+ | `lanes` | `RoadmapLane[]` | |
3576
+ | `periods` | `string[]` | |
3577
+
3578
+ ## Hooks
3579
+
3580
+ <sub>`src/hooks/useBreakpoint.ts`</sub>
3581
+
3582
+ ### `Breakpoint`
3583
+
3584
+ _Type._
3585
+
3586
+ <sub>`src/hooks/useControllableState.ts`</sub>
3587
+
3588
+ ### `useControllableState`
3589
+
3590
+ One state hook for every component that supports both `value` and `defaultValue`: uncontrolled by default, fully controlled when the host passes `value`, and never a silent no-op in between.
3591
+
3592
+ | Prop | Type | Notes |
3593
+ | -------------- | -------------------- | ----- |
3594
+ | `defaultValue` | `T` | |
3595
+ | `onChange?` | `(value: T) => void` | |
3596
+ | `value?` | `T` | |
3597
+
3598
+ <sub>`src/hooks/useListCursor.ts`</sub>
3599
+
3600
+ ### `useListCursor`
3601
+
3602
+ The cursor an inline picker roves over its rows, shared by `PeoplePicker` and `QuickSelect`.
3603
+
3604
+ _No props type — see the source._
3605
+
3606
+ ## Utilities
3607
+
3608
+ <sub>`src/utils/cx.ts`</sub>
3609
+
3610
+ ### `cx`
3611
+
3612
+ _No props type — see the source._
3613
+
3614
+ <sub>`src/utils/format.ts`</sub>
3615
+
3616
+ ### `formatCompact`
3617
+
3618
+ Turns 1234 into 1.2k the way the product's vote counters do.
3619
+
3620
+ _No props type — see the source._
3621
+
3622
+ ### `formatCount`
3623
+
3624
+ `1,234` in the UI, but the full value stays available for screen readers.
3625
+
3626
+ _No props type — see the source._
3627
+
3628
+ ### `formatDateTime`
3629
+
3630
+ Full timestamp for tooltips / detail panels.
3631
+
3632
+ _No props type — see the source._
3633
+
3634
+ ### `formatDay`
3635
+
3636
+ _No props type — see the source._
3637
+
3638
+ ### `formatListTime`
3639
+
3640
+ PingCode's list timestamps are relative for the current week ("Today 15:44", "Yesterday 15:44", "Tuesday 09:12") and absolute beyond it.
3641
+
3642
+ _No props type — see the source._
3643
+
3644
+ ### `formatNumber`
3645
+
3646
+ _No props type — see the source._
3647
+
3648
+ ### `pluralize`
3649
+
3650
+ _No props type — see the source._
3651
+
3652
+ <sub>`src/utils/options.ts`</sub>
3653
+
3654
+ ### `cursorAfter`
3655
+
3656
+ Where a listbox key moves the cursor, clamped to the list — no wrap, so the ends of a list behave the way the arrow keys do everywhere else in the grid.
3657
+
3658
+ _No props type — see the source._
3659
+
3660
+ ### `matchesQuery`
3661
+
3662
+ Case-insensitive substring match of a query against the fields a row exposes.
3663
+
3664
+ _No props type — see the source._
3665
+
3666
+ ---
3667
+
3668
+ Generated from 131 source files. Run `pnpm docs` after changing a
3669
+ component, or `pnpm verify` will fail on the diff.