118 lines
3.4 KiB
TypeScript
118 lines
3.4 KiB
TypeScript
import React from "react";
|
|
import { FormContext, IFormContext } from ".";
|
|
import { ValidationError } from "class-validator";
|
|
import Typography, { ITypo, ITypoColor } from "../Typography";
|
|
|
|
export type IProps = {
|
|
value?: string;
|
|
onChange?: (event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => void;
|
|
name: string;
|
|
required?: boolean;
|
|
placeholder?: string;
|
|
readonly?: boolean;
|
|
className?: string;
|
|
defaultValue?: string;
|
|
disableValidation?: boolean;
|
|
validationError?: ValidationError;
|
|
disabled?: boolean;
|
|
};
|
|
|
|
type IState = {
|
|
value: string;
|
|
validationError: ValidationError | null;
|
|
};
|
|
|
|
export default abstract class BaseField<P extends IProps, S extends IState = IState> extends React.Component<P, S> {
|
|
public static override contextType = FormContext;
|
|
public override context: IFormContext | null = null;
|
|
public fieldRef: React.RefObject<any> = React.createRef();
|
|
|
|
static defaultProps: Partial<IProps> = {
|
|
disableValidation: false,
|
|
required: true,
|
|
};
|
|
|
|
constructor(props: P) {
|
|
super(props);
|
|
this.onChange = this.onChange.bind(this);
|
|
this.onFocus = this.onFocus.bind(this);
|
|
this.onBlur = this.onBlur.bind(this);
|
|
this.hasError = this.hasError.bind(this);
|
|
this.renderErrors = this.renderErrors.bind(this);
|
|
}
|
|
|
|
public override componentDidMount() {
|
|
this.context?.setField(this.props.name, this);
|
|
this.setState({
|
|
value: this.props.defaultValue ?? "",
|
|
});
|
|
}
|
|
|
|
public override componentDidUpdate(prevProps: IProps) {
|
|
if (this.props.value !== prevProps.value) {
|
|
this.setState({
|
|
value: this.props.value ?? "",
|
|
});
|
|
}
|
|
|
|
if (this.props.defaultValue !== prevProps.defaultValue) {
|
|
this.setState({
|
|
value: this.props.defaultValue ?? "",
|
|
});
|
|
}
|
|
|
|
if (this.props.validationError !== prevProps.validationError) {
|
|
this.setState({
|
|
validationError: this.props.validationError ?? null,
|
|
});
|
|
}
|
|
}
|
|
|
|
public override componentWillUnmount() {
|
|
this.context?.unSetField(this.props.name);
|
|
}
|
|
|
|
protected getDefaultState(): IState {
|
|
return {
|
|
value: this.props.value ?? "",
|
|
validationError: this.props.validationError ?? null,
|
|
};
|
|
}
|
|
|
|
protected onFocus(event: React.FocusEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
|
|
this.context?.onFieldFocusChange(this.props.name, this, true);
|
|
}
|
|
|
|
protected onBlur(event: React.FocusEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
|
|
this.context?.onFieldFocusChange(this.props.name, this, false);
|
|
}
|
|
|
|
protected onChange(event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
|
|
this.context?.onFieldChange(this.props.name, this);
|
|
this.setState({ value: event.currentTarget.value, validationError: null });
|
|
if (this.props.onChange) {
|
|
this.props.onChange(event);
|
|
}
|
|
}
|
|
|
|
protected hasError(): boolean {
|
|
return this.state.validationError !== null;
|
|
// if(!this.context) return false;
|
|
// if(!this.context.hasOneFocusedInput() && this.state.validationError !== null) return true;
|
|
// return this.state.validationError !== null && this.context.isInputFocused(this.props.name);
|
|
}
|
|
|
|
protected renderErrors(): JSX.Element[] | null {
|
|
if (!this.state.validationError || !this.state.validationError.constraints) return null;
|
|
let errors: JSX.Element[] = [];
|
|
Object.entries(this.state.validationError.constraints).forEach(([key, value]) => {
|
|
errors.push(
|
|
<Typography key={key} typo={ITypo.CAPTION_14} color={ITypoColor.RED_FLASH}>
|
|
{value}
|
|
</Typography>,
|
|
);
|
|
});
|
|
return errors;
|
|
}
|
|
}
|