import * as React from 'react'; import { IFormComponentProps, IFormFieldViewDrivenProps, IFormFieldModelDrivenProps, ValidateOccasion, defaultRenderError, useFormChild, } from 'zent/es/form/shared'; import { FormDescription, FormControl, FormNotice, defaultGetValidateOption, useInitialValue, FieldModel, Validators, } from 'zent'; import { useField } from 'zent/es/form/formulr'; import Select, { ISelectProps, ISelectChangeEvent, ISelectItem, } from '../../select'; export type IFormSelectFieldInnerProps = Omit< ISelectProps, 'value' | 'onChange' | 'onDelete' >; export type IFormSelectFieldProps< T, P extends IFormSelectFieldInnerProps > = IFormComponentProps; /** * Old `Select` implementation is a disaster, * temporary dirty code. */ export function FormSelectField( props: IFormSelectFieldProps ) { type FieldValue = P['tags'] extends true ? Item[] : Item; let model: FieldModel; const { name, model: rawModel } = props as IFormFieldViewDrivenProps< FieldValue > & IFormFieldModelDrivenProps; if (name) { const { name, required, defaultValue, destroyOnUnmount, } = props as IFormFieldViewDrivenProps & IFormSelectFieldProps; let validators = (props as IFormFieldViewDrivenProps).validators || []; if ( required && !validators.some(it => it.$$id === Validators.SYMBOL_REQUIRED) ) { validators = validators.concat([ Validators.required(typeof required === 'string' ? required : ''), ]); } // eslint-disable-next-line react-hooks/rules-of-hooks model = useField(name, defaultValue, validators); model.destroyOnUnmount = Boolean(destroyOnUnmount); } else { // eslint-disable-next-line react-hooks/rules-of-hooks model = useField(rawModel); } useInitialValue(model, props.initialValue); const propsRef = React.useRef(props); propsRef.current = props; const { className, style, label, required, before, after, notice, helpDesc, withoutError, withoutLabel, renderError = defaultRenderError, validateOccasion = ValidateOccasion.Default, getValidateOption = defaultGetValidateOption, } = props; const anchorRef = React.useRef(null); useFormChild(model, anchorRef); const dispatch = React.useCallback( (value: Item, isDelete: boolean) => { if (propsRef.current.props?.tags) { const selectedValues = (model.value || []) as Item[]; if (isDelete) { (model.value as Item[]) = selectedValues.filter(it => it !== value); } else if (!selectedValues.includes(value)) { (model.value as Item[]) = [...selectedValues, value]; } } else { (model.value as Item) = value; } if (validateOccasion & ValidateOccasion.Change) { model.validate(getValidateOption('change')); } model.isTouched = true; }, [getValidateOption, model, validateOccasion] ); const onChange = React.useCallback( (e: ISelectChangeEvent) => dispatch(e.target.value, false), [dispatch] ); const onDelete = React.useCallback( (item: ISelectItem) => dispatch(item.value, true), [dispatch] ); return (
{before} {after}
{!!notice && {notice}} {!!helpDesc && {helpDesc}} {withoutError ? null : renderError(model.error)}
); }