@wangs-ui/skills 1.1.0-alpha.3 → 1.1.0-alpha.7
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 +147 -18
- package/dist/{src-XyTMubnF.js → src-CtM02kKf.js} +2 -2
- package/package.json +1 -1
- package/skills/create-form/SKILL.md +147 -18
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-CtM02kKf.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-CtM02kKf.js";
|
|
2
2
|
export { addSkills, getAgentSkillDirs, getInstalledSkills, getSkill, installSkill, isSkillInstalled, listSkills, loadAllSkills, removeSkill, removeSkills, updateSkills };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-form
|
|
3
|
-
description: Architecture, validation workflows, and MCP discovery protocol for building forms and input controls with @wangs-ui/react-core.
|
|
3
|
+
description: Architecture, validation workflows, strongly-typed forms (useForm, useDialogForm, useWatchField), and MCP discovery protocol for building forms and input controls with @wangs-ui/react-core.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Skill: Form Architecture & Validation Workflows
|
|
7
7
|
|
|
8
|
-
Use this skill when building forms, data entry panels, settings pages, or multipart forms in Wangs UI applications.
|
|
8
|
+
Use this skill when building forms, data entry panels, modal forms, settings pages, or multipart forms in Wangs UI applications.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -18,6 +18,7 @@ Do **NOT** hardcode or guess prop names, field configurations, or validation opt
|
|
|
18
18
|
```json
|
|
19
19
|
get-documentation({ "id": "form" })
|
|
20
20
|
get-documentation({ "id": "field" })
|
|
21
|
+
get-documentation({ "id": "dialogform" })
|
|
21
22
|
get-documentation({ "id": "input" })
|
|
22
23
|
get-documentation({ "id": "numberinput" })
|
|
23
24
|
get-documentation({ "id": "select" })
|
|
@@ -39,29 +40,157 @@ get-documentation-for-story({ "id": "fileupload", "storyName": "Default" })
|
|
|
39
40
|
### Inspect Knowledge Graph & Usages:
|
|
40
41
|
|
|
41
42
|
```json
|
|
42
|
-
query_graph({ "query": "
|
|
43
|
-
query_graph({ "query": "
|
|
43
|
+
query_graph({ "query": "useForm" })
|
|
44
|
+
query_graph({ "query": "useDialogForm" })
|
|
45
|
+
query_graph({ "query": "useWatchField" })
|
|
44
46
|
```
|
|
45
47
|
|
|
46
48
|
---
|
|
47
49
|
|
|
48
|
-
## 2. Form Architecture &
|
|
50
|
+
## 2. Form Architecture & Latest API Patterns
|
|
51
|
+
|
|
52
|
+
### Pattern A: Strongly Typed Forms with `useForm<T>()`
|
|
53
|
+
|
|
54
|
+
For standard page forms, use `useForm<T>()` from `@wangs-ui/react-core/primitive/form`. It returns a strongly-typed `Form`, `Field`, and `control` where `Field`'s `name` prop is constrained to dot-path keys of `T` (`Path<T>`) with full IDE autocomplete and type inference.
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import Button from '@wangs-ui/react-core/primitive/button';
|
|
58
|
+
import { useForm } from '@wangs-ui/react-core/primitive/form';
|
|
59
|
+
import Input from '@wangs-ui/react-core/primitive/input';
|
|
60
|
+
import { useI18n } from '@wangs-ui/react-i18n';
|
|
61
|
+
|
|
62
|
+
interface UserFormData {
|
|
63
|
+
name: string;
|
|
64
|
+
email: string;
|
|
65
|
+
address: {
|
|
66
|
+
city: string;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function UserFormPage() {
|
|
71
|
+
const { t } = useI18n();
|
|
72
|
+
// Strongly-typed Form, Field, and control bound to UserFormData
|
|
73
|
+
const { Form, Field, control } = useForm<UserFormData>();
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<Form control={control} onSubmit={(values) => console.log(values)}>
|
|
77
|
+
<Field required label={t('Full Name')} name="name">
|
|
78
|
+
{({ fieldProps }) => <Input {...fieldProps} placeholder={t('Enter full name')} />}
|
|
79
|
+
</Field>
|
|
80
|
+
|
|
81
|
+
{/* Autocompletes nested dot-path keys */}
|
|
82
|
+
<Field required label={t('City')} name="address.city">
|
|
83
|
+
{({ fieldProps }) => <Input {...fieldProps} placeholder={t('Enter city')} />}
|
|
84
|
+
</Field>
|
|
85
|
+
|
|
86
|
+
<div className="flex gap-2">
|
|
87
|
+
<Button
|
|
88
|
+
label={t('Reset')}
|
|
89
|
+
type="button"
|
|
90
|
+
severity="secondary"
|
|
91
|
+
onClick={() => control.reset()}
|
|
92
|
+
/>
|
|
93
|
+
<Button label={t('Submit')} type="submit" />
|
|
94
|
+
</div>
|
|
95
|
+
</Form>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### Pattern B: Modal Forms with `useDialogForm<T>()`
|
|
103
|
+
|
|
104
|
+
For modal/dialog forms, use `useDialogForm<T>()` from `@wangs-ui/react-core/primitive/dialogform`. It combines a modal `Dialog` with form provider lifecycle, providing automatic modal close on success (`closeOnSubmit`), validation interception, and native Enter-key submission.
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import Button from '@wangs-ui/react-core/primitive/button';
|
|
108
|
+
import { useDialogForm } from '@wangs-ui/react-core/primitive/dialogform';
|
|
109
|
+
import Input from '@wangs-ui/react-core/primitive/input';
|
|
110
|
+
import { useI18n } from '@wangs-ui/react-i18n';
|
|
111
|
+
import { useState } from 'react';
|
|
112
|
+
|
|
113
|
+
interface EditProfileData {
|
|
114
|
+
fullName: string;
|
|
115
|
+
email: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function EditProfileModal() {
|
|
119
|
+
const { t } = useI18n();
|
|
120
|
+
const [open, setOpen] = useState(false);
|
|
121
|
+
const { DialogForm, Field, control } = useDialogForm<EditProfileData>();
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<>
|
|
125
|
+
<Button label={t('Edit Profile')} onClick={() => setOpen(true)} />
|
|
126
|
+
|
|
127
|
+
<DialogForm
|
|
128
|
+
closeOnSubmit
|
|
129
|
+
control={control}
|
|
130
|
+
header={t('Edit Profile')}
|
|
131
|
+
open={open}
|
|
132
|
+
onOpenChange={setOpen}
|
|
133
|
+
onSubmit={(values) => console.log('Saved:', values)}
|
|
134
|
+
footer={
|
|
135
|
+
<div className="flex w-full justify-end gap-2">
|
|
136
|
+
<Button
|
|
137
|
+
label={t('Cancel')}
|
|
138
|
+
severity="secondary"
|
|
139
|
+
type="button"
|
|
140
|
+
variant="outline"
|
|
141
|
+
onClick={() => setOpen(false)}
|
|
142
|
+
/>
|
|
143
|
+
<Button label={t('Save Changes')} type="submit" />
|
|
144
|
+
</div>
|
|
145
|
+
}
|
|
146
|
+
>
|
|
147
|
+
<div className="flex flex-col gap-4">
|
|
148
|
+
<Field required label={t('Full Name')} name="fullName">
|
|
149
|
+
{({ fieldProps }) => <Input {...fieldProps} placeholder="John Doe" />}
|
|
150
|
+
</Field>
|
|
151
|
+
<Field required label={t('Email')} name="email">
|
|
152
|
+
{({ fieldProps }) => (
|
|
153
|
+
<Input {...fieldProps} type="email" placeholder="you@example.com" />
|
|
154
|
+
)}
|
|
155
|
+
</Field>
|
|
156
|
+
</div>
|
|
157
|
+
</DialogForm>
|
|
158
|
+
</>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### Pattern C: Real-Time Field Watching with `useWatchField`
|
|
166
|
+
|
|
167
|
+
To observe real-time field changes without causing the entire form to re-render, use `useWatchField` from `@wangs-ui/form/react`.
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { useWatchField } from '@wangs-ui/form/react';
|
|
171
|
+
|
|
172
|
+
function FormSummaryWatcher({ control }) {
|
|
173
|
+
// Subscribes only to 'username' value changes
|
|
174
|
+
const username = useWatchField({ control, name: 'username' });
|
|
175
|
+
|
|
176
|
+
return <div>Current Username: {username}</div>;
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 3. Submission Types
|
|
49
183
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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.
|
|
184
|
+
| Config | Use case |
|
|
185
|
+
| -------------------------------------------------------------------- | ------------------------- |
|
|
186
|
+
| `useForm<T>()` / `useDialogForm<T>()` | Default JSON submission |
|
|
187
|
+
| `useForm<T, 'multipart/form-data'>({ type: 'multipart/form-data' })` | File uploads (`FormData`) |
|
|
60
188
|
|
|
61
189
|
---
|
|
62
190
|
|
|
63
|
-
##
|
|
191
|
+
## 4. Mandatory Implementation Rules
|
|
64
192
|
|
|
65
|
-
1. **Always Query MCP First**:
|
|
66
|
-
2. **Strict Subpath Imports**:
|
|
193
|
+
1. **Always Query MCP First**: Retrieve exact component and prop types via `get-documentation`.
|
|
194
|
+
2. **Strict Subpath Imports**: Import primitive components via granular subpaths (`@wangs-ui/react-core/primitive/form`, `@wangs-ui/react-core/primitive/dialogform`, `@wangs-ui/react-core/primitive/field`).
|
|
67
195
|
3. **Translate All Visible Strings**: Every field label, placeholder, helper text, and error message must be wrapped in `t('...')` from `@wangs-ui/react-i18n`.
|
|
196
|
+
4. **Server Validation Error Mapping**: Map backend validation errors (e.g., 422 HTTP status) back into the form via `control.setError('fieldName', 'Error message')`.
|
|
@@ -3,7 +3,7 @@ import fs from "node:fs";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { cancel, intro, isCancel, multiselect, outro } from "@clack/prompts";
|
|
5
5
|
//#region skills/create-form/SKILL.md?raw
|
|
6
|
-
var SKILL_default$7 = "---\nname: create-form\ndescription: Architecture, validation workflows, and MCP discovery protocol for building forms and input controls with @wangs-ui/react-core.\n---\n\n# Skill: Form Architecture & Validation Workflows\n\nUse this skill when building forms, data entry panels, settings pages, or multipart forms in Wangs UI applications.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** hardcode or guess prop names, field configurations, or validation options. Retrieve active component definitions and live implementation stories directly from MCP:\n\n### Inspect Component & Form Contracts:\n\n```json\nget-documentation({ \"id\": \"form\" })\nget-documentation({ \"id\": \"field\" })\nget-documentation({ \"id\": \"input\" })\nget-documentation({ \"id\": \"numberinput\" })\nget-documentation({ \"id\": \"select\" })\nget-documentation({ \"id\": \"multiselect\" })\nget-documentation({ \"id\": \"datepicker\" })\nget-documentation({ \"id\": \"fileupload\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget-documentation-for-story({ \"id\": \"form\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"field\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"select\", \"storyName\": \"Basic\" })\nget-documentation-for-story({ \"id\": \"datepicker\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"fileupload\", \"storyName\": \"Default\" })\n```\n\n### Inspect Knowledge Graph & Usages:\n\n```json\nquery_graph({ \"query\": \"
|
|
6
|
+
var SKILL_default$7 = "---\nname: create-form\ndescription: Architecture, validation workflows, strongly-typed forms (useForm, useDialogForm, useWatchField), and MCP discovery protocol for building forms and input controls with @wangs-ui/react-core.\n---\n\n# Skill: Form Architecture & Validation Workflows\n\nUse this skill when building forms, data entry panels, modal forms, settings pages, or multipart forms in Wangs UI applications.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** hardcode or guess prop names, field configurations, or validation options. Retrieve active component definitions and live implementation stories directly from MCP:\n\n### Inspect Component & Form Contracts:\n\n```json\nget-documentation({ \"id\": \"form\" })\nget-documentation({ \"id\": \"field\" })\nget-documentation({ \"id\": \"dialogform\" })\nget-documentation({ \"id\": \"input\" })\nget-documentation({ \"id\": \"numberinput\" })\nget-documentation({ \"id\": \"select\" })\nget-documentation({ \"id\": \"multiselect\" })\nget-documentation({ \"id\": \"datepicker\" })\nget-documentation({ \"id\": \"fileupload\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget-documentation-for-story({ \"id\": \"form\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"field\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"select\", \"storyName\": \"Basic\" })\nget-documentation-for-story({ \"id\": \"datepicker\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"fileupload\", \"storyName\": \"Default\" })\n```\n\n### Inspect Knowledge Graph & Usages:\n\n```json\nquery_graph({ \"query\": \"useForm\" })\nquery_graph({ \"query\": \"useDialogForm\" })\nquery_graph({ \"query\": \"useWatchField\" })\n```\n\n---\n\n## 2. Form Architecture & Latest API Patterns\n\n### Pattern A: Strongly Typed Forms with `useForm<T>()`\n\nFor standard page forms, use `useForm<T>()` from `@wangs-ui/react-core/primitive/form`. It returns a strongly-typed `Form`, `Field`, and `control` where `Field`'s `name` prop is constrained to dot-path keys of `T` (`Path<T>`) with full IDE autocomplete and type inference.\n\n```tsx\nimport Button from '@wangs-ui/react-core/primitive/button';\nimport { useForm } from '@wangs-ui/react-core/primitive/form';\nimport Input from '@wangs-ui/react-core/primitive/input';\nimport { useI18n } from '@wangs-ui/react-i18n';\n\ninterface UserFormData {\n name: string;\n email: string;\n address: {\n city: string;\n };\n}\n\nexport function UserFormPage() {\n const { t } = useI18n();\n // Strongly-typed Form, Field, and control bound to UserFormData\n const { Form, Field, control } = useForm<UserFormData>();\n\n return (\n <Form control={control} onSubmit={(values) => console.log(values)}>\n <Field required label={t('Full Name')} name=\"name\">\n {({ fieldProps }) => <Input {...fieldProps} placeholder={t('Enter full name')} />}\n </Field>\n\n {/* Autocompletes nested dot-path keys */}\n <Field required label={t('City')} name=\"address.city\">\n {({ fieldProps }) => <Input {...fieldProps} placeholder={t('Enter city')} />}\n </Field>\n\n <div className=\"flex gap-2\">\n <Button\n label={t('Reset')}\n type=\"button\"\n severity=\"secondary\"\n onClick={() => control.reset()}\n />\n <Button label={t('Submit')} type=\"submit\" />\n </div>\n </Form>\n );\n}\n```\n\n---\n\n### Pattern B: Modal Forms with `useDialogForm<T>()`\n\nFor modal/dialog forms, use `useDialogForm<T>()` from `@wangs-ui/react-core/primitive/dialogform`. It combines a modal `Dialog` with form provider lifecycle, providing automatic modal close on success (`closeOnSubmit`), validation interception, and native Enter-key submission.\n\n```tsx\nimport Button from '@wangs-ui/react-core/primitive/button';\nimport { useDialogForm } from '@wangs-ui/react-core/primitive/dialogform';\nimport Input from '@wangs-ui/react-core/primitive/input';\nimport { useI18n } from '@wangs-ui/react-i18n';\nimport { useState } from 'react';\n\ninterface EditProfileData {\n fullName: string;\n email: string;\n}\n\nexport function EditProfileModal() {\n const { t } = useI18n();\n const [open, setOpen] = useState(false);\n const { DialogForm, Field, control } = useDialogForm<EditProfileData>();\n\n return (\n <>\n <Button label={t('Edit Profile')} onClick={() => setOpen(true)} />\n\n <DialogForm\n closeOnSubmit\n control={control}\n header={t('Edit Profile')}\n open={open}\n onOpenChange={setOpen}\n onSubmit={(values) => console.log('Saved:', values)}\n footer={\n <div className=\"flex w-full justify-end gap-2\">\n <Button\n label={t('Cancel')}\n severity=\"secondary\"\n type=\"button\"\n variant=\"outline\"\n onClick={() => setOpen(false)}\n />\n <Button label={t('Save Changes')} type=\"submit\" />\n </div>\n }\n >\n <div className=\"flex flex-col gap-4\">\n <Field required label={t('Full Name')} name=\"fullName\">\n {({ fieldProps }) => <Input {...fieldProps} placeholder=\"John Doe\" />}\n </Field>\n <Field required label={t('Email')} name=\"email\">\n {({ fieldProps }) => (\n <Input {...fieldProps} type=\"email\" placeholder=\"you@example.com\" />\n )}\n </Field>\n </div>\n </DialogForm>\n </>\n );\n}\n```\n\n---\n\n### Pattern C: Real-Time Field Watching with `useWatchField`\n\nTo observe real-time field changes without causing the entire form to re-render, use `useWatchField` from `@wangs-ui/form/react`.\n\n```tsx\nimport { useWatchField } from '@wangs-ui/form/react';\n\nfunction FormSummaryWatcher({ control }) {\n // Subscribes only to 'username' value changes\n const username = useWatchField({ control, name: 'username' });\n\n return <div>Current Username: {username}</div>;\n}\n```\n\n---\n\n## 3. Submission Types\n\n| Config | Use case |\n| -------------------------------------------------------------------- | ------------------------- |\n| `useForm<T>()` / `useDialogForm<T>()` | Default JSON submission |\n| `useForm<T, 'multipart/form-data'>({ type: 'multipart/form-data' })` | File uploads (`FormData`) |\n\n---\n\n## 4. Mandatory Implementation Rules\n\n1. **Always Query MCP First**: Retrieve exact component and prop types via `get-documentation`.\n2. **Strict Subpath Imports**: Import primitive components via granular subpaths (`@wangs-ui/react-core/primitive/form`, `@wangs-ui/react-core/primitive/dialogform`, `@wangs-ui/react-core/primitive/field`).\n3. **Translate All Visible Strings**: Every field label, placeholder, helper text, and error message must be wrapped in `t('...')` from `@wangs-ui/react-i18n`.\n4. **Server Validation Error Mapping**: Map backend validation errors (e.g., 422 HTTP status) back into the form via `control.setError('fieldName', 'Error message')`.\n";
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region skills/data-table/SKILL.md?raw
|
|
9
9
|
var SKILL_default$6 = "---\nname: data-table\ndescription: Architecture, workflows, and MCP discovery protocol for building DataTables with sorting, pagination, filtering, selection, and export.\n---\n\n# Skill: DataTable Architecture & Integration Workflows\n\nUse this skill when implementing data grids, server-paginated tables, filterable listing views, or batch management interfaces with `@wangs-ui/react-core`.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **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:\n\n### Inspect Component Contracts:\n\n```json\nget-documentation({ \"id\": \"datatable\" })\nget-documentation({ \"id\": \"exportbutton\" })\nget-documentation({ \"id\": \"filtercontainer\" })\nget-documentation({ \"id\": \"bulkactionbutton\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget-documentation-for-story({ \"id\": \"datatable\", \"storyName\": \"Basic\" })\nget-documentation-for-story({ \"id\": \"datatable\", \"storyName\": \"ServerPagination\" })\nget-documentation-for-story({ \"id\": \"datatable\", \"storyName\": \"Sortable\" })\nget-documentation-for-story({ \"id\": \"datatable\", \"storyName\": \"MultipleSelection\" })\nget-documentation-for-story({ \"id\": \"datatable\", \"storyName\": \"CustomColumn\" })\nget-documentation-for-story({ \"id\": \"exportbutton\", \"storyName\": \"WithTable\" })\n```\n\n### Inspect Knowledge Graph & Usages:\n\n```json\nquery_graph({ \"query\": \"DataTable\" })\nquery_graph({ \"query\": \"useDataTableFetch\" })\n```\n\n---\n\n## 2. Core Architecture & Mental Model\n\nThe Wangs UI `DataTable` is built on a modular, headless-first architecture:\n\n1. **Declarative Column Definitions (`TableColumn<T>[]`)**:\n Columns are configured as typed array objects, not as JSX children. Check `get-documentation({ \"id\": \"datatable\" })` for column field types.\n2. **Table Instance Hook (`useDataTable`)**:\n Coordinates table state (sorting, pagination, selection, column ordering, pinning, visibility).\n3. **Data Fetching Hook (`useDataTableFetch`)**:\n Feeds server-side data, handles loading indicators, manages query parameters (`search`, `filter`, `sort`, `page`, `limit`), and debounces requests automatically.\n4. **Ecosystem Companions**:\n - `FilterContainer` & `FilterToggleButton`: Filter popovers and faceted search.\n - `ExportButton`: Client/server export to Excel, CSV, PDF, or Print.\n - `BulkActionButton`: Contextual batch actions triggered when rows are selected.\n - `CustomColumn`: User-controlled column ordering, visibility toggling, and pinning.\n\n---\n\n## 3. Mandatory Implementation Rules\n\n1. **Query MCP for Current Code Patterns**: Always run `get-documentation-for-story` for `datatable` before drafting code.\n2. **Strict Subpath Imports**: Import via `@wangs-ui/react-core/primitive/datatable` and companion primitive paths.\n3. **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`.\n4. **Stable Row Identity**: Always configure a unique key identifier for stable selection and row identity.\n";
|
|
@@ -144,7 +144,7 @@ function removeSkill(skillId, baseDir = process.cwd()) {
|
|
|
144
144
|
//#endregion
|
|
145
145
|
//#region src/commands/list.ts
|
|
146
146
|
function listSkills(baseDir = process.cwd()) {
|
|
147
|
-
intro(`\x1b[1m\x1b[36m📦 Wangs UI Consumer Skills Registry\x1b[0m [2m(v1.1.0-alpha.
|
|
147
|
+
intro(`\x1b[1m\x1b[36m📦 Wangs UI Consumer Skills Registry\x1b[0m [2m(v1.1.0-alpha.4)[0m`);
|
|
148
148
|
const allSkills = loadAllSkills();
|
|
149
149
|
const targetDirs = getAgentSkillDirs(baseDir);
|
|
150
150
|
if (allSkills.length === 0) {
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-form
|
|
3
|
-
description: Architecture, validation workflows, and MCP discovery protocol for building forms and input controls with @wangs-ui/react-core.
|
|
3
|
+
description: Architecture, validation workflows, strongly-typed forms (useForm, useDialogForm, useWatchField), and MCP discovery protocol for building forms and input controls with @wangs-ui/react-core.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Skill: Form Architecture & Validation Workflows
|
|
7
7
|
|
|
8
|
-
Use this skill when building forms, data entry panels, settings pages, or multipart forms in Wangs UI applications.
|
|
8
|
+
Use this skill when building forms, data entry panels, modal forms, settings pages, or multipart forms in Wangs UI applications.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -18,6 +18,7 @@ Do **NOT** hardcode or guess prop names, field configurations, or validation opt
|
|
|
18
18
|
```json
|
|
19
19
|
get-documentation({ "id": "form" })
|
|
20
20
|
get-documentation({ "id": "field" })
|
|
21
|
+
get-documentation({ "id": "dialogform" })
|
|
21
22
|
get-documentation({ "id": "input" })
|
|
22
23
|
get-documentation({ "id": "numberinput" })
|
|
23
24
|
get-documentation({ "id": "select" })
|
|
@@ -39,29 +40,157 @@ get-documentation-for-story({ "id": "fileupload", "storyName": "Default" })
|
|
|
39
40
|
### Inspect Knowledge Graph & Usages:
|
|
40
41
|
|
|
41
42
|
```json
|
|
42
|
-
query_graph({ "query": "
|
|
43
|
-
query_graph({ "query": "
|
|
43
|
+
query_graph({ "query": "useForm" })
|
|
44
|
+
query_graph({ "query": "useDialogForm" })
|
|
45
|
+
query_graph({ "query": "useWatchField" })
|
|
44
46
|
```
|
|
45
47
|
|
|
46
48
|
---
|
|
47
49
|
|
|
48
|
-
## 2. Form Architecture &
|
|
50
|
+
## 2. Form Architecture & Latest API Patterns
|
|
51
|
+
|
|
52
|
+
### Pattern A: Strongly Typed Forms with `useForm<T>()`
|
|
53
|
+
|
|
54
|
+
For standard page forms, use `useForm<T>()` from `@wangs-ui/react-core/primitive/form`. It returns a strongly-typed `Form`, `Field`, and `control` where `Field`'s `name` prop is constrained to dot-path keys of `T` (`Path<T>`) with full IDE autocomplete and type inference.
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import Button from '@wangs-ui/react-core/primitive/button';
|
|
58
|
+
import { useForm } from '@wangs-ui/react-core/primitive/form';
|
|
59
|
+
import Input from '@wangs-ui/react-core/primitive/input';
|
|
60
|
+
import { useI18n } from '@wangs-ui/react-i18n';
|
|
61
|
+
|
|
62
|
+
interface UserFormData {
|
|
63
|
+
name: string;
|
|
64
|
+
email: string;
|
|
65
|
+
address: {
|
|
66
|
+
city: string;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function UserFormPage() {
|
|
71
|
+
const { t } = useI18n();
|
|
72
|
+
// Strongly-typed Form, Field, and control bound to UserFormData
|
|
73
|
+
const { Form, Field, control } = useForm<UserFormData>();
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<Form control={control} onSubmit={(values) => console.log(values)}>
|
|
77
|
+
<Field required label={t('Full Name')} name="name">
|
|
78
|
+
{({ fieldProps }) => <Input {...fieldProps} placeholder={t('Enter full name')} />}
|
|
79
|
+
</Field>
|
|
80
|
+
|
|
81
|
+
{/* Autocompletes nested dot-path keys */}
|
|
82
|
+
<Field required label={t('City')} name="address.city">
|
|
83
|
+
{({ fieldProps }) => <Input {...fieldProps} placeholder={t('Enter city')} />}
|
|
84
|
+
</Field>
|
|
85
|
+
|
|
86
|
+
<div className="flex gap-2">
|
|
87
|
+
<Button
|
|
88
|
+
label={t('Reset')}
|
|
89
|
+
type="button"
|
|
90
|
+
severity="secondary"
|
|
91
|
+
onClick={() => control.reset()}
|
|
92
|
+
/>
|
|
93
|
+
<Button label={t('Submit')} type="submit" />
|
|
94
|
+
</div>
|
|
95
|
+
</Form>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### Pattern B: Modal Forms with `useDialogForm<T>()`
|
|
103
|
+
|
|
104
|
+
For modal/dialog forms, use `useDialogForm<T>()` from `@wangs-ui/react-core/primitive/dialogform`. It combines a modal `Dialog` with form provider lifecycle, providing automatic modal close on success (`closeOnSubmit`), validation interception, and native Enter-key submission.
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import Button from '@wangs-ui/react-core/primitive/button';
|
|
108
|
+
import { useDialogForm } from '@wangs-ui/react-core/primitive/dialogform';
|
|
109
|
+
import Input from '@wangs-ui/react-core/primitive/input';
|
|
110
|
+
import { useI18n } from '@wangs-ui/react-i18n';
|
|
111
|
+
import { useState } from 'react';
|
|
112
|
+
|
|
113
|
+
interface EditProfileData {
|
|
114
|
+
fullName: string;
|
|
115
|
+
email: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function EditProfileModal() {
|
|
119
|
+
const { t } = useI18n();
|
|
120
|
+
const [open, setOpen] = useState(false);
|
|
121
|
+
const { DialogForm, Field, control } = useDialogForm<EditProfileData>();
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<>
|
|
125
|
+
<Button label={t('Edit Profile')} onClick={() => setOpen(true)} />
|
|
126
|
+
|
|
127
|
+
<DialogForm
|
|
128
|
+
closeOnSubmit
|
|
129
|
+
control={control}
|
|
130
|
+
header={t('Edit Profile')}
|
|
131
|
+
open={open}
|
|
132
|
+
onOpenChange={setOpen}
|
|
133
|
+
onSubmit={(values) => console.log('Saved:', values)}
|
|
134
|
+
footer={
|
|
135
|
+
<div className="flex w-full justify-end gap-2">
|
|
136
|
+
<Button
|
|
137
|
+
label={t('Cancel')}
|
|
138
|
+
severity="secondary"
|
|
139
|
+
type="button"
|
|
140
|
+
variant="outline"
|
|
141
|
+
onClick={() => setOpen(false)}
|
|
142
|
+
/>
|
|
143
|
+
<Button label={t('Save Changes')} type="submit" />
|
|
144
|
+
</div>
|
|
145
|
+
}
|
|
146
|
+
>
|
|
147
|
+
<div className="flex flex-col gap-4">
|
|
148
|
+
<Field required label={t('Full Name')} name="fullName">
|
|
149
|
+
{({ fieldProps }) => <Input {...fieldProps} placeholder="John Doe" />}
|
|
150
|
+
</Field>
|
|
151
|
+
<Field required label={t('Email')} name="email">
|
|
152
|
+
{({ fieldProps }) => (
|
|
153
|
+
<Input {...fieldProps} type="email" placeholder="you@example.com" />
|
|
154
|
+
)}
|
|
155
|
+
</Field>
|
|
156
|
+
</div>
|
|
157
|
+
</DialogForm>
|
|
158
|
+
</>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### Pattern C: Real-Time Field Watching with `useWatchField`
|
|
166
|
+
|
|
167
|
+
To observe real-time field changes without causing the entire form to re-render, use `useWatchField` from `@wangs-ui/form/react`.
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { useWatchField } from '@wangs-ui/form/react';
|
|
171
|
+
|
|
172
|
+
function FormSummaryWatcher({ control }) {
|
|
173
|
+
// Subscribes only to 'username' value changes
|
|
174
|
+
const username = useWatchField({ control, name: 'username' });
|
|
175
|
+
|
|
176
|
+
return <div>Current Username: {username}</div>;
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 3. Submission Types
|
|
49
183
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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.
|
|
184
|
+
| Config | Use case |
|
|
185
|
+
| -------------------------------------------------------------------- | ------------------------- |
|
|
186
|
+
| `useForm<T>()` / `useDialogForm<T>()` | Default JSON submission |
|
|
187
|
+
| `useForm<T, 'multipart/form-data'>({ type: 'multipart/form-data' })` | File uploads (`FormData`) |
|
|
60
188
|
|
|
61
189
|
---
|
|
62
190
|
|
|
63
|
-
##
|
|
191
|
+
## 4. Mandatory Implementation Rules
|
|
64
192
|
|
|
65
|
-
1. **Always Query MCP First**:
|
|
66
|
-
2. **Strict Subpath Imports**:
|
|
193
|
+
1. **Always Query MCP First**: Retrieve exact component and prop types via `get-documentation`.
|
|
194
|
+
2. **Strict Subpath Imports**: Import primitive components via granular subpaths (`@wangs-ui/react-core/primitive/form`, `@wangs-ui/react-core/primitive/dialogform`, `@wangs-ui/react-core/primitive/field`).
|
|
67
195
|
3. **Translate All Visible Strings**: Every field label, placeholder, helper text, and error message must be wrapped in `t('...')` from `@wangs-ui/react-i18n`.
|
|
196
|
+
4. **Server Validation Error Mapping**: Map backend validation errors (e.g., 422 HTTP status) back into the form via `control.setError('fieldName', 'Error message')`.
|