on 44dc2fe help sign in
bridge/src/form/EmailChipInput.js
138 lines 3.3 kB history raw
1import React, { useState, useCallback } from 'react';
2import { isEqual } from 'lodash';
3import { Flex, ErrorText } from 'indigo-react';
4import cn from 'classnames';
5import { useField } from 'react-final-form';
7import { hasErrors } from 'form/validators';
9const Chip = ({ value, onDelete, disabled }) => {
10 return (
11 <Flex
12 className={cn('r32 ph2 m1 flex-center h7', {
13 'bg-gray2': !disabled,
14 'bg-gray1 gray4': disabled,
15 })}>
16 <Flex.Item>{value}</Flex.Item>
17 <Flex.Item onClick={disabled ? onDelete : undefined} className="ml1 f6">
18 ✗
19 </Flex.Item>
20 </Flex>
21 );
22};
24const EmailChipInput = ({ className, name, label, disabled }) => {
25 const [chips, _setChips] = useState([]);
27 const [value, setValue] = useState('');
29 const handleChange = useCallback(
30 event => {
31 setValue(event.target.value);
32 },
33 [setValue]
34 );
36 const {
37 input,
38 meta: { active, error, dirtySinceLastSubmit },
39 } = useField(name, {
40 subscription: {
41 active: true,
42 error: true,
43 value: true,
44 dirtySinceLastSubmit: true,
45 },
46 isEqual,
47 });
49 const setChips = useCallback(
50 chips => {
51 console.log(chips);
52 _setChips(chips);
53 input.onChange(chips);
54 },
55 [input, _setChips]
56 );
58 const addToChips = useCallback(() => {
59 setChips([...chips, value]);
60 setValue('');
61 }, [chips, value, setChips]);
63 const handleKeyDown = useCallback(
64 event => {
65 if (['Enter', 'Tab', ','].includes(event.key) && value !== '') {
66 event.preventDefault();
67 addToChips();
68 } else if ('Backspace' === event.key && value === '') {
69 event.preventDefault();
70 setChips(chips.slice(0, -1));
71 } else if (disabled) {
72 event.preventDefault();
73 }
74 },
75 [setChips, chips, value, addToChips, disabled]
76 );
78 const handleDelete = useCallback(
79 idx => () => {
80 setChips([...chips.slice(0, idx), ...chips.slice(idx + 1)]);
81 },
82 [setChips, chips]
83 );
85 const handleBlur = useCallback(
86 e => {
87 if (value !== '') {
88 addToChips();
89 input.onBlur();
90 }
91 },
92 [addToChips, value, input]
93 );
95 const hasError = hasErrors(error);
97 return (
98 <Flex col className={className}>
99 {label && (
100 <Flex.Item as="label" className={cn('f6 lh-tall')} htmlFor={name}>
101 {label}
102 </Flex.Item>
103 )}
104 <Flex.Item
105 className={cn('flex b1 flex-wrap', {
106 'b-green2': active && !disabled && !hasError,
107 'b-red3': active && !disabled && hasError,
108 })}>
109 {chips.map((chip, idx) => (
110 <Chip
111 key={idx}
112 value={chip}
113 disabled={disabled}
114 onDelete={handleDelete(idx)}
115 />
116 ))}
118 <input
119 type="textarea"
120 className="mv1 mh2 h7 b-none flex-grow"
121 placeholder="Enter an email address"
122 value={value}
123 name={name}
124 onChange={handleChange}
125 onKeyDown={handleKeyDown}
126 onBlur={handleBlur}
127 />
128 </Flex.Item>
129 {error && (
130 <Flex.Item as={ErrorText} className="mv1">
131 {error}
132 </Flex.Item>
133 )}
134 </Flex>
135 );
136};
138export default EmailChipInput;