bigbuffet-rw/app/soapbox/components/ui/input/input.tsx

113 lines
4.1 KiB
TypeScript
Raw Normal View History

2022-03-21 11:09:01 -07:00
import classNames from 'classnames';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import Icon from '../icon/icon';
import SvgIcon from '../icon/svg-icon';
2022-03-21 11:09:01 -07:00
import Tooltip from '../tooltip/tooltip';
const messages = defineMessages({
showPassword: { id: 'input.password.show_password', defaultMessage: 'Show password' },
hidePassword: { id: 'input.password.hide_password', defaultMessage: 'Hide password' },
});
2022-05-06 15:13:00 -07:00
interface IInput extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'maxLength' | 'onChange' | 'onBlur' | 'type' | 'autoComplete' | 'autoCorrect' | 'autoCapitalize' | 'required' | 'disabled' | 'onClick' | 'readOnly' | 'min' | 'pattern'> {
/** Put the cursor into the input on mount. */
2022-03-21 11:09:01 -07:00
autoFocus?: boolean,
/** The initial text in the input. */
2022-03-21 11:09:01 -07:00
defaultValue?: string,
/** Extra class names for the <input> element. */
2022-03-21 11:09:01 -07:00
className?: string,
2022-05-02 19:38:15 -07:00
/** Extra class names for the outer <div> element. */
outerClassName?: string,
/** URL to the svg icon. Cannot be used with addon. */
2022-03-21 11:09:01 -07:00
icon?: string,
/** Internal input name. */
2022-03-21 11:09:01 -07:00
name?: string,
/** Text to display before a value is entered. */
2022-03-21 11:09:01 -07:00
placeholder?: string,
/** Text in the input. */
2022-05-05 14:35:30 -07:00
value?: string | number,
/** Change event handler for the input. */
2022-04-07 10:39:22 -07:00
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void,
/** HTML input type. */
type?: 'text' | 'number' | 'email' | 'tel' | 'password',
2022-05-06 15:13:00 -07:00
/** Whether to display the input in red. */
hasError?: boolean,
/** An element to display as prefix to input. Cannot be used with icon. */
addon?: React.ReactElement,
2022-03-21 11:09:01 -07:00
}
/** Form input element. */
2022-03-21 11:09:01 -07:00
const Input = React.forwardRef<HTMLInputElement, IInput>(
(props, ref) => {
const intl = useIntl();
const { type = 'text', icon, className, outerClassName, hasError, addon, ...filteredProps } = props;
2022-03-21 11:09:01 -07:00
const [revealed, setRevealed] = React.useState(false);
const isPassword = type === 'password';
const togglePassword = React.useCallback(() => {
setRevealed((prev) => !prev);
}, []);
return (
<div className={classNames('mt-1 relative rounded-md shadow-sm', outerClassName)}>
2022-03-21 11:09:01 -07:00
{icon ? (
<div className='absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none'>
<Icon src={icon} className='h-4 w-4 text-gray-700 dark:text-gray-600' aria-hidden='true' />
2022-03-21 11:09:01 -07:00
</div>
) : null}
{addon ? (
<div className='absolute inset-y-0 left-0 flex items-center'>
{addon}
</div>
) : null}
2022-03-21 11:09:01 -07:00
<input
{...filteredProps}
type={revealed ? 'text' : type}
ref={ref}
className={classNames({
'bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 placeholder:text-gray-600 dark:placeholder:text-gray-600 block w-full sm:text-sm border-gray-400 dark:border-gray-800 dark:ring-1 dark:ring-gray-800 rounded-md focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-500 dark:focus:border-primary-500':
2022-06-01 11:18:01 -07:00
true,
2022-03-21 11:09:01 -07:00
'pr-7': isPassword,
2022-05-09 09:28:38 -07:00
'text-red-600 border-red-600': hasError,
2022-03-21 11:09:01 -07:00
'pl-8': typeof icon !== 'undefined',
'pl-16': typeof addon !== 'undefined',
}, className)}
2022-03-21 11:09:01 -07:00
/>
{isPassword ? (
<Tooltip
text={
revealed ?
intl.formatMessage(messages.hidePassword) :
intl.formatMessage(messages.showPassword)
}
>
<div className='absolute inset-y-0 right-0 flex items-center'>
<button
type='button'
onClick={togglePassword}
tabIndex={-1}
className='text-gray-700 dark:text-gray-600 hover:text-gray-500 dark:hover:text-gray-400 h-full px-2 focus:ring-primary-500 focus:ring-2'
2022-03-21 11:09:01 -07:00
>
<SvgIcon
src={revealed ? require('@tabler/icons/eye-off.svg') : require('@tabler/icons/eye.svg')}
2022-03-21 11:09:01 -07:00
className='h-4 w-4'
/>
</button>
</div>
</Tooltip>
) : null}
</div>
);
},
);
export default Input;