# finform-react-builder

A powerful, flexible React form builder with dynamic field rendering, custom validation, and Material-UI integration.

[![npm version](https://badge.fury.io/js/finform-react-builder.svg)](https://www.npmjs.com/package/finform-react-builder)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## 🚨 Migration Notice

**If you're currently using this package from GitHub Packages**, you'll need to update your installation:

```bash
# Remove the old package
npm uninstall @finflow-analytics/finform-react-builder

# Install from public npm registry
npm install finform-react-builder
```

If you have a `.npmrc` file with GitHub Packages configuration, remove the line:
```
@finflow-analytics:registry=https://npm.pkg.github.com
```

## ✨ Features

- 🎨 **Material-UI Integration** - Beautiful, responsive form components
- 🔧 **Dynamic Field Rendering** - Support for text, email, password, number, select, checkbox, date, and textarea fields
- ✅ **Advanced Validation** - Built-in validation with custom regex patterns and validation functions
- 📱 **Responsive Grid System** - Flexible column-based layout system
- 🎯 **TypeScript Support** - Full type safety and IntelliSense support
- 🚀 **Easy Integration** - Simple API with sensible defaults
- 🔄 **Real-time Validation** - Instant feedback with react-hook-form
- 🎨 **Customizable** - Highly configurable with custom validation rules
- 🔄 **Multi-Step Forms** - Support for step-by-step form completion with smart navigation
- 💾 **Stateless Design** - Works with data from backend/config without local storage dependencies

## 📦 Installation

```bash
npm install finform-react-builder
```

### Peer Dependencies

Make sure you have the required peer dependencies installed:

```bash
npm install react react-dom @mui/material @emotion/react @emotion/styled
```

## 🚀 Quick Start

```tsx
import React from 'react';
import { FinForm, FieldConfig } from 'finform-react-builder';

const fields: FieldConfig[] = [
  {
    name: 'firstName',
    label: 'First Name',
    type: 'text',
    placeholder: 'Enter your first name',
    required: true,
    col: 6
  },
  {
    name: 'lastName',
    label: 'Last Name',
    type: 'text',
    placeholder: 'Enter your last name',
    required: true,
    col: 6
  },
  {
    name: 'email',
    label: 'Email',
    type: 'email',
    placeholder: 'Enter your email',
    required: true,
    col: 12
  }
];

function App() {
  const handleSubmit = (data: any) => {
    console.log('Form submitted:', data);
  };

  return (
    <FinForm
      fields={fields}
      onSubmit={handleSubmit}
      submitButtonText="Submit Form"
    />
  );
}

export default App;
```

## 📋 Field Types

### Text Fields
```tsx
{
  name: 'username',
  label: 'Username',
  type: 'text',
  placeholder: 'Enter username',
  validation: {
    pattern: /^[a-zA-Z0-9_]+$/,
    message: 'Username can only contain letters, numbers, and underscores'
  }
}
```

### Email Fields
```tsx
{
  name: 'email',
  label: 'Email Address',
  type: 'email',
  placeholder: 'Enter your email',
  required: true
}
```

### Number Fields
```tsx
{
  name: 'age',
  label: 'Age',
  type: 'number',
  placeholder: 'Enter your age',
  validation: {
    min: 18,
    max: 120,
    message: 'Age must be between 18 and 120'
  }
}
```

### Select Fields
```tsx
{
  name: 'country',
  label: 'Country',
  type: 'select',
  options: [
    { label: 'United States', value: 'us' },
    { label: 'Canada', value: 'ca' },
    { label: 'United Kingdom', value: 'uk' }
  ],
  required: true
}
```

### Date Fields
```tsx
{
  name: 'birthDate',
  label: 'Birth Date',
  type: 'date',
  validation: {
    custom: (value) => {
      const today = new Date();
      const birthDate = new Date(value);
      return birthDate < today;
    },
    message: 'Birth date must be in the past'
  }
}
```

### Image Fields
```tsx
{
  name: 'profileImage',
  label: 'Profile Image',
  type: 'image',
  src: 'https://example.com/image.jpg',
  alt: 'User profile image',
  width: 300,
  height: 200,
  style: {
    border: '2px solid #e0e0e0',
    borderRadius: '8px'
  },
  onClick: () => {
    console.log('Image clicked!');
  }
}
```

### Textarea Fields
```tsx
{
  name: 'bio',
  label: 'Biography',
  type: 'textarea',
  placeholder: 'Tell us about yourself...',
  validation: {
    maxLength: 500,
    message: 'Biography must be less than 500 characters'
  }
}
```

### Checkbox Fields
```tsx
{
  name: 'newsletter',
  label: 'Subscribe to Newsletter',
  type: 'checkbox',
  required: true
}
```

## 🔧 Advanced Validation

### Custom Regex Patterns
```tsx
{
  name: 'phoneNumber',
  label: 'Phone Number',
  type: 'text',
  placeholder: '+1 (555) 123-4567',
  validation: {
    pattern: /^\+?[1-9]\d{1,14}$/,
    message: 'Please enter a valid phone number'
  }
}
```

### Custom Validation Functions
```tsx
{
  name: 'password',
  label: 'Password',
  type: 'password',
  placeholder: 'Enter password',
  validation: {
    minLength: 8,
    custom: (value) => {
      const hasUpperCase = /[A-Z]/.test(value);
      const hasLowerCase = /[a-z]/.test(value);
      const hasNumbers = /\d/.test(value);
      const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(value);
      
      return hasUpperCase && hasLowerCase && hasNumbers && hasSpecialChar;
    },
    message: 'Password must contain uppercase, lowercase, number and special character'
  }
}
```

## 📐 Grid System

Use the responsive grid system to control field layout:

```tsx
// Full width field
{ name: 'description', type: 'textarea', col: 12 }

// Half width fields
{ name: 'firstName', type: 'text', col: 6 }
{ name: 'lastName', type: 'text', col: 6 }

// Responsive breakpoints
{
  name: 'address',
  type: 'text',
  xs: 12,  // Full width on extra small screens
  md: 8,   // 8/12 width on medium screens
  lg: 6    // Half width on large screens
}
```

## 🔄 Multi-Step Forms

FinForm supports multi-step forms with smart navigation and completion tracking. Perfect for complex forms that need to be broken down into manageable steps.

### Basic Multi-Step Form

```tsx
const multiStepFields: FieldConfig[] = [
  // Step 1: Personal Information
  {
    name: 'firstName',
    label: 'First Name',
    type: 'text',
    required: true,
    step: 1,
    col: 6,
  },
  {
    name: 'lastName',
    label: 'Last Name',
    type: 'text',
    required: true,
    step: 1,
    col: 6,
  },
  {
    name: 'email',
    label: 'Email Address',
    type: 'email',
    required: true,
    step: 1,
    col: 12,
  },

  // Step 2: Address Information
  {
    name: 'street',
    label: 'Street Address',
    type: 'text',
    required: true,
    step: 2,
    col: 12,
  },
  {
    name: 'city',
    label: 'City',
    type: 'text',
    required: true,
    step: 2,
    col: 6,
  },
  {
    name: 'state',
    label: 'State',
    type: 'select',
    required: true,
    step: 2,
    col: 3,
    options: [
      { label: 'California', value: 'CA' },
      { label: 'New York', value: 'NY' },
      { label: 'Texas', value: 'TX' },
    ],
  },
  {
    name: 'zipCode',
    label: 'ZIP Code',
    type: 'text',
    required: true,
    step: 2,
    col: 3,
    validation: {
      pattern: /^\d{5}(-\d{4})?$/,
      message: 'Please enter a valid ZIP code',
    },
  },

  // Step 3: Preferences
  {
    name: 'newsletter',
    label: 'Subscribe to Newsletter',
    type: 'checkbox',
    step: 3,
    col: 12,
  },
  {
    name: 'preferences',
    label: 'Communication Preferences',
    type: 'select',
    step: 3,
    col: 6,
    options: [
      { label: 'Email', value: 'email' },
      { label: 'Phone', value: 'phone' },
      { label: 'Both', value: 'both' },
    ],
  },
];

function MultiStepForm() {
  const [currentStep, setCurrentStep] = useState(1);

  const handleStepChange = (step: number, totalSteps: number) => {
    console.log(`Moving to step ${step} of ${totalSteps}`);
    setCurrentStep(step);
  };

  return (
    <FinForm
      fields={multiStepFields}
      onSubmit={(data) => console.log('Form submitted:', data)}
      isMultiStep={true}
      currentStep={currentStep}
      onStepChange={handleStepChange}
      submitButtonText="Complete Registration"
      stepNavigationProps={{
        showStepNumbers: true,
        showStepTitles: true,
        stepTitles: ['Personal Info', 'Address', 'Preferences'],
      }}
    />
  );
}
```

### Smart Step Navigation with Backend Data

The form automatically detects completed steps and starts from the first incomplete step when data is provided:

```tsx
// Data from backend showing user has completed step 1
const backendData = {
  firstName: 'John',
  lastName: 'Doe',
  email: 'john.doe@example.com',
  // Step 2 and 3 are empty
};

function SmartMultiStepForm() {
  return (
    <FinForm
      fields={multiStepFields}
      onSubmit={(data) => console.log('Form submitted:', data)}
      defaultValues={backendData}
      isMultiStep={true}
      // Form will automatically start at step 2 since step 1 is complete
      submitButtonText="Complete Registration"
    />
  );
}
```

### Multi-Step Form Props

| Prop | Type | Description | Default |
|------|------|-------------|---------|
| `isMultiStep` | `boolean` | Enable multi-step functionality | `false` |
| `currentStep` | `number` | Current step (controlled by parent) | `1` |
| `onStepChange` | `(step: number, totalSteps: number) => void` | Step change callback | - |
| `showStepNavigation` | `boolean` | Show step navigation | `true` |
| `stepNavigationProps` | `object` | Step navigation configuration | `{}` |

### Step Navigation Configuration

```tsx
stepNavigationProps={{
  showStepNumbers: true,    // Show step numbers
  showStepTitles: true,     // Show step titles
  stepTitles: ['Step 1', 'Step 2', 'Step 3'], // Custom step titles
}}
```

### Field Step Assignment

Add a `step` property to any field to assign it to a specific step:

```tsx
{
  name: 'fieldName',
  label: 'Field Label',
  type: 'text',
  step: 1, // This field will appear in step 1
  required: true,
}
```

## 🎛️ API Reference

### FinForm Props

| Prop | Type | Description | Required |
|------|------|-------------|----------|
| `fields` | `FieldConfig[]` | Array of field configurations | ✅ |
| `onSubmit` | `(data: any) => void` | Form submission handler | ✅ |
| `onChange` | `(data: any) => void` | Form change handler | ❌ |
| `submitButtonText` | `string` | Submit button text | ❌ |
| `defaultValues` | `Record<string, any>` | Default form values | ❌ |
| `isMultiStep` | `boolean` | Enable multi-step functionality | ❌ |
| `currentStep` | `number` | Current step (controlled by parent) | ❌ |
| `onStepChange` | `(step: number, totalSteps: number) => void` | Step change callback | ❌ |
| `showStepNavigation` | `boolean` | Show step navigation | ❌ |
| `stepNavigationProps` | `object` | Step navigation configuration | ❌ |

### Field Configuration

```tsx
interface BaseField {
  name: string;
  label: string;
  type: 'text' | 'email' | 'password' | 'number' | 'select' | 'checkbox' | 'date' | 'textarea' | 'image';
  placeholder?: string;
  required?: boolean;
  disabled?: boolean;
  validation?: ValidationRule;
  step?: number; // Step number for multi-step forms (1-based)
  col?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
  xs?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
  sm?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
  md?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
  lg?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
  xl?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
}

interface ImageField extends BaseField {
  type: 'image';
  src?: string; // Image source URL
  alt?: string; // Alt text for accessibility
  width?: number | string; // Image width
  height?: number | string; // Image height
  style?: React.CSSProperties; // Custom styles
  className?: string; // Custom CSS class
  onClick?: () => void; // Click handler
}
```

### Validation Rules

```tsx
interface ValidationRule {
  pattern?: string | RegExp;
  message?: string;
  required?: boolean;
  minLength?: number;
  maxLength?: number;
  min?: number;
  max?: number;
  custom?: (value: any) => boolean | string;
}
```

## 💡 Examples

### Complete Registration Form

```tsx
const registrationFields: FieldConfig[] = [
  {
    name: 'firstName',
    label: 'First Name',
    type: 'text',
    placeholder: 'Enter first name',
    required: true,
    col: 6
  },
  {
    name: 'lastName',
    label: 'Last Name',
    type: 'text',
    placeholder: 'Enter last name',
    required: true,
    col: 6
  },
  {
    name: 'email',
    label: 'Email',
    type: 'email',
    placeholder: 'Enter email address',
    required: true,
    col: 12
  },
  {
    name: 'password',
    label: 'Password',
    type: 'password',
    placeholder: 'Enter password',
    required: true,
    col: 6,
    validation: {
      minLength: 8,
      pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/,
      message: 'Password must be at least 8 characters with uppercase, lowercase, number and special character'
    }
  },
  {
    name: 'confirmPassword',
    label: 'Confirm Password',
    type: 'password',
    placeholder: 'Confirm password',
    required: true,
    col: 6
  },
  {
    name: 'agreeToTerms',
    label: 'I agree to the Terms and Conditions',
    type: 'checkbox',
    required: true,
    col: 12
  }
];
```

## 🛠️ Development

### Building the Library

```bash
# Build for production
npm run build:lib

# Build types only
npm run build:types
```

### Running Development Server

```bash
npm run dev
```

## 📄 License

MIT © [Ritik](https://github.com/finflow-analytics/finform)

## 🤝 Contributing

Contributions, issues and feature requests are welcome!

Feel free to check [issues page](https://github.com/finflow-analytics/finform/issues).

## 📞 Support

If you like this project, please ⭐ star it on [GitHub](https://github.com/finflow-analytics/finform)! 