diff --git a/src/components/form/TextField.tsx b/src/components/form/TextField.tsx index 3661cf15..b916267c 100644 --- a/src/components/form/TextField.tsx +++ b/src/components/form/TextField.tsx @@ -26,41 +26,54 @@ import { import { wrap } from '../../helpers'; import ClickableTooltip from '../ClickableTooltip'; -export type TextFieldProps = Omit & { - validate?: FieldValidator | StringSchema; +type StringArraySchema = ArraySchema | undefined, AnyObject, '', ''>; +type Validate = FieldValidator | StringSchema | StringArraySchema; +type Split = string | RegExp; + +type BaseTextFieldProps = Omit & { name: string; }; -type StringArraySchema = ArraySchema | undefined, AnyObject, '', ''>; +type RepeatTextFieldProps = BaseTextFieldProps & { + repeat?: Array>; +}; -interface ITextField { - ( - props: TextFieldProps, - context?: any - ): React.ReactElement | null; +export type TextFieldProps< + SingleValue extends boolean = true +> = RepeatTextFieldProps & ( + SingleValue extends true + ? { validate?: FieldValidator | StringSchema; } + : { + validate?: FieldValidator | StringArraySchema; + split: Split; + } +); + +interface ITextField { + // eslint-disable-next-line @typescript-eslint/prefer-function-type ( - props: Omit & { - validate?: FieldValidator | StringArraySchema; - split: string | RegExp; - }, + props: TextFieldProps, context?: any ): React.ReactElement | null; } -const TextField: ITextField = ({ +const TextField: ITextField & ITextField = ({ validate, split, required = false, name, - type = 'text', - InputProps = {}, onKeyUp, - onBlur, + repeat = [], ...otherTextFieldProps -}: Omit & { - validate?: FieldValidator | StringSchema | StringArraySchema; - split?: string | RegExp +}: RepeatTextFieldProps & { + validate?: Validate; + split?: Split; }) => { + const [validateRepeat, setValidateRepeat] = React.useState(YupString()); + if (validate === undefined) { validate = (split === undefined) ? YupString() @@ -71,78 +84,125 @@ const TextField: ITextField = ({ validate = validate.required(); } - const fieldConfig: FieldConfig = { + // Internal TextField. + const TextField: React.FC = ({ + validate, + split, name, - type, - validate: async (value) => { - if (validate instanceof Schema) { - try { - validate.validateSync(value); - } catch (error) { - if (error instanceof ValidationError) { - return error.errors[0]; + type = 'text', + InputProps = {}, + onKeyUp, + onBlur + }) => { + const fieldConfig: FieldConfig = { + name, + type, + validate: async (value) => { + if (validate instanceof Schema) { + try { + validate.validateSync(value); + } catch (error) { + if (error instanceof ValidationError) { + return error.errors[0]; + } + throw error; + } + } else if (validate !== undefined) { + return await validate(value); } - throw error; - } - } else if (validate !== undefined) { - return await validate(value); - } - } - }; - - return ( - - {({ meta, form }: FieldProps) => { - const [showError, setShowError] = React.useState(false); - - let { - endAdornment, - ...otherInputProps - } = InputProps; - - if (showError && - meta.error !== undefined && - meta.error !== '' - ) { - endAdornment = <> - {endAdornment} - - - - - - ; } + }; - onKeyUp = wrap({ - after: (event: React.KeyboardEvent) => { - let value: string | string[] = (event.target as HTMLTextAreaElement).value; - if (split !== undefined) value = value.split(split); - form.setFieldValue(name, value, true); - } - }, onKeyUp); - - onBlur = wrap({ - after: () => { setShowError(true); } - }, onBlur); - - return ( - + {({ meta, form }: FieldProps) => { + const [showError, setShowError] = React.useState(false); + + let { endAdornment, ...otherInputProps - }} - {...otherTextFieldProps} - /> - ); - }} - - ); + } = InputProps; + + if (showError && + meta.error !== undefined && + meta.error !== '' + ) { + endAdornment = <> + {endAdornment} + + + + + + ; + } + + onKeyUp = wrap({ + after: (event: React.KeyboardEvent) => { + let value: string | string[] = (event.target as HTMLTextAreaElement).value; + if (split !== undefined) value = value.split(split); + form.setFieldValue(name, value, true); + } + }, onKeyUp); + + onBlur = wrap({ + after: () => { setShowError(true); } + }, onBlur); + + return ( + + ); + }} + + ); + }; + + if (repeat.length > 0) { + onKeyUp = wrap({ + after: (event: React.KeyboardEvent) => { + setValidateRepeat(YupString().test( + `matches-${name}`, + `doesn't match ${name}`, + (repeatValue) => { + const value = (event.target as HTMLTextAreaElement).value; + return value === repeatValue; + } + )); + } + }, onKeyUp); + } + + return <> + + {repeat.map(textFieldProps => + + )} + ; }; export default TextField;