-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathInput.tsx
More file actions
82 lines (70 loc) · 2.12 KB
/
Input.tsx
File metadata and controls
82 lines (70 loc) · 2.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import classnames from 'classnames';
import type { JSX } from 'preact';
import { useSyncedRef } from '../../hooks/use-synced-ref';
import { useValidationError } from '../../hooks/use-validation-error';
import type { FormControlProps, PresentationalProps } from '../../types';
import { downcastRef } from '../../util/typing';
import { inputGroupStyles } from './InputGroup';
export type InputStylesOptions = {
classes?: string | string[];
feedback?: 'error' | 'warning';
};
export function inputStyles({ classes, feedback }: InputStylesOptions) {
return classnames(
'focus-visible-ring ring-inset border rounded w-full p-2',
'bg-grey-0 focus:bg-white disabled:bg-grey-1',
'placeholder:text-grey-6 disabled:placeholder:text-grey-7',
// On iOS, the input font size must be at least 16px to prevent the browser
// from zooming into it on touch.
'touch:text-at-least-16px',
{
'ring-2': !!feedback,
'ring-red-error': feedback === 'error',
'ring-yellow-notice': feedback === 'warning',
},
// Adapt styles when this component is inside an InputGroup
inputGroupStyles,
classes,
);
}
type ComponentProps = FormControlProps & {
type?: 'text' | 'email' | 'search' | 'number' | 'password' | 'url';
};
export type InputProps = PresentationalProps &
ComponentProps &
JSX.InputHTMLAttributes<HTMLInputElement>;
/**
* Render a text field input
*/
export default function Input({
elementRef,
type = 'text',
classes,
error,
feedback,
...htmlAttributes
}: InputProps) {
if (!htmlAttributes.id && !htmlAttributes['aria-label']) {
console.warn(
'`Input` component should have either an `id` or an `aria-label` attribute',
);
}
const inputRef = downcastRef<HTMLElement | undefined, HTMLInputElement>(
elementRef,
);
const ref = useSyncedRef<HTMLInputElement>(inputRef);
if (error) {
feedback = 'error';
}
useValidationError(ref, error);
return (
<input
data-component="Input"
{...htmlAttributes}
ref={ref}
type={type}
className={inputStyles({ classes, feedback })}
aria-invalid={feedback === 'error'}
/>
);
}