npm package: @kodeme-io/next-core-forms
Description: Dynamic form builder and validation for Next.js applications
Author: ABC Food
Latest version: 0.8.4

# @kodeme-io/next-core-forms

Dynamic form builder and validation for Next.js applications with TypeScript support and Zod integration.

## 🚀 Features

- **📝 Dynamic Form Generation** - Build forms from JSON definitions
- **✅ Powerful Validation** - Zod-based validation with custom rules
- **🔄 Array Fields** - Dynamic field lists with add/remove functionality
- **🎯 Cross-Field Validation** - Validate relationships between multiple fields
- **🧭 Form Wizard** - Multi-step forms with progress tracking
- **🎨 Flexible Components** - Pre-built form components and layouts
- **🔄 Conditional Fields** - Show/hide fields based on user input
- **📱 Mobile-First** - Responsive design optimized for all devices
- **♿ Accessible** - WCAG compliant with proper ARIA labels
- **🔧 TypeScript Native** - Full type safety and IntelliSense support
- **⚡ Performance Optimized** - Cached validation and efficient rendering

## 📦 Installation

```bash
npm install @kodeme-io/next-core-forms
# or
yarn add @kodeme-io/next-core-forms
# or
pnpm add @kodeme-io/next-core-forms
```

### Peer Dependencies

```bash
npm install react react-hook-form zod
```

## 🎯 Quick Start

### Basic Form Example

```tsx
'use client'

import { DynamicForm, FormDefinition } from '@kodeme-io/next-core-forms'
import { z } from 'zod'

const registrationForm: FormDefinition = {
  id: 'registration',
  title: 'User Registration',
  description: 'Create your account',
  sections: [
    {
      id: 'personal-info',
      title: 'Personal Information',
      fields: [
        {
          name: 'firstName',
          label: 'First Name',
          type: 'text',
          required: true,
          placeholder: 'Enter your first name',
          validation: z.string().min(2, 'Must be at least 2 characters')
        },
        {
          name: 'email',
          label: 'Email Address',
          type: 'email',
          required: true,
          validation: z.string().email('Invalid email address')
        },
        {
          name: 'password',
          label: 'Password',
          type: 'password',
          required: true,
          validation: z.string().min(8, 'Password must be at least 8 characters')
        }
      ]
    }
  ],
  submitLabel: 'Register',
  layout: 'vertical'
}

export default function RegistrationPage() {
  const handleSubmit = async (data: any) => {
    console.log('Form submitted:', data)
    // Handle form submission
  }

  return (
    <div className="max-w-md mx-auto">
      <DynamicForm form={registrationForm} onSubmit={handleSubmit} />
    </div>
  )
}
```

## 📚 Core Concepts

### Form Definition Structure

```typescript
interface FormDefinition {
  id: string                    // Unique form identifier
  title: string                 // Form title
  description?: string          // Optional description
  sections: FormSection[]       // Form sections
  submitLabel?: string          // Submit button text
  cancelLabel?: string          // Cancel button text
  layout?: 'vertical' | 'horizontal' | 'grid'  // Layout style
}
```

### Field Types

Supported field types:

- `text` - Single line text input
- `email` - Email input with validation
- `number` - Numeric input
- `tel` - Telephone number input
- `url` - URL input
- `password` - Password input
- `textarea` - Multi-line text input
- `select` - Single select dropdown
- `multiselect` - Multi-select dropdown
- `checkbox` - Single checkbox
- `radio` - Radio button group
- `date` - Date picker
- `time` - Time picker
- `datetime` - Date and time picker
- `file` - File upload
- `array` - Dynamic field lists with add/remove functionality
- `custom` - Custom field component

### Field Definition

```typescript
interface FieldDefinition {
  name: string                  // Field name (form data key)
  label: string                 // Display label
  type: FieldType              // Field type
  placeholder?: string         // Placeholder text
  defaultValue?: any          // Default value
  required?: boolean           // Required field
  options?: FieldOption[]     // Options for select/radio
  validation?: ZodType       // Zod validation schema
  helperText?: string         // Help text
  disabled?: boolean          // Disabled state
  hidden?: boolean            // Hidden field
  dependsOn?: {               // Conditional display
    field: string
    value: any
    condition?: 'equals' | 'not_equals' | 'contains'
  }
  arrayConfig?: ArrayFieldConfig // Configuration for array fields
}

interface ArrayFieldConfig {
  minItems?: number           // Minimum number of items
  maxItems?: number           // Maximum number of items
  itemLabel: string           // Label for each item
  addLabel?: string           // Add button label
  removeLabel?: string        // Remove button label
  canReorder?: boolean        // Allow reordering items
  fields: FieldDefinition[]   // Field definitions for array items
}
```

## 🎨 Components

### DynamicForm

Main component for rendering forms from definitions.

```tsx
<DynamicForm
  form={formDefinition}
  onSubmit={handleSubmit}
  onSubmitSuccess={handleSuccess}
  onSubmitError={handleError}
  className="custom-form"
  disabled={false}
/>
```

### Form Components

Lower-level components for custom form building:

```tsx
import {
  FormProvider,
  FormField,
  FormItem,
  FormLabel,
  FormControl,
  FormMessage
} from '@kodeme-io/next-core-forms'

function CustomForm() {
  const form = useForm({
    defaultValues: { name: '', email: '' }
  })

  return (
    <FormProvider {...form}>
      <FormField
        name="name"
        render={({ field }) => (
          <FormItem>
            <FormLabel>Name</FormLabel>
            <FormControl>
              <input {...field} />
            </FormControl>
            <FormMessage />
          </FormItem>
        )}
      />
    </FormProvider>
  )
}
```

### FormSection

Section component with collapsible support:

```tsx
<FormSection
  section={sectionDefinition}
  defaultCollapsed={false}
  onToggle={(collapsed) => console.log(collapsed)}
>
  {/* Custom section content */}
</FormSection>
```

## ✅ Validation

### Built-in Validation

Using Zod for powerful validation:

```tsx
import { z } from 'zod'

const validationSchema = z.object({
  email: z.string().email('Invalid email'),
  password: z.string()
    .min(8, 'Password must be at least 8 characters')
    .regex(/[A-Z]/, 'Must contain uppercase letter')
    .regex(/[0-9]/, 'Must contain number'),
  age: z.number().min(18, 'Must be 18 or older'),
  terms: z.boolean().refine(val => val === true, 'Must accept terms')
})

const field: FieldDefinition = {
  name: 'email',
  label: 'Email',
  type: 'email',
  required: true,
  validation: validationSchema.shape.email
}
```

### Custom Validation

Create custom validation rules:

```tsx
const customValidation = z.string().refine(
  (val) => !val.includes('spam'),
  'Email cannot contain "spam"'
)

const field: FieldDefinition = {
  name: 'customEmail',
  label: 'Email',
  type: 'email',
  validation: customValidation
}
```

### Async Validation

For server-side validation:

```tsx
const asyncValidation = z.string().refine(
  async (email) => {
    const response = await fetch(`/api/check-email?email=${email}`)
    const data = await response.json()
    return !data.exists
  },
  'Email already exists'
)
```

## 🔄 Array Fields

Dynamic field lists with add/remove functionality:

```tsx
const arrayFieldForm: FormDefinition = {
  id: 'array-form',
  title: 'Array Field Example',
  sections: [
    {
      id: 'phone-numbers',
      title: 'Phone Numbers',
      fields: [
        {
          name: 'phoneNumbers',
          label: 'Phone Numbers',
          type: 'array',
          required: true,
          arrayConfig: {
            minItems: 1,
            maxItems: 5,
            itemLabel: 'Phone Number',
            addLabel: 'Add Phone',
            removeLabel: 'Remove',
            canReorder: true,
            fields: [
              {
                name: 'type',
                label: 'Type',
                type: 'select',
                required: true,
                options: [
                  { label: 'Mobile', value: 'mobile' },
                  { label: 'Home', value: 'home' },
                  { label: 'Work', value: 'work' }
                ]
              },
              {
                name: 'number',
                label: 'Phone Number',
                type: 'tel',
                required: true,
                validation: z.string().regex(/^[0-9+\-\s()]+$/, 'Invalid phone number')
              }
            ]
          },
          validation: z.array(z.object({
            type: z.enum(['mobile', 'home', 'work']),
            number: z.string().regex(/^[0-9+\-\s()]+$/)
          })).min(1, 'At least one phone number required')
        }
      ]
    }
  ]
}
```

## 🎯 Cross-Field Validation

Validate relationships between multiple fields:

```tsx
import { commonCrossFieldRules } from '@kodeme-io/next-core-forms'

const crossFieldForm: FormDefinition = {
  id: 'cross-field-form',
  title: 'Cross-Field Validation Example',
  sections: [
    // ... sections with password and confirmPassword fields
    // ... sections with startDate and endDate fields
  ],
  crossFieldRules: [
    commonCrossFieldRules.passwordMatch('password', 'confirmPassword'),
    commonCrossFieldRules.dateRange('startDate', 'endDate'),
    commonCrossFieldRules.minAge('birthDate', 18),
    {
      name: 'customRule',
      message: 'Custom validation message',
      validate: (formData) => {
        // Return true if valid, false or string if invalid
        return formData.field1 !== formData.field2
      }
    }
  ]
}
```

## 🧭 Form Wizard

Multi-step forms with progress tracking:

```tsx
import { FormWizard } from '@kodeme-io/next-core-forms'

export default function MultiStepForm() {
  return (
    <FormWizard
      form={multiStepFormDefinition}
      onStepChange={(stepIndex, stepData) => {
        console.log(`Step ${stepIndex + 1}:`, stepData)
      }}
      onComplete={() => {
        console.log('Wizard completed')
      }}
    />
  )
}
```

## 🔄 Conditional Fields

Show/hide fields based on other field values:

```tsx
const formWithConditionalFields: FormDefinition = {
  id: 'conditional-form',
  title: 'Conditional Form',
  sections: [
    {
      id: 'main',
      title: 'Main Section',
      fields: [
        {
          name: 'hasAccount',
          label: 'Do you have an account?',
          type: 'radio',
          options: [
            { label: 'Yes', value: 'yes' },
            { label: 'No', value: 'no' }
          ],
          required: true
        },
        {
          name: 'email',
          label: 'Email Address',
          type: 'email',
          required: true,
          validation: z.string().email(),
          dependsOn: {
            field: 'hasAccount',
            value: 'yes',
            condition: 'equals'
          }
        },
        {
          name: 'newEmail',
          label: 'New Email Address',
          type: 'email',
          required: true,
          validation: z.string().email(),
          dependsOn: {
            field: 'hasAccount',
            value: 'no',
            condition: 'equals'
          }
        }
      ]
    }
  ]
}
```

## 🎯 Advanced Usage

### Multi-Step Forms

```tsx
const multiStepForm: FormDefinition = {
  id: 'multi-step',
  title: 'Multi-Step Registration',
  sections: [
    {
      id: 'step1',
      title: 'Personal Information',
      fields: [
        { name: 'firstName', label: 'First Name', type: 'text', required: true },
        { name: 'lastName', label: 'Last Name', type: 'text', required: true }
      ],
      collapsible: true,
      defaultCollapsed: false
    },
    {
      id: 'step2',
      title: 'Contact Information',
      fields: [
        { name: 'email', label: 'Email', type: 'email', required: true },
        { name: 'phone', label: 'Phone', type: 'tel', required: true }
      ],
      collapsible: true,
      defaultCollapsed: true
    },
    {
      id: 'step3',
      title: 'Preferences',
      fields: [
        { name: 'newsletter', label: 'Subscribe to newsletter', type: 'checkbox' },
        { name: 'notifications', label: 'Enable notifications', type: 'checkbox' }
      ],
      collapsible: true,
      defaultCollapsed: true
    }
  ]
}
```

### Form with File Upload

```tsx
const fileUploadForm: FormDefinition = {
  id: 'upload-form',
  title: 'File Upload',
  sections: [
    {
      id: 'upload',
      title: 'Upload Document',
      fields: [
        {
          name: 'document',
          label: 'Document (PDF, DOC, DOCX)',
          type: 'file',
          required: true,
          validation: z.instanceof(File).refine(
            (file) => file.size <= 10 * 1024 * 1024, // 10MB
            'File must be smaller than 10MB'
          ).refine(
            (file) => ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'].includes(file.type),
            'Invalid file type'
          )
        }
      ]
    }
  ]
}
```

## 🧪 Testing

The package includes comprehensive test coverage:

```bash
# Run tests
npm test

# Run with coverage
npm run test:coverage

# Run tests in watch mode
npm run test:watch
```

### Testing Custom Forms

```tsx
import { render, screen, fireEvent } from '@testing-library/react'
import { DynamicForm } from '@kodeme-io/next-core-forms'

test('form submission', async () => {
  const handleSubmit = jest.fn()

  render(<DynamicForm form={testForm} onSubmit={handleSubmit} />)

  fireEvent.change(screen.getByLabelText('Name'), {
    target: { value: 'John Doe' }
  })

  fireEvent.click(screen.getByText('Submit'))

  await waitFor(() => {
    expect(handleSubmit).toHaveBeenCalledWith({ name: 'John Doe' })
  })
})
```

## 🔧 API Reference

### Types

```typescript
// Core types
export type FieldType = 'text' | 'email' | 'number' | 'tel' | 'url' | 'password' | 'textarea' | 'select' | 'multiselect' | 'checkbox' | 'radio' | 'date' | 'time' | 'datetime' | 'file' | 'custom'

export interface FieldOption {
  label: string
  value: string | number
  disabled?: boolean
}

export interface FormState<T = any> {
  values: T
  errors: Record<string, string>
  touched: Record<string, boolean>
  isDirty: boolean
  isSubmitting: boolean
  isValid: boolean
}

// Component props
export interface DynamicFormProps {
  form: FormDefinition
  onSubmit: (data: any) => void | Promise<void>
  onSubmitSuccess?: (data: any) => void
  onSubmitError?: (error: Error) => void
  className?: string
  disabled?: boolean
  defaultValues?: Record<string, any>
}
```

### Utilities

```typescript
// Validation utilities
export function validateField(field: FieldDefinition, value: any): ValidationResult
export function validateForm(form: FormDefinition, data: any, partial?: boolean): FormValidationResult
export function createFormValidator(schema: ZodSchema): ZodSchema

// Form utilities
export function getDefaultValues(form: FormDefinition): Record<string, any>
export function getFormData(form: FormDefinition): any
export function resetForm(form: FormDefinition): void
```

## 🔍 Troubleshooting

### Common Issues

1. **Validation Not Working**
   - Ensure Zod schema is properly configured
   - Check that validation is assigned to the correct field
   - Verify field names match form data keys

2. **Conditional Fields Not Showing**
   - Check the `dependsOn` configuration
   - Ensure the dependent field has the correct value
   - Verify the condition logic

3. **Form Not Submitting**
   - Check if form is valid (`isValid` state)
   - Ensure onSubmit handler is properly defined
   - Check for validation errors

## 🤝 Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Submit a pull request

## 📄 License

MIT License - see LICENSE file for details

## 🔗 Related Packages

- [@kodeme-io/next-core-ui](../ui/README.md) - UI components
- [@kodeme-io/next-core-workflow](../workflow/README.md) - Workflow management
- [@kodeme-io/next-core-analytics](../analytics/README.md) - Analytics and charts

## 📞 Support

- Documentation: [Full documentation](https://docs.abc-food.com/next-core/forms)
- Issues: [GitHub Issues](https://github.com/abc-food/next-core/issues)
- Discord: [Community Discord](https://discord.gg/abc-food)