@uform/antd

npm install --save @uform/antd

Usage no npm install needed!

<script type="module">
  import uformAntd from 'https://cdn.skypack.dev/@uform/antd';
</script>

README

@uform/antd

Install

npm install --save @uform/antd

Table Of Contents

Quick-Start


Example:develop with JSX

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import { Button } from 'antd'
import'antd/dist/antd.css'

const actions = createFormActions()

const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="radio"
        enum={['1', '2', '3', '4']}
        title="Radio"
        name="radio"
      />
      <Field
        type="string"
        enum={['1', '2', '3', '4']}
        required
        title="Select"
        name="select"
      />
      <Field
        type="checkbox"
        enum={['1', '2', '3', '4']}
        required
        title="Checkbox"
        name="checkbox"
      />
      <Field
        type="string"
        title="TextArea"
        name="textarea"
        x-component="textarea"
      />
      <Field type="number" title="number" name="number" />
      <Field type="boolean" title="boolean" name="boolean" />
      <Field type="date" title="date" name="date" />
      <Field
        type="daterange"
        title="daterange"
        default={['2018-12-19', '2018-12-19']}
        name="daterange"
      />
      <Field type="year" title="year" name="year" />
      <Field type="time" title="time" name="time" />
      <Field
        type="upload"
        title="upload(card)"
        name="upload"
        x-props={{ listType: 'card' }}
      />
      <Field
        type="upload"
        title="upload(dragge)"
        name="upload2"
        x-props={{ listType: 'dragger' }}
      />
      <Field
        type="upload"
        title="upload(text)"
        name="upload3"
        x-props={{ listType: 'text' }}
      />
      <Field
        type="range"
        title="range"
        name="range"
        x-props={{ min: 0, max: 1024, marks: [0, 1024] }}
      />
      <Field
        type="transfer"
        enum={[{ value: 1, title: 'opt1' }, { value: 2, title: 'opt2' }]}
        x-props={{
          render: (item) => item.title
        }}
        title="transfer"
        name="transfer"

      />
      <Field type="rating" title="rating" name="rating" />
      <FormButtonGroup offset={7} sticky>
        <Submit />
        <Reset />
        <Button
          onClick={() => {
            actions.setFieldState('upload', state => {
              state.value = [
                {
                  downloadURL:
                    '//img.alicdn.com/tfs/TB1n8jfr1uSBuNjy1XcXXcYjFXa-200-200.png',
                  imgURL:
                    '//img.alicdn.com/tfs/TB1n8jfr1uSBuNjy1XcXXcYjFXa-200-200.png',
                  name: 'doc.svg'
                }
              ]
            })
          }}
        >
          Upload
        </Button>
        <Button
          onClick={() => {
            actions.setFormState(state => {
              state.values = {
                radio: '4',
                checkbox: ['2', '3']
              }
            })
          }}
        >
          Set Value
        </Button>
      </FormButtonGroup>
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

Example:develop with JSON Schema

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import { Button } from 'antd'
import'antd/dist/antd.css'

const actions = createFormActions()

const App = () => {
  const schema = {
    type: 'object',
    properties: {
      radio: {
        type: 'radio',
        enum: ['1', '2', '3', '4'],
        title: 'Radio'
      },
      select: {
        type: 'string',
        enum: ['1', '2', '3', '4'],
        title: 'Select',
        required: true
      },
      checkbox: {
        type: 'checkbox',
        enum: ['1', '2', '3', '4'],
        title: 'Checkbox',
        required: true
      },
      textarea: {
        type: 'string',
        'x-component': 'textarea',
        title: 'TextArea'
      },
      number: {
        type: 'number',
        title: 'number'
      },
      boolean: {
        type: 'boolean',
        title: 'boolean'
      },
      date: {
        type: 'date',
        title: 'date'
      },
      daterange: {
        type: 'daterange',
        default: ['2018-12-19', '2018-12-19'],
        title: 'daterange'
      },
      year: {
        type: 'year',
        title: 'year'
      },
      time: {
        type: 'time',
        title: 'time'
      },
      upload: {
        type: 'upload',
        'x-props': {
          listType: 'card'
        },
        title: 'upload(card)'
      },
      upload2: {
        type: 'upload',
        'x-props': {
          listType: 'dragger'
        },
        title: 'uplaod(dragger)'
      },
      upload3: {
        type: 'upload',
        'x-props': {
          listType: 'text'
        },
        title: 'upload(text)'
      },
      range: {
        type: 'range',
        'x-props': {
          min: 0,
          max: 1024,
          marks: [0, 1024]
        },
        title: 'range'
      },
      transfer: {
        type: 'transfer',
        enum: [
          {
            key: 1,
            title: 'opt1'
          },
          {
            key: 2,
            title: 'opt2'
          }
        ],
        'x-props': {
          render: (item) => item.title
        },
        title: 'transfer'
      },
      rating: {
        type: 'rating',
        title: 'rating'
      },
      layout_btb_group: {
        type: 'object',
        'x-component': 'button-group',
        'x-component-props': {
          offset:7,
          sticky: true,
        },
        properties: {
          submit_btn: {
            type: 'object',
            'x-component': 'submit',
            'x-component-props': {
              children: 'Submit',
            },
          },
          reset_btn: {
            type: 'object',
            'x-component': 'reset',
            'x-component-props': {
              children: 'Reset',
            },
          },
        }
      },
    }
  }
  return <SchemaForm actions={actions} schema={schema} />
}

ReactDOM.render(<App />, document.getElementById('root'))

Components


<SchemaForm/>

Base on <SchemaMarkupForm/> of @uform/react-schema-renderer. Recommended for production environments.

interface IAntdSchemaFormProps {
    // render by schema
    schema?: ISchema;
    fields?: ISchemaFormRegistry['fields'];
    virtualFields?: ISchemaFormRegistry['virtualFields'];
    // pre-registered Form Component
    formComponent?: ISchemaFormRegistry['formComponent'];
    // pre-registered FormItem Component
    formItemComponent?: ISchemaFormRegistry['formItemComponent'];
    // layout setting
    layout?: FormLayout;
    form?: WrappedFormUtils;
    // triggered by `htmlType="submit"` or action.submit
    onSubmit?: React.FormEventHandler<HTMLFormElement>;
    style?: React.CSSProperties;
    className?: string;
    // className of prefix
    prefixCls?: string;
    hideRequiredMark?: boolean;
    // FormItem column settiing
    wrapperCol?: ColProps;
    // label column settiing
    labelCol?: ColProps;
    // it there a colon
    colon?: boolean;
    // alignment of label
    labelAlign?: FormLabelAlign;
    // is it inline
    inline?: boolean
    className?: string
    style?: React.CSSProperties
    // custom placeholder when preivew
    previewPlaceholder?: string | ((props: IPreviewTextProps) => string);
    // form state value
    value?: Value;
    // form state defaultValue
    defaultValue?: DefaultValue;
    // form state initialValues
    initialValues?: DefaultValue;
    // FormActions instance 
    actions?: FormActions;
    // IFormEffect instance
    effects?: IFormEffect<FormEffectPayload, FormActions>;
    // form instance
    form?: IForm;
    // Form change event callback
    onChange?: (values: Value) => void;
    // triggered by `htmlType="submit"` or actions.submit时
    onSubmit?: (values: Value) => void | Promise<Value>;
    // triggered by <Reset/> or actions.reset
    onReset?: () => void;
    // Form verification failure event callback
    onValidateFailed?: (valideted: IFormValidateResult) => void;
    children?: React.ReactElement | ((form: IForm) => React.ReactElement);
    // Whether to use the dirty check, the default will go immer accurate update
    useDirty?: boolean;
    // Is it editable, overall control in the Form dimension
    editable?: boolean | ((name: string) => boolean);
    // Whether to go pessimistic check, stop the subsequent check when the first check fails
    validateFirst?: boolean;    
}

Usage

Example1: Sync value of a and a-mirror

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  registerFormField,
  Field,  
  connect,
  createFormActions
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()

ReactDOM.render(
    <SchemaForm actions={actions} effects={($)=>{
       $('onFieldChange','aa').subscribe((fieldState)=>{
         actions.setFieldState('bb',state=>{
           state.value = fieldState.value
         })
       })
    }}>
       <Field type="string" name="a" title="a"/>
       <Field type="string" name="a-mirror" title="a-mirror"/>
    </SchemaForm>,
    document.getElementById('root')
)

Example:Layout

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  Field,  
  createFormActions,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset,
} from '@uform/antd'

const actions = createFormActions()

ReactDOM.render(
    <div>
    <h5>Basic Layout</h5>
    <SchemaForm>
      <FormLayout labelCol={8} wrapperCol={6}>
        <Field name="aaa" type="string" title="field1" />
        <Field name="bbb" type="number" title="field2" />
        <Field name="ccc" type="date" title="field3" />
      </FormLayout>
      <FormButtonGroup offset={8}>
        <Submit>Submit</Submit>​ <Reset>Reset</Reset>​
      </FormButtonGroup>
    </SchemaForm>
    <h5>Inline Layout</h5>
    <SchemaForm inline>
      <Field name="aaa" type="string" title="field1" />
      <Field name="bbb" type="number" title="field2" />
      <Field name="ccc" type="date" title="field3" />​
      <FormButtonGroup>
        <Submit>Submit</Submit>​ <Reset>Reset</Reset>​
      </FormButtonGroup>
    </SchemaForm>
    <h5>editable = false</h5>
    <SchemaForm inline editable={false}>
      <Field name="aaa" type="string" title="field1" />
      <Field name="bbb" type="number" title="field2" />
      <Field name="ccc" type="date" title="field3" />​
      <FormButtonGroup>
        <Submit>Submit</Submit>​ <Reset>Reset</Reset>​
      </FormButtonGroup>
    </SchemaForm>
    </div>,
    document.getElementById('root')
)

<SchemaMarkupField/>

Core components of @uform/antd, used to describe form fields

interface IMarkupSchemaFieldProps {
  name?: string
  /** base json schema spec**/
  title?: SchemaMessage
  description?: SchemaMessage
  default?: any
  readOnly?: boolean
  writeOnly?: boolean
  type?: 'string' | 'object' | 'array' | 'number' | string
  enum?: Array<string | number | { label: SchemaMessage; value: any }>
  const?: any
  multipleOf?: number
  maximum?: number
  exclusiveMaximum?: number
  minimum?: number
  exclusiveMinimum?: number
  maxLength?: number
  minLength?: number
  pattern?: string | RegExp
  maxItems?: number
  minItems?: number
  uniqueItems?: boolean
  maxProperties?: number
  minProperties?: number
  required?: string[] | boolean
  format?: string
  /** nested json schema spec **/
  properties?: {
    [key: string]: ISchema
  }
  items?: ISchema | ISchema[]
  additionalItems?: ISchema
  patternProperties?: {
    [key: string]: ISchema
  }
  additionalProperties?: ISchema
  /** extend json schema specs */
  editable?: boolean
  visible?: boolean
  display?: boolean
  ['x-props']?: { [name: string]: any }
  ['x-index']?: number
  ['x-rules']?: ValidatePatternRules
  ['x-component']?: string
  ['x-component-props']?: { [name: string]: any }
  ['x-render']?: <T = ISchemaFieldComponentProps>(
    props: T & {
      renderComponent: () => React.ReactElement
    }
  ) => React.ReactElement
  ['x-effect']?: (
    dispatch: (type: string, payload: any) => void,
    option?: object
  ) => { [key: string]: any }
}
Usage
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  FormSlot,
  Field,  
  createFormActions,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset,
} from '@uform/antd'

const actions = createFormActions()

ReactDOM.render(
    <SchemaForm>
      <FormSlot><div>required</div></FormSlot>
      <Field name="a" required type="string" title="field1" />
      
      <FormSlot><div>description</div></FormSlot>
      <Field name="b" description="description" type="string" title="field1" />
      
      <FormSlot><div>default value</div></FormSlot>
      <Field name="c" default={10} type="string" title="field1" />

      <FormSlot><div>readOnly</div></FormSlot>
      <Field name="d" readOnly default={10} type="string" title="field1" />

      <FormSlot><div>visible = false</div></FormSlot>
      <Field name="e" visible={false} default={10} type="string" title="field1" />

      <FormSlot><div>display = false</div></FormSlot>
      <Field name="f" visible={false} default={10} type="string" title="field1" />

      <FormSlot><div>editable = false</div></FormSlot>
      <Field name="g" editable={false} default={10} type="string" title="field1" />
    </SchemaForm>,
    document.getElementById('root')
)

<Submit/>

Props of <Submit/>

interface ISubmitProps {
  /** reset pops **/
  onSubmit?: ISchemaFormProps['onSubmit']
  showLoading?: boolean
  /** nextBtnProps **/
  // type of btn
  type?: 'primary' | 'secondary' | 'normal'
  // size of btn
  size?: 'small' | 'medium' | 'large'
  // size of Icon 
  iconSize?: 'xxs' | 'xs' | 'small' | 'medium' | 'large' | 'xl' | 'xxl' | 'xxxl'
  // type of button  when component = 'button'
  htmlType?: 'submit' | 'reset' | 'button'
  // typeof btn
  component?: 'button' | 'a'
  // Set the loading state of the button
  loading?: boolean
  // Whether it is a ghost button
  ghost?: true | false | 'light' | 'dark'
  // Whether it is a text button
  text?: boolean
  // Whether it is a warning button
  warning?: boolean
  // Whether it is disabled
  disabled?: boolean
  // Callback for button click
  onClick?: (e: {}) => void
  // Valid when Button component is set to 'a', which represents the URL of the linked page
  href?: string
  // Valid when Button component is set to 'a', which represents the way of open the linked document
  target?: string
}

<Reset/>

Props of <Reset/>

interface IResetProps {
  /** reset pops **/
  forceClear?: boolean
  validate?: boolean
  /** nextBtnProps **/
  // type of btn
  type?: 'primary' | 'secondary' | 'normal'
  // size of btn
  size?: 'small' | 'medium' | 'large'
  // size of Icon 
  iconSize?: 'xxs' | 'xs' | 'small' | 'medium' | 'large' | 'xl' | 'xxl' | 'xxxl'
  // type of button when component = 'button'
  htmlType?: 'submit' | 'reset' | 'button'
  // typeof btn
  component?: 'button' | 'a'
  // Set the loading state of the button
  loading?: boolean
  // Whether it is a ghost button
  ghost?: true | false | 'light' | 'dark'
  // Whether it is a text button
  text?: boolean
  // Whether it is a warning button
  warning?: boolean
  // Whether it is disabled
  disabled?: boolean
  // Callback for button click
  onClick?: (e: {}) => void
  // Valid when Button component is set to 'a', which represents the URL of the linked page
  href?: string
  // Valid when Button component is set to 'a', which represents the way of open the linked document
  target?: string
}

<FormSpy/>

<FormSpy> Props

interface IFormSpyProps {
  // selector, eg: [ LifeCycleTypes.ON_FORM_SUBMIT_START, LifeCycleTypes.ON_FORM_SUBMIT_END ]
  selector?: string[] | string
  // reducer
  reducer?: (
    state: any,
    action: { type: string; payload: any },
    form: IForm
  ) => any
  children?: React.ReactElement | ((api: IFormSpyAPI) => React.ReactElement)
}

Usage

Example1: Form state change counter

import React from 'react'
import ReactDOM from 'react-dom'
import { Form, Field, createFormActions, FormSpy, LifeCycleTypes } from '@uform/react'

const actions = createFormActions()
const InputField = props => (
  <Field {...props}>
    {({ state, mutators }) => (
      <React.Fragment>
        <input
          disabled={!state.editable}
          value={state.value || ''}
          onChange={mutators.change}
          onBlur={mutators.blur}
          onFocus={mutators.focus}
        />
        <span style={{ color: 'red' }}>{state.errors}</span>
        <span style={{ color: 'orange' }}>{state.warnings}</span>
      </React.Fragment>
    )}
  </Field>
)

const App = () => {
  return (
    <Form actions={actions}>
      <label>username</label>
      <InputField name="username" />
      <label>age</label>
      <InputField name="age" />
      <FormSpy
        selector={LifeCycleTypes.ON_FORM_VALUES_CHANGE}
        reducer={(state, action, form) => ({
          count: state.count ? state.count + 1 : 1
        })}
      >
        {({ state, type, form }) => {
          return <div>count: {state.count || 0}</div>
        }}
      </FormSpy>
    </Form>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

Example2:Combo

import React from 'react'
import ReactDOM from 'react-dom'
import { Form, Field, createFormActions, FormSpy } from '@uform/react'

const actions = createFormActions()
const InputField = props => (
  <Field {...props}>
    {({ state, mutators }) => (
      <React.Fragment>
        <input
          disabled={!state.editable}
          value={state.value || ''}
          onChange={mutators.change}
          onBlur={mutators.blur}
          onFocus={mutators.focus}
        />
        <span style={{ color: 'red' }}>{state.errors}</span>
        <span style={{ color: 'orange' }}>{state.warnings}</span>
      </React.Fragment>
    )}
  </Field>
)

const App = () => {
  return (
    <Form actions={actions}>
      <label>username</label>
      <InputField name="username" />
      <label>age</label>
      <InputField name="age" />
      <FormSpy>
        {({ state, form }) => {
          return (
            <div>
              name: {form.getFieldValue('username')}
              <br />
              age: {form.getFieldValue('age')}
            </div>
          )
        }}
      </FormSpy>
    </Form>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

<Field/>

deprecated,please use SchemaMarkupField

Array Components

array

import React, { useState, useEffect } from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  Field,
  FormItemGrid,
  FormButtonGroup,
  Submit,
  Reset,
  FormBlock,
  FormLayout
} from '@uform/antd'
import'antd/dist/antd.css'
import Printer from '@uform/printer'

const App = () => {
  const [value, setValues] = useState({})
  useEffect(() => {
    setTimeout(() => {
      setValues({
        array: [{ array2: [{ aa: '123', bb: '321' }] }]
      })
    }, 1000)
  }, [])
  return (
    <Printer>
      <SchemaForm initialValues={value} onSubmit={v => console.log(v)}>
        <Field
          title="Array"
          name="array"
          maxItems={3}
          type="array"
          x-props={{
            renderAddition: 'Add Text',
            renderRemove: 'Remove Text'
          }}
        >
          <Field type="object">
            <FormBlock title="Object Field">
              <FormLayout labelCol={9} wrapperCol={6}>
                <Field name="aa" type="string" title="field1" />
                <Field name="bb" type="string" title="field2" />
                <FormItemGrid title="field3" gutter={10}>
                  <Field name="cc" type="string" />
                  <Field name="dd" type="string" />
                </FormItemGrid>
              </FormLayout>
            </FormBlock>
            <FormBlock title="Nested Array Field">
              <Field name="array2" maxItems={3} type="array">
                <Field type="object">
                  <FormLayout labelCol={9} wrapperCol={6}>
                    <Field name="aa" type="string" title="field1" />
                    <Field name="bb" type="string" title="field2" />
                    <FormItemGrid title="field3" gutter={10}>
                      <Field name="cc" type="string" />
                      <Field name="dd" type="string" />
                    </FormItemGrid>
                  </FormLayout>
                </Field>
              </Field>
            </FormBlock>
          </Field>
        </Field>
        <FormButtonGroup>
          <Submit>Submit</Submit>
          <Reset>Reset</Reset>
        </FormButtonGroup>
      </SchemaForm>
    </Printer>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

cards

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  Field,
  FormItemGrid,
  FormButtonGroup,
  Submit,
  Reset,
  FormBlock,
  FormLayout
} from '@uform/antd'
import'antd/dist/antd.css'
import Printer from '@uform/printer'

const App = () => (
  <Printer>
    <SchemaForm>
      <Field
        name="array"
        maxItems={3}
        type="array"
        x-component="cards"
        x-props={{
          title: 'Title of cards',
          renderAddition: 'Add Text',
          renderRemove: 'Remove Text'
        }}
      >
        <Field type="object">
          <FormLayout labelCol={6} wrapperCol={8}>
            <Field
              name="aa"
              type="string"
              description="hello world"
              title="field1"
            />
            <Field name="bb" type="string" title="field2" />
            <Field name="cc" type="string" title="field3" />
            <Field name="dd" type="string" title="field4" />
            <Field name="dd" type="string" title="field5" />
            <Field name="ee" type="string" title="field6" />
            <Field name="ff" type="string" title="field7" />
            <Field name="gg" type="daterange" title="field8" />
          </FormLayout>
          <Field
            name="array"
            maxItems={3}
            type="array"
            x-component="cards"
            x-props={{ title: 'Title of cards' }}
          >
            <Field type="object">
              <FormLayout labelCol={6} wrapperCol={8}>
                <Field
                  name="aa"
                  type="string"
                  description="hello world"
                  title="field1"
                />
                <Field name="bb" type="string" title="field2" />
                <Field name="cc" type="string" title="field3" />
                <Field name="dd" type="string" title="field4" />
                <Field name="dd" type="string" title="field5" />
                <Field name="ee" type="string" title="field6" />
                <Field name="ff" type="string" title="field7" />
                <Field name="gg" type="daterange" title="field8" />
              </FormLayout>
            </Field>
          </Field>
        </Field>
      </Field>
    </SchemaForm>
  </Printer>
)
ReactDOM.render(<App />, document.getElementById('root'))

table

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  Field,
  FormItemGrid,
  FormButtonGroup,
  Submit,
  Reset,
  FormBlock,
  FormLayout
} from '@uform/antd'
import'antd/dist/antd.css'
import Printer from '@uform/printer'

const App = () => (
  <Printer>
    <SchemaForm>
      <FormLayout>
        <Field
          title="Array"
          name="array"
          maxItems={3}
          type="array"
          x-component="table"
          x-props={{
            renderExtraOperations() {
              return <div>Hello worldasdasdasdasd</div>
            },
            operationsWidth: 300
          }}
        >
          <Field type="object">
            <Field
              name="aa"
              type="string"
              description="hello world"
              title="field1"
            />
            <Field name="bb" type="string" title="field2" />
            <Field name="cc" type="string" title="field3" />
            <Field name="dd" type="string" title="field4" x-index={1} />
            <Field name="ee" type="string" title="field5" />
            <Field name="ff" type="string" title="field6" />
            <Field name="gg" type="string" title="field7" />
            <Field name="hh" type="daterange" title="field8" />
          </Field>
        </Field>
      </FormLayout>
    </SchemaForm>
  </Printer>
)
ReactDOM.render(<App />, document.getElementById('root'))

Layout Components

<FormCard/>

Props of <FormCard/>, fully inherited from CardProps。 The only difference between FormCard FormBlock is a border on the style

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, { FormCard, SchemaMarkupField as Field } from '@uform/antd'
import'antd/dist/antd.css'

const App = () => (
  <SchemaForm>
    <FormCard title="block">
      <Field type="string" name="username" title="username" />
    </FormCard>
  </SchemaForm>
)
ReactDOM.render(<App />, document.getElementById('root'))

<FormBlock/>

Props of <FormBlock/> , fully inherited from CardProps

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, { FormBlock, SchemaMarkupField as Field } from '@uform/antd'
import'antd/dist/antd.css'

const App = () => (
  <SchemaForm>
    <FormBlock title="block">
      <Field type="string" name="username" title="username" />
    </FormBlock>
  </SchemaForm>
)
ReactDOM.render(<App />, document.getElementById('root'))

<FormStep/>

Props of <FormStep/>

interface IFormStep {
  dataSource: StepItemProps[]
  /** next step props**/
  // current
  current?: number
  // direction of step
  direction?: 'hoz' | 'ver'
  // Content arrangement in horizontal layout
  labelPlacement?: 'hoz' | 'ver'
  // shape of step
  shape?: 'circle' | 'arrow' | 'dot'
  readOnly?: boolean
  // Whether to activate animation
  animation?: boolean
  className?: string
  // Custom StepItem render
  itemRender?: (index: number, status: string) => React.ReactNode
}

Usage

import {
  SchemaForm,
  Field,
  FormButtonGroup,
  Submit,
  FormEffectHooks,
  createFormActions,
  FormGridRow,
  FormItemGrid,
  FormGridCol,
  FormPath,
  FormLayout,
  FormBlock,
  FormCard,
  FormTextBox,
  FormStep
} from '@uform/antd'
import { Button } from 'antd'
import'antd/dist/antd.css'

const { onFormInit$ } = FormEffectHooks

const actions = createFormActions()

let cache = {}

export default () => (
  <SchemaForm
    onSubmit={values => {
      console.log('submit')
      console.log(values)
    }}
    actions={actions}
    labelCol={{ span: 8 }}
    wrapperCol={{ span: 6 }}
    validateFirst
    effects={({ setFieldState, getFormGraph }) => {
      onFormInit$().subscribe(() => {
        setFieldState('col1', state => {
          state.visible = false
        })
      })
    }}
  >
    <FormStep
      style={{ marginBottom: 20 }}
      dataSource={[
        { title: 'Step1', name: 'step-1' },
        { title: 'Step2', name: 'step-2' },
        { title: 'Step3', name: 'step-3' }
      ]}
    />
    <FormCard name="step-1" title="Step1">
      <Field name="a1" required title="A1" type="string" />
    </FormCard>
    <FormCard name="step-2" title="Step2">
      <Field name="a2" required title="A2" type="string" />
    </FormCard>
    <FormCard name="step-3" title="Step3">
      <Field name="a3" required title="A3" type="string" />
    </FormCard>
    <FormButtonGroup>
      <Submit>Submit</Submit>
      <Button onClick={() => actions.dispatch(FormStep.ON_FORM_STEP_PREVIOUS)}>
        Prev
      </Button>
      <Button onClick={() => actions.dispatch(FormStep.ON_FORM_STEP_NEXT)}>
        Next
      </Button>
      <Button
        onClick={() => {
          cache = actions.getFormGraph()
        }}
      >
        Save State
      </Button>
      <Button
        onClick={() => {
          actions.setFormGraph(cache)
        }}
      >
        Rollback State
      </Button>
    </FormButtonGroup>
  </SchemaForm>
)

<FormLayout/>

Props of <FormLayout/>

interface IFormItemTopProps {
  inline?: boolean
  className?: string
  style?: React.CSSProperties
  labelCol?: number | { span: number; offset?: number }
  wrapperCol?: number | { span: number; offset?: number }
}

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import {
  SchemaForm,
  Field,
  FormButtonGroup,
  Submit,
  Reset,
  FormItemGrid,
  FormCard,
  FormBlock,
  FormLayout
} from '@uform/antd'
import { Button } from 'antd'
import Printer from '@uform/printer'
import'antd/dist/antd.css'
const App = () => (
  <Printer>
    <SchemaForm>
      <FormLayout labelCol={8} wrapperCol={6}>
        <Field name="aaa" type="string" title="field1" />
        <Field name="bbb" type="number" title="field2" />
        <Field name="ccc" type="date" title="field3" />
      </FormLayout>
      <FormButtonGroup offset={8}>
        <Submit>Submit</Submit>​ <Reset>Reset</Reset>​
      </FormButtonGroup>
    </SchemaForm>
  </Printer>
)
ReactDOM.render(<App />, document.getElementById('root'))

<FormItemGrid/>

Props of <FormItemGrid/>

interface IFormItemGridProps {
  cols?: Array<number | { span: number; offset: number }>
  gutter?: number
  /** next Form.Item props**/
  // prefix od FormItem
  prefix?: string

  // label od FormItem
  label?: React.ReactNode

  // label layout setting, eg, {span: 8, offset: 16}
  labelCol?: {}
  wrapperCol?: {}

  // Custom prompt information, if not set, it will be automatically generated according to the verification rules.
  help?: React.ReactNode

  // Additional prompt information, similar to help, can be used when error messages and prompt copy are required at the same time. Behind the error message.
  extra?: React.ReactNode

  // Check status, if not set, it will be generated automatically according to check rules
  validateState?: 'error' | 'success' | 'loading'

  // Used in conjunction with the validateState property, whether to display the success / loading validation status icon. Currently only Input supports
  hasFeedback?: boolean

  // Custom inline style

  style?: React.CSSProperties

  // node or function(values)
  children?: React.ReactNode | (() => void)

  // The size of a single Item is customized, and takes precedence over the size of the Form, and when a component is used with an Item, the component itself does not set the size property.
  size?: 'large' | 'small' | 'medium'

  // Position of the label
  labelAlign?: 'top' | 'left' | 'inset'

  // alignment of labels
  labelTextAlign?: 'left' | 'right'

  className?: string

  // [validation] required
  required?: boolean

  // whether required asterisks are displayed
  asterisk?: boolean

  // required custom error message
  requiredMessage?: string

  // required Custom trigger method
  requiredTrigger?: string | Array<any>

  // [validation] min
  min?: number

  // [validation] max
  max?: number

  // min/max error message
  minmaxMessage?: string

  // min/max custom trigger method
  minmaxTrigger?: string | Array<any>

  // [validation] min length of string / min length of array
  minLength?: number

  // [validation] max length of string / max length of array
  maxLength?: number

  // minLength/maxLength custom error message
  minmaxLengthMessage?: string

  // minLength/maxLength custom trigger method
  minmaxLengthTrigger?: string | Array<any>

  // [validation] length of string / length of array
  length?: number

  // length custom error message
  lengthMessage?: string

  // length custom trigger method
  lengthTrigger?: string | Array<any>

  // Regular pattern
  pattern?: any

  // pattern custom error message
  patternMessage?: string

  // pattern custom trigger method
  patternTrigger?: string | Array<any>

  // [validation] regular pattern
  format?: 'number' | 'email' | 'url' | 'tel'

  // format custom error message
  formatMessage?: string

  // format custom trigger method
  formatTrigger?: string | Array<any>

  // [validation] custom validator
  validator?: () => void

  // validator custom trigger method
  validatorTrigger?: string | Array<any>

  // Whether to automatically trigger validate when data is modified
  autoValidate?: boolean
}

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import {
  SchemaForm,
  Field,
  FormButtonGroup,
  Submit,
  Reset,
  FormItemGrid,
  FormCard,
  FormBlock,
  FormLayout
} from '@uform/antd'
import { Button } from 'antd'
import Printer from '@uform/printer'
import'antd/dist/antd.css'

const App = () => (
  <Printer>
    <SchemaForm onSubmit={v => console.log(v)}>
      <FormItemGrid gutter={20}>
        <Field type="string" name="a1" title="field1" />
        <Field type="string" name="a2" title="field2" />
        <Field type="string" name="a3" title="field3" />
        <Field type="string" name="a4" title="field4" />
      </FormItemGrid>
      <FormItemGrid gutter={20} cols={[6, 6]}>
        <Field type="string" name="a5" title="field5" />
        <Field type="string" name="a6" title="field6" />
      </FormItemGrid>
      <FormButtonGroup style={{ minWidth: 150 }}>
        ​<Submit>Submit</Submit>​<Reset>Reset</Reset>​
      </FormButtonGroup>
    </SchemaForm>
  </Printer>
)
ReactDOM.render(<App />, document.getElementById('root'))

<FormTextBox/>

Props of <FormTextBox/>

interface IFormTextBox {
  text?: string
  gutter?: number
  title?: React.ReactText
  description?: React.ReactText
}

Usage

import React, { useState } from 'react'
import ReactDOM from 'react-dom'
import {
  SchemaForm,
  Field,
  FormTextBox,
  FormCard,
  FormLayout
} from '@uform/antd'
import { Button } from 'antd'
import Printer from '@uform/printer'
import'antd/dist/antd.css'

const App = () => {
  return (
    <Printer>
      <SchemaForm labelCol={8} wrapperCol={6} onSubmit={v => console.log(v)}>
        <FormCard title="FormTextBox">
          <FormLayout labelCol={8} wrapperCol={16}>
            <FormTextBox
              title="text label"
              text="prefix%suffix prefix2%suffix2 prefix3%suffix3"
              gutter={8}
            >
              <Field
                type="string"
                default={10}
                required
                name="aa1"
                x-props={{ style: { width: 80 } }}
                description="desc1"
              />
              <Field
                type="number"
                default={20}
                required
                name="aa2"
                description="desc2"
              />
              <Field
                type="number"
                default={30}
                required
                name="aa3"
                description="desc3"
              />
            </FormTextBox>
          </FormLayout>
        </FormCard>
      </SchemaForm>
    </Printer>
  )
}
ReactDOM.render(<App />, document.getElementById('root'))

<FormButtonGroup/>

Props of <FormButtonGroup/>

interface IFormButtonGroupProps {
  sticky?: boolean
  style?: React.CSSProperties
  itemStyle?: React.CSSProperties
  className?: string
  align?: 'left' | 'right' | 'start' | 'end' | 'top' | 'bottom' | 'center'
  triggerDistance?: number
  zIndex?: number
  span?: ColSpanType
  offset?: ColSpanType
}

Usage

import React, { useState } from 'react'
import ReactDOM from 'react-dom'
import {
  SchemaForm,
  Field,
  FormButtonGroup,
  Submit,
  Reset,
  FormItemGrid,
  FormCard,
  FormBlock,
  FormLayout
} from '@uform/antd'
import { Button } from 'antd'
import Printer from '@uform/printer'
import'antd/dist/antd.css'

const App = () => {
  const [state, setState] = useState({ editable: true })
  return (
    <Printer>
      <SchemaForm onSubmit={v => console.log(v)}>
        <div>normal</div>
        <FormButtonGroup style={{ minWidth: 150 }}>
          ​<Submit>Submit</Submit>​<Reset>Reset</Reset>​
        </FormButtonGroup>
        <div>sticky</div>
        <FormButtonGroup offset={8} sticky>
          ​<Submit>Submit</Submit>​
          <Button
            type="primary"
            onClick={() => setState({ editable: !state.editable })}
          >
            {state.editable ? 'Preview' : 'Edit'}
          </Button>
          <Reset>Reset</Reset>​
        </FormButtonGroup>
      </SchemaForm>
    </Printer>
  )
}
ReactDOM.render(<App />, document.getElementById('root'))

<TextButton/>

Props of <TextButton/>, fully inherited from ButtonProps

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, { TextButton } from '@uform/antd'
import'antd/dist/antd.css'

const App = () => (
  <SchemaForm>
    <TextButton>content</TextButton>
  </SchemaForm>
)
ReactDOM.render(<App />, document.getElementById('root'))

<CircleButton/>

Props of <CircleButton/>, fully inherited from ButtonProps

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, { CircleButton } from '@uform/antd'
import'antd/dist/antd.css'

const App = () => (
  <SchemaForm>
    <CircleButton>ok</CircleButton>
  </SchemaForm>
)
ReactDOM.render(<App />, document.getElementById('root'))

Type of SchemaMarkupField

string

  • Schema Type : string
  • Schema UI Component: Fusion-Next <Input/>, <Input.Textarea/>, <Select/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="string"
        required
        title="Text"
        name="text"
        x-component-props={{
          placeholder: 'input'
        }}
      />
      <Field
        type="string"
        enum={['1', '2', '3', '4']}
        required
        title="Simple Select"
        name="simpleSelect"
        x-component-props={{
          placeholder: 'select'
        }}
      />
      <Field
        type="string"
        enum={[
          { label: 'One', value: '1' },
          { label: 'Two', value: '2' },
          { label: 'Three', value: '3' },
          { label: 'Four', value: '4' }
        ]}
        required
        title="Object Select"
        name="objSelect"
        x-component-props={{
          placeholder: 'select'
        }}
      />
      <Field
        type="string"
        title="TextArea"
        name="textarea"
        x-component="textarea"
        x-component-props={{
          placeholder: 'textarea'
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

textarea

  • Schema Type : string
  • Schema UI Component: Fusion-Next <Input.Textarea/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="string"
        title="TextArea"
        name="textarea"
        x-component="textarea"
        x-component-props={{
          placeholder: 'textarea'
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

password

  • Schema Type : password
  • Schema UI Component: Fusion-Next <Input htmlType="password"/>
interface IPasswordProps {
  checkStrength: boolean
  /** next input props **/
  // value
  value?: string | number

  // default value
  defaultValue?: string | number

  // callback triggered when value change
  onChange?: (value: string, e: React.ChangeEvent<HTMLInputElement>) => void

  // callback triggered when keyboard is press
  onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>, opts: {}) => void

  // Disabled
  disabled?: boolean

  // Max length
  maxLength?: number

  // Whether to show the maximum length style
  hasLimitHint?: boolean

  // When maxLength is set, whether to truncate beyond the string
  cutString?: boolean

  // readOnly
  readOnly?: boolean

  // Automatically remove the leading and trailing blank characters when trigger onChange
  trim?: boolean

  // placeholder
  placeholder?: string

  // callback triggered when focus
  onFocus?: () => void

  // callback triggered when blur
  onBlur?: () => void

  // Custom string length calculation
  getValueLength?: (value: string) => number

  className?: string
  style?: React.CSSProperties
  htmlType?: string

  // name of field
  name?: string

  // state of field
  state?: 'error' | 'loading' | 'success'

  // label
  label?: React.ReactNode

  // whether to show clear
  hasClear?: boolean

  // whether to show border
  hasBorder?: boolean

  // size of field
  size?: 'small' | 'medium' | 'large'

  // callback triggered when enter is press
  onPressEnter?: () => void

  // Watermark (Icon type, shared with hasClear)
  hint?: string

  // Append content before text
  innerBefore?: React.ReactNode

  // Append content after text
  innerAfter?: React.ReactNode

  // Append content before input
  addonBefore?: React.ReactNode

  // Append content after input
  addonAfter?: React.ReactNode

  // Append text before input
  addonTextBefore?: React.ReactNode

  // Append text after input
  addonTextAfter?: React.ReactNode

  // (Native supported by input)
  autoComplete?: string

  // (Native supported by input)
  autoFocus?: boolean
}

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="string"
        title="Password"
        name="password"
        x-component="password"
        x-component-props={{
          placeholder: 'password'
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

number

  • Schema Type : number
  • Schema UI Component: Fusion-Next <NumberPicker/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field type="number" required title="Number" name="number" />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

boolean

  • Schema Type : boolean
  • Schema UI Component: Fusion-Next <Switch/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="boolean"
        required
        title="Boolean"
        name="boolean"
        x-component-props={{
          checkedChildren: 'on',
          unCheckedChildren: 'off'
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

date

  • Schema Type : date
  • Schema UI Component: Fusion-Next <DatePicker/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="date"
        required
        title="DatePicker"
        name="datePicker"
        x-component-props={{
          format: 'YYYY-MM-DD HH:mm:ss'
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

time

  • Schema Type : time
  • Schema UI Component: Fusion-Next <TimePicker/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="time"
        required
        title="TimePicker"
        name="timePicker"
        x-component-props={{
          format: 'YYYY-MM-DD HH:mm:ss'
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

range

  • Schema Type : range
  • Schema UI Component: Fusion-Next <Range/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="range"
        required
        title="Range"
        name="range"
        x-component-props={{
          min: 0,
          max: 1024,
          marks: [0, 1024]
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

upload

  • Schema Type : upload
  • Schema UI Component: Fusion-Next <Upload/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="upload"
        required
        title="Card Upload"
        name="upload2"
        x-component-props={{
          listType: 'card'
        }}
      />
      <Field
        type="upload"
        required
        title="Dragger Upload"
        name="upload1"
        x-component-props={{
          listType: 'dragger'
        }}
      />
      <Field
        type="upload"
        required
        title="Text Upload"
        name="upload3"
        x-component-props={{
          listType: 'text'
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

checkbox

  • Schema Type : checkbox
  • Schema UI Component: Fusion-Next <Checkbox/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="checkbox"
        required
        title="Simple Checkbox"
        name="checkbox"
        enum={['1', '2', '3', '4']}
      />
      <Field
        type="checkbox"
        required
        title="Object Checkbox"
        name="checkbox2"
        enum={[
          { label: 'One', value: '1' },
          { label: 'Two', value: '2' },
          { label: 'Three', value: '3' },
          { label: 'Four', value: '4' }
        ]}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

radio

  • Schema Type : radio
  • Schema UI Component: Fusion-Next <Radio/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="radio"
        required
        title="Simple Radio"
        name="radio"
        enum={['1', '2', '3', '4']}
      />
      <Field
        type="radio"
        required
        title="Object Radio"
        name="radio2"
        enum={[
          { label: 'One', value: '1' },
          { label: 'Two', value: '2' },
          { label: 'Three', value: '3' },
          { label: 'Four', value: '4' }
        ]}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

rating

  • Schema Type : rating
  • Schema UI Component: Fusion-Next <Rating/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="rating"
        title="Rating"
        name="rating"
        x-component-props={{
          allowHalf: true
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

transfer

  • Schema Type : transfer
  • Schema UI Component: Fusion-Next <Transfer/>

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  createFormActions,
  FormBlock,
  FormLayout,
  FormButtonGroup,
  Submit,
  Reset
} from '@uform/antd'
import'antd/dist/antd.css'

const actions = createFormActions()
const App = () => {
  return (
    <SchemaForm actions={actions}>
      <Field
        type="transfer"
        title="Transfer"
        name="transfer"
        enum={[
          { title: 'One', key: '1' },
          { title: 'Two', key: '2' },
          { title: 'Three', key: '3' },
          { title: 'Four', key: '4' }
        ]}
        x-props={{
          render: (item) => item.title
        }}
        x-component-props={{
          showSearch: true
        }}
      />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

Hook

useFormEffects

Implement local effects by using useFormEffects. Same effect as the example of Linkage Note: The life cycle of the listener starts from ON_FORM_MOUNT

Signature

(effects: IFormEffect): void
import React from 'react'
import ReactDOM from 'react-dom'
import SchemaForm, {
  SchemaMarkupField as Field,
  VirtualField,
  createFormActions,
  useFormEffects,
  LifeCycleTypes,
  createVirtualBox
} from '@uform/antd'

const actions = createFormActions()

const FragmentContainer = createVirtualBox('ffb', (props) => {
  useFormEffects(($, { setFieldState }) => {
    $(LifeCycleTypes.ON_FORM_MOUNT).subscribe(() => {
      setFieldState('a~', state => state.visible = false)
    })

    $(LifeCycleTypes.ON_FIELD_VALUE_CHANGE, 'trigger').subscribe((triggerState) => {
      setFieldState('a~', state => {
        state.visible = triggerState.value
      })
    })

    $(LifeCycleTypes.ON_FIELD_VALUE_CHANGE, 'a').subscribe((fieldState) => {
      setFieldState('a-copy', state => {
        state.value = fieldState.value
      })
    })
  })

  return (
    <React.Fragment>
      {props.children}
    </React.Fragment>
  )
});

const FormFragment = () => {
  return <FragmentContainer>
    <Field
      type="radio"
      name="trigger"
      title="trigger"
      enum={[{ label: 'show', value: true }, { label: 'hide', value: false } ]}
    />
    <Field type="string" name="a" title="a" />
    <Field type="string" name="a-copy" title="a-copy" />   
  </FragmentContainer>   
}

const App = () => {
  return (
    <SchemaForm actions={actions}>
      <FormFragment />
    </SchemaForm>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

useFormState

使用 useFormState 为自定义组件提供FormState扩展和管理能力

签名

(defaultState: T): [state: IFormState, setFormState: (state?: IFormState) => void]

用法

import React, { useRef } from 'react'
import ReactDOM from 'react-dom'
import { Form, Field, VirtualField,
  createFormActions, createEffectHook,
  useForm,  
  useFormState,
  useFormEffects,
  useFieldState,
  LifeCycleTypes
} from '@uform/react'

const InputField = props => (
  <Field {...props}>
    {({ state, mutators }) => {
      const loading = state.props.loading
      return <React.Fragment>
        { props.label && <label>{props.label}</label> }
        { loading ? ' loading... ' : <input
          disabled={!state.editable}
          value={state.value || ''}
          onChange={mutators.change}
          onBlur={mutators.blur}
          onFocus={mutators.focus}
        /> }
        <span style={{ color: 'red' }}>{state.errors}</span>
        <span style={{ color: 'orange' }}>{state.warnings}</span>
      </React.Fragment>
    }}
  </Field>
)

const actions = createFormActions()
const FormFragment = (props) => {  
  const [formState, setFormState ] = useFormState({ extendVar: 0 })
  const { extendVar } = formState

  return <div>
    <button onClick={() => {
      setFormState({ extendVar: extendVar + 1 })
    }}>add</button>
    <div>count: {extendVar}</div>
  </div>
}

const App = () => {
  return (
    <Form actions={actions}>
      <FormFragment />
    </Form>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

useFieldState

Manage state of custom field by using useFieldState

Signature

(defaultState: T): [state: IFieldState, setFieldState: (state?: IFieldState) => void]
import React, { useRef } from 'react'
import ReactDOM from 'react-dom'
import { Form, Field, VirtualField,
  createFormActions, createEffectHook,
  useForm,  
  useFormEffects,
  useFieldState,
  LifeCycleTypes
} from '@uform/react'

const InputField = props => (
  <Field {...props}>
    {({ state, mutators }) => {
      const loading = state.props.loading
      return <React.Fragment>
        { props.label && <label>{props.label}</label> }
        { loading ? ' loading... ' : <input
          disabled={!state.editable}
          value={state.value || ''}
          onChange={mutators.change}
          onBlur={mutators.blur}
          onFocus={mutators.focus}
        /> }
        <span style={{ color: 'red' }}>{state.errors}</span>
        <span style={{ color: 'orange' }}>{state.warnings}</span>
      </React.Fragment>
    }}
  </Field>
)

const changeTab$ = createEffectHook('changeTab')
const actions = createFormActions()
const TabFragment = (props) => {  
  const [fieldState, setLocalFieldState ] = useFieldState({ current: 0 })
  const { current } = fieldState
  const { children, dataSource, form } = props
  const ref = useRef(current)

  const update = (cur) => {    
    form.notify('changeTab', cur)
    setLocalFieldState({
      current: cur
    })
  }

  useFormEffects(($, { setFieldState }) => {
    dataSource.forEach((item, itemIdx) => {
      setFieldState(item.name, state => {
        state.display = itemIdx === current
      })
    })

    changeTab$().subscribe((idx) => {
      dataSource.forEach((item, itemIdx) => {
      setFieldState(item.name, state => {
        state.display = itemIdx === idx
      })
    })
    })
  })

  ref.current = current
  const btns = dataSource.map((item, idx) => {
    console.log('current', current, ref.current)
    const focusStyle = idx === current ? { color: '#fff', background: 'blue' } : {}
    return <button style={focusStyle} onClick={() => {
      update(idx)
    }}>{item.label}</button>
  })

  return btns
}

const FormTab = (props) => {
  return <VirtualField name="layout_tab">
    {({ form }) => {
      return <TabFragment {...props} form={form} />
    }}
  </VirtualField>
}

const App = () => {
  return (
    <Form actions={actions}>
      <FormTab dataSource={[
        { label: 'tab-1', name: 'username' },
        { label: 'tab-2', name: 'age' }
      ]} />
      <div>
        <InputField name="username" label="username"/>
        <InputField name="age" label="age"/>
      </div>
    </Form>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

useForm

get IForm instance

Signature

type useForm = <
  Value = any,
  DefaultValue = any,
  EffectPayload = any,
  EffectAction = any
>(
  props: IFormProps<Value, DefaultValue, EffectPayload, EffectAction>
) => IForm

Usage

import { useForm } from '@uform/react'

const FormFragment = () => {
  const form = useForm()
  return <div>{form.getFieldValue('username')}</div>
}

useField

get IFieldHook instance

Signature

type useField = (options: IFieldStateUIProps): IFieldHook

Usage

import { useField } from '@uform/react'

const FormFragment = (props) => {
  const {
    form,
    state,
    props: fieldProps,
    mutators
  } = useField({ name: 'username' })
  
  return <input {...fieldProps} {...props} value={state.value} onChange={mutators.change} />
}

useVirtualField

get IVirtualFieldHook instance

Signature

type UseVirtualField = (options: IVirtualFieldStateProps): IVirtualFieldHook

Usage

import { UseVirtualField } from '@uform/react'

const FormFragment = (props) => {
  const {
    form,
    state,
    props: fieldProps,
  } = UseVirtualField({ name: 'username' })
  
  return <div style={{ width: fieldProps.width, height: fieldProps.height }}>
    {props.children}
  </div>
}

useFormSpy

get ISpyHook instance. Same effect as the first example of FormSpy.

Signature

type useFormSpy = (props: IFormSpyProps): ISpyHook

Usage

import { useFormSpy, LifeCycleTypes } from '@uform/react'
const FormFragment = (props) => {
  const {
    form,
    state,
    type,
  } = useFormSpy({
    selector: LifeCycleTypes.ON_FORM_VALUES_CHANGE,
    reducer: (state, action, form) => ({
      count: state.count ? state.count + 1 : 1
    })
  })
  
  return <div>
    <div>count: {state.count || 0}</div>
  </div>
}

API

Fully inherited from @uform/react, The specific API of @uform/antd is listed below.


createFormActions

Return IFormActions

Signature

createFormActions(): IFormActions

Usage

import { createFormActions } from '@uform/antd'

const actions = createFormActions()
console.log(actions.getFieldValue('username'))

createAsyncFormActions

Return IFormAsyncActions

Signature

createAsyncFormActions(): IFormAsyncActions

Usage

import { createAsyncFormActions } from '@uform/antd'

const actions = createAsyncFormActions()
actions.getFieldValue('username').then(val => console.log(val))

FormEffectHooks

Return all @uform/core lifeCycles hook which can be subscribe

Usage

import { FormEffectHooks, Form } from '@uform/react'
const {
  /**
   * Form LifeCycle
   **/
  // Form pre-initialization trigger
  onFormWillInit$,
  // Form initialization trigger
  onFormInit$,
  // Triggered when the form changes
  onFormChange$,
  // Triggered when the form event is triggered, used to monitor only manual operations
  onFormInputChange$,
  // Trigger when the form initial value changes
  onFormInitialValueChange$,
  // Triggered when the form is reset
  onFormReset$,
  // Triggered when the form is submitted
  onFormSubmit$,
  // Triggered when the form submission starts
  onFormSubmitStart$,
  // Triggered when the form submission ends
  onFormSubmitEnd$,
  // Triggered when the form is mounted
  onFormMount$,
  // Triggered when the form is unloaded
  onFormUnmount$,
  // Triggered when form validation begins
  onFormValidateStart$,
  // Triggered when the form validation ends
  onFormValidateEnd$,
  // Trigger when the form initial value changes
  onFormValuesChange$,
  /**
   * FormGraph LifeCycle
   **/
  // Triggered when the form observer tree changes
  onFormGraphChange$,
  /**
   * Field LifeCycle
   **/
  // Triggered when pre-initialized
  onFieldWillInit$,
  // Triggered when the field is initialized
  onFieldInit$,
  // Triggered when the field changes
  onFieldChange$,
  // Triggered when the field is mounted
  onFieldMount$,
  // Trigger when the field is unloaded
  onFieldUnmount$,
  // Triggered when the field event is triggered, used to monitor only manual operations
  onFieldInputChange$,
  // Triggered when the field value changes
  onFieldValueChange$,
  // Trigger when the initial value of the field changes
  onFieldInitialValueChange$
} = FormEffectHooks

const App = () => {
  return (
    <Form
      effects={() => {
        onFormInit$().subscribe(() => {
          console.log('initialized')
        })
      }}
    >
      ...
    </Form>
  )
}

createEffectHook

Custom your own hook by this api

Usage

import SchemaForm, { createEffectHook, createFormActions } from '@uform/antd'

const actions = createFormActions()
const diyHook1$ = createEffectHook('diy