on e4c125f help sign in
134 lines 3.3 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 onPass,
18 onError,
19 onFocus,
20 onEnter,
22 // state from hook
23 focused,
24 pass,
25 visiblyPassed,
26 error,
27 data,
28 bind,
29 autoFocus,
30 disabled,
32 // ignored
33 initialValue,
34 validators,
35 transformers,
37 // extra
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 // notify parent of value only when passing
52 useEffect(() => {
53 pass && onValue && onValue(data);
54 }, [pass, data]); // eslint-disable-line react-hooks/exhaustive-deps
56 // notify parent of pass
57 useEffect(() => {
58 onPass && onPass(pass);
59 }, [pass]); // eslint-disable-line react-hooks/exhaustive-deps
61 // notify parent of error whenever error changes
62 useEffect(() => {
63 onError && onError(error);
64 }, [error]); // eslint-disable-line react-hooks/exhaustive-deps
66 // notify parent of focus
67 useEffect(() => {
68 onFocus && onFocus(focused);
69 }, [focused]); // eslint-disable-line react-hooks/exhaustive-deps
71 console.log(name, visiblyPassed, error);
72 return (
73 <Flex className={className} col>
74 <Flex.Item as="label" className="f6 lh-tall" htmlFor={name}>
75 {label}
76 </Flex.Item>
77 <Flex.Item as={Flex} className="rel" row>
78 <Flex.Item
79 as="input"
80 {...rest}
81 cols={[1, accessory ? 11 : 13]}
82 className={cn(
83 'rel b b1 p3 outline-none',
84 { mono },
85 {
86 'bg-white': !disabled,
87 'bg-gray1': disabled,
88 },
89 {
90 gray4: !focused,
91 black: focused,
92 },
93 {
94 'b-green3': visiblyPassed,
95 'b-black': focused && !visiblyPassed,
96 'b-yellow3': !focused && error,
97 'b-gray3': !focused && !error && !visiblyPassed,
98 }
99 // TODO: inputClassName ?
100 )}
101 style={{
102 ...(disabled && {
103 pointerEvents: 'none',
104 cursor: 'not-allowed',
105 }),
106 }}
107 id={name}
108 name={name}
109 onKeyPress={onKeyPress}
110 {...bind}
111 flex
112 />
113 {accessory && (
114 <div
115 className="abs"
116 style={{
117 top: 0,
118 right: 0,
119 height: '100%',
120 width: '44px',
121 overflow: 'hidden',
122 }}>
123 {accessory}
124 </div>
125 )}
126 </Flex.Item>
127 {error && (
128 <Flex.Item as={ErrorText} className="mv1">
129 {error}
130 </Flex.Item>
131 )}
132 </Flex>
133 );