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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.html.erb +7 -30
  3. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.md +2 -0
  4. data/app/pb_kits/playbook/pb_form/docs/example.yml +0 -1
  5. data/app/pb_kits/playbook/pb_form/form.rb +0 -2
  6. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +195 -228
  7. data/app/pb_kits/playbook/pb_multi_level_select/context/index.tsx +5 -0
  8. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +1 -1
  9. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx +105 -0
  10. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.md +1 -0
  11. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +106 -0
  12. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.md +1 -0
  13. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +3 -0
  14. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +2 -0
  15. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx +149 -0
  16. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +45 -11
  17. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +6 -4
  18. data/dist/chunks/_typeahead-BgSfpf21.js +22 -0
  19. data/dist/chunks/{_weekday_stacked-DnNh3oJT.js → _weekday_stacked-CU-r3k4h.js} +1 -1
  20. data/dist/chunks/{lib-C9Somihj.js → lib-CEpcaI8y.js} +1 -1
  21. data/dist/chunks/{pb_form_validation-C8U7gqcT.js → pb_form_validation-D9zkwt2b.js} +1 -1
  22. data/dist/chunks/vendor.js +1 -1
  23. data/dist/playbook-doc.js +1 -1
  24. data/dist/playbook-rails-react-bindings.js +1 -1
  25. data/dist/playbook-rails.js +1 -1
  26. data/dist/playbook.css +1 -1
  27. data/lib/playbook/pb_forms_helper.rb +1 -3
  28. data/lib/playbook/version.rb +1 -1
  29. metadata +12 -9
  30. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb +0 -8
  31. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.md +0 -1
  32. data/app/pb_kits/playbook/pb_form/formHelper.js +0 -39
  33. 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 { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props"
5
- import Checkbox from "../pb_checkbox/_checkbox"
6
- import Radio from "../pb_radio/_radio"
7
- import Body from "../pb_body/_body"
8
- import Icon from "../pb_icon/_icon"
9
- import FormPill from "../pb_form_pill/_form_pill"
10
- import CircleIconButton from "../pb_circle_icon_button/_circle_icon_button"
11
- import { cloneDeep } from "lodash"
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
- // Function to map over data and add parent_id + depth property to each item
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(selectedIds && selectedIds.length && selectedIds.includes(item.id)),
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(formattedData, selectedIds[0])
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
- e: React.ChangeEvent<HTMLInputElement>,
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(selectedItemID, treeWithNoSelections, true)
306
- const selectedItem = filterFormattedDataById(treeWithSelectedItem, selectedItemID)
307
-
308
- setFormattedData(treeWithSelectedItem)
309
- setSingleSelectedItem({id: [selectedItemID], value: inputText, item: selectedItem})
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]: any }[]) => {
355
- return (
356
- <ul>
357
- {Array.isArray(items) &&
358
- items.map((item: { [key: string]: any }) => {
359
- return (
360
- <div key={item.id}>
361
- <li
362
- className={"dropdown_item"}
363
- data-name={item.id}
364
- >
365
- <div className="dropdown_item_checkbox_row">
366
- { !item.parent_id && !item.children ? null :
367
- <div
368
- key={isTreeRowExpanded(item) ? "chevron-down" : "chevron-right"}
369
- >
370
- <CircleIconButton
371
- className={
372
- item.children && item.children.length > 0
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
- <div
442
- className="wrapper"
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()} ${itemsSelectedLength() === 1 ? "item" : "items"} selected`
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
- {renderNestedOptions(
550
- filterItem
551
- ? findByFilter(formattedData, filterItem)
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;
@@ -0,0 +1,5 @@
1
+ import { createContext } from "react";
2
+
3
+ const MultiLevelSelectContext = createContext<any>({});
4
+
5
+ export default MultiLevelSelectContext;
@@ -87,4 +87,4 @@ const MultiLevelSelectDefault = (props) => {
87
87
  )
88
88
  };
89
89
 
90
- export default MultiLevelSelectDefault;
90
+ export default MultiLevelSelectDefault;