playbook_ui 14.5.0.pre.alpha.PLAY1510railsformloading3977 → 14.5.0.pre.alpha.PLAY1548intltelinputupdatelatest4028
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_dialog/docs/_dialog_loading.html.erb +7 -30
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.md +2 -0
- data/app/pb_kits/playbook/pb_form/docs/example.yml +0 -1
- data/app/pb_kits/playbook/pb_form/form.rb +0 -2
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +195 -228
- data/app/pb_kits/playbook/pb_multi_level_select/context/index.tsx +5 -0
- 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_with_children.jsx +105 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.md +1 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +106 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.md +1 -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 -0
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx +149 -0
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +45 -11
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +6 -4
- data/dist/chunks/_typeahead-BgSfpf21.js +22 -0
- data/dist/chunks/{_weekday_stacked-DnNh3oJT.js → _weekday_stacked-CU-r3k4h.js} +1 -1
- data/dist/chunks/{lib-C9Somihj.js → lib-CEpcaI8y.js} +1 -1
- data/dist/chunks/{pb_form_validation-C8U7gqcT.js → pb_form_validation-D9zkwt2b.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-doc.js +1 -1
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/pb_forms_helper.rb +1 -3
- data/lib/playbook/version.rb +1 -1
- metadata +12 -9
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb +0 -8
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.md +0 -1
- data/app/pb_kits/playbook/pb_form/formHelper.js +0 -39
- data/dist/chunks/_typeahead-CbSMQAjp.js +0 -22
@@ -1,14 +1,17 @@
|
|
1
|
-
import React, { useState, useEffect, useRef } from "react"
|
2
|
-
import classnames from "classnames"
|
3
|
-
import { globalProps, GlobalProps } from "../utilities/globalProps"
|
4
|
-
import {
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
import
|
11
|
-
import
|
1
|
+
import React, { useState, useEffect, useRef } from "react";
|
2
|
+
import classnames from "classnames";
|
3
|
+
import { globalProps, GlobalProps } from "../utilities/globalProps";
|
4
|
+
import {
|
5
|
+
buildAriaProps,
|
6
|
+
buildCss,
|
7
|
+
buildDataProps,
|
8
|
+
buildHtmlProps,
|
9
|
+
} from "../utilities/props";
|
10
|
+
import Icon from "../pb_icon/_icon";
|
11
|
+
import FormPill from "../pb_form_pill/_form_pill";
|
12
|
+
import { cloneDeep } from "lodash";
|
13
|
+
import MultiLevelSelectOptions from "./multi_level_select_options";
|
14
|
+
import MultiLevelSelectContext from "./context";
|
12
15
|
|
13
16
|
import {
|
14
17
|
getAncestorsOfUnchecked,
|
@@ -18,7 +21,7 @@ import {
|
|
18
21
|
getDefaultCheckedItems,
|
19
22
|
recursiveCheckParent,
|
20
23
|
getExpandedItems,
|
21
|
-
} from "./_helper_functions"
|
24
|
+
} from "./_helper_functions";
|
22
25
|
|
23
26
|
type MultiLevelSelectProps = {
|
24
27
|
aria?: { [key: string]: string }
|
@@ -30,9 +33,9 @@ type MultiLevelSelectProps = {
|
|
30
33
|
inputName?: string
|
31
34
|
name?: string
|
32
35
|
returnAllSelected?: boolean
|
33
|
-
treeData?: { [key: string]: string }[]
|
36
|
+
treeData?: { [key: string]: string; }[] | any
|
34
37
|
onSelect?: (prop: { [key: string]: any }) => void
|
35
|
-
selectedIds?: string[]
|
38
|
+
selectedIds?: string[] | any
|
36
39
|
variant?: "multi" | "single"
|
37
40
|
pillColor?: "primary" | "neutral" | "success" | "warning" | "error" | "info" | "data_1" | "data_2" | "data_3" | "data_4" | "data_5" | "data_6" | "data_7" | "data_8" | "windows" | "siding" | "roofing" | "doors" | "gutters" | "solar" | "insulation" | "accessories",
|
38
41
|
} & GlobalProps
|
@@ -52,126 +55,132 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
52
55
|
onSelect = () => null,
|
53
56
|
selectedIds,
|
54
57
|
variant = "multi",
|
58
|
+
children,
|
55
59
|
pillColor = "primary"
|
56
60
|
} = props
|
57
61
|
|
58
|
-
const ariaProps = buildAriaProps(aria)
|
59
|
-
const dataProps = buildDataProps(data)
|
60
|
-
const htmlProps = buildHtmlProps(htmlOptions)
|
62
|
+
const ariaProps = buildAriaProps(aria);
|
63
|
+
const dataProps = buildDataProps(data);
|
64
|
+
const htmlProps = buildHtmlProps(htmlOptions);
|
61
65
|
const classes = classnames(
|
62
66
|
buildCss("pb_multi_level_select"),
|
63
67
|
globalProps(props),
|
64
68
|
className
|
65
|
-
)
|
69
|
+
);
|
66
70
|
|
67
|
-
const dropdownRef = useRef(null)
|
71
|
+
const dropdownRef = useRef(null);
|
68
72
|
|
69
73
|
// State for whether dropdown is open or closed
|
70
|
-
const [isDropdownClosed, setIsDropdownClosed] = useState(true)
|
74
|
+
const [isDropdownClosed, setIsDropdownClosed] = useState(true);
|
71
75
|
// State from onChange for textinput, to use for filtering to create typeahead
|
72
|
-
const [filterItem, setFilterItem] = useState("")
|
76
|
+
const [filterItem, setFilterItem] = useState("");
|
73
77
|
// FormattedData with checked and parent_id added
|
74
|
-
const [formattedData, setFormattedData] = useState([])
|
78
|
+
const [formattedData, setFormattedData] = useState([]);
|
75
79
|
// State for the return of returnAllSelected
|
76
|
-
const [returnedArray, setReturnedArray] = useState([])
|
80
|
+
const [returnedArray, setReturnedArray] = useState([]);
|
77
81
|
// State for default return
|
78
|
-
const [defaultReturn, setDefaultReturn] = useState([])
|
82
|
+
const [defaultReturn, setDefaultReturn] = useState([]);
|
79
83
|
// Get expanded items from treeData
|
80
|
-
const initialExpandedItems = getExpandedItems(treeData, selectedIds)
|
84
|
+
const initialExpandedItems = getExpandedItems(treeData, selectedIds);
|
81
85
|
// Initialize state with expanded items
|
82
|
-
const [expanded, setExpanded] = useState(initialExpandedItems)
|
86
|
+
const [expanded, setExpanded] = useState(initialExpandedItems);
|
83
87
|
|
84
88
|
// Single Select specific state
|
85
89
|
const [singleSelectedItem, setSingleSelectedItem] = useState({
|
86
90
|
id: [],
|
87
91
|
value: "",
|
88
|
-
item: []
|
89
|
-
})
|
92
|
+
item: [],
|
93
|
+
});
|
90
94
|
|
91
95
|
const arrowDownElementId = `arrow_down_${id}`
|
92
96
|
const arrowUpElementId = `arrow_up_${id}`
|
93
97
|
|
94
98
|
const modifyRecursive = (tree: { [key: string]: any }[], check: boolean) => {
|
95
99
|
if (!Array.isArray(tree)) {
|
96
|
-
return
|
100
|
+
return;
|
97
101
|
}
|
98
102
|
return tree.map((item: { [key: string]: any }) => {
|
99
|
-
item.checked = check
|
100
|
-
item.children = modifyRecursive(item.children, check)
|
101
|
-
return item
|
102
|
-
})
|
103
|
-
}
|
103
|
+
item.checked = check;
|
104
|
+
item.children = modifyRecursive(item.children, check);
|
105
|
+
return item;
|
106
|
+
});
|
107
|
+
};
|
104
108
|
|
105
|
-
|
109
|
+
// Function to map over data and add parent_id + depth property to each item
|
106
110
|
const addCheckedAndParentProperty = (
|
107
111
|
treeData: { [key: string]: any }[],
|
108
112
|
selectedIds: string[],
|
109
|
-
parent_id: string = null,
|
110
|
-
depth = 0
|
113
|
+
parent_id: string | null = null,
|
114
|
+
depth = 0
|
111
115
|
) => {
|
112
116
|
if (!Array.isArray(treeData)) {
|
113
|
-
return
|
117
|
+
return;
|
114
118
|
}
|
115
119
|
return treeData.map((item: { [key: string]: any } | any) => {
|
116
120
|
const newItem = {
|
117
121
|
...item,
|
118
|
-
checked: Boolean(
|
122
|
+
checked: Boolean(
|
123
|
+
selectedIds && selectedIds.length && selectedIds.includes(item.id)
|
124
|
+
),
|
119
125
|
parent_id,
|
120
126
|
depth,
|
121
|
-
}
|
127
|
+
};
|
122
128
|
if (newItem.children && newItem.children.length > 0) {
|
123
129
|
const children =
|
124
130
|
item.checked && !returnAllSelected
|
125
131
|
? modifyRecursive(item.children, true)
|
126
|
-
: item.children
|
132
|
+
: item.children;
|
127
133
|
newItem.children = addCheckedAndParentProperty(
|
128
134
|
children,
|
129
135
|
selectedIds,
|
130
136
|
newItem.id,
|
131
137
|
depth + 1
|
132
|
-
)
|
138
|
+
);
|
133
139
|
}
|
134
|
-
return newItem
|
135
|
-
})
|
136
|
-
}
|
140
|
+
return newItem;
|
141
|
+
});
|
142
|
+
};
|
137
143
|
|
138
144
|
useEffect(() => {
|
139
145
|
const formattedData = addCheckedAndParentProperty(
|
140
146
|
treeData,
|
141
147
|
variant === "single" ? [selectedIds?.[0]] : selectedIds
|
142
|
-
)
|
148
|
+
);
|
143
149
|
|
144
|
-
setFormattedData(formattedData)
|
150
|
+
setFormattedData(formattedData);
|
145
151
|
|
146
152
|
if (variant === "single") {
|
147
153
|
// No selectedIds, reset state
|
148
154
|
if (selectedIds?.length === 0 || !selectedIds?.length) {
|
149
|
-
setSingleSelectedItem({ id: [], value: "", item: []})
|
155
|
+
setSingleSelectedItem({ id: [], value: "", item: [] });
|
150
156
|
} else {
|
151
157
|
// If there is a selectedId but no current item, set the selectedItem
|
152
158
|
if (selectedIds?.length !== 0 && !singleSelectedItem.value) {
|
153
|
-
const selectedItem = filterFormattedDataById(
|
159
|
+
const selectedItem = filterFormattedDataById(
|
160
|
+
formattedData,
|
161
|
+
selectedIds[0]
|
162
|
+
);
|
154
163
|
|
155
164
|
if (!selectedItem.length) {
|
156
|
-
setSingleSelectedItem({ id: [], value: "", item: []})
|
165
|
+
setSingleSelectedItem({ id: [], value: "", item: [] });
|
157
166
|
} else {
|
158
|
-
const { id, value } = selectedItem[0]
|
159
|
-
setSingleSelectedItem({ id: [id], value, item: selectedItem})
|
167
|
+
const { id, value } = selectedItem[0];
|
168
|
+
setSingleSelectedItem({ id: [id], value, item: selectedItem });
|
160
169
|
}
|
161
170
|
}
|
162
171
|
}
|
163
172
|
}
|
164
|
-
}, [treeData, selectedIds])
|
173
|
+
}, [treeData, selectedIds]);
|
165
174
|
|
166
175
|
useEffect(() => {
|
167
176
|
if (returnAllSelected) {
|
168
|
-
setReturnedArray(getCheckedItems(formattedData))
|
177
|
+
setReturnedArray(getCheckedItems(formattedData));
|
169
178
|
} else if (variant === "single") {
|
170
|
-
setDefaultReturn(singleSelectedItem.item)
|
179
|
+
setDefaultReturn(singleSelectedItem.item);
|
171
180
|
} else {
|
172
|
-
setDefaultReturn(getDefaultCheckedItems(formattedData))
|
181
|
+
setDefaultReturn(getDefaultCheckedItems(formattedData));
|
173
182
|
}
|
174
|
-
}, [formattedData])
|
183
|
+
}, [formattedData]);
|
175
184
|
|
176
185
|
useEffect(() => {
|
177
186
|
// Function to handle clicks outside the dropdown
|
@@ -184,16 +193,14 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
184
193
|
) {
|
185
194
|
setIsDropdownClosed(true)
|
186
195
|
}
|
187
|
-
}
|
196
|
+
};
|
188
197
|
// Attach the event listener
|
189
|
-
window.addEventListener("click", handleClickOutside)
|
198
|
+
window.addEventListener("click", handleClickOutside);
|
190
199
|
// Clean up the event listener on unmount
|
191
200
|
return () => {
|
192
|
-
window.removeEventListener("click", handleClickOutside)
|
193
|
-
}
|
194
|
-
}, [])
|
195
|
-
|
196
|
-
|
201
|
+
window.removeEventListener("click", handleClickOutside);
|
202
|
+
};
|
203
|
+
}, []);
|
197
204
|
|
198
205
|
// Iterate over tree, find item and set checked or unchecked
|
199
206
|
const modifyValue = (
|
@@ -202,69 +209,67 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
202
209
|
check: boolean
|
203
210
|
) => {
|
204
211
|
if (!Array.isArray(tree)) {
|
205
|
-
return
|
212
|
+
return;
|
206
213
|
}
|
207
214
|
return tree.map((item: any) => {
|
208
|
-
if (item.id != id) item.children = modifyValue(id, item.children, check)
|
215
|
+
if (item.id != id) item.children = modifyValue(id, item.children, check);
|
209
216
|
else {
|
210
|
-
item.checked = check
|
217
|
+
item.checked = check;
|
211
218
|
|
212
219
|
if (variant === "single") {
|
213
220
|
// Single select: no children should be checked
|
214
|
-
item.children = modifyRecursive(item.children, !check)
|
221
|
+
item.children = modifyRecursive(item.children, !check);
|
215
222
|
} else {
|
216
|
-
item.children = modifyRecursive(item.children, check)
|
223
|
+
item.children = modifyRecursive(item.children, check);
|
217
224
|
}
|
218
225
|
}
|
219
226
|
|
220
|
-
return item
|
221
|
-
})
|
222
|
-
}
|
227
|
+
return item;
|
228
|
+
});
|
229
|
+
};
|
223
230
|
|
224
231
|
// Clone tree, check items + children
|
225
232
|
const checkItem = (item: { [key: string]: any }) => {
|
226
|
-
const tree = cloneDeep(formattedData)
|
233
|
+
const tree = cloneDeep(formattedData);
|
227
234
|
if (returnAllSelected) {
|
228
|
-
return modifyValue(item.id, tree, true)
|
235
|
+
return modifyValue(item.id, tree, true);
|
229
236
|
} else {
|
230
|
-
const checkedTree = modifyValue(item.id, tree, true)
|
231
|
-
return recursiveCheckParent(item, checkedTree)
|
237
|
+
const checkedTree = modifyValue(item.id, tree, true);
|
238
|
+
return recursiveCheckParent(item, checkedTree);
|
232
239
|
}
|
233
|
-
}
|
240
|
+
};
|
234
241
|
|
235
242
|
// Clone tree, uncheck items + children
|
236
243
|
const unCheckItem = (item: { [key: string]: any }) => {
|
237
|
-
const tree = cloneDeep(formattedData)
|
244
|
+
const tree = cloneDeep(formattedData);
|
238
245
|
if (returnAllSelected) {
|
239
|
-
return modifyValue(item.id, tree, false)
|
246
|
+
return modifyValue(item.id, tree, false);
|
240
247
|
} else {
|
241
|
-
const uncheckedTree = modifyValue(item.id, tree, false)
|
242
|
-
return getAncestorsOfUnchecked(uncheckedTree, item)
|
248
|
+
const uncheckedTree = modifyValue(item.id, tree, false);
|
249
|
+
return getAncestorsOfUnchecked(uncheckedTree, item);
|
243
250
|
}
|
244
|
-
}
|
251
|
+
};
|
245
252
|
|
246
253
|
// setFormattedData with proper properties
|
247
254
|
const changeItem = (item: { [key: string]: any }, check: boolean) => {
|
248
|
-
const tree = check ? checkItem(item) : unCheckItem(item)
|
249
|
-
setFormattedData(tree)
|
250
|
-
|
251
|
-
return tree
|
252
|
-
}
|
255
|
+
const tree = check ? checkItem(item) : unCheckItem(item);
|
256
|
+
setFormattedData(tree);
|
253
257
|
|
254
|
-
|
258
|
+
return tree;
|
259
|
+
};
|
255
260
|
|
256
261
|
// Click event for x on form pill
|
257
262
|
const handlePillClose = (event: any, clickedItem: { [key: string]: any }) => {
|
258
263
|
// Prevents the dropdown from closing when clicking on the pill
|
259
|
-
event.stopPropagation()
|
260
|
-
const updatedTree = changeItem(clickedItem, false)
|
264
|
+
event.stopPropagation();
|
265
|
+
const updatedTree = changeItem(clickedItem, false);
|
261
266
|
// Logic for removing items from returnArray or defaultReturn when pills clicked
|
262
267
|
if (returnAllSelected) {
|
263
|
-
onSelect(getCheckedItems(updatedTree))
|
268
|
+
onSelect(getCheckedItems(updatedTree));
|
264
269
|
} else {
|
265
|
-
onSelect(getDefaultCheckedItems(updatedTree))
|
270
|
+
onSelect(getDefaultCheckedItems(updatedTree));
|
266
271
|
}
|
267
|
-
}
|
272
|
+
};
|
268
273
|
|
269
274
|
// Handle click on input wrapper(entire div with pills, typeahead, etc) so it doesn't close when input or form pill is clicked
|
270
275
|
const handleInputWrapperClick = (e: any) => {
|
@@ -272,163 +277,114 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
272
277
|
e.target.id === "multiselect_input" ||
|
273
278
|
e.target.classList.contains("pb_form_pill_tag")
|
274
279
|
) {
|
275
|
-
return
|
280
|
+
return;
|
276
281
|
}
|
277
|
-
setIsDropdownClosed(!isDropdownClosed)
|
278
|
-
}
|
282
|
+
setIsDropdownClosed(!isDropdownClosed);
|
283
|
+
};
|
279
284
|
|
280
285
|
// Main function to handle any click inside dropdown
|
281
286
|
const handledropdownItemClick = (e: any, check: boolean) => {
|
282
|
-
const clickedItem = e.target.parentNode.id
|
287
|
+
const clickedItem = e.target.parentNode.id;
|
283
288
|
// Setting filterItem to "" will clear textinput and clear typeahead
|
284
|
-
setFilterItem("")
|
289
|
+
setFilterItem("");
|
285
290
|
|
286
|
-
const filtered = filterFormattedDataById(formattedData, clickedItem)
|
287
|
-
const updatedTree = changeItem(filtered[0], check)
|
291
|
+
const filtered = filterFormattedDataById(formattedData, clickedItem);
|
292
|
+
const updatedTree = changeItem(filtered[0], check);
|
288
293
|
if (returnAllSelected) {
|
289
|
-
onSelect(getCheckedItems(updatedTree))
|
294
|
+
onSelect(getCheckedItems(updatedTree));
|
290
295
|
} else {
|
291
|
-
onSelect(getDefaultCheckedItems(updatedTree))
|
296
|
+
onSelect(getDefaultCheckedItems(updatedTree));
|
292
297
|
}
|
293
|
-
}
|
298
|
+
};
|
294
299
|
|
295
300
|
// Single select
|
296
|
-
const handleRadioButtonClick = (
|
297
|
-
|
298
|
-
) => {
|
299
|
-
const { id, value: inputText } = e.target
|
301
|
+
const handleRadioButtonClick = (e: React.ChangeEvent<HTMLInputElement>) => {
|
302
|
+
const { id, value: inputText } = e.target;
|
300
303
|
// The radio button needs a unique ID, this grabs the ID before the hyphen
|
301
|
-
const selectedItemID = id.match(/^[^-]*/)[0]
|
304
|
+
const selectedItemID = id.match(/^[^-]*/)[0];
|
302
305
|
// Reset tree checked state, triggering useEffect
|
303
|
-
const treeWithNoSelections = modifyRecursive(formattedData, false)
|
306
|
+
const treeWithNoSelections = modifyRecursive(formattedData, false);
|
304
307
|
// Update tree with single selection
|
305
|
-
const treeWithSelectedItem = modifyValue(
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
308
|
+
const treeWithSelectedItem = modifyValue(
|
309
|
+
selectedItemID,
|
310
|
+
treeWithNoSelections,
|
311
|
+
true
|
312
|
+
);
|
313
|
+
const selectedItem = filterFormattedDataById(
|
314
|
+
treeWithSelectedItem,
|
315
|
+
selectedItemID
|
316
|
+
);
|
317
|
+
|
318
|
+
setFormattedData(treeWithSelectedItem);
|
319
|
+
setSingleSelectedItem({
|
320
|
+
id: [selectedItemID],
|
321
|
+
value: inputText,
|
322
|
+
item: selectedItem,
|
323
|
+
});
|
310
324
|
// Reset the filter to always display dropdown options on click
|
311
|
-
setFilterItem("")
|
312
|
-
setIsDropdownClosed(true)
|
325
|
+
setFilterItem("");
|
326
|
+
setIsDropdownClosed(true);
|
313
327
|
|
314
|
-
onSelect(selectedItem)
|
328
|
+
onSelect(selectedItem);
|
315
329
|
};
|
316
330
|
|
317
331
|
// Single select: reset the tree state upon typing
|
318
332
|
const handleRadioInputChange = (inputText: string) => {
|
319
|
-
modifyRecursive(formattedData, false)
|
320
|
-
setDefaultReturn([])
|
321
|
-
setSingleSelectedItem({id: [], value: inputText, item: []})
|
322
|
-
setFilterItem(inputText)
|
333
|
+
modifyRecursive(formattedData, false);
|
334
|
+
setDefaultReturn([]);
|
335
|
+
setSingleSelectedItem({ id: [], value: inputText, item: [] });
|
336
|
+
setFilterItem(inputText);
|
323
337
|
};
|
324
338
|
|
325
|
-
const isTreeRowExpanded = (item: any) => expanded.indexOf(item.id) > -1
|
339
|
+
const isTreeRowExpanded = (item: any) => expanded.indexOf(item.id) > -1;
|
326
340
|
|
327
341
|
// Handle click on chevron toggles in dropdown
|
328
342
|
const handleToggleClick = (id: string, event: React.MouseEvent) => {
|
329
|
-
event.stopPropagation()
|
330
|
-
const clickedItem = filterFormattedDataById(formattedData, id)
|
343
|
+
event.stopPropagation();
|
344
|
+
const clickedItem = filterFormattedDataById(formattedData, id);
|
331
345
|
if (clickedItem) {
|
332
|
-
let expandedArray = [...expanded]
|
333
|
-
const itemExpanded = isTreeRowExpanded(clickedItem[0])
|
346
|
+
let expandedArray = [...expanded];
|
347
|
+
const itemExpanded = isTreeRowExpanded(clickedItem[0]);
|
334
348
|
|
335
349
|
if (itemExpanded)
|
336
|
-
expandedArray = expandedArray.filter((i) => i != clickedItem[0].id)
|
337
|
-
else expandedArray.push(clickedItem[0].id)
|
350
|
+
expandedArray = expandedArray.filter((i) => i != clickedItem[0].id);
|
351
|
+
else expandedArray.push(clickedItem[0].id);
|
338
352
|
|
339
|
-
setExpanded(expandedArray)
|
353
|
+
setExpanded(expandedArray);
|
340
354
|
}
|
341
|
-
}
|
355
|
+
};
|
342
356
|
|
343
357
|
const itemsSelectedLength = () => {
|
344
|
-
let items
|
358
|
+
let items;
|
345
359
|
if (returnAllSelected && returnedArray && returnedArray.length) {
|
346
|
-
items = returnedArray.length
|
360
|
+
items = returnedArray.length;
|
347
361
|
} else if (!returnAllSelected && defaultReturn && defaultReturn.length) {
|
348
|
-
items = defaultReturn.length
|
362
|
+
items = defaultReturn.length;
|
349
363
|
}
|
350
|
-
return items
|
351
|
-
}
|
364
|
+
return items;
|
365
|
+
};
|
352
366
|
|
353
367
|
// Rendering formattedData to UI based on typeahead
|
354
|
-
const renderNestedOptions = (items: { [key: string]:
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
: "toggle_icon"
|
375
|
-
}
|
376
|
-
icon={
|
377
|
-
isTreeRowExpanded(item) ? "chevron-down" : "chevron-right"
|
378
|
-
}
|
379
|
-
onClick={(event: any) =>
|
380
|
-
handleToggleClick(item.id, event)
|
381
|
-
}
|
382
|
-
variant="link"
|
383
|
-
/>
|
384
|
-
</div>
|
385
|
-
}
|
386
|
-
{ variant === "single" ? (
|
387
|
-
item.hideRadio ? (
|
388
|
-
<Body>{item.label}</Body>
|
389
|
-
) :
|
390
|
-
<Radio
|
391
|
-
checked={item.checked}
|
392
|
-
id={`${item.id}-${item.label}`}
|
393
|
-
label={item.label}
|
394
|
-
name={inputName}
|
395
|
-
onChange={(e: React.ChangeEvent<HTMLInputElement>) => (
|
396
|
-
handleRadioButtonClick(e)
|
397
|
-
)}
|
398
|
-
padding={item.children ? 'none' : 'xs'}
|
399
|
-
type="radio"
|
400
|
-
value={item.label}
|
401
|
-
/>
|
402
|
-
) : (
|
403
|
-
<Checkbox
|
404
|
-
id={item.id}
|
405
|
-
text={item.label}
|
406
|
-
>
|
407
|
-
<input
|
408
|
-
checked={item.checked}
|
409
|
-
name={item.label}
|
410
|
-
onChange={(e) => {
|
411
|
-
handledropdownItemClick(e, !item.checked)
|
412
|
-
}}
|
413
|
-
type="checkbox"
|
414
|
-
value={item.label}
|
415
|
-
/>
|
416
|
-
</Checkbox>
|
417
|
-
)}
|
418
|
-
</div>
|
419
|
-
{isTreeRowExpanded(item) &&
|
420
|
-
item.children &&
|
421
|
-
item.children.length > 0 &&
|
422
|
-
(variant === "single" || !filterItem) && ( // Show children if expanded is true
|
423
|
-
<div>{renderNestedOptions(item.children)}</div>
|
424
|
-
)}
|
425
|
-
</li>
|
426
|
-
</div>
|
427
|
-
)
|
428
|
-
})}
|
429
|
-
</ul>
|
430
|
-
)
|
431
|
-
}
|
368
|
+
const renderNestedOptions = (items: { [key: string]: string; }[] | any ) => {
|
369
|
+
const hasOptionsChild = React.Children.toArray(props.children).some(
|
370
|
+
(child: any) => child.type === MultiLevelSelect.Options
|
371
|
+
);
|
372
|
+
|
373
|
+
if (hasOptionsChild) {
|
374
|
+
return React.Children.map(props.children, (child) => {
|
375
|
+
if (child.type === MultiLevelSelect.Options) {
|
376
|
+
return React.cloneElement(child, { items });
|
377
|
+
}
|
378
|
+
return null;
|
379
|
+
});
|
380
|
+
} else {
|
381
|
+
// If no children, use the default rendering
|
382
|
+
return (
|
383
|
+
<MultiLevelSelectOptions items={items} />
|
384
|
+
);
|
385
|
+
}
|
386
|
+
};
|
387
|
+
|
432
388
|
|
433
389
|
return (
|
434
390
|
<div
|
@@ -438,12 +394,20 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
438
394
|
className={classes}
|
439
395
|
id={id}
|
440
396
|
>
|
441
|
-
<
|
442
|
-
|
397
|
+
<MultiLevelSelectContext.Provider value={{
|
398
|
+
variant,
|
399
|
+
inputName,
|
400
|
+
renderNestedOptions,
|
401
|
+
isTreeRowExpanded,
|
402
|
+
handleToggleClick,
|
403
|
+
handleRadioButtonClick,
|
404
|
+
handledropdownItemClick,
|
405
|
+
filterItem,
|
406
|
+
}}>
|
407
|
+
<div className="wrapper"
|
443
408
|
ref={dropdownRef}
|
444
409
|
>
|
445
|
-
<div
|
446
|
-
className="input_wrapper"
|
410
|
+
<div className="input_wrapper"
|
447
411
|
onClick={handleInputWrapperClick}
|
448
412
|
>
|
449
413
|
<div className="input_inner_container">
|
@@ -509,15 +473,17 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
509
473
|
|
510
474
|
<input
|
511
475
|
id="multiselect_input"
|
512
|
-
onChange={(e) =>{
|
476
|
+
onChange={(e) => {
|
513
477
|
variant === "single"
|
514
478
|
? handleRadioInputChange(e.target.value)
|
515
|
-
: setFilterItem(e.target.value)
|
479
|
+
: setFilterItem(e.target.value);
|
516
480
|
}}
|
517
481
|
onClick={() => setIsDropdownClosed(false)}
|
518
482
|
placeholder={
|
519
483
|
inputDisplay === "none" && itemsSelectedLength()
|
520
|
-
? `${itemsSelectedLength()} ${
|
484
|
+
? `${itemsSelectedLength()} ${
|
485
|
+
itemsSelectedLength() === 1 ? "item" : "items"
|
486
|
+
} selected`
|
521
487
|
: "Start typing..."
|
522
488
|
}
|
523
489
|
value={singleSelectedItem.value || filterItem}
|
@@ -546,15 +512,16 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
|
|
546
512
|
</div>
|
547
513
|
|
548
514
|
<div className={`dropdown_menu ${isDropdownClosed ? "close" : "open"}`}>
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
: formattedData
|
553
|
-
)}
|
515
|
+
{renderNestedOptions(
|
516
|
+
filterItem ? findByFilter(formattedData, filterItem) : formattedData
|
517
|
+
)}
|
554
518
|
</div>
|
555
519
|
</div>
|
520
|
+
</MultiLevelSelectContext.Provider>
|
556
521
|
</div>
|
557
|
-
)
|
558
|
-
}
|
522
|
+
);
|
523
|
+
};
|
524
|
+
|
525
|
+
MultiLevelSelect.Options = MultiLevelSelectOptions;
|
559
526
|
|
560
|
-
export default MultiLevelSelect
|
527
|
+
export default MultiLevelSelect;
|