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