on ea25a45 help sign in
bridge/src/form/EmailChipInput.jsx
122 lines 3.0 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';
5import { useFieldArray } from 'react-final-form-arrays';
7import { hasErrors } from 'form/validators';
9const Chip = ({ onDelete, disabled, name }) => {
10 const { input } = useField(name, { subscription: { value: true } });
11 return (
12 <Flex
13 className={cn('r32 ph2 m1 flex-center h7', {
14 'bg-gray2': !disabled,
15 'bg-gray1 gray4': disabled,
16 })}>
17 <Flex.Item>{input.value}</Flex.Item>
18 <Flex.Item
19 onClick={disabled ? undefined : onDelete}
20 className="ml1 f6 pointer-hover">
21 ✗
22 </Flex.Item>
23 </Flex>
24 );
25};
27const EmailChipInput = ({ className, name, label, disabled }) => {
28 const {
29 fields,
30 meta: { error, active },
31 } = useFieldArray(name, { subscription: { error: true, active: true } });
33 const [value, setValue] = useState('');
35 const handleChange = useCallback(
36 event => {
37 event.preventDefault();
38 setValue(event.target.value);
39 },
40 [setValue]
41 );
43 const addToChips = useCallback(() => {
44 fields.concat(value.split(/[\n\t, ]+/));
45 setValue('');
46 }, [value, fields, setValue]);
48 const handleKeyDown = useCallback(
49 event => {
50 if (['Enter', 'Tab', ',', ' '].includes(event.key) && value !== '') {
51 event.preventDefault();
52 addToChips();
53 } else if ('Backspace' === event.key && value === '') {
54 event.preventDefault();
55 fields.pop();
56 } else if (disabled) {
57 event.preventDefault();
58 }
59 },
60 [fields, value, disabled, addToChips]
61 );
63 const handleDelete = useCallback(
64 idx => () => {
65 fields.remove(idx);
66 },
67 [fields]
68 );
70 const handleBlur = useCallback(
71 e => {
72 e.preventDefault();
73 if (value !== '') {
74 addToChips();
75 }
76 },
77 [addToChips, value]
78 );
80 const hasError = hasErrors(error);
82 return (
83 <Flex col className={className}>
84 {label && (
85 <Flex.Item as="label" className={cn('f6 lh-tall')} htmlFor={name}>
86 {label}
87 </Flex.Item>
88 )}
89 <Flex.Item
90 className={cn('flex b1 flex-wrap', {
91 'b-green2': active && !disabled && !hasError,
92 'b-red3': active && !disabled && hasError,
93 })}>
94 {fields.map((name, idx) => (
95 <Chip
96 key={idx}
97 name={name}
98 disabled={disabled}
99 onDelete={handleDelete(idx)}
100 />
101 ))}
103 <input
104 type="textarea"
105 className="mv1 mh2 h7 b-none flex1"
106 placeholder="Enter an email address"
107 value={value}
108 onChange={handleChange}
109 onKeyDown={handleKeyDown}
110 onBlur={handleBlur}
111 />
112 </Flex.Item>
113 {error && (
114 <Flex.Item as={ErrorText} className="mv1">
115 {JSON.stringify(error)}
116 </Flex.Item>
117 )}
118 </Flex>
119 );
120};
122export default EmailChipInput;