@uform/next
v1.0.5
Published
### Install
Downloads
82
Keywords
Readme
@uform/next
Install
npm install --save @uform/next
Table Of Contents
- Quick-Start
- Components
- Form List
- Layout Components
- Type of SchemaMarkupField
- Hook
- API
- Interfaces
ISchema
IFormActions
IFormAsyncActions
ButtonProps
CardProps
ICompatItemProps
IFieldState
ISchemaFieldComponentProps
ISchemaVirtualFieldComponentProps
ISchemaFieldWrapper
ISchemaFieldComponent
ISchemaVirtualFieldComponent
ISchemaFormRegistry
InternalFormats
CustomValidator
ValidateDescription
ValidateArrayRules
ValidatePatternRules
INextSchemaFieldProps
IPreviewTextProps
IMutators
IFieldProps
IConnectOptions
ISpyHook
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/next'
import { Button } from '@alifd/next'
import '@alifd/next/dist/next.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, label: 'opt1' }, { value: 2, label: 'opt2' }]}
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/next'
import { Button } from '@alifd/next'
import '@alifd/next/dist/next.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: [
{
value: 1,
label: 'opt1'
},
{
value: 2,
label: 'opt2'
}
],
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 INextSchemaFormProps {
// 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'];
// label column settiing
labelCol?: number | { span: number; offset?: number }
// FormItem column settiing
wrapperCol?: number | { span: number; offset?: number }
// custom placeholder when preivew
previewPlaceholder?: string | ((props: IPreviewTextProps) => string);
// prefix
prefix?: string;
// is it inline
inline?: boolean;
// 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' | 'medium' | 'small';
// position of label
labelAlign?: 'top' | 'left' | 'inset';
// aligment of label
labelTextAlign?: 'left' | 'right';
// labelCol of FormItem
labelCol?: {};
// wrapperCol of FormItem
wrapperCol?: {};
children?: any;
className?: string;
style?: React.CSSProperties;
// type of component
component?: string | (() => void);
// 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/next'
const actions = createFormActions()
ReactDOM.render(
<SchemaForm actions={actions} effects={($)=>{
$('onFieldChange','a').subscribe((fieldState)=>{
actions.setFieldState('a-mirror',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/next'
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/next, 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/next'
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)
}
<Field/>
deprecated,please use SchemaMarkupField
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'))
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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import { Button } from '@alifd/next'
import '@alifd/next/dist/next.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/next'
import { Button } from '@alifd/next'
import Printer from '@uform/printer'
import '@alifd/next/dist/next.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/next'
import { Button } from '@alifd/next'
import Printer from '@uform/printer'
import '@alifd/next/dist/next.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/next'
import { Button } from '@alifd/next'
import Printer from '@uform/printer'
import '@alifd/next/dist/next.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/next'
import { Button } from '@alifd/next'
import Printer from '@uform/printer'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.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/next'
import '@alifd/next/dist/next.css'
const actions = createFormActions()
const App = () => {
return (
<SchemaForm actions={actions}>
<Field
type="transfer"
title="Transfer"
name="transfer"
enum={[
{ label: 'One', value: '1' },
{ label: 'Two', value: '2' },
{ label: 'Three', value: '3' },
{ label: 'Four', value: '4' }
]}
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/next'
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/next is listed below.
createFormActions
Return IFormActions
Signature
createFormActions(): IFormActions
Usage
import { createFormActions } from '@uform/next'
const actions = createFormActions()
console.log(actions.getFieldValue('username'))
createAsyncFormActions
Return IFormAsyncActions
Signature
createAsyncFormActions(): IFormAsyncActions
Usage
import { createAsyncFormActions } from '@uform/next'
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')
})
}}
>