on c2ab9d2 help sign in
bridge/src/form/EmailChipInput.js
120 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 onClick={disabled ? onDelete : undefined} className="ml1 f6">
19 ✗
20 </Flex.Item>
21 </Flex>
22 );
23};
25const EmailChipInput = ({ className, name, label, disabled }) => {
26 const {
27 fields,
28 meta: { error, active },
29 } = useFieldArray(name, { subscription: { error: true, active: true } });
31 const [value, setValue] = useState('');
33 const handleChange = useCallback(
34 event => {
35 event.preventDefault();
36 setValue(event.target.value);
37 },
38 [setValue]
39 );
41 const addToChips = useCallback(() => {
42 fields.push(value);
43 setValue('');
44 }, [value, fields, setValue]);
46 const handleKeyDown = useCallback(
47 event => {
48 if (['Enter', 'Tab', ','].includes(event.key) && value !== '') {
49 event.preventDefault();
50 addToChips();
51 } else if ('Backspace' === event.key && value === '') {
52 event.preventDefault();
53 fields.pop();
54 } else if (disabled) {
55 event.preventDefault();
56 }
57 },
58 [fields, value, disabled, addToChips]
59 );
61 const handleDelete = useCallback(
62 idx => () => {
63 fields.remove(idx);
64 },
65 [fields]
66 );
68 const handleBlur = useCallback(
69 e => {
70 e.preventDefault();
71 if (value !== '') {
72 addToChips();
73 }
74 },
75 [addToChips, value]
76 );
78 const hasError = hasErrors(error);
80 return (
81 <Flex col className={className}>
82 {label && (
83 <Flex.Item as="label" className={cn('f6 lh-tall')} htmlFor={name}>
84 {label}
85 </Flex.Item>
86 )}
87 <Flex.Item
88 className={cn('flex b1 flex-wrap', {
89 'b-green2': active && !disabled && !hasError,
90 'b-red3': active && !disabled && hasError,
91 })}>
92 {fields.map((name, idx) => (
93 <Chip
94 key={idx}
95 name={name}
96 disabled={disabled}
97 onDelete={handleDelete(idx)}
98 />
99 ))}
101 <input
102 type="textarea"
103 className="mv1 mh2 h7 b-none flex-grow"
104 placeholder="Enter an email address"
105 value={value}
106 onChange={handleChange}
107 onKeyDown={handleKeyDown}
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;