表单类型#
#类型方法
src/common/interface.ts
export type MObject<T> = {
[K in keyof T]: T[K];
};
export type MakeFieldRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;#实例
src/common/instance/index.ts
import { MObject } from '../interface';
import { RuleItem, ValidateFieldsError, Values } from 'async-validator';
import { FairysValtioFormAttrsProps } from '../../form/form';
/**表单实例*/
export declare class FairysValtioFormInstance<T extends MObject<T> = Record<string, any>> {
/**
* 表单值改变时回调
* @param path 表单项路径
* @param value 表单项值
*/
onValuesChange?: (path: PropertyKey, value: any) => void;
/***
* 判断值是否为代理对象
* @param value 值
* @returns 是否为代理对象
*/
isValtioProxy: (value: any) => boolean;
/**状态*/
state: T;
/**
* 错误信息
*/
errorState: Record<PropertyKey, string[]>;
/**隐藏状态*/
hideState: Record<PropertyKey, boolean>;
/**初始化表单值*/
ctor: (options?: {
formData?: Partial<T>;
hideState?: Record<PropertyKey, boolean>;
initFormDataType?: FairysValtioFormAttrsProps["initFormDataType"];
}) => void;
/**
* 更新数据
* @param state 更新数据对象
* @param isValidate 是否验证(可选)
*/
updated: <M = T>(state: Partial<M>, isValidate?: boolean) => void;
/**根据路径设置值
* @param path 值路径
* @param value 值
*/
updatedValueByPaths: (path: PropertyKey, value: any) => void;
/**表单项卸载移除保存值*/
removeValueByPaths: (path: PropertyKey) => void;
/**
* 清理值
*/
clearValue: (fields?: PropertyKey[]) => this;
/**
* 更新行数据的隐藏信息
* @param objectHideInfo 行数据隐藏信息对象
*/
updatedHideInfo: (objectHideInfo: Record<PropertyKey, boolean>) => this;
/**
* 清理隐藏信息
*/
clearHideInfo: (fields?: PropertyKey[]) => this;
/**
* 更新行数据的错误信息
* @param objectErrorInfo 行数据错误信息对象
*/
updatedErrorInfo: (objectErrorInfo: Record<PropertyKey, string[]>) => this;
/**
* 清理错误信息
*/
clearErrorInfo: (fields?: PropertyKey[]) => this;
/**
* 清理所有数据
*/
clear: () => void;
/**由表单项挂载规则,(根据表单项的字段存储路径对应校验规则)*/
mountRules: Record<PropertyKey, RuleItem[]>;
/**移除表单项挂载规则*/
removeRules: (name: PropertyKey) => void;
/**表单项规则*/
rules: Record<PropertyKey, RuleItem[]>;
/**表单项名称到路径映射*/
nameToPaths: Record<PropertyKey, PropertyKey[]>;
/**验证表单项规则
* @param fields 要验证的字段(可选)
* @param isReturn 是否返回验证结果(可选)
*/
validate: (fields?: PropertyKey[], isReturn?: boolean) => Promise<ValidateFieldsError | Values | Partial<T>>;
/**
* 验证某些前缀的字段
* @param prefix 前缀字段数组
* @param isReturn 是否返回验证结果(可选)
*/
validatePrefixFields: (prefix: string[], isReturn?: boolean) => Promise<ValidateFieldsError | Values>;
}
声明实例
/**声明实例*/
export declare function useFairysValtioFormInstance<T extends MObject<T> = Record<string, any>>(instance?: FairysValtioFormInstance<T>): FairysValtioFormInstance<T>;表单实例上下文
/**表单实例上下文*/
export declare const FairysValtioFormInstanceContext: import("react").Context<FairysValtioFormInstance<any>>;获取表单实例上下文
/**获取表单实例上下文*/
export declare function useFairysValtioFormInstanceContext<T extends MObject<T> = Record<string, any>>(): FairysValtioFormInstance<T>;状态取值
/**状态取值*/
export declare function useFairysValtioFormInstanceContextState<T extends MObject<T> = Record<string, any>>(): [T, Record<PropertyKey, string[]>, FairysValtioFormInstance<T>, any, any];隐藏组件状态取值
/**隐藏组件状态取值*/
export declare function useFairysValtioFormInstanceContextHideState<T extends MObject<T> = Record<string, any>>(): [Record<PropertyKey, boolean>, FairysValtioFormInstance<T>, any];传递表单实例获取状态
/**
* 传递表单实例获取状态
*/
export declare function useFairysValtioFormInstanceToState<T extends MObject<T> = Record<string, any>>(formInstance: FairysValtioFormInstance<T>): T;传递表单实例获取隐藏状态
/**
* 传递表单实例获取隐藏状态
*/
export declare function useFairysValtioFormInstanceToHideState<T extends MObject<T> = Record<string, any>>(formInstance: FairysValtioFormInstance<T>): Record<PropertyKey, boolean>;
#获取父级表单项name属性值
src/common/hooks/index.ts
export interface FairysValtioFormParentAttrsState {
name?: string;
}
/***
* 父级属性
*/
export declare class FairysValtioFormParentAttrs {
state: FairysValtioFormParentAttrsState;
updated: (attrs: Record<string, any>) => void;
/***更新父级字段值*/
updatedName: (name?: string, parentName?: string) => void;
}
export interface FairysValtioFormAttrsNameOptions {
name?: string;
/**是否拼接父级字段名*/
isJoinParentField?: boolean;
}初始化父级属性**
/**初始化父级属性*/
export declare const useFairysValtioFormParentAttrs: (instance?: FairysValtioFormParentAttrs) => FairysValtioFormParentAttrs;父级属性上下文
/***父级属性上下文*/
export declare const FairysValtioFormParentAttrsContext: import("react").Context<FairysValtioFormParentAttrs>;获取父级属性实例
/**获取父级属性实例*/
export declare const useFairysValtioFormParentAttrsContext: () => FairysValtioFormParentAttrs;获取父级属性状态
/**获取父级属性状态*/
export declare const useFairysValtioFormParentAttrsState: () => readonly [{
readonly name?: string;
}, FairysValtioFormParentAttrs];
获取属性名和路径
/**获取属性名和路径*/
export declare const useFairysValtioFormAttrsName: (options?: FairysValtioFormAttrsNameOptions) => {
formAttrsNameInstance: FairysValtioFormParentAttrs;
parentName: string;
name: string;
paths: (number | symbol)[] | (string | number)[];
};#useId
src/common/hooks/index.ts
export declare const useId: (suffix?: string) => string;#form
src/form/form.tsx
import { MObject } from '../common/interface';
import { FairysValtioFormInstance } from '../common/instance';
import { type ReactNode } from 'react';
import { FairysValtioFormLayoutAttrsProps } from './layout';
import { RuleItem } from 'async-validator';
export interface FairysValtioFormAttrsProps<T extends MObject<T> = Record<string, any>> extends FairysValtioFormLayoutAttrsProps {
/**表单实例*/
form?: FairysValtioFormInstance<T>;
/**子元素*/
children: ReactNode;
/**表单项规则(如果表单项没有指定规则,则使用全局规则,如果表单项指定规则,则使用表单项规则)*/
rules?: Record<PropertyKey, RuleItem[]>;
/**表单初始值*/
formData?: FairysValtioFormInstance<T>['state'];
/**表单隐藏状态*/
hideState?: FairysValtioFormInstance<T>['hideState'];
/**
* 初始化表单数据类型,默认值为 deepCopy
* - deepCopy:使用深度拷贝初始化表单数据
* - immutable:直接使用对象(注意:当传递的不是`valtio`的`proxy`对象时,会使用`valtio`中的`proxy`声明)
*/
initFormDataType?: 'deepCopy' | 'immutable';
/**
* 表单值改变时回调
* @param path 表单项路径
* @param value 表单项值
*/
onValuesChange?: (path: PropertyKey, value: any) => void;
}
/**
* 表单属性处理
*
* @example
*
* ```tsx
import { useFairysValtioForm } from "@fairys/valtio-form"
import type { FairysValtioFormAttrProps } from "@fairys/valtio-form"
export interface FormProps extends FairysValtioFormAttrProps{}
export const Form = (props: FormProps) => {
const { formInstance,children, ...rest } = useFairysValtioForm(props)
return (
<FairysValtioFormInstanceContext.Provider value={formInstance}>
<布局组件 {...rest}>{children}</布局组件>
</FairysValtioFormInstanceContext.Provider>
);
}
* ```
*/
export declare function useFairysValtioForm<T extends MObject<T> = Record<string, any>>(props: FairysValtioFormAttrsProps<T>, ref: React.Ref<FairysValtioFormInstance<T>>): Omit<FairysValtioFormAttrsProps<T>, "initFormDataType" | "form" | "rules" | "formData" | "hideState" | "onValuesChange"> & {
formInstance: FairysValtioFormInstance<T>;
};
#formItem
src/form/form.item.tsx
/**表单项*/
import { MObject } from '../common/interface';
import React from 'react';
import { FairysValtioFormInstance } from '../common/instance';
import { FairysValtioFormLayoutContextOptions } from './layout';
import { FairysValtioFormParentAttrs } from '../common/hooks';
import { RuleItem } from 'async-validator';
export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = Record<string, any>> {
/**平台*/
platform?: 'pc' | 'rn' | 'taro';
/**
* 表单项名称 ,字段需要和存储的字段路径一致
*
* @example
* 路径中的值为 number 类型时,会创建一个空数组。路径中的值为 string 类型时,会创建一个空对象。最后一个直接赋值
*
* 默认:"name"
* 嵌套字段:"name.a.doc" ===> { name: { a: { doc: undefined } } }
* 嵌套字段:"name[1].a.doc" ===> { name: [{}, { a: { doc: undefined } }] }
* 嵌套字段:"name.a[2].doc" ===> { name: { a: [{}, {}, { doc: undefined }] } }
*/
name?: string;
/**表单项标签*/
label?: string;
/**传递组件字段*/
valuePropName?: string;
/**取值字段(默认 valuePropName字段值)*/
getValuePath?: string;
/**自定义获取值*/
getValueFromEvent?: (event: any, form: FairysValtioFormInstance<T>) => any;
/**值格式化*/
formatValue?: (value: any, form: FairysValtioFormInstance<T>, event: any) => any;
/**触发数据更新之后触发(用于数据联动之类的)*/
onAfterUpdate?: (value: any, form: FairysValtioFormInstance<T>, event: any) => void;
/**事件名称*/
trigger?: string;
className?: string;
style?: React.CSSProperties;
labelClassName?: string;
labelStyle?: React.CSSProperties;
bodyClassName?: string;
bodyStyle?: React.CSSProperties;
children?: React.ReactNode;
/**规则校验失败错误提示位置*/
errorLayout?: FairysValtioFormLayoutContextOptions['errorLayout'];
/**label显示模式*/
labelMode?: FairysValtioFormLayoutContextOptions['labelMode'];
/**额外内容*/
extra?: React.ReactNode;
/**底部提示内容*/
helpText?: React.ReactNode;
/**
* 表单项占据列数
* @default 1
*/
colSpan?: number;
/**
* 表单项占据行数
* @default 1
*/
rowSpan?: number;
/**是否必填*/
isRequired?: boolean;
/**是否显示冒号*/
showColon?: boolean;
/**底部显示边框*/
itemBorderType?: FairysValtioFormLayoutContextOptions['itemBorderType'];
/**边框颜色*/
itemBorderColor?: React.CSSProperties['borderColor'];
/**是否校验失败时显示红色边框*/
isInvalidBorderRed?: boolean;
/**是否校验失败时显示红色文本*/
isInvalidTextRed?: boolean;
/**输入框属性*/
attrs?: any;
/**是否拼接父级字段名*/
isJoinParentField?: boolean;
/**校验规则*/
rules?: RuleItem[];
}
表单项属性参数处理
/**
* 处理表单表单项属性
*
* @example
*
* ```tsx
import { Fragment } from 'react'
import { useFairysValtioFormItemAttrs , FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
export const FormItem = (props: FormItemProps) => {
const { label, extra, helpText } = props
const {
itemClassName, itemStyle, containerClassName, itemLabelClassName, itemLabelStyle,
itemBodyClassName, itemBodyStyle, itemInputClassName, itemExtraClassName, errorClassName, helpClassName,
isInvalid, itemBorderType, children, error,formAttrsNameInstance
} = useFairysValtioFormItemAttrs(props)
return (
<FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
<View className={itemClassName} style={itemStyle}>
<View className={containerClassName}>
<View className={itemLabelClassName} style={itemLabelStyle}>
{label}
</View>
<View className={itemBodyClassName} style={itemBodyStyle}>
<View className={itemInputClassName}>
{children}
</View>
{extra ? <View className={itemExtraClassName}>{extra}</View> : <Fragment />}
{itemBorderType === 'body' && isInvalid ? <View className={errorClassName}>{error}</View> : <Fragment />}
</View>
</View>
{helpText ? <View className={helpClassName}>{helpText}</View> : <Fragment />}
{isInvalid && itemBorderType !== 'body' ? <View className={errorClassName}>{error}</View> : <Fragment />}
</View>
</FairysValtioFormParentAttrsContext.Provider>
);
}
* ```
*
*/
export declare function useFairysValtioFormItemAttrs<T extends MObject<T> = Record<string, any>>(props: FairysValtioFormItemAttrsProps<T>): FairysValtioFormItemAttrsReturn<T>;
export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = Record<string, any>> {
/**表单项值*/
value?: any;
/**是否校验错误*/
isInvalid: boolean;
/**边框类型*/
itemBorderType: FairysValtioFormLayoutContextOptions['itemBorderType'];
/**值改变事件*/
onValueChange: (event: any) => void;
/**当前表单项占据列数*/
colSpan: number;
/**当前表单项占据行数*/
rowSpan: number;
/**列数*/
colCount: number;
/**标签显示模式*/
labelMode: FairysValtioFormLayoutContextOptions['labelMode'];
/**错误提示位置*/
errorLayout: FairysValtioFormLayoutContextOptions['errorLayout'];
/**是否必填*/
isRequired: boolean;
/**表单状态*/
state: T;
/**错误状态*/
errorState: Record<PropertyKey, string[]>;
/**表单实例*/
formInstance: FairysValtioFormInstance<T>;
/**错误信息*/
error?: string[];
/**拼接父级字段名后得到的表单项名称*/
_name?: string;
/**表单项名称*/
name?: string;
/**表单项ID*/
id?: string;
/**表单项路径*/
paths?: (string | number)[];
/**父级字段名*/
parentName?: string;
/**表单属性名实例*/
formAttrsNameInstance: FairysValtioFormParentAttrs;
/**表单项类名*/
itemClassName: string;
/**表单项样式*/
itemStyle: React.CSSProperties;
/**容器类名*/
containerClassName: string;
/**标签类名*/
itemLabelClassName: string;
/**标签样式*/
itemLabelStyle: React.CSSProperties;
/**体类名*/
itemBodyClassName: string;
/**体样式*/
itemBodyStyle: React.CSSProperties;
/**输入框类名*/
itemInputClassName: string;
/**额外内容类名*/
itemExtraClassName: string;
/**错误提示类名*/
errorClassName: string;
/**帮助提示类名*/
helpClassName: string;
/**子元素*/
children?: React.ReactNode;
}
没有样式的表单项属性,仅返回基础输入组件参数
/**
* 没有样式的表单项属性,仅返回基础输入组件参数
*
* @example
*
*```tsx
import { Fragment } from 'react'
import { useFairysValtioFormItemAttrs, FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
export const FormItem = (props: FormItemProps) => {
const { children , formAttrsNameInstance } = useFairysValtioFormItemNoStyleAttrs(props)
return <FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
{children}
</FairysValtioFormParentAttrsContext.Provider>
}
* ```
*/
export declare function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = Record<string, any>>(props: FairysValtioFormItemAttrsProps<T>): FairysValtioFormItemNoStyleAttrsReturn<T>;
export interface FairysValtioFormItemNoStyleAttrsReturn<T extends MObject<T> = Record<string, any>> {
/**表单项值*/
value?: any;
/**是否校验错误*/
isInvalid: boolean;
/**是否必填*/
isRequired: boolean;
/**错误信息*/
error?: string[];
/**值改变事件*/
onValueChange: (event: any) => void;
/**表单状态*/
state: T;
/**错误状态*/
errorState: Record<PropertyKey, string[]>;
/**表单实例*/
formInstance: FairysValtioFormInstance<T>;
/**拼接父级字段名后得到的表单项名称*/
_name?: string;
/**表单项名称*/
name?: string;
/**表单项ID*/
id?: string;
/**表单项路径*/
paths?: (string | number)[];
/**父级字段名*/
parentName?: string;
/**表单属性名实例*/
formAttrsNameInstance: FairysValtioFormParentAttrs;
/**子元素*/
children?: React.ReactNode;
}#layout
src/form/layout.tsx
export interface FairysValtioFormLayoutContextOptions {
/**平台*/
platform?: 'pc' | 'rn' | 'taro';
/**列数据*/
colCount?: number;
/**规则校验失败错误提示位置*/
errorLayout?: 'bottom-left' | 'bottom-right' | 'top-right' | 'top-left' | 'left-border-top' | 'right-border-top';
/**
* label显示模式
* @platform taro 支持 between
*/
labelMode?: 'left' | 'top' | 'between';
/**表单项 className*/
formItemClassName?: string;
/**表单项 style*/
formItemStyle?: React.CSSProperties;
/**表单项 label className*/
formItemLabelClassName?: string;
/**表单项 label style*/
formItemLabelStyle?: React.CSSProperties;
/**表单项 body className*/
formItemBodyClassName?: string;
/**表单项 body style*/
formItemBodyStyle?: React.CSSProperties;
/**
* 底部边框类型
*/
itemBorderType?: 'bottom' | 'body' | 'none';
/**边框颜色*/
itemBorderColor?: React.CSSProperties['borderColor'];
/**是否校验失败时显示红色边框*/
isInvalidBorderRed?: boolean;
/**是否校验失败时显示红色文本*/
isInvalidTextRed?: boolean;
/**是否显示冒号*/
showColon?: boolean;
}
export interface FairysValtioFormLayoutAttrsProps extends FairysValtioFormLayoutContextOptions {
/**
* @description gap 属性是用来设置网格行与列之间的间隙,该属性是row-gap and column-gap的简写形式。
*/
gap?: string | number;
/**标题*/
title?: React.ReactNode;
/**额外内容*/
extra?: React.ReactNode;
/**内容*/
children?: React.ReactNode;
/**是否占据整行*/
isAllColSpan?: boolean;
className?: string;
style?: React.CSSProperties;
/**头部ClassName*/
headerClassName?: string;
/**头部样式*/
headerStyle?: React.CSSProperties;
/**内容ClassName*/
bodyClassName?: string;
/**内容样式*/
bodyStyle?: React.CSSProperties;
/**是否边框*/
bordered?: boolean;
/**显示阴影*/
boxShadow?: boolean;
/**最后一个是否显示底部边框*/
lastItemBordered?: boolean;
}
export declare class FairysValtioFormLayoutInstance {
state: FairysValtioFormLayoutContextOptions;
updated: (options?: FairysValtioFormLayoutContextOptions) => void;
}
初始化布局实例
export declare const useFairysValtioFormLayoutInstance: (instance?: FairysValtioFormLayoutInstance) => FairysValtioFormLayoutInstance;创建布局上下文
export declare const FairysValtioFormLayoutContext: import("react").Context<FairysValtioFormLayoutInstance>;获取布局上下文
export declare const useFairysValtioFormLayoutContext: () => [FairysValtioFormLayoutContextOptions, FairysValtioFormLayoutInstance];布局参数处理
/**
* 布局属性处理
*
* @example
*
* ```tsx
import { Fragment } from 'react'
import { useFairysValtioFormLayoutAttrs, FairysValtioFormLayoutContext } from "@fairys/valtio-form"
import type { FairysValtioFormLayoutAttrsProps } from "@fairys/valtio-form"
export interface LayoutProps extends FairysValtioFormLayoutAttrsProps {}
export const Layout = (props: LayoutProps) => {
const { children, title, extra } = props
const {
formLayoutInstance,
layoutName, layoutStyle,
headerName, headerStyle,
headerTitleName, headerExtraName,
bodyName, bodyStyle
} = useFairysValtioFormLayoutAttrs(props)
return (
<FairysValtioFormLayoutContext.Provider value={formLayoutInstance}>
<div className={layoutName} style={layoutStyle}>
<div>
{title || extra ? (
<div style={headerStyle} className={headerName}>
<div className={headerTitleName}>{title}</div>
<div className={headerExtraName}>{extra}</div>
</div>
) : (
<Fragment />
)}
</div>
<div className={bodyName} style={bodyStyle}>
{children}
</div>
</div>
</FairysValtioFormLayoutContext.Provider>
);
}
* ```
*/
export declare function useFairysValtioFormLayoutAttrs(props: FairysValtioFormLayoutAttrsProps): FairysValtioFormLayoutAttrsReturn;
export interface FairysValtioFormLayoutAttrsReturn {
/**列数*/
colCount: number;
/**规则校验失败错误提示位置*/
errorLayout: string;
/**
* label显示模式
* @platform taro 支持 between
*/
labelMode: string;
/**
* 底部边框类型
*/
itemBorderType: string;
/**表单布局实例*/
formLayoutInstance: FairysValtioFormLayoutInstance;
/**布局ClassName*/
layoutName: string;
/**布局样式*/
layoutStyle: React.CSSProperties;
/**头部ClassName*/
headerName: string;
/**头部样式*/
headerStyle: React.CSSProperties;
/**头部标题ClassName*/
headerTitleName: string;
/**头部额外内容ClassName*/
headerExtraName: string;
/**内容ClassName*/
bodyName: string;
/**内容样式*/
bodyStyle: React.CSSProperties;
}#utils
src/common/utils/index.ts
/***
* 设置值
* @param object 任意对象
* @param paths 值路径
* @param nextValue 新值
*
* @description
* 值不存在时,当 paths 路径中的值为 number 类型时,会创建一个空数组。当 paths 路径中的值为 string 类型时,会创建一个空对象。
*/
export declare function set<T>(state: any, paths: PropertyKey[], nextValue: T): any;
/***
* 获取值
* @param value 任意值
* @param segments 键路径
*/
export declare function get<TDefault = unknown>(value: any, segments: PropertyKey[]): TDefault;
/***
* 格式化路径,将路径中的数组索引转换为数字
* @param path 路径
* @returns 格式化后的路径
*/
export declare function formatePath(path: PropertyKey): (number | symbol)[] | (string | number)[];
/***
* 移除值
* @param value 任意值
* @param segments 键路径
*/
export declare function removeValueByPaths(value: any, segments: PropertyKey[]): void;
/**格式化属性名*/
export declare function formateName(name?: string, parentName?: string): string;
/***
* 是否为对象
* @param x 任意值
* @returns 是否为对象
*/
export declare const isObject: (x: unknown) => x is object;