1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
import React, {
FocusEvent,
FunctionComponent,
KeyboardEvent,
useCallback,
useMemo,
useRef,
useState,
} from "react";
import "./chip.scss";
const SplitKeys = ["Tab", "Enter", " ", ",", ";"];
export interface ChipsProps {
disabled?: boolean;
defaultValue?: readonly string[];
onChange?: (v: string[]) => void;
}
export const Chips: FunctionComponent<ChipsProps> = ({
defaultValue,
disabled,
onChange,
}) => {
const [chips, setChips] = useState(defaultValue ?? []);
const input = useRef<HTMLInputElement>(null);
const addChip = useCallback(
(value: string) => {
const newChips = [...chips];
newChips.push(value);
setChips(newChips);
onChange && onChange(newChips);
},
[chips, onChange]
);
const removeChip = useCallback(
(idx?: number) => {
idx = idx ?? chips.length - 1;
if (idx !== -1) {
const newChips = [...chips];
newChips.splice(idx, 1);
setChips(newChips);
onChange && onChange(newChips);
}
},
[chips, onChange]
);
const clearInput = useCallback(() => {
if (input.current) {
input.current.value = "";
}
}, [input]);
const onKeyUp = useCallback(
(event: KeyboardEvent<HTMLInputElement>) => {
const pressed = event.key;
const value = event.currentTarget.value;
if (SplitKeys.includes(pressed) && value.length !== 0) {
event.preventDefault();
addChip(value);
clearInput();
} else if (pressed === "Backspace" && value.length === 0) {
event.preventDefault();
removeChip();
}
},
[addChip, removeChip, clearInput]
);
const onKeyDown = useCallback((event: KeyboardEvent<HTMLInputElement>) => {
const pressed = event.key;
const value = event.currentTarget.value;
if (SplitKeys.includes(pressed) && value.length !== 0) {
event.preventDefault();
}
}, []);
const onBlur = useCallback(
(event: FocusEvent<HTMLInputElement>) => {
const value = event.currentTarget.value;
if (value.length !== 0) {
event.preventDefault();
addChip(value);
clearInput();
}
},
[addChip, clearInput]
);
const chipElements = useMemo(
() =>
chips.map((v, idx) => (
<span
key={idx}
title={v}
className={`custom-chip ${disabled ? "" : "active"}`}
onClick={() => {
if (!disabled) {
removeChip(idx);
}
}}
>
{v}
</span>
)),
[chips, removeChip, disabled]
);
return (
<div className="form-control custom-chip-input d-flex">
<div className="chip-container">{chipElements}</div>
<input
disabled={disabled}
className="main-input p-0"
ref={input}
onKeyUp={onKeyUp}
onKeyDown={onKeyDown}
onBlur={onBlur}
></input>
</div>
);
};
|