@ng-forge/dynamic-form-mcp 0.5.1
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 +221 -0
- package/bin/ng-forge-mcp.d.ts +8 -0
- package/bin/ng-forge-mcp.d.ts.map +1 -0
- package/bin/ng-forge-mcp.js +10202 -0
- package/package.json +61 -0
- package/src/index.d.ts +14 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +10265 -0
- package/src/registry/api-reference.json +510 -0
- package/src/registry/docs.json +230 -0
- package/src/registry/examples.json +629 -0
- package/src/registry/field-types.json +490 -0
- package/src/registry/index.d.ts +110 -0
- package/src/registry/index.d.ts.map +1 -0
- package/src/registry/instructions.d.ts +8 -0
- package/src/registry/instructions.d.ts.map +1 -0
- package/src/registry/ui-adapters.json +225 -0
- package/src/registry/validators.json +158 -0
- package/src/resources/documentation.resource.d.ts +8 -0
- package/src/resources/documentation.resource.d.ts.map +1 -0
- package/src/resources/examples.resource.d.ts +8 -0
- package/src/resources/examples.resource.d.ts.map +1 -0
- package/src/resources/field-types.resource.d.ts +8 -0
- package/src/resources/field-types.resource.d.ts.map +1 -0
- package/src/resources/index.d.ts +11 -0
- package/src/resources/index.d.ts.map +1 -0
- package/src/resources/instructions.resource.d.ts +8 -0
- package/src/resources/instructions.resource.d.ts.map +1 -0
- package/src/resources/schemas.resource.d.ts +9 -0
- package/src/resources/schemas.resource.d.ts.map +1 -0
- package/src/resources/ui-adapters.resource.d.ts +8 -0
- package/src/resources/ui-adapters.resource.d.ts.map +1 -0
- package/src/resources/validators.resource.d.ts +8 -0
- package/src/resources/validators.resource.d.ts.map +1 -0
- package/src/server.d.ts +22 -0
- package/src/server.d.ts.map +1 -0
- package/src/tools/data/lookup-topics.d.ts +18 -0
- package/src/tools/data/lookup-topics.d.ts.map +1 -0
- package/src/tools/examples.tool.d.ts +12 -0
- package/src/tools/examples.tool.d.ts.map +1 -0
- package/src/tools/index.d.ts +33 -0
- package/src/tools/index.d.ts.map +1 -0
- package/src/tools/lookup.tool.d.ts +15 -0
- package/src/tools/lookup.tool.d.ts.map +1 -0
- package/src/tools/scaffold.tool.d.ts +11 -0
- package/src/tools/scaffold.tool.d.ts.map +1 -0
- package/src/tools/validate.tool.d.ts +14 -0
- package/src/tools/validate.tool.d.ts.map +1 -0
- package/src/utils/ast-extractor.d.ts +88 -0
- package/src/utils/ast-extractor.d.ts.map +1 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "input",
|
|
4
|
+
"category": "value",
|
|
5
|
+
"description": "Text-based input field with HTML5 type support (text, email, password, number, tel, url)",
|
|
6
|
+
"valueType": "string | number",
|
|
7
|
+
"baseInterface": "BaseValueField",
|
|
8
|
+
"props": {
|
|
9
|
+
"type": {
|
|
10
|
+
"name": "type",
|
|
11
|
+
"type": "'text' | 'email' | 'password' | 'number' | 'tel' | 'url'",
|
|
12
|
+
"description": "HTML input type",
|
|
13
|
+
"required": false,
|
|
14
|
+
"default": "text"
|
|
15
|
+
},
|
|
16
|
+
"placeholder": {
|
|
17
|
+
"name": "placeholder",
|
|
18
|
+
"type": "DynamicText",
|
|
19
|
+
"description": "Placeholder text displayed when field is empty",
|
|
20
|
+
"required": false
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"validationSupported": true,
|
|
24
|
+
"source": "adapter",
|
|
25
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
26
|
+
"example": "{\n key: 'email',\n type: 'input',\n label: 'Email Address',\n required: true,\n email: true,\n props: { type: 'email', placeholder: 'user@example.com' }\n}",
|
|
27
|
+
"minimalExample": "{ key: 'name', type: 'input', label: 'Name' }"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"type": "textarea",
|
|
31
|
+
"category": "value",
|
|
32
|
+
"description": "Multi-line text input field for longer content",
|
|
33
|
+
"valueType": "string",
|
|
34
|
+
"baseInterface": "BaseValueField",
|
|
35
|
+
"props": {
|
|
36
|
+
"rows": {
|
|
37
|
+
"name": "rows",
|
|
38
|
+
"type": "number",
|
|
39
|
+
"description": "Number of visible text lines",
|
|
40
|
+
"required": false,
|
|
41
|
+
"default": 3
|
|
42
|
+
},
|
|
43
|
+
"placeholder": {
|
|
44
|
+
"name": "placeholder",
|
|
45
|
+
"type": "DynamicText",
|
|
46
|
+
"description": "Placeholder text displayed when field is empty",
|
|
47
|
+
"required": false
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"validationSupported": true,
|
|
51
|
+
"source": "adapter",
|
|
52
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
53
|
+
"example": "{\n key: 'description',\n type: 'textarea',\n label: 'Description',\n props: { rows: 5, placeholder: 'Enter description...' }\n}",
|
|
54
|
+
"minimalExample": "{ key: 'bio', type: 'textarea', label: 'Bio' }"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"type": "select",
|
|
58
|
+
"category": "value",
|
|
59
|
+
"description": "Dropdown selection field with single or multiple selection",
|
|
60
|
+
"valueType": "T | T[]",
|
|
61
|
+
"baseInterface": "BaseValueField",
|
|
62
|
+
"props": {
|
|
63
|
+
"options": {
|
|
64
|
+
"name": "options",
|
|
65
|
+
"type": "FieldOption[]",
|
|
66
|
+
"description": "Array of selectable options with label and value. IMPORTANT: options goes at FIELD level, NOT inside props",
|
|
67
|
+
"required": true
|
|
68
|
+
},
|
|
69
|
+
"multiple": {
|
|
70
|
+
"name": "multiple",
|
|
71
|
+
"type": "boolean",
|
|
72
|
+
"description": "Allow multiple selections",
|
|
73
|
+
"required": false,
|
|
74
|
+
"default": false
|
|
75
|
+
},
|
|
76
|
+
"placeholder": {
|
|
77
|
+
"name": "placeholder",
|
|
78
|
+
"type": "DynamicText",
|
|
79
|
+
"description": "Placeholder text for empty selection",
|
|
80
|
+
"required": false
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"validationSupported": true,
|
|
84
|
+
"source": "adapter",
|
|
85
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
86
|
+
"example": "{\n key: 'country',\n type: 'select',\n label: 'Country',\n required: true,\n options: [\n { label: 'United States', value: 'us' },\n { label: 'Canada', value: 'ca' }\n ]\n}",
|
|
87
|
+
"minimalExample": "{ key: 'status', type: 'select', label: 'Status', options: [{ label: 'Active', value: 'active' }] }"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"type": "checkbox",
|
|
91
|
+
"category": "value",
|
|
92
|
+
"description": "Boolean toggle checkbox field",
|
|
93
|
+
"valueType": "boolean",
|
|
94
|
+
"baseInterface": "BaseCheckedField",
|
|
95
|
+
"props": {},
|
|
96
|
+
"validationSupported": true,
|
|
97
|
+
"source": "adapter",
|
|
98
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
99
|
+
"example": "{\n key: 'acceptTerms',\n type: 'checkbox',\n label: 'I accept the terms and conditions',\n required: true\n}",
|
|
100
|
+
"minimalExample": "{ key: 'agree', type: 'checkbox', label: 'I agree' }"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"type": "multi-checkbox",
|
|
104
|
+
"category": "value",
|
|
105
|
+
"description": "Multiple checkbox group for selecting multiple values from options",
|
|
106
|
+
"valueType": "T[]",
|
|
107
|
+
"baseInterface": "BaseValueField",
|
|
108
|
+
"props": {
|
|
109
|
+
"options": {
|
|
110
|
+
"name": "options",
|
|
111
|
+
"type": "FieldOption[]",
|
|
112
|
+
"description": "Array of selectable options. IMPORTANT: options goes at FIELD level, NOT inside props",
|
|
113
|
+
"required": true
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"validationSupported": true,
|
|
117
|
+
"source": "adapter",
|
|
118
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
119
|
+
"example": "{\n key: 'interests',\n type: 'multi-checkbox',\n label: 'Select your interests',\n options: [\n { label: 'Sports', value: 'sports' },\n { label: 'Music', value: 'music' },\n { label: 'Art', value: 'art' },\n { label: 'Technology', value: 'tech' }\n ]\n}",
|
|
120
|
+
"minimalExample": "{ key: 'tags', type: 'multi-checkbox', label: 'Tags', options: [{ label: 'A', value: 'a' }] }"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"type": "radio",
|
|
124
|
+
"category": "value",
|
|
125
|
+
"description": "Radio button group for single selection from options",
|
|
126
|
+
"valueType": "T",
|
|
127
|
+
"baseInterface": "BaseValueField",
|
|
128
|
+
"props": {
|
|
129
|
+
"options": {
|
|
130
|
+
"name": "options",
|
|
131
|
+
"type": "FieldOption[]",
|
|
132
|
+
"description": "Array of selectable options. IMPORTANT: options goes at FIELD level, NOT inside props",
|
|
133
|
+
"required": true
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"validationSupported": true,
|
|
137
|
+
"source": "adapter",
|
|
138
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
139
|
+
"example": "{\n key: 'gender',\n type: 'radio',\n label: 'Gender',\n options: [\n { label: 'Male', value: 'male' },\n { label: 'Female', value: 'female' },\n { label: 'Other', value: 'other' }\n ]\n}",
|
|
140
|
+
"minimalExample": "{ key: 'choice', type: 'radio', label: 'Choice', options: [{ label: 'Yes', value: 'yes' }, { label: 'No', value: 'no' }] }"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"type": "datepicker",
|
|
144
|
+
"category": "value",
|
|
145
|
+
"description": "Date selection field with calendar picker",
|
|
146
|
+
"valueType": "Date | string",
|
|
147
|
+
"baseInterface": "BaseValueField",
|
|
148
|
+
"props": {
|
|
149
|
+
"minDate": {
|
|
150
|
+
"name": "minDate",
|
|
151
|
+
"type": "Date | string",
|
|
152
|
+
"description": "Minimum selectable date",
|
|
153
|
+
"required": false
|
|
154
|
+
},
|
|
155
|
+
"maxDate": {
|
|
156
|
+
"name": "maxDate",
|
|
157
|
+
"type": "Date | string",
|
|
158
|
+
"description": "Maximum selectable date",
|
|
159
|
+
"required": false
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"validationSupported": true,
|
|
163
|
+
"source": "adapter",
|
|
164
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
165
|
+
"example": "{\n key: 'birthDate',\n type: 'datepicker',\n label: 'Date of Birth',\n required: true,\n props: { maxDate: new Date() }\n}",
|
|
166
|
+
"minimalExample": "{ key: 'date', type: 'datepicker', label: 'Date' }"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"type": "toggle",
|
|
170
|
+
"category": "value",
|
|
171
|
+
"description": "Switch/toggle control for boolean values",
|
|
172
|
+
"valueType": "boolean",
|
|
173
|
+
"baseInterface": "BaseCheckedField",
|
|
174
|
+
"props": {},
|
|
175
|
+
"validationSupported": true,
|
|
176
|
+
"source": "adapter",
|
|
177
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
178
|
+
"example": "{\n key: 'notifications',\n type: 'toggle',\n label: 'Enable notifications'\n}",
|
|
179
|
+
"minimalExample": "{ key: 'enabled', type: 'toggle', label: 'Enable' }"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"type": "slider",
|
|
183
|
+
"category": "value",
|
|
184
|
+
"description": "Numeric range slider for value selection",
|
|
185
|
+
"valueType": "number",
|
|
186
|
+
"baseInterface": "BaseValueField",
|
|
187
|
+
"props": {
|
|
188
|
+
"minValue": {
|
|
189
|
+
"name": "minValue",
|
|
190
|
+
"type": "number",
|
|
191
|
+
"description": "Minimum value. IMPORTANT: This is at FIELD level, NOT inside props",
|
|
192
|
+
"required": false,
|
|
193
|
+
"default": 0
|
|
194
|
+
},
|
|
195
|
+
"maxValue": {
|
|
196
|
+
"name": "maxValue",
|
|
197
|
+
"type": "number",
|
|
198
|
+
"description": "Maximum value. IMPORTANT: This is at FIELD level, NOT inside props",
|
|
199
|
+
"required": false,
|
|
200
|
+
"default": 100
|
|
201
|
+
},
|
|
202
|
+
"step": {
|
|
203
|
+
"name": "step",
|
|
204
|
+
"type": "number",
|
|
205
|
+
"description": "Step increment. IMPORTANT: This is at FIELD level, NOT inside props",
|
|
206
|
+
"required": false,
|
|
207
|
+
"default": 1
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
"validationSupported": true,
|
|
211
|
+
"source": "adapter",
|
|
212
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
213
|
+
"example": "{\n key: 'volume',\n type: 'slider',\n label: 'Volume',\n value: 50,\n minValue: 0,\n maxValue: 100,\n step: 5\n}",
|
|
214
|
+
"minimalExample": "{ key: 'rating', type: 'slider', label: 'Rating' }"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"type": "hidden",
|
|
218
|
+
"category": "value",
|
|
219
|
+
"description": "Hidden field that participates in form values without rendering. REQUIRED: The \"value\" property MUST be provided (string, number, boolean, or array). FORBIDDEN: label, logic, validators, required, props, disabled, readonly, hidden, col, tabIndex, meta - hidden fields are purely for passing values through the form. IMPORTANT: In multi-page forms, hidden fields must go INSIDE a page, not at the root level.",
|
|
220
|
+
"valueType": "string | number | boolean | (string | number | boolean)[]",
|
|
221
|
+
"baseInterface": "FieldDef",
|
|
222
|
+
"props": {},
|
|
223
|
+
"validationSupported": false,
|
|
224
|
+
"source": "core",
|
|
225
|
+
"allowedIn": ["top-level (single-page forms only)", "page.fields", "group.fields", "array.fields"],
|
|
226
|
+
"notAllowedIn": ["row", "top-level when using pages"],
|
|
227
|
+
"example": "// Hidden field - value is REQUIRED!\n{\n key: 'userId',\n type: 'hidden',\n value: 'abc123' // REQUIRED: string, number, boolean, or array\n}\n\n// Valid value types:\n{ key: 'count', type: 'hidden', value: 42 } // number\n{ key: 'active', type: 'hidden', value: true } // boolean\n{ key: 'tags', type: 'hidden', value: [1, 2, 3] } // array\n\n// ❌ FORBIDDEN (will cause validation error):\n// - label, logic, validators, required, props\n// - disabled, readonly, hidden, col, tabIndex, meta\n// - Validation shorthand: email, min, max, minLength, maxLength, pattern",
|
|
228
|
+
"minimalExample": "{ key: 'id', type: 'hidden', value: 'abc123' }"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"type": "text",
|
|
232
|
+
"category": "display",
|
|
233
|
+
"description": "Static text display element (headings, paragraphs, spans). The text content comes from the label property.",
|
|
234
|
+
"baseInterface": "FieldDef",
|
|
235
|
+
"props": {
|
|
236
|
+
"elementType": {
|
|
237
|
+
"name": "elementType",
|
|
238
|
+
"type": "'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span'",
|
|
239
|
+
"description": "HTML element type for rendering",
|
|
240
|
+
"required": false,
|
|
241
|
+
"default": "p"
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
"validationSupported": false,
|
|
245
|
+
"source": "core",
|
|
246
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
247
|
+
"example": "{\n key: 'sectionTitle',\n type: 'text',\n label: 'Personal Information',\n props: { elementType: 'h2' }\n}",
|
|
248
|
+
"minimalExample": "{ key: 'header', type: 'text', label: 'Section Title' }"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"type": "row",
|
|
252
|
+
"category": "container",
|
|
253
|
+
"description": "Horizontal layout container for grouping fields in columns. Rows do NOT have a label property and do NOT support logic blocks.",
|
|
254
|
+
"baseInterface": "FieldDef",
|
|
255
|
+
"props": {
|
|
256
|
+
"fields": {
|
|
257
|
+
"name": "fields",
|
|
258
|
+
"type": "RowAllowedChildren[]",
|
|
259
|
+
"description": "Child fields to render horizontally. Allowed: groups, arrays, VALUE fields (input, select, etc). NOT ALLOWED: pages, rows, hidden fields",
|
|
260
|
+
"required": true
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
"validationSupported": false,
|
|
264
|
+
"source": "core",
|
|
265
|
+
"allowedIn": ["top-level", "page", "group", "array"],
|
|
266
|
+
"notAllowedIn": ["row"],
|
|
267
|
+
"canContain": [
|
|
268
|
+
"group",
|
|
269
|
+
"array",
|
|
270
|
+
"input",
|
|
271
|
+
"textarea",
|
|
272
|
+
"select",
|
|
273
|
+
"checkbox",
|
|
274
|
+
"multi-checkbox",
|
|
275
|
+
"radio",
|
|
276
|
+
"datepicker",
|
|
277
|
+
"toggle",
|
|
278
|
+
"slider",
|
|
279
|
+
"text",
|
|
280
|
+
"button",
|
|
281
|
+
"submit",
|
|
282
|
+
"next",
|
|
283
|
+
"previous"
|
|
284
|
+
],
|
|
285
|
+
"cannotContain": ["page", "row", "hidden"],
|
|
286
|
+
"example": "{\n key: 'nameRow',\n type: 'row',\n // NOTE: Rows do NOT have label or logic properties\n fields: [\n { key: 'firstName', type: 'input', label: 'First Name', col: 6 },\n { key: 'lastName', type: 'input', label: 'Last Name', col: 6 }\n ]\n}\n// NOT ALLOWED in rows:\n// - type: 'hidden' (hidden fields cannot be inside rows)\n// - type: 'page' (pages are top-level only)\n// - type: 'row' (no nested rows)",
|
|
287
|
+
"minimalExample": "{ key: 'row1', type: 'row', fields: [...] }"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"type": "group",
|
|
291
|
+
"category": "container",
|
|
292
|
+
"description": "Nested form group container creating a sub-object in form values. Groups are logical containers only and do NOT have a label property.",
|
|
293
|
+
"valueType": "object",
|
|
294
|
+
"baseInterface": "FieldDef",
|
|
295
|
+
"props": {
|
|
296
|
+
"fields": {
|
|
297
|
+
"name": "fields",
|
|
298
|
+
"type": "GroupAllowedChildren[]",
|
|
299
|
+
"description": "Child fields in the group. Allowed: rows, leaf fields (NOT pages or other groups)",
|
|
300
|
+
"required": true
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
"validationSupported": true,
|
|
304
|
+
"source": "core",
|
|
305
|
+
"allowedIn": ["top-level", "page", "row", "array"],
|
|
306
|
+
"notAllowedIn": ["group"],
|
|
307
|
+
"canContain": [
|
|
308
|
+
"row",
|
|
309
|
+
"input",
|
|
310
|
+
"textarea",
|
|
311
|
+
"select",
|
|
312
|
+
"checkbox",
|
|
313
|
+
"multi-checkbox",
|
|
314
|
+
"radio",
|
|
315
|
+
"datepicker",
|
|
316
|
+
"toggle",
|
|
317
|
+
"slider",
|
|
318
|
+
"hidden",
|
|
319
|
+
"text",
|
|
320
|
+
"button",
|
|
321
|
+
"submit",
|
|
322
|
+
"next",
|
|
323
|
+
"previous"
|
|
324
|
+
],
|
|
325
|
+
"cannotContain": ["page", "group"],
|
|
326
|
+
"example": "{\n key: 'address',\n type: 'group',\n // NOTE: Groups do NOT have a label property\n fields: [\n { key: 'street', type: 'input', label: 'Street' },\n { key: 'city', type: 'input', label: 'City' },\n { key: 'zip', type: 'input', label: 'ZIP Code' }\n ]\n}",
|
|
327
|
+
"minimalExample": "{ key: 'address', type: 'group', fields: [...] }"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"type": "array",
|
|
331
|
+
"category": "container",
|
|
332
|
+
"description": "Repeatable field group for dynamic lists/arrays. Arrays do NOT have label, minItems, or maxItems properties. Use \"fields\" (not \"template\") to define the item template.",
|
|
333
|
+
"valueType": "T[]",
|
|
334
|
+
"baseInterface": "FieldDef",
|
|
335
|
+
"props": {
|
|
336
|
+
"fields": {
|
|
337
|
+
"name": "fields",
|
|
338
|
+
"type": "ArrayAllowedChildren[]",
|
|
339
|
+
"description": "Template field(s) for each array item. Allowed: rows, groups, leaf fields (NOT pages or other arrays)",
|
|
340
|
+
"required": true
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
"validationSupported": false,
|
|
344
|
+
"source": "core",
|
|
345
|
+
"allowedIn": ["top-level", "page", "row", "group"],
|
|
346
|
+
"notAllowedIn": ["array"],
|
|
347
|
+
"canContain": [
|
|
348
|
+
"row",
|
|
349
|
+
"group",
|
|
350
|
+
"input",
|
|
351
|
+
"textarea",
|
|
352
|
+
"select",
|
|
353
|
+
"checkbox",
|
|
354
|
+
"multi-checkbox",
|
|
355
|
+
"radio",
|
|
356
|
+
"datepicker",
|
|
357
|
+
"toggle",
|
|
358
|
+
"slider",
|
|
359
|
+
"hidden",
|
|
360
|
+
"text",
|
|
361
|
+
"button",
|
|
362
|
+
"submit",
|
|
363
|
+
"next",
|
|
364
|
+
"previous"
|
|
365
|
+
],
|
|
366
|
+
"cannotContain": ["page", "array"],
|
|
367
|
+
"example": "// Flat array (primitive values)\n{\n key: 'tags',\n type: 'array',\n // NOTE: Arrays do NOT have label, minItems, or maxItems\n fields: [\n { key: 'tag', type: 'input', label: 'Tag' }\n ]\n}\n// Result: { tags: ['value1', 'value2'] }\n\n// Object array (nested groups)\n{\n key: 'contacts',\n type: 'array',\n fields: [{\n type: 'group',\n fields: [\n { key: 'name', type: 'input', label: 'Name' },\n { key: 'email', type: 'input', label: 'Email' }\n ]\n }]\n}\n// Result: { contacts: [{name: '', email: ''}, ...] }",
|
|
368
|
+
"minimalExample": "{ key: 'items', type: 'array', fields: [...] }"
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"type": "page",
|
|
372
|
+
"category": "container",
|
|
373
|
+
"description": "Multi-step form page container for wizard-style forms. Pages do NOT have label or title properties. ALL top-level fields must be pages if using multi-page mode. IMPORTANT: Navigation buttons (next, previous) must be added as fields WITHIN each page that needs them.",
|
|
374
|
+
"baseInterface": "FieldDef",
|
|
375
|
+
"props": {
|
|
376
|
+
"fields": {
|
|
377
|
+
"name": "fields",
|
|
378
|
+
"type": "PageAllowedChildren[]",
|
|
379
|
+
"description": "Fields in this page. Allowed: rows, groups, arrays, leaf fields (NOT other pages). Include next/previous buttons as needed.",
|
|
380
|
+
"required": true
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
"validationSupported": false,
|
|
384
|
+
"source": "core",
|
|
385
|
+
"allowedIn": ["top-level"],
|
|
386
|
+
"notAllowedIn": ["page", "row", "group", "array"],
|
|
387
|
+
"canContain": [
|
|
388
|
+
"row",
|
|
389
|
+
"group",
|
|
390
|
+
"array",
|
|
391
|
+
"input",
|
|
392
|
+
"textarea",
|
|
393
|
+
"select",
|
|
394
|
+
"checkbox",
|
|
395
|
+
"multi-checkbox",
|
|
396
|
+
"radio",
|
|
397
|
+
"datepicker",
|
|
398
|
+
"toggle",
|
|
399
|
+
"slider",
|
|
400
|
+
"hidden",
|
|
401
|
+
"text",
|
|
402
|
+
"button",
|
|
403
|
+
"submit",
|
|
404
|
+
"next",
|
|
405
|
+
"previous"
|
|
406
|
+
],
|
|
407
|
+
"cannotContain": ["page"],
|
|
408
|
+
"example": "{\n key: 'step1',\n type: 'page',\n // NOTE: Pages do NOT have label or title properties\n // Navigation buttons are fields WITHIN the page\n fields: [\n { key: 'firstName', type: 'input', label: 'First Name' },\n { key: 'lastName', type: 'input', label: 'Last Name' },\n { key: 'next', type: 'next', label: 'Next' }\n ]\n}",
|
|
409
|
+
"minimalExample": "{ key: 'step1', type: 'page', fields: [...] }"
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
"type": "next",
|
|
413
|
+
"category": "button",
|
|
414
|
+
"description": "Navigation button to go to next page in multi-step forms. Must be placed INSIDE a page's fields array.",
|
|
415
|
+
"baseInterface": "FieldDef",
|
|
416
|
+
"props": {},
|
|
417
|
+
"validationSupported": false,
|
|
418
|
+
"source": "adapter",
|
|
419
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
420
|
+
"example": "{\n key: 'next',\n type: 'next',\n label: 'Next'\n}",
|
|
421
|
+
"minimalExample": "{ key: 'next', type: 'next', label: 'Next' }"
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
"type": "previous",
|
|
425
|
+
"category": "button",
|
|
426
|
+
"description": "Navigation button to go to previous page in multi-step forms. Must be placed INSIDE a page's fields array.",
|
|
427
|
+
"baseInterface": "FieldDef",
|
|
428
|
+
"props": {},
|
|
429
|
+
"validationSupported": false,
|
|
430
|
+
"source": "adapter",
|
|
431
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
432
|
+
"example": "{\n key: 'back',\n type: 'previous',\n label: 'Back'\n}",
|
|
433
|
+
"minimalExample": "{ key: 'back', type: 'previous', label: 'Back' }"
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"type": "button",
|
|
437
|
+
"category": "button",
|
|
438
|
+
"description": "Generic button for custom actions. IMPORTANT: The generic 'button' type REQUIRES the 'event' property with a FormEventConstructor. For simple use cases, prefer 'submit', 'next', or 'previous' which don't require event configuration.",
|
|
439
|
+
"baseInterface": "FieldDef",
|
|
440
|
+
"props": {
|
|
441
|
+
"event": {
|
|
442
|
+
"name": "event",
|
|
443
|
+
"type": "FormEventConstructor<TEvent>",
|
|
444
|
+
"description": "REQUIRED. Event constructor that will be emitted when button is clicked. Must be registered with provideFormEvents().",
|
|
445
|
+
"required": true
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
"validationSupported": false,
|
|
449
|
+
"source": "adapter",
|
|
450
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
451
|
+
"example": "// RECOMMENDED: Use pre-defined button types for common actions\n{ key: 'submit', type: 'submit', label: 'Submit Form' }\n{ key: 'next', type: 'next', label: 'Next' }\n{ key: 'back', type: 'previous', label: 'Back' }\n\n// ADVANCED: Generic button with custom event (requires setup)\n// 1. Create event class: class MyCustomEvent extends FormEvent {}\n// 2. Register with: provideFormEvents([MyCustomEvent])\n// 3. Use in config:\n{\n key: 'customAction',\n type: 'button',\n label: 'Custom Action',\n event: MyCustomEvent // Must be the class reference\n}",
|
|
452
|
+
"minimalExample": "{ key: 'action', type: 'button', label: 'Action', event: MyEvent }"
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"type": "submit",
|
|
456
|
+
"category": "button",
|
|
457
|
+
"description": "Form submit button",
|
|
458
|
+
"baseInterface": "FieldDef",
|
|
459
|
+
"props": {},
|
|
460
|
+
"validationSupported": false,
|
|
461
|
+
"source": "adapter",
|
|
462
|
+
"allowedIn": ["top-level", "page", "row", "group", "array"],
|
|
463
|
+
"example": "{\n key: 'submit',\n type: 'submit',\n label: 'Submit Form'\n}",
|
|
464
|
+
"minimalExample": "{ key: 'submit', type: 'submit', label: 'Submit' }"
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
"type": "addArrayItem",
|
|
468
|
+
"category": "button",
|
|
469
|
+
"description": "Button to add a new item to an array field. Must be placed within or near the array container.",
|
|
470
|
+
"baseInterface": "FieldDef",
|
|
471
|
+
"props": {},
|
|
472
|
+
"validationSupported": false,
|
|
473
|
+
"source": "adapter",
|
|
474
|
+
"allowedIn": ["array", "row", "group"],
|
|
475
|
+
"example": "{\n key: 'addContact',\n type: 'addArrayItem',\n label: 'Add Contact'\n}",
|
|
476
|
+
"minimalExample": "{ key: 'add', type: 'addArrayItem', label: 'Add Item' }"
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"type": "removeArrayItem",
|
|
480
|
+
"category": "button",
|
|
481
|
+
"description": "Button to remove the current item from an array field. Typically placed within each array item template.",
|
|
482
|
+
"baseInterface": "FieldDef",
|
|
483
|
+
"props": {},
|
|
484
|
+
"validationSupported": false,
|
|
485
|
+
"source": "adapter",
|
|
486
|
+
"allowedIn": ["array", "row", "group"],
|
|
487
|
+
"example": "{\n key: 'removeContact',\n type: 'removeArrayItem',\n label: 'Remove'\n}",
|
|
488
|
+
"minimalExample": "{ key: 'remove', type: 'removeArrayItem', label: 'Remove' }"
|
|
489
|
+
}
|
|
490
|
+
]
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry module for loading generated JSON metadata
|
|
3
|
+
*
|
|
4
|
+
* This module provides access to field types, validators, and UI adapters
|
|
5
|
+
* that are generated at build time from the ng-forge packages.
|
|
6
|
+
*
|
|
7
|
+
* JSON data is imported directly to work correctly with esbuild bundling.
|
|
8
|
+
*/
|
|
9
|
+
export interface PropertyInfo {
|
|
10
|
+
name: string;
|
|
11
|
+
type: string;
|
|
12
|
+
description: string;
|
|
13
|
+
required: boolean;
|
|
14
|
+
default?: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface FieldTypeInfo {
|
|
17
|
+
type: string;
|
|
18
|
+
category: 'value' | 'container' | 'button' | 'display';
|
|
19
|
+
description: string;
|
|
20
|
+
valueType?: string;
|
|
21
|
+
baseInterface?: string;
|
|
22
|
+
props: Record<string, PropertyInfo>;
|
|
23
|
+
validationSupported: boolean;
|
|
24
|
+
example: string;
|
|
25
|
+
/** Field types that this container can contain (for containers only) */
|
|
26
|
+
canContain?: string[];
|
|
27
|
+
/** Field types that this container CANNOT contain (for containers only) */
|
|
28
|
+
cannotContain?: string[];
|
|
29
|
+
/** Where this field type is allowed to be placed */
|
|
30
|
+
allowedIn?: string[];
|
|
31
|
+
/** Where this field type is NOT allowed to be placed */
|
|
32
|
+
notAllowedIn?: string[];
|
|
33
|
+
/** Whether this field type is part of core library or requires an adapter */
|
|
34
|
+
source: 'core' | 'adapter';
|
|
35
|
+
/** Minimal valid example (just required properties) */
|
|
36
|
+
minimalExample?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface ValidatorInfo {
|
|
39
|
+
type: string;
|
|
40
|
+
category: 'built-in' | 'custom' | 'async' | 'http';
|
|
41
|
+
description: string;
|
|
42
|
+
parameters: Record<string, PropertyInfo>;
|
|
43
|
+
example: string;
|
|
44
|
+
}
|
|
45
|
+
export interface UIAdapterFieldType {
|
|
46
|
+
type: string;
|
|
47
|
+
componentName: string;
|
|
48
|
+
additionalProps: Record<string, PropertyInfo>;
|
|
49
|
+
}
|
|
50
|
+
export interface UIAdapterInfo {
|
|
51
|
+
library: string;
|
|
52
|
+
package: string;
|
|
53
|
+
fieldTypes: UIAdapterFieldType[];
|
|
54
|
+
providerFunction: string;
|
|
55
|
+
}
|
|
56
|
+
export interface DocTopic {
|
|
57
|
+
id: string;
|
|
58
|
+
title: string;
|
|
59
|
+
category: string;
|
|
60
|
+
content: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get all available field types
|
|
64
|
+
*/
|
|
65
|
+
export declare function getFieldTypes(): FieldTypeInfo[];
|
|
66
|
+
/**
|
|
67
|
+
* Get a specific field type by name
|
|
68
|
+
*/
|
|
69
|
+
export declare function getFieldType(type: string): FieldTypeInfo | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Get field types by category
|
|
72
|
+
*/
|
|
73
|
+
export declare function getFieldTypesByCategory(category: 'value' | 'container' | 'button' | 'display'): FieldTypeInfo[];
|
|
74
|
+
/**
|
|
75
|
+
* Get all available validators
|
|
76
|
+
*/
|
|
77
|
+
export declare function getValidators(): ValidatorInfo[];
|
|
78
|
+
/**
|
|
79
|
+
* Get a specific validator by type
|
|
80
|
+
*/
|
|
81
|
+
export declare function getValidator(type: string): ValidatorInfo | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Get validators by category
|
|
84
|
+
*/
|
|
85
|
+
export declare function getValidatorsByCategory(category: 'built-in' | 'custom' | 'async' | 'http'): ValidatorInfo[];
|
|
86
|
+
/**
|
|
87
|
+
* Get all UI adapters
|
|
88
|
+
*/
|
|
89
|
+
export declare function getUIAdapters(): UIAdapterInfo[];
|
|
90
|
+
/**
|
|
91
|
+
* Get a specific UI adapter by library name
|
|
92
|
+
*/
|
|
93
|
+
export declare function getUIAdapter(library: 'material' | 'bootstrap' | 'primeng' | 'ionic'): UIAdapterInfo | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Get UI adapter field type configuration
|
|
96
|
+
*/
|
|
97
|
+
export declare function getUIAdapterFieldType(library: 'material' | 'bootstrap' | 'primeng' | 'ionic', fieldType: string): UIAdapterFieldType | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Get all documentation topics
|
|
100
|
+
*/
|
|
101
|
+
export declare function getDocs(): DocTopic[];
|
|
102
|
+
/**
|
|
103
|
+
* Get a specific documentation topic by ID
|
|
104
|
+
*/
|
|
105
|
+
export declare function getDoc(id: string): DocTopic | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Get documentation topics by category
|
|
108
|
+
*/
|
|
109
|
+
export declare function getDocsByCategory(category: string): DocTopic[];
|
|
110
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACpC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAUD;;GAEG;AACH,wBAAgB,aAAa,IAAI,aAAa,EAAE,CAE/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEpE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,OAAO,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,EAAE,CAE/G;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,aAAa,EAAE,CAE/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEpE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,EAAE,CAE3G;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,aAAa,EAAE,CAE/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,GAAG,SAAS,CAE/G;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,EACvD,SAAS,EAAE,MAAM,GAChB,kBAAkB,GAAG,SAAS,CAGhC;AAED;;GAEG;AACH,wBAAgB,OAAO,IAAI,QAAQ,EAAE,CAkBpC;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAEvD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,CAE9D"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ng-forge Best Practices
|
|
3
|
+
*
|
|
4
|
+
* This content is served via the ng-forge://instructions resource
|
|
5
|
+
* to guide AI assistants in generating FormConfig objects.
|
|
6
|
+
*/
|
|
7
|
+
export declare const INSTRUCTIONS = "# ng-forge Dynamic Forms - Best Practices\n\nYou MUST follow these practices when generating FormConfig objects for ng-forge.\n\n## Core Principles\n\n1. **Configuration-driven**: ng-forge wraps Angular Reactive Forms. Define structure declaratively via `FormConfig`, not imperatively.\n2. **Type-safe**: Use TypeScript interfaces for form values. The library provides full type inference.\n3. **Validation-first**: Always include validation and user-friendly error messages.\n\n## FormConfig Structure\n\n```typescript\nconst config: FormConfig = {\n // Optional: Default validation messages for all fields\n defaultValidationMessages: {\n required: 'This field is required',\n email: 'Please enter a valid email',\n minLength: 'Must be at least {{requiredLength}} characters',\n },\n // Required: Array of field definitions\n fields: [\n // ... field definitions\n ],\n};\n```\n\n## Field Definition Rules\n\n### Required Properties\n\nEvery field MUST have:\n\n- `key`: Unique identifier (except for `row` type which is layout-only)\n- `type`: One of the registered field types\n- `label`: Human-readable label (for accessibility)\n\n### Value Fields\n\nFor fields that collect user input (`input`, `textarea`, `select`, `checkbox`, `radio`, `datepicker`, `toggle`, `slider`):\n\n```typescript\n{\n key: 'email',\n type: 'input',\n label: 'Email Address',\n required: true, // Shorthand validator\n email: true, // Shorthand validator\n validationMessages: { // Always provide clear messages\n required: 'Email is required',\n email: 'Please enter a valid email'\n },\n props: {\n type: 'email', // HTML input type\n placeholder: 'user@example.com',\n hint: 'We will never share your email' // UI library specific\n }\n}\n```\n\n### Select/Radio Fields\n\nMUST include `options` array:\n\n```typescript\n{\n key: 'country',\n type: 'select',\n label: 'Country',\n required: true,\n options: [\n { value: 'us', label: 'United States' },\n { value: 'uk', label: 'United Kingdom' }\n ],\n props: { placeholder: 'Select a country' }\n}\n```\n\n### Container Fields\n\n#### Row (Horizontal Layout)\n\nUse for side-by-side fields. Row fields do NOT create nested values - children are flat.\n\n```typescript\n{\n key: 'nameRow',\n type: 'row',\n fields: [\n { key: 'firstName', type: 'input', label: 'First', col: 6 },\n { key: 'lastName', type: 'input', label: 'Last', col: 6 }\n ]\n}\n// Result: { firstName: '...', lastName: '...' }\n```\n\nUse `col` property (1-12) to control column widths.\n\n#### Group (Nested Object)\n\nUse when you need nested object structure in form values:\n\n```typescript\n{\n key: 'address',\n type: 'group',\n fields: [\n { key: 'street', type: 'input', label: 'Street' },\n { key: 'city', type: 'input', label: 'City' }\n ]\n}\n// Result: { address: { street: '...', city: '...' } }\n```\n\n#### Array (Repeatable Items)\n\nUse for dynamic lists:\n\n```typescript\n{\n key: 'contacts',\n type: 'array',\n label: 'Emergency Contacts',\n fields: [\n {\n key: 'contact',\n type: 'group',\n fields: [\n { key: 'name', type: 'input', label: 'Name', required: true },\n { key: 'phone', type: 'input', label: 'Phone', required: true }\n ]\n }\n ]\n}\n// Result: { contacts: [{ name: '...', phone: '...' }, ...] }\n```\n\n#### Page (Multi-step Forms)\n\nUse for wizard-style forms:\n\n```typescript\n{\n fields: [\n {\n key: 'step1',\n type: 'page',\n fields: [\n { key: 'name', type: 'input', label: 'Name' },\n { key: 'next', type: 'next', label: 'Continue' },\n ],\n },\n {\n key: 'step2',\n type: 'page',\n fields: [\n { key: 'prev', type: 'previous', label: 'Back' },\n { key: 'submit', type: 'submit', label: 'Submit' },\n ],\n },\n ];\n}\n```\n\n## Validation\n\n### Shorthand Validators (Preferred)\n\nUse shorthand properties directly on field definitions:\n\n```typescript\n{\n key: 'age',\n type: 'input',\n label: 'Age',\n required: true,\n min: 18,\n max: 120,\n validationMessages: {\n required: 'Age is required',\n min: 'Must be at least {{min}}',\n max: 'Cannot exceed {{max}}'\n }\n}\n```\n\nAvailable shorthands: `required`, `email`, `min`, `max`, `minLength`, `maxLength`, `pattern`\n\n### Validation Messages\n\nALWAYS provide validation messages. Use template variables:\n\n- `{{requiredLength}}` - for minLength/maxLength\n- `{{min}}`, `{{max}}` - for min/max\n- `{{requiredPattern}}` - for pattern\n\n## Conditional Logic\n\nUse `logic` array for conditional behavior:\n\n```typescript\n{\n key: 'businessName',\n type: 'input',\n label: 'Business Name',\n logic: [\n {\n type: 'hidden',\n condition: {\n type: 'fieldValue',\n fieldPath: 'accountType',\n operator: 'notEquals',\n value: 'business'\n }\n },\n {\n type: 'required',\n condition: {\n type: 'fieldValue',\n fieldPath: 'accountType',\n operator: 'equals',\n value: 'business'\n }\n }\n ]\n}\n```\n\n### Logic Types\n\n- `hidden` - Show/hide field\n- `disabled` - Enable/disable field\n- `required` - Conditional requirement\n\n### Condition Operators\n\n- `equals`, `notEquals`\n- `greaterThan`, `lessThan`, `greaterThanOrEquals`, `lessThanOrEquals`\n- `contains`, `notContains`\n- `empty`, `notEmpty`\n\n## UI Library Integration\n\nng-forge supports multiple UI libraries. Configure in `app.config.ts`:\n\n```typescript\nimport { provideDynamicForm } from '@ng-forge/dynamic-forms';\nimport { withMaterialFields } from '@ng-forge/dynamic-forms-material';\n\nexport const appConfig = {\n providers: [provideDynamicForm(...withMaterialFields())],\n};\n```\n\nAvailable adapters:\n\n- `@ng-forge/dynamic-forms-material` - Angular Material\n- `@ng-forge/dynamic-forms-bootstrap` - Bootstrap 5\n- `@ng-forge/dynamic-forms-primeng` - PrimeNG\n- `@ng-forge/dynamic-forms-ionic` - Ionic\n\n## Common Patterns\n\n### Always End with Submit Button\n\n```typescript\n{ type: 'submit', key: 'submit', label: 'Submit', props: { color: 'primary' } }\n```\n\n### Use Text Fields for Headings\n\n```typescript\n{ key: 'sectionTitle', type: 'text', label: 'Personal Info', props: { elementType: 'h3' } }\n```\n\n### Input Types via Props\n\n```typescript\n// Email input\n{ key: 'email', type: 'input', props: { type: 'email' } }\n\n// Password input\n{ key: 'password', type: 'input', props: { type: 'password' } }\n\n// Number input\n{ key: 'age', type: 'input', props: { type: 'number' } }\n\n// Phone input\n{ key: 'phone', type: 'input', props: { type: 'tel' } }\n```\n\n## Anti-patterns to Avoid\n\n1. **Missing labels** - Always include labels for accessibility\n2. **Missing validation messages** - Users need clear feedback\n3. **Duplicate keys** - Each key must be unique within its scope\n4. **Select without options** - Select/radio fields must have options\n5. **Array without fields** - Array fields need a fields template\n6. **Group without fields** - Group fields need child fields\n7. **min > max** - Ensure min values are less than max values\n\n## CRITICAL: UI Library Differences\n\nDifferent UI libraries support different properties. Always validate against the correct library using `ngforge_validate_form_config` with the appropriate `uiIntegration` parameter.\n\n### Property Differences by Library\n\n| Property | Material | Bootstrap | PrimeNG | Ionic |\n|----------|----------|-----------|---------|-------|\n| `appearance` | \u2713 (fill, outline) | \u2717 | \u2717 | \u2713 (fill, outline) |\n| `subscriptSizing` | \u2713 | \u2717 | \u2717 | \u2717 |\n| `floatLabel` | \u2713 | \u2717 | \u2713 | \u2717 |\n| `hint` | \u2713 | \u2713 (as `helpText`) | \u2713 | \u2713 |\n\n### Container Fields\n\nContainer fields (`page`, `group`, `row`) do NOT support these properties:\n- `label` - Use `text` field type for headings instead\n- `required`, `email`, `min`, `max`, etc. - Validation is for leaf fields only\n\n### Common Mistakes to Avoid\n\n1. **Using `expressions` on fields** - This property is NOT supported on standard fields. Use `derivation` for computed values or `logic` for conditional behavior.\n\n2. **Adding `label` to container fields** - Pages, groups, and rows don't have labels:\n ```typescript\n // \u274C WRONG\n { key: 'address', type: 'group', label: 'Address', fields: [...] }\n\n // \u2705 CORRECT - Use a text field for the heading\n { key: 'addressTitle', type: 'text', label: 'Address', props: { elementType: 'h3' } }\n { key: 'address', type: 'group', fields: [...] }\n ```\n\n3. **Adding `id` to FormConfig** - The root FormConfig does not accept an `id` property.\n\n4. **Putting slider min/max in props** - For slider fields, `min`, `max`, and `step` are field-level properties:\n ```typescript\n // \u274C WRONG\n { key: 'volume', type: 'slider', label: 'Volume', props: { min: 0, max: 100 } }\n\n // \u2705 CORRECT\n { key: 'volume', type: 'slider', label: 'Volume', min: 0, max: 100 }\n ```\n\n5. **Using unsupported field types** - Each UI library supports specific field types. Use `ngforge_get_field_schema` to see available types.\n\n## Validation Before Use\n\nAlways validate your FormConfig using the `ngforge_validate_form_config` tool before using it. This tool uses the actual TypeScript/Zod schemas, so if validation passes, the config will work correctly at runtime.\n\n```typescript\n// Always specify the UI integration you're using\nngforge_validate_form_config({\n uiIntegration: 'material', // or 'bootstrap', 'primeng', 'ionic'\n config: { fields: [...] }\n})\n```\n\nTo understand what properties are supported for each field type, use `ngforge_get_field_schema`:\n\n```typescript\nngforge_get_field_schema({ uiIntegration: 'material' })\n```\n";
|
|
8
|
+
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/instructions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,YAAY,4rTA4WxB,CAAC"}
|