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