on 859db71 help sign in
118 lines 2.7 kB history raw
1import React, { useCallback } from 'react';
2import cn from 'classnames';
4import Flex from './Flex';
5import { ErrorText } from './Typography';
7export default React.memo(function Input({
8 // visuals
9 name,
10 label,
11 className,
12 accessory,
13 mono = false,
15 // callbacks
16 onEnter,
18 // state from hook
19 focused,
20 pass,
21 syncPass,
22 visiblyPassed,
23 error,
24 hintError,
25 data,
26 bind,
27 autoFocus,
28 disabled,
30 // ignored
31 initialValue,
32 validators,
33 transformers,
35 // extra
36 ...rest
37}) {
38 // NB(shrugs): we disable exhaustive deps because we don't want the callbacks
39 // (whose identity might change between renders) to trigger a re-notify of
40 // state that we already know
41 // this also happens to prevent render loops when rendering a map of inputs
43 // notify parent of enter keypress iff not disabled and passing
44 const onKeyPress = useCallback(
45 e => !disabled && pass && e.key === 'Enter' && onEnter && onEnter(),
46 [disabled, pass] // eslint-disable-line react-hooks/exhaustive-deps
47 );
49 return (
50 <Flex
51 className={cn(className, 'mb1')}
52 col
53 style={{
54 ...(disabled && {
55 pointerEvents: 'none',
56 cursor: 'not-allowed',
57 }),
58 }}>
59 <Flex.Item
60 as="label"
61 className={cn('f6 lh-tall', {
62 black: !disabled,
63 gray4: disabled,
64 })}
65 htmlFor={name}>
66 {label}
67 </Flex.Item>
68 <Flex.Item as={Flex} className="rel" row>
69 <Flex.Item
70 as="input"
71 {...rest}
72 className={cn(
73 'b b1 p3 outline-none',
74 { mono },
75 {
76 'bg-white': !disabled,
77 'bg-gray1': disabled,
78 },
79 {
80 gray4: !focused,
81 black: focused,
82 },
83 {
84 'b-green3': visiblyPassed,
85 'b-black': focused && !visiblyPassed,
86 'b-yellow3': !focused && hintError,
87 'b-gray2': !focused && !hintError && !visiblyPassed,
88 }
89 // TODO: inputClassName ?
90 )}
91 id={name}
92 name={name}
93 onKeyPress={onKeyPress}
94 {...bind}
95 flex
96 />
97 {accessory && (
98 <div
99 className="abs"
100 style={{
101 top: 0,
102 right: 0,
103 height: '100%',
104 width: '44px',
105 overflow: 'hidden',
106 }}>
107 {accessory}
108 </div>
109 )}
110 </Flex.Item>
111 {error && (
112 <Flex.Item as={ErrorText} className="mv1">
113 {error}
114 </Flex.Item>
115 )}
116 </Flex>
117 );
118});