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