-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathOptions.tsx
More file actions
executable file
·123 lines (105 loc) · 3.67 KB
/
Options.tsx
File metadata and controls
executable file
·123 lines (105 loc) · 3.67 KB
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
import React, { useCallback, useContext, useMemo } from "react";
import { twMerge } from "tailwind-merge";
import { DEFAULT_THEME } from "../constants";
import DisabledItem from "./DisabledItem";
import GroupItem from "./GroupItem";
import Item from "./Item";
import { SelectContext } from "./SelectProvider";
import { Option, Options as ListOption } from "./type";
interface OptionsProps {
list: ListOption;
noOptionsMessage: string;
text: string;
isMultiple: boolean;
value: Option | Option[] | null;
primaryColor: string;
}
const Options: React.FC<OptionsProps> = ({
list,
noOptionsMessage,
text,
isMultiple,
value,
primaryColor = DEFAULT_THEME
}) => {
const { classNames } = useContext(SelectContext);
const filterByText = useCallback(() => {
const filterItem = (item: Option) => {
return item.label.toLowerCase().indexOf(text.toLowerCase()) > -1;
};
let result = list.map(item => {
if ("options" in item) {
return {
label: item.label,
options: item.options.filter(filterItem)
};
}
return item;
});
result = result.filter(item => {
if ("options" in item) {
return item.options.length > 0;
}
return filterItem(item);
});
return result;
}, [text, list]);
const removeValues = useCallback(
(array: ListOption) => {
if (!isMultiple) {
return array;
}
if (Array.isArray(value)) {
const valueId = value.map(item => item.value);
const filterItem = (item: Option) => !valueId.includes(item.value);
let newArray = array.map(item => {
if ("options" in item) {
return {
label: item.label,
options: item.options.filter(filterItem)
};
}
return item;
});
newArray = newArray.filter(item => {
if ("options" in item) {
return item.options.length > 0;
} else {
return filterItem(item);
}
});
return newArray;
}
return array;
},
[isMultiple, value]
);
const filterResult = useMemo(() => {
return removeValues(filterByText());
}, [filterByText, removeValues]);
return (
<div role="options" className={twMerge("max-h-72 overflow-y-auto", classNames?.list)}>
{filterResult.map((item, index) => (
<React.Fragment key={index}>
{"options" in item ? (
<>
<div className="px-2.5">
<GroupItem
primaryColor={primaryColor || DEFAULT_THEME}
item={item}
/>
</div>
{index + 1 < filterResult.length && <hr className="my-1" />}
</>
) : (
<div className="px-2.5">
<Item primaryColor={primaryColor || DEFAULT_THEME} item={item} />
</div>
)}
</React.Fragment>
))}
{filterResult.length === 0 && <DisabledItem>{noOptionsMessage}</DisabledItem>}
</div>
);
};
export default Options;