playbook_ui 12.26.0.pre.alpha.multiselectfixes825 → 12.26.0.pre.alpha.railsmultilevelimprovements805
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/pb_multi_level_select/_helper_functions.tsx +125 -47
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +259 -190
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.html.erb +2 -2
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +1 -1
- 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 +1 -2
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.jsx +1 -1
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_complete_data.html.erb +73 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_complete_data.jsx +87 -0
- 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 +3 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb +6 -0
- data/dist/playbook-rails.js +5 -5
- data/lib/playbook/forms/builder/multi_level_select_field.rb +12 -0
- data/lib/playbook/forms/builder.rb +1 -0
- data/lib/playbook/version.rb +1 -1
- metadata +6 -2
@@ -1,31 +1,36 @@
|
|
1
|
-
import React, { useState, useEffect, useRef } from "react"
|
2
|
-
import classnames from "classnames"
|
3
|
-
import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props"
|
4
|
-
import { globalProps, GlobalProps } from "../utilities/globalProps"
|
5
|
-
import Icon from "../pb_icon/_icon"
|
6
|
-
import Checkbox from "../pb_checkbox/_checkbox"
|
7
|
-
import FormPill from "../pb_form_pill/_form_pill"
|
8
|
-
import CircleIconButton from "../pb_circle_icon_button/_circle_icon_button"
|
9
|
-
import { cloneDeep } from "lodash";
|
10
|
-
|
1
|
+
import React, { useState, useEffect, useRef } from "react"
|
2
|
+
import classnames from "classnames"
|
3
|
+
import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props"
|
4
|
+
import { globalProps, GlobalProps } from "../utilities/globalProps"
|
5
|
+
import Icon from "../pb_icon/_icon"
|
6
|
+
import Checkbox from "../pb_checkbox/_checkbox"
|
7
|
+
import FormPill from "../pb_form_pill/_form_pill"
|
8
|
+
import CircleIconButton from "../pb_circle_icon_button/_circle_icon_button"
|
11
9
|
import {
|
10
|
+
unCheckIt,
|
12
11
|
getAncestorsOfUnchecked,
|
12
|
+
unCheckedRecursive,
|
13
|
+
checkedRecursive,
|
13
14
|
filterFormattedDataById,
|
14
15
|
findByFilter,
|
15
16
|
getCheckedItems,
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
updateReturnItems,
|
18
|
+
recursiveReturnOnlyParent,
|
19
|
+
removeChildrenIfParentChecked,
|
20
|
+
getChildIds,
|
21
|
+
} from "./_helper_functions"
|
19
22
|
|
20
23
|
type MultiLevelSelectProps = {
|
21
|
-
aria?: { [key: string]: string }
|
22
|
-
className?: string
|
23
|
-
data?: { [key: string]: string }
|
24
|
-
id?: string
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
aria?: { [key: string]: string }
|
25
|
+
className?: string
|
26
|
+
data?: { [key: string]: string }
|
27
|
+
id?: string
|
28
|
+
name?: string
|
29
|
+
returnCompleteData?: boolean
|
30
|
+
returnAllSelected?: boolean
|
31
|
+
treeData?: { [key: string]: string }[]
|
32
|
+
onSelect?: (prop: { [key: string]: any }) => void
|
33
|
+
} & GlobalProps
|
29
34
|
|
30
35
|
const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
31
36
|
const {
|
@@ -33,121 +38,100 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
33
38
|
className,
|
34
39
|
data = {},
|
35
40
|
id,
|
41
|
+
name,
|
36
42
|
returnAllSelected = false,
|
43
|
+
returnCompleteData = false,
|
37
44
|
treeData,
|
38
45
|
onSelect = () => {},
|
39
|
-
} = props
|
46
|
+
} = props
|
40
47
|
|
41
|
-
const ariaProps = buildAriaProps(aria)
|
42
|
-
const dataProps = buildDataProps(data)
|
48
|
+
const ariaProps = buildAriaProps(aria)
|
49
|
+
const dataProps = buildDataProps(data)
|
43
50
|
const classes = classnames(
|
44
51
|
buildCss("pb_multi_level_select"),
|
45
52
|
globalProps(props),
|
46
53
|
className
|
47
|
-
)
|
54
|
+
)
|
48
55
|
|
49
|
-
const dropdownRef = useRef(null)
|
56
|
+
const dropdownRef = useRef(null)
|
50
57
|
|
51
|
-
//state for expanded property
|
52
|
-
const [expanded, setExpanded] = useState([]);
|
53
58
|
//state for whether dropdown is open or closed
|
54
|
-
const [isClosed, setIsClosed] = useState(true)
|
59
|
+
const [isClosed, setIsClosed] = useState(true)
|
55
60
|
//state from onchange for textinput, to use for filtering to create typeahead
|
56
|
-
const [filterItem, setFilterItem] = useState("")
|
61
|
+
const [filterItem, setFilterItem] = useState("")
|
57
62
|
//this is essentially the return that the user will get when they use the kit
|
58
|
-
const [returnedArray, setReturnedArray] = useState([])
|
63
|
+
const [returnedArray, setReturnedArray] = useState([])
|
59
64
|
//formattedData with checked and parent_id added
|
60
|
-
const [formattedData, setFormattedData] = useState(
|
65
|
+
const [formattedData, setFormattedData] = useState(treeData)
|
66
|
+
//toggle chevron in dropdown
|
67
|
+
//@ts-ignore
|
68
|
+
const [isToggled, setIsToggled] = useState<{ [id: number]: boolean }>({})
|
61
69
|
//state for return for default
|
62
|
-
const [defaultReturn, setDefaultReturn] = useState([])
|
70
|
+
const [defaultReturn, setDefaultReturn] = useState([])
|
63
71
|
|
64
|
-
|
65
|
-
setFormattedData(addCheckedAndParentProperty(treeData));
|
66
|
-
}, [treeData]);
|
72
|
+
const [formattedReturn, setFormattedReturn] = useState([])
|
67
73
|
|
68
|
-
|
69
|
-
|
70
|
-
|
74
|
+
const getSelectedIds = (selectedData: { [key: string]: any }[]) => {
|
75
|
+
return selectedData
|
76
|
+
.map((item) => item.id)
|
77
|
+
.filter((value, index, self) => self.indexOf(value) === index)
|
78
|
+
}
|
79
|
+
|
80
|
+
const getValues = () => {
|
81
|
+
if(returnCompleteData){
|
82
|
+
if(returnAllSelected){
|
83
|
+
return setFormattedReturn(returnedArray)
|
71
84
|
} else {
|
72
|
-
|
85
|
+
return setFormattedReturn(defaultReturn)
|
86
|
+
}
|
87
|
+
} else {
|
88
|
+
if(returnAllSelected){
|
89
|
+
setFormattedReturn(getSelectedIds(returnedArray))
|
90
|
+
} else {
|
91
|
+
setFormattedReturn(getSelectedIds(defaultReturn))
|
92
|
+
}
|
73
93
|
}
|
74
|
-
}
|
94
|
+
}
|
95
|
+
|
96
|
+
const updateHiddenInputValue = (value: any) => {
|
97
|
+
const hiddenInput = document.querySelector(
|
98
|
+
"input#" + id
|
99
|
+
) as HTMLInputElement
|
100
|
+
if (hiddenInput) {
|
101
|
+
hiddenInput.value = JSON.stringify(value)
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
useEffect(() => {
|
106
|
+
getValues()
|
107
|
+
}, [returnedArray, defaultReturn])
|
75
108
|
|
76
109
|
useEffect(() => {
|
110
|
+
onSelect(formattedReturn)
|
111
|
+
updateHiddenInputValue(formattedReturn)
|
112
|
+
}, [formattedReturn])
|
113
|
+
|
114
|
+
useEffect(() => {
|
115
|
+
//Create new formattedData array for use
|
116
|
+
setFormattedData(addCheckedAndParentProperty(treeData))
|
77
117
|
// Function to handle clicks outside the dropdown
|
78
118
|
const handleClickOutside = (event: any) => {
|
79
119
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
80
|
-
setIsClosed(true)
|
120
|
+
setIsClosed(true)
|
81
121
|
}
|
82
|
-
}
|
122
|
+
}
|
123
|
+
//if any items already checked in first render, set return accordingly
|
124
|
+
const initialChecked = getCheckedItems(treeData)
|
125
|
+
initialChecked && returnAllSelected && setReturnedArray(initialChecked)
|
126
|
+
initialChecked && !returnAllSelected && setDefaultReturn(initialChecked)
|
127
|
+
|
83
128
|
// Attach the event listener
|
84
|
-
window.addEventListener("click", handleClickOutside)
|
129
|
+
window.addEventListener("click", handleClickOutside)
|
85
130
|
// Clean up the event listener on unmount
|
86
131
|
return () => {
|
87
|
-
window.removeEventListener("click", handleClickOutside)
|
88
|
-
};
|
89
|
-
}, []);
|
90
|
-
|
91
|
-
const modifyRecursive = (tree: { [key: string]: any }[], check: boolean) => {
|
92
|
-
if (!Array.isArray(tree)) {
|
93
|
-
return;
|
94
|
-
}
|
95
|
-
return tree.map((item: { [key: string]: any }) => {
|
96
|
-
item.checked = check;
|
97
|
-
item.children = modifyRecursive(item.children, check);
|
98
|
-
return item;
|
99
|
-
});
|
100
|
-
};
|
101
|
-
|
102
|
-
//iterate over tree, find item and set checked or unchecked
|
103
|
-
const modifyValue = (
|
104
|
-
id: string,
|
105
|
-
tree: { [key: string]: any }[],
|
106
|
-
check: boolean
|
107
|
-
) => {
|
108
|
-
if (!Array.isArray(tree)) {
|
109
|
-
return;
|
132
|
+
window.removeEventListener("click", handleClickOutside)
|
110
133
|
}
|
111
|
-
|
112
|
-
if (item.id != id) item.children = modifyValue(id, item.children, check);
|
113
|
-
else {
|
114
|
-
item.checked = check;
|
115
|
-
item.children = modifyRecursive(item.children, check);
|
116
|
-
}
|
117
|
-
|
118
|
-
return item;
|
119
|
-
});
|
120
|
-
};
|
121
|
-
|
122
|
-
//clone tree, check items + children
|
123
|
-
const checkItem = (item: { [key: string]: any }) => {
|
124
|
-
const tree = cloneDeep(formattedData);
|
125
|
-
if (returnAllSelected) {
|
126
|
-
return modifyValue(item.id, tree, true);
|
127
|
-
} else {
|
128
|
-
const checkedTree = modifyValue(item.id, tree, true);
|
129
|
-
return recursiveCheckParent(item, checkedTree);
|
130
|
-
}
|
131
|
-
};
|
132
|
-
|
133
|
-
//clone tree, uncheck items + children
|
134
|
-
const unCheckItem = (item: { [key: string]: any }) => {
|
135
|
-
const tree = cloneDeep(formattedData);
|
136
|
-
if (returnAllSelected) {
|
137
|
-
return modifyValue(item.id, tree, false);
|
138
|
-
} else {
|
139
|
-
const uncheckedTree = modifyValue(item.id, tree, false);
|
140
|
-
return getAncestorsOfUnchecked(uncheckedTree, item);
|
141
|
-
}
|
142
|
-
};
|
143
|
-
|
144
|
-
//setformattedData with proper properties
|
145
|
-
const changeItem = (item: { [key: string]: any }, check: boolean) => {
|
146
|
-
const tree = check ? checkItem(item) : unCheckItem(item);
|
147
|
-
setFormattedData(tree);
|
148
|
-
|
149
|
-
return tree;
|
150
|
-
};
|
134
|
+
}, [])
|
151
135
|
|
152
136
|
//function to map over data and add parent_id + depth property to each item
|
153
137
|
const addCheckedAndParentProperty = (
|
@@ -156,87 +140,166 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
156
140
|
depth: number = 0
|
157
141
|
) => {
|
158
142
|
if (!Array.isArray(treeData)) {
|
159
|
-
return
|
143
|
+
return
|
160
144
|
}
|
161
145
|
return treeData.map((item: { [key: string]: any } | any) => {
|
162
146
|
const newItem = {
|
163
147
|
...item,
|
164
148
|
parent_id,
|
165
149
|
depth,
|
166
|
-
}
|
150
|
+
}
|
167
151
|
if (newItem.children && newItem.children.length > 0) {
|
168
|
-
const children =
|
169
|
-
item.checked && !returnAllSelected
|
170
|
-
? modifyRecursive(item.children, true)
|
171
|
-
: item.children;
|
172
152
|
newItem.children = addCheckedAndParentProperty(
|
173
|
-
children,
|
153
|
+
newItem.children,
|
174
154
|
newItem.id,
|
175
155
|
depth + 1
|
176
|
-
)
|
156
|
+
)
|
177
157
|
}
|
178
|
-
return newItem
|
179
|
-
})
|
180
|
-
}
|
158
|
+
return newItem
|
159
|
+
})
|
160
|
+
}
|
181
161
|
|
182
162
|
//click event for x on form pill
|
183
163
|
const handlePillClose = (event: any, clickedItem: { [key: string]: any }) => {
|
184
164
|
// prevents the dropdown from closing when clicking on the pill
|
185
|
-
event.stopPropagation()
|
186
|
-
const updatedTree = changeItem(clickedItem, false);
|
165
|
+
event.stopPropagation()
|
187
166
|
//logic for removing items from returnArray or defaultReturn when pills clicked
|
188
167
|
if (returnAllSelected) {
|
189
|
-
|
168
|
+
if (returnedArray.includes(clickedItem)) {
|
169
|
+
if (clickedItem.children && clickedItem.children.length > 0) {
|
170
|
+
const childrenOfChecked = getChildIds(clickedItem, returnedArray)
|
171
|
+
const updatedFiltered = returnedArray
|
172
|
+
.filter((item) => item !== clickedItem)
|
173
|
+
.filter((item) => !childrenOfChecked.includes(item.id))
|
174
|
+
setReturnedArray(updatedFiltered)
|
175
|
+
} else {
|
176
|
+
const updatedFiltered = returnedArray.filter(
|
177
|
+
(item) => item !== clickedItem
|
178
|
+
)
|
179
|
+
setReturnedArray(updatedFiltered)
|
180
|
+
}
|
181
|
+
}
|
190
182
|
} else {
|
191
|
-
|
183
|
+
if (defaultReturn.includes(clickedItem)) {
|
184
|
+
getAncestorsOfUnchecked(formattedData, clickedItem)
|
185
|
+
const newChecked = getCheckedItems(formattedData)
|
186
|
+
const filteredReturn = updateReturnItems(newChecked).filter(
|
187
|
+
(item) => item.id !== clickedItem.id
|
188
|
+
)
|
189
|
+
setDefaultReturn(filteredReturn)
|
190
|
+
}
|
192
191
|
}
|
193
|
-
|
192
|
+
if (clickedItem.children && clickedItem.children.length > 0) {
|
193
|
+
unCheckedRecursive(clickedItem)
|
194
|
+
}
|
195
|
+
//logic to uncheck clickedItem in formattedData
|
196
|
+
unCheckIt(formattedData, clickedItem.id)
|
197
|
+
}
|
194
198
|
|
195
199
|
//handle click on input wrapper(entire div with pills, typeahead, etc) so it doesn't close when input or form pill is clicked
|
196
200
|
const handleInputWrapperClick = (e: any) => {
|
197
|
-
e.stopPropagation()
|
201
|
+
e.stopPropagation()
|
198
202
|
if (
|
199
203
|
e.target.id === "multiselect_input" ||
|
200
204
|
e.target.classList.contains("pb_form_pill_tag")
|
201
205
|
) {
|
202
|
-
return
|
206
|
+
return
|
203
207
|
}
|
204
|
-
setIsClosed(!isClosed)
|
205
|
-
}
|
208
|
+
setIsClosed(!isClosed)
|
209
|
+
}
|
206
210
|
|
207
211
|
//Main function to handle any click inside dropdown
|
208
|
-
const handledropdownItemClick = (e: any
|
209
|
-
const clickedItem = e.target.parentNode.id
|
212
|
+
const handledropdownItemClick = (e: any) => {
|
213
|
+
const clickedItem = e.target.parentNode.id
|
210
214
|
//setting filterItem to "" will clear textinput and clear typeahead
|
211
|
-
setFilterItem("")
|
215
|
+
setFilterItem("")
|
212
216
|
|
213
|
-
const filtered = filterFormattedDataById(formattedData, clickedItem)
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
217
|
+
const filtered = filterFormattedDataById(formattedData, clickedItem)
|
218
|
+
//check and uncheck all children of checked/unchecked parent item
|
219
|
+
if (filtered[0].children && filtered[0].children.length > 0) {
|
220
|
+
if (filtered[0].checked) {
|
221
|
+
filtered[0].children.forEach((item: { [key: string]: any }) => {
|
222
|
+
checkedRecursive(item)
|
223
|
+
})
|
224
|
+
} else if (!filtered[0].checked) {
|
225
|
+
filtered[0].children.forEach((item: { [key: string]: any }) => {
|
226
|
+
unCheckedRecursive(item)
|
227
|
+
})
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
const checkedItems = getCheckedItems(formattedData)
|
232
|
+
|
233
|
+
//checking and unchecking items for returnAllSelected variant
|
234
|
+
if (returnedArray.includes(filtered[0])) {
|
235
|
+
if (!filtered[0].checked) {
|
236
|
+
if (filtered[0].children && filtered[0].children.length > 0) {
|
237
|
+
const childrenOfChecked = getChildIds(filtered[0], returnedArray)
|
238
|
+
const updatedFiltered = returnedArray
|
239
|
+
.filter((item) => item !== filtered[0])
|
240
|
+
.filter((item) => !childrenOfChecked.includes(item.id))
|
241
|
+
|
242
|
+
setReturnedArray(updatedFiltered)
|
243
|
+
} else {
|
244
|
+
const updatedFiltered = returnedArray.filter(
|
245
|
+
(item) => item !== filtered[0]
|
246
|
+
)
|
247
|
+
setReturnedArray(updatedFiltered)
|
248
|
+
}
|
249
|
+
}
|
218
250
|
} else {
|
219
|
-
|
251
|
+
setReturnedArray(checkedItems)
|
252
|
+
}
|
253
|
+
|
254
|
+
//when item is unchecked for default variant
|
255
|
+
if (!filtered[0].checked && !returnAllSelected) {
|
256
|
+
//uncheck parent and grandparent if any child unchecked
|
257
|
+
getAncestorsOfUnchecked(formattedData, filtered[0])
|
258
|
+
|
259
|
+
const newChecked = getCheckedItems(formattedData)
|
260
|
+
//get all checked items, and filter to check if all children checked, if yes return only parent
|
261
|
+
const filteredReturn = updateReturnItems(newChecked)
|
262
|
+
setDefaultReturn(filteredReturn)
|
220
263
|
}
|
221
|
-
};
|
222
264
|
|
223
|
-
|
265
|
+
//when item is checked for default variant
|
266
|
+
if (!returnAllSelected && filtered[0].checked) {
|
267
|
+
//if checked item has children
|
268
|
+
if (filtered[0].children && filtered[0].children.length > 0) {
|
269
|
+
removeChildrenIfParentChecked(
|
270
|
+
filtered[0],
|
271
|
+
defaultReturn,
|
272
|
+
setDefaultReturn
|
273
|
+
)
|
274
|
+
}
|
275
|
+
|
276
|
+
//if clicked item has parent_id, find parent and check if all children checked or not
|
277
|
+
if (filtered[0].parent_id !== null) {
|
278
|
+
recursiveReturnOnlyParent(
|
279
|
+
filtered[0],
|
280
|
+
formattedData,
|
281
|
+
defaultReturn,
|
282
|
+
setDefaultReturn
|
283
|
+
)
|
284
|
+
} else {
|
285
|
+
setDefaultReturn([filtered[0]])
|
286
|
+
}
|
287
|
+
}
|
288
|
+
}
|
224
289
|
|
225
290
|
//handle click on chevron toggles in dropdown
|
226
291
|
const handleToggleClick = (id: string, event: React.MouseEvent) => {
|
227
|
-
event.stopPropagation()
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
if (itemExpanded)
|
234
|
-
expandedArray = expandedArray.filter((i) => i != clickedItem[0].id);
|
235
|
-
else expandedArray.push(clickedItem[0].id);
|
292
|
+
event.stopPropagation()
|
293
|
+
setIsToggled((prevState: { [id: string]: boolean }) => ({
|
294
|
+
...prevState,
|
295
|
+
[id]: !prevState[id],
|
296
|
+
}))
|
297
|
+
const clickedItem = filterFormattedDataById(formattedData, id)
|
236
298
|
|
237
|
-
|
299
|
+
if (clickedItem) {
|
300
|
+
clickedItem[0].expanded = !clickedItem[0].expanded
|
238
301
|
}
|
239
|
-
}
|
302
|
+
}
|
240
303
|
|
241
304
|
//rendering formattedData to UI based on typeahead
|
242
305
|
const renderNestedOptions = (items: { [key: string]: any }[]) => {
|
@@ -246,39 +309,34 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
246
309
|
items.map((item: { [key: string]: any }) => {
|
247
310
|
return (
|
248
311
|
<>
|
249
|
-
<li key={item.id} className=
|
250
|
-
<div className=
|
251
|
-
<div
|
252
|
-
key={isExpanded(item) ? "chevron-down" : "chevron-right"}
|
253
|
-
>
|
312
|
+
<li key={item.id} className='dropdown_item' data-name={item.id}>
|
313
|
+
<div className='dropdown_item_checkbox_row'>
|
314
|
+
<div key={item.expanded ? "chevron-down" : "chevron-right"}>
|
254
315
|
<CircleIconButton
|
255
|
-
icon={
|
256
|
-
isExpanded(item) ? "chevron-down" : "chevron-right"
|
257
|
-
}
|
316
|
+
icon={item.expanded ? "chevron-down" : "chevron-right"}
|
258
317
|
className={
|
259
318
|
item.children && item.children.length > 0
|
260
319
|
? ""
|
261
320
|
: "toggle_icon"
|
262
321
|
}
|
263
|
-
onClick={(event
|
264
|
-
|
265
|
-
}
|
266
|
-
variant="link"
|
322
|
+
onClick={(event) => handleToggleClick(item.id, event)}
|
323
|
+
variant='link'
|
267
324
|
/>
|
268
325
|
</div>
|
269
326
|
<Checkbox text={item.label} id={item.id}>
|
270
327
|
<input
|
271
328
|
checked={item.checked}
|
272
|
-
type=
|
329
|
+
type='checkbox'
|
273
330
|
name={item.label}
|
274
331
|
value={item.label}
|
275
332
|
onChange={(e) => {
|
276
|
-
|
333
|
+
item.checked = !item.checked
|
334
|
+
handledropdownItemClick(e)
|
277
335
|
}}
|
278
336
|
/>
|
279
337
|
</Checkbox>
|
280
338
|
</div>
|
281
|
-
{
|
339
|
+
{item.expanded &&
|
282
340
|
item.children &&
|
283
341
|
item.children.length > 0 &&
|
284
342
|
!filterItem && ( // Show children if expanded is true
|
@@ -286,56 +344,67 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
286
344
|
)}
|
287
345
|
</li>
|
288
346
|
</>
|
289
|
-
)
|
347
|
+
)
|
290
348
|
})}
|
291
349
|
</ul>
|
292
|
-
)
|
293
|
-
}
|
350
|
+
)
|
351
|
+
}
|
294
352
|
|
295
353
|
return (
|
296
354
|
<div {...ariaProps} {...dataProps} className={classes} id={id}>
|
297
|
-
<div ref={dropdownRef} className=
|
298
|
-
<div className=
|
299
|
-
<div className=
|
355
|
+
<div ref={dropdownRef} className='wrapper'>
|
356
|
+
<div className='input_wrapper' onClick={handleInputWrapperClick}>
|
357
|
+
<div className='input_inner_container'>
|
358
|
+
<input
|
359
|
+
type='hidden'
|
360
|
+
id={id}
|
361
|
+
name={name}
|
362
|
+
value={JSON.stringify(formattedReturn)}
|
363
|
+
/>
|
300
364
|
{returnedArray.length !== 0 && returnAllSelected
|
301
365
|
? returnedArray.map((item, index) => (
|
302
366
|
<FormPill
|
303
367
|
key={index}
|
304
368
|
text={item.label}
|
305
|
-
size=
|
306
|
-
onClick={(event
|
369
|
+
size='small'
|
370
|
+
onClick={(event) => handlePillClose(event, item)}
|
307
371
|
/>
|
308
372
|
))
|
309
373
|
: null}
|
310
374
|
{!returnAllSelected &&
|
311
375
|
defaultReturn.length !== 0 &&
|
312
|
-
defaultReturn
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
376
|
+
defaultReturn
|
377
|
+
.filter(
|
378
|
+
(item, index, self) =>
|
379
|
+
index === self.findIndex((obj) => obj.id === item.id)
|
380
|
+
)
|
381
|
+
.map((item, index) => (
|
382
|
+
<FormPill
|
383
|
+
key={index}
|
384
|
+
text={item.label}
|
385
|
+
size='small'
|
386
|
+
onClick={(event) => handlePillClose(event, item)}
|
387
|
+
/>
|
388
|
+
))}
|
320
389
|
{returnedArray.length !== 0 && returnAllSelected && <br />}
|
321
390
|
{defaultReturn.length !== 0 && !returnAllSelected && <br />}
|
322
391
|
<input
|
323
|
-
id=
|
392
|
+
id='multiselect_input'
|
324
393
|
onChange={(e) => {
|
325
|
-
setFilterItem(e.target.value)
|
394
|
+
setFilterItem(e.target.value)
|
326
395
|
}}
|
327
|
-
placeholder=
|
396
|
+
placeholder='Start typing...'
|
328
397
|
value={filterItem}
|
329
398
|
onClick={() => setIsClosed(false)}
|
330
399
|
/>
|
331
400
|
</div>
|
332
401
|
{isClosed ? (
|
333
|
-
<div key=
|
334
|
-
<Icon icon=
|
402
|
+
<div key='chevron-down'>
|
403
|
+
<Icon icon='chevron-down' />
|
335
404
|
</div>
|
336
405
|
) : (
|
337
|
-
<div key=
|
338
|
-
<Icon icon=
|
406
|
+
<div key='chevron-up'>
|
407
|
+
<Icon icon='chevron-up' />
|
339
408
|
</div>
|
340
409
|
)}
|
341
410
|
</div>
|
@@ -346,7 +415,7 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
346
415
|
</div>
|
347
416
|
</div>
|
348
417
|
</div>
|
349
|
-
)
|
350
|
-
}
|
418
|
+
)
|
419
|
+
}
|
351
420
|
|
352
|
-
export default MultiLevelSelect
|
421
|
+
export default MultiLevelSelect
|
@@ -74,7 +74,7 @@ const MultiLevelSelectDefault = (props) => {
|
|
74
74
|
<MultiLevelSelect
|
75
75
|
id="multiselect-default"
|
76
76
|
onSelect={(selectedNodes) =>
|
77
|
-
console.log("Selected Items", selectedNodes)
|
77
|
+
console.log("Selected Items (default... with ids only)", selectedNodes)
|
78
78
|
}
|
79
79
|
treeData={treeData}
|
80
80
|
{...props}
|
@@ -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
|
-
|
5
|
+
By default, the return will be an array of Id's. If you want to return the entire object, you can pass `returnCompleteData` as true. This will return an array of objects.
|
data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.jsx
CHANGED
@@ -74,7 +74,7 @@ const MultiLevelSelectReturnAllSelected = (props) => {
|
|
74
74
|
<MultiLevelSelect
|
75
75
|
id="multiselect-parent-persistence"
|
76
76
|
onSelect={(selectedNodes) =>
|
77
|
-
console.log("Selected Items", selectedNodes)
|
77
|
+
console.log("Selected Items with Return All Selected Data", selectedNodes)
|
78
78
|
}
|
79
79
|
returnAllSelected
|
80
80
|
treeData={treeData}
|