@livelybone/form
Version:
A cross-framework form management library, realized validate, format, reset, submit
536 lines (493 loc) • 14.9 kB
TypeScript
import {
IsTuple,
TupleMap,
TupleToUnion,
UnionPop,
UnionToTupleWithMap,
} from 'union-tuple'
declare type ErrorText = string
/**
* 表示表单/表单项是否被修改,true - 未被修改过,false - 已被修改过
*
* Indicates whether the form or the form item has been modified.
* true - pristine
* false - modified
* */
declare type Pristine = boolean
/**
* 是否应该在表单项的值发生变化时调用校验函数
*
* Whether validator should be called at the time the value of form item changed
*
* Default: false
* */
declare type ValidateOnChange = boolean
/**
* 表示当前表单/表单项是否合法
*
* Indicates whether the form or the form item is valid.
* */
declare type Valid = boolean
interface FormItem<
ValueType extends any,
NameType extends string | number,
IdType extends string | number
> {
name: NameType
value: ValueType
/**
* 如果 id 没有定义,它的值将会被置为 name 的值
*
* If !!id === false, the value of id will be reset to the value of name
* */
id?: IdType | NameType
/**
* 当检验值为空的表单项时,errorText 需根据 label 生成
* 比如:`姓名不能为空`,`密码不能为空`
*
* When verifying a form item with an empty value, the errorText is generated based on the label
* e.g. `姓名不能为空`,`密码不能为空`
* */
label?: string
/**
* Default: true
* */
pristine?: Pristine
/**
* Default: true
* */
valid?: Valid
/**
* Default: ''
* */
errorText?: string
validateOnChange?: ValidateOnChange
/**
* Default: true
* */
required?: boolean
/**
* 用于动态计算表单项是否必填,优先级高于 required
*
* @params formDataAndOptions form.options.optionsForValidatorAndFormatter 与 form.data 的结合
*
*
* It is used to calculate the required property of the form item dynamically, with a priority higher than `required` key
*
* @options formDataAndOptions The combination of `form.options.optionsForValidatorAndFormatter` and `form.data`
*
* Default: undefined
* */
calcRequired?(formDataAndOptions: any): boolean
/**
* 这个表单项的校验函数
*
* @params formDataAndOptions form.options.optionsForValidatorAndFormatter 与 form.data 的结合
*
*
* Validate function of the form item
*
* @options formDataAndOptions The combination of `form.options.optionsForValidatorAndFormatter` and `form.data`
*
* Default: (val) => ''
* */
validator?(value: ValueType, formDataAndOptions: any): ErrorText
/**
* 格式化函数,每当值发生变化时触发
*
* @params formDataAndOptions form.options.optionsForValidatorAndFormatter 与 form.data 的结合
*
* Format the value when the value changes
*
* @options formDataAndOptions The combination of `form.options.optionsForValidatorAndFormatter` and `form.data`
*
* Default: val => val
* */
formatter?(value: ValueType, formDataAndOptions: any): ValueType
/**
* Other keys
* */
[key: string]: any
}
interface FullFormItem<
ValueType extends any,
NameType extends string | number,
IdType extends string | number
> extends FormItem<ValueType, NameType, IdType> {
readonly name: NameType
readonly id: NonNullable<IdType | NameType>
value: ValueType
pristine: Pristine
valid: Valid
errorText: ErrorText
validateOnChange: ValidateOnChange
required: boolean
}
interface FormOptions<DT extends {}, ST extends any> {
initialValues?: Partial<DT>
/**
* formValidate 方法的 validateAll 参数的默认值
*
* The default value of param validateAll of method formValidate
*
* Default: false
* */
validateAll?: boolean
validateOnChange?: ValidateOnChange
/**
* 当检验值为空的表单项时,errorText 的生成模板。`{label}` 为表单项 label 属性的占位符
*
* ErrorText's generated template when verifying a form item with an empty value. `{label}` is a placeholder of the label prop of the form item
*
* Default: `{label}不能为空`
* */
emptyErrorTemplate?: string
/**
* 提供一些参数,用于实现表单项的动态校验或者动态格式化
* 比如:不同币种金额的校验,币种的小数位可能会不一样,这时候我们可以提供一个 precision 参数,validator 函数可以从 options 拿到这个参数,从而做对应校验
*
* Provides parameters for dynamic validation of form items
* This is an application scenario:
* Where the number of decimal places in different currencies may be different with each other.
* In this case, we can provide a precision parameter, which the validator function can take from the options to do the validating
*
* Code Example:
*
* const formItems = {
* asset: {
* label: 'asset',
* name: 'asset',
* value: 'CNY',
* type: 'select',
* options: [
* { name: 'CNY', value: 'CNY', precision: '2' },
* { name: 'USD', value: 'USD', precision: '4' },
* ]
* },
* amount: {
* label: 'amount',
* name: 'amount',
* value: '',
* validator: (val, { precision }) => {
* if (precision <= 0) {
* return /^\d+$/.test(val) && +val % 10 ** -precision === 0
* ? ''
* : 'Please input the correct amount'
* }
* const reg = new RegExp(`^(0|[1-9]\\d*)(\\.\\d{1,${precision}})?$`)
* return reg.test(val) ? '' : 'Please input the correct amount'
* }
* }
* }
*
* const form = new Form(
* [
* formItems.asset,
* formItems.amount,
* ],
* {
* optionsForValidatorAndFormatter: { precision: 2 }
* },
* )
*
* // When the asset change to USD, you can update the options
* form.itemChange('asset', 'USD')
* form.updateOptions({ optionsForValidatorAndFormatter: { precision: 4 } })
* */
optionsForValidatorAndFormatter?: {
[key: string]: any
[key: number]: any
}
/**
* Called in Form.prototype.submit
* */
onSubmit?(data: DT): PromiseLike<ST>
/**
* 目标组件更新的方法,比如 React 组件的 forceUpdate 方法和 Vue 组件的 $forceUpdate 方法
*
* The update method of the component which used the library, e.g: forceUpdate of React, $forceUpdate of Vue
* */
componentUpdateFn?(): void
}
interface FullFormOptions<DT extends {}, ST extends any>
extends FormOptions<DT, ST> {
initialValues: DT
validateAll: boolean
validateOnChange: ValidateOnChange
emptyErrorTemplate: string
}
declare type FormProp<T, K extends string, FallbackType = any> = T extends {
[k in K]: infer E
}[]
? unknown extends E
? FallbackType
: E
: FallbackType
declare type FormName<FormItems extends FormItem<any, any, any>[]> = FormProp<
FormItems,
'name',
string | number
>
declare type FormValue<FormItems extends FormItem<any, any, any>[]> = FormProp<
FormItems,
'value',
any
>
declare type FormId<FormItems extends FormItem<any, any, any>[]> = FormProp<
FormItems,
'id',
string | number
>
declare type R<FormItemUnion, Result extends {} = {}> = {
1: Result
0: R<
Exclude<FormItemUnion, UnionPop<FormItemUnion>>,
Result &
(UnionPop<FormItemUnion> extends {
name: infer Name
value: infer Value
}
? Name extends string | number
? {
[k in Name]: Value
}
: any
: any)
> extends infer R
? R
: {}
}[[FormItemUnion] extends [never] ? 1 : 0]
declare type FormItemsData<
FormItems extends FormItem<any, string | number, string | number>[]
> = (IsTuple<FormItems> extends true
? R<TupleToUnion<FormItems>>
: R<FormItems[0]>) extends infer E
? unknown extends E
? any
: E
: any
/**
* 是否要更新组件
*
* Whether should update the component
*
* Default: true
* */
declare type ShouldUpdateComponent = boolean
declare type Item<FormItems extends any[]> = {
[index in Extract<keyof FormItems, number>]: FormItems[index] &
FullFormItem<
FormItems[index]['value'],
FormItems[index]['name'],
FormItems[index]['id'] | FormItems[index]['name']
>
}[Extract<keyof FormItems, number>]
declare class Form<
FormItems extends FormItem<any, any, any>[],
ReturnTypeOfSubmit extends any = FormItemsData<FormItems>
> {
/**
* @desc 表单项数组
*
* @desc Array of form items
* */
items: Item<FormItems>[]
$errorText: ErrorText
readonly options: Required<
FullFormOptions<FormItemsData<FormItems>, ReturnTypeOfSubmit>
>
constructor(
formItems: FormItems,
options?: FormOptions<FormItemsData<FormItems>, ReturnTypeOfSubmit>,
)
/**
* @desc 当前表单数据,由表单项数组生成
*
* @desc Data of the form, generated by form items
* */
data: FormItemsData<FormItems>
get pristine(): Pristine
get valid(): Valid
/**
* @desc 当前表单应该显示的错误信息
*
* @desc The current errorText of the form
* */
get errorText(): ErrorText
set errorText(errorText: ErrorText)
getItemByName(name: FormName<FormItems>): Item<FormItems> | undefined
getItemById(
id: FormId<FormItems> | FormName<FormItems>,
): Item<FormItems> | undefined
/**
* @desc 更新与参数 name 对应的表单项的值
*
* @desc Update the value of the form item that matched the param `name`
* */
itemChange(
name: FormName<FormItems>,
value: FormValue<FormItems>,
shouldUpdateComp?: ShouldUpdateComponent,
): void
/**
* @desc 批量更新与表单项的值
*
* @desc Batch updates with the values of form items
* */
itemsChange(
values: Partial<FormItemsData<FormItems>>,
shouldUpdateComp?: ShouldUpdateComponent,
): void
/**
* @desc 校验与参数 name 对应的表单项
*
* @desc Validate the value of the form item that matched the param `name`
* */
itemValidate(
name: FormName<FormItems>,
updatePristine?: boolean,
shouldUpdateComp?: ShouldUpdateComponent,
): ErrorText
/**
* @desc 从外部更新表单项的校验结果,这个可以用于异步校验
*
* @desc Update the validate result outside, it is useful for async validate
* */
updateValidateResult(
results: {
[key in FormName<FormItems>]: ErrorText
},
shouldUpdateComp?: ShouldUpdateComponent,
): void
/**
* @desc 校验整个表单
* @params validateAll 是否校验所有表单项
* true - 校验所有表单项
* false - 当遇到第一个校验错误的表单项时,停止对其他表单项的校验
*
* 默认值: this.options.validateAll
*
* @desc Form validate
* @params validateAll Whether validate all the form item in the form
* true - validate all
* false - stop validate other form items when the first form item with a validation error is encountered
*
* Default: this.options.validateAll
*
* @return ErrorText
* */
formValidate(
validateAll?: boolean,
shouldUpdateComp?: ShouldUpdateComponent,
): ErrorText
/**
* @desc 在提交之前会先做一次表单校验(运行 formValidate)
*
* @desc Method formValidate will be called before run the onSubmit function in this method
* */
submit(shouldUpdateComp?: ShouldUpdateComponent): Promise<ReturnTypeOfSubmit>
/**
* @desc 重置表单。会更新表单的初始值,如果不想更新初始值,请使用 itemsChange
*
* @desc Reset form. The initialValues of the form will be update. If you do not want to update the initialValues, use itemsChange
*
* @params values Default: this.options.initialValues
* */
reset(
values?: Partial<FormItemsData<FormItems>>,
shouldUpdateComp?: ShouldUpdateComponent,
): void
/**
* @desc 用参数 value 的值重置与参数 name 对应的表单项。会更新表单项的初始值
*
* @desc Reset form item that matched the param name with the param value. The initial value of the form item will be update
*
* @params name
* @params value Default: this.options.initialValues[name]
* */
resetItem(
name: FormName<FormItems>,
value?: FormValue<FormItems>,
shouldUpdateComp?: ShouldUpdateComponent,
): void
/**
* @desc 清除表单/表单项的校验结果
*
* @desc Clear the validate result of the form or the form item that matched the param name
*
* @params [name] If `!!name === true`, it will clear the validate result of the form item that matched the param name
* else, if will clear the validate result of the form
* */
clearValidateResult(
name?: FormName<FormItems>,
shouldUpdateComp?: ShouldUpdateComponent,
): void
private $updateOptions
/**
* 应在 this.options.optionsForValidatorAndFormatter 或者 this.data 发生变化时更新 required 值
*
* The required value of form item should be updated after the `this.options.optionsForValidatorAndFormatter` and `this.data` changed
* */
updateItemsRequired(): void
updateOptions(
options: FormOptions<FormItemsData<FormItems>, ReturnTypeOfSubmit>,
): void
}
declare type InfiniteItems<
FormItems extends {
[id: string]: FormItem<any, any, any>
},
Ids extends any[]
> = {
[id in TupleToUnion<Ids>]: FormItemsManager<FormItems>['allItems'][id]
}[TupleToUnion<Ids>][]
declare type GetFormItems<
FormItems extends {
[id: string]: FormItem<any, any, any>
},
Ids extends any[]
> = (IsTuple<Ids> extends true
? TupleMap<Ids, FormItemsManager<FormItems>['allItems']>
: UnionToTupleWithMap<
Ids[0],
FormItemsManager<FormItems>['allItems']
>) extends infer E
? unknown extends E
? InfiniteItems<FormItems, Ids>
: E
: InfiniteItems<FormItems, Ids>
declare class FormItemsManager<
FormItems extends {
[id: string]: FormItem<any, any, any>
}
> {
readonly allItems: {
[id in Exclude<keyof FormItems, symbol>]: FormItems[id] &
FormItem<FormItems[id]['value'], FormItems[id]['name'], id>
}
constructor(formItems: FormItems)
getItem<Id extends keyof FormItemsManager<FormItems>['allItems']>(
id: Id,
): FormItemsManager<FormItems>['allItems'][Id]
getItems<Ids extends (keyof FormItemsManager<FormItems>['allItems'])[]>(
ids: Ids,
): GetFormItems<FormItems, Ids>
}
export {
ErrorText,
Form,
FormId,
FormItem,
FormItemsData,
FormItemsManager,
FormName,
FormOptions,
FormProp,
FormValue,
FullFormItem,
FullFormOptions,
Pristine,
ShouldUpdateComponent,
Valid,
ValidateOnChange,
}