playbook_ui 14.5.0.pre.alpha.psych4support3941 → 14.5.0.pre.alpha.20241007playbookwebsiteaddrdbms4036

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +9 -1
  3. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb +19 -0
  4. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx +27 -0
  5. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.md +1 -0
  6. data/app/pb_kits/playbook/pb_form_pill/docs/example.yml +2 -0
  7. data/app/pb_kits/playbook/pb_form_pill/docs/index.js +1 -0
  8. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +195 -228
  9. data/app/pb_kits/playbook/pb_multi_level_select/context/index.tsx +5 -0
  10. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +1 -1
  11. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx +105 -0
  12. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.md +1 -0
  13. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +106 -0
  14. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.md +1 -0
  15. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +3 -0
  16. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +2 -0
  17. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx +149 -0
  18. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +4 -1
  19. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +3 -1
  20. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -1
  21. data/dist/chunks/{_typeahead-BYw0HEgO.js → _typeahead-CT2ByCBK.js} +1 -1
  22. data/dist/chunks/{_weekday_stacked-DumiyWjh.js → _weekday_stacked-Bwdy1TtH.js} +1 -1
  23. data/dist/chunks/vendor.js +1 -1
  24. data/dist/playbook-doc.js +1 -1
  25. data/dist/playbook-rails-react-bindings.js +1 -1
  26. data/dist/playbook-rails.js +1 -1
  27. data/lib/playbook/version.rb +1 -1
  28. metadata +13 -4
@@ -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;