ginskill-init 1.0.2 → 2.4.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.
Potentially problematic release.
This version of ginskill-init might be problematic. Click here for more details.
- package/package.json +1 -1
- 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/ant-design/scripts/fetch-component-docs.sh +169 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Ant Design — Navigation Components (Menu, Tabs, Layout, Grid)
|
|
2
|
+
|
|
3
|
+
## Menu
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { Menu } from 'antd';
|
|
7
|
+
import type { MenuProps } from 'antd';
|
|
8
|
+
type MenuItem = Required<MenuProps>['items'][number];
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### MenuProps
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `items` | `ItemType[]` | — | Menu items array (preferred over JSX children) |
|
|
16
|
+
| `mode` | `'vertical' \| 'horizontal' \| 'inline'` | `'vertical'` | Layout orientation |
|
|
17
|
+
| `theme` | `'light' \| 'dark'` | `'light'` | Color scheme |
|
|
18
|
+
| `selectedKeys` | `string[]` | — | Controlled selected keys |
|
|
19
|
+
| `defaultSelectedKeys` | `string[]` | — | Initial selected keys (uncontrolled) |
|
|
20
|
+
| `openKeys` | `string[]` | — | Controlled open submenu keys |
|
|
21
|
+
| `defaultOpenKeys` | `string[]` | — | Initial open submenu keys (uncontrolled) |
|
|
22
|
+
| `inlineCollapsed` | `boolean` | — | Collapse/expand inline menu |
|
|
23
|
+
| `inlineIndent` | `number` | `24` | Pixel indent per nesting level |
|
|
24
|
+
| `multiple` | `boolean` | `false` | Allow multi-selection |
|
|
25
|
+
| `triggerSubMenuAction` | `'hover' \| 'click'` | `'hover'` | What opens submenus |
|
|
26
|
+
| `onClick` | `({ key, keyPath, domEvent }) => void` | — | Item click handler |
|
|
27
|
+
| `onSelect` | `({ key, keyPath, selectedKeys }) => void` | — | Item select handler |
|
|
28
|
+
| `onOpenChange` | `(openKeys: string[]) => void` | — | Submenu open state change |
|
|
29
|
+
|
|
30
|
+
### ItemType Variants
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// Menu item
|
|
34
|
+
type MenuItemType = {
|
|
35
|
+
key: string;
|
|
36
|
+
label: ReactNode;
|
|
37
|
+
icon?: ReactNode;
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
danger?: boolean; // red danger styling
|
|
40
|
+
title?: string; // tooltip when collapsed
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Submenu
|
|
44
|
+
type SubMenuType = {
|
|
45
|
+
key: string;
|
|
46
|
+
label: ReactNode;
|
|
47
|
+
icon?: ReactNode;
|
|
48
|
+
children: ItemType[];
|
|
49
|
+
popupClassName?: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Group
|
|
53
|
+
type MenuItemGroupType = { type: 'group'; label?: ReactNode; children?: MenuItemType[] };
|
|
54
|
+
|
|
55
|
+
// Divider
|
|
56
|
+
type MenuDividerType = { type: 'divider'; dashed?: boolean };
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Patterns
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
// Sidebar (inline collapsible)
|
|
63
|
+
const items: MenuItem[] = [
|
|
64
|
+
{ key: '1', icon: <PieChartOutlined />, label: 'Dashboard' },
|
|
65
|
+
{ key: '2', icon: <MailOutlined />, label: 'Inbox' },
|
|
66
|
+
{
|
|
67
|
+
key: 'sub1', label: 'Settings', icon: <SettingOutlined />,
|
|
68
|
+
children: [
|
|
69
|
+
{ key: '5', label: 'Profile' },
|
|
70
|
+
{ key: '6', label: 'Security' },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
{ type: 'divider' },
|
|
74
|
+
{ type: 'group', label: 'Admin', children: [{ key: 'g1', label: 'Users', danger: true }] },
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
<Menu mode="inline" theme="dark" inlineCollapsed={collapsed}
|
|
78
|
+
selectedKeys={[current]} onClick={({ key }) => setCurrent(key)} items={items} />
|
|
79
|
+
|
|
80
|
+
// Horizontal nav
|
|
81
|
+
<Menu mode="horizontal" items={items} style={{ flex: 1, minWidth: 0 }} />
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Common Mistakes
|
|
85
|
+
- **Use `items` prop**, not JSX children (`<Menu.Item>`) — deprecated
|
|
86
|
+
- **`openKeys` (controlled) requires `onOpenChange`** — or submenus never open; use `defaultOpenKeys` for uncontrolled
|
|
87
|
+
- **`key` must be unique** across the entire items tree
|
|
88
|
+
- **`inlineCollapsed` only works with `mode="inline"`**
|
|
89
|
+
- **Horizontal menu needs `style={{ flex: 1, minWidth: 0 }}`** to handle overflow correctly
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Tabs
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { Tabs } from 'antd';
|
|
97
|
+
import type { TabsProps } from 'antd';
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### TabsProps
|
|
101
|
+
|
|
102
|
+
| Prop | Type | Default | Description |
|
|
103
|
+
|------|------|---------|-------------|
|
|
104
|
+
| `items` | `TabItemType[]` | `[]` | Tab definitions |
|
|
105
|
+
| `activeKey` | `string` | — | Controlled active key |
|
|
106
|
+
| `defaultActiveKey` | `string` | First key | Initial active key (uncontrolled) |
|
|
107
|
+
| `type` | `'line' \| 'card' \| 'editable-card'` | `'line'` | Visual style |
|
|
108
|
+
| `tabPlacement` | `'top' \| 'end' \| 'bottom' \| 'start'` | `'top'` | Tab bar position |
|
|
109
|
+
| `size` | `'large' \| 'middle' \| 'small'` | `'middle'` | Tab size |
|
|
110
|
+
| `centered` | `boolean` | `false` | Center the tab bar |
|
|
111
|
+
| `destroyOnHidden` | `boolean` | `false` | Unmount inactive panes |
|
|
112
|
+
| `animated` | `boolean \| { inkBar, tabPane }` | `{ inkBar: true, tabPane: false }` | Animation config |
|
|
113
|
+
| `tabBarExtraContent` | `ReactNode \| { left?, right? }` | — | Extra content in tab bar |
|
|
114
|
+
| `onChange` | `(activeKey: string) => void` | — | Active tab change |
|
|
115
|
+
| `onEdit` | `(targetKey, action: 'add' \| 'remove') => void` | — | Add/remove (editable-card only) |
|
|
116
|
+
|
|
117
|
+
### TabItemType
|
|
118
|
+
|
|
119
|
+
| Prop | Type | Default | Description |
|
|
120
|
+
|------|------|---------|-------------|
|
|
121
|
+
| `key` | `string` | — | Unique identifier |
|
|
122
|
+
| `label` | `ReactNode` | — | Tab header |
|
|
123
|
+
| `icon` | `ReactNode` | — | Icon in header |
|
|
124
|
+
| `children` | `ReactNode` | — | Tab pane content |
|
|
125
|
+
| `disabled` | `boolean` | `false` | Disable the tab |
|
|
126
|
+
| `closable` | `boolean` | `true` | Show close button (editable-card) |
|
|
127
|
+
| `destroyOnHidden` | `boolean` | `false` | Per-tab unmount override |
|
|
128
|
+
| `forceRender` | `boolean` | `false` | Render before first activation |
|
|
129
|
+
|
|
130
|
+
### Patterns
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
// Basic
|
|
134
|
+
const items: TabsProps['items'] = [
|
|
135
|
+
{ key: '1', label: 'Tab 1', icon: <AppleOutlined />, children: <Content /> },
|
|
136
|
+
{ key: '2', label: 'Tab 2', children: <Content />, disabled: true },
|
|
137
|
+
];
|
|
138
|
+
<Tabs defaultActiveKey="1" items={items} onChange={setActiveKey} />
|
|
139
|
+
|
|
140
|
+
// Editable-card (add/remove tabs)
|
|
141
|
+
const onEdit = (targetKey: string, action: 'add' | 'remove') => {
|
|
142
|
+
if (action === 'add') addTab();
|
|
143
|
+
else setItems(items.filter(i => i.key !== targetKey));
|
|
144
|
+
};
|
|
145
|
+
<Tabs type="editable-card" activeKey={activeKey} onChange={setActiveKey}
|
|
146
|
+
onEdit={onEdit} items={items} />
|
|
147
|
+
|
|
148
|
+
// Side placement + extra content
|
|
149
|
+
<Tabs tabPlacement="start" items={items}
|
|
150
|
+
tabBarExtraContent={{ right: <Button>Action</Button> }} />
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Common Mistakes
|
|
154
|
+
- **`tabPosition` is deprecated** — use `tabPlacement`; values changed: `'left'/'right'` → `'start'/'end'`
|
|
155
|
+
- **`destroyInactiveTabPane` is deprecated** — use `destroyOnHidden`
|
|
156
|
+
- **`onEdit` only fires for `type="editable-card"`**
|
|
157
|
+
- **Tab `key` must be a string**, even for numeric IDs
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Layout
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { Layout } from 'antd';
|
|
165
|
+
const { Header, Sider, Content, Footer } = Layout;
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Layout.Sider Props
|
|
169
|
+
|
|
170
|
+
| Prop | Type | Default | Description |
|
|
171
|
+
|------|------|---------|-------------|
|
|
172
|
+
| `collapsed` | `boolean` | — | Controlled collapsed state |
|
|
173
|
+
| `collapsible` | `boolean` | `false` | Show collapse trigger |
|
|
174
|
+
| `defaultCollapsed` | `boolean` | `false` | Initial state (uncontrolled) |
|
|
175
|
+
| `collapsedWidth` | `number \| string` | `80` | Width when collapsed; `0` = fully hidden |
|
|
176
|
+
| `width` | `number \| string` | `200` | Width when expanded |
|
|
177
|
+
| `breakpoint` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'xxl'` | — | Responsive auto-collapse |
|
|
178
|
+
| `theme` | `'light' \| 'dark'` | `'dark'` | Sider color scheme |
|
|
179
|
+
| `trigger` | `ReactNode` | — | Custom trigger; `null` = hide trigger |
|
|
180
|
+
| `reverseArrow` | `boolean` | `false` | Flip arrow (for right-side siders) |
|
|
181
|
+
| `onCollapse` | `(collapsed, type) => void` | — | Collapse state change |
|
|
182
|
+
| `onBreakpoint` | `(broken: boolean) => void` | — | Responsive breakpoint hit |
|
|
183
|
+
|
|
184
|
+
### Patterns
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
// Classic admin dashboard
|
|
188
|
+
<Layout style={{ minHeight: '100vh' }}>
|
|
189
|
+
<Sider collapsible collapsed={collapsed} onCollapse={setCollapsed}>
|
|
190
|
+
<Menu theme="dark" mode="inline" items={menuItems} />
|
|
191
|
+
</Sider>
|
|
192
|
+
<Layout>
|
|
193
|
+
<Header style={{ padding: 0, background: colorBgContainer }} />
|
|
194
|
+
<Content style={{ margin: 16 }}>
|
|
195
|
+
<div style={{ padding: 24, background: colorBgContainer, borderRadius: borderRadiusLG }}>
|
|
196
|
+
Page Content
|
|
197
|
+
</div>
|
|
198
|
+
</Content>
|
|
199
|
+
<Footer style={{ textAlign: 'center' }}>App ©{new Date().getFullYear()}</Footer>
|
|
200
|
+
</Layout>
|
|
201
|
+
</Layout>
|
|
202
|
+
|
|
203
|
+
// Custom trigger in header (not Sider)
|
|
204
|
+
<Sider trigger={null} collapsible collapsed={collapsed}>...</Sider>
|
|
205
|
+
<Header>
|
|
206
|
+
<Button type="text" icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
|
207
|
+
onClick={() => setCollapsed(!collapsed)} />
|
|
208
|
+
</Header>
|
|
209
|
+
|
|
210
|
+
// Responsive auto-collapse at lg
|
|
211
|
+
<Sider breakpoint="lg" collapsedWidth="0" onBreakpoint={console.log}>
|
|
212
|
+
<Menu theme="dark" mode="inline" items={menuItems} />
|
|
213
|
+
</Sider>
|
|
214
|
+
|
|
215
|
+
// Sticky sider (scrollable content)
|
|
216
|
+
<Layout hasSider>
|
|
217
|
+
<Sider style={{ overflow: 'auto', height: '100vh', position: 'sticky', top: 0, insetInlineStart: 0 }}>
|
|
218
|
+
...
|
|
219
|
+
</Sider>
|
|
220
|
+
<Layout>...</Layout>
|
|
221
|
+
</Layout>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Common Mistakes
|
|
225
|
+
- **Add `hasSider` for SSR** — prevents layout flash during hydration
|
|
226
|
+
- **`trigger={null}` requires your own toggle mechanism**
|
|
227
|
+
- **Sider `theme` and Menu `theme` must match** or background colors conflict
|
|
228
|
+
- **`collapsedWidth={0}` shows a floating trigger button** — style it with `zeroWidthTriggerStyle`
|
|
229
|
+
- **Outer Layout needs `minHeight: '100vh'`** for full-page dashboard backgrounds
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Grid (Row / Col)
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { Row, Col, Grid } from 'antd';
|
|
237
|
+
const { useBreakpoint } = Grid;
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
24-column Flex-based layout system.
|
|
241
|
+
|
|
242
|
+
### Breakpoints
|
|
243
|
+
|
|
244
|
+
| Name | Min Width |
|
|
245
|
+
|------|-----------|
|
|
246
|
+
| `xs` | < 576px |
|
|
247
|
+
| `sm` | ≥ 576px |
|
|
248
|
+
| `md` | ≥ 768px |
|
|
249
|
+
| `lg` | ≥ 992px |
|
|
250
|
+
| `xl` | ≥ 1200px |
|
|
251
|
+
| `xxl` | ≥ 1600px |
|
|
252
|
+
|
|
253
|
+
### Row Props
|
|
254
|
+
|
|
255
|
+
| Prop | Type | Default | Description |
|
|
256
|
+
|------|------|---------|-------------|
|
|
257
|
+
| `gutter` | `number \| [h, v] \| { xs, sm, md, lg, xl, xxl }` | `0` | Column spacing |
|
|
258
|
+
| `justify` | `'start' \| 'end' \| 'center' \| 'space-around' \| 'space-between' \| 'space-evenly'` | `'start'` | Horizontal distribution |
|
|
259
|
+
| `align` | `'top' \| 'middle' \| 'bottom' \| 'stretch'` | `'top'` | Vertical alignment |
|
|
260
|
+
| `wrap` | `boolean` | `true` | Whether columns wrap |
|
|
261
|
+
|
|
262
|
+
### Col Props
|
|
263
|
+
|
|
264
|
+
| Prop | Type | Default | Description |
|
|
265
|
+
|------|------|---------|-------------|
|
|
266
|
+
| `span` | `number` | — | Columns to span (0–24); `0` = hidden |
|
|
267
|
+
| `offset` | `number` | `0` | Left offset columns |
|
|
268
|
+
| `order` | `number` | `0` | Flex order |
|
|
269
|
+
| `push` / `pull` | `number` | `0` | Visual shift (no DOM change) |
|
|
270
|
+
| `flex` | `number \| string` | — | CSS flex value |
|
|
271
|
+
| `xs/sm/md/lg/xl/xxl` | `number \| ColSize` | — | Responsive config |
|
|
272
|
+
|
|
273
|
+
`ColSize = { span?, offset?, order?, push?, pull?, flex? }`
|
|
274
|
+
|
|
275
|
+
### Patterns
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
// Responsive card grid
|
|
279
|
+
<Row gutter={[16, 16]}>
|
|
280
|
+
<Col xs={24} sm={12} md={8} lg={6}><Card /></Col>
|
|
281
|
+
<Col xs={24} sm={12} md={8} lg={6}><Card /></Col>
|
|
282
|
+
<Col xs={24} sm={12} md={8} lg={6}><Card /></Col>
|
|
283
|
+
<Col xs={24} sm={12} md={8} lg={6}><Card /></Col>
|
|
284
|
+
</Row>
|
|
285
|
+
|
|
286
|
+
// Flex ratio layout
|
|
287
|
+
<Row>
|
|
288
|
+
<Col flex={2}>2/5</Col>
|
|
289
|
+
<Col flex={3}>3/5</Col>
|
|
290
|
+
</Row>
|
|
291
|
+
|
|
292
|
+
// Fixed + auto-fill
|
|
293
|
+
<Row>
|
|
294
|
+
<Col flex="100px">Fixed</Col>
|
|
295
|
+
<Col flex="auto">Fills rest</Col>
|
|
296
|
+
</Row>
|
|
297
|
+
|
|
298
|
+
// Responsive hook
|
|
299
|
+
const screens = useBreakpoint();
|
|
300
|
+
// { xs: true, sm: true, md: false, ... }
|
|
301
|
+
const isMobile = !screens.md;
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Common Mistakes
|
|
305
|
+
- **Spans must sum ≤ 24** or columns wrap (by design)
|
|
306
|
+
- **`gutter` adds padding to Col, negative margin to Row** — don't add extra padding to Col children
|
|
307
|
+
- **Nested grids**: always `Row > Col > Row > Col` — never Col directly inside Col
|
|
308
|
+
- **`offset` vs `push`**: `offset` counts toward total span, `push` is visual-only
|
|
309
|
+
- **Breakpoints are mobile-first** — `xs` applies at all sizes unless overridden
|
|
310
|
+
- **`useBreakpoint` may return `undefined` on SSR** — use strict `=== true` comparisons
|