on 0000e51 help sign in
bridge/src/form/EmailChipInput.js
120 lines 2.8 kB history raw
1import React, { useState, useCallback } from 'react';
2import { Flex, ErrorText } from 'indigo-react';
3import cn from 'classnames';
4import { useField } from 'react-final-form';
6import { hasErrors } from 'form/validators';
8const Chip = ({ value, onDelete }) => {
9 return (
10 <Flex className="r32 ph2 m1 flex-center h7 bg-gray2">
11 <Flex.Item>{value}</Flex.Item>
12 <Flex.Item onClick={onDelete} className="ml1 f6">
13 ✗
14 </Flex.Item>
15 </Flex>
16 );
17};
19const EmailChipInput = ({ className, name, label }) => {
20 const [chips, _setChips] = useState([]);
22 const [value, setValue] = useState('');
24 const handleChange = useCallback(
25 event => {
26 setValue(event.target.value);
27 },
28 [setValue]
29 );
31 const {
32 input,
33 meta: { active, error },
34 } = useField(name, {
35 subscription: { active: true, error: true },
36 });
38 const setChips = useCallback(
39 chips => {
40 _setChips(chips);
41 input.onChange(chips);
42 },
43 [input, _setChips]
44 );
46 const addToChips = useCallback(() => {
47 setChips([...chips, value]);
48 setValue('');
49 }, [chips, value, setChips]);
51 const handleKeyDown = useCallback(
52 event => {
53 if (['Enter', 'Tab', ','].includes(event.key) && value !== '') {
54 event.preventDefault();
55 addToChips();
56 } else if ('Backspace' === event.key && value === '') {
57 event.preventDefault();
58 setChips(chips.slice(0, -1));
59 }
60 },
61 [setChips, chips, value]
62 );
64 const handleDelete = useCallback(
65 idx => () => {
66 setChips([...chips.slice(0, idx), ...chips.slice(idx + 1)]);
67 },
68 [setChips, chips]
69 );
71 const handleBlur = useCallback(
72 e => {
73 if (value !== '') {
74 addToChips();
75 input.handleBlur();
76 }
77 },
78 [addToChips, value]
79 );
81 const hasError = hasErrors(error);
83 return (
84 <Flex col className={className}>
85 {label && (
86 <Flex.Item as="label" className={cn('f6 lh-tall')} htmlFor={name}>
87 {label}
88 </Flex.Item>
89 )}
90 <Flex.Item
91 className={cn('flex b1 flex-wrap', {
92 'b-green2': active && !hasError,
93 'b-red3': active && hasError,
94 })}>
95 {chips.map((chip, idx) => (
96 <Chip key={idx} value={chip} onDelete={handleDelete(idx)} />
97 ))}
99 <input
100 type="textarea"
101 className="mv1 mh2 h7 b-none flex-grow"
102 placeholder="Enter an email address"
103 value={value}
104 name={name}
105 onChange={handleChange}
106 onKeyDown={handleKeyDown}
107 onFocus={input.onFocus}
108 onBlur={handleBlur}
109 />
110 </Flex.Item>
111 {error && (
112 <Flex.Item as={ErrorText} className="mv1">
113 {error}
114 </Flex.Item>
115 )}
116 </Flex>
117 );
118};
120export default EmailChipInput;