@famgia/omnify-ai-guides 2.0.15
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/README.md +105 -0
- package/dist/chunk-RCTEXK7C.js +549 -0
- package/dist/chunk-RCTEXK7C.js.map +1 -0
- package/dist/config/rules.yaml +524 -0
- package/dist/index.cjs +587 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +55 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge/agents/architect.md.stub +150 -0
- package/dist/knowledge/agents/developer.md.stub +190 -0
- package/dist/knowledge/agents/reviewer.md.stub +134 -0
- package/dist/knowledge/agents/tester.md.stub +196 -0
- package/dist/knowledge/checklists/backend.md.stub +112 -0
- package/dist/knowledge/checklists/react.md.stub +108 -0
- package/dist/knowledge/claude-rules/laravel-controllers.md.stub +57 -0
- package/dist/knowledge/claude-rules/laravel-migrations.md.stub +47 -0
- package/dist/knowledge/claude-rules/laravel-tests.md.stub +52 -0
- package/dist/knowledge/claude-rules/naming.md.stub +369 -0
- package/dist/knowledge/claude-rules/performance.md.stub +256 -0
- package/dist/knowledge/claude-rules/php-standards.md.stub +305 -0
- package/dist/knowledge/claude-rules/react-components.md.stub +67 -0
- package/dist/knowledge/claude-rules/schema-yaml.md.stub +83 -0
- package/dist/knowledge/claude-rules/security.md.stub +164 -0
- package/dist/knowledge/cursor-rules/antd-deprecations.mdc.stub +62 -0
- package/dist/knowledge/cursor-rules/basemodel-readonly.mdc.stub +66 -0
- package/dist/knowledge/cursor-rules/baserequest-readonly.mdc.stub +74 -0
- package/dist/knowledge/cursor-rules/baseresource-readonly.mdc.stub +78 -0
- package/dist/knowledge/cursor-rules/laravel-controller.mdc.stub +421 -0
- package/dist/knowledge/cursor-rules/laravel-request.mdc.stub +112 -0
- package/dist/knowledge/cursor-rules/laravel-resource.mdc.stub +73 -0
- package/dist/knowledge/cursor-rules/laravel-review.mdc.stub +69 -0
- package/dist/knowledge/cursor-rules/laravel-testing.mdc.stub +138 -0
- package/dist/knowledge/cursor-rules/laravel.mdc.stub +138 -0
- package/dist/knowledge/cursor-rules/migrations-workflow.mdc.stub +224 -0
- package/dist/knowledge/cursor-rules/model-editable.mdc.stub +120 -0
- package/dist/knowledge/cursor-rules/omnify-migrations.mdc.stub +109 -0
- package/dist/knowledge/cursor-rules/omnify-schema.mdc.stub +358 -0
- package/dist/knowledge/cursor-rules/omnify.mdc.stub +58 -0
- package/dist/knowledge/cursor-rules/react-design.mdc.stub +693 -0
- package/dist/knowledge/cursor-rules/react-form.mdc.stub +292 -0
- package/dist/knowledge/cursor-rules/react-services.mdc.stub +304 -0
- package/dist/knowledge/cursor-rules/react.mdc.stub +336 -0
- package/dist/knowledge/cursor-rules/request-editable.mdc.stub +111 -0
- package/dist/knowledge/cursor-rules/resource-editable.mdc.stub +125 -0
- package/dist/knowledge/cursor-rules/schema-create.mdc.stub +440 -0
- package/dist/knowledge/cursor-rules/validation-rules.mdc.stub +181 -0
- package/dist/knowledge/laravel/README.md.stub +59 -0
- package/dist/knowledge/laravel/architecture.md.stub +424 -0
- package/dist/knowledge/laravel/authentication.md.stub +588 -0
- package/dist/knowledge/laravel/controller.md.stub +484 -0
- package/dist/knowledge/laravel/datetime.md.stub +334 -0
- package/dist/knowledge/laravel/migrations-team.md.stub +376 -0
- package/dist/knowledge/laravel/openapi.md.stub +449 -0
- package/dist/knowledge/laravel/request.md.stub +450 -0
- package/dist/knowledge/laravel/resource.md.stub +516 -0
- package/dist/knowledge/laravel/service.md.stub +503 -0
- package/dist/knowledge/laravel/testing.md.stub +1504 -0
- package/dist/knowledge/omnify/antdesign-guide.md.stub +401 -0
- package/dist/knowledge/omnify/config-guide.md.stub +405 -0
- package/dist/knowledge/omnify/japan-guide.md.stub +186 -0
- package/dist/knowledge/omnify/laravel-guide.md.stub +61 -0
- package/dist/knowledge/omnify/partial-schema-guide.md.stub +353 -0
- package/dist/knowledge/omnify/react-form-guide.md.stub +225 -0
- package/dist/knowledge/omnify/schema-guide.md.stub +144 -0
- package/dist/knowledge/omnify/typescript-guide.md.stub +337 -0
- package/dist/knowledge/react/README.md.stub +221 -0
- package/dist/knowledge/react/antd-guide.md +528 -0
- package/dist/knowledge/react/antd-guide.md.stub +528 -0
- package/dist/knowledge/react/checklist.md.stub +108 -0
- package/dist/knowledge/react/datetime-guide.md.stub +137 -0
- package/dist/knowledge/react/design-philosophy.md.stub +363 -0
- package/dist/knowledge/react/i18n-guide.md.stub +211 -0
- package/dist/knowledge/react/laravel-integration.md.stub +181 -0
- package/dist/knowledge/react/service-pattern.md.stub +180 -0
- package/dist/knowledge/react/tanstack-query.md.stub +339 -0
- package/dist/knowledge/react/types-guide.md +669 -0
- package/dist/knowledge/react/types-guide.md.stub +669 -0
- package/dist/knowledge/workflows/bug-fix.md.stub +201 -0
- package/dist/knowledge/workflows/code-review.md.stub +164 -0
- package/dist/knowledge/workflows/new-feature.md.stub +327 -0
- package/dist/plugin-M95GyBll.d.cts +191 -0
- package/dist/plugin-M95GyBll.d.ts +191 -0
- package/dist/plugin.cjs +573 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +2 -0
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +15 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
# Ant Design Guide
|
|
2
|
+
|
|
3
|
+
> **Related:** [README](./README.md) | [i18n](./i18n-guide.md)
|
|
4
|
+
|
|
5
|
+
## ⚠️ IMPORTANT: Use Ant Design First
|
|
6
|
+
|
|
7
|
+
**ALWAYS check if Ant Design has a component before creating your own.**
|
|
8
|
+
|
|
9
|
+
Ant Design provides 60+ components: https://ant.design/components/overview
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// ✅ DO: Use Ant Design components
|
|
13
|
+
import { Table, Form, Input, Button, Modal, Card, Descriptions } from "antd";
|
|
14
|
+
|
|
15
|
+
// ❌ DON'T: Create custom components that Ant Design already has
|
|
16
|
+
// DON'T create: CustomTable, CustomModal, CustomForm, CustomButton
|
|
17
|
+
// DON'T create: DataGrid, Popup, FormInput
|
|
18
|
+
|
|
19
|
+
// ✅ DO: Extend Ant Design if needed
|
|
20
|
+
function UserTable(props: { users: User[] }) {
|
|
21
|
+
return <Table dataSource={props.users} columns={...} />; // Wraps AntD Table
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ❌ DON'T: Build from scratch
|
|
25
|
+
function UserTable(props: { users: User[] }) {
|
|
26
|
+
return <table><tbody>{users.map(...)}</tbody></table>; // WRONG!
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## ⚠️ No New Libraries Without Permission
|
|
33
|
+
|
|
34
|
+
**DO NOT install new npm packages without explicit user approval.**
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# ❌ DON'T: Install without asking
|
|
38
|
+
npm install lodash
|
|
39
|
+
npm install moment
|
|
40
|
+
npm install react-table
|
|
41
|
+
|
|
42
|
+
# ✅ DO: Ask first
|
|
43
|
+
"Do you want to install library X for Y?"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Already installed libraries (use these):**
|
|
47
|
+
- UI: `antd`, `@ant-design/icons`
|
|
48
|
+
- HTTP: `axios`
|
|
49
|
+
- State: `@tanstack/react-query`
|
|
50
|
+
- Styling: `tailwindcss`
|
|
51
|
+
- i18n: `next-intl`
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## When to Create a Component
|
|
56
|
+
|
|
57
|
+
| Create Component | Don't Create |
|
|
58
|
+
| ------------------------------- | ----------------------------- |
|
|
59
|
+
| Used in 2+ places | Used only once |
|
|
60
|
+
| Has own state/logic (>50 lines) | Simple markup (<30 lines) |
|
|
61
|
+
| Needs unit testing | Trivial display |
|
|
62
|
+
| Complex props interface | Few inline props |
|
|
63
|
+
| **Ant Design doesn't have it** | **Ant Design already has it** |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Container vs Presentational
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// CONTAINER COMPONENT (Smart) - pages or complex components
|
|
72
|
+
// - Fetches data
|
|
73
|
+
// - Handles mutations
|
|
74
|
+
// - Contains business logic
|
|
75
|
+
// ============================================================================
|
|
76
|
+
|
|
77
|
+
// app/(dashboard)/users/page.tsx
|
|
78
|
+
"use client";
|
|
79
|
+
|
|
80
|
+
import { useState } from "react";
|
|
81
|
+
import { useQuery } from "@tanstack/react-query";
|
|
82
|
+
import { userService, UserListParams } from "@/services/users";
|
|
83
|
+
import { queryKeys } from "@/lib/queryKeys";
|
|
84
|
+
import { UserTable } from "@/components/tables/UserTable";
|
|
85
|
+
|
|
86
|
+
export default function UsersPage() {
|
|
87
|
+
const [filters, setFilters] = useState<UserListParams>({ page: 1 });
|
|
88
|
+
|
|
89
|
+
const { data, isLoading } = useQuery({
|
|
90
|
+
queryKey: queryKeys.users.list(filters),
|
|
91
|
+
queryFn: () => userService.list(filters),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<UserTable
|
|
96
|
+
users={data?.data ?? []}
|
|
97
|
+
loading={isLoading}
|
|
98
|
+
pagination={data?.meta}
|
|
99
|
+
onPageChange={(page) => setFilters({ ...filters, page })}
|
|
100
|
+
/>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// PRESENTATIONAL COMPONENT (Dumb) - reusable UI
|
|
106
|
+
// - Receives data via props
|
|
107
|
+
// - No data fetching
|
|
108
|
+
// - No business logic
|
|
109
|
+
// ============================================================================
|
|
110
|
+
|
|
111
|
+
// components/tables/UserTable.tsx
|
|
112
|
+
import { Table } from "antd";
|
|
113
|
+
import type { User } from "@omnify/schemas";
|
|
114
|
+
import type { PaginatedResponse } from "@/lib/api";
|
|
115
|
+
|
|
116
|
+
interface UserTableProps {
|
|
117
|
+
users: User[];
|
|
118
|
+
loading: boolean;
|
|
119
|
+
pagination?: PaginatedResponse<User>["meta"];
|
|
120
|
+
onPageChange: (page: number) => void;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function UserTable({ users, loading, pagination, onPageChange }: UserTableProps) {
|
|
124
|
+
return (
|
|
125
|
+
<Table
|
|
126
|
+
dataSource={users}
|
|
127
|
+
loading={loading}
|
|
128
|
+
rowKey="id"
|
|
129
|
+
pagination={{
|
|
130
|
+
current: pagination?.current_page,
|
|
131
|
+
total: pagination?.total,
|
|
132
|
+
onChange: onPageChange,
|
|
133
|
+
}}
|
|
134
|
+
columns={[
|
|
135
|
+
{ title: "ID", dataIndex: "id" },
|
|
136
|
+
{ title: "Name", dataIndex: "name" },
|
|
137
|
+
{ title: "Email", dataIndex: "email" },
|
|
138
|
+
]}
|
|
139
|
+
/>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Form Pattern with Laravel Validation
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
"use client";
|
|
150
|
+
|
|
151
|
+
import { Form, Input, Button, message } from "antd";
|
|
152
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
153
|
+
import { useTranslations } from "next-intl";
|
|
154
|
+
import { getFormErrors } from "@/lib/api";
|
|
155
|
+
import { queryKeys } from "@/lib/queryKeys";
|
|
156
|
+
import { userService } from "@/services/users";
|
|
157
|
+
|
|
158
|
+
export default function UserForm() {
|
|
159
|
+
const t = useTranslations();
|
|
160
|
+
const [form] = Form.useForm();
|
|
161
|
+
const queryClient = useQueryClient();
|
|
162
|
+
|
|
163
|
+
const mutation = useMutation({
|
|
164
|
+
mutationFn: userService.create,
|
|
165
|
+
onSuccess: () => {
|
|
166
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.users.all });
|
|
167
|
+
message.success(t("messages.created"));
|
|
168
|
+
form.resetFields();
|
|
169
|
+
},
|
|
170
|
+
onError: (error) => {
|
|
171
|
+
// This maps Laravel's 422 { errors: { email: ["Already exists"] } }
|
|
172
|
+
// to Ant Design's form.setFields format
|
|
173
|
+
form.setFields(getFormErrors(error));
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<Form
|
|
179
|
+
form={form}
|
|
180
|
+
layout="vertical"
|
|
181
|
+
onFinish={(values) => mutation.mutate(values)}
|
|
182
|
+
>
|
|
183
|
+
<Form.Item
|
|
184
|
+
name="name"
|
|
185
|
+
label={t("common.name")}
|
|
186
|
+
rules={[{ required: true }]}
|
|
187
|
+
>
|
|
188
|
+
<Input />
|
|
189
|
+
</Form.Item>
|
|
190
|
+
|
|
191
|
+
<Form.Item
|
|
192
|
+
name="email"
|
|
193
|
+
label={t("auth.email")}
|
|
194
|
+
rules={[{ required: true }, { type: "email" }]}
|
|
195
|
+
>
|
|
196
|
+
<Input />
|
|
197
|
+
</Form.Item>
|
|
198
|
+
|
|
199
|
+
<Form.Item>
|
|
200
|
+
<Button
|
|
201
|
+
type="primary"
|
|
202
|
+
htmlType="submit"
|
|
203
|
+
loading={mutation.isPending}
|
|
204
|
+
>
|
|
205
|
+
{t("common.save")}
|
|
206
|
+
</Button>
|
|
207
|
+
</Form.Item>
|
|
208
|
+
</Form>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## ⚠️ Ant Design Breaking Changes & Deprecated Props
|
|
216
|
+
|
|
217
|
+
> **IMPORTANT**: Check your `package.json` to determine which Ant Design version you're using:
|
|
218
|
+
> - **Ant Design 5.x**: Use `visible`, `valueStyle`, `bodyStyle`, `headStyle` (deprecated but still work)
|
|
219
|
+
> - **Ant Design 6.x**: Use `open`, `styles={{ ... }}` (semantic DOM API)
|
|
220
|
+
|
|
221
|
+
### Deprecated Props Reference Table
|
|
222
|
+
|
|
223
|
+
| Component | ❌ Deprecated (v6+) | ✅ Use Instead (v6+) | Notes |
|
|
224
|
+
| ----------------------- | -------------------------- | -------------------------- | -------------------------------------- |
|
|
225
|
+
| **Statistic** | `valueStyle` | `styles={{ content: {} }}` | ⚠️ v6.0.0+ only! Use `valueStyle` in v5 |
|
|
226
|
+
| **Card** | `bodyStyle` | `styles={{ body: {} }}` | ⚠️ v6.0.0+ only! Use `bodyStyle` in v5 |
|
|
227
|
+
| **Card** | `headStyle` | `styles={{ header: {} }}` | ⚠️ v6.0.0+ only! Use `headStyle` in v5 |
|
|
228
|
+
| **Divider** | `orientation` | `titlePlacement` | `orientation` is for direction only |
|
|
229
|
+
| Modal | `visible` | `open` | v5.0.0+ |
|
|
230
|
+
| Drawer | `visible` | `open` | v5.0.0+ |
|
|
231
|
+
| Dropdown | `visible` | `open` | v5.0.0+ |
|
|
232
|
+
| Tooltip | `visible` | `open` | v5.0.0+ |
|
|
233
|
+
| Popover | `visible` | `open` | v5.0.0+ |
|
|
234
|
+
| Popconfirm | `visible` | `open` | v5.0.0+ |
|
|
235
|
+
| Select | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` | v5.0.0+ |
|
|
236
|
+
| TreeSelect | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` | v5.0.0+ |
|
|
237
|
+
| Cascader | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` | v5.0.0+ |
|
|
238
|
+
| AutoComplete | `dropdownMatchSelectWidth` | `popupMatchSelectWidth` | v5.0.0+ |
|
|
239
|
+
| Table | `filterDropdownVisible` | `filterDropdownOpen` | v5.0.0+ |
|
|
240
|
+
| DatePicker | `dropdownClassName` | `popupClassName` | v5.0.0+ |
|
|
241
|
+
| TimePicker | `dropdownClassName` | `popupClassName` | v5.0.0+ |
|
|
242
|
+
| Mentions | `dropdownClassName` | `popupClassName` | v5.0.0+ |
|
|
243
|
+
| Tag | `closable` | `closeIcon={false}` | Use `closeIcon={false}` to hide |
|
|
244
|
+
| **List** | (component) | Use `Table` or custom | DEPRECATED in v6.0.0 |
|
|
245
|
+
| **Statistic.Countdown** | (component) | `Statistic.Timer` | Use `Statistic.Timer` (v5.25.0+) |
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// ❌ DON'T: Use deprecated props (causes console warnings)
|
|
249
|
+
<Statistic value={100} valueStyle={{ color: 'green' }} />
|
|
250
|
+
<Card bodyStyle={{ padding: 0 }} headStyle={{ background: '#f5f5f5' }}>
|
|
251
|
+
<Divider orientation="left">Title</Divider>
|
|
252
|
+
<Modal visible={isOpen}>
|
|
253
|
+
|
|
254
|
+
// ✅ DO: Use new props (Ant Design 6+)
|
|
255
|
+
<Statistic value={100} styles={{ content: { color: 'green' } }} />
|
|
256
|
+
<Card styles={{ body: { padding: 0 }, header: { background: '#f5f5f5' } }}>
|
|
257
|
+
<Divider titlePlacement="left">Title</Divider>
|
|
258
|
+
<Modal open={isOpen}>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 🎨 Ant Design 6.0 Semantic DOM API (NEW!)
|
|
264
|
+
|
|
265
|
+
**Version 6.0.0** introduced a new **Semantic DOM** pattern for styling. Instead of single style props, use `styles` and `classNames` objects:
|
|
266
|
+
|
|
267
|
+
### Statistic - Semantic Structure
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// Semantic keys: root, header, title, prefix, content, suffix
|
|
271
|
+
|
|
272
|
+
// ❌ OLD (deprecated in v6)
|
|
273
|
+
<Statistic
|
|
274
|
+
value={112893}
|
|
275
|
+
valueStyle={{ color: token.colorSuccess }}
|
|
276
|
+
prefix={<ArrowUpOutlined />}
|
|
277
|
+
/>
|
|
278
|
+
|
|
279
|
+
// ✅ NEW (v6.0.0+)
|
|
280
|
+
<Statistic
|
|
281
|
+
value={112893}
|
|
282
|
+
styles={{
|
|
283
|
+
content: { color: token.colorSuccess },
|
|
284
|
+
prefix: { marginRight: 8 },
|
|
285
|
+
}}
|
|
286
|
+
classNames={{
|
|
287
|
+
root: 'my-statistic',
|
|
288
|
+
content: 'my-statistic-value',
|
|
289
|
+
}}
|
|
290
|
+
prefix={<ArrowUpOutlined />}
|
|
291
|
+
/>
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Card - Semantic Structure
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// Semantic keys: root, header, title, extra, body, actions, cover
|
|
298
|
+
|
|
299
|
+
// ❌ OLD (deprecated)
|
|
300
|
+
<Card bodyStyle={{ padding: 0 }} headStyle={{ background: '#fafafa' }}>
|
|
301
|
+
|
|
302
|
+
// ✅ NEW (v6.0.0+)
|
|
303
|
+
<Card styles={{ body: { padding: 0 }, header: { background: '#fafafa' } }}>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Common Components with Semantic DOM (v6.0.0+)
|
|
307
|
+
|
|
308
|
+
| Component | Semantic Keys |
|
|
309
|
+
| ------------ | ------------------------------------------------------------- |
|
|
310
|
+
| Statistic | `root`, `header`, `title`, `prefix`, `content`, `suffix` |
|
|
311
|
+
| Card | `root`, `header`, `title`, `extra`, `body`, `actions` |
|
|
312
|
+
| Modal | `root`, `header`, `title`, `body`, `footer`, `mask` |
|
|
313
|
+
| Drawer | `root`, `header`, `title`, `body`, `footer`, `mask` |
|
|
314
|
+
| Table | `root`, `header`, `body`, `footer`, `cell` |
|
|
315
|
+
| Form | `root`, `item`, `label`, `input`, `feedback` |
|
|
316
|
+
| Descriptions | `root`, `header`, `title`, `body`, `item`, `label`, `content` |
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
// General pattern for semantic styling
|
|
320
|
+
<Component
|
|
321
|
+
styles={{ [semanticKey]: { /* CSSProperties */ } }}
|
|
322
|
+
classNames={{ [semanticKey]: 'my-class' }}
|
|
323
|
+
/>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## 🚨 Common Ant Design 6+ Mistakes
|
|
329
|
+
|
|
330
|
+
### 1. Divider - `orientation` vs `titlePlacement`
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
// ❌ WRONG: This will show a deprecation warning!
|
|
334
|
+
<Divider orientation="left">Section Title</Divider>
|
|
335
|
+
// Warning: [antd: Divider] `orientation` is used for direction, please use `titlePlacement` replace this
|
|
336
|
+
|
|
337
|
+
// ✅ CORRECT: Use titlePlacement for title position
|
|
338
|
+
<Divider titlePlacement="left">Section Title</Divider>
|
|
339
|
+
<Divider titlePlacement="center">Section Title</Divider>
|
|
340
|
+
<Divider titlePlacement="right">Section Title</Divider>
|
|
341
|
+
|
|
342
|
+
// For horizontal/vertical dividers, use `type`:
|
|
343
|
+
<Divider type="horizontal" /> // default
|
|
344
|
+
<Divider type="vertical" />
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### 2. Modal/Drawer - `visible` vs `open`
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
// ❌ WRONG
|
|
351
|
+
const [visible, setVisible] = useState(false);
|
|
352
|
+
<Modal visible={visible} onCancel={() => setVisible(false)}>
|
|
353
|
+
|
|
354
|
+
// ✅ CORRECT
|
|
355
|
+
const [open, setOpen] = useState(false);
|
|
356
|
+
<Modal open={open} onCancel={() => setOpen(false)}>
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### 3. Form.Item - `dependencies` must be array
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
// ❌ WRONG: dependencies as string
|
|
363
|
+
<Form.Item dependencies="password">
|
|
364
|
+
|
|
365
|
+
// ✅ CORRECT: dependencies as array
|
|
366
|
+
<Form.Item dependencies={['password']}>
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### 4. Table - Column `render` function signature
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
// ❌ WRONG: Using wrong parameter order
|
|
373
|
+
columns={[{
|
|
374
|
+
render: (record, text) => <span>{text}</span> // WRONG ORDER!
|
|
375
|
+
}]}
|
|
376
|
+
|
|
377
|
+
// ✅ CORRECT: (text, record, index)
|
|
378
|
+
columns={[{
|
|
379
|
+
render: (text, record, index) => <span>{text}</span>
|
|
380
|
+
}]}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 5. Select/TreeSelect - Option rendering
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
// ❌ WRONG: Using children in v6+
|
|
387
|
+
<Select>
|
|
388
|
+
<Select.Option value="1">Option 1</Select.Option>
|
|
389
|
+
</Select>
|
|
390
|
+
|
|
391
|
+
// ✅ PREFERRED: Use options prop (better performance)
|
|
392
|
+
<Select options={[
|
|
393
|
+
{ value: '1', label: 'Option 1' },
|
|
394
|
+
{ value: '2', label: 'Option 2' },
|
|
395
|
+
]} />
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### 6. DatePicker - Dayjs instead of Moment
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
// ❌ WRONG: Ant Design 6+ uses dayjs, not moment
|
|
402
|
+
import moment from 'moment';
|
|
403
|
+
<DatePicker value={moment(date)} />
|
|
404
|
+
|
|
405
|
+
// ✅ CORRECT: Use dayjs
|
|
406
|
+
import dayjs from 'dayjs';
|
|
407
|
+
<DatePicker value={dayjs(date)} />
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### 7. ConfigProvider - Theme customization
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
// ❌ WRONG: Old less variable approach
|
|
414
|
+
@primary-color: #1890ff;
|
|
415
|
+
|
|
416
|
+
// ✅ CORRECT: Use ConfigProvider theme token
|
|
417
|
+
<ConfigProvider
|
|
418
|
+
theme={{
|
|
419
|
+
token: {
|
|
420
|
+
colorPrimary: '#1890ff',
|
|
421
|
+
borderRadius: 6,
|
|
422
|
+
},
|
|
423
|
+
}}
|
|
424
|
+
>
|
|
425
|
+
<App />
|
|
426
|
+
</ConfigProvider>
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### 8. App Component - message/notification/modal
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
// ❌ WRONG: Direct import (won't respect ConfigProvider)
|
|
433
|
+
import { message } from 'antd';
|
|
434
|
+
message.success('Done!');
|
|
435
|
+
|
|
436
|
+
// ✅ CORRECT: Use App.useApp() hook
|
|
437
|
+
import { App } from 'antd';
|
|
438
|
+
|
|
439
|
+
function MyComponent() {
|
|
440
|
+
const { message, notification, modal } = App.useApp();
|
|
441
|
+
|
|
442
|
+
const handleClick = () => {
|
|
443
|
+
message.success('Done!'); // Respects ConfigProvider theme
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Wrap your app with App component
|
|
448
|
+
<ConfigProvider theme={...}>
|
|
449
|
+
<App>
|
|
450
|
+
<YourApp />
|
|
451
|
+
</App>
|
|
452
|
+
</ConfigProvider>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### 9. Icons - Named imports required
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
// ❌ WRONG: Default import
|
|
459
|
+
import Icon from '@ant-design/icons';
|
|
460
|
+
<Icon type="user" />
|
|
461
|
+
|
|
462
|
+
// ✅ CORRECT: Named imports
|
|
463
|
+
import { UserOutlined, EditOutlined } from '@ant-design/icons';
|
|
464
|
+
<UserOutlined />
|
|
465
|
+
<EditOutlined />
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### 10. Grid - `xs`, `sm`, etc. as objects
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
// ❌ CAREFUL: Mixing number and object syntax
|
|
472
|
+
<Col xs={24} sm={{ span: 12, offset: 6 }}>
|
|
473
|
+
|
|
474
|
+
// ✅ PREFERRED: Be consistent
|
|
475
|
+
<Col xs={{ span: 24 }} sm={{ span: 12, offset: 6 }}>
|
|
476
|
+
// OR
|
|
477
|
+
<Col xs={24} sm={12}>
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## Anti-Patterns
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
// ❌ Creating components that Ant Design already has
|
|
486
|
+
function CustomButton({ children }) { ... } // Use <Button> from antd
|
|
487
|
+
function CustomModal({ visible }) { ... } // Use <Modal> from antd
|
|
488
|
+
function CustomTable({ data }) { ... } // Use <Table> from antd
|
|
489
|
+
function DataGrid({ rows }) { ... } // Use <Table> from antd
|
|
490
|
+
|
|
491
|
+
// ❌ Installing libraries without permission
|
|
492
|
+
npm install lodash // Ask first!
|
|
493
|
+
npm install react-icons // Use @ant-design/icons
|
|
494
|
+
npm install styled-components // Use Tailwind CSS
|
|
495
|
+
|
|
496
|
+
// ❌ API call in component (bypass service layer)
|
|
497
|
+
function UserList() {
|
|
498
|
+
const { data } = useQuery({
|
|
499
|
+
queryKey: ["users"],
|
|
500
|
+
queryFn: () => axios.get("/api/users"), // WRONG: Use service
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// ❌ Business logic in component
|
|
505
|
+
function UserList() {
|
|
506
|
+
const users = data?.filter(u => u.active).sort((a, b) => a.name > b.name);
|
|
507
|
+
// Move to service or utility function
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// ❌ Hardcoded strings - use i18n
|
|
511
|
+
<Button>Save</Button> // WRONG
|
|
512
|
+
<Button>{t("common.save")}</Button> // CORRECT
|
|
513
|
+
|
|
514
|
+
// ❌ Multiple sources of truth
|
|
515
|
+
const [users, setUsers] = useState([]); // Local state
|
|
516
|
+
const { data } = useQuery({ ... }); // Server state
|
|
517
|
+
// Pick one: TanStack Query for server data
|
|
518
|
+
|
|
519
|
+
// ❌ Prop drilling
|
|
520
|
+
<Parent data={data}>
|
|
521
|
+
<Child data={data}>
|
|
522
|
+
<GrandChild data={data} /> // Use Context or pass minimal props
|
|
523
|
+
</Child>
|
|
524
|
+
</Parent>
|
|
525
|
+
|
|
526
|
+
// ❌ Giant components (>200 lines)
|
|
527
|
+
// Split into smaller components or extract hooks
|
|
528
|
+
```
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Checklists
|
|
2
|
+
|
|
3
|
+
> **Related:** [README](./README.md)
|
|
4
|
+
|
|
5
|
+
## After Writing Code
|
|
6
|
+
|
|
7
|
+
> **IMPORTANT**: Always run these commands after writing/modifying code:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# 1. Type check
|
|
11
|
+
npm run typecheck
|
|
12
|
+
|
|
13
|
+
# 2. Lint check
|
|
14
|
+
npm run lint
|
|
15
|
+
|
|
16
|
+
# Or combined
|
|
17
|
+
npm run typecheck && npm run lint
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Adding New Resource
|
|
23
|
+
|
|
24
|
+
When adding a new resource (e.g., `posts`), follow these steps:
|
|
25
|
+
|
|
26
|
+
### 1. Service Layer (Always in `services/`)
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Create: services/posts.ts
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- [ ] Import types: `import type { Post, PostCreate, PostUpdate } from "@omnify/schemas"`
|
|
33
|
+
- [ ] Define only `PostListParams` (Create/Update come from Omnify)
|
|
34
|
+
- [ ] Create `postService` object with CRUD methods
|
|
35
|
+
- [ ] Add JSDoc comments for each method
|
|
36
|
+
|
|
37
|
+
### 2. Query Keys
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Update: lib/queryKeys.ts
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- [ ] Add `posts` object to `queryKeys`
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
posts: {
|
|
47
|
+
all: ["posts"] as const,
|
|
48
|
+
lists: () => [...queryKeys.posts.all, "list"] as const,
|
|
49
|
+
list: (params?: PostListParams) => [...queryKeys.posts.lists(), params] as const,
|
|
50
|
+
details: () => [...queryKeys.posts.all, "detail"] as const,
|
|
51
|
+
detail: (id: number) => [...queryKeys.posts.details(), id] as const,
|
|
52
|
+
},
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3. Feature Components (in `features/posts/`)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Create: features/posts/
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- [ ] `PostTable.tsx` - Table component
|
|
62
|
+
- [ ] `PostForm.tsx` - Form component
|
|
63
|
+
- [ ] `usePostFilters.ts` - Feature-specific hooks (if needed)
|
|
64
|
+
|
|
65
|
+
### 4. Pages
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Create pages in app/(dashboard)/posts/
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- [ ] `page.tsx` - List page (imports from `features/posts/`)
|
|
72
|
+
- [ ] `new/page.tsx` - Create form
|
|
73
|
+
- [ ] `[id]/page.tsx` - Detail view
|
|
74
|
+
- [ ] `[id]/edit/page.tsx` - Edit form
|
|
75
|
+
|
|
76
|
+
### 5. Shared Components (only if reused)
|
|
77
|
+
|
|
78
|
+
- [ ] If component used in 2+ features → move to `components/common/`
|
|
79
|
+
|
|
80
|
+
### 6. Translations
|
|
81
|
+
|
|
82
|
+
- [ ] Add labels to `src/i18n/messages/*.json` if needed
|
|
83
|
+
|
|
84
|
+
### 7. Final Check
|
|
85
|
+
|
|
86
|
+
- [ ] Run `npm run typecheck && npm run lint`
|
|
87
|
+
- [ ] Test create, read, update, delete operations
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Adding New Language
|
|
92
|
+
|
|
93
|
+
- [ ] Create message file: `src/i18n/messages/{locale}.json`
|
|
94
|
+
- [ ] Add locale to `src/i18n/config.ts`
|
|
95
|
+
- [ ] Import Ant Design locale in `src/components/AntdThemeProvider.tsx`
|
|
96
|
+
- [ ] Test with `LocaleSwitcher` component
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Before Commit
|
|
101
|
+
|
|
102
|
+
- [ ] `npm run typecheck` passes
|
|
103
|
+
- [ ] `npm run lint` passes
|
|
104
|
+
- [ ] No console warnings about deprecated props
|
|
105
|
+
- [ ] No hardcoded strings (use i18n)
|
|
106
|
+
- [ ] Forms handle loading state (`isPending`)
|
|
107
|
+
- [ ] Forms handle validation errors (`getFormErrors`)
|
|
108
|
+
- [ ] Mutations invalidate related queries
|