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