// Copyright 2019-2025 @pezkuwi/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 import type { ResultType, Validator } from '../util/validators.js'; import React, { useEffect, useState } from 'react'; import { useIsMounted } from '../hooks/index.js'; import { Result } from '../util/validators.js'; import Warning from './Warning.js'; interface BasicProps { isError?: boolean; value?: string | null; onChange?: (value: string) => void; onFocus?: () => void; onBlur?: () => void; } type Props = T & { className?: string; component: React.ComponentType; defaultValue?: string; onValidatedChange: (value: string | null) => void; validator: Validator; } function ValidatedInput> ({ className, component: Input, defaultValue, onValidatedChange, validator, ...props }: Props): React.ReactElement> { const [value, setValue] = useState(defaultValue || ''); const [validationResult, setValidationResult] = useState>(Result.ok('')); const isMounted = useIsMounted(); useEffect(() => { if (defaultValue) { setValue(defaultValue); } }, [defaultValue]); useEffect(() => { // Do not show any error on first mount if (!isMounted) { return; } // eslint-disable-next-line @typescript-eslint/no-floating-promises (async (): Promise => { const result = await validator(value); setValidationResult(result); onValidatedChange(Result.isOk(result) ? value : null); })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [value, validator, onValidatedChange]); return (
{Result.isError(validationResult) && ( {validationResult.error.errorDescription} )}
); } export default ValidatedInput;