Skip to content

Commit

Permalink
feat: add docs and some test cases (#395)
Browse files Browse the repository at this point in the history
  • Loading branch information
janryWang authored Nov 14, 2019
1 parent fa7bae7 commit ecff8ef
Show file tree
Hide file tree
Showing 11 changed files with 2,218 additions and 58 deletions.
1,108 changes: 1,087 additions & 21 deletions packages/core/README.md

Large diffs are not rendered by default.

929 changes: 929 additions & 0 deletions packages/core/README.zh-cn.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ Object {
undefined,
],
"visible": true,
"visited": true,
"visited": false,
"warnings": Array [],
},
}
Expand Down
164 changes: 155 additions & 9 deletions packages/core/src/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { isEqual } from '@uform/shared'
import { createForm, LifeCycleTypes, FormLifeCycle, FormPath } from '../index'
import {
createForm,
LifeCycleTypes,
FormLifeCycle,
FormPath,
registerValidationFormats,
registerValidationRules,
registerValidationMTEngine
} from '../index'
import { ValidateDescription, ValidatePatternRules } from '@uform/validator'

// mock datasource
Expand Down Expand Up @@ -595,14 +603,14 @@ describe('setFormState', () => {
form.setFormState(state => {
state.values = { a: '1234' }
})
expect(form.getFormState((state) => state.values)).toEqual({ a: '1234' })
expect(form.getFormState(state => state.values)).toEqual({ a: '1234' })
expect(fieldChange).toBeCalledTimes(2)
expect(formChange).toBeCalledTimes(2)

form.setFormState((state) => state.values = { a: '5678' }, true)
expect(form.getFormState((state) => state.values)).toEqual({ a: '5678' })
form.setFormState(state => (state.values = { a: '5678' }), true)
expect(form.getFormState(state => state.values)).toEqual({ a: '5678' })
expect(formChange).toBeCalledTimes(2)
expect(fieldChange).toBeCalledTimes(2)
expect(fieldChange).toBeCalledTimes(2)
})
})

Expand Down Expand Up @@ -650,18 +658,18 @@ describe('setFieldState', () => {
const fieldChange = jest.fn()
const form = createForm({
lifecycles: [
new FormLifeCycle(LifeCycleTypes.ON_FIELD_CHANGE, fieldChange),
new FormLifeCycle(LifeCycleTypes.ON_FIELD_CHANGE, fieldChange)
]
})
form.registerField({ path: 'a' })
form.getFieldState('a')
form.getFieldState('a')
form.setFieldState('a', state => (state.value = '1234'))
expect(form.getFieldState('a', state => state.value)).toEqual('1234')
expect(fieldChange).toBeCalledTimes(2)

form.setFieldState('a', state => (state.value = '5678'), true)
expect(form.getFieldState('a', state => state.value)).toEqual('5678')
expect(fieldChange).toBeCalledTimes(2)
expect(fieldChange).toBeCalledTimes(2)
})

test('validating and loading', () => {
Expand Down Expand Up @@ -1089,6 +1097,16 @@ describe('createMutators', () => {
}))
).toEqual({
active: true,
visited: false
})
mutators.blur()
expect(
form.getFieldState('a', state => ({
active: state.active,
visited: state.visited
}))
).toEqual({
active: false,
visited: true
})
})
Expand Down Expand Up @@ -1300,7 +1318,10 @@ describe('major sences', () => {
test('dynamic remove with intialValues', async () => {
const form = createForm({
initialValues: {
aa: [{ aa: 123, bb: 321 }, { aa: 345, bb: 678 }]
aa: [
{ aa: 123, bb: 321 },
{ aa: 345, bb: 678 }
]
}
})
const aa = form.registerField({ path: 'aa' })
Expand Down Expand Up @@ -1398,3 +1419,128 @@ describe('major sences', () => {
expect(form.getFormGraph()).toMatchSnapshot()
})
})

describe('validator', () => {
test('registerValidationFormats', async () => {
registerValidationFormats({
number: /^[+-]?\d+(\.\d+)?$/
})

const form = createForm({
values: {},
initialValues: {},
onChange: values => {
// console.log(values)
}
})

const aa = form.registerField({
path: 'aa',
rules: [
{
format: 'number',
message: 'This field is not a number.'
}
]
})

aa.setState(state => {
state.value = 'hello world'
})
await form.validate()

form.getFormState(state =>
expect(state.errors).toEqual([
{
path: 'aa',
messages: ['This field is not a number.']
}
])
)
})

test('registerValidationRules', async () => {
registerValidationRules({
custom: value => {
return value === '123' ? 'This field can not be 123' : ''
}
})

const form = createForm({
values: {},
initialValues: {},
onChange: values => {
// console.log(values)
}
})

const aa = form.registerField({
path: 'aa',
rules: [
{
custom: true
}
]
})

aa.setState(state => {
state.value = '123'
})
await form.validate()

form.getFormState(state =>
expect(state.errors).toEqual([
{
path: 'aa',
messages: ['This field can not be 123']
}
])
)
})

test('registerValidationMTEngine', async () => {
registerValidationMTEngine((message, context) => {
return message.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, $0) => {
return FormPath.getIn(context, $0)
})
})

const form = createForm({
values: {},
initialValues: {},
onChange: values => {
// console.log(values)
}
})

const aa = form.registerField({
path: 'aa',
rules: [
{
validator(value) {
return value === 123
? 'This field can not be 123 {{scope.outerVariable}}'
: ''
},
scope: {
outerVariable: 'addonAfter'
}
}
]
})

aa.setState(state => {
state.value = 123
})
await form.validate()

form.getFormState(state =>
expect(state.errors).toEqual([
{
path: 'aa',
messages: ['This field can not be 123 addonAfter']
}
])
)
})
})
7 changes: 4 additions & 3 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {
import {
FormValidator,
setValidationLanguage,
setValidationLocale
setValidationLocale,
ValidateFieldOptions
} from '@uform/validator'
import { FormHeart } from './shared/lifecycle'
import { FormGraph } from './shared/graph'
Expand Down Expand Up @@ -545,12 +546,12 @@ export function createForm<FieldProps, VirtualFieldProps>(
focus() {
field.setState((state: IFieldState<FieldProps>) => {
state.active = true
state.visited = true
})
},
blur() {
field.setState((state: IFieldState<FieldProps>) => {
state.active = false
state.visited = true
})
},
push(value?: any) {
Expand Down Expand Up @@ -752,7 +753,7 @@ export function createForm<FieldProps, VirtualFieldProps>(

async function validate(
path?: FormPathPattern,
opts?: {}
opts?: ValidateFieldOptions
): Promise<IFormValidateResult> {
if (!state.getState(state => state.validating)) {
state.unsafe_setSourceState(state => {
Expand Down
14 changes: 10 additions & 4 deletions packages/core/src/shared/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ import {
FormPathPattern
} from '@uform/shared'
import produce, { Draft } from 'immer'
import { IStateModelFactory, StateDirtyMap, IModel, StateModel } from '../types'
import {
IStateModelProvider,
IStateModelFactory,
StateDirtyMap,
IModel,
StateModel
} from '../types'
const hasProxy = !!globalThisPolyfill.Proxy

export const createStateModel = <State = {}, Props = {}>(
Factory: IStateModelFactory<State, Props>
) => {
return class Model<DefaultProps> extends Subscribable<State>
): IStateModelProvider<State, Props> => {
return class Model<DefaultProps = any> extends Subscribable<State>
implements IModel<State, Props & DefaultProps> {
public state: State & { displayName?: string }
public props: Props &
Expand Down Expand Up @@ -218,5 +224,5 @@ export const createStateModel = <State = {}, Props = {}>(
)
: !isEqual(this.prevState, this.state)
}
}
} as any
}
10 changes: 6 additions & 4 deletions packages/core/src/state/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@ export const FormState = createStateModel<IFormState, IFormStateProps>(
} else {
draft.pristine = false
}
if (draft.validating === true) {
draft.loading = true
} else if (draft.validating === false) {
draft.loading = false
if (draft.validating !== prevState.validating) {
if (draft.validating === true) {
draft.loading = true
} else if (draft.validating === false) {
draft.loading = false
}
}
if (draft.mounted === true && draft.mounted !== prevState.mounted) {
draft.unmounted = false
Expand Down
30 changes: 19 additions & 11 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { FormPath, FormPathPattern, isFn, Subscribable } from '@uform/shared'
import { ValidatePatternRules, ValidateNodeResult } from '@uform/validator'
import {
ValidatePatternRules,
ValidateNodeResult,
ValidateFieldOptions
} from '@uform/validator'
import { FormLifeCycle } from './shared/lifecycle'
import { Draft } from 'immer'

Expand Down Expand Up @@ -105,6 +109,10 @@ export interface IStateModelFactory<S, P> {
displayName?: string
}

export interface IStateModelProvider<S, P> {
new (props: P): IModel<S, P>
}

export interface IFieldState<FieldProps = any> {
displayName?: string
name: string
Expand Down Expand Up @@ -155,7 +163,6 @@ export interface IFieldStateProps<FieldProps = any> {
editable?: boolean
useDirty?: boolean
computeState?: (draft: IFieldState, prevState: IFieldState) => void
onChange?: (fieldState: IField) => void
}

export const isField = (target: any): target is IField =>
Expand Down Expand Up @@ -208,13 +215,12 @@ export interface IFormStateProps {
initialValues?: {}
values?: {}
lifecycles?: FormLifeCycle[]
useDirty?: boolean
editable?: boolean | ((name: string) => boolean)
validateFirst?: boolean
}

export interface IFormCreatorOptions extends IFormStateProps {
useDirty?: boolean
validateFirst?: boolean
editable?: boolean
onChange?: (values: IFormState['values']) => void
onSubmit?: (values: IFormState['values']) => any | Promise<any>
onReset?: () => void
Expand Down Expand Up @@ -245,7 +251,6 @@ export interface IVirtualFieldStateProps<FieldProps = any> {
) => void
name?: string
props?: FieldProps
onChange?: (fieldState: IVirtualField) => void
}

export type IFormValidateResult = ValidateNodeResult
Expand Down Expand Up @@ -275,9 +280,9 @@ export interface IMutators {
remove(index: number | string): any
unshift(value: any): any[]
shift(): any[]
move($from: number, $to: number): any
moveDown(index: number): any
moveUp(index: number): any
move($from: number, $to: number): any[]
moveDown(index: number): any[]
moveUp(index: number): any[]
validate(): Promise<IFormValidateResult>
exist(index?: number | string): boolean
}
Expand All @@ -297,7 +302,7 @@ export interface IModel<S = {}, P = {}> extends Subscribable {
setState: (callback?: (state: S | Draft<S>) => void, silent?: boolean) => void
unsafe_getSourceState: (callback?: (state: S) => any) => any
unsafe_setSourceState: (callback?: (state: S) => void) => void
hasChanged: (key?: string) => boolean
hasChanged: (path?: FormPathPattern) => boolean
isDirty: (key?: string) => boolean
getDirtyInfo: () => StateDirtyMap<S>
}
Expand All @@ -315,7 +320,10 @@ export interface IForm {
clearErrors: (pattern?: FormPathPattern) => void
hasChanged(target: any, path: FormPathPattern): boolean
reset(options?: IFormResetOptions): Promise<void | IFormValidateResult>
validate(path?: FormPathPattern, options?: {}): Promise<IFormValidateResult>
validate(
path?: FormPathPattern,
options?: ValidateFieldOptions
): Promise<IFormValidateResult>
setFormState(callback?: (state: IFormState) => any, silent?: boolean): void
getFormState(callback?: (state: IFormState) => any): any
setFieldState(
Expand Down
Loading

0 comments on commit ecff8ef

Please sign in to comment.