gbs-add-block 0.0.32 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -4
- package/package.json +1 -1
- package/source/components/formrenderer/InputHandles.tsx +1 -1
- package/source/components/formrenderer/MultiHandles.tsx +64 -0
- package/source/components/formrenderer/SelectHandles.tsx +1 -1
- package/source/components/formrenderer/index.tsx +13 -0
- package/source/components/multiselect/index.tsx +205 -189
- package/source/components/multiselect/types.ts +14 -3
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# GBS Building Blocks 2.0 (v0.0.
|
|
1
|
+
# GBS Building Blocks 2.0 (v0.0.33)
|
|
2
2
|
|
|
3
3
|
Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
|
|
4
4
|
|
|
@@ -8,9 +8,7 @@ For detailed documentation on usage and props, Please visit: [Building Block Doc
|
|
|
8
8
|
|
|
9
9
|
## What's New 🎉 (Ver 0.0.23)
|
|
10
10
|
|
|
11
|
-
- Updated
|
|
12
|
-
- Updated Modal
|
|
13
|
-
- New Components (Material Input (Material Design Inspired Input), Form Renderer(Dynamic Form Rendering))
|
|
11
|
+
- Updated Form Renderer (Added Multi Select)
|
|
14
12
|
|
|
15
13
|
## Authors
|
|
16
14
|
|
package/package.json
CHANGED
|
@@ -52,7 +52,7 @@ const InputHandles = ({
|
|
|
52
52
|
name={item?.name}
|
|
53
53
|
placeholder={item?.placeholder || ""}
|
|
54
54
|
onChange={handleChange}
|
|
55
|
-
className={`border rounded
|
|
55
|
+
className={`border rounded-md px-4 py-[6px] w-full text-black ${
|
|
56
56
|
inputError || (item?.name && requirementError.includes(item?.name))
|
|
57
57
|
? "border-red-500"
|
|
58
58
|
: "border-gray-300"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FormItem } from "./types";
|
|
3
|
+
import { MultiSelect } from "../multiselect";
|
|
4
|
+
|
|
5
|
+
interface MultiSelectHandlesProps {
|
|
6
|
+
item?: FormItem;
|
|
7
|
+
requirementError: string[];
|
|
8
|
+
setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
|
|
9
|
+
formRef?: React.RefObject<HTMLFormElement | null>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function MultiHandles({
|
|
13
|
+
item,
|
|
14
|
+
requirementError,
|
|
15
|
+
setRequirementError,
|
|
16
|
+
formRef,
|
|
17
|
+
}: MultiSelectHandlesProps) {
|
|
18
|
+
const handleSelect = (value: string[], key: string) => {
|
|
19
|
+
if (formRef && formRef.current) {
|
|
20
|
+
const hiddenInput = formRef.current.querySelector(
|
|
21
|
+
`input[name="${key}"]`
|
|
22
|
+
) as HTMLInputElement;
|
|
23
|
+
|
|
24
|
+
if (hiddenInput) {
|
|
25
|
+
hiddenInput.value = Array.isArray(value)
|
|
26
|
+
? JSON.stringify(value)
|
|
27
|
+
: value;
|
|
28
|
+
} else {
|
|
29
|
+
const input = document.createElement("input");
|
|
30
|
+
input.type = "hidden";
|
|
31
|
+
input.name = key;
|
|
32
|
+
input.value = Array.isArray(value) ? JSON.stringify(value) : value;
|
|
33
|
+
formRef.current.appendChild(input);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className="w-full">
|
|
40
|
+
{item?.label && (
|
|
41
|
+
<label htmlFor={item.name} className="font-medium text-sm">
|
|
42
|
+
{item.label}
|
|
43
|
+
</label>
|
|
44
|
+
)}
|
|
45
|
+
<MultiSelect
|
|
46
|
+
name={item?.name}
|
|
47
|
+
items={item?.options}
|
|
48
|
+
onSelect={(value: string[]) => {
|
|
49
|
+
if (item?.name) {
|
|
50
|
+
handleSelect(value, item.name);
|
|
51
|
+
setRequirementError?.((prevErrors) =>
|
|
52
|
+
prevErrors.filter((errorName) => errorName !== item.name)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}}
|
|
56
|
+
error={
|
|
57
|
+
item?.name && requirementError.includes(item.name)
|
|
58
|
+
? `${item.name} is required`
|
|
59
|
+
: undefined
|
|
60
|
+
}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -45,7 +45,7 @@ export default function SelectHandles({
|
|
|
45
45
|
items={item?.options}
|
|
46
46
|
selectedItem={item?.value ?? ""}
|
|
47
47
|
onSelect={(value: string) => {
|
|
48
|
-
item?.
|
|
48
|
+
item?.name && handleSelect(value, item.name);
|
|
49
49
|
setRequirementError &&
|
|
50
50
|
setRequirementError((prevErrors: any) =>
|
|
51
51
|
prevErrors.filter((errorName: any) => errorName !== item?.name)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
/**
|
|
2
3
|
* Copyright (c) Grampro Business Services and affiliates.
|
|
3
4
|
*
|
|
@@ -9,6 +10,7 @@ import React, { useRef, useState } from "react";
|
|
|
9
10
|
import InputHandles from "./InputHandles";
|
|
10
11
|
import SelectHandles from "./SelectHandles";
|
|
11
12
|
import { FormItem, FormRendererProps } from "./types";
|
|
13
|
+
import MultiHandles from "./MultiHandles";
|
|
12
14
|
|
|
13
15
|
const FormRenderer = ({
|
|
14
16
|
onSubmit,
|
|
@@ -71,6 +73,17 @@ const FormRenderer = ({
|
|
|
71
73
|
/>
|
|
72
74
|
);
|
|
73
75
|
|
|
76
|
+
case "multi-select":
|
|
77
|
+
return (
|
|
78
|
+
<MultiHandles
|
|
79
|
+
key={index}
|
|
80
|
+
item={item}
|
|
81
|
+
requirementError={requirementError}
|
|
82
|
+
setRequirementError={setRequirementError}
|
|
83
|
+
formRef={formRef}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
|
|
74
87
|
case "button":
|
|
75
88
|
return (
|
|
76
89
|
<div key={index} className="w-full mt-1">
|
|
@@ -17,207 +17,223 @@ import React, {
|
|
|
17
17
|
import Icon from "../icon/Icon";
|
|
18
18
|
import { check, search, upDown, x } from "../icon/iconPaths";
|
|
19
19
|
import { getSourceData } from "../utils";
|
|
20
|
-
import type { MultiSelectProps } from "./types";
|
|
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
|
-
|
|
20
|
+
import type { ItemsProps, MultiSelectHandle, MultiSelectProps } from "./types";
|
|
21
|
+
import { primary } from "../globalStyle";
|
|
22
|
+
|
|
23
|
+
const MultiSelect = forwardRef<MultiSelectHandle, MultiSelectProps>(
|
|
24
|
+
(props, ref) => {
|
|
25
|
+
const {
|
|
26
|
+
placeholder = "Select Items...",
|
|
27
|
+
items,
|
|
28
|
+
lazy = false,
|
|
29
|
+
showSearch = true,
|
|
30
|
+
onSelect,
|
|
31
|
+
truncate = true,
|
|
32
|
+
selectedItems = [],
|
|
33
|
+
name,
|
|
34
|
+
error,
|
|
35
|
+
} = props;
|
|
36
|
+
|
|
37
|
+
const [showPopover, setShowPopover] = useState(false);
|
|
38
|
+
const [workingDataSource, setWorkingDataSource] = useState<ItemsProps[]>(
|
|
39
|
+
[]
|
|
40
|
+
);
|
|
41
|
+
const [filteredItems, setFilteredItems] = useState<ItemsProps[]>([]);
|
|
42
|
+
const [selected, setSelected] = useState<string[]>(selectedItems);
|
|
43
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
44
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
45
|
+
const selectRef = useRef<HTMLDivElement>(null);
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
inputRef.current?.focus();
|
|
49
|
+
}, [showPopover]);
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
handleDataSource();
|
|
53
|
+
}, [items]);
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
57
|
+
if (
|
|
58
|
+
selectRef.current &&
|
|
59
|
+
!selectRef.current.contains(event.target as Node)
|
|
60
|
+
) {
|
|
61
|
+
setShowPopover(false);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
65
|
+
return () =>
|
|
66
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
const getSelectItems = async (itemsApi: string) => {
|
|
70
|
+
const itemsData = await getSourceData(itemsApi);
|
|
71
|
+
setWorkingDataSource(itemsData.sourcedata);
|
|
72
|
+
setFilteredItems(itemsData.sourcedata);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const handleDataSource = async () => {
|
|
76
|
+
if (Array.isArray(items)) {
|
|
77
|
+
setWorkingDataSource(items);
|
|
78
|
+
setFilteredItems(items);
|
|
79
|
+
} else if (typeof items === "string") {
|
|
80
|
+
await getSelectItems(items);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const togglePopover = (e: React.MouseEvent) => {
|
|
85
|
+
e.stopPropagation();
|
|
86
|
+
setShowPopover(!showPopover);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const handleSelect = useCallback(
|
|
90
|
+
(value: string) => {
|
|
91
|
+
const newSelected = selected.includes(value)
|
|
92
|
+
? selected.filter((item) => item !== value)
|
|
93
|
+
: [...selected, value];
|
|
94
|
+
setSelected(newSelected);
|
|
95
|
+
onSelect?.(newSelected);
|
|
96
|
+
},
|
|
97
|
+
[selected, onSelect]
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const getSelectedDisplay = () => {
|
|
101
|
+
if (selected.length === 0) return placeholder;
|
|
102
|
+
const displayedItems = selected
|
|
103
|
+
.slice(0, 3)
|
|
104
|
+
.map(
|
|
105
|
+
(value) =>
|
|
106
|
+
workingDataSource.find((item) => item.value === value)?.label || ""
|
|
107
|
+
);
|
|
108
|
+
let display = displayedItems.join(", ");
|
|
109
|
+
if (selected.length > 3 && truncate) {
|
|
110
|
+
display += `, +${selected.length - 3} more`;
|
|
61
111
|
}
|
|
112
|
+
return display;
|
|
62
113
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const handleDataSource = async () => {
|
|
74
|
-
if (Array.isArray(items)) {
|
|
75
|
-
setWorkingDataSource(items);
|
|
76
|
-
setFilteredItems(items);
|
|
77
|
-
} else if (typeof items === "string") {
|
|
78
|
-
await getSelectItems(items);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const togglePopover = (e: React.MouseEvent) => {
|
|
83
|
-
e.stopPropagation();
|
|
84
|
-
setShowPopover(!showPopover);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const handleSelect = useCallback(
|
|
88
|
-
(value: string) => {
|
|
89
|
-
const newSelected = selected.includes(value)
|
|
90
|
-
? selected.filter((item) => item !== value)
|
|
91
|
-
: [...selected, value];
|
|
92
|
-
setSelected(newSelected);
|
|
93
|
-
onSelect?.(newSelected);
|
|
94
|
-
},
|
|
95
|
-
[selected, onSelect]
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
const getSelectedDisplay = () => {
|
|
99
|
-
if (selected.length === 0) return placeholder;
|
|
100
|
-
const displayedItems = selected
|
|
101
|
-
.slice(0, 3)
|
|
102
|
-
.map(
|
|
103
|
-
(value) =>
|
|
104
|
-
workingDataSource.find((item) => item.value === value)?.label || ""
|
|
105
|
-
);
|
|
106
|
-
let display = displayedItems.join(", ");
|
|
107
|
-
if (selected.length > 3 && truncate) {
|
|
108
|
-
display += `, +${selected.length - 3} more`;
|
|
109
|
-
}
|
|
110
|
-
return display;
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const inputSearchHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
114
|
-
const value = e.target.value.toLowerCase();
|
|
115
|
-
setSearchTerm(value);
|
|
116
|
-
if (!lazy) {
|
|
117
|
-
setFilteredItems(
|
|
118
|
-
workingDataSource.filter((item) =>
|
|
119
|
-
Object.values(item).some((val) =>
|
|
120
|
-
val.toString().toLowerCase().includes(value)
|
|
114
|
+
|
|
115
|
+
const inputSearchHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
116
|
+
const value = e.target.value.toLowerCase();
|
|
117
|
+
setSearchTerm(value);
|
|
118
|
+
if (!lazy) {
|
|
119
|
+
setFilteredItems(
|
|
120
|
+
workingDataSource.filter((item) =>
|
|
121
|
+
Object.values(item).some((val) =>
|
|
122
|
+
val.toString().toLowerCase().includes(value)
|
|
123
|
+
)
|
|
121
124
|
)
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
className="flex-grow text-sm text-left"
|
|
149
|
-
type="button"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const clearSelected = () => {
|
|
130
|
+
setSelected([]);
|
|
131
|
+
setShowPopover(false);
|
|
132
|
+
if (onSelect) onSelect([]);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
useImperativeHandle(ref, () => ({
|
|
136
|
+
workingDataSource,
|
|
137
|
+
items,
|
|
138
|
+
clearSelected,
|
|
139
|
+
togglePopover,
|
|
140
|
+
getSelectItems,
|
|
141
|
+
selectedDisplay: getSelectedDisplay(),
|
|
142
|
+
selected,
|
|
143
|
+
}));
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<div className="relative w-full" ref={selectRef}>
|
|
147
|
+
<div
|
|
148
|
+
className={`relative border w-full flex items-center px-4 py-2 rounded-lg ${
|
|
149
|
+
error && "border-red-500"
|
|
150
|
+
}`}
|
|
150
151
|
>
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
onClick={clearSelected}
|
|
158
|
-
type="button"
|
|
159
|
-
>
|
|
160
|
-
<Icon
|
|
161
|
-
elements={x}
|
|
162
|
-
svgClass="h-4 w-4 stroke-gray-500 fill-none dark:stroke-white"
|
|
163
|
-
/>
|
|
164
|
-
</button>
|
|
165
|
-
)}
|
|
166
|
-
<button onClick={togglePopover} type="button">
|
|
167
|
-
<Icon
|
|
168
|
-
elements={upDown}
|
|
169
|
-
svgClass="h-4 w-4 stroke-gray-500 fill-none dark:stroke-white"
|
|
170
|
-
/>
|
|
152
|
+
<button
|
|
153
|
+
onClick={togglePopover}
|
|
154
|
+
className="flex-grow text-sm text-left font-medium"
|
|
155
|
+
type="button"
|
|
156
|
+
>
|
|
157
|
+
{getSelectedDisplay()}
|
|
171
158
|
</button>
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
{showPopover && (
|
|
176
|
-
<div className="w-[200px] absolute overflow-y-auto border px-2 rounded-lg mt-[1px] scrollbar bg-white z-50 scrollbar h-auto dark:bg-black dark:text-white">
|
|
177
|
-
{showSearch && (
|
|
178
|
-
<div className="flex p-2 gap-1 items-center sticky top-0 bg-white border-b dark:bg-black">
|
|
179
|
-
<Icon
|
|
180
|
-
elements={search}
|
|
181
|
-
svgClass="stroke-gray-500 fill-none dark:stroke-white"
|
|
182
|
-
/>
|
|
183
|
-
<input
|
|
184
|
-
autoComplete="off"
|
|
185
|
-
type="text"
|
|
186
|
-
name="search"
|
|
187
|
-
id="search"
|
|
188
|
-
placeholder="Search a value"
|
|
189
|
-
className="w-full outline-none dark:bg-black"
|
|
190
|
-
ref={inputRef}
|
|
191
|
-
value={searchTerm}
|
|
192
|
-
onChange={inputSearchHandler}
|
|
193
|
-
/>
|
|
194
|
-
</div>
|
|
195
|
-
)}
|
|
196
|
-
{filteredItems.length > 0 ? (
|
|
197
|
-
filteredItems.map(({ value, label }) => (
|
|
159
|
+
<div className="flex items-center space-x-2">
|
|
160
|
+
{selected.length > 0 && (
|
|
198
161
|
<button
|
|
162
|
+
className="flex items-center px-2"
|
|
163
|
+
onClick={clearSelected}
|
|
199
164
|
type="button"
|
|
200
|
-
key={value}
|
|
201
|
-
className="flex items-center w-full px-2 py-1 text-left hover:bg-blue-100 gap-2 rounded-lg mt-1 text-sm dark:hover:bg-blue-600"
|
|
202
|
-
onClick={() => handleSelect(value)}
|
|
203
165
|
>
|
|
204
166
|
<Icon
|
|
205
|
-
elements={
|
|
206
|
-
svgClass=
|
|
207
|
-
selected.includes(value) ? "stroke-gray-500" : ""
|
|
208
|
-
}`}
|
|
167
|
+
elements={x}
|
|
168
|
+
svgClass="h-4 w-4 stroke-gray-500 fill-none dark:stroke-white"
|
|
209
169
|
/>
|
|
210
|
-
{label}
|
|
211
170
|
</button>
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
171
|
+
)}
|
|
172
|
+
<button onClick={togglePopover} type="button">
|
|
173
|
+
<Icon
|
|
174
|
+
elements={upDown}
|
|
175
|
+
svgClass="h-4 w-4 stroke-gray-500 fill-none dark:stroke-white"
|
|
176
|
+
/>
|
|
177
|
+
</button>
|
|
178
|
+
</div>
|
|
216
179
|
</div>
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
180
|
+
<p className={primary["error-primary"]}>{error && error}</p>
|
|
181
|
+
|
|
182
|
+
{/* Hidden input to integrate with the form */}
|
|
183
|
+
<input
|
|
184
|
+
type="hidden"
|
|
185
|
+
name={name}
|
|
186
|
+
value={JSON.stringify(selected) || ""}
|
|
187
|
+
readOnly
|
|
188
|
+
/>
|
|
189
|
+
|
|
190
|
+
{showPopover && (
|
|
191
|
+
<div className="w-full absolute overflow-y-auto border px-2 rounded-lg mt-[1px] scrollbar bg-white z-50 scrollbar h-auto dark:bg-black dark:text-white">
|
|
192
|
+
{showSearch && (
|
|
193
|
+
<div className="flex p-2 gap-1 items-center sticky top-0 bg-white border-b dark:bg-black">
|
|
194
|
+
<Icon
|
|
195
|
+
elements={search}
|
|
196
|
+
svgClass="stroke-gray-500 fill-none dark:stroke-white"
|
|
197
|
+
/>
|
|
198
|
+
<input
|
|
199
|
+
autoComplete="off"
|
|
200
|
+
type="text"
|
|
201
|
+
name="search"
|
|
202
|
+
id="search"
|
|
203
|
+
placeholder="Search a value"
|
|
204
|
+
className="w-full outline-none dark:bg-black"
|
|
205
|
+
ref={inputRef}
|
|
206
|
+
value={searchTerm}
|
|
207
|
+
onChange={inputSearchHandler}
|
|
208
|
+
/>
|
|
209
|
+
</div>
|
|
210
|
+
)}
|
|
211
|
+
{filteredItems.length > 0 ? (
|
|
212
|
+
filteredItems.map(({ value, label }) => (
|
|
213
|
+
<button
|
|
214
|
+
type="button"
|
|
215
|
+
key={value}
|
|
216
|
+
className="flex items-center w-full px-2 py-1 text-left hover:bg-blue-100 gap-2 rounded-lg mt-1 text-sm dark:hover:bg-blue-600"
|
|
217
|
+
onClick={() => handleSelect(value)}
|
|
218
|
+
>
|
|
219
|
+
<Icon
|
|
220
|
+
elements={check}
|
|
221
|
+
svgClass={`h-4 w-4 fill-none ${
|
|
222
|
+
selected.includes(value) ? "stroke-gray-500" : ""
|
|
223
|
+
}`}
|
|
224
|
+
/>
|
|
225
|
+
{label}
|
|
226
|
+
</button>
|
|
227
|
+
))
|
|
228
|
+
) : (
|
|
229
|
+
<div className="text-sm text-center">No Data Found</div>
|
|
230
|
+
)}
|
|
231
|
+
</div>
|
|
232
|
+
)}
|
|
233
|
+
</div>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
);
|
|
221
237
|
|
|
222
238
|
const MemoizedMultiSelect = memo(MultiSelect);
|
|
223
239
|
export { MemoizedMultiSelect as MultiSelect };
|
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
export type ItemsProps = {
|
|
2
2
|
value: string;
|
|
3
3
|
label: string;
|
|
4
|
-
}
|
|
4
|
+
};
|
|
5
5
|
|
|
6
6
|
export type MultiSelectProps = {
|
|
7
7
|
placeholder?: string;
|
|
8
8
|
items?: ItemsProps[] | string;
|
|
9
9
|
lazy?: boolean;
|
|
10
10
|
showSearch?: boolean;
|
|
11
|
-
onSelect?:
|
|
11
|
+
onSelect?: (selectedItem: string[]) => void;
|
|
12
12
|
truncate?: boolean;
|
|
13
13
|
selectedItems?: string[];
|
|
14
|
+
name?: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type MultiSelectHandle = {
|
|
19
|
+
workingDataSource: ItemsProps[];
|
|
20
|
+
clearSelected: () => void;
|
|
21
|
+
togglePopover: (e: React.MouseEvent) => void;
|
|
22
|
+
getSelectItems: (itemsApi: string) => Promise<void>;
|
|
23
|
+
selectedDisplay: string;
|
|
24
|
+
selected: string[] | undefined;
|
|
14
25
|
};
|