# Form Builder Library

A powerful React library for building dynamic, drag-and-drop forms with a rich set of field types and customization options. Uses Tailwind CSS classes - requires Tailwind CSS as a peer dependency in your project.

## Features

- 🎨 **Visual Form Builder** - Drag and drop interface for creating forms
- 📝 **Rich Field Types** - 25+ field types including text, numbers, choices, dates, uploads, and more
- 🔧 **Field Customization** - Extensive settings for each field type
- 👀 **Real-time Preview** - See your form as users will see it
- 📱 **Responsive Design** - Works perfectly on desktop and mobile
- 💾 **Local Storage** - Automatic form persistence
- 🎯 **Form Validation** - Built-in validation rules and custom logic
- 🎨 **Icon Support** - Choose from 30+ icons for each field
- 🎨 **Tailwind CSS** - Uses Tailwind utility classes for styling
- 📦 **Minimal Dependencies** - Only React, React DOM, and Tailwind CSS required

## Installation

```bash
npm install @diludilshad/form-builder-library
```

### Prerequisites

This library requires Tailwind CSS to be installed and configured in your project. If you haven't already set up Tailwind CSS, follow these steps:

1. **Install Tailwind CSS:**

```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

2. **Configure your `tailwind.config.js`:**

```javascript
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
    // Add this line to scan the form builder library
    "./node_modules/@diludilshad/form-builder-library/**/*.{js,jsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};
```

3. **Add Tailwind directives to your CSS:**

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

### Why Peer Dependency?

The Form Builder Library uses Tailwind CSS classes for styling. By using Tailwind as a peer dependency instead of bundling it:

- ✅ **No Style Conflicts** - Avoids duplicate Tailwind base styles
- ✅ **Consistent Theming** - Components use your project's Tailwind configuration
- ✅ **Smaller Bundle Size** - No duplicate CSS utilities
- ✅ **Customization** - Easy to customize colors, spacing, and other design tokens

## Using in Your Project

### Step 1: Create a New React Project

```bash
# Create a new React project
npx create-react-app my-form-app
cd my-form-app

# Or with Vite (recommended)
npm create vite@latest my-form-app -- --template react
cd my-form-app
npm install
```

### Step 2: Install Dependencies

```bash
# Install the form builder library
npm install @diludilshad/form-builder-library

# Install required peer dependencies
npm install tailwindcss postcss autoprefixer
```

### Step 3: Setup Tailwind CSS

```bash
# Initialize Tailwind
npx tailwindcss init -p
```

Update your `tailwind.config.js`:

```javascript
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
    // IMPORTANT: Include the form builder library
    "./node_modules/@diludilshad/form-builder-library/**/*.{js,jsx}",
  ],
  theme: {
    extend: {
      // You can extend the theme to customize form builder appearance
      colors: {
        primary: {
          50: "#eff6ff",
          500: "#3b82f6",
          600: "#2563eb",
          700: "#1d4ed8",
        },
      },
    },
  },
  plugins: [],
};
```

Add to your `src/index.css`:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

### Step 4: Basic Implementation

Create `src/App.jsx`:

```jsx
import React, { useState } from "react";
import { BuilderForm, FormReader } from "@diludilshad/form-builder-library";

function App() {
  const [currentView, setCurrentView] = useState("builder");
  const [form, setForm] = useState({
    name: "",
    type: "",
    description: "",
    structure: [],
    formsRules: [],
  });

  const handleSave = (formData) => {
    console.log("Form saved:", formData);
    setForm(formData);
    // Here you would typically save to your backend
  };

  const handleFormSubmit = (values) => {
    console.log("Form submitted:", values);
    // Handle form submission
  };

  return (
    <div className="min-h-screen bg-gray-100">
      {/* Navigation */}
      <nav className="bg-white shadow-sm border-b px-6 py-4">
        <div className="flex space-x-4">
          <button
            onClick={() => setCurrentView("builder")}
            className={`px-4 py-2 rounded-md ${
              currentView === "builder"
                ? "bg-blue-500 text-white"
                : "bg-gray-200 text-gray-700"
            }`}
          >
            Form Builder
          </button>
          <button
            onClick={() => setCurrentView("reader")}
            className={`px-4 py-2 rounded-md ${
              currentView === "reader"
                ? "bg-blue-500 text-white"
                : "bg-gray-200 text-gray-700"
            }`}
            disabled={!form.structure?.length}
          >
            Form Preview
          </button>
        </div>
      </nav>

      {/* Content */}
      {currentView === "builder" ? (
        <BuilderForm
          editFormId="demo-form"
          form={form}
          setForm={setForm}
          onSave={handleSave}
        />
      ) : (
        <div className="p-6">
          <div className="max-w-2xl mx-auto bg-white rounded-lg shadow-sm p-6">
            <FormReader
              formData={form}
              onSubmit={handleFormSubmit}
              onFieldChange={(fieldId, value) => {
                console.log(`Field ${fieldId} changed:`, value);
              }}
            />
          </div>
        </div>
      )}
    </div>
  );
}

export default App;
```

## Quick Start

### Basic Form Builder

```jsx
import React, { useState } from "react";
import { BuilderForm } from "@diludilshad/form-builder-library";

function App() {
  const [form, setForm] = useState({
    name: "",
    type: "",
    description: "",
    structure: [],
    formsRules: [],
  });

  const handleSave = (formData) => {
    console.log("Form saved:", formData);
    setForm(formData);
  };

  return (
    <BuilderForm
      editFormId="my-form-1"
      form={form}
      setForm={setForm}
      onSave={handleSave}
    />
  );
}
```

### Form Reader (Display Forms)

```jsx
import React from "react";
import { FormReader } from "@diludilshad/form-builder-library";

function FormDisplay() {
  const formData = {
    name: "Contact Form",
    description: "Please fill out this contact form",
    structure: [
      {
        id: "name",
        type: "single-line",
        label: "Full Name",
        placeholder: "Enter your full name",
        required: true,
        selectedIcon: "person",
      },
      {
        id: "email",
        type: "email",
        label: "Email Address",
        placeholder: "Enter your email",
        required: true,
        selectedIcon: "mail",
      },
    ],
  };

  const handleSubmit = (values) => {
    console.log("Form submitted:", values);
  };

  return (
    <FormReader
      formData={formData}
      onSubmit={handleSubmit}
      onFieldChange={(fieldId, value) => console.log(fieldId, value)}
    />
  );
}
```

## Components

### BuilderForm

The main form builder component with drag-and-drop functionality.

#### Props

| Prop         | Type     | Required | Default | Description                                                |
| ------------ | -------- | -------- | ------- | ---------------------------------------------------------- |
| `editFormId` | string   | Yes      | -       | Unique identifier for the form (used for localStorage key) |
| `form`       | object   | Yes      | -       | Current form state object                                  |
| `setForm`    | function | Yes      | -       | Function to update form state                              |
| `onSave`     | function | No       | -       | Callback function called when form is saved                |

#### Form Object Structure

```javascript
{
  name: string,           // Form name
  type: string,           // Form type
  description: string,    // Form description
  structure: array,       // Array of form fields
  formsRules: array       // Array of validation rules
}
```

### FormReader

Component for displaying and collecting data from forms.

#### Props

| Prop               | Type     | Required | Default  | Description                          |
| ------------------ | -------- | -------- | -------- | ------------------------------------ |
| `formData`         | object   | Yes      | -        | Form data object with structure      |
| `onSubmit`         | function | Yes      | -        | Called when form is submitted        |
| `onFieldChange`    | function | No       | -        | Called when any field value changes  |
| `initialValues`    | object   | No       | {}       | Initial values for form fields       |
| `customSubmitText` | string   | No       | "Submit" | Custom submit button text            |
| `customCancelText` | string   | No       | "Cancel" | Custom cancel button text            |
| `onCancel`         | function | No       | -        | Called when cancel button is clicked |
| `className`        | string   | No       | ""       | Additional CSS classes               |
| `formRules`        | array    | No       | []       | Form validation rules                |

### FormPreview

Component for previewing forms in builder mode.

#### Props

| Prop            | Type     | Required | Default | Description                     |
| --------------- | -------- | -------- | ------- | ------------------------------- |
| `formFields`    | array    | Yes      | -       | Array of form fields            |
| `previewData`   | object   | No       | {}      | Preview data                    |
| `isTestMode`    | boolean  | No       | false   | Whether in test mode            |
| `formRules`     | array    | No       | []      | Form validation rules           |
| `onExit`        | function | Yes      | -       | Called when exiting preview     |
| `onSubmit`      | function | Yes      | -       | Called when form is submitted   |
| `onFieldUpdate` | function | No       | -       | Called when field values change |

## Field Types

### Basic Information Fields

- **Name** (`name`) - Person icon, blue color
- **Address** (`address`) - Location icon, green color
- **Phone** (`phone`) - Call icon, purple color
- **Email** (`email`) - Mail icon, red color
- **Website** (`website`) - Globe icon, indigo color

### Text Fields

- **Single Line** (`single-line`) - Document icon, orange color
- **Dynamic Single Line** (`dynamic-single-line`) - Document icon, orange color
- **Multi Line** (`multi-line`) - Reader icon, teal color
- **Rich Text** (`rich-text`) - Options icon, indigo color

### Number Fields

- **Number** (`number`) - 123 icon, purple color
- **Decimal** (`decimal`) - .00 icon, emerald color
- **Formula** (`formula`) - fx icon, pink color
- **Currency** (`currency`) - Wallet icon, yellow color

### Choice Fields

- **Dropdown** (`dropdown`) - Chevron down icon, blue color
- **Radio** (`radio`) - Radio button icon, green color
- **Checkbox** (`checkbox`) - Checkbox icon, purple color
- **Multiple Choice** (`multiple-choice`) - List icon, teal color
- **Image Choices** (`image-choices`) - Images icon, pink color
- **Matrix Choice** (`matrix-choice`) - Grid icon, indigo color
- **Table** (`table`) - Grid icon, orange color

### Date & Time Fields

- **Date** (`date`) - Calendar icon, orange color
- **Time** (`time`) - Time icon, blue color
- **Date-Time** (`date-time`) - Calendar clear icon, green color
- **Month-Year** (`month-year`) - MY icon, amber color

### Upload Fields

- **File Upload** (`file-upload`) - Document attach icon, green color
- **Image Upload** (`image-upload`) - Cloud upload icon, teal color
- **Audio/Video Upload** (`audio-video-upload`) - Musical notes icon, purple color

### Rating & Scale Fields

- **Rating** (`rating`) - Star icon, yellow color
- **Slider** (`slider`) - Options icon, pink color

### Layout Fields

- **Section** (`section-header`) - Remove icon, gray color

## Field Structure

Each field in the form structure has the following properties:

```javascript
{
  id: string,                    // Unique field identifier
  type: string,                  // Field type (see above)
  label: string,                 // Field label
  placeholder: string,           // Field placeholder text
  required: boolean,             // Whether field is required
  selectedIcon: string,          // Icon identifier
  iconColor: string,             // Icon color class
  options: array,                // Options for choice fields
  validation: object,            // Field-specific validation rules
  settings: object,              // Field-specific settings
  // ... other field-specific properties
}
```

## Form Rules

Form rules allow you to create conditional logic and validation:

```javascript
{
  id: string,                    // Unique rule identifier
  name: string,                  // Rule name
  conditions: array,             // Array of conditions
  actions: array,                // Array of actions
  enabled: boolean               // Whether rule is active
}
```

## LocalStorage Persistence

The BuilderForm component automatically saves form data to localStorage using the `editFormId` as the key:

```javascript
localStorage.setItem(`form_${editFormId}`, JSON.stringify(formData));
```

## Available Icons

The library includes 30+ icons from react-icons/io5:

- `person`, `location`, `call`, `mail`, `globe`
- `document`, `reader`, `wallet`, `calendar`, `time`
- `business`, `briefcase`, `home`, `car`, `airplane`
- `train`, `bus`, `restaurant`, `shirt`, `ticket`
- `id-card`, `checkmark`, `heart`, `music`, `camera`
- `game`, `book`, `school`, `medical`, `fitness`
- `palette`

## Examples

### Complete Example with Both Builder and Reader

```jsx
import React, { useState } from "react";
import { BuilderForm, FormReader } from "@diludilshad/form-builder-library";

function FormBuilderApp() {
  const [formData, setFormData] = useState(null);
  const [isBuilderMode, setIsBuilderMode] = useState(true);
  const [formValues, setFormValues] = useState({});

  const handleSaveForm = (formData) => {
    console.log("Form saved:", formData);
    setFormData(formData);
  };

  const handleFormSubmit = (values) => {
    console.log("Form submitted:", values);
    setFormValues(values);
    alert("Form submitted successfully!");
  };

  return (
    <div className="min-h-screen bg-gray-50">
      <div className="max-w-7xl mx-auto py-8 px-4">
        <div className="text-center mb-8">
          <h1 className="text-3xl font-bold text-gray-900 mb-4">
            Form Builder Library
          </h1>

          <div className="flex justify-center space-x-4 mb-8">
            <button
              onClick={() => setIsBuilderMode(true)}
              className={`px-4 py-2 rounded-md font-medium ${
                isBuilderMode
                  ? "bg-blue-600 text-white"
                  : "bg-white text-gray-700 border border-gray-300 hover:bg-gray-50"
              }`}
            >
              Builder Mode
            </button>
            <button
              onClick={() => setIsBuilderMode(false)}
              className={`px-4 py-2 rounded-md font-medium ${
                !isBuilderMode
                  ? "bg-blue-600 text-white"
                  : "bg-white text-gray-700 border border-gray-300 hover:bg-gray-50"
              }`}
            >
              Reader Mode
            </button>
          </div>
        </div>

        {isBuilderMode ? (
          <BuilderForm
            editFormId="example-form"
            form={
              formData || {
                name: "",
                type: "",
                description: "",
                structure: [],
                formsRules: [],
              }
            }
            setForm={setFormData}
            onSave={handleSaveForm}
          />
        ) : (
          formData && (
            <div className="max-w-2xl mx-auto">
              <FormReader
                formData={formData}
                onSubmit={handleFormSubmit}
                onFieldChange={(fieldId, value) =>
                  console.log("Field changed:", fieldId, value)
                }
              />
            </div>
          )
        )}
      </div>
    </div>
  );
}

export default FormBuilderApp;
```

### Custom Form with Validation

```jsx
import React from "react";
import { FormReader } from "@diludilshad/form-builder-library";

function CustomForm() {
  const formData = {
    name: "Registration Form",
    description: "Please complete your registration",
    structure: [
      {
        id: "fullName",
        type: "single-line",
        label: "Full Name",
        placeholder: "Enter your full name",
        required: true,
        selectedIcon: "person",
        validation: {
          minLength: 2,
          maxLength: 50,
          pattern: "^[a-zA-Z\\s]+$",
        },
      },
      {
        id: "email",
        type: "email",
        label: "Email Address",
        placeholder: "Enter your email",
        required: true,
        selectedIcon: "mail",
        validation: {
          pattern: "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",
        },
      },
      {
        id: "country",
        type: "dropdown",
        label: "Country",
        placeholder: "Select your country",
        required: true,
        selectedIcon: "location",
        options: [
          { value: "us", label: "United States" },
          { value: "uk", label: "United Kingdom" },
          { value: "ca", label: "Canada" },
          { value: "au", label: "Australia" },
        ],
      },
    ],
  };

  const formRules = [
    {
      id: "email-validation",
      name: "Email Validation",
      conditions: [
        {
          fieldId: "email",
          operator: "contains",
          value: "@",
        },
      ],
      actions: [
        {
          type: "show_field",
          fieldId: "fullName",
        },
      ],
      enabled: true,
    },
  ];

  return (
    <FormReader
      formData={formData}
      formRules={formRules}
      onSubmit={(values) => {
        console.log("Registration submitted:", values);
        // Handle form submission
      }}
      onFieldChange={(fieldId, value) => {
        console.log(`${fieldId} changed to:`, value);
      }}
      customSubmitText="Register"
      customCancelText="Back"
    />
  );
}
```

## Development

### Prerequisites

- Node.js >= 16.0.0
- React >= 18.0.0
- React DOM >= 18.0.0

### Installation

```bash
git clone https://github.com/diludilshad/form-builder-library.git
cd form-builder-library
npm install
```

### Development Server

```bash
npm run dev
```

### Building

```bash
npm run build
```

### Type Checking

```bash
npm run type-check
```

### Linting

```bash
npm run lint
```

## Advanced Usage & Integration

### Backend Integration

#### Saving Forms to Database

```jsx
import React, { useState, useEffect } from "react";
import { BuilderForm } from "@diludilshad/form-builder-library";

function FormBuilderPage() {
  const [form, setForm] = useState(null);
  const [loading, setLoading] = useState(true);

  // Load existing form
  useEffect(() => {
    const loadForm = async () => {
      try {
        const response = await fetch("/api/forms/123");
        const formData = await response.json();
        setForm(formData);
      } catch (error) {
        console.error("Failed to load form:", error);
        setForm({
          name: "",
          type: "",
          description: "",
          structure: [],
          formsRules: [],
        });
      } finally {
        setLoading(false);
      }
    };

    loadForm();
  }, []);

  const handleSave = async (formData) => {
    try {
      const response = await fetch("/api/forms/123", {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(formData),
      });

      if (response.ok) {
        console.log("Form saved successfully!");
        setForm(formData);
      }
    } catch (error) {
      console.error("Failed to save form:", error);
    }
  };

  if (loading) return <div className="p-6">Loading...</div>;

  return (
    <BuilderForm
      editFormId="form-123"
      form={form}
      setForm={setForm}
      onSave={handleSave}
    />
  );
}
```

#### Processing Form Submissions

```jsx
import React from "react";
import { FormReader } from "@diludilshad/form-builder-library";

function PublicForm({ formId }) {
  const [formData, setFormData] = useState(null);

  useEffect(() => {
    fetch(`/api/forms/${formId}/public`)
      .then((res) => res.json())
      .then(setFormData);
  }, [formId]);

  const handleSubmit = async (values) => {
    try {
      const response = await fetch(`/api/forms/${formId}/submissions`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          formId,
          submittedAt: new Date().toISOString(),
          values,
        }),
      });

      if (response.ok) {
        alert("Form submitted successfully!");
      }
    } catch (error) {
      console.error("Submission failed:", error);
      alert("Failed to submit form. Please try again.");
    }
  };

  if (!formData) return <div>Loading form...</div>;

  return (
    <div className="max-w-2xl mx-auto p-6">
      <FormReader
        formData={formData}
        onSubmit={handleSubmit}
        onFieldChange={(fieldId, value) => {
          // Optional: Auto-save draft
          localStorage.setItem(
            `draft_${formId}`,
            JSON.stringify({
              ...JSON.parse(localStorage.getItem(`draft_${formId}`) || "{}"),
              [fieldId]: value,
            })
          );
        }}
      />
    </div>
  );
}
```

### Framework Integration

#### Next.js Setup

```javascript
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: ["@diludilshad/form-builder-library"],
};

module.exports = nextConfig;
```

```javascript
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
    // Include form builder library
    "./node_modules/@diludilshad/form-builder-library/**/*.{js,jsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};
```

#### Vite Setup

```javascript
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  optimizeDeps: {
    include: ["@diludilshad/form-builder-library"],
  },
});
```

### Custom Styling & Theming

#### Override Default Colors

```javascript
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        // Override primary colors used by form builder
        primary: {
          50: "#fdf2f8",
          500: "#ec4899", // Pink instead of blue
          600: "#db2777",
          700: "#be185d",
        },
      },
    },
  },
};
```

#### Custom CSS Classes

```css
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  /* Customize form builder styles */
  .form-builder-container {
    @apply bg-gradient-to-br from-purple-50 to-pink-50;
  }

  .form-field-item {
    @apply border-purple-200 hover:border-purple-400;
  }

  .form-builder-button {
    @apply bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700;
  }
}
```

### State Management Integration

#### Redux Integration

```jsx
import { useSelector, useDispatch } from "react-redux";
import { BuilderForm } from "@diludilshad/form-builder-library";
import { updateForm, saveForm } from "./store/formSlice";

function ReduxFormBuilder() {
  const dispatch = useDispatch();
  const form = useSelector((state) => state.forms.currentForm);

  return (
    <BuilderForm
      editFormId="redux-form"
      form={form}
      setForm={(formData) => dispatch(updateForm(formData))}
      onSave={(formData) => dispatch(saveForm(formData))}
    />
  );
}
```

### Performance Optimization

#### Lazy Loading

```jsx
import React, { lazy, Suspense } from "react";

// Lazy load the form builder
const BuilderForm = lazy(() =>
  import("@diludilshad/form-builder-library").then((module) => ({
    default: module.BuilderForm,
  }))
);

function App() {
  return (
    <Suspense fallback={<div className="p-6">Loading Form Builder...</div>}>
      <BuilderForm {...props} />
    </Suspense>
  );
}
```

### Troubleshooting

#### Common Issues

**1. Styles not applying:**

```bash
# Make sure Tailwind is scanning the library
# Check your tailwind.config.js includes:
"./node_modules/@diludilshad/form-builder-library/**/*.{js,jsx}"
```

**2. TypeScript errors:**

```javascript
// Add to your tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "node",
    "skipLibCheck": true
  }
}
```

**3. Build errors in production:**

```javascript
// For Webpack-based builds, add to webpack.config.js
module.exports = {
  resolve: {
    alias: {
      "@diludilshad/form-builder-library": require.resolve(
        "@diludilshad/form-builder-library"
      ),
    },
  },
};
```

## Browser Support

- Chrome >= 88
- Firefox >= 85
- Safari >= 14
- Edge >= 88

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## Support

- 📧 Email: diludilshad@example.com
- 🐛 Issues: [GitHub Issues](https://github.com/diludilshad/form-builder-library/issues)
- 📖 Documentation: [GitHub Wiki](https://github.com/diludilshad/form-builder-library/wiki)

## Changelog

### v1.0.5

- Added 30+ field types
- Improved drag and drop functionality
- Enhanced form validation
- Added icon support
- Bundled Tailwind CSS
- Zero additional dependencies

---

**Made with ❤️ by Dilshad**
