@wangs-ui/skills 1.0.39 → 1.0.41
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/dist/bin.js +1 -1
- package/dist/index.js +1 -1
- package/dist/skills/create-form/SKILL.md +45 -144
- package/dist/skills/data-table/SKILL.md +51 -161
- package/dist/skills/dialog-modal/SKILL.md +41 -114
- package/dist/skills/i18n-usage/SKILL.md +65 -70
- package/dist/skills/layout-navigation/SKILL.md +44 -45
- package/dist/skills/react19-compiler-typescript/SKILL.md +388 -0
- package/dist/skills/typescript-strict-typing/SKILL.md +317 -0
- package/dist/skills/wangs-ui-components/SKILL.md +48 -29
- package/dist/src-Dolm1urJ.js +244 -0
- package/package.json +1 -1
- package/skills/create-form/SKILL.md +45 -144
- package/skills/data-table/SKILL.md +51 -161
- package/skills/dialog-modal/SKILL.md +41 -114
- package/skills/i18n-usage/SKILL.md +65 -70
- package/skills/layout-navigation/SKILL.md +44 -45
- package/skills/react19-compiler-typescript/SKILL.md +388 -0
- package/skills/typescript-strict-typing/SKILL.md +317 -0
- package/skills/wangs-ui-components/SKILL.md +48 -29
- package/dist/src-95qOyh-g.js +0 -236
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as listSkills, n as updateSkills, r as addSkills, t as removeSkills } from "./src-
|
|
2
|
+
import { i as listSkills, n as updateSkills, r as addSkills, t as removeSkills } from "./src-Dolm1urJ.js";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
//#region bin.ts
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as getAgentSkillDirs, c as isSkillInstalled, d as loadAllSkills, i as listSkills, l as removeSkill, n as updateSkills, o as getInstalledSkills, r as addSkills, s as installSkill, t as removeSkills, u as getSkill } from "./src-
|
|
1
|
+
import { a as getAgentSkillDirs, c as isSkillInstalled, d as loadAllSkills, i as listSkills, l as removeSkill, n as updateSkills, o as getInstalledSkills, r as addSkills, s as installSkill, t as removeSkills, u as getSkill } from "./src-Dolm1urJ.js";
|
|
2
2
|
export { addSkills, getAgentSkillDirs, getInstalledSkills, getSkill, installSkill, isSkillInstalled, listSkills, loadAllSkills, removeSkill, removeSkills, updateSkills };
|
|
@@ -1,166 +1,67 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-form
|
|
3
|
-
description:
|
|
3
|
+
description: Architecture, validation workflows, and MCP discovery protocol for building forms and input controls with @wangs-ui/react-core.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Skill:
|
|
6
|
+
# Skill: Form Architecture & Validation Workflows
|
|
7
7
|
|
|
8
|
-
Use this skill when building
|
|
8
|
+
Use this skill when building forms, data entry panels, settings pages, or multipart forms in Wangs UI applications.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
## 1. MCP Inspection
|
|
12
|
+
## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Do **NOT** hardcode or guess prop names, field configurations, or validation options. Retrieve active component definitions and live implementation stories directly from MCP:
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
- `get-documentation({ id: "datepicker" })` — Check `selectionMode` (`single`, `range`, `multiple`) and date format props.
|
|
18
|
-
- `get-documentation({ id: "multiselect" })` — Check chips display and filter behavior.
|
|
19
|
-
- `get-documentation({ id: "fileupload" })` — Check accepted mime types and upload handlers.
|
|
16
|
+
### Inspect Component & Form Contracts:
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import Button from '@wangs-ui/react-core/primitive/button';
|
|
31
|
-
import InputText from '@wangs-ui/react-core/primitive/inputtext';
|
|
32
|
-
import Select from '@wangs-ui/react-core/primitive/select';
|
|
33
|
-
import { Form, Field } from '@wangs-ui/react-core';
|
|
34
|
-
import { useFormControl } from '@wangs-ui/form';
|
|
35
|
-
import { useI18n } from '@wangs-ui/react-i18n';
|
|
36
|
-
|
|
37
|
-
interface UserFormValues {
|
|
38
|
-
fullName: string;
|
|
39
|
-
email: string;
|
|
40
|
-
role: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export default function UserForm({ onSuccess }: { onSuccess?: () => void }) {
|
|
44
|
-
const { t } = useI18n();
|
|
45
|
-
const formControl = useFormControl<UserFormValues>({ type: 'json' });
|
|
46
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
47
|
-
|
|
48
|
-
const roleOptions = [
|
|
49
|
-
{ label: t('Administrator'), value: 'admin' },
|
|
50
|
-
{ label: t('Operator'), value: 'operator' },
|
|
51
|
-
{ label: t('Viewer'), value: 'viewer' },
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
const handleSubmit = async (values: UserFormValues) => {
|
|
55
|
-
setIsSubmitting(true);
|
|
56
|
-
try {
|
|
57
|
-
// Execute API call: await api.createUser(values);
|
|
58
|
-
onSuccess?.();
|
|
59
|
-
} catch (err: any) {
|
|
60
|
-
// Map server validation error directly to field
|
|
61
|
-
if (err?.fieldErrors?.email) {
|
|
62
|
-
formControl.setError('email', {
|
|
63
|
-
type: 'server',
|
|
64
|
-
message: err.fieldErrors.email,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
} finally {
|
|
68
|
-
setIsSubmitting(false);
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<Card className="p-6">
|
|
74
|
-
<Form control={formControl} onSubmit={handleSubmit} className="flex flex-col gap-m">
|
|
75
|
-
<h2 className="heading-2">{t('User Information')}</h2>
|
|
76
|
-
|
|
77
|
-
{/* Text Field */}
|
|
78
|
-
<Field<string>
|
|
79
|
-
name="fullName"
|
|
80
|
-
label={t('Full Name')}
|
|
81
|
-
required
|
|
82
|
-
rules={{ required: t('Full name is required') }}
|
|
83
|
-
>
|
|
84
|
-
{(field) => (
|
|
85
|
-
<InputText {...field} placeholder={t('e.g. Jane Doe')} value={field.value || ''} />
|
|
86
|
-
)}
|
|
87
|
-
</Field>
|
|
88
|
-
|
|
89
|
-
{/* Email Field with Regex Validation */}
|
|
90
|
-
<Field<string>
|
|
91
|
-
name="email"
|
|
92
|
-
label={t('Email Address')}
|
|
93
|
-
required
|
|
94
|
-
rules={{
|
|
95
|
-
required: t('Email is required'),
|
|
96
|
-
pattern: {
|
|
97
|
-
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
98
|
-
message: t('Enter a valid email address'),
|
|
99
|
-
},
|
|
100
|
-
}}
|
|
101
|
-
>
|
|
102
|
-
{(field) => (
|
|
103
|
-
<InputText {...field} placeholder={t('name@company.com')} value={field.value || ''} />
|
|
104
|
-
)}
|
|
105
|
-
</Field>
|
|
106
|
-
|
|
107
|
-
{/* Select Dropdown Field */}
|
|
108
|
-
<Field<string>
|
|
109
|
-
name="role"
|
|
110
|
-
label={t('Access Role')}
|
|
111
|
-
required
|
|
112
|
-
rules={{ required: t('Role selection is required') }}
|
|
113
|
-
>
|
|
114
|
-
{(field) => (
|
|
115
|
-
<Select
|
|
116
|
-
{...field}
|
|
117
|
-
options={roleOptions}
|
|
118
|
-
placeholder={t('Select role')}
|
|
119
|
-
value={field.value}
|
|
120
|
-
onChange={(e) => field.onChange(e.value)}
|
|
121
|
-
/>
|
|
122
|
-
)}
|
|
123
|
-
</Field>
|
|
124
|
-
|
|
125
|
-
{/* Form Actions */}
|
|
126
|
-
<div className="flex justify-end gap-s pt-s">
|
|
127
|
-
<Button
|
|
128
|
-
type="button"
|
|
129
|
-
variant="text"
|
|
130
|
-
label={t('Reset')}
|
|
131
|
-
onClick={() => formControl.reset()}
|
|
132
|
-
disabled={isSubmitting}
|
|
133
|
-
/>
|
|
134
|
-
<Button type="submit" label={t('Save User')} severity="primary" loading={isSubmitting} />
|
|
135
|
-
</div>
|
|
136
|
-
</Form>
|
|
137
|
-
</Card>
|
|
138
|
-
);
|
|
139
|
-
}
|
|
18
|
+
```json
|
|
19
|
+
get-documentation({ "id": "form" })
|
|
20
|
+
get-documentation({ "id": "field" })
|
|
21
|
+
get-documentation({ "id": "input" })
|
|
22
|
+
get-documentation({ "id": "numberinput" })
|
|
23
|
+
get-documentation({ "id": "select" })
|
|
24
|
+
get-documentation({ "id": "multiselect" })
|
|
25
|
+
get-documentation({ "id": "datepicker" })
|
|
26
|
+
get-documentation({ "id": "fileupload" })
|
|
140
27
|
```
|
|
141
28
|
|
|
142
|
-
|
|
29
|
+
### Inspect Live Story Implementations:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
get-documentation-for-story({ "id": "form", "storyName": "Default" })
|
|
33
|
+
get-documentation-for-story({ "id": "field", "storyName": "Default" })
|
|
34
|
+
get-documentation-for-story({ "id": "select", "storyName": "Basic" })
|
|
35
|
+
get-documentation-for-story({ "id": "datepicker", "storyName": "Default" })
|
|
36
|
+
get-documentation-for-story({ "id": "fileupload", "storyName": "Default" })
|
|
37
|
+
```
|
|
143
38
|
|
|
144
|
-
|
|
39
|
+
### Inspect Knowledge Graph & Usages:
|
|
145
40
|
|
|
146
|
-
|
|
41
|
+
```json
|
|
42
|
+
query_graph({ "query": "useFormControl" })
|
|
43
|
+
query_graph({ "query": "Field" })
|
|
44
|
+
```
|
|
147
45
|
|
|
148
|
-
|
|
149
|
-
import { useFormControl } from '@wangs-ui/form';
|
|
46
|
+
---
|
|
150
47
|
|
|
151
|
-
|
|
152
|
-
displayName: string;
|
|
153
|
-
avatar: File | null;
|
|
154
|
-
}
|
|
48
|
+
## 2. Form Architecture & State Principles
|
|
155
49
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
50
|
+
1. **State & Control**:
|
|
51
|
+
- Standard REST payload forms use `useFormControl` with JSON mode.
|
|
52
|
+
- Multipart file upload workflows use `useFormControl` with FormData mode.
|
|
53
|
+
2. **Field Composition**:
|
|
54
|
+
- Form inputs are wrapped with `<Field>` layout containers for unified label, tooltip, helper text, and error rendering.
|
|
55
|
+
- Exact props, slot rendering functions, and field binding options must be retrieved via MCP (`get-documentation({ "id": "field" })`).
|
|
56
|
+
3. **Server Validation Error Mapping**:
|
|
57
|
+
- Backend validation responses (e.g. `422 Unprocessable Entity`) are mapped back into the form instance via `formControl.setError()`.
|
|
58
|
+
4. **Submission Lifecycle**:
|
|
59
|
+
- In-flight network requests should manage loading state on submit actions and prevent accidental reset during mutations.
|
|
159
60
|
|
|
160
61
|
---
|
|
161
62
|
|
|
162
|
-
##
|
|
63
|
+
## 3. Mandatory Implementation Rules
|
|
163
64
|
|
|
164
|
-
1. **Always
|
|
165
|
-
2. **
|
|
166
|
-
3. **
|
|
65
|
+
1. **Always Query MCP First**: Never guess input props or event signatures; obtain the exact types from `get-documentation`.
|
|
66
|
+
2. **Strict Subpath Imports**: All components must be imported via their granular subpath (`@wangs-ui/react-core/primitive/*`, `@wangs-ui/form`).
|
|
67
|
+
3. **Translate All Visible Strings**: Every field label, placeholder, helper text, and error message must be wrapped in `t('...')` from `@wangs-ui/react-i18n`.
|
|
@@ -1,178 +1,68 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: data-table
|
|
3
|
-
description:
|
|
3
|
+
description: Architecture, workflows, and MCP discovery protocol for building DataTables with sorting, pagination, filtering, selection, and export.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Skill:
|
|
6
|
+
# Skill: DataTable Architecture & Integration Workflows
|
|
7
7
|
|
|
8
|
-
Use this skill when
|
|
8
|
+
Use this skill when implementing data grids, server-paginated tables, filterable listing views, or batch management interfaces with `@wangs-ui/react-core`.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
## 1. MCP Inspection
|
|
12
|
+
## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)
|
|
13
13
|
|
|
14
|
-
Query the MCP server to inspect
|
|
14
|
+
Do **NOT** guess table prop names or hardcode table structures. Query the MCP server dynamically to inspect exact TypeScript signatures, live story implementations, and companion controls:
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
- `get-documentation({ id: "column" })` — Check `body` template, `sortable`, `frozen`, and `headerStyle`.
|
|
18
|
-
- `get-documentation({ id: "tag" })` — Check severity colors for status pill badges (`success`, `warning`, `danger`, `info`).
|
|
16
|
+
### Inspect Component Contracts:
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
```json
|
|
19
|
+
get-documentation({ "id": "datatable" })
|
|
20
|
+
get-documentation({ "id": "exportbutton" })
|
|
21
|
+
get-documentation({ "id": "filtercontainer" })
|
|
22
|
+
get-documentation({ "id": "bulkactionbutton" })
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Inspect Live Story Implementations:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
get-documentation-for-story({ "id": "datatable", "storyName": "Basic" })
|
|
29
|
+
get-documentation-for-story({ "id": "datatable", "storyName": "ServerPagination" })
|
|
30
|
+
get-documentation-for-story({ "id": "datatable", "storyName": "Sortable" })
|
|
31
|
+
get-documentation-for-story({ "id": "datatable", "storyName": "MultipleSelection" })
|
|
32
|
+
get-documentation-for-story({ "id": "datatable", "storyName": "CustomColumn" })
|
|
33
|
+
get-documentation-for-story({ "id": "exportbutton", "storyName": "WithTable" })
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Inspect Knowledge Graph & Usages:
|
|
21
37
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import React, { useState } from 'react';
|
|
26
|
-
import DataTable, { Column } from '@wangs-ui/react-core/primitive/datatable';
|
|
27
|
-
import Button from '@wangs-ui/react-core/primitive/button';
|
|
28
|
-
import InputText from '@wangs-ui/react-core/primitive/inputtext';
|
|
29
|
-
import Select from '@wangs-ui/react-core/primitive/select';
|
|
30
|
-
import Tag from '@wangs-ui/react-core/primitive/tag';
|
|
31
|
-
import Dialog from '@wangs-ui/react-core/primitive/dialog';
|
|
32
|
-
import Card from '@wangs-ui/react-core/primitive/card';
|
|
33
|
-
import { useI18n } from '@wangs-ui/react-i18n';
|
|
34
|
-
import { SearchLine, DeleteBin6Line, EditLine, AddLine } from '@wangs-ui/react-icons';
|
|
35
|
-
|
|
36
|
-
interface CustomerRecord {
|
|
37
|
-
id: string;
|
|
38
|
-
name: string;
|
|
39
|
-
email: string;
|
|
40
|
-
status: 'active' | 'pending' | 'suspended';
|
|
41
|
-
createdAt: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export default function CustomerManagementView() {
|
|
45
|
-
const { t } = useI18n();
|
|
46
|
-
const [records, setRecords] = useState<CustomerRecord[]>([]);
|
|
47
|
-
const [loading, setLoading] = useState(false);
|
|
48
|
-
const [searchQuery, setSearchQuery] = useState('');
|
|
49
|
-
const [selectedStatus, setSelectedStatus] = useState<string | null>(null);
|
|
50
|
-
const [selectedRows, setSelectedRows] = useState<CustomerRecord[]>([]);
|
|
51
|
-
const [deleteTarget, setDeleteTarget] = useState<CustomerRecord | null>(null);
|
|
52
|
-
|
|
53
|
-
// Status Badge Template
|
|
54
|
-
const statusTemplate = (row: CustomerRecord) => {
|
|
55
|
-
const severityMap: Record<string, 'success' | 'warning' | 'danger'> = {
|
|
56
|
-
active: 'success',
|
|
57
|
-
pending: 'warning',
|
|
58
|
-
suspended: 'danger',
|
|
59
|
-
};
|
|
60
|
-
return <Tag value={t(row.status)} severity={severityMap[row.status] || 'info'} />;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// Row Actions Template
|
|
64
|
-
const actionsTemplate = (row: CustomerRecord) => (
|
|
65
|
-
<div className="flex items-center gap-xs">
|
|
66
|
-
<Button
|
|
67
|
-
variant="text"
|
|
68
|
-
icon={<EditLine />}
|
|
69
|
-
aria-label={t('Edit')}
|
|
70
|
-
onClick={() => console.log('Edit', row.id)}
|
|
71
|
-
/>
|
|
72
|
-
<Button
|
|
73
|
-
variant="text"
|
|
74
|
-
severity="danger"
|
|
75
|
-
icon={<DeleteBin6Line />}
|
|
76
|
-
aria-label={t('Delete')}
|
|
77
|
-
onClick={() => setDeleteTarget(row)}
|
|
78
|
-
/>
|
|
79
|
-
</div>
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<Card className="flex flex-col gap-m p-6">
|
|
84
|
-
{/* 1. Filter & Search Toolbar */}
|
|
85
|
-
<div className="flex flex-wrap items-center justify-between gap-s">
|
|
86
|
-
<div className="flex flex-wrap items-center gap-s">
|
|
87
|
-
<InputText
|
|
88
|
-
value={searchQuery}
|
|
89
|
-
onChange={(e) => setSearchQuery(e.target.value)}
|
|
90
|
-
placeholder={t('Search customer...')}
|
|
91
|
-
className="w-64"
|
|
92
|
-
/>
|
|
93
|
-
<Select
|
|
94
|
-
value={selectedStatus}
|
|
95
|
-
options={[
|
|
96
|
-
{ label: t('All Statuses'), value: null },
|
|
97
|
-
{ label: t('Active'), value: 'active' },
|
|
98
|
-
{ label: t('Pending'), value: 'pending' },
|
|
99
|
-
{ label: t('Suspended'), value: 'suspended' },
|
|
100
|
-
]}
|
|
101
|
-
onChange={(e) => setSelectedStatus(e.value)}
|
|
102
|
-
placeholder={t('Filter status')}
|
|
103
|
-
/>
|
|
104
|
-
</div>
|
|
105
|
-
|
|
106
|
-
<Button label={t('Add Customer')} icon={<AddLine />} severity="primary" />
|
|
107
|
-
</div>
|
|
108
|
-
|
|
109
|
-
{/* 2. Batch Selection Action Bar */}
|
|
110
|
-
{selectedRows.length > 0 && (
|
|
111
|
-
<div className="flex items-center justify-between rounded bg-primary-50 px-4 py-2 text-primary-900">
|
|
112
|
-
<span className="p font-medium">
|
|
113
|
-
{t('{{count}} items selected', { count: selectedRows.length })}
|
|
114
|
-
</span>
|
|
115
|
-
<Button
|
|
116
|
-
size="small"
|
|
117
|
-
severity="danger"
|
|
118
|
-
label={t('Delete Selected')}
|
|
119
|
-
icon={<DeleteBin6Line />}
|
|
120
|
-
onClick={() => console.log('Batch delete', selectedRows)}
|
|
121
|
-
/>
|
|
122
|
-
</div>
|
|
123
|
-
)}
|
|
124
|
-
|
|
125
|
-
{/* 3. Paginated DataTable */}
|
|
126
|
-
<DataTable
|
|
127
|
-
value={records}
|
|
128
|
-
loading={loading}
|
|
129
|
-
selection={selectedRows}
|
|
130
|
-
onSelectionChange={(e) => setSelectedRows(e.value)}
|
|
131
|
-
dataKey="id"
|
|
132
|
-
paginator
|
|
133
|
-
rows={10}
|
|
134
|
-
rowsPerPageOptions={[10, 25, 50]}
|
|
135
|
-
emptyMessage={t('No customers found')}
|
|
136
|
-
>
|
|
137
|
-
<Column selectionMode="multiple" headerStyle={{ width: '3rem' }} />
|
|
138
|
-
<Column field="name" header={t('Customer Name')} sortable />
|
|
139
|
-
<Column field="email" header={t('Email')} sortable />
|
|
140
|
-
<Column field="status" header={t('Status')} body={statusTemplate} sortable />
|
|
141
|
-
<Column header={t('Actions')} body={actionsTemplate} headerStyle={{ width: '6rem' }} />
|
|
142
|
-
</DataTable>
|
|
143
|
-
|
|
144
|
-
{/* 4. Delete Confirmation Dialog */}
|
|
145
|
-
<Dialog
|
|
146
|
-
visible={!!deleteTarget}
|
|
147
|
-
onHide={() => setDeleteTarget(null)}
|
|
148
|
-
header={t('Delete Customer')}
|
|
149
|
-
footer={
|
|
150
|
-
<div className="flex justify-end gap-xs">
|
|
151
|
-
<Button variant="text" label={t('Cancel')} onClick={() => setDeleteTarget(null)} />
|
|
152
|
-
<Button
|
|
153
|
-
severity="danger"
|
|
154
|
-
label={t('Delete')}
|
|
155
|
-
onClick={() => {
|
|
156
|
-
// Execute delete API
|
|
157
|
-
setDeleteTarget(null);
|
|
158
|
-
}}
|
|
159
|
-
/>
|
|
160
|
-
</div>
|
|
161
|
-
}
|
|
162
|
-
>
|
|
163
|
-
<p className="p">
|
|
164
|
-
{t('Are you sure you want to delete {{name}}?', { name: deleteTarget?.name })}
|
|
165
|
-
</p>
|
|
166
|
-
</Dialog>
|
|
167
|
-
</Card>
|
|
168
|
-
);
|
|
169
|
-
}
|
|
38
|
+
```json
|
|
39
|
+
query_graph({ "query": "DataTable" })
|
|
40
|
+
query_graph({ "query": "useDataTableFetch" })
|
|
170
41
|
```
|
|
171
42
|
|
|
172
43
|
---
|
|
173
44
|
|
|
174
|
-
##
|
|
45
|
+
## 2. Core Architecture & Mental Model
|
|
46
|
+
|
|
47
|
+
The Wangs UI `DataTable` is built on a modular, headless-first architecture:
|
|
48
|
+
|
|
49
|
+
1. **Declarative Column Definitions (`TableColumn<T>[]`)**:
|
|
50
|
+
Columns are configured as typed array objects, not as JSX children. Check `get-documentation({ "id": "datatable" })` for column field types.
|
|
51
|
+
2. **Table Instance Hook (`useDataTable`)**:
|
|
52
|
+
Coordinates table state (sorting, pagination, selection, column ordering, pinning, visibility).
|
|
53
|
+
3. **Data Fetching Hook (`useDataTableFetch`)**:
|
|
54
|
+
Feeds server-side data, handles loading indicators, manages query parameters (`search`, `filter`, `sort`, `page`, `limit`), and debounces requests automatically.
|
|
55
|
+
4. **Ecosystem Companions**:
|
|
56
|
+
- `FilterContainer` & `FilterToggleButton`: Filter popovers and faceted search.
|
|
57
|
+
- `ExportButton`: Client/server export to Excel, CSV, PDF, or Print.
|
|
58
|
+
- `BulkActionButton`: Contextual batch actions triggered when rows are selected.
|
|
59
|
+
- `CustomColumn`: User-controlled column ordering, visibility toggling, and pinning.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 3. Mandatory Implementation Rules
|
|
175
64
|
|
|
176
|
-
1. **Always
|
|
177
|
-
2. **
|
|
178
|
-
3. **
|
|
65
|
+
1. **Query MCP for Current Code Patterns**: Always run `get-documentation-for-story` for `datatable` before drafting code.
|
|
66
|
+
2. **Strict Subpath Imports**: Import via `@wangs-ui/react-core/primitive/datatable` and companion primitive paths.
|
|
67
|
+
3. **Always Translate Visible Copy**: All column header labels, empty state messages, and action button labels must be wrapped in `t('...')` from `@wangs-ui/react-i18n`.
|
|
68
|
+
4. **Stable Row Identity**: Always configure a unique key identifier for stable selection and row identity.
|
|
@@ -1,131 +1,58 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dialog-modal
|
|
3
|
-
description:
|
|
3
|
+
description: Patterns, overlay selection criteria, and MCP discovery protocol for Dialog, Modal, and DialogForm components in Wangs UI.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Skill:
|
|
6
|
+
# Skill: Dialog, Modal & Overlay Workflows
|
|
7
7
|
|
|
8
|
-
Use this skill when building interactive modals, create/edit
|
|
8
|
+
Use this skill when building interactive modals, create/edit dialog forms, destructive action confirmations, or slide-in overlay panels.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
## 1. MCP Inspection
|
|
12
|
+
## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)
|
|
13
13
|
|
|
14
|
-
Query the MCP server to
|
|
14
|
+
Do **NOT** guess overlay props, event names, or footer slots. Query the MCP server dynamically to inspect exact contracts and live story implementations:
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
- `get-documentation({ id: "modal" })` — Check fullscreen modes, size variants, and slide-in drawer options.
|
|
18
|
-
- `get-documentation({ id: "toast" })` — Check severity toasts (`success`, `error`, `info`, `warn`) to trigger after modal actions.
|
|
16
|
+
### Inspect Overlay Contracts:
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
```json
|
|
19
|
+
get-documentation({ "id": "dialog" })
|
|
20
|
+
get-documentation({ "id": "dialogform" })
|
|
21
|
+
get-documentation({ "id": "modal" })
|
|
22
|
+
get-documentation({ "id": "toast" })
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Inspect Live Story Implementations:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
get-documentation-for-story({ "id": "dialog", "storyName": "Confirmation" })
|
|
29
|
+
get-documentation-for-story({ "id": "dialogform", "storyName": "Default" })
|
|
30
|
+
get-documentation-for-story({ "id": "modal", "storyName": "Default" })
|
|
31
|
+
```
|
|
21
32
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
import React, { useState, useEffect } from 'react';
|
|
28
|
-
import Dialog from '@wangs-ui/react-core/primitive/dialog';
|
|
29
|
-
import Button from '@wangs-ui/react-core/primitive/button';
|
|
30
|
-
import InputText from '@wangs-ui/react-core/primitive/inputtext';
|
|
31
|
-
import { Form, Field } from '@wangs-ui/react-core';
|
|
32
|
-
import { useFormControl } from '@wangs-ui/form';
|
|
33
|
-
import { useI18n } from '@wangs-ui/react-i18n';
|
|
34
|
-
|
|
35
|
-
interface EditItemModel {
|
|
36
|
-
title: string;
|
|
37
|
-
code: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface ItemModalProps {
|
|
41
|
-
visible: boolean;
|
|
42
|
-
item?: EditItemModel | null;
|
|
43
|
-
onHide: () => void;
|
|
44
|
-
onSaved: (item: EditItemModel) => void;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export default function ItemFormModal({ visible, item, onHide, onSaved }: ItemModalProps) {
|
|
48
|
-
const { t } = useI18n();
|
|
49
|
-
const formControl = useFormControl<EditItemModel>({ type: 'json' });
|
|
50
|
-
const [saving, setSaving] = useState(false);
|
|
51
|
-
|
|
52
|
-
// Sync form values when modal opens or item changes
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
if (visible) {
|
|
55
|
-
formControl.reset(item || { title: '', code: '' });
|
|
56
|
-
}
|
|
57
|
-
}, [visible, item]);
|
|
58
|
-
|
|
59
|
-
const handleFormSubmit = async (values: EditItemModel) => {
|
|
60
|
-
setSaving(true);
|
|
61
|
-
try {
|
|
62
|
-
// Execute API call: await api.save(values);
|
|
63
|
-
onSaved(values);
|
|
64
|
-
onHide();
|
|
65
|
-
} finally {
|
|
66
|
-
setSaving(false);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const footerActions = (
|
|
71
|
-
<div className="flex justify-end gap-xs">
|
|
72
|
-
<Button type="button" variant="text" label={t('Cancel')} onClick={onHide} disabled={saving} />
|
|
73
|
-
<Button
|
|
74
|
-
type="submit"
|
|
75
|
-
form="modal-item-form"
|
|
76
|
-
label={item ? t('Save Changes') : t('Create Item')}
|
|
77
|
-
severity="primary"
|
|
78
|
-
loading={saving}
|
|
79
|
-
/>
|
|
80
|
-
</div>
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<Dialog
|
|
85
|
-
visible={visible}
|
|
86
|
-
onHide={() => !saving && onHide()}
|
|
87
|
-
header={item ? t('Edit Item') : t('New Item')}
|
|
88
|
-
footer={footerActions}
|
|
89
|
-
style={{ width: '450px' }}
|
|
90
|
-
modal
|
|
91
|
-
>
|
|
92
|
-
<Form
|
|
93
|
-
id="modal-item-form"
|
|
94
|
-
control={formControl}
|
|
95
|
-
onSubmit={handleFormSubmit}
|
|
96
|
-
className="flex flex-col gap-m pt-xs"
|
|
97
|
-
>
|
|
98
|
-
<Field<string>
|
|
99
|
-
name="title"
|
|
100
|
-
label={t('Item Title')}
|
|
101
|
-
required
|
|
102
|
-
rules={{ required: t('Title is required') }}
|
|
103
|
-
>
|
|
104
|
-
{(field) => (
|
|
105
|
-
<InputText {...field} placeholder={t('Enter title')} value={field.value || ''} />
|
|
106
|
-
)}
|
|
107
|
-
</Field>
|
|
108
|
-
|
|
109
|
-
<Field<string>
|
|
110
|
-
name="code"
|
|
111
|
-
label={t('Item Code')}
|
|
112
|
-
required
|
|
113
|
-
rules={{ required: t('Code is required') }}
|
|
114
|
-
>
|
|
115
|
-
{(field) => (
|
|
116
|
-
<InputText {...field} placeholder={t('e.g. SKU-100')} value={field.value || ''} />
|
|
117
|
-
)}
|
|
118
|
-
</Field>
|
|
119
|
-
</Form>
|
|
120
|
-
</Dialog>
|
|
121
|
-
);
|
|
122
|
-
}
|
|
33
|
+
### Inspect Knowledge Graph & Usages:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
query_graph({ "query": "Dialog" })
|
|
37
|
+
query_graph({ "query": "DialogForm" })
|
|
123
38
|
```
|
|
124
39
|
|
|
125
40
|
---
|
|
126
41
|
|
|
127
|
-
##
|
|
42
|
+
## 2. Overlay Selection Matrix
|
|
43
|
+
|
|
44
|
+
| Component | Primary Use Case | Key Characteristics |
|
|
45
|
+
| :--------------- | :-------------------------------------------- | :------------------------------------------------------------------------------------ |
|
|
46
|
+
| **`Dialog`** | Confirmations, alerts, simple detail previews | Standard `header`, `footer`, and body layout; built-in backdrop dimming. |
|
|
47
|
+
| **`DialogForm`** | Create/Edit forms embedded inside a dialog | Built-in form submit/cancel action bar, dirty state tracking, and submit lifecycle. |
|
|
48
|
+
| **`Modal`** | Slide-in drawers, complex custom viewports | Headless overlay primitive with flexible animations, size variants, and drawer modes. |
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 3. Mandatory Implementation Rules
|
|
128
53
|
|
|
129
|
-
1. **
|
|
130
|
-
2. **
|
|
131
|
-
3. **
|
|
54
|
+
1. **Query MCP for Current Code Patterns**: Always inspect `dialog`, `dialogform`, or `modal` stories via MCP before writing overlay code.
|
|
55
|
+
2. **Strict Subpath Imports**: Import via `@wangs-ui/react-core/primitive/dialog`, `@wangs-ui/react-core/primitive/dialogform`, `@wangs-ui/react-core/primitive/modal`, or `@wangs-ui/react-core/primitive/toast`.
|
|
56
|
+
3. **Prevent Dismissal During Async Mutations**: Guard the close handler so users cannot accidentally dismiss the dialog while a mutation request is in-flight.
|
|
57
|
+
4. **Coordinate with Toast Notifications**: Trigger feedback toasts on successful creation, update, or deletion actions.
|
|
58
|
+
5. **Translate All Overlay Copy**: All dialog titles, confirmation descriptions, and button labels must be localized using `t('...')` from `@wangs-ui/react-i18n`.
|