on af19266 help sign in
120 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 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 // notify parent of value only when passing
50 // TODO: deprecate/remove this
51 // keeping it around for now to avoid refactoring InviteEmail.js, but this
52 // feels like a hack
53 useEffect(() => {
54 pass && onValue && onValue(data);
55 }, [pass, data]); // eslint-disable-line react-hooks/exhaustive-deps
57 return (
58 <Flex
59 className={cn(className, 'mb1')}
60 col
61 style={{
62 ...(disabled && {
63 pointerEvents: 'none',
64 cursor: 'not-allowed',
65 }),
66 }}>
67 <Flex.Item as="label" className="f6 lh-tall" htmlFor={name}>
68 {label}
69 </Flex.Item>
70 <Flex.Item as={Flex} className="rel" row>
71 <Flex.Item
72 as="input"
73 {...rest}
74 className={cn(
75 'b b1 p3 outline-none',
76 { mono },
77 {
78 'bg-white': !disabled,
79 'bg-gray1': disabled,
80 },
81 {
82 gray4: !focused,
83 black: focused,
84 },
85 {
86 'b-green3': visiblyPassed,
87 'b-black': focused && !visiblyPassed,
88 'b-yellow3': !focused && hintError,
89 'b-gray3': !focused && !hintError && !visiblyPassed,
90 }
91 // TODO: inputClassName ?
92 )}
93 id={name}
94 name={name}
95 onKeyPress={onKeyPress}
96 {...bind}
97 flex
98 />
99 {accessory && (
100 <div
101 className="abs"
102 style={{
103 top: 0,
104 right: 0,
105 height: '100%',
106 width: '44px',
107 overflow: 'hidden',
108 }}>
109 {accessory}
110 </div>
111 )}
112 </Flex.Item>
113 {error && (
114 <Flex.Item as={ErrorText} className="mv1">
115 {error}
116 </Flex.Item>
117 )}
118 </Flex>
119 );