playbook_ui 12.25.0.pre.alpha.play824786 → 12.25.0.pre.alpha.railsmultilevelimprovements758
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/_playbook.scss +0 -1
- data/app/pb_kits/playbook/index.js +0 -1
- data/app/pb_kits/playbook/pb_avatar/docs/_avatar_swift.md +1 -82
- data/app/pb_kits/playbook/pb_docs/kit_example.html.erb +13 -14
- data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +2 -3
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss +98 -58
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +102 -337
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_select_helper.tsx +31 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.html.erb +4 -4
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.md +1 -1
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.html.erb +0 -1
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_form.html.erb +72 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_multi_level_select/helper_functions.ts +87 -0
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb +3 -0
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.test.jsx +1 -1
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +44 -109
- data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +1 -3
- data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +0 -1
- data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +0 -6
- data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.test.js +62 -110
- data/app/pb_kits/playbook/playbook-doc.js +0 -2
- data/dist/menu.yml +0 -1
- data/dist/playbook-rails.js +7 -7
- data/lib/playbook/forms/builder/{intl_telephone_field.rb → multi_level_select_field.rb} +2 -2
- data/lib/playbook/forms/builder.rb +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +6 -26
- data/app/pb_kits/playbook/pb_detail/_detail.scss +0 -44
- data/app/pb_kits/playbook/pb_detail/_detail.tsx +0 -55
- data/app/pb_kits/playbook/pb_detail/_detail_mixins.scss +0 -29
- data/app/pb_kits/playbook/pb_detail/detail.html.erb +0 -7
- data/app/pb_kits/playbook/pb_detail/detail.rb +0 -31
- data/app/pb_kits/playbook/pb_detail/detail.test.jsx +0 -46
- data/app/pb_kits/playbook/pb_detail/docs/_description.md +0 -1
- data/app/pb_kits/playbook/pb_detail/docs/_detail_bold.html.erb +0 -34
- data/app/pb_kits/playbook/pb_detail/docs/_detail_bold.jsx +0 -49
- data/app/pb_kits/playbook/pb_detail/docs/_detail_bold.md +0 -1
- data/app/pb_kits/playbook/pb_detail/docs/_detail_colors.html.erb +0 -24
- data/app/pb_kits/playbook/pb_detail/docs/_detail_colors.jsx +0 -38
- data/app/pb_kits/playbook/pb_detail/docs/_detail_colors.md +0 -6
- data/app/pb_kits/playbook/pb_detail/docs/_detail_default.html.erb +0 -3
- data/app/pb_kits/playbook/pb_detail/docs/_detail_default.jsx +0 -13
- data/app/pb_kits/playbook/pb_detail/docs/_detail_styled.html.erb +0 -22
- data/app/pb_kits/playbook/pb_detail/docs/_detail_styled.jsx +0 -32
- data/app/pb_kits/playbook/pb_detail/docs/example.yml +0 -11
- data/app/pb_kits/playbook/pb_detail/docs/index.js +0 -4
- data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +0 -212
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.html.erb +0 -14
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.jsx +0 -60
- data/app/pb_kits/playbook/utilities/object.ts +0 -3
@@ -1,34 +1,20 @@
|
|
1
|
-
import React, { useState, useEffect,
|
1
|
+
import React, { useState, useEffect, useMemo } from "react";
|
2
2
|
import classnames from "classnames";
|
3
3
|
import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
|
4
|
-
import { globalProps
|
5
|
-
import
|
6
|
-
import
|
7
|
-
import FormPill from "../pb_form_pill/_form_pill";
|
8
|
-
import CircleIconButton from "../pb_circle_icon_button/_circle_icon_button";
|
9
|
-
import {
|
10
|
-
unCheckIt,
|
11
|
-
getAncestorsOfUnchecked,
|
12
|
-
unCheckedRecursive,
|
13
|
-
checkedRecursive,
|
14
|
-
filterFormattedDataById,
|
15
|
-
findByFilter,
|
16
|
-
getCheckedItems,
|
17
|
-
updateReturnItems,
|
18
|
-
recursiveReturnOnlyParent,
|
19
|
-
removeChildrenIfParentChecked,
|
20
|
-
getChildIds,
|
21
|
-
} from "./_helper_functions";
|
4
|
+
import { globalProps } from "../utilities/globalProps";
|
5
|
+
import { findItemById, checkIt, unCheckIt, getParentAndAncestorsIds } from "./helper_functions";
|
6
|
+
import MultiSelectHelper from "./_multi_select_helper";
|
22
7
|
|
23
8
|
type MultiLevelSelectProps = {
|
24
9
|
aria?: { [key: string]: string };
|
25
10
|
className?: string;
|
26
11
|
data?: { [key: string]: string };
|
27
12
|
id?: string;
|
13
|
+
name?: string;
|
28
14
|
returnAllSelected?: boolean;
|
29
15
|
treeData?: { [key: string]: string }[];
|
30
16
|
onSelect?: (prop: { [key: string]: any }) => void;
|
31
|
-
}
|
17
|
+
};
|
32
18
|
|
33
19
|
const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
34
20
|
const {
|
@@ -36,6 +22,7 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
36
22
|
className,
|
37
23
|
data = {},
|
38
24
|
id,
|
25
|
+
name,
|
39
26
|
returnAllSelected = false,
|
40
27
|
treeData,
|
41
28
|
onSelect = () => {},
|
@@ -49,343 +36,121 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
49
36
|
className
|
50
37
|
);
|
51
38
|
|
52
|
-
const dropdownRef = useRef(null);
|
53
|
-
|
54
|
-
//state for whether dropdown is open or closed
|
55
|
-
const [isClosed, setIsClosed] = useState(true);
|
56
|
-
//state from onchange for textinput, to use for filtering to create typeahead
|
57
|
-
const [filterItem, setFilterItem] = useState("");
|
58
|
-
//this is essentially the return that the user will get when they use the kit
|
59
|
-
const [returnedArray, setReturnedArray] = useState([]);
|
60
|
-
//formattedData with checked and parent_id added
|
61
39
|
const [formattedData, setFormattedData] = useState(treeData);
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
JSON.stringify(returnAllSelected ? returnedArray : defaultReturn)
|
74
|
-
);
|
75
|
-
}
|
76
|
-
returnAllSelected
|
77
|
-
? onSelect(returnedArray)
|
78
|
-
: onSelect(
|
79
|
-
defaultReturn.filter(
|
80
|
-
(item, index, self) =>
|
81
|
-
index === self.findIndex((obj) => obj.id === item.id)
|
82
|
-
)
|
83
|
-
);
|
84
|
-
}, [returnedArray, defaultReturn]);
|
85
|
-
|
86
|
-
useEffect(() => {
|
87
|
-
//Create new formattedData array for use
|
88
|
-
setFormattedData(addCheckedAndParentProperty(treeData));
|
89
|
-
// Function to handle clicks outside the dropdown
|
90
|
-
const handleClickOutside = (event: any) => {
|
91
|
-
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
92
|
-
setIsClosed(true);
|
93
|
-
}
|
94
|
-
};
|
95
|
-
//if any items already checked in first render, set return accordingly
|
96
|
-
const initialChecked = getCheckedItems(treeData)
|
97
|
-
initialChecked && returnAllSelected && setReturnedArray(initialChecked)
|
98
|
-
initialChecked && !returnAllSelected && setDefaultReturn(initialChecked)
|
99
|
-
|
100
|
-
// Attach the event listener
|
101
|
-
window.addEventListener("click", handleClickOutside);
|
102
|
-
// Clean up the event listener on unmount
|
103
|
-
return () => {
|
104
|
-
window.removeEventListener("click", handleClickOutside);
|
105
|
-
};
|
106
|
-
}, []);
|
107
|
-
|
108
|
-
//function to map over data and add parent_id + depth property to each item
|
109
|
-
const addCheckedAndParentProperty = (
|
110
|
-
treeData: { [key: string]: any }[],
|
111
|
-
parent_id: string = null,
|
112
|
-
depth: number = 0,
|
113
|
-
) => {
|
114
|
-
if (!Array.isArray(treeData)) {
|
115
|
-
return;
|
116
|
-
}
|
117
|
-
return treeData.map((item: { [key: string]: any } | any) => {
|
118
|
-
const newItem = {
|
119
|
-
...item,
|
120
|
-
parent_id,
|
121
|
-
depth,
|
122
|
-
};
|
123
|
-
if (newItem.children && newItem.children.length > 0) {
|
124
|
-
newItem.children = addCheckedAndParentProperty(
|
125
|
-
newItem.children,
|
126
|
-
newItem.id,
|
127
|
-
depth + 1,
|
128
|
-
);
|
129
|
-
}
|
130
|
-
return newItem;
|
131
|
-
});
|
132
|
-
};
|
133
|
-
|
134
|
-
//click event for x on form pill
|
135
|
-
const handlePillClose = (event: any, clickedItem: { [key: string]: any }) => {
|
136
|
-
// prevents the dropdown from closing when clicking on the pill
|
137
|
-
event.stopPropagation();
|
138
|
-
//logic for removing items from returnArray or defaultReturn when pills clicked
|
139
|
-
if (returnAllSelected) {
|
140
|
-
if (returnedArray.includes(clickedItem)) {
|
141
|
-
if (clickedItem.children && clickedItem.children.length > 0) {
|
142
|
-
const childrenOfChecked = getChildIds(clickedItem, returnedArray);
|
143
|
-
const updatedFiltered = returnedArray
|
144
|
-
.filter((item) => item !== clickedItem)
|
145
|
-
.filter((item) => !childrenOfChecked.includes(item.id));
|
146
|
-
setReturnedArray(updatedFiltered);
|
40
|
+
const [selectedItems, setSelectedItems] = useState([]);
|
41
|
+
const [checkedData, setCheckedData] = useState([]);
|
42
|
+
|
43
|
+
const onChange = (currentNode: { [key: string]: any }) => {
|
44
|
+
console.log("currentNode", currentNode)
|
45
|
+
const updatedData = formattedData.map((item: any) => {
|
46
|
+
if (item.id === currentNode._id) {
|
47
|
+
console.log("GETTING HERE --------- item", item)
|
48
|
+
if (currentNode.checked) {
|
49
|
+
console.log("GETTING HERE --------- currentNode.checked", currentNode.checked)
|
50
|
+
checkIt(item, selectedItems, setSelectedItems, false);
|
147
51
|
} else {
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
52
|
+
unCheckIt(item, selectedItems, setSelectedItems, false);
|
53
|
+
}
|
54
|
+
} else if (item.children) {
|
55
|
+
console.log("GETTING HERE --------- item.children", item.children)
|
56
|
+
const foundItem = findItemById(item.children, currentNode._id);
|
57
|
+
if (foundItem) {
|
58
|
+
console.log("GETTING HERE --------- foundItem", foundItem)
|
59
|
+
if (currentNode.checked) {
|
60
|
+
console.log("GETTING HERE --------- currentNode.checked other one", currentNode.checked)
|
61
|
+
checkIt(foundItem, selectedItems, setSelectedItems, false);
|
62
|
+
if (currentNode._parent) {
|
63
|
+
const parents = getParentAndAncestorsIds(currentNode._parent, formattedData)
|
64
|
+
parents.forEach((item:string) => {
|
65
|
+
const ancestor = findItemById(formattedData,item)
|
66
|
+
ancestor.expanded = true
|
67
|
+
});
|
68
|
+
}
|
69
|
+
} else {
|
70
|
+
unCheckIt(foundItem, selectedItems, setSelectedItems, false);
|
71
|
+
if (currentNode._parent) {
|
72
|
+
const parents = getParentAndAncestorsIds(currentNode._parent, formattedData)
|
73
|
+
parents.forEach((item:string) => {
|
74
|
+
const ancestor = findItemById(formattedData,item)
|
75
|
+
ancestor.expanded = true
|
76
|
+
});
|
77
|
+
}
|
78
|
+
}
|
152
79
|
}
|
153
80
|
}
|
154
|
-
} else {
|
155
|
-
if (defaultReturn.includes(clickedItem)) {
|
156
|
-
getAncestorsOfUnchecked(formattedData, clickedItem);
|
157
|
-
const newChecked = getCheckedItems(formattedData);
|
158
|
-
const filteredReturn = updateReturnItems(newChecked).filter(
|
159
|
-
(item) => item.id !== clickedItem.id
|
160
|
-
);
|
161
|
-
setDefaultReturn(filteredReturn);
|
162
|
-
}
|
163
|
-
}
|
164
|
-
if (clickedItem.children && clickedItem.children.length > 0) {
|
165
|
-
unCheckedRecursive(clickedItem);
|
166
|
-
}
|
167
|
-
//logic to uncheck clickedItem in formattedData
|
168
|
-
unCheckIt(formattedData, clickedItem.id);
|
169
|
-
};
|
170
81
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
e.target.id === "multiselect_input" ||
|
176
|
-
e.target.classList.contains("pb_form_pill_tag")
|
177
|
-
) {
|
178
|
-
return;
|
179
|
-
}
|
180
|
-
setIsClosed(!isClosed);
|
82
|
+
return item;
|
83
|
+
});
|
84
|
+
console.log("updatedData", updatedData)
|
85
|
+
setFormattedData(updatedData);
|
181
86
|
};
|
182
87
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
setFilterItem("");
|
188
|
-
|
189
|
-
const filtered = filterFormattedDataById(formattedData, clickedItem);
|
190
|
-
//check and uncheck all children of checked/unchecked parent item
|
191
|
-
if (filtered[0].children && filtered[0].children.length > 0) {
|
192
|
-
if (filtered[0].checked) {
|
193
|
-
filtered[0].children.forEach((item: { [key: string]: any }) => {
|
194
|
-
checkedRecursive(item);
|
195
|
-
});
|
196
|
-
} else if (!filtered[0].checked) {
|
197
|
-
filtered[0].children.forEach((item: { [key: string]: any }) => {
|
198
|
-
unCheckedRecursive(item);
|
199
|
-
});
|
200
|
-
}
|
201
|
-
}
|
202
|
-
|
203
|
-
const checkedItems = getCheckedItems(formattedData);
|
204
|
-
|
205
|
-
//checking and unchecking items for returnAllSelected variant
|
206
|
-
if (returnedArray.includes(filtered[0])) {
|
207
|
-
if (!filtered[0].checked) {
|
208
|
-
if (filtered[0].children && filtered[0].children.length > 0) {
|
209
|
-
const childrenOfChecked = getChildIds(filtered[0], returnedArray);
|
210
|
-
const updatedFiltered = returnedArray
|
211
|
-
.filter((item) => item !== filtered[0])
|
212
|
-
.filter((item) => !childrenOfChecked.includes(item.id));
|
213
|
-
|
214
|
-
setReturnedArray(updatedFiltered);
|
215
|
-
} else {
|
216
|
-
const updatedFiltered = returnedArray.filter(
|
217
|
-
(item) => item !== filtered[0]
|
218
|
-
);
|
219
|
-
setReturnedArray(updatedFiltered);
|
220
|
-
}
|
221
|
-
}
|
222
|
-
} else {
|
223
|
-
setReturnedArray(checkedItems);
|
88
|
+
const updateHiddenInputValue = (value: any) => {
|
89
|
+
const hiddenInput = document.querySelector('input#'+id) as HTMLInputElement;
|
90
|
+
if (hiddenInput) {
|
91
|
+
hiddenInput.value = JSON.stringify(value);
|
224
92
|
}
|
93
|
+
};
|
225
94
|
|
226
|
-
//when item is unchecked for default variant
|
227
|
-
if (!filtered[0].checked && !returnAllSelected) {
|
228
|
-
//uncheck parent and grandparent if any child unchecked
|
229
|
-
getAncestorsOfUnchecked(formattedData, filtered[0]);
|
230
95
|
|
231
|
-
|
232
|
-
|
233
|
-
const
|
234
|
-
|
96
|
+
useEffect(() => {
|
97
|
+
if (returnAllSelected) {
|
98
|
+
const selected = selectedItems.filter(
|
99
|
+
(item: { [key: string]: any }) => item.checked
|
100
|
+
);
|
101
|
+
//filter to remove duplicate items
|
102
|
+
const uniqueSelected = selected.filter(
|
103
|
+
(obj, index, self) => index === self.findIndex((t) => t.id === obj.id)
|
104
|
+
);
|
105
|
+
setCheckedData(uniqueSelected);
|
235
106
|
}
|
107
|
+
}, [selectedItems]);
|
236
108
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
removeChildrenIfParentChecked(
|
242
|
-
filtered[0],
|
243
|
-
defaultReturn,
|
244
|
-
setDefaultReturn
|
245
|
-
);
|
246
|
-
}
|
247
|
-
|
248
|
-
//if clicked item has parent_id, find parent and check if all children checked or not
|
249
|
-
if (filtered[0].parent_id !== null) {
|
250
|
-
recursiveReturnOnlyParent(
|
251
|
-
filtered[0],
|
252
|
-
formattedData,
|
253
|
-
defaultReturn,
|
254
|
-
setDefaultReturn
|
255
|
-
);
|
256
|
-
} else {
|
257
|
-
setDefaultReturn([filtered[0]]);
|
258
|
-
}
|
109
|
+
useEffect(() => {
|
110
|
+
let el = document.getElementById(`pb_data_wrapper_${id}`);
|
111
|
+
if (el) {
|
112
|
+
el.setAttribute("data-tree", JSON.stringify(checkedData));
|
259
113
|
}
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
const handleToggleClick = (id: string, event: React.MouseEvent) => {
|
264
|
-
event.stopPropagation();
|
265
|
-
setIsToggled((prevState: { [id: string]: boolean }) => ({
|
266
|
-
...prevState,
|
267
|
-
[id]: !prevState[id],
|
268
|
-
}));
|
269
|
-
const clickedItem = filterFormattedDataById(formattedData, id);
|
270
|
-
|
271
|
-
if (clickedItem) {
|
272
|
-
clickedItem[0].expanded = !clickedItem[0].expanded;
|
114
|
+
updateHiddenInputValue(checkedData);
|
115
|
+
if (returnAllSelected) {
|
116
|
+
onSelect(checkedData);
|
273
117
|
}
|
274
|
-
};
|
118
|
+
}, [checkedData]);
|
275
119
|
|
276
|
-
|
277
|
-
const renderNestedOptions = (items: { [key: string]: any }[]) => {
|
120
|
+
const DropDownSelectComponent = useMemo(() => {
|
278
121
|
return (
|
279
|
-
<
|
280
|
-
{
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
}
|
294
|
-
>
|
295
|
-
<CircleIconButton
|
296
|
-
icon={
|
297
|
-
item.expanded ? "chevron-down" : "chevron-right"
|
298
|
-
}
|
299
|
-
className={item.children && item.children.length > 0 ? "" : "toggle_icon"}
|
300
|
-
onClick={(event) => handleToggleClick(item.id, event)}
|
301
|
-
variant="link"
|
302
|
-
/>
|
303
|
-
</div>
|
304
|
-
<Checkbox text={item.label} id={item.id}>
|
305
|
-
<input
|
306
|
-
checked={item.checked}
|
307
|
-
type="checkbox"
|
308
|
-
name={item.label}
|
309
|
-
value={item.label}
|
310
|
-
onChange={(e) => {
|
311
|
-
item.checked = !item.checked;
|
312
|
-
handledropdownItemClick(e);
|
313
|
-
}}
|
314
|
-
/>
|
315
|
-
</Checkbox>
|
316
|
-
</div>
|
317
|
-
{item.expanded &&
|
318
|
-
item.children &&
|
319
|
-
item.children.length > 0 &&
|
320
|
-
!filterItem && ( // Show children if expanded is true
|
321
|
-
<div>{renderNestedOptions(item.children)}</div>
|
322
|
-
)}
|
323
|
-
</li>
|
324
|
-
</>
|
325
|
-
);
|
326
|
-
})}
|
327
|
-
</ul>
|
122
|
+
<MultiSelectHelper
|
123
|
+
treeData={formattedData}
|
124
|
+
onChange={(
|
125
|
+
// @ts-ignore
|
126
|
+
selectedNodes: { [key: string]: any }[],
|
127
|
+
currentNode: { [key: string]: any }[]
|
128
|
+
) => {
|
129
|
+
setCheckedData(currentNode);
|
130
|
+
onSelect(currentNode);
|
131
|
+
|
132
|
+
}}
|
133
|
+
id={id}
|
134
|
+
{...props}
|
135
|
+
/>
|
328
136
|
);
|
329
|
-
}
|
137
|
+
}, [formattedData])
|
330
138
|
|
331
139
|
return (
|
332
140
|
<div {...ariaProps} {...dataProps} className={classes} id={id}>
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
{!returnAllSelected &&
|
347
|
-
defaultReturn.length !== 0 &&
|
348
|
-
defaultReturn
|
349
|
-
.filter(
|
350
|
-
(item, index, self) =>
|
351
|
-
index === self.findIndex((obj) => obj.id === item.id)
|
352
|
-
)
|
353
|
-
.map((item, index) => (
|
354
|
-
<FormPill
|
355
|
-
key={index}
|
356
|
-
text={item.label}
|
357
|
-
size="small"
|
358
|
-
onClick={(event) => handlePillClose(event, item)}
|
359
|
-
/>
|
360
|
-
))}
|
361
|
-
{returnedArray.length !== 0 && returnAllSelected && <br />}
|
362
|
-
{defaultReturn.length !== 0 && !returnAllSelected && <br />}
|
363
|
-
<input
|
364
|
-
id="multiselect_input"
|
365
|
-
onChange={(e) => {
|
366
|
-
setFilterItem(e.target.value);
|
367
|
-
}}
|
368
|
-
placeholder="Start typing..."
|
369
|
-
value={filterItem}
|
370
|
-
onClick={() => setIsClosed(false)}
|
371
|
-
/>
|
372
|
-
</div>
|
373
|
-
{isClosed ? (
|
374
|
-
<div key="chevron-down">
|
375
|
-
<Icon icon="chevron-down" />
|
376
|
-
</div>
|
377
|
-
) : (
|
378
|
-
<div key="chevron-up">
|
379
|
-
<Icon icon="chevron-up" />
|
380
|
-
</div>
|
381
|
-
)}
|
382
|
-
</div>
|
383
|
-
<div className={`dropdown_menu ${isClosed ? "close" : "open"}`}>
|
384
|
-
{renderNestedOptions(
|
385
|
-
filterItem ? findByFilter(formattedData, filterItem) : formattedData
|
386
|
-
)}
|
387
|
-
</div>
|
388
|
-
</div>
|
141
|
+
|
142
|
+
<input type="hidden" id={id} name={name} value="" />
|
143
|
+
{returnAllSelected ? (
|
144
|
+
<MultiSelectHelper
|
145
|
+
treeData={formattedData}
|
146
|
+
treeMode={returnAllSelected}
|
147
|
+
id={id}
|
148
|
+
onChange={onChange}
|
149
|
+
{...props}
|
150
|
+
/>
|
151
|
+
) : (
|
152
|
+
<>{DropDownSelectComponent}</>
|
153
|
+
)}
|
389
154
|
</div>
|
390
155
|
);
|
391
156
|
};
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import React from "react"
|
2
|
+
import DropdownTreeSelect from "react-dropdown-tree-select"
|
3
|
+
import "react-dropdown-tree-select/dist/styles.css"
|
4
|
+
|
5
|
+
type HelperProps = {
|
6
|
+
id?: string
|
7
|
+
treeData?: { [key: string]: string }[]
|
8
|
+
treeMode?: boolean
|
9
|
+
onChange?: any
|
10
|
+
|
11
|
+
}
|
12
|
+
|
13
|
+
const MultiSelectHelper = (props: HelperProps) => {
|
14
|
+
const { id, treeData, onChange, treeMode } = props
|
15
|
+
|
16
|
+
|
17
|
+
return (
|
18
|
+
<DropdownTreeSelect
|
19
|
+
data={treeData}
|
20
|
+
id={id}
|
21
|
+
keepOpenOnSelect
|
22
|
+
keepTreeOnSearch
|
23
|
+
keepChildrenOnSearch
|
24
|
+
onChange={onChange}
|
25
|
+
texts={{ placeholder: "Select..." }}
|
26
|
+
mode={treeMode ? 'hierarchical' : 'multiSelect'}
|
27
|
+
/>
|
28
|
+
)
|
29
|
+
}
|
30
|
+
|
31
|
+
export default MultiSelectHelper
|
@@ -2,4 +2,4 @@ The MultiLevelSelect kit renders a multi leveled select dropdown based on data f
|
|
2
2
|
|
3
3
|
For the React version of the kit, the `onSelect` prop returns an array of all checked items, irrespective of whether it is a parent, child or grandchild. Open the console on this example and check and uncheck checkboxes to see this is action!
|
4
4
|
|
5
|
-
For the Rails version, the array of checked items is attached to the DOM in a data attribute titled `data-tree` on the wrapping div around
|
5
|
+
For the Rails version, the array of checked items is attached to the DOM in a data attribute titled `data-tree` on the wrapping div around the MultiLevelSelect.
|
@@ -0,0 +1,72 @@
|
|
1
|
+
<%= pb_form_with(scope: :example, url: "", method: :get) do |form| %>
|
2
|
+
|
3
|
+
<% treeData = [{
|
4
|
+
label: "Power Home Remodeling",
|
5
|
+
value: "Power Home Remodeling",
|
6
|
+
id: "powerhome1",
|
7
|
+
expanded: true,
|
8
|
+
children: [
|
9
|
+
{
|
10
|
+
label: "People",
|
11
|
+
value: "People",
|
12
|
+
id: "people1",
|
13
|
+
children: [
|
14
|
+
{
|
15
|
+
label: "Talent Acquisition",
|
16
|
+
value: "Talent Acquisition",
|
17
|
+
id: "talent1",
|
18
|
+
},
|
19
|
+
{
|
20
|
+
label: "Business Affairs",
|
21
|
+
value: "Business Affairs",
|
22
|
+
id: "business1",
|
23
|
+
children: [
|
24
|
+
{
|
25
|
+
label: "Initiatives",
|
26
|
+
value: "Initiatives",
|
27
|
+
id: "initiative1",
|
28
|
+
},
|
29
|
+
{
|
30
|
+
label: "Learning & Development",
|
31
|
+
value: "Learning & Development",
|
32
|
+
id: "development1",
|
33
|
+
},
|
34
|
+
],
|
35
|
+
},
|
36
|
+
{
|
37
|
+
label: "People Experience",
|
38
|
+
value: "People Experience",
|
39
|
+
id: "experience1",
|
40
|
+
},
|
41
|
+
],
|
42
|
+
},
|
43
|
+
{
|
44
|
+
label: "Contact Center",
|
45
|
+
value: "Contact Center",
|
46
|
+
id: "contact1",
|
47
|
+
children: [
|
48
|
+
{
|
49
|
+
label: "Appointment Management",
|
50
|
+
value: "Appointment Management",
|
51
|
+
id: "appointment1",
|
52
|
+
},
|
53
|
+
{
|
54
|
+
label: "Customer Service",
|
55
|
+
value: "Customer Service",
|
56
|
+
id: "customer1",
|
57
|
+
},
|
58
|
+
{
|
59
|
+
label: "Energy",
|
60
|
+
value: "Energy",
|
61
|
+
id: "energy1",
|
62
|
+
},
|
63
|
+
],
|
64
|
+
},
|
65
|
+
],
|
66
|
+
}] %>
|
67
|
+
|
68
|
+
<%= form.multi_level_select :example, props: {id: "with-form-multi-level-select", tree_data: treeData, return_all_selected: true } %>
|
69
|
+
<%= form.actions do |action| %>
|
70
|
+
<%= action.button props: { type: "submit", text: "Submit", variant: "primary", margin_top: "lg" } %>
|
71
|
+
<% end %>
|
72
|
+
<% end %>
|