import { useFieldSet, FormProvider, BasicModel, IMaybeError, FieldSetModel, IValidators, $FieldSetValue, ModelRef, FieldArrayModel, } from './formulr'; import { IRenderError, defaultRenderError, useFormChild, IFormFieldViewDrivenProps, } from './shared'; import { useImperativeHandle } from 'react'; import { UnknownFieldSetModelChildren } from './formulr/utils'; import { useObservableEagerState } from 'observable-hooks'; export interface IFieldSetBaseProps { /** * 表单提交时滚动到错误时的`DOM`元素的`ref`(来自`React.createRef`或`React.useRef`) */ scrollAnchorRef?: React.RefObject; /** * 校验规则数组,按数组顺序执行,直到所有都通过或者在第一个失败的地方停止 */ validators?: IValidators<$FieldSetValue>; children?: React.ReactNode; /** * 用于渲染整个 `FieldSet` 层面的错误 */ renderError?: IRenderError; modelRef?: React.RefObject>; } export interface IFieldSetModelDrivenProps< T extends UnknownFieldSetModelChildren > extends IFieldSetBaseProps { model: | FieldSetModel | ModelRef< $FieldSetValue, | FieldSetModel | FieldArrayModel<$FieldSetValue, FieldSetModel>, FieldSetModel >; } export interface IFieldSetViewDrivenProps< T extends UnknownFieldSetModelChildren > extends Omit< IFormFieldViewDrivenProps<$FieldSetValue>, 'defaultValue' | 'validators' | 'initialValue' >, IFieldSetBaseProps {} export function FieldSet( props: IFieldSetModelDrivenProps | IFieldSetViewDrivenProps ) { const { scrollAnchorRef, renderError = defaultRenderError, validators, modelRef, } = props as IFieldSetBaseProps; const { name } = props as IFieldSetViewDrivenProps; const { model: rawModel } = props as IFieldSetModelDrivenProps; // It's safe to use `any` const [ctx, model] = useFieldSet((name ?? rawModel) as any, validators); if (isFieldSetViewDrivenProps(props)) { const { normalizeBeforeSubmit, destroyOnUnmount } = props; model.destroyOnUnmount = Boolean(destroyOnUnmount); if (normalizeBeforeSubmit) { model.normalizeBeforeSubmit = normalizeBeforeSubmit; } } useImperativeHandle(modelRef, () => model, [model]); useFormChild(model as BasicModel, scrollAnchorRef); useObservableEagerState(model.error$); return ( {props.children} {renderError(model.error as IMaybeError)} ); } function isFieldSetViewDrivenProps( props: IFieldSetModelDrivenProps | IFieldSetViewDrivenProps ): props is IFieldSetViewDrivenProps { return (props as IFieldSetViewDrivenProps).name !== undefined; }