npm package: @n3/react-form-kit
Description: Integration of @vtaits/react-final-form-schema and @n3/kit.
Author: Vadim Taits
Latest version: 0.16.12

# @n3/react-form-kit

Интеграция `@vtaits/react-final-form-schema` с `@n3/kit`

## Использование

### Форма создания/редактирования

```javascript
import { Button, buttonColors } from '@n3/kit';
import {
  Form,
  createFormFields,
  BottomBlock,
  ButtonsBlock,
} from '@n3/react-form-kit';

const fieldTypes = createFormFields(options);

const getFieldType = ({ type }) => fieldTypes[type];

...

<Form
  {...otherFormProps}
  names={[
    'fieldName1',
    'fieldName2',
    'fieldName3',
  ]}
  fields={fields}
  getFieldType={getFieldType}
  renderBottom={({
    renderError,
    submitting,
  }) => (
    <BottomBlock>
      {renderError()}

      <ButtonsBlock>
        <Button
          color={buttonColors.PRIMARY}
          componentProps={{
            type: 'submit',
          }}
          disabled={submitting}
        >
          Сохранить
        </Button>

        <Button
          color={buttonColors.DEFAULT}
          componentProps={{
            type: 'button',
          }}
          disabled={submitting}
        >
          Отмена
        </Button>
      </ButtonsBlock>
    </BottomBlock>
  )}
/>
```

### createFormFields options

Необязательное, объект, может содержать параметры:

- `get` - асинхронная функция get-запроса на сервер, принимает аргументы:

  1. `url` - строка;

  2. `queryParams` - объект параметров;

- `getFetchHeaders` - функция получения заголовков для вызова `fetch`;

- `processUploadedAttachment` - функция процессинга файлов в поле `attachment`, принимает аргументы:

  1. `response` - ответ сервера в результате загрузки;

  2. `file` - загруженный файл;

- `uploadAttachment` - асихнхронная функция загрузкий файлов в поле `attachment`, принимает аргументы:

  1. `file` - загруженный файл;

  2. `schema` - схема поля;

  3. `getFetchHeaders` -  функция из параметров;

  4. `processUploadedAttachment` -  функция из параметров.

### Form props

Принимает props `@vtaits/react-final-form-schema`, а также добавляются:

- `fields` - необязательное, объект, ключами которого являются имена полей, а значениями - их схемы, работает только в случае, если `getFieldSchema` не задано;

- `renderFields` - необязательное, функция рендера блока полей формы с помощью `renderFieldsBlock` (смотри *Form renderProps*). Если не задано, поля будут отрендерены подряд одно за другим. Принимает `renderProps` формы.

- `renderBottom` - необязательное, функция рендера контента ниже полей ввода (кнопки, сообщения об ошибках, не относящихся к полям, ...) с помощью `renderBottomBlock` (смотри *Form renderProps*). Принимает `renderProps` формы.

- `children` - необязательное, функция рендера формы. Если не задана, будут рендериться подряд результаты вызовов `renderFieldsBlock` и `renderBottomBlock`;

- `errorTitle` - необязательное, строка, заголовок сообщения о наличии ошибок формы;

- `errorMessages` - необязательное, массив строк, тексты сообщений о наличии ошибок формы;

- `excludeNames` - необязательное, массив имён полей, исключённых из рендера;

- `errorsPath` - необязательное, строка, путь до объекта ошибок в случае неудачной отправки, по умолчанию `"response.data"`;

- `onSubmitSuccess` - необязательное, функция, обработчик успешной отправки формы, первым аргументом принимает результат вызова `onSubmit`;

- `onSubmitError` - необязательное, функция, обработчик отправки формы с ошибкой;

- `redirectTo` - необязательное, адрес редиректа после успешной отправки формы;

- `getRedirectTo` - необязательное, функция получения адреса редиректа после успешной отправки формы, первым аргументом принимает результат вызова `onSubmit`;

- `notification` - необязательное, объект, параметры вспывающего сообщения `successLog` после успешной отправки формы;

- `getNotification` - необязательное, функция получения параметров вспывающего сообщения `successLog` после успешной отправки формы, первым аргументом принимает результат вызова `onSubmit`.

### Form renderProps

Передаются все renderProps из `@vtaits/react-final-form-schema`, а также добавляются следующие:

- `renderFieldsBlock` - функиця рендера полей формы;

- `renderBottomBlock` - функция рендера контента ниже полей ввода;

- `renderError` - функция рендера ошибки отправки формы;

- `names` - спиок полей для рендера формы.

### Ошибки формы

В отличие от `final-form`, если функция `onSubmit` не бросила исключение, отправка счиатется успешной. Есть способы вывести ошибки:

- Бросить исключение `SubmissionError`:

  ```javascript
  import { Form, SubmissionError } from '@n3/react-form-kit';

  ...

  <Form
    onSubmit={async () => {
      throw new SubmissionError({
        field1: ['Ошибка'],
        field2: ['Ошибка'],
      });
    }}
  />
  ```

- Бросить любое другое исключение, параметр `errorsPath` должен содержать путь до объекта ошибок, например, при использовании `axios`:

  ```javascript
  import { Form } from '@n3/react-form-kit';

  ...

  <Form
    onSubmit={async (values) => {
      await axios.post('/url/', values);
    }}
    errorsPath="response.data"
  />
  ```


### Форма просмотра

```javascript
import {
  Form,
  createShowFields,
} from '@n3/react-form-kit';

const showFieldTypes = createShowFields();

const getShowFieldType = ({ type }) => showFieldTypes[type];

...

<Form
  {...otherFormProps}
  names={[
    'fieldName1',
    'fieldName2',
    'fieldName3',
  ]}
  fields={fields}
  getFieldType={getShowFieldType}
/>
```

### Кастомное поле для формы создания/редактирования

Создаёт поле с выводом заголовка, ошибок, ворнингов, звёздочки в случае обязательности

```javascript
import { FieldWrapper } from '@n3/react-form-kit';

const FieldComponent = (props) => {
  ...

  return (
    <FieldWrapper
      {...props}
    >
      {({
        input,
        meta,
        disabled,
        hasError,
        hasWarning,
        name,
      }) => {
        ...
      }}
    </FieldWrapper>
  );
};
```

### Кастомное поле для формы просмотра

Создаёт поле с выводом заголовка

```javascript
import { ShowFieldWrapper } from '@n3/react-form-kit';

const FieldComponent = (props) => {
  ...

  return (
    <ShowFieldWrapper
      {...props}
    >
      {({
        input,
        meta,
        disabled,
        hasError,
        hasWarning,
        name,
      }) => {
        ...
      }}
    </ShowFieldWrapper>
  );
};
```

### Кастомный массив полей для формы создания/редактирования

Создаёт группу полей с выводом заголовка, ошибок, ворнингов, звёздочки в случае обязательности

```javascript
import { FieldArrayWrapper } from '@n3/react-form-kit';

const FieldArrayComponent = (props) => {
  ...

  return (
    <FieldArrayWrapper
      {...props}
    >
      {({
        fields,
        meta,
        disabled,
        hasError,
        hasWarning,
        name,
      }) => {
        ...
      }}
    </FieldArrayWrapper>
  );
};
```

### Кастомный массив полей для формы просмотра

Создаёт группу полей с выводом заголовка

```javascript
import { ShowFieldArrayWrapper } from '@n3/react-form-kit';

const FieldArrayComponent = (props) => {
  ...

  return (
    <ShowFieldArrayWrapper
      {...props}
    >
      {({
        fields,
        meta,
        disabled,
        hasError,
        hasWarning,
        name,
      }) => {
        ...
      }}
    </ShowFieldArrayWrapper>
  );
};
```

### Повторяющиеся группы полей с кнопками добавления и удаления

#### RepeatWrapper

Аналогично `FieldArrayWrapper`, но добавляются функции `handleAdd` и `handleRemove`.

```javascript
import { RepeatWrapper } from '@n3/react-form-kit';

const RepeatComponent = (props) => {
  ...

  return (
    <RepeatWrapper
      {...props}
      fieldSchema={{
        required,
        initialValues,
      }}
    >
      {({
        fields,
        meta,
        disabled,
        hasError,
        hasWarning,
        handleAdd,
        handleRemove,
        name,
      }) => {
        ...
      }}
    </RepeatWrapper>
  );
};
```

- `handleAdd` - функция, при вызове добавляет новую группу полей со значениями `initialValues`;

- `handleRemove` - функция, удаляет группу полей по выбранному индексу. Если группа была единственная, а также `required` = true, то добавляет новую группу полей с `initialValues`.

#### useRepeat

Хук для создания повторяющихся групп полей на основе `useFieldArray` из `react-final-form-arrays`.

```javascript
import { useRepeat } from '@n3/react-form-kit';

const RepeatField = ({
  name,
  initialValues,
  required,
}) => {
  const {
    fields,
    meta,
    handleAdd,
    handleRemove,
  } = useRepeat(name, {
    required,
    initialValues,
  });

  const removeByIndex = (index) => {
    handleRemove(index);
  };
}
```

Аналогично `useFieldArray`, но добавляются функции добавления и удаления групп полей.

- `handleAdd` - функция, при вызове добавляет новую группу полей со значениями `initialValues`;

- `handleRemove` - функция, удаляет группу полей по выбранному индексу. Если группа была единственная, а также `required` = true, то добавляет новую группу полей с `initialValues`.

## Схема полей

Каждое поле, созданное при помощи `createField` или `createShowField` имеет следующие необязательные параметры:

- `label` - строка, заголовок поля;

- `onlyField` - булево, если true, заголовок поля не отображается;

- `required` - булево, если true, на форме создания/редактирования рядом с заголовком отображается `*`;

- `help_text` - строка, подсказка, выводящаяся под полем;

- `help_tooltip` - строка, подсказка, выводящаяся в тултипе рядом с заголовком;

- `unit` - React.Node, единицы измерения;

- `initial` - значение поля по умолчанию;

- `labelCols` - число, количество колонок, которое занимает заголовок поля, по умолчанию 3;

- `fieldCols` - число, количество колонок, которое занимает поле, по умолчанию 5;

- `unitCols` - число, количество колонок, которое занимает блок единиц измерения, по умолчанию 1.

### Реализованные поля

#### string

Поле ввода текста. Параметры:

- `inputComponent` - react-компонент, компонент поля, по умолчанию `input`;

- `inputType` - строка, тип инпута, по умолчанию `text`;

- `inputProps` - обеъект, дополнительные props элемента `input`;

- `debounceTimeout` - задержка debounce-инпута, по умолчанию `300`;

- `max_length` - число, максимальное количество введённых символов;

- `mask` - маска формата [react-input-mask](https://www.npmjs.com/package/react-input-mask), если задано, параметры `debounceTimeout` и `max_length` не работают;

- `disabled` - булево;

- `read_only` - булево;

- `placeholder` - строка.

#### email

Полностью аналогично `string`.

#### url

Полностью аналогично `string`.

#### integer

Аналогично `string`, отличия:

- отсутствие свойства `mask`;
- сериализация пустого значения в `null`.

#### choice

Список опций для выбора. Параметры:

- `choices` - массив объектов опций селекта, по умолчанию имеют формат `{ value, display_name }`, где `value` - значение, отправляемое на сервер, `label` - текст для отображения опции;

- `valueKey` - ключ значения опции для отправки на сервер, по умолчанию `value`;

- `labelKey` - ключ значения опции для отображения, по умолчанию `display_name`;

- `disabled` - булево;

- `read_only` - булево;

- `renderWith` - `'select'` или `'radio'`, по умолчанию `'select'`.

#### multiple_choice

Мультиселект. Аналогичен `choice`, но принимает и отправляет массивы значений. Параметры:

- `renderWith` - `'select'` или `'checkbox'`, по умолчанию `'select'`.

#### ajax_choice

Селект с подгрузкой опций с сервера. Использует компонент `SelectAjax`. Параметры:

- `choices_url` - строка, url для запроса данных. Опции могут приходить массивом или в формате `drf` (`{ results, next }`);

- `mapResponse` - необязательное, функция маппинга ответа сервера в формат `react-select-async-paginate`;

- `queryParams` - объект параметров запроса, не зависящих от других полей;

- `debounceTimeout` - задержка перед запросом в мс, по умолчанию `300`;

- `choices_cascade_params` - объект, ключами которого являются имена других полей, а значениями - названия параметров, под которыми они будут переданы на сервер;

- `disabledWithoutCascadeValues` - булево, выключать ли поле в случае незаполненности хотя бы одного из полей `choices_cascade_params`;

- `searchParamName` - строка, параметр `SelectAjax`;

- `pageParamName` - строка, параметр `SelectAjax`;

- `offsetParamName` - строка, параметр `SelectAjax`;

- `parseValue` - необязательное, функция загрузки опции по id. По умолчанию делается запрос на `<choices_url><id>/` с параметрами `queryParams`. Принимает аргументы;

  1. `get` - из параметров `createFormFields`;

  2. `value` - id опции;

  3. `choicesUrl`

  4. `queryParams`

  5. `mapResponseSimple` - смотри ниже;

- `mapResponseSimple` - необязательное, функция маппинга загруженного значения при парсинге в опцию.

#### ajax_multiple_choice

Мультиселект с подгрузкой опций с сервера. Аналогичен `ajax_choice`, но принимает и отправляет массивы значений.

#### date

Дейтпикер. Принимает значения в формате js-объекта `Date`, строки формата `2018-12-26` или строки формата `2018-10-14T22:33:20`. Параметры:

- `disabled` - булево;

- `read_only` - булево.

#### datetime

Дейттаймпикер. Принимает значения в формате js-объекта `Date` или строки формата `2018-10-14T22:33:20`. Параметры:

- `disabled` - булево;

- `read_only` - булево.

#### boolean

Чекбокс. Принимает булевы значения. Параметры:

- `disabled` - булево;

- `checkboxLabel` - строка, текст чекбокса;

- `falsyLabel` - строка, используется для вывода ложного значения на форме просмотра;

- `truthyLabel` - строка, используется для вывода истинного значения на форме просмотра.

#### phone

Поле ввода телефона с маской.

#### time

Поле ввода времени с маской.

#### attachment

Загрузчик файлов по схемам `drf`. Параметры:

- `upload_url` - обязательное, url для загрузки файла;

- `upload_field` - необязательное, ключ, по которому загруженный файл будет передан на сервер, по умолчанию `'tmpfile'`;

- `allowed_extensions` - необязательное, список доступных расширений (`[".docx", ".pdf", ".xlsx"]`);

- `max_length` - необязательное, максимальное количество файлов;

- `max_size` - необязательное, максимальный размер файла в байтах;

- `isDragAndDrop` - необязательное, из компонента `FileUploader`.

#### file

Загрузчик **одного** файла. Параметры:

- `uploadFile` - обязательное, асинхронная функция загрузки файла `@n3/react-fileuploader`;

- `extensions` - необязательное, массив возможных расширений файлов;

- `placeholder` - необязательное, react node, текст загрузчика;

- `isDragAndDrop` - необязательное, из компонента `FileUploader`.

#### multiple_file

Загрузчик нескольких файлов. Параметры:

- `uploadFile` - обязательное, асинхронная функция загрузки файла `@n3/react-fileuploader`;

- `extensions` - необязательное, массив возможных расширений файлов;

- `placeholder` - необязательное, react node, текст загрузчика;

- `maxLength` - необязательное, число, максимальное количество файлов;

- `isDragAndDrop` - необязательное, из компонента `FileUploader`.

#### nested_object

Группа полей. Параметры:

- `child` - обязательное, объект, поля:

  - `fields` - обязательное, объект, схемы полея группы;

  - `ordering` - обязательное, массив, список имён полей группы;

- `excludeNames` - необязательное, массив полей, которые нужно исключить из `ordering`;

- `render` - необязательное, функция рендера содержимого блока. Пример:

  ```
  render: ({
    renderField,
    ordering,
  }) => (
    <>
      {renderField('nestedField1')}
      {renderField('nestedField2')}
    </>
  )
  ```

  - `renderField` - функция рендера вложенного поля по имени;

  - `ordering` - массив имён вложенных полей, из которого исключены `excludeNames`.

#### list

Повторяющееся поле. Параметры:

- `child` - обязательное, объект, схема повторяющегося поля;

- `addButtonTitle` - необязательное, текст кнопки добавления, по умолчанию `'Добавить ещё'`;

- `getBlockTitle` - необязательное, функция генерации заголовка блока, принимает аргументы:

  1. `index` - число, индекс блока в списке;

- `blockTitle` - необязательное, заголовок каждого блока, работает в случае, если не определено `getBlockTitle`;

- `style` - необязательное, `'default' | 'mini'`,  стиль блоков;

- `min_length` - необязательное, минимальное количество элементов;

- `max_length` - необязательное, максимальное количество элементов;

#### nested_objects_list

Повторяющаяся группа полей. Параметры:

- `child` - обязательное, объект, поля:

  - `fields` - обязательное, объект, схемы полей группы;

  - `ordering` - обязательное, массив, список имён полей группы;

- `excludeNames` - необязательное, массив полей, которые нужно исключить из `ordering`;

- `addButtonTitle` - необязательное, текст кнопки добавления, по умолчанию `'Добавить ещё'`;

- `getBlockTitle` - необязательное, функция генерации заголовка группы полей, принимает аргументы:

  1. `index` - число, индекс группы полей в списке;

- `blockTitle` - необязательное, заголовок каждой группы полей, работает в случае, если не определено `getBlockTitle`;

- `renderBlock` - необязательное, функция рендера содержимого блока. Пример:

  ```
  renderBlock: ({
    renderField,
    ordering,
  }) => (
    <>
      {renderField('nestedField1')}
      {renderField('nestedField2')}
    </>
  )
  ```

  - `renderField` - функция рендера вложенного поля по имени;

  - `ordering` - массив имён вложенных полей, из которого исключены `excludeNames`.

- `style` - необязательное, `'default' | 'mini'`,  стиль блоков;

- `min_length` - необязательное, минимальное количество элементов;

- `max_length` - необязательное, максимальное количество элементов;

#### dynamic

Поле со схемой, зависящей от других полей. Пример:

```javascript
const schema = {
  type: 'dynamic',

  getSchema: ({
    otherField,
  }, phase) => ({
    type: 'string',
    label: 'Поле',
    required: Boolean(otherField),
  }),
};
```

Параметры:

- `getSchema` - обязательное, функция, первым аргументом принимает объект значений формы. Должна вернуть схему поля для рендера или `null`. В случае возврата `null` поле не отображается и не участвует в сериализации и парсинге значений формы, а также сборе ошибок. Аргументы;

  1. `values` - объект значений формы на этапе рендера/сериализации или объект необработанных значений на этапе парсинга;
  2. `phase` - текущая фаза [@vtaits/form-schema](https://www.npmjs.com/package/@vtaits/form-schema). Принимает значения: `'parse'`, `'serialize'`, `'render'`;

- `getSchemaAsync` - необязательное, функция. Может быть использована для асинхронного парсинга. Аналогична `getSchema`, но должна вернуть `Promise` с итоговой схемой;

- `onShow` - необязательное, функиця. которая вызывается после показа поля. Аргументы:

  1. `form` - экземпляр `final-form`;

  2. `name` - имя поля;

  3. `schema` - схема дочернего поля;

  4. `getFieldSchema` - текущее `getFieldSchema`;

  5. `getFieldType` - глобальное `getFieldType`;

  6. `parents` - массив родительских полей;

- `onHide` - not required, callback that called when field has hidden. Arguments:

  1. `form` - экземпляр `final-form`;

  2. `name` - имя поля;

  3. `getFieldSchema` - текущее `getFieldSchema`;

  4. `getFieldType` - глобальное `getFieldType`;

  5. `parents` - массив родительских полей.

## Вспомогательные компоненты

### BottomBlock

Контейнер для вывода блоков ошибок и кнопок.

#### props

| Название | Обязательность | Тип | Значение по умолчанию | Описание |
|----------|----------------|-----|-----------------------|----------|
| hasSections |  | bool | `false` | Поля формы сгруппированы в секции с заголовками слева |
| children |  | node | `null` |  |

### ButtonsBlock

Контейнер для кнопок действий.

### SubmitButtonByType

Кнопка для создания форм с несколькими способами отправки.

#### props

| Название | Обязательность | Тип | Значение по умолчанию | Описание |
|----------|----------------|-----|-----------------------|----------|
| handleSubmit | + | `() => void` | | Функция отправки формы `react-final-form` |
| submitTypeRef | + | `MutableRefObject<any>` | | `ref` для установки способа отправки |
| submitType | + | `any` | | Способ отправки формы |

## Утилиты

### getErrorsAndWarnings

```typescript
import { getErrorsAndWarnings } from '@n3/react-form-kit';

...

const {
  errors,
  warnings,
} = getErrorsAndWarnings(submitError);
```

Функция для получения списков ошибок и предупреждений по стандартной ошибке поля.

### Конфигурация через FormConfigContext

```typescript
import { FormConfigContext } from '@n3/react-form-kit';

<FormConfigContext.Provider
  value={{
    labelCols: 4,
    fieldCols: 8,
    onFieldChange: (value, prevValue, name, form) => {
      // ...
    },
  }}
>
  {/** ... */}
</FormConfigContext.Provider>
```

- `isCellsPercentage` - необязательное, `boolean`, пропорциональная ширина поля и контейнера для единиц измерения;
- `labelCols` - обязательное, число, количество колонок заголовков по умолчанию;
- `fieldCols` - обязательное, число, количество колонок полей по умолчанию;
- `colon` - необязательное, `boolean`, показывать ли двоеточие после заголовка поля;
- `direction` - необязательное,  `'horizontal' | 'vertical'`, направление рендера полей;
- `onFieldChange` - необязательное, функция, глобальный обработчик изменений значений полей.