on a0107e0 help sign in
bridge/src/form/EmailChipInput.js
137 lines 3.2 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 },
39 } = useField(name, {
40 subscription: {
41 active: true,
42 error: true,
43 value: true,
44 },
45 isEqual,
46 });
48 const setChips = useCallback(
49 chips => {
50 console.log(chips);
51 _setChips(chips);
52 input.onChange(chips);
53 },
54 [input, _setChips]
55 );
57 const addToChips = useCallback(() => {
58 setChips([...chips, value]);
59 setValue('');
60 }, [chips, value, setChips]);
62 const handleKeyDown = useCallback(
63 event => {
64 if (['Enter', 'Tab', ','].includes(event.key) && value !== '') {
65 event.preventDefault();
66 addToChips();
67 } else if ('Backspace' === event.key && value === '') {
68 event.preventDefault();
69 setChips(chips.slice(0, -1));
70 } else if (disabled) {
71 event.preventDefault();
72 }
73 },
74 [setChips, chips, value, addToChips, disabled]
75 );
77 const handleDelete = useCallback(
78 idx => () => {
79 setChips([...chips.slice(0, idx), ...chips.slice(idx + 1)]);
80 },
81 [setChips, chips]
82 );
84 const handleBlur = useCallback(
85 e => {
86 if (value !== '') {
87 addToChips();
88 input.onBlur();
89 }
90 },
91 [addToChips, value, input]
92 );
94 const hasError = hasErrors(error);
96 return (
97 <Flex col className={className}>
98 {label && (
99 <Flex.Item as="label" className={cn('f6 lh-tall')} htmlFor={name}>
100 {label}
101 </Flex.Item>
102 )}
103 <Flex.Item
104 className={cn('flex b1 flex-wrap', {
105 'b-green2': active && !disabled && !hasError,
106 'b-red3': active && !disabled && hasError,
107 })}>
108 {chips.map((chip, idx) => (
109 <Chip
110 key={idx}
111 value={chip}
112 disabled={disabled}
113 onDelete={handleDelete(idx)}
114 />
115 ))}
117 <input
118 type="textarea"
119 className="mv1 mh2 h7 b-none flex-grow"
120 placeholder="Enter an email address"
121 value={value}
122 name={name}
123 onChange={handleChange}
124 onKeyDown={handleKeyDown}
125 onBlur={handleBlur}
126 />
127 </Flex.Item>
128 {error && (
129 <Flex.Item as={ErrorText} className="mv1">
130 {error}
131 </Flex.Item>
132 )}
133 </Flex>
134 );
135};
137export default EmailChipInput;