# Form for React ⚡️ Kufm

一个简单灵活的可配置表单

<p align="center">
    <img width="80" src="./doc/logo.svg" alt="rmox logo">
</p>
<br/>
<p align="center">
  <img src="https://img.shields.io/npm/dependency-version/rmox/peer/react?logo=react" alt="react version">
</p>
<br/>
<img  src="./doc/textlogo.svg" alt="rmox logo" height="60">

## 特性

- 支持表单的 Json 配置生成
- 支持表单项之间关联(value disabled visible options render)
- 支持表单项捆绑成组(批量处理组表单项)
- 支持组件全局注册

### npm 配置私库

```
@elune:registry="http://192.168.6.125:4873/"
```

### 安装

```
yarn add @elune/kufm
```

# 使用手册

## 全局配置

### 全局注册组件

> 全局注册组件方便配置时使用

```tsx
import { Switch, Input, Select } from 'antd';
import { registerField } from '@elune/kufm';
registerField('switch')(Switch, 'checked');
registerField('input')(Input);
registerField('select')(Select);
```

### 全局设置公共 props

> 可以设置全局 props，减少重复配置(例如 placehokder)

```tsx
import kufm from '@elune/kufm';
kufm.interceptors.props.use(({ field, label }) => {
  return {
    placeholder:
      {
        input: `请输入${label || ''}`,
        select: `请选择${label || ''}`,
      }[field] || '请输入',
  };
});
```

## 配置表单

### 配置用法

> 表单配置支持全局注册组件 也支持未注册组件

```tsx
import { KuFmGroup, KuForm, useKuForm, KuFmLayout } from '@elune/kufm';
import { Input } from 'antd';
const FormView = () => {
  const [form] = useKuForm();
  const list: IKuFmField[] = [
    {
      field: 'input',
      label: 'input',
      name: 'input',
      required: true,
    },
    {
      name: 'customInput',
      label: 'customInput',
      children: ({ value, onChange }) => {
        return (
          <>
            <Input value={value} />
            <Button
              onClick={() => {
                onChange?.('123');
              }}>
              测试自定义
            </Button>
          </>
        );
      },
    },
  ];
  return (
    <KuForm form={form} initialValues={{ input: '1' }}>
      <KuFmGroup list={list} />
    </KuForm>
  );
};
```

## 关联配置(支持多关联以及异步关联)

### visible 关联

> 注意：当 visible 为 false 获取值不会返回对应字段,且不处理当前项校验

案例:当 name 为小红并且 age 为 11 输入框 class 才显示

```tsx
const list: IKuFmField[] = [
  {
    field: 'input',
    label: 'name',
    name: 'name',
  },
  {
    field: 'input',
    label: 'sex',
    name: 'sex',
  },
  {
    field: 'input',
    label: 'class',
    name: 'class',
    dependency: [
      {
        type: FieldOption.VISIBLE,
        relates: ['name', 'sex'],
        relateFun: (formStore, [name, age]) => name === '小红' && age === 11,
      },
    ],
  },
];
```

### disabled 关联

> 注意：当 disabled 为 true 时不处理当前项校验

案例:当 name 为小红时禁用 class 输入框

```tsx
const list: IKuFmField[] = [
  {
    field: 'input',
    label: 'name',
    name: 'name',
  },
  {
    field: 'input',
    label: 'class',
    name: 'class',
    dependency: [
      {
        type: FieldOption.DISABLED,
        relates: ['name'],
        relateFun: (formStore, [name, age]) => name === '小红',
      },
    ],
  },
];
```

### render 关联(主要处理关联试图的改变)

案例:当 unit 为比例显示%,为数量不显示单位

```tsx
const list: IKuFmField[] = [
  {
    field: 'select',
    label: 'unit',
    name: 'unit',
    props: {
      options: [
        { value: 1, label: '数量' },
        { value: 2, label: '比例' },
      ],
    },
  },
  {
    field: 'input',
    label: 'count',
    name: 'count',
    dependency: [
      {
        type: FieldOption.REHDER,
        relates: ['unit'],
        suffixRender: (form) => <>{form.unit === 2 ? '%' : ''}</>,
      },
    ],
  },
];
```

### value 关联(初始化和 reset setFiledsValue 不处理值关联)

案例:当 en_name 为 jack name 值为小李(支持异步)

```tsx
const list: IKuFmField[] = [
  {
    field: 'input',
    label: 'en_name',
    name: 'en_name',
  },
  {
    field: 'input',
    label: 'name',
    name: 'name',
    dependency: [
      {
        type: FieldOption.VALUE,
        relates: ['en_name'],
        relateFun: (formStore, [en_name]) => en_name === 'jack',
        output: '小李',
      },
    ],
  },
];
```

### options 关联(注：当前项值不在 options 里将会清空)

案例:当 en_name 为 jack name 值为小李(支持异步)

```tsx
const list: IKuFmField[] = [
  {
    field: 'select',
    label: 'species',
    name: 'species',
    props: {
      options: [
        { value: 1, label: '数量' },
        { value: 2, label: '比例' },
      ],
    },
  },
  {
    field: 'input',
    label: 'name',
    name: 'name',
    dependency: [
      {
        type: FieldOption.VALUE,
        relates: ['en_name'],
        relateFun: (formStore, [en_name]) => en_name === 'jack',
        output: '小李',
      },
    ],
  },
];
```

## 组合项

组合多个项,批量校验以及获取某组的值

```tsx
import { KuFmGroup, KuForm, useKuForm, KuFmLayout } from '@elune/kufm';
import { Input, Button } from 'antd';
const FormView = () => {
  const [form] = useKuForm();
  const list: IKuFmField[] = [
    {
      field: 'input',
      label: 'input',
      name: 'input',
      required: true,
    },
    {
      name: 'customInput',
      label: 'customInput',
      required: true,
      children: ({ value, onChange }) => {
        return (
          <>
            <Input value={value} />
            <Button
              onClick={() => {
                onChange('123');
              }}>
              测试自定义
            </Button>
          </>
        );
      },
    },
  ];
  return (
    <>
      <KuForm form={form} initialValues={{ input: '1' }}>
        <KuFmGroup list={list} name="group" />
      </KuForm>
      <Button
        onClick={() => {
          form.validateFields({ groupName: 'group' });
        }}>
        校验
      </Button>
      <Button
        onClick={() => {
          form.getFieldsValue({ groupName: 'group' });
        }}>
        获取值
      </Button>
    </>
  );
};
```

## API

### KuFm Api(与配置一致)

| 参数          |             说明 |               类型               | 默认值                  |
| :------------ | ---------------: | :------------------------------: | ----------------------- |
| form          |        form 实例 |        IKulaFromInstance         | -                       |
| initialValues |       表单默认值 |              object              | -                       |
| count         |         一行几个 |              number              | 3                       |
| disabled      |         是否禁用 |             boolean              | false                   |
| layout        |         表单布局 |            KuFmLayout            | KuFmLayout.VERTICAL     |
| labelAlign    | 标签文本对齐方式 |            left/right            | left                    |
| labelCol      |   label 标签布局 | { span: number; offset: number } | { span: 6, offset: 18 } |
| size          |             大小 |   'small' \ 'middle' \'large'    | -                       |

### KuFmField Api(与配置一致)

| 参数 | 说明 | 类型 | 默认值 |
| :-- | --: | :-: | --- |
| field | 表单项全局组件类型 | string | - |
| name | 字段名，支持数组 | NamePath | - |
| props | 组件属性(带有组件自己属性) | object | - |
| noStyle | 为 true 时不带样式，作为纯字段控件使用 | boolean | false |
| colon | 配合 label 属性使用，表示是否显示 label 后面的冒号 | boolean | true |
| disabled | 是否禁用 | boolean | false |
| label | 标签的文本 | ReactNode | - |
| required | 是否必填 | boolean | false |
| rules | 校验规则 | Rule[] | - |
| disClearValueNotInOptions | 不清空不在 options 中的值 | string | false |
| suffixRender | 后缀渲染 | (form: object) => ReactNode | - |
| prefixRender | 前缀渲染 | (form: object) => ReactNode | - |
| onChange | 字段变更回调 | (data: any) => void | - |
| dependency | 关联关系 | IFieldKuFmDependency[] | - |
| layout | 表单布局 | KuFmLayout | - |
| labelAlign | 标签文本对齐方式 | left/right | left |
| size | 大小 | 'small' \ 'middle' \'large' | - |
| labelCol | label 标签布局 | { span: number; offset: number } | { span: 6, offset: 18 } |

### KuFmGroup Api

| 参数       |             说明 |               类型               | 默认值                  |
| :--------- | ---------------: | :------------------------------: | ----------------------- |
| list       |       表单项集合 |           IKuFmField[]           | -                       |
| name       |             组名 |              string              | -                       |
| count      |         一行几个 |              number              | 3                       |
| disabled   |         是否禁用 |             boolean              | false                   |
| layout     |         表单布局 |            KuFmLayout            | KuFmLayout.VERTICAL     |
| labelAlign | 标签文本对齐方式 |            left/right            | left                    |
| labelCol   |   label 标签布局 | { span: number; offset: number } | { span: 6, offset: 18 } |

### Form Api

| 参数 | 说明 | 类型 |
| :-- | --: | :-: |
| setFieldsValue | 设置值 | (values: CommonObject, isReset?: boolean) => void; |
| getFieldsValue | 获取对应字段名的值 | (validate?: TNameCollection) => object; |
| validateFields | 检验字段 | (validate?: TNameCollection) => Promise<CommonObject>; |
| getFieldValue | 获取对应字段名的值 | getFieldValue: (name: NamePath) => any; |
| setFieldValue | 通过 namePath 设置内容 | (validate?: TNameCollection) => boolean; |
| isFieldsTouched | 检查一组字段是否被用户操作过 | (validate?: TNameCollection) => boolean; |
| resetFields | 重置字段值 重置一组字段到 initialValues | () => void; |
| clearValidate | 清空认证状态 | (validate?: TNameCollection) => void; |

# 注意

1.在初始化的时候不处理 value 关联(options 关联清空也不处理)

2.多层级关联:关联对象具体某个字段的时候，如果直接修改对象不处理关联

# TODO

[ ] 添加防抖策略
