@ng-forge/dynamic-form-mcp 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/ng-forge-mcp.js +1192 -307
- package/package.json +7 -7
- package/src/index.js +1192 -307
- package/src/registry/api-reference.json +76 -25
- package/src/registry/docs.json +45 -15
- package/src/registry/field-types.json +18 -6
- package/src/registry/instructions.d.ts +1 -1
- package/src/registry/instructions.d.ts.map +1 -1
- package/src/registry/validators.json +56 -4
- package/src/tools/data/lookup-topics.d.ts.map +1 -1
- package/src/tools/examples.tool.d.ts.map +1 -1
- package/src/tools/scaffold.tool.d.ts.map +1 -1
- package/src/tools/validate.tool.d.ts.map +1 -1
|
@@ -250,7 +250,7 @@
|
|
|
250
250
|
{
|
|
251
251
|
"type": "row",
|
|
252
252
|
"category": "container",
|
|
253
|
-
"description": "Horizontal layout container for grouping fields in columns. Rows do NOT have a label property
|
|
253
|
+
"description": "Horizontal layout container for grouping fields in columns. Rows do NOT have a label property. Supports only 'hidden' logic type for conditional visibility.",
|
|
254
254
|
"baseInterface": "FieldDef",
|
|
255
255
|
"props": {
|
|
256
256
|
"fields": {
|
|
@@ -283,13 +283,13 @@
|
|
|
283
283
|
"previous"
|
|
284
284
|
],
|
|
285
285
|
"cannotContain": ["page", "row", "hidden"],
|
|
286
|
-
"example": "{\n key: 'nameRow',\n type: 'row',\n // NOTE: Rows do NOT have label
|
|
286
|
+
"example": "{\n key: 'nameRow',\n type: 'row',\n // NOTE: Rows do NOT have a label property\n // Rows support only 'hidden' logic type for conditional visibility\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
287
|
"minimalExample": "{ key: 'row1', type: 'row', fields: [...] }"
|
|
288
288
|
},
|
|
289
289
|
{
|
|
290
290
|
"type": "group",
|
|
291
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.",
|
|
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. Supports only 'hidden' logic type for conditional visibility.",
|
|
293
293
|
"valueType": "object",
|
|
294
294
|
"baseInterface": "FieldDef",
|
|
295
295
|
"props": {
|
|
@@ -329,7 +329,7 @@
|
|
|
329
329
|
{
|
|
330
330
|
"type": "array",
|
|
331
331
|
"category": "container",
|
|
332
|
-
"description": "Repeatable field group for dynamic lists/arrays. Arrays do NOT have label
|
|
332
|
+
"description": "Repeatable field group for dynamic lists/arrays. Arrays do NOT have a label property. Use \"fields\" (not \"template\") to define the item template. Supports only 'hidden' logic type for conditional visibility. Supports minLength/maxLength for array size validation. Each array item is rendered inside a `<div class=\"df-array-item\">` wrapper with `role=\"group\"`, `aria-label=\"Item N\"` (1-based), `data-array-item-id`, and `data-array-item-index` attributes for styling, accessibility, and testing.",
|
|
333
333
|
"valueType": "T[]",
|
|
334
334
|
"baseInterface": "FieldDef",
|
|
335
335
|
"props": {
|
|
@@ -338,9 +338,21 @@
|
|
|
338
338
|
"type": "ArrayAllowedChildren[]",
|
|
339
339
|
"description": "Template field(s) for each array item. Allowed: rows, groups, leaf fields (NOT pages or other arrays)",
|
|
340
340
|
"required": true
|
|
341
|
+
},
|
|
342
|
+
"minLength": {
|
|
343
|
+
"name": "minLength",
|
|
344
|
+
"type": "number",
|
|
345
|
+
"description": "Minimum number of items required in the array. Validation fails if fewer items.",
|
|
346
|
+
"required": false
|
|
347
|
+
},
|
|
348
|
+
"maxLength": {
|
|
349
|
+
"name": "maxLength",
|
|
350
|
+
"type": "number",
|
|
351
|
+
"description": "Maximum number of items allowed in the array. Validation fails if more items.",
|
|
352
|
+
"required": false
|
|
341
353
|
}
|
|
342
354
|
},
|
|
343
|
-
"validationSupported":
|
|
355
|
+
"validationSupported": true,
|
|
344
356
|
"source": "core",
|
|
345
357
|
"allowedIn": ["top-level", "page", "row", "group"],
|
|
346
358
|
"notAllowedIn": ["array"],
|
|
@@ -364,7 +376,7 @@
|
|
|
364
376
|
"previous"
|
|
365
377
|
],
|
|
366
378
|
"cannotContain": ["page", "array"],
|
|
367
|
-
"example": "// Flat array
|
|
379
|
+
"example": "// Flat array with length validation\n{\n key: 'tags',\n type: 'array',\n minLength: 1, // At least one tag required\n maxLength: 5, // No more than 5 tags\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 minLength: 1,\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
380
|
"minimalExample": "{ key: 'items', type: 'array', fields: [...] }"
|
|
369
381
|
},
|
|
370
382
|
{
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* This content is served via the ng-forge://instructions resource
|
|
5
5
|
* to guide AI assistants in generating FormConfig objects.
|
|
6
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";
|
|
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. Each item is wrapped in a `<div class=\"df-array-item\">` with `role=\"group\"` and `aria-label=\"Item N\"` for accessibility. Use `--df-array-item-gap` CSS variable to control spacing between items.\n\n```typescript\n{\n key: 'contacts',\n type: 'array',\n // \u26A0\uFE0F NO label property on arrays!\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
8
|
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -1 +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,
|
|
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,o5TA4WxB,CAAC"}
|
|
@@ -115,10 +115,30 @@
|
|
|
115
115
|
},
|
|
116
116
|
"example": "// Expression-based custom validator with error message\n// The validator:\n{\n type: 'custom',\n expression: 'fieldValue === formValue.password',\n kind: 'passwordMismatch' // Just the error KIND, not the message\n}\n\n// COMPLETE FIELD with validationMessages at FIELD level:\n{\n key: 'confirmPassword',\n type: 'input',\n label: 'Confirm Password',\n props: { type: 'password' },\n validators: [\n { type: 'custom', expression: 'fieldValue === formValue.password', kind: 'passwordMismatch' }\n ],\n validationMessages: {\n passwordMismatch: 'Passwords do not match' // Message goes HERE at field level\n }\n}"
|
|
117
117
|
},
|
|
118
|
+
{
|
|
119
|
+
"type": "async",
|
|
120
|
+
"category": "async",
|
|
121
|
+
"description": "Async validator using registered async function (resource-based). Register the function via customFnConfig.asyncValidators.",
|
|
122
|
+
"parameters": {
|
|
123
|
+
"functionName": {
|
|
124
|
+
"name": "functionName",
|
|
125
|
+
"type": "string",
|
|
126
|
+
"description": "Name of registered async validator function",
|
|
127
|
+
"required": true
|
|
128
|
+
},
|
|
129
|
+
"params": {
|
|
130
|
+
"name": "params",
|
|
131
|
+
"type": "Record<string, unknown>",
|
|
132
|
+
"description": "Parameters to pass to validator function",
|
|
133
|
+
"required": false
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"example": "{\n type: 'async',\n functionName: 'checkUsernameAvailability'\n}"
|
|
137
|
+
},
|
|
118
138
|
{
|
|
119
139
|
"type": "customAsync",
|
|
120
140
|
"category": "async",
|
|
121
|
-
"description": "Async validator using registered async function",
|
|
141
|
+
"description": "DEPRECATED — use type: 'async' instead. Async validator using registered async function.",
|
|
122
142
|
"parameters": {
|
|
123
143
|
"functionName": {
|
|
124
144
|
"name": "functionName",
|
|
@@ -133,12 +153,12 @@
|
|
|
133
153
|
"required": false
|
|
134
154
|
}
|
|
135
155
|
},
|
|
136
|
-
"example": "{\n type: 'customAsync',\n functionName: 'checkUsernameAvailability'\n}"
|
|
156
|
+
"example": "// DEPRECATED — use type: 'async' instead\n{\n type: 'customAsync',\n functionName: 'checkUsernameAvailability'\n}"
|
|
137
157
|
},
|
|
138
158
|
{
|
|
139
159
|
"type": "customHttp",
|
|
140
160
|
"category": "http",
|
|
141
|
-
"description": "HTTP-based validator with automatic request cancellation",
|
|
161
|
+
"description": "DEPRECATED — use type: 'http' with functionName instead. HTTP-based validator with automatic request cancellation.",
|
|
142
162
|
"parameters": {
|
|
143
163
|
"functionName": {
|
|
144
164
|
"name": "functionName",
|
|
@@ -153,6 +173,38 @@
|
|
|
153
173
|
"required": false
|
|
154
174
|
}
|
|
155
175
|
},
|
|
156
|
-
"example": "{\n type: 'customHttp',\n functionName: 'validateEmailExists'\n}"
|
|
176
|
+
"example": "// DEPRECATED — use type: 'http' with functionName instead\n{\n type: 'customHttp',\n functionName: 'validateEmailExists'\n}"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"type": "http",
|
|
180
|
+
"category": "http",
|
|
181
|
+
"description": "HTTP validator — supports two modes: (1) Declarative (fully JSON-serializable, no function registration) using http + responseMapping properties, or (2) Function-based using functionName to reference a registered HTTP validator function. Query param values and (optionally) body values are expressions evaluated against the form context. Response mapping uses validWhen (truthy = valid) and errorKind (maps to field-level validationMessages).",
|
|
182
|
+
"parameters": {
|
|
183
|
+
"functionName": {
|
|
184
|
+
"name": "functionName",
|
|
185
|
+
"type": "string",
|
|
186
|
+
"description": "Name of registered HTTP validator function (function-based mode). Mutually exclusive with http + responseMapping.",
|
|
187
|
+
"required": false
|
|
188
|
+
},
|
|
189
|
+
"http": {
|
|
190
|
+
"name": "http",
|
|
191
|
+
"type": "HttpRequestConfig",
|
|
192
|
+
"description": "HTTP request configuration: { url, method?, queryParams?, body?, evaluateBodyExpressions?, headers?, debounceMs? }. queryParams values are expressions. When evaluateBodyExpressions is true, top-level string values in body are evaluated as expressions (shallow only). Required for declarative mode.",
|
|
193
|
+
"required": false
|
|
194
|
+
},
|
|
195
|
+
"responseMapping": {
|
|
196
|
+
"name": "responseMapping",
|
|
197
|
+
"type": "HttpValidationResponseMapping",
|
|
198
|
+
"description": "Response mapping: { validWhen, errorKind, errorParams? }. validWhen is an expression evaluated with { response } scope — truthy means valid. errorKind maps to field-level validationMessages. Required for declarative mode.",
|
|
199
|
+
"required": false
|
|
200
|
+
},
|
|
201
|
+
"params": {
|
|
202
|
+
"name": "params",
|
|
203
|
+
"type": "Record<string, unknown>",
|
|
204
|
+
"description": "Parameters to pass to HTTP validator function (function-based mode only).",
|
|
205
|
+
"required": false
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"example": "// HTTP validator (fully JSON-serializable)\n{\n type: 'http',\n http: {\n url: '/api/validate-username',\n method: 'GET',\n queryParams: {\n username: 'fieldValue'\n }\n },\n responseMapping: {\n validWhen: 'response.available',\n errorKind: 'usernameTaken',\n errorParams: {\n suggestion: 'response.suggestion'\n }\n }\n}\n\n// COMPLETE FIELD with validationMessages at FIELD level:\n{\n key: 'username',\n type: 'input',\n label: 'Username',\n validators: [\n {\n type: 'http',\n http: {\n url: '/api/validate-username',\n method: 'GET',\n queryParams: { username: 'fieldValue' }\n },\n responseMapping: {\n validWhen: 'response.available',\n errorKind: 'usernameTaken',\n errorParams: { suggestion: 'response.suggestion' }\n }\n }\n ],\n validationMessages: {\n usernameTaken: 'Username is taken. Try {{suggestion}}'\n }\n}"
|
|
157
209
|
}
|
|
158
210
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lookup-topics.d.ts","sourceRoot":"","sources":["../../../../../../packages/dynamic-form-mcp/src/tools/data/lookup-topics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"lookup-topics.d.ts","sourceRoot":"","sources":["../../../../../../packages/dynamic-form-mcp/src/tools/data/lookup-topics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAo4ElE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA8HhD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"examples.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/examples.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"examples.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/examples.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsuEpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuI5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/scaffold.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"scaffold.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/scaffold.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4VpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8E5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/validate.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/validate.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAyQpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2J5D"}
|