ginskill-init 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.wrangler/cache/pages.json +4 -0
- package/.wrangler/cache/wrangler-account.json +6 -0
- package/DEVELOPMENT.md +510 -0
- package/README.md +104 -0
- package/agents/developer.md +56 -0
- package/agents/frontend-design.md +69 -0
- package/agents/mobile-reviewer.md +36 -0
- package/agents/review-code.md +49 -0
- package/agents/security-scanner.md +50 -0
- package/agents/tester.md +72 -0
- package/bin/cli.js +461 -0
- package/landing/ai-build-ai.png +0 -0
- package/landing/index.html +1495 -0
- package/landing/logo.png +0 -0
- package/package.json +37 -0
- package/skills/active-life-dev/SKILL.md +157 -0
- package/skills/active-life-dev/docs/auth.md +187 -0
- package/skills/active-life-dev/docs/customers.md +216 -0
- package/skills/active-life-dev/docs/integrations.md +209 -0
- package/skills/active-life-dev/docs/inventory.md +192 -0
- package/skills/active-life-dev/docs/modules.md +181 -0
- package/skills/active-life-dev/docs/orders.md +180 -0
- package/skills/active-life-dev/docs/patterns.md +319 -0
- package/skills/active-life-dev/docs/products.md +216 -0
- package/skills/active-life-dev/docs/schema.md +502 -0
- package/skills/active-life-dev/docs/setup.md +169 -0
- package/skills/active-life-dev/docs/vouchers.md +144 -0
- package/skills/ai-asset-generator/SKILL.md +247 -0
- package/skills/ai-asset-generator/docs/gen-image.md +274 -0
- package/skills/ai-asset-generator/docs/genvideo.md +341 -0
- package/skills/ai-asset-generator/docs/remove-background.md +19 -0
- package/skills/ai-asset-generator/lib/bg-remove.mjs +34 -0
- package/skills/ai-asset-generator/lib/env.mjs +48 -0
- package/skills/ai-asset-generator/lib/kie-client.mjs +100 -0
- package/skills/ai-build-ai/SKILL.md +127 -0
- package/skills/ai-build-ai/docs/agent-teams.md +293 -0
- package/skills/ai-build-ai/docs/checkpointing.md +161 -0
- package/skills/ai-build-ai/docs/create-agent.md +399 -0
- package/skills/ai-build-ai/docs/create-mcp.md +395 -0
- package/skills/ai-build-ai/docs/create-skill.md +299 -0
- package/skills/ai-build-ai/docs/headless-mode.md +614 -0
- package/skills/ai-build-ai/docs/hooks.md +578 -0
- package/skills/ai-build-ai/docs/memory-claude-md.md +375 -0
- package/skills/ai-build-ai/docs/output-styles.md +208 -0
- package/skills/ai-build-ai/docs/overview.md +162 -0
- package/skills/ai-build-ai/docs/permissions.md +391 -0
- package/skills/ai-build-ai/docs/plugins.md +396 -0
- package/skills/ai-build-ai/docs/sandbox.md +262 -0
- package/skills/ai-build-ai/docs/team-lead-workflow.md +648 -0
- package/skills/ant-design/SKILL.md +323 -0
- package/skills/ant-design/docs/components.md +160 -0
- package/skills/ant-design/docs/data-entry.md +406 -0
- package/skills/ant-design/docs/display.md +594 -0
- package/skills/ant-design/docs/feedback.md +451 -0
- package/skills/ant-design/docs/key-components.md +414 -0
- package/skills/ant-design/docs/navigation.md +310 -0
- package/skills/ant-design/docs/pro-components.md +543 -0
- package/skills/ant-design/docs/setup.md +213 -0
- package/skills/ant-design/docs/theme.md +265 -0
- package/skills/flutter-performance/SKILL.md +803 -0
- package/skills/flutter-performance/references/flutter-patterns.md +595 -0
- package/skills/icon-generator/SKILL.md +270 -0
- package/skills/mobile-app-review/SKILL.md +321 -0
- package/skills/mobile-app-review/references/apple-review.md +132 -0
- package/skills/mobile-app-review/references/google-play-review.md +203 -0
- package/skills/mongodb/SKILL.md +667 -0
- package/skills/mongodb/references/mongoose-patterns.md +368 -0
- package/skills/nestjs-architecture/SKILL.md +1086 -0
- package/skills/nestjs-architecture/references/advanced-patterns.md +590 -0
- package/skills/performance/SKILL.md +509 -0
- package/skills/react-fsd-architecture/SKILL.md +693 -0
- package/skills/react-fsd-architecture/references/fsd-patterns.md +747 -0
- package/skills/react-native-expo/SKILL.md +128 -0
- package/skills/react-native-expo/references/data-layer.md +252 -0
- package/skills/react-native-expo/references/design-system.md +252 -0
- package/skills/react-native-expo/references/navigation.md +199 -0
- package/skills/react-native-expo/references/performance.md +229 -0
- package/skills/react-native-expo/references/platform-services.md +179 -0
- package/skills/react-native-expo/references/state-management.md +209 -0
- package/skills/react-native-expo/references/ui-patterns.md +301 -0
- package/skills/react-query/SKILL.md +685 -0
- package/skills/react-query/references/query-patterns.md +365 -0
- package/skills/review-code/SKILL.md +374 -0
- package/skills/review-code/references/clean-code-principles.md +395 -0
- package/skills/review-code/references/frontend-patterns.md +136 -0
- package/skills/review-code/references/nestjs-patterns.md +184 -0
- package/skills/security-scanner/SKILL.md +366 -0
- package/skills/security-scanner/references/nestjs-security.md +260 -0
- package/skills/security-scanner/references/nextjs-security.md +201 -0
- package/skills/security-scanner/references/react-native-security.md +199 -0
- package/skills/traefik/SKILL.md +105 -0
- package/skills/traefik/docs/advanced-routing.md +186 -0
- package/skills/traefik/docs/auth-providers.md +137 -0
- package/skills/traefik/docs/cicd-devops.md +396 -0
- package/skills/traefik/docs/core-config.md +171 -0
- package/skills/traefik/docs/distributed-config.md +96 -0
- package/skills/traefik/docs/docker-compose.md +182 -0
- package/skills/traefik/docs/ha-performance.md +177 -0
- package/skills/traefik/docs/kubernetes.md +278 -0
- package/skills/traefik/docs/middleware.md +205 -0
- package/skills/traefik/docs/monitoring.md +357 -0
- package/skills/traefik/docs/security.md +391 -0
- package/skills/traefik/docs/tls-acme.md +155 -0
- package/skills/ui-ux-pro-max/SKILL.md +377 -0
- package/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# Ant Design — Data Entry Components (Select, Upload, DatePicker, Input)
|
|
2
|
+
|
|
3
|
+
## Select
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { Select } from 'antd';
|
|
7
|
+
import type { SelectProps, LabeledValue, DefaultOptionType } from 'antd';
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
### SelectProps
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
|------|------|---------|-------------|
|
|
14
|
+
| `options` | `{ label, value, disabled?, title? }[]` | — | Preferred way to define options |
|
|
15
|
+
| `mode` | `'multiple' \| 'tags'` | — | Multi-select (`tags` allows new entries) |
|
|
16
|
+
| `value` | `string \| number \| string[] \| LabeledValue` | — | Controlled value |
|
|
17
|
+
| `defaultValue` | same | — | Initial value (uncontrolled) |
|
|
18
|
+
| `placeholder` | `ReactNode` | — | Placeholder when nothing selected |
|
|
19
|
+
| `allowClear` | `boolean \| { clearIcon? }` | `false` | Show clear button |
|
|
20
|
+
| `showSearch` | `boolean \| SearchConfig` | `false` (single), `true` (multiple) | Enable search |
|
|
21
|
+
| `filterOption` | `boolean \| (input, option) => boolean` | `true` | Client-side filter; set `false` for server-side |
|
|
22
|
+
| `optionFilterProp` | `string` | `'value'` | Property used for filtering — usually set to `'label'` |
|
|
23
|
+
| `loading` | `boolean` | `false` | Show loading spinner |
|
|
24
|
+
| `disabled` | `boolean` | `false` | Disable select |
|
|
25
|
+
| `labelInValue` | `boolean` | `false` | onChange receives `{ value, label }` instead of raw value |
|
|
26
|
+
| `fieldNames` | `{ label?, value?, options? }` | — | Override field names for custom option schemas |
|
|
27
|
+
| `maxCount` | `number` | — | Max selectable items (multiple/tags mode) |
|
|
28
|
+
| `maxTagCount` | `number \| 'responsive'` | — | Max visible tags |
|
|
29
|
+
| `tokenSeparators` | `string[]` | — | Characters that trigger tag creation (tags mode) |
|
|
30
|
+
| `virtual` | `boolean` | `true` | Virtual scroll for large option lists |
|
|
31
|
+
| `popupRender` | `(menu) => ReactNode` | — | Customize dropdown (add footer/button) |
|
|
32
|
+
| `optionRender` | `(option, { index }) => ReactNode` | — | Custom option row renderer |
|
|
33
|
+
| `tagRender` | `(props) => ReactNode` | — | Custom tag renderer |
|
|
34
|
+
| `getPopupContainer` | `(trigger) => HTMLElement` | `document.body` | Popup container node |
|
|
35
|
+
| `status` | `'error' \| 'warning'` | — | Validation status |
|
|
36
|
+
| `variant` | `'outlined' \| 'borderless' \| 'filled'` | `'outlined'` | Visual style |
|
|
37
|
+
| `size` | `'large' \| 'middle' \| 'small'` | `'middle'` | Input size |
|
|
38
|
+
| `onChange` | `(value, option) => void` | — | Value change |
|
|
39
|
+
| `onSearch` | `(value: string) => void` | — | Search input change |
|
|
40
|
+
| `onSelect` / `onDeselect` | `(value, option) => void` | — | Item selected/removed |
|
|
41
|
+
| `onClear` | `() => void` | — | Clear button clicked |
|
|
42
|
+
|
|
43
|
+
### Patterns
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
// Basic
|
|
47
|
+
<Select style={{ width: 200 }} onChange={handleChange}
|
|
48
|
+
options={[{ value: 'a', label: 'Option A' }, { value: 'b', label: 'Option B' }]} />
|
|
49
|
+
|
|
50
|
+
// Search by label (most common)
|
|
51
|
+
<Select showSearch optionFilterProp="label" placeholder="Search..."
|
|
52
|
+
options={options} onChange={setValue} />
|
|
53
|
+
|
|
54
|
+
// Server-side async search
|
|
55
|
+
<Select showSearch filterOption={false} onSearch={debounce(fetchOptions, 300)}
|
|
56
|
+
loading={loading} options={options} placeholder="Type to search..." />
|
|
57
|
+
|
|
58
|
+
// Multiple with max count
|
|
59
|
+
<Select mode="multiple" allowClear maxCount={3}
|
|
60
|
+
placeholder="Select up to 3" options={options} onChange={setValues} />
|
|
61
|
+
|
|
62
|
+
// labelInValue — get both value and label
|
|
63
|
+
<Select labelInValue defaultValue={{ value: 'lucy', label: 'Lucy' }}
|
|
64
|
+
onChange={(v: LabeledValue) => console.log(v.value, v.label)} options={options} />
|
|
65
|
+
|
|
66
|
+
// Custom option schema (fieldNames)
|
|
67
|
+
<Select fieldNames={{ label: 'name', value: 'id' }}
|
|
68
|
+
options={[{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]} />
|
|
69
|
+
|
|
70
|
+
// Add footer button to dropdown
|
|
71
|
+
<Select popupRender={(menu) => (
|
|
72
|
+
<>
|
|
73
|
+
{menu}
|
|
74
|
+
<Divider style={{ margin: '8px 0' }} />
|
|
75
|
+
<Button type="link" onClick={addItem}>+ Add item</Button>
|
|
76
|
+
</>
|
|
77
|
+
)} options={options} />
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Common Mistakes
|
|
81
|
+
- **Default `optionFilterProp` is `'value'`**, not `'label'` — users searching by text see no results unless you set `optionFilterProp="label"`
|
|
82
|
+
- **For server-side search, always set `filterOption={false}`** — otherwise antd applies its own client-side filter on top
|
|
83
|
+
- **`labelInValue` changes `onChange` signature** to `{ value, label }` — causes TypeScript errors if you mix them
|
|
84
|
+
- **`mode="tags"` auto-creates options from typed text** — use `mode="multiple"` to restrict to predefined options
|
|
85
|
+
- **`value={undefined}` is not the same as omitting `value`** — don't switch between controlled/uncontrolled
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Upload
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { Upload } from 'antd';
|
|
93
|
+
import type { UploadProps, UploadFile, UploadChangeParam, GetProp } from 'antd';
|
|
94
|
+
// Derive FileType from beforeUpload
|
|
95
|
+
type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];
|
|
96
|
+
const { Dragger } = Upload;
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### UploadProps
|
|
100
|
+
|
|
101
|
+
| Prop | Type | Default | Description |
|
|
102
|
+
|------|------|---------|-------------|
|
|
103
|
+
| `action` | `string \| ((file: RcFile) => Promise<string>)` | — | Upload URL |
|
|
104
|
+
| `fileList` | `UploadFile[]` | — | Controlled file list — must update in `onChange` |
|
|
105
|
+
| `defaultFileList` | `UploadFile[]` | — | Initial files (uncontrolled) |
|
|
106
|
+
| `accept` | `string` | — | Accepted MIME types / extensions |
|
|
107
|
+
| `multiple` | `boolean` | `false` | Allow multi-file select |
|
|
108
|
+
| `maxCount` | `number` | — | Cap number of files |
|
|
109
|
+
| `listType` | `'text' \| 'picture' \| 'picture-card' \| 'picture-circle'` | `'text'` | UI style |
|
|
110
|
+
| `beforeUpload` | `(file, fileList) => boolean \| Promise \| Upload.LIST_IGNORE` | — | Pre-upload validation |
|
|
111
|
+
| `customRequest` | `(options) => void` | — | Replace XHR upload entirely |
|
|
112
|
+
| `showUploadList` | `boolean \| { showRemoveIcon?, showPreviewIcon?, ... }` | `true` | List icons config |
|
|
113
|
+
| `data` | `object \| ((file) => object \| Promise<object>)` | — | Extra form fields with upload |
|
|
114
|
+
| `headers` | `object` | — | Extra HTTP headers |
|
|
115
|
+
| `method` | `string` | `'post'` | HTTP method |
|
|
116
|
+
| `name` | `string` | `'file'` | Form field name |
|
|
117
|
+
| `withCredentials` | `boolean` | `false` | Send cookies with upload |
|
|
118
|
+
| `directory` | `boolean` | `false` | Allow folder selection |
|
|
119
|
+
| `disabled` | `boolean` | `false` | Disable upload |
|
|
120
|
+
| `onChange` | `(info: UploadChangeParam) => void` | — | Fires at every stage |
|
|
121
|
+
| `onPreview` | `(file: UploadFile) => void` | — | Preview click |
|
|
122
|
+
| `onRemove` | `(file) => boolean \| Promise<boolean>` | — | Remove click; return `false` to prevent |
|
|
123
|
+
| `onDownload` | `(file) => void` | — | Download click |
|
|
124
|
+
|
|
125
|
+
### UploadFile type
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
interface UploadFile<T = any> {
|
|
129
|
+
uid: string; // unique ID (required in controlled fileList)
|
|
130
|
+
name: string;
|
|
131
|
+
status?: 'error' | 'done' | 'uploading' | 'removed';
|
|
132
|
+
percent?: number;
|
|
133
|
+
url?: string;
|
|
134
|
+
thumbUrl?: string;
|
|
135
|
+
originFileObj?: File; // raw File — undefined for server-initialized files
|
|
136
|
+
response?: T;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Patterns
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
// Button upload
|
|
144
|
+
<Upload name="file" action="/api/upload" onChange={({ file, fileList }) => {
|
|
145
|
+
if (file.status === 'done') message.success(`${file.name} uploaded`);
|
|
146
|
+
if (file.status === 'error') message.error(`${file.name} failed`);
|
|
147
|
+
}}>
|
|
148
|
+
<Button icon={<UploadOutlined />}>Upload</Button>
|
|
149
|
+
</Upload>
|
|
150
|
+
|
|
151
|
+
// Drag-and-drop
|
|
152
|
+
<Upload.Dragger name="files" multiple action="/api/upload"
|
|
153
|
+
onChange={({ file }) => { if (file.status === 'done') message.success('Done!'); }}>
|
|
154
|
+
<p className="ant-upload-drag-icon"><InboxOutlined /></p>
|
|
155
|
+
<p className="ant-upload-text">Click or drag to upload</p>
|
|
156
|
+
</Upload.Dragger>
|
|
157
|
+
|
|
158
|
+
// Picture card with preview
|
|
159
|
+
<Upload listType="picture-card" fileList={fileList}
|
|
160
|
+
onPreview={handlePreview} onChange={({ fileList }) => setFileList(fileList)}>
|
|
161
|
+
{fileList.length >= 8 ? null : <div><PlusOutlined /><div>Upload</div></div>}
|
|
162
|
+
</Upload>
|
|
163
|
+
|
|
164
|
+
// Manual upload (beforeUpload returns false)
|
|
165
|
+
<Upload beforeUpload={(file) => { setFiles(f => [...f, file]); return false; }} fileList={fileList}>
|
|
166
|
+
<Button>Select File</Button>
|
|
167
|
+
</Upload>
|
|
168
|
+
<Button onClick={doUpload}>Upload</Button>
|
|
169
|
+
|
|
170
|
+
// Validation: type + size check
|
|
171
|
+
const beforeUpload = (file: FileType) => {
|
|
172
|
+
const ok = file.type === 'image/jpeg' || file.type === 'image/png';
|
|
173
|
+
if (!ok) { message.error('JPG/PNG only!'); return Upload.LIST_IGNORE; }
|
|
174
|
+
if (file.size / 1024 / 1024 > 2) { message.error('Max 2MB!'); return false; }
|
|
175
|
+
return true;
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Common Mistakes
|
|
180
|
+
- **Controlled `fileList` requires manual update in `onChange`** — not updating freezes the list
|
|
181
|
+
- **`onChange` fires multiple times** per upload (select → progress ticks → done/error) — always check `file.status`
|
|
182
|
+
- **`beforeUpload` returning `false`** adds file in error state; **`Upload.LIST_IGNORE`** silently drops it — prefer the latter for avatar uploaders
|
|
183
|
+
- **`uid` must be unique and stable** in controlled `fileList` — duplicate UIDs break list behavior
|
|
184
|
+
- **`originFileObj` is undefined for server-initialized files** — guard before FileReader
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## DatePicker
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { DatePicker } from 'antd';
|
|
192
|
+
import type { DatePickerProps, RangePickerProps } from 'antd';
|
|
193
|
+
import dayjs from 'dayjs';
|
|
194
|
+
import type { Dayjs } from 'dayjs';
|
|
195
|
+
const { RangePicker } = DatePicker;
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
> **dayjs is required** — Ant Design v5 switched from moment.js. Install `dayjs` separately.
|
|
199
|
+
|
|
200
|
+
### DatePickerProps
|
|
201
|
+
|
|
202
|
+
| Prop | Type | Default | Description |
|
|
203
|
+
|------|------|---------|-------------|
|
|
204
|
+
| `value` | `Dayjs` | — | Controlled date |
|
|
205
|
+
| `defaultValue` | `Dayjs` | — | Initial date (uncontrolled) |
|
|
206
|
+
| `picker` | `'date' \| 'week' \| 'month' \| 'quarter' \| 'year'` | `'date'` | Selection granularity |
|
|
207
|
+
| `format` | `string \| ((v: Dayjs) => string)` | Depends on picker | Display format |
|
|
208
|
+
| `showTime` | `boolean \| TimePicker.Options` | — | Add time column |
|
|
209
|
+
| `disabledDate` | `(current: Dayjs, info) => boolean` | — | Restrict selectable dates |
|
|
210
|
+
| `disabledTime` | `(date: Dayjs) => { disabledHours?, ... }` | — | Restrict selectable times |
|
|
211
|
+
| `presets` | `{ label: ReactNode; value: Dayjs \| (() => Dayjs) }[]` | — | Quick-select shortcuts |
|
|
212
|
+
| `minDate` / `maxDate` | `Dayjs` | — | Date bounds (v5.14+) |
|
|
213
|
+
| `multiple` | `boolean` | `false` | Select multiple dates |
|
|
214
|
+
| `allowClear` | `boolean` | `true` | Show clear button |
|
|
215
|
+
| `disabled` | `boolean` | `false` | Disable picker |
|
|
216
|
+
| `inputReadOnly` | `boolean` | `false` | Calendar-only (no keyboard input) |
|
|
217
|
+
| `needConfirm` | `boolean` | — | Require OK button to confirm |
|
|
218
|
+
| `open` | `boolean` | — | Controlled open state |
|
|
219
|
+
| `status` | `'error' \| 'warning'` | — | Validation status |
|
|
220
|
+
| `variant` | `'outlined' \| 'borderless' \| 'filled' \| 'underlined'` | `'outlined'` | Visual style |
|
|
221
|
+
| `size` | `'large' \| 'middle' \| 'small'` | — | Input size |
|
|
222
|
+
| `onChange` | `(date: Dayjs \| null, dateString: string) => void` | — | Value change |
|
|
223
|
+
| `onOk` | `() => void` | — | OK button click (with showTime) |
|
|
224
|
+
|
|
225
|
+
**Default formats by picker:**
|
|
226
|
+
|
|
227
|
+
| picker | Format |
|
|
228
|
+
|--------|--------|
|
|
229
|
+
| `date` | `YYYY-MM-DD` |
|
|
230
|
+
| `week` | `YYYY-wo` |
|
|
231
|
+
| `month` | `YYYY-MM` |
|
|
232
|
+
| `quarter` | `YYYY-\QQ` |
|
|
233
|
+
| `year` | `YYYY` |
|
|
234
|
+
| with `showTime` | `YYYY-MM-DD HH:mm:ss` |
|
|
235
|
+
|
|
236
|
+
### RangePicker extras
|
|
237
|
+
|
|
238
|
+
| Prop | Type | Description |
|
|
239
|
+
|------|------|-------------|
|
|
240
|
+
| `value` | `[Dayjs, Dayjs]` | Controlled range |
|
|
241
|
+
| `presets` | `{ label, value: [Dayjs, Dayjs] }[]` | Preset ranges |
|
|
242
|
+
| `disabled` | `[boolean, boolean]` | Disable only start or end |
|
|
243
|
+
| `allowEmpty` | `[boolean, boolean]` | Allow unset start/end |
|
|
244
|
+
| `onCalendarChange` | `(dates, dateStrings, { range }) => void` | Fires after each side selected |
|
|
245
|
+
| `onChange` | `(dates, dateStrings) => void` | Fires when both sides selected |
|
|
246
|
+
|
|
247
|
+
### Patterns
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
// All picker types
|
|
251
|
+
<DatePicker onChange={(date, str) => console.log(date, str)} />
|
|
252
|
+
<DatePicker picker="week" />
|
|
253
|
+
<DatePicker picker="month" />
|
|
254
|
+
<DatePicker picker="year" />
|
|
255
|
+
|
|
256
|
+
// With time
|
|
257
|
+
<DatePicker showTime onChange={(val, str) => console.log(str)} onOk={console.log} />
|
|
258
|
+
|
|
259
|
+
// Disable past dates
|
|
260
|
+
<DatePicker disabledDate={(d) => d && d < dayjs().startOf('day')} />
|
|
261
|
+
|
|
262
|
+
// Min/Max range constraint (v5.14+)
|
|
263
|
+
<DatePicker minDate={dayjs('2024-01-01')} maxDate={dayjs('2024-12-31')} />
|
|
264
|
+
|
|
265
|
+
// RangePicker with presets
|
|
266
|
+
const presets = [
|
|
267
|
+
{ label: 'Last 7 Days', value: [dayjs().subtract(7, 'd'), dayjs()] },
|
|
268
|
+
{ label: 'Last 30 Days', value: [dayjs().subtract(30, 'd'), dayjs()] },
|
|
269
|
+
];
|
|
270
|
+
<RangePicker presets={presets} onChange={(dates, strs) => console.log(strs)} />
|
|
271
|
+
|
|
272
|
+
// Disable future in range based on start
|
|
273
|
+
<RangePicker disabledDate={(current, { from }) =>
|
|
274
|
+
from ? current > from.add(7, 'd') : false
|
|
275
|
+
} />
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Common Mistakes
|
|
279
|
+
- **`value` must be a `Dayjs` object** — not a string or `Date`; always wrap: `dayjs(myDate)`
|
|
280
|
+
- **`onChange` receives `null` when cleared** — always handle: `date && doSomething(date)`
|
|
281
|
+
- **`optionFilterProp` for search is set on Select** — for DatePicker, use `disabledDate`
|
|
282
|
+
- **RangePicker `onChange` fires only when both sides selected** — use `onCalendarChange` for intermediate state
|
|
283
|
+
- **`showTime` without `needConfirm`** auto-confirms when panel closes (even without OK)
|
|
284
|
+
- **`mode` prop vs `picker` prop** — don't use `mode` to set granularity; use `picker`
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Input
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { Input } from 'antd';
|
|
292
|
+
import type { InputProps, InputRef, GetProps } from 'antd';
|
|
293
|
+
type OTPProps = GetProps<typeof Input.OTP>;
|
|
294
|
+
const { Search, TextArea, Password, OTP } = Input;
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### InputProps
|
|
298
|
+
|
|
299
|
+
| Prop | Type | Default | Description |
|
|
300
|
+
|------|------|---------|-------------|
|
|
301
|
+
| `value` | `string` | — | Controlled value |
|
|
302
|
+
| `defaultValue` | `string` | — | Initial value (uncontrolled) |
|
|
303
|
+
| `prefix` | `ReactNode` | — | Left element inside input |
|
|
304
|
+
| `suffix` | `ReactNode` | — | Right element inside input |
|
|
305
|
+
| `allowClear` | `boolean \| { clearIcon? }` | `false` | Show clear button |
|
|
306
|
+
| `maxLength` | `number` | — | Hard character limit |
|
|
307
|
+
| `showCount` | `boolean \| function` | `false` | Show character counter |
|
|
308
|
+
| `count` | `CountConfig` | — | Advanced count config (v5.10+) |
|
|
309
|
+
| `disabled` | `boolean` | `false` | Disable input |
|
|
310
|
+
| `status` | `'error' \| 'warning'` | — | Validation status |
|
|
311
|
+
| `size` | `'large' \| 'middle' \| 'small'` | — | Input size |
|
|
312
|
+
| `variant` | `'outlined' \| 'borderless' \| 'filled' \| 'underlined'` | `'outlined'` | Visual style (v5.13+) |
|
|
313
|
+
| `type` | `string` | `'text'` | HTML input type |
|
|
314
|
+
| `id` | `string` | — | HTML id |
|
|
315
|
+
| `onChange` | `ChangeEventHandler<HTMLInputElement>` | — | Change handler |
|
|
316
|
+
| `onPressEnter` | `KeyboardEventHandler<HTMLInputElement>` | — | Enter key shorthand |
|
|
317
|
+
| `onClear` | `() => void` | — | Clear button click (v5.20+) |
|
|
318
|
+
|
|
319
|
+
### Instance ref (InputRef)
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
const ref = useRef<InputRef>(null);
|
|
323
|
+
ref.current?.focus();
|
|
324
|
+
ref.current?.blur();
|
|
325
|
+
ref.current?.select();
|
|
326
|
+
ref.current?.setSelectionRange(0, 5);
|
|
327
|
+
ref.current?.input; // raw HTMLInputElement
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Sub-components
|
|
331
|
+
|
|
332
|
+
**`Input.TextArea`** — adds:
|
|
333
|
+
- `autoSize?: boolean | { minRows?, maxRows? }` — auto-grow height
|
|
334
|
+
- `rows`, `cols`, `wrap` — standard textarea attrs
|
|
335
|
+
|
|
336
|
+
**`Input.Search`** — adds:
|
|
337
|
+
- `enterButton?: boolean | ReactNode` — show search button
|
|
338
|
+
- `loading?: boolean` — loading state on button
|
|
339
|
+
- `onSearch: (value, event, { source }) => void` — fires on Enter or button click
|
|
340
|
+
|
|
341
|
+
**`Input.Password`** — adds:
|
|
342
|
+
- `visibilityToggle?: boolean | { visible?, onVisibleChange? }` — show/hide toggle
|
|
343
|
+
- `iconRender?: (visible) => ReactNode` — custom eye icon
|
|
344
|
+
|
|
345
|
+
**`Input.OTP`** (v5.16+):
|
|
346
|
+
- `length?: number` — number of cells (default 6)
|
|
347
|
+
- `mask?: boolean | string` — mask cells
|
|
348
|
+
- `formatter?: (value: string) => string` — transform display
|
|
349
|
+
- `separator?: ReactNode | ((index) => ReactNode)` — between cells
|
|
350
|
+
- `onChange?: (value: string) => void`
|
|
351
|
+
|
|
352
|
+
> **`Input.Group` is deprecated** — use `Space.Compact` instead.
|
|
353
|
+
|
|
354
|
+
### Patterns
|
|
355
|
+
|
|
356
|
+
```tsx
|
|
357
|
+
// Basic with prefix/suffix
|
|
358
|
+
<Input prefix={<UserOutlined />} suffix={<InfoCircleOutlined />}
|
|
359
|
+
placeholder="Username" allowClear />
|
|
360
|
+
|
|
361
|
+
// Variants
|
|
362
|
+
<Input variant="borderless" placeholder="Borderless" />
|
|
363
|
+
<Input variant="filled" placeholder="Filled" />
|
|
364
|
+
<Input status="error" placeholder="Error state" />
|
|
365
|
+
|
|
366
|
+
// TextArea with auto-resize
|
|
367
|
+
<Input.TextArea autoSize={{ minRows: 2, maxRows: 6 }} showCount maxLength={200} />
|
|
368
|
+
|
|
369
|
+
// Search
|
|
370
|
+
<Input.Search placeholder="Search..." enterButton="Search" size="large"
|
|
371
|
+
onSearch={(val, _e, { source }) => source !== 'clear' && fetchResults(val)} />
|
|
372
|
+
|
|
373
|
+
// Password with external control
|
|
374
|
+
const [visible, setVisible] = useState(false);
|
|
375
|
+
<Input.Password visibilityToggle={{ visible, onVisibleChange: setVisible }} />
|
|
376
|
+
|
|
377
|
+
// OTP
|
|
378
|
+
<Input.OTP length={6} onChange={(val) => console.log(val)}
|
|
379
|
+
formatter={(s) => s.toUpperCase()} />
|
|
380
|
+
|
|
381
|
+
// Ref focus
|
|
382
|
+
const ref = useRef<InputRef>(null);
|
|
383
|
+
<Input ref={ref} />
|
|
384
|
+
<Button onClick={() => ref.current?.focus()}>Focus</Button>
|
|
385
|
+
|
|
386
|
+
// Unicode-safe character count
|
|
387
|
+
<Input count={{
|
|
388
|
+
show: true, max: 50,
|
|
389
|
+
strategy: (txt) => [...txt].length, // counts code points, not UTF-16 units
|
|
390
|
+
exceedFormatter: (txt, { max }) => [...txt].slice(0, max).join(''),
|
|
391
|
+
}} />
|
|
392
|
+
|
|
393
|
+
// Space.Compact replaces deprecated Input.Group
|
|
394
|
+
<Space.Compact>
|
|
395
|
+
<Input defaultValue="https://" style={{ width: '30%' }} />
|
|
396
|
+
<Input placeholder="domain.com" style={{ width: '70%' }} />
|
|
397
|
+
</Space.Compact>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Common Mistakes
|
|
401
|
+
- **`Input.Group` is deprecated** — use `Space.Compact`
|
|
402
|
+
- **`addonBefore`/`addonAfter` are deprecated** — use `Space.Compact` with `Space.Addon`
|
|
403
|
+
- **`showCount` only shows counter UI; `maxLength` enforces the limit** — they're independent
|
|
404
|
+
- **`autoSize` on TextArea causes synchronous reflow** — set `maxRows` to bound layout jumping
|
|
405
|
+
- **Search `onSearch` source field**: `'input'` = Enter key, `'suffix'` = button click, `'clear'` = clear button
|
|
406
|
+
- **Default `count.strategy` uses `.length`** which counts UTF-16 units — emoji counts as 2; use `[...txt].length` for Unicode safety
|