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.
Files changed (128) hide show
  1. package/.wrangler/cache/pages.json +4 -0
  2. package/.wrangler/cache/wrangler-account.json +6 -0
  3. package/DEVELOPMENT.md +510 -0
  4. package/README.md +104 -0
  5. package/agents/developer.md +56 -0
  6. package/agents/frontend-design.md +69 -0
  7. package/agents/mobile-reviewer.md +36 -0
  8. package/agents/review-code.md +49 -0
  9. package/agents/security-scanner.md +50 -0
  10. package/agents/tester.md +72 -0
  11. package/bin/cli.js +461 -0
  12. package/landing/ai-build-ai.png +0 -0
  13. package/landing/index.html +1495 -0
  14. package/landing/logo.png +0 -0
  15. package/package.json +37 -0
  16. package/skills/active-life-dev/SKILL.md +157 -0
  17. package/skills/active-life-dev/docs/auth.md +187 -0
  18. package/skills/active-life-dev/docs/customers.md +216 -0
  19. package/skills/active-life-dev/docs/integrations.md +209 -0
  20. package/skills/active-life-dev/docs/inventory.md +192 -0
  21. package/skills/active-life-dev/docs/modules.md +181 -0
  22. package/skills/active-life-dev/docs/orders.md +180 -0
  23. package/skills/active-life-dev/docs/patterns.md +319 -0
  24. package/skills/active-life-dev/docs/products.md +216 -0
  25. package/skills/active-life-dev/docs/schema.md +502 -0
  26. package/skills/active-life-dev/docs/setup.md +169 -0
  27. package/skills/active-life-dev/docs/vouchers.md +144 -0
  28. package/skills/ai-asset-generator/SKILL.md +247 -0
  29. package/skills/ai-asset-generator/docs/gen-image.md +274 -0
  30. package/skills/ai-asset-generator/docs/genvideo.md +341 -0
  31. package/skills/ai-asset-generator/docs/remove-background.md +19 -0
  32. package/skills/ai-asset-generator/lib/bg-remove.mjs +34 -0
  33. package/skills/ai-asset-generator/lib/env.mjs +48 -0
  34. package/skills/ai-asset-generator/lib/kie-client.mjs +100 -0
  35. package/skills/ai-build-ai/SKILL.md +127 -0
  36. package/skills/ai-build-ai/docs/agent-teams.md +293 -0
  37. package/skills/ai-build-ai/docs/checkpointing.md +161 -0
  38. package/skills/ai-build-ai/docs/create-agent.md +399 -0
  39. package/skills/ai-build-ai/docs/create-mcp.md +395 -0
  40. package/skills/ai-build-ai/docs/create-skill.md +299 -0
  41. package/skills/ai-build-ai/docs/headless-mode.md +614 -0
  42. package/skills/ai-build-ai/docs/hooks.md +578 -0
  43. package/skills/ai-build-ai/docs/memory-claude-md.md +375 -0
  44. package/skills/ai-build-ai/docs/output-styles.md +208 -0
  45. package/skills/ai-build-ai/docs/overview.md +162 -0
  46. package/skills/ai-build-ai/docs/permissions.md +391 -0
  47. package/skills/ai-build-ai/docs/plugins.md +396 -0
  48. package/skills/ai-build-ai/docs/sandbox.md +262 -0
  49. package/skills/ai-build-ai/docs/team-lead-workflow.md +648 -0
  50. package/skills/ant-design/SKILL.md +323 -0
  51. package/skills/ant-design/docs/components.md +160 -0
  52. package/skills/ant-design/docs/data-entry.md +406 -0
  53. package/skills/ant-design/docs/display.md +594 -0
  54. package/skills/ant-design/docs/feedback.md +451 -0
  55. package/skills/ant-design/docs/key-components.md +414 -0
  56. package/skills/ant-design/docs/navigation.md +310 -0
  57. package/skills/ant-design/docs/pro-components.md +543 -0
  58. package/skills/ant-design/docs/setup.md +213 -0
  59. package/skills/ant-design/docs/theme.md +265 -0
  60. package/skills/flutter-performance/SKILL.md +803 -0
  61. package/skills/flutter-performance/references/flutter-patterns.md +595 -0
  62. package/skills/icon-generator/SKILL.md +270 -0
  63. package/skills/mobile-app-review/SKILL.md +321 -0
  64. package/skills/mobile-app-review/references/apple-review.md +132 -0
  65. package/skills/mobile-app-review/references/google-play-review.md +203 -0
  66. package/skills/mongodb/SKILL.md +667 -0
  67. package/skills/mongodb/references/mongoose-patterns.md +368 -0
  68. package/skills/nestjs-architecture/SKILL.md +1086 -0
  69. package/skills/nestjs-architecture/references/advanced-patterns.md +590 -0
  70. package/skills/performance/SKILL.md +509 -0
  71. package/skills/react-fsd-architecture/SKILL.md +693 -0
  72. package/skills/react-fsd-architecture/references/fsd-patterns.md +747 -0
  73. package/skills/react-native-expo/SKILL.md +128 -0
  74. package/skills/react-native-expo/references/data-layer.md +252 -0
  75. package/skills/react-native-expo/references/design-system.md +252 -0
  76. package/skills/react-native-expo/references/navigation.md +199 -0
  77. package/skills/react-native-expo/references/performance.md +229 -0
  78. package/skills/react-native-expo/references/platform-services.md +179 -0
  79. package/skills/react-native-expo/references/state-management.md +209 -0
  80. package/skills/react-native-expo/references/ui-patterns.md +301 -0
  81. package/skills/react-query/SKILL.md +685 -0
  82. package/skills/react-query/references/query-patterns.md +365 -0
  83. package/skills/review-code/SKILL.md +374 -0
  84. package/skills/review-code/references/clean-code-principles.md +395 -0
  85. package/skills/review-code/references/frontend-patterns.md +136 -0
  86. package/skills/review-code/references/nestjs-patterns.md +184 -0
  87. package/skills/security-scanner/SKILL.md +366 -0
  88. package/skills/security-scanner/references/nestjs-security.md +260 -0
  89. package/skills/security-scanner/references/nextjs-security.md +201 -0
  90. package/skills/security-scanner/references/react-native-security.md +199 -0
  91. package/skills/traefik/SKILL.md +105 -0
  92. package/skills/traefik/docs/advanced-routing.md +186 -0
  93. package/skills/traefik/docs/auth-providers.md +137 -0
  94. package/skills/traefik/docs/cicd-devops.md +396 -0
  95. package/skills/traefik/docs/core-config.md +171 -0
  96. package/skills/traefik/docs/distributed-config.md +96 -0
  97. package/skills/traefik/docs/docker-compose.md +182 -0
  98. package/skills/traefik/docs/ha-performance.md +177 -0
  99. package/skills/traefik/docs/kubernetes.md +278 -0
  100. package/skills/traefik/docs/middleware.md +205 -0
  101. package/skills/traefik/docs/monitoring.md +357 -0
  102. package/skills/traefik/docs/security.md +391 -0
  103. package/skills/traefik/docs/tls-acme.md +155 -0
  104. package/skills/ui-ux-pro-max/SKILL.md +377 -0
  105. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  106. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  107. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  108. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  109. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  110. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  111. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  112. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  113. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  114. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  115. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  116. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  117. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  118. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  119. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  120. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  121. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  122. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  123. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  124. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  125. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  126. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  127. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  128. 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