2024-07-02 14:52:36 +02:00

118 lines
3.5 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.TEXT_SM_REGULAR} color={ITypoColor.COLOR_ERROR_600}>
{value}
</Typography>,
);
});
return errors;
}
}