on fd7895b help sign in
133 lines 3.3 kB history raw
1import React from 'react';
2import cn from 'classnames';
3import { useField } from 'react-final-form';
4import Flex from './Flex';
5import { ErrorText } from './Typography';
7export default function Input({
8 // visuals
9 type,
10 name,
11 label,
12 className,
13 accessory,
14 labelAccessory,
15 disabled = false,
16 mono = false,
17 obscure,
19 // callbacks
20 onEnter,
22 // state
23 config,
25 // extra
26 ...rest
27}) {
28 const {
29 input,
30 meta: {
31 active,
32 error,
33 submitError,
34 dirtySinceLastSubmit,
35 submitting,
36 submitSucceeded,
37 touched,
38 valid,
39 },
40 } = useField(name, config);
42 disabled = disabled || submitting || submitSucceeded;
44 // choose the base dom component
45 const BaseComponent = type === 'textarea' ? 'textarea' : 'input';
47 // notify parent of enter keypress iff not disabled and passing
48 // TODO: integrate this into react-final-form submission
49 // const onKeyPress = useCallback(
50 // e => !disabled && valid && e.key === 'Enter' && onEnter && onEnter(),
51 // [disabled, valid] // eslint-disable-line react-hooks/exhaustive-deps
52 // );
54 const showError = !!error;
55 const showSubmitError = !!submitError && !dirtySinceLastSubmit;
56 const indicateError = touched && !active && (showError || showSubmitError);
58 return (
59 <Flex
60 col
61 className={cn(className, 'mb1')}
62 style={{
63 ...(disabled && {
64 pointerEvents: 'none',
65 cursor: 'not-allowed',
66 }),
67 }}>
68 <Flex.Item
69 as={Flex}
70 justify="between"
71 align="center"
72 className={cn('f6 lh-tall', {
73 black: !disabled,
74 gray4: disabled,
75 })}>
76 <Flex.Item as="label" justify="center" htmlFor={name}>
77 {label}
78 </Flex.Item>
79 {labelAccessory && <Flex.Item>{labelAccessory}</Flex.Item>}
80 </Flex.Item>
81 <Flex.Item as={Flex} row className="rel">
82 <Flex.Item
83 flex
84 as={BaseComponent}
85 {...rest}
86 // NOTE: 1.15 from input line-height, 24px = 12px * 2 (from p3 styling)
87 style={type === 'textarea' ? { minHeight: 'calc(1.5rem * 3)' } : {}}
88 className={cn(
89 'b b1 p3 outline-none bs-none r4',
90 { mono },
91 {
92 'bg-white': !disabled,
93 'bg-gray1': disabled,
94 },
95 {
96 gray4: !(active || touched),
97 black: active || touched,
98 },
99 {
100 'b-green3': valid,
101 'b-black': !valid && active,
102 'b-yellow3': !valid && !active && touched,
103 'b-gray2': !valid && !active && !touched,
104 }
105 )}
106 id={name}
107 name={name}
108 {...input}
109 type={type === 'textarea' ? undefined : type}
110 />
111 {accessory && (
112 <div
113 className="abs"
114 style={{
115 top: 0,
116 right: 0,
117 height: '100%',
118 width: 'calc(1.5em + 24px)',
119 overflow: 'hidden',
120 }}>
121 {accessory}
122 </div>
123 )}
124 </Flex.Item>
126 {indicateError && (
127 <Flex.Item as={ErrorText} className="mv1">
128 {error || submitError}
129 </Flex.Item>
130 )}
131 </Flex>
132 );