# 表单生成器

## descr

可以根据jsonschema 动态生成表单。

用于具有大量表单界面。

> 注意，设置初始值时，不同的组件有可能有细微差别，value 字段将会被 datas 数据中覆盖，因此在配置文件中，设置初始值需要采用诸如 `defaultValue` 字段。

以下两种方式设置初始值:

```js
// 在配置文件中设置初始值
{ key: 'borderStyle', label: '边框样式', type: 'select', defaultValue: 'dotted', data: { items: ['solid', 'dotted', 'dashed'] } }

// 在当前组件 datas 中设置初始值, 【推荐该方式】,该方式直接作用于 value 字段

this.state = {
  datas: {
    borderStyle: 'dotted'
  }
};

```

## 内置表单 type

- [x] textSetting 文本对齐设置
- [x] input 字符串输入
- [x] inputWeek 周选择
- [x] inputDateTime 时间输入
- [x] inputArray 采用 `,` 号进行分割数据，输出数组
- [x] inputNumber 数字输入框
- [x] textarea 文本域输入
- [x] position 平面坐标位置输入，返回 `{ x, y }`， data 支持设置 `{showUnit: true, unit: 'px', width: 100, min: 0, max: 1000, step: 5}`
- [x] size 元素宽高输入，返回 `{ width, height }`， data 支持设置 `{showUnit: true, unit: 'px', width: 100, min: 0, max: 1000, step: 5}`
- [x] margins 外边距输入，返回 `{ marginTop, marginRight, marginBottom, marginLeft }`
- [x] slider
- [x] switch
- [x] tags
- [x] radio
- [x] select 下拉框，数据为对象类型时，可通过 设置 `label` 来自定义渲染
- [x] mselect
- [x] checkbox
- [x] singleCheckbox 单值 checkbox，返回值为 true or false。 同 switch 组件
- [x] fontFamily
- [x] fontSize
- [x] color
- [x] iptColor
- [x] iptColorNone
- [x] chartColor
- [x] themeColor
- [x] bgPosition
- [x] divider
- [x] align
- [x] vAlign
- [x] border
- [x] borderRadius
- [x] boxShadow
- [x] textShadow
- [x] paddingMargin
- [x] property3d
- [x] boardGrid
- [x] paperSize
- [x] borderStyle

> 注意： 为了最佳体验， `chartColor` 最好设置为 `direction='vertical'`
> 自定义扩展 formFields ，必须采用 `enhanceForm` 和 `BasicForm` 创建。

## 案例演示

### 基本使用

---demo
```js
import { FormBuilder } from 'amos-framework';

const formMapper = FormBuilder.formFields;

const bgAttach = [
  { key: 'fill', label: '填充', value: 'fill' },
  { key: 'adapt', label: '适应', value: 'adapt' },
  { key: 'stretch', label: '拉伸', value: 'stretch' },
  { key: 'tiling', label: '平铺', value: 'tiling' },
  { key: 'center', label: '居中', value: 'center' },
  { key: 'spanned', label: '跨区', value: 'spanned' }
];

const fields = [
  { key: 'name', label: '名称', type: 'input' },
  { key: 'week', label: '周', type: 'inputWeek' },
  { key: 'datetime', label: '时间', type: 'inputDateTime' },
  { key: 'inlinename', label: 'inline名称', type: 'input', data: { inline: true } },
  { key: 'length', label: '长度', type: 'inputNumber', data: { min: 0, max: 1000, step: 5 } },
  { key: 'inlineLength', label: 'inline长度', type: 'inputNumber', data: { min: 0, max: 1000, step: 5, inline: true } },
  { key: 'background', label: '背景', type: 'color' },
  { key: 'textSetting', label: '内容显示', type: 'textSetting' },
  { key: 'basic', label: '基础配置项', type: 'divider' },
  { key: 'fontSize', label: '字体大小', type: 'fontSize' },
  { key: 'fontSize2', label: '字体大小2', type: 'fontSize', useNumber: true, tip: '值采用number类型' },
  { key: 'fontFamily', label: '字体', type: 'fontFamily' },
  { key: 'borderSize', label: '边框大小', type: 'inputNumber', data: { type: 'outer' } },
  { key: 'borderStyle', label: '边框样式', type: 'select', defaultValue: 'dotted', data: { items: ['solid', 'dotted', 'dashed'] } },
  { key: 'borderColor', label: '边框颜色', type: 'color' },
  { key: 'borderColor2', label: '边框颜色2', type: 'color', data: { direction: 'right' } },
  { key: 'borderColor3', label: '边框颜色3', type: 'iptColor' },
  { key: 'borderColor4', label: '边框颜色4', type: 'iptColorNone' },
  { key: 'borderColor5', label: '边框颜色5', type: 'iptColor', data: { useRgba: true, alpha: true } },
  { key: 'boxShadow', label: '边框阴影', type: 'boxShadow' },
  { key: 'textShadow', label: '文本阴影', type: 'textShadow' },
  { key: 'borderRadius', label: '内置圆角', type: 'borderRadius' },
  { key: 'borderRadius2', label: '数字圆角', type: 'slider', data: { min: 0, max: 100, step: 1 } },
  { key: 'opacity', label: '透明', type: 'slider', data: { min: 0, max: 100, step: 1 } },
  { key: 'rotate', label: '旋转', type: 'slider', data: { min: 0, max: 360, step: 1 } },
  { key: 'position', label: '位置(左-上)', type: 'position' },
  { key: 'size', label: '大小(宽-高)', type: 'size' },
  // { key: 'size2', label: '大小(宽-高)', type: 'size', data: { showUnit: false } },
  { key: 'margins', label: '页边距', type: 'margins' },
  { key: 'padding', label: '内边距', type: 'paddingMargin' },
  { key: 'padding2', label: '内边距2', type: 'paddingMargin', tip: '设置弹出层自定义的上下限', data: {
    iptNumProps: {
      min: -100,
      max: 200,
      step: 1,
    }
  } },
  { key: 'boardGrid', label: '画布配置', type: 'boardGrid' },
  { key: 'enable', label: '用户状态', type: 'switch', data: { onLabel: '启用', offLabel: '禁用' }, style: { width: 60 } },
  { key: 'status', label: '用户状态2', type: 'singleCheckbox', data: {  } },
  { key: 'inlineEnable', label: 'inline用户状态', type: 'switch', data: { onLabel: '是', offLabel: '否', inline: true } },
  { key: 'searchRange', label: '查询范围', type: 'tags', data: { items: [
    { key: 'java', value: 'java', text: 'java开发' },
    { key: 'web', value: 'web', text: 'web开发' },
    { key: 'designer', value: 'designer', text: '设计师' },
    { key: 'other', value: 'other', text: '其它' }
  ], expandable: false, single: false } },
  { key: 'sex', label: '性别', type: 'radio', defaultValue: 'm', data: {
    items: [{ key: 'f', text: '男', value: 'f' }, { key: 'm', text: '女', value: 'm' }]
  } },
  { key: 'lesson', label: '学科', type: 'checkbox', defaultValue: ['math'], data: {
    items: [
      { key: 'math', text: '数学', value: 'math' },
      { key: 'chinese', text: '语文', value: 'chinese' },
      { key: 'physics', text: '物理', value: 'physics' },
      { key: 'english', text: '英语', value: 'english' },
      { key: 'chemistry', text: '英语', value: 'chemistry' }
    ]
  } },
  { key: 'descr', label: '描述信息', type: 'textarea', data: { rows: 4 } },
  { key: 'backgroundPosition', label: '背景位置', type: 'bgPosition', wrapStyle: { alignItems: 'flex-start' } },
  { key: 'backgroundAttach', label: '背景契合度', type: 'select', data: { items: bgAttach } },
  { key: 'customBackground', label: '自定义背景色', type: 'iptMixColor', data: { direction: 'down', align: 'left' } },
  { key: 'dropChartColor', label: '颜色系列', type: 'dropChartColor', popoverProps: {
      align: 'right'
    },
    chartColorProps: {
      basic: {
        alpha: true,
        useRgba: true,
        defaultValue: '#0060ff'
      },
      linear: {
        alpha: true,
        align: 'left',
        useRgba: true,
        defaultValue: {
          colorStops: [
            { id: 0, offset: 0, color: '#4a90e2' },
            { id: 1, offset: 1, color: '#50e3c2' }
          ]
        }
      },
      radial: {
        alpha: true,
        align: 'left',
        useRgba: true,
        defaultValue: {
          colorStops: [
            { id: 0, offset: 0, color: '#4a90e2' },
            { id: 1, offset: 1, color: '#50e3c2' }
          ]
        }
      }
    } },
    { key: 'dropSectionColor', label: '颜色段', type: 'dropSectionColor', popoverProps: { align: 'right' }}
];

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      datas: {
        // 颜色默认值
        // borderColor2: '#eeffee' // 支持 hex, rgb, rgba
        // borderColor2: 'rgb(238, 255, 238)' // 支持 hex, rgb, rgba
        borderColor2: 'rgb(238, 255, 238, 0.5)', // 支持 hex, rgb, rgba
        borderStyle: 'dotted',
        margins: {
          marginTop: 10,
          marginRight: 20,
          marginBottom: 30,
          marginLeft: 40
        },
        position: {
          x: 16, y: 25
        },
        size: {
          width: 11, height: 15
        }
      }
    };
  }

  onChange = ({ key, value }) => {
    const { datas } = this.state;
    datas[key] = value;
    this.setState({
      datas
    });
    console.log(key, value);
  }

  render() {
    const { datas } = this.state;
    return (
      <div style={{ width: '30em' }}>
        <FormBuilder
          fields={fields}
          formMapper={formMapper}
          onChange={this.onChange}
          datas={datas}
          labelWidth="7em"
        />
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### FormBuilder formFields 配置说明

[FieldItem详情](#FieldItem)，FormItem 通用属性说明：

* `tip`: form 提示信息
* `style`: 自定义样式，FormItem 的样式

---demo
```js
import { FormBuilder } from 'amos-framework';

const formMapper = FormBuilder.formFields;

const fields = [
  { key: 'name', label: '名称', type: 'input', tip: '名称，支持字母、数字、中文' },
  { key: 'align', label: '水平对齐', type: 'align' },
  { key: 'verticalAlign', label: '垂直对齐', type: 'vAlign' },
  { key: 'length', label: '长度', type: 'inputNumber', data: { min: 0, max: 1000, step: 5 } },
  { key: 'status', label: '状态', type: 'switch', data: { onLabel: '启用', offLabel: '禁用', inline: true }, style: { width: 60 } },
  { key: 'padding', label: '内边距', type: 'inputArray', tip: '内边距，单位px，默认各方向内边距为5，接受数组分别设定上右下左边距' },
  { key: 'padding2', label: '内边距2', type: 'inputArray', valueFmt: 'number', tip: '内边距，格式化为number，如：1,2,3,4' },
  { key: 'borderStyle', label: '边框样式', type: 'select', defaultValue: 'dotted', data: { items: ['solid', 'dotted', 'dashed'].map(t => ({
    key: t,
    label: (
      <div style={{ height: 30 }} title={t}>
        <div style={{ height: 15, borderBottom: `1px ${t} black` }} />
      </div>
    ),
    value: t
  })) } },
  { key: 'color', label: '图表颜色', type: 'chartColor', tip: '图表颜色，支持基本颜色和渐变色', data: {
    basic: {
      alpha: true,
      useRgba: true,
      noneValue: 'rgba(0, 0, 0, 0)'
    },
    linear: {
      alpha: true,
      useRgba: true
    },
    radial: {
      alpha: true,
      useRgba: true
    }
  } },
  // 如果设置 format 为 array，则返回值为 [x,y,z] 否则为 {x,y,z}
  { key: 'position', label: '位置', type: 'property3d', data: { format: 'array' } },
  { key: 'scale', label: '缩放', type: 'property3d' },
  { key: 'themeColor', label: '颜色组', type: 'themeColor', tip: '颜色组' },
  { key: 'themeColor2', label: '自定义颜色组', type: 'themeColor', tip: '颜色结果最多显示6个，大于6个不在结果列显示',
    maxShowResult: 12, minColors: 1, maxColors: 16, data: {
      basic: {
        alpha: true,
        useRgba: true,
        noneValue: 'rgba(0, 0, 0, 0)'
      }
    }
  },
];

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      datas: {
        color: {
          type: 'linear',
          x: 0,
          y: 0,
          x2: 0,
          y2: 1,
          colorStops: [
            // 0% 处的颜色
            { offset: 0, color: 'red' },
            // 100% 处的颜色
            { offset: 1, color: 'blue' }
          ],
          globalCoord: false // 缺省为 false
        },
        position: [1,2,3]
      }
    };
  }

  onChange = ({ key, value }) => {
    const { datas } = this.state;
    datas[key] = value;
    this.setState({
      datas
    });
    console.log(key, value);
  }

  render() {
    const { datas } = this.state;
    return (
      <div style={{ width: '30em' }}>
        <FormBuilder
          fields={fields}
          formMapper={formMapper}
          onChange={this.onChange}
          datas={datas}
          labelWidth="8em"
        />
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 统一处理: 自定义form

---demo
```js
import { FormBuilder } from 'amos-framework';

const formMapper = FormBuilder.formFields;

const fields = [
  { key: 'name', label: '名称', type: 'input' },
  { key: 'length', label: '长度', type: 'inputNumber', data: { min: 0, max: 1000, step: 5 } },
  { key: 'background', label: '背景', type: 'color' },
  { key: 'textSetting', label: '内容显示', type: 'textSetting' }
];

class CustomForm extends Component {
  render() {

    const { datas, onChange } = this.props;

    return (
      <FormBuilder
        fields={fields}
        formMapper={formMapper}
        onChange={onChange}
        datas={datas}
      />
    );
  }
}

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      datas2: {
        textSetting: {
            textAlign: 'center', // left center right
            fontStyle: 'italic', // normal italic
            fontWeight: 'bold', // normal bold
            textDecoration: 'underline' // none underline
        }
      }
    };
  }

  onChange2 = ({ key, value }) => {
    const { datas2 } = this.state;
    datas2[key] = value;
    this.setState({
      datas2
    });
    console.log(key, value);
  }

  render() {
    const { datas2 } = this.state;
    return (
      <div style={{ width: '30em' }}>
        <CustomForm
          onChange={this.onChange2}
          datas={datas2}
        />
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 高频FormFiled使用说明

---demo
```js
import { FormBuilder } from 'amos-framework';

const formMapper = FormBuilder.formFields;

const paperSizes = [
  { key: '1024X768', label: '1024X768', value: '1024X768' },
  { key: '1280X900', label: '1280X900', value: '1280X900' },
  { key: '1366X768', label: '1366X768', value: '1366X768' },
  { key: '1440X900', label: '1440X900', value: '1440X900' },
  { key: '1920X1080', label: '1920X1080', value: '1920X1080' },
  { key: '750X1260', label: '手机竖屏', value: '750X1260' },
  { key: '2048X1408', label: '平板横屏', value: '2048X1408' },
  { key: '100%X100%', label: '全屏', value: '100%X100%' }
];

const fields = [
  { key: 'borderColor4', label: '边框颜色4', type: 'iptColorNone' },
  { key: 'fill', label: '填充色', type: 'iptColorNone', data: { noneValue: 'none', noneValueTitle: '无填充' } },
  { key: 'borderColor5', label: '边框颜色5', type: 'iptColor', data: { useRgba: true, alpha: true } },
  { key: 'boxShadow', label: '边框阴影', type: 'boxShadow' },
  { key: 'boxShadow1', label: '边框阴影', type: 'boxShadow', defaultValue: '1px 1px #eee', data: { disabledInput: true } },
  { key: 'border', label: '边框', type: 'border' },
  { key: 'borderRadius', label: '圆角', type: 'borderRadius' },
  { key: 'paperSize', label: '画布尺寸', type: 'paperSize', direction: 'vertical', data: {
    items: paperSizes,
      x: { min: 10, max: 10000, step: 5 },
      y: { min: 10, max: 10000, step: 5 }
  } },
];

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      datas: {
      }
    };
  }

  onChange = ({ key, value }) => {
    const { datas } = this.state;
    datas[key] = value;
    this.setState({
      datas
    });
    console.log(key, value);
  }

  render() {
    const { datas } = this.state;
    return (
      <div style={{ width: '30em' }}>
        <FormBuilder
          fields={fields}
          formMapper={formMapper}
          onChange={this.onChange}
          datas={datas}
          labelWidth="8em"
        />
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### FormFiled 设置 Column、宽度、字段校验

column 采用的是 grid 布局，grid 布局教程，可查阅 [grid-layout-tutorial](http://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html)

> 默认情况下，采用 `enhanceForm` 创建的 `Form` 项，并且配置 `rules` 的表单，会在 `onChange` 时进行校验。

---demo
```js
import { FormBuilder, Button } from 'amos-framework';

const formMapper = FormBuilder.formFields;

const fields = [
  { key: 'name', label: '用户名', type: 'input', rules: [
    { required: true, message: '请输入活动名称' },
    { min: 5, message: '长度不够！' }
  ] },
  { key: 'age', label: '年龄', type: 'inputNumber'},
  { key: 'hobby', label: '擅长语言', type: 'select', defaultValue: 'java', data: { items: ['java', 'javascript', 'c++'] } },
  { key: 'borderColor4', label: '边框颜色4', type: 'iptColorNone' },
  { key: 'borderColor5', label: '边框颜色5', type: 'iptColor', data: { useRgba: true, alpha: true } },
  { key: 'boxShadow', label: '边框阴影', type: 'boxShadow' },
  { key: 'boxShadow1', label: '边框阴影', type: 'boxShadow', defaultValue: '1px 1px #eee', data: { disabledInput: true } },
  { key: 'borderRadius', label: '圆角', type: 'borderRadius' },
];

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      datas: {
      }
    };
  }

  onCreated = (builder) => {
    this.builder = builder;
  }

  onChange = ({ key, value }) => {
    const { datas } = this.state;
    datas[key] = value;
    this.setState({
      datas
    });
    console.log(key, value);
  }

  submit = () => {
    const { datas } = this.state;
    console.log('submit', datas);

    this.builder.validate((valid, dataValues, errors) => {
      console.log('返回内容:', dataValues, valid, errors);
      if (valid) {
        alert(`结果: ${JSON.stringify(dataValues)}`);
      } else {
        console.log('error submit!!');
        return false;
      }
    });
  }

  render() {
    const { datas } = this.state;
    return (
      <div style={{ width: '50em' }}>
        <FormBuilder
          column={2}
          labelWidth="6em"
          contentWidth="100%"
          fields={fields}
          formMapper={formMapper}
          onChange={this.onChange}
          datas={datas}
          onCreated={this.onCreated}
          enableCheck
        />
        <Button onClick={this.submit}>提交</Button>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### FormFiled 设置 简单的联动

注意：隐藏的表单项，在提交时，依然会被提交。

---demo
```js
import { FormBuilder, Button } from 'amos-framework';

const formMapper = FormBuilder.formFields;

const fields = [
  { key: 'name', label: '用户名', type: 'input', rules: [
    { required: true, message: '请输入活动名称' },
    { min: 5, message: '长度不够！' }
  ] },
  { key: 'major', label: '职业', type: 'select', data: { items: ['software', 'teacher', 'tester', 'worker', 'none'] } },
  { key: 'software', label: '擅长语言', type: 'select',
    linkage: { data: { targetKey: 'major', sync: true, conditions: { show: ['software'], hide: ['teacher', 'none'] } } },
    data: { items: ['java', 'javascript', 'c++'] } },
  { key: 'teacher', label: '擅长科目', type: 'select',
    linkage: { data: { targetKey: 'major', sync: true, conditions: { show: ['teacher'], hide: ['software', 'none'] } } },
    data: { items: ['Chinese', 'English', 'other'] }
  },
  // 仅设置 show 条件
  {
    key: 'tester', label: '测试', type: 'select',
    linkage: { data: { targetKey: 'major', sync: true, conditions: { show: ['tester'] } }},
    data: { items: ['UI', 'Unit', 'App'] }
  },
  // 判断条件采用 function 方式
  {
    key: 'worker', label: '工种', type: 'select',
    linkage: { data: { targetKey: 'major', sync: true, conditions: { show: (tarVal) => tarVal === 'worker' } }},
    data: { items: ['building', 'farmer'] }
  }
];

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      datas: {
      }
    };
  }

  onCreated = (builder) => {
    this.builder = builder;
  }

  onChange = ({ key, value }) => {
    const { datas } = this.state;
    datas[key] = value;
    this.setState({
      datas
    });
    console.log(key, value);
  }

  submit = () => {
    const { datas } = this.state;
    console.log('submit', datas);

    this.builder.validate((valid, dataValues, errors) => {
      console.log('返回内容:', dataValues, valid, errors);
      if (valid) {
        alert(`结果: ${JSON.stringify(dataValues)}`);
      } else {
        console.log('error submit!!');
        return false;
      }
    });
  }

  render() {
    const { datas } = this.state;
    return (
      <div style={{ width: '50em' }}>
        <FormBuilder
          labelWidth="6em"
          contentWidth="100%"
          fields={fields}
          formMapper={formMapper}
          onChange={this.onChange}
          datas={datas}
          onCreated={this.onCreated}
          enableCheck
        />
        <Button onClick={this.submit}>提交</Button>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 类 Form 组件： StdForm 使用

---demo
```js
import { StdForm, Input, FormLink } from 'amos-framework';

class Demo extends Component {
  render() {
    return (
      <div style={{ display: 'inline-block', width: '30em' }}>
        <StdForm label="名称">
          <Input placeholder="请输入..." />
        </StdForm>
        <StdForm label="描述">
          <Input placeholder="请输入..." />
        </StdForm>
        <StdForm label="数据配置">
          <FormLink>查看数据项</FormLink>
          <FormLink>编辑数据项</FormLink>
        </StdForm>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 类 Form 组件： StdForm tip 使用

---demo
```js
import { StdForm, Input, FormLink } from 'amos-framework';

class Demo extends Component {
  render() {
    return (
      <div style={{ display: 'inline-block', width: '30em' }}>
        <StdForm label="名称" tip="支持中英文数字">
          <Input placeholder="请输入..." />
        </StdForm>
        <StdForm label="描述" tip="支持中英文数字" tipPosition="content">
          <Input placeholder="请输入..." />
        </StdForm>
        <StdForm label="数据配置">
          <FormLink>查看数据项</FormLink>
          <FormLink>编辑数据项</FormLink>
        </StdForm>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 类 Form 组件： StdForm 使用 垂直

---demo
```js
import { StdForm, Input, Button } from 'amos-framework';

class Demo extends Component {
  render() {
    return (
      <div style={{ display: 'inline-block', width: '30em' }}>
        <StdForm label="名称" vertical>
          <Input placeholder="请输入..." />
        </StdForm>
        <StdForm label="描述" vertical>
          <Input placeholder="请输入..." />
        </StdForm>
        <StdForm label="操作" vertical>
          <Button>选择</Button>
          <Button>重置</Button>
        </StdForm>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 类 Form 组件： StdForm 使用 填充content

---demo
```js
import { StdForm, Input, Button } from 'amos-framework';

class Demo extends Component {
  render() {
    return (
      <div style={{ display: 'inline-block', width: '30em' }}>
        <StdForm label="名称" fullness>
          <Input placeholder="请输入..." />
        </StdForm>
        <StdForm label="描述" fullness>
          <Input placeholder="请输入..." />
        </StdForm>
        <StdForm label="操作" fullness>
          <Button>选择</Button>
          <Button>重置</Button>
        </StdForm>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 类 Form 组件： StdFormRow 使用 block

---demo
```js
import { StdFormRow, Input } from 'amos-framework';

class Demo extends Component {
  render() {
    return (
      <div style={{ display: 'inline-block', width: '30em' }}>
        <StdFormRow label="名称">
          <Input placeholder="请输入..." />
        </StdFormRow>
        <StdFormRow label="描述(block)" block>
          <Input placeholder="请输入..." />
        </StdFormRow>
        <StdFormRow label="编号" block required>
          <Input placeholder="请输入..." />
        </StdFormRow>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 类 Form 组件： StdFormRow 使用 hide

> 通过 devtool 查看渲染的 elements，查看区别。

---demo
```js
import { StdFormRow, Input } from 'amos-framework';

class Demo extends Component {
  state = {
    value: ''
  };

  handleChange = (e) => {
    this.setState({ value: e.target.value });
  }

  render() {
    const { value } = this.state;
    return (
      <div style={{ display: 'inline-block', width: '30em' }}>
        <StdFormRow label="输入1则隐藏">
          <Input placeholder="请输入..." value={value} onChange={this.handleChange} />
        </StdFormRow>
        <StdFormRow label="bool值隐藏" hide>
          <Input placeholder="请输入..." />
        </StdFormRow>
        <StdFormRow label="值为1时该项隐藏" hide={() => value === '1'}>
          <Input placeholder="请输入..." />
        </StdFormRow>
        <StdFormRow
          label="值为2时该项置空"
          hide={{
            type: 'empty',
            value: () => value === '2'
          }}
        >
          <Input placeholder="请输入..." />
        </StdFormRow>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 类 Form 组件： FormGroup 使用
---demo
```js
import { FormGroup, StdForm, Input } from 'amos-framework';

class Demo extends Component {
  render() {
    return (
      <div style={{ display: 'inline-block', width: '30em' }}>
        <StdForm label="名称" align="left" tip="支持中文、字母、数字、下划线">
          <Input placeholder="请输入..." />
        </StdForm>
        <FormGroup label="个人信息" vertical suffix={null}>
          <StdForm label="真实姓名" align="left">
            <Input placeholder="请输入..." />
          </StdForm>
          <StdForm label="身份证号" align="left">
            <Input placeholder="请输入..." />
          </StdForm>
        </FormGroup>
        <FormGroup label="健康信息" suffix={null} showBrackets>
          <StdForm label="身高">
            <Input placeholder="请输入..." />
          </StdForm>
          <StdForm label="体重">
            <Input placeholder="请输入..." />
          </StdForm>
        </FormGroup>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### FormInfo 使用
---demo
```js
import { FormInfo } from 'amos-framework';

const fields = [
  { key: 'name', label: '名称' },
  { key: 'addr', label: '地址' },
  { key: 'contact', label: '联系人' },
  { key: 'phone', label: '联系电话' }
];

const datas = {
  name: 'ilex',
  addr: '西安市',
  contact: 'ray',
  phone: '152xxxxxxxx'
};

const fields2 = [
  { key: 'name', label: '名称' },
  { key: 'contact', label: '联系人' },
  { key: 'addr', label: '地址', block: true },
  { key: 'phone', label: '联系电话' }
];

const datas2 = {
  name: 'ilex',
  contact: 'ray',
  addr: '西安市，这是一行特别长的字段，这一行占满整行...',
  phone: '152xxxxxxxx'
};

class Demo extends Component {
  render() {
    return (
      <div style={{ display: 'inline-block', width: '30em' }}>
        <FormInfo fields={fields} datas={datas} />
        <div>-------分割线------</div>
        <FormInfo fields={fields} datas={datas} column={2}/>
        <div>-------分割线------</div>
        <FormInfo fields={fields2} datas={datas2} column={2}/>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

## FormBuilder props

| params  | type | default | description |
|--------- |-------- |--------- |-------- |
| prefixCls | String | `amos-form-builder` | 样式前缀 |
| className | String | - | 自定义样式名 |
| fields | Array<[FieldItem](#FieldItem)> | - | 表单域集合 |
| formMapper | Object | - | 表单 item 组件集  |
| onChange | Function | - | 表单 onChange 回调 |
| datas | Object or Array | form 数据集 |
| direction | string | horizontal | 可取的值为： 'horizontal', 'vertical' |
| column | Number | - | 列个数，表示多少列，值 大于等于 2 才有效 |
| labelWidth | `Number or String` | - | form label 域宽度 |
| contentWidth | `Number or String` | - | form content 宽度 |
| renderItem | func | - | 自定义 render item， `(props, item, frmbuilderIst) => React.Node` |
| processItemData | `func: item => item` | - | 自定义处理 item 数据。如果不是用自定义 `renderItem`，可以采用该参数统一 item 参数 |
| onCreated | `func: ist => {}` | - | 组件创建成功之后的回调 `(frmBuilder) => {}`，用于 `rules` 校验回调 |

具体的 field、datas 格式，可查看 `案例演示` 中相关参数。

如果自定义 FormField 则需要继承自 `FormBuilder.BasicForm`。

> FormBuilder 选项校验，由具体的 FormItem 实现，直接在配置相中配置 rules 即可

```js
// FormBuilder 还提供 `BasicForm 和 formFields`

import { FormBuilder } from 'amos-framework';

const { formFields, BasicForm } = FormBuilder;

// methods， 通过onCreated方法，缓存 formBuilder instance

class Demo extends Component {
  onCreated = (builder) => {
    this.builder = builder;
  }

  submit = () => {
    const { datas } = this.state;
    console.log('submit', datas);

    this.builder.validate((valid, dataValues, errors) => {
      console.log('返回内容:', dataValues, valid, errors);
      if (valid) {
        alert(`结果: ${JSON.stringify(dataValues)}`);
      } else {
        console.log('error submit!!');
        return false;
      }
    });
  }

  render() {
    return <FormBuilder onCreated={this.onCreated} />;
  }
}
```

> FormItem 具体组件 className 命名，均需要以 `param-` 开头，如果是组合的 form，此时需要以 `mixparams-` 开头。

### FieldItem

| params  | type | description |
|--------- |-------- |-------- |
| key | String | 唯一字段，form 键，与 datas 中的键一一对应 |
| label | String | form 表单前显示名称 |
| type | String | 具体的 FormItem 类型，内置具体取值详见： [fieldItemType](#fieldItemType) |
| data | any | 每一个 `FormItem` 配置参数 |
| tip | ReactNode | 表单 Item 提示 |
| style | Object | 表单 FormItem 样式 |
| linkage | Object | 联动配置 |
| labelStyle | Object | label 标签的样式，优先级高于 `Formbuilder` 中设置的 `labelStyle` |
| wrapStyle | Object | 外层 form item style |
| block | bool | 是否采用块级 |
| direction | bool | 布局方式，可选值为: `horizontal、vertical` |

> data 配置参数

```js
{
  items: [] // 表示各个 FieldItem 子节点集合，如 checkbox/fontFamily/fontSize/radio/select/tags
  ... // 各自组件其它 props 配置项
}
```

> linkage 配置参数

```js
{
  // 联动配置项 { targetKey: '联动触发的 field', conditions: { show: ['1'], hide: ['2'] }, sync: false }
  // 表示：当 targetKey 所在的formItem 值 等于 '1' 时 显示， 等于 '2' 时隐藏
  // sync 设置为true，则表单项隐藏时，同步删除该表单项的 data
  data: Object,
  // 处理联动之后，返回新的 FormItem， (content, data) => content;
  renderWithCheck: (content, data) => content;
}
```

#### fieldItemType

| params  | component |
|--------- |-------- |
| textSetting | TextSetting |
| input | Ipt |
| inputNumber | IptNumber |
| textarea | Textarea |
| position | Position |
| size | Size |
| margins | Margins |
| slider | Slider |
| switch | Switch |
| tags | Tags |
| radio | Radio |
| checkbox | Checkbox |
| fontFamily | FontFamily |
| fontSize | FontSize |
| color | ColorParam |
| bgPosition | BackgroundPosition |

> borderStyle 中，也可以配置自己的 items，items 案例如下：

```js
const fields = [
  {
    key: 'borderStyle', label: '边框样式', type: 'borderStyle', defaultValue: 'none', data: {
    items: [
      { key: 'none', label: '无边框' },
      { key: 'dotted', label: '点状', isRender: true },
      { key: 'dashed', label: '虚线', isRender: true },
      { key: 'solid', label: '实线', isRender: true },
      { key: 'double', label: '双线', isRender: true }
    ]
  }}
];
```

## FormGrop props

一组表单联合使用时，使用

| params  | type | default | description |
|--------- |-------- |--------- |-------- |
| prefixCls | String | `amos-formgroup` | 样式前缀 |
| className | String | - | 自定义样式名 |
| label | String | - | 表单条目 label |
| vertical | boolean | - | 垂直显示  |
| suffix | String | ':' | label 后缀，设置为 null 或者 false 可以禁用后缀 |
| showBrackets | boolean | - | 仅支持水平分组时，显示括号 |

## StdForm props

| params  | type | default | description |
|--------- |-------- |--------- |-------- |
| prefixCls | String | `amos-std-form` | 样式前缀 |
| className | String | - | 自定义样式名 |
| style | Object | - | 外层容器内联样式 |
| labelStyle | Object | - | form label 内联样式 |
| contentStyle | Object | - | form item 内容内联样式 |
| label | String | - | 表单条目 label |
| children | ReactNode | - | 表单内容 |
| vertical | boolean | - | 垂直显示 |
| tight | boolean | - | 是否采用紧蹙的，label 之后紧跟 content，当 vertical = true 时，无效 |
| fullness | boolean | - | 填满content，当 vertical = true 时，无效。`children` 仅接受单个`ReactElement` |
| align | String | 'right' | 对齐方式，默认 右对齐，可选值为 `left`、`right` |
| tip | ReactNode | - | 表单 Item 提示 |
| tipPosition | String | 'label' | tip 出现的位置，可选值为 `label、content` |
| `data-xxx` | String | - | 支持给根节点div添加 `data-xxx` 属性 |
| tipPopProps | Object | - | tip 的 popover 配置项 |

## StdFormRow props

| params  | type | default | description |
|--------- |-------- |--------- |-------- |
| prefixCls | String | `amos-stdform-row` | 样式前缀 |
| className | String | - | 自定义样式名 |
| style | Object | - | 自定义内敛样式 |
| label | String | - | 表单条目 label |
| children | ReactNode | - | 表单内容 |
| last | boolean | - | 最后一个  |
| block | boolean | - | 块级  |
| grid | boolean | - | 格子 |
| hide | `boolean` or `function` or `{type, value: Boolean or Function}` | - | 隐藏 |
| required | boolean | - | 是否必填，设置为 true 时，会在 label 前显示红色的 `*` |

## FormLink props

| params  | type | default | description |
|--------- |-------- |--------- |-------- |
| children | ReactNode | - | 内容 |
| blank | Boolean | - | 当设置 href 时，是否打开新页面 |
| href | String | - | 超链接 |
| onClick | Function | - | 点击事件回调 |

## FormInfo props

| params  | type | default | description |
|--------- |-------- |--------- |-------- |
| prefixCls | string | amos-forminfo | 自定义样式前缀 |
| className | string | - | 自定义样 |
| style | object | - | 容器内联样式 |
| fields | `{key, label, value, type, block}[]` | - | 表单项 |
| labelWidth | `string or number` | - | label 宽度 |
| labelStyle | object | - | label 内联样式 |
| valueStyle | object | - | 值 内联样式 |
| renderValue | func | - | 自定义渲染 value 值 |
| datas | object | - | 与 fields 对应的值 |
| column | number | - | 列个数，表示多少列 |

> 注意，当设置  column 列个数大于 1  时，设置当前 fields item 为 block，表示占满一整行
