import React, { FC, memo, useEffect, useRef, useState, } from 'react'; import { useTranslation } from 'react-i18next'; export const AlertType = { WARNING: 'warning', ERROR: 'error', } as const; export type AlertType = typeof AlertType[keyof typeof AlertType]; export type AlertInfo = { type?: AlertType message?: string } type ClosableTextInputProps = { isShown: boolean value?: string placeholder?: string inputValidator?(text: string): AlertInfo | Promise | null onPressEnter?(inputText: string | null): void onClickOutside?(): void } const ClosableTextInput: FC = memo((props: ClosableTextInputProps) => { const { t } = useTranslation(); const inputRef = useRef(null); const [inputText, setInputText] = useState(props.value); const [currentAlertInfo, setAlertInfo] = useState(null); const [isAbleToShowAlert, setIsAbleToShowAlert] = useState(false); const createValidation = async(inputText: string) => { if (props.inputValidator != null) { const alertInfo = await props.inputValidator(inputText); setAlertInfo(alertInfo); } }; const onChangeHandler = async(e: React.ChangeEvent) => { const inputText = e.target.value; createValidation(inputText); setInputText(inputText); setIsAbleToShowAlert(true); }; const onFocusHandler = async(e: React.ChangeEvent) => { const inputText = e.target.value; await createValidation(inputText); }; const onPressEnter = () => { if (props.onPressEnter != null) { const text = inputText != null ? inputText.trim() : null; if (currentAlertInfo == null) { props.onPressEnter(text); } } }; const onKeyDownHandler = (e) => { switch (e.key) { case 'Enter': onPressEnter(); break; default: break; } }; /* * Hide when click outside the ref */ const onBlurHandler = () => { if (props.onClickOutside == null) { return; } props.onClickOutside(); }; // didMount useEffect(() => { // autoFocus if (inputRef?.current == null) { return; } inputRef.current.focus(); }); const AlertInfo = () => { if (currentAlertInfo == null) { return <>; } const alertType = currentAlertInfo.type != null ? currentAlertInfo.type : AlertType.ERROR; const alertMessage = currentAlertInfo.message != null ? currentAlertInfo.message : 'Invalid value'; const alertTextStyle = alertType === AlertType.ERROR ? 'text-danger' : 'text-warning'; const translation = alertType === AlertType.ERROR ? 'Error' : 'Warning'; return (

{t(translation)}: {alertMessage}

); }; return (
{isAbleToShowAlert && }
); }); export default ClosableTextInput;