# Form Builder Plugin for Vue 3

The **Form Builder** plugin for Vue 3 is a dynamic tool that allows developers to create customizable forms based on
JSON configurations. It supports a variety of field types, custom components, and flexible layouts. The plugin
simplifies the process of building and managing forms by offering a configurable, extendable, and intuitive structure
for form elements. It provides features like field grouping, custom field registration, form validation, and automatic
form submission.

---

## Supported  Field Types

### 1. **group**

### 2. **input**

### 3. **textarea**

### 4. **checkbox-group**

### 5. **radio-group**

### 6. **file-upload**

### 7. **select**

- A dropdown selection field.

### 8. **select-ajax**

- A dynamic select field that fetches options from an API.

### 9. **date**

- A date picker field.

### 10. **password**

### 11. **button**

### 12. **Custom Fields**

- Developers can create custom fields by creating Vue components and registering them with the plugin.

---

## Validation

- Validation is handled using **Vuelidate**, and developers can apply rules like `required`, `minLength`, etc., to form
  fields.

---

## Additional Features

- **Automatic Submission**: The form can automatically submit when data changes (via `autoSubmit`).
- **Styling**: The plugin supports customizable CSS variables and classes for adjusting form appearance.

## Installation

```sh
npm install vi-form-builder
```

---

## Integration

### Integrate Plugin into a Vue App

```javascript
import ViFormBuilder from "vi-form-builder";
import {createApp} from 'vue';
import App from './App.vue';

const app = createApp(App).use(ViFormBuilder);
```

Import the styles

```html
@import "vi-common/style.css";
@import "vi-form-builder/style.css";
```

---

## Usage Examples

To see usage examples, download the project and run:

```sh
cd playground
npm run dev
```

---

## Form Props

| Prop             | Type                     | Description                                                      | Default Value |
|------------------|--------------------------|------------------------------------------------------------------|---------------|
| `config`         | Array                    | Array of fields to display in the form.                          | /             |
| `modelValue`     | Object                   | Object to hold the form data.                                    | /             |
| `layout`         | `vertical`, `horizontal` | Layout for the form, either vertical or horizontal.              | `vertical`    |
| `submitAction`   | Function                 | Function to handle form submission and return a promise.         | /             |
| `hideSubmit`     | Boolean                  | Whether to hide the submit button.                               | `false`       |
| `autoSubmit`     | Boolean                  | Automatically submit the form when data changes every 2 seconds. | `false`       |
| `buttonLabel`    | String                   | Label for the submit button.                                     | `Save`        |
| `resetOnSuccess` | Boolean                  | Whether to reset form data after successful submission.          | `false`       |
| `omitNulls`      | Boolean                  | Null values will be removed from model when form is submitted.   | `false`       |

---

## Field Options

| Option        | Type                                           | Description                                                                                         | Default Value  |
|---------------|------------------------------------------------|-----------------------------------------------------------------------------------------------------|----------------|
| `field`       | `group`, `input`, `textarea`, `checkbox`, etc. | Field component to display.                                                                         | /              |
| `name`        | String                                         | Name of the field in the form data model.                                                           | /              |
| `label`       | String                                         | Label for the field.                                                                                | /              |
| `hideLabel`   | Boolean                                        | Whether to hide the field label.                                                                    | `false`        |
| `placeholder` | String                                         | Placeholder text for the field. Defaults to the label if not specified.                             | /              |
| `info`        | String                                         | Additional text displayed above the field.                                                          | /              |
| `hint`        | String                                         | Additional text displayed below the field.                                                          | /              |
| `isVisible`   | Function                                       | Function that determines field visibility based on form data.                                       | Always visible |
| `rules`       | Object                                         | Validation rules (e.g., Vuelidate rules or custom validation).                                      | /              |
| `transform`   | Function                                       | Function that wil transform the original field value (do not use it in combination with sync model) | /              |

---

## Additional Field Props by Type

| Field Type               | Prop             | Type                                        | Description                                                                                                                         | Default Value                |
|--------------------------|------------------|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|------------------------------|
| `group`                  | `title`          | String                                      | Title for a group field.                                                                                                            | /                            |
| `group`                  | `children`       | Array                                       | Array of fields in a group.                                                                                                         | /                            |
| `group`                  | `horizontal`     | Boolean                                     | Whether fields in a group should be displayed horizontally.                                                                         | `false`                      |
| `group`                  | `flatModel`      | Boolean                                     | Whether group field data should appear at the root level of the model.                                                              | `false`                      |
| `input`                  | `type`           | 'text', 'email', 'url', 'number', 'numeric' | Input type                                                                                                                          | `text`                       |
| `input` ,`textarea`      | `debounce`       | Number                                      | Number of milliseconds for debounce of input value                                                                                  | `300`                        |
| `textarea`               | `rows`           | Number                                      | Number fo rowsfor textarea                                                                                                          | `6`                          |
| `checkbox-group`         | `options`        | Array                                       | Array of objects tha have label and value                                                                                           | /                            |
| `radio-group`            | `options`        | Array                                       | Array of objects tha have label and value                                                                                           | /                            |
| `file-upload`            | `multiple`       | Boolean                                     | Are multiple files upload allowed                                                                                                   | `false`                      |
| `file-upload`            | `bucket`         | String                                      | Name of bucket used to upload files to S3                                                                                           | /                            |
| `file-upload`            | `extensions`     | Array                                       | Array of strings for  allowed extensions (optional)                                                                                 | ex: `['.jpg','.png','jpeg']` |
| `file-upload`            | `maxFiles`       | Number                                      | Number of maximum allowed files to be uploaded if multiple is true                                                                  | /                            |
| `select`                 | `otpions`        | Array                                       | Array of options for select                                                                                                         | /                            |
| `select`, `select-ajax`  | `multiple`       | Boolean                                     | Can be selected more then one value                                                                                                 | `false`                      |
| `select`, `select-ajax`  | `optionValue`    | String                                      | If options is array of objects which field should be considered as value for the otpion                                             | /                            |
| `select` , `select-ajax` | `optionLabel`    | String                                      | If options is array of objects which field should be considered as label for the otpion                                             | /                            |
| `select`                 | `emitValue`      | Boolean                                     | If options is array of objects should only value be emitted or the whole object   (does not work with multiple true in select ajax) | `true`                       |
| `select`, `select-ajax`  | `clearable`      | Boolean                                     | If selected value can be remove form the input          (only for single select)                                                    | `false`                      |
| `select`, `select-ajax`  | `objectOptions`  | Boolean                                     | If options are list of ojects not strings                                                                                           | `true`                       |
| `select-ajax`            | `fetchOptions`   | Function                                    | Function that returns proimse with response for  the otpions that needs to appeaer in the select                                    | /                            |
| `select-ajax`            | `rowsPerPage`    | Number                                      | Number of options displayed   and returned form server on every request                                                             | `50`                         |
| `select-ajax`            | `infiniteScroll` | Boolean                                     | Should load more options when end fo srcoll is riched                                                                               | `false`                      |

---

- For **date** field we use this [library](https://vue3datepicker.com/), every prop form here can be used in config for
  any date field or as global setting for date fields
- For **select**  and **select-ajax** fields we use this [library](https://vue-select.org/), every prop form here can be
  used in config for any select os select-ajax field

## Example Field Configuration

```javascript
[
    {
        label: 'First Name',
        field: 'input',
        name: 'firstName',
    },
    {
        label: 'Last Name',
        field: 'input',
        name: 'lastName',
    },
    {
        label: 'Email',
        field: 'input',
        type: 'email',
        name: 'email',
    },
    {
        field: 'group',
        name: 'address',
        horizontal: true,
        children: [
            {
                label: 'City',
                field: 'input',
                name: 'city',
                rules: {required},
            },
            {
                label: 'Zip',
                field: 'input',
                name: 'zip',
                rules: {required},
            },
            {
                label: 'State',
                field: 'input',
                name: 'state',
            },
        ],
    },
]
```

---

## Registering Custom Field Types

The Form Builder supports default fields like `input`, `textarea`, `checkbox`, etc. To add custom fields:

1. Create a Vue component for the custom field.
2. Register the component in the plugin options.

### Example: Creating a Rating Component

```vue

<template>
  <div class="rating">
    <rating-star v-for="i in 5" :key="i" :color="color" :filled="i"></rating-star>
  </div>
</template>

<script>
  export default {
    name: 'Rating',
    props: {
      field: String,
      modelValue: {},
      name: String,
      label: String,
      color: String,
    },
  };
</script>
```

### Register the Custom Field

```javascript
import Rating from "./components/Rating.vue";
import ViFormBuilder from "vi-form-builder";

const app = createApp(App)
    .use(ViFormBuilder, {
        fieldComponents: {Rating},
    });

// Use the new field type in your field configuration:
fields: [
    {
        label: 'Rate our service',
        field: 'rating',
        name: 'rating',
        color: 'yellow',
    },
];
```

---

## Field Validations

Validation is handled using [Vuelidate](https://vuelidate-next.netlify.app/). Example validation rules:

```javascript
import {required, minLength} from "@vuelidate/validators";

const config = [
    {
        label: 'First Name',
        name: "firstName",
        field: "input",
        placeholder: "First Name",
        rules: {
            required,
            minLength: minLength(3),
        },
    },
];
```

---

## Styling

### CSS Classes

| Class Name                                        | Description                                                                |
|---------------------------------------------------|----------------------------------------------------------------------------|
| `.vi-form-builder`                                | Class on the form                                                          |
| `.vi-form-builder.no-submit`                      | Classes for form without submit button.                                    |
| `.vi-form-builder.with-submit`                    | Classes for form with submit button.                                       |
| `.vi-form-builder.horizontal`                     | Class for from with horizontal layout                                      |
| `.vi-form-builder.vertical`                       | Class for from with vertical layout                                        |
| `.vi-form-field`                                  | wrapper class around each field                                            |
| `.vi-form-field.group`                            | wrapper class around group field                                           |
| `.vi-form-field .vi-form-label`                   | class for lable of the field                                               |
| `.vi-form-field .field-container`                 | wraaper class around field content (field, hint, info, errors)             |
| `.field-container .info `                         | class for field info                                                       |
| `.field-container .hint `                         | class for field hint                                                       |
| `.field-container .field-error `                  | class  for  div that holds one field error                                 |
| `.field-container .field `                        | class  for  div that holds one field error                                 |
| `.group-title `                                   | class  for  div that holds title for the group                             |
| `.vi-form-field  .field-container .group-fields ` | class  for  div that is contatiner which holds all the fields in the group |

### CSS Variables

| Variable Name                      | Usage                                                                     | Default Value            |
|------------------------------------|---------------------------------------------------------------------------|--------------------------|
| `--vi-form-primary-color`          | Main general color for brand identity                                     | `#5C67F7`                |
| `--vi-form-primary-light-color`    | Lighter version of primary color                                          | `30% from primary color` |
| `--vi-form-neutral-color`          | Colors used for displaying error messages and border when field has error | `#d8d8d8`                |
| `--vi-form-neutral-color-light`    |                                                                           | ``                       |
| `--vi-form-neutral-color-light-2`  |                                                                           | ``                       |
| `--vi-form-contrasting-text-color` |                                                                           | ``                       |
| `--vi-form-field-padding`          |                                                                           | ``                       |
| `--vi-form-error-color`            |                                                                           | ``                       |
| `--vi-form-background`             |                                                                           | ``                       |
| `--vi-form-input-height`           |                                                                           | ``                       |
| `--vi-form-input-padding`          |                                                                           | ``                       |
| `--vi-form-input-background`       |                                                                           | ``                       |
| `--vi-form-input-border-radius`    |                                                                           | ``                       |
| `--vi-form-input-border-width`     |                                                                           | ``                       |
| `--vi-form-input-border-color`     |                                                                           | ``                       |
| ``                                 |                                                                           | ``                       |
| ``                                 |                                                                           | ``                       |
| ``                                 |                                                                           | ``                       |
| ``                                 |                                                                           | ``                       |
| ``                                 |                                                                           | ``                       |
| ``                                 |                                                                           | ``                       |
| ``                                 |                                                                           | ``                       |
| ``                                 |                                                                           | ``                       |

## GLOBAL SETTINGS

### **Field value transform global settings**

For every field we can provide transform function to transform the value of the field before submit/input, 
we can do the same also globally, only when we use this globalay we cna only set it per field type.
For example:

```javascript
const app = createApp(App);
app.use(ViFormBuilderPlugin, {
...,
transforms: {
"select-ajax": (value, field) => {
return field.multiple ? (value??[]).map(val => val[field.optionValue]): value[field.optionValue]
}
});
```
This means that every time when we submit a form which has field of type select-ajax, this function will be called to tranform the 
value unless we have transform setting locally set for the filed.
Example use case would be , you have registered custom filed 'use-select' where every time use ris selected we wnt to get the id not the whole object




### **Style global settings**

You can override all css variables in the options when plugin is installed:

```vue
const app = createApp(App);
app.use(ViFormBuilderPlugin, {
...
style: {
'primary-color': '#f18080',
'primary-light-color': '#f18080',
'error-color': 'red',
}
});
```

### **File upload global settings**

Under **fileSettings** we can define:

- **getPreSignedUrl** - must be defined, this function should return pre-sgined url from aws s3 for uplading files
- **bucket** - s3 bucket name must be proivded here or in th global settings or as config in the date field

```javascript
createApp(App)
    .use(ViFormBuilderPlugin, {

        fileSettings: {
            getPreSignedUrl({file, bucket}) {
                return fetchGraphQL(query, {file, bucket})
            },
            bucket: 'file-upload'
        }
    })
```

### **Field `date` global settings**

From  [vue-datepicker library](https://vue3datepicker.com/) we can use any prop as global settings for date field:

```javascript
createApp(App)
    .use(ViFormBuilderPlugin, {
        dateSettings: {format: 'HH:mm'}
    })
```

### **Toastify global settings**

```javascript
{
    toastify: {
        autoClose: 2000,
            theme
    :
        'colored',
            hideProgressBar
    :
        true
    }
,
    successMessage:'Form Saved'
}
```

### Steps for adding changes for contributors

- git pull origin main
- add and test your changes in playground
- change the version in package.json
- vite build
- git push origin main
- npm publish

