2024-04-06 22:54:44 -04:00
|
|
|
import React from 'react';
|
2024-04-07 00:13:19 -04:00
|
|
|
import classNames from 'classnames';
|
2024-04-06 22:54:44 -04:00
|
|
|
|
2024-04-07 00:13:19 -04:00
|
|
|
type CommonProps = {
|
2024-04-06 22:54:44 -04:00
|
|
|
label: React.ReactNode;
|
2024-04-07 00:13:19 -04:00
|
|
|
error?: React.ReactNode;
|
|
|
|
};
|
|
|
|
|
|
|
|
type TextInputProps = {
|
2024-04-06 22:54:44 -04:00
|
|
|
value: string;
|
|
|
|
onChange: (value: string) => void;
|
2024-04-07 00:13:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
type HTMLInputProps = Omit<React.HTMLProps<HTMLInputElement>, 'onChange' | 'label'>;
|
|
|
|
|
|
|
|
function BaseInput({label, value, onChange, error, ...props}: CommonProps & HTMLInputProps & TextInputProps) {
|
2024-04-06 22:54:44 -04:00
|
|
|
const id = React.useId();
|
|
|
|
const handleChange = React.useCallback(
|
|
|
|
(e: React.ChangeEvent<HTMLInputElement>) => onChange(e.target.value),
|
|
|
|
[onChange],
|
|
|
|
);
|
|
|
|
|
2024-04-07 00:13:19 -04:00
|
|
|
return <div className={classNames('totp-input', {'has-validation': !!error})}>
|
2024-04-06 22:54:44 -04:00
|
|
|
<label htmlFor={id} className="form-label">{label}</label>
|
2024-04-07 00:13:19 -04:00
|
|
|
<input id={id} className={classNames('form-control', {'is-invalid': !!error})}
|
|
|
|
value={value} onChange={handleChange} {...props}/>
|
|
|
|
{error && <div className="invalid-feedback">{error}</div>}
|
2024-04-06 22:54:44 -04:00
|
|
|
</div>;
|
|
|
|
}
|
2024-04-07 00:13:19 -04:00
|
|
|
|
|
|
|
export function TextInput(props: CommonProps & TextInputProps) {
|
|
|
|
return <BaseInput {...props} />;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function NumberInput({value, onChange, ...props}: CommonProps & {
|
|
|
|
value: number;
|
|
|
|
onChange: (value: number) => void;
|
|
|
|
min?: number;
|
|
|
|
max?: number;
|
|
|
|
}) {
|
|
|
|
const handleChange = React.useCallback((value: string) => onChange(+value), [onChange]);
|
|
|
|
return <BaseInput type="number" value={`${value}`} onChange={handleChange} {...props}/>;
|
|
|
|
}
|