playbook_ui 14.5.0.pre.alpha.20241007playbookwebsiteaddrdbms4036 → 14.5.0.pre.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +0 -2
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/SortIconButton.tsx +4 -23
  4. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +1 -1
  5. data/app/pb_kits/playbook/pb_button/_button.tsx +2 -6
  6. data/app/pb_kits/playbook/pb_contact/_contact.tsx +5 -17
  7. data/app/pb_kits/playbook/pb_contact/contact.html.erb +6 -14
  8. data/app/pb_kits/playbook/pb_contact/contact.rb +0 -4
  9. data/app/pb_kits/playbook/pb_contact/contact.test.js +1 -1
  10. data/app/pb_kits/playbook/pb_dashboard/pbChartsDarkTheme.ts +6 -2
  11. data/app/pb_kits/playbook/pb_dashboard/pbChartsLightTheme.ts +7 -2
  12. data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +3 -4
  13. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +1 -1
  14. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +0 -4
  15. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +3 -6
  16. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_inline.html.erb +1 -1
  17. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_header_styles.scss +2 -6
  18. data/app/pb_kits/playbook/pb_dialog/_dialog.scss +0 -2
  19. data/app/pb_kits/playbook/pb_dialog/dialog_header.html.erb +1 -1
  20. data/app/pb_kits/playbook/pb_filter/docs/_filter_default.html.erb +2 -10
  21. data/app/pb_kits/playbook/pb_filter/docs/_filter_max_height.html.erb +1 -5
  22. data/app/pb_kits/playbook/pb_filter/docs/_filter_max_width.html.erb +1 -5
  23. data/app/pb_kits/playbook/pb_filter/docs/_filter_no_background.html.erb +1 -5
  24. data/app/pb_kits/playbook/pb_filter/docs/_filter_no_sort.html.erb +1 -5
  25. data/app/pb_kits/playbook/pb_filter/docs/_filter_only.html.erb +1 -5
  26. data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.html.erb +1 -5
  27. data/app/pb_kits/playbook/pb_filter/docs/_filter_single.html.erb +1 -5
  28. data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +1 -9
  29. data/app/pb_kits/playbook/pb_form_pill/docs/example.yml +0 -2
  30. data/app/pb_kits/playbook/pb_form_pill/docs/index.js +0 -1
  31. data/app/pb_kits/playbook/pb_map/_map_controls.tsx +1 -7
  32. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +232 -210
  33. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +1 -1
  34. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +0 -3
  35. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +0 -2
  36. data/app/pb_kits/playbook/pb_pagination/docs/_pagination_page_change.jsx +1 -12
  37. data/app/pb_kits/playbook/pb_pagination/docs/_pagination_page_change_react.md +1 -3
  38. data/app/pb_kits/playbook/pb_passphrase/_passphrase.tsx +2 -10
  39. data/app/pb_kits/playbook/pb_popover/docs/_popover_list.html.erb +13 -14
  40. data/app/pb_kits/playbook/pb_popover/docs/_popover_list.jsx +4 -4
  41. data/app/pb_kits/playbook/pb_radio/_radio.tsx +33 -92
  42. data/app/pb_kits/playbook/pb_radio/docs/_radio_custom_children.html.erb +0 -2
  43. data/app/pb_kits/playbook/pb_radio/docs/example.yml +0 -1
  44. data/app/pb_kits/playbook/pb_radio/docs/index.js +0 -1
  45. data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/ToolbarDropdown.tsx +5 -12
  46. data/app/pb_kits/playbook/pb_select/_select.tsx +2 -5
  47. data/app/pb_kits/playbook/pb_select/select.html.erb +1 -1
  48. data/app/pb_kits/playbook/pb_select/select.rb +0 -4
  49. data/app/pb_kits/playbook/pb_text_input/_text_input.scss +1 -0
  50. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +13 -17
  51. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +1 -0
  52. data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +0 -14
  53. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +1 -7
  54. data/app/pb_kits/playbook/pb_typeahead/components/Control.tsx +5 -6
  55. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +1 -3
  56. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +0 -2
  57. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +0 -1
  58. data/app/pb_kits/playbook/pb_typeahead/typeahead.html.erb +1 -2
  59. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +2 -9
  60. data/app/pb_kits/playbook/utilities/icons/allicons.tsx +13 -136
  61. data/dist/chunks/_typeahead-B2zRxReA.js +22 -0
  62. data/dist/chunks/_weekday_stacked-Co95UEiW.js +45 -0
  63. data/dist/chunks/lib-D2U4I1U6.js +16 -0
  64. data/dist/chunks/{pb_form_validation-D9zkwt2b.js → pb_form_validation-zV9OpdSt.js} +1 -1
  65. data/dist/chunks/vendor.js +1 -1
  66. data/dist/menu.yml +1 -3
  67. data/dist/playbook-doc.js +1 -1
  68. data/dist/playbook-rails-react-bindings.js +1 -1
  69. data/dist/playbook-rails.js +1 -1
  70. data/dist/playbook.css +1 -1
  71. data/lib/playbook/pagination_renderer.rb +2 -10
  72. data/lib/playbook/pb_doc_helper.rb +5 -5
  73. data/lib/playbook/version.rb +2 -2
  74. metadata +6 -35
  75. data/app/pb_kits/playbook/pb_drawer/_close_icon.tsx +0 -25
  76. data/app/pb_kits/playbook/pb_drawer/_drawer.scss +0 -465
  77. data/app/pb_kits/playbook/pb_drawer/_drawer.tsx +0 -195
  78. data/app/pb_kits/playbook/pb_drawer/_drawer_context.tsx +0 -3
  79. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_borders.jsx +0 -117
  80. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_breakpoints.jsx +0 -43
  81. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_default.html.erb +0 -1
  82. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_default.jsx +0 -63
  83. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_overlay.jsx +0 -55
  84. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_sizes.jsx +0 -113
  85. data/app/pb_kits/playbook/pb_drawer/docs/example.yml +0 -12
  86. data/app/pb_kits/playbook/pb_drawer/docs/index.js +0 -5
  87. data/app/pb_kits/playbook/pb_drawer/drawer.html.erb +0 -12
  88. data/app/pb_kits/playbook/pb_drawer/drawer.rb +0 -8
  89. data/app/pb_kits/playbook/pb_drawer/drawer.test.jsx +0 -77
  90. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb +0 -19
  91. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx +0 -27
  92. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.md +0 -1
  93. data/app/pb_kits/playbook/pb_multi_level_select/context/index.tsx +0 -5
  94. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx +0 -105
  95. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.md +0 -1
  96. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +0 -106
  97. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.md +0 -1
  98. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx +0 -149
  99. data/app/pb_kits/playbook/pb_radio/docs/_radio_custom_children.jsx +0 -62
  100. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_margin_bottom.html.erb +0 -88
  101. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_margin_bottom.jsx +0 -60
  102. data/app/pb_kits/playbook/utilities/icons/angle-down.svg +0 -3
  103. data/app/pb_kits/playbook/utilities/icons/envelope.svg +0 -3
  104. data/dist/chunks/_typeahead-CT2ByCBK.js +0 -22
  105. data/dist/chunks/_weekday_stacked-Bwdy1TtH.js +0 -45
  106. data/dist/chunks/lib-CEpcaI8y.js +0 -29
@@ -1,17 +1,14 @@
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";
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"
15
12
 
16
13
  import {
17
14
  getAncestorsOfUnchecked,
@@ -21,7 +18,7 @@ import {
21
18
  getDefaultCheckedItems,
22
19
  recursiveCheckParent,
23
20
  getExpandedItems,
24
- } from "./_helper_functions";
21
+ } from "./_helper_functions"
25
22
 
26
23
  type MultiLevelSelectProps = {
27
24
  aria?: { [key: string]: string }
@@ -33,9 +30,9 @@ type MultiLevelSelectProps = {
33
30
  inputName?: string
34
31
  name?: string
35
32
  returnAllSelected?: boolean
36
- treeData?: { [key: string]: string; }[] | any
33
+ treeData?: { [key: string]: string }[]
37
34
  onSelect?: (prop: { [key: string]: any }) => void
38
- selectedIds?: string[] | any
35
+ selectedIds?: string[]
39
36
  variant?: "multi" | "single"
40
37
  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",
41
38
  } & GlobalProps
@@ -55,152 +52,140 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
55
52
  onSelect = () => null,
56
53
  selectedIds,
57
54
  variant = "multi",
58
- children,
59
55
  pillColor = "primary"
60
56
  } = props
61
57
 
62
- const ariaProps = buildAriaProps(aria);
63
- const dataProps = buildDataProps(data);
64
- const htmlProps = buildHtmlProps(htmlOptions);
58
+ const ariaProps = buildAriaProps(aria)
59
+ const dataProps = buildDataProps(data)
60
+ const htmlProps = buildHtmlProps(htmlOptions)
65
61
  const classes = classnames(
66
62
  buildCss("pb_multi_level_select"),
67
63
  globalProps(props),
68
64
  className
69
- );
65
+ )
70
66
 
71
- const dropdownRef = useRef(null);
67
+ const dropdownRef = useRef(null)
72
68
 
73
69
  // State for whether dropdown is open or closed
74
- const [isDropdownClosed, setIsDropdownClosed] = useState(true);
70
+ const [isDropdownClosed, setIsDropdownClosed] = useState(true)
75
71
  // State from onChange for textinput, to use for filtering to create typeahead
76
- const [filterItem, setFilterItem] = useState("");
72
+ const [filterItem, setFilterItem] = useState("")
77
73
  // FormattedData with checked and parent_id added
78
- const [formattedData, setFormattedData] = useState([]);
74
+ const [formattedData, setFormattedData] = useState([])
79
75
  // State for the return of returnAllSelected
80
- const [returnedArray, setReturnedArray] = useState([]);
76
+ const [returnedArray, setReturnedArray] = useState([])
81
77
  // State for default return
82
- const [defaultReturn, setDefaultReturn] = useState([]);
78
+ const [defaultReturn, setDefaultReturn] = useState([])
83
79
  // Get expanded items from treeData
84
- const initialExpandedItems = getExpandedItems(treeData, selectedIds);
80
+ const initialExpandedItems = getExpandedItems(treeData, selectedIds)
85
81
  // Initialize state with expanded items
86
- const [expanded, setExpanded] = useState(initialExpandedItems);
82
+ const [expanded, setExpanded] = useState(initialExpandedItems)
87
83
 
88
84
  // Single Select specific state
89
85
  const [singleSelectedItem, setSingleSelectedItem] = useState({
90
86
  id: [],
91
87
  value: "",
92
- item: [],
93
- });
94
-
95
- const arrowDownElementId = `arrow_down_${id}`
96
- const arrowUpElementId = `arrow_up_${id}`
88
+ item: []
89
+ })
97
90
 
98
91
  const modifyRecursive = (tree: { [key: string]: any }[], check: boolean) => {
99
92
  if (!Array.isArray(tree)) {
100
- return;
93
+ return
101
94
  }
102
95
  return tree.map((item: { [key: string]: any }) => {
103
- item.checked = check;
104
- item.children = modifyRecursive(item.children, check);
105
- return item;
106
- });
107
- };
96
+ item.checked = check
97
+ item.children = modifyRecursive(item.children, check)
98
+ return item
99
+ })
100
+ }
108
101
 
109
- // Function to map over data and add parent_id + depth property to each item
102
+ // Function to map over data and add parent_id + depth property to each item
110
103
  const addCheckedAndParentProperty = (
111
104
  treeData: { [key: string]: any }[],
112
105
  selectedIds: string[],
113
- parent_id: string | null = null,
114
- depth = 0
106
+ parent_id: string = null,
107
+ depth = 0,
115
108
  ) => {
116
109
  if (!Array.isArray(treeData)) {
117
- return;
110
+ return
118
111
  }
119
112
  return treeData.map((item: { [key: string]: any } | any) => {
120
113
  const newItem = {
121
114
  ...item,
122
- checked: Boolean(
123
- selectedIds && selectedIds.length && selectedIds.includes(item.id)
124
- ),
115
+ checked: Boolean(selectedIds && selectedIds.length && selectedIds.includes(item.id)),
125
116
  parent_id,
126
117
  depth,
127
- };
118
+ }
128
119
  if (newItem.children && newItem.children.length > 0) {
129
120
  const children =
130
121
  item.checked && !returnAllSelected
131
122
  ? modifyRecursive(item.children, true)
132
- : item.children;
123
+ : item.children
133
124
  newItem.children = addCheckedAndParentProperty(
134
125
  children,
135
126
  selectedIds,
136
127
  newItem.id,
137
128
  depth + 1
138
- );
129
+ )
139
130
  }
140
- return newItem;
141
- });
142
- };
131
+ return newItem
132
+ })
133
+ }
143
134
 
144
135
  useEffect(() => {
145
136
  const formattedData = addCheckedAndParentProperty(
146
137
  treeData,
147
138
  variant === "single" ? [selectedIds?.[0]] : selectedIds
148
- );
139
+ )
149
140
 
150
- setFormattedData(formattedData);
141
+ setFormattedData(formattedData)
151
142
 
152
143
  if (variant === "single") {
153
144
  // No selectedIds, reset state
154
145
  if (selectedIds?.length === 0 || !selectedIds?.length) {
155
- setSingleSelectedItem({ id: [], value: "", item: [] });
146
+ setSingleSelectedItem({ id: [], value: "", item: []})
156
147
  } else {
157
148
  // If there is a selectedId but no current item, set the selectedItem
158
149
  if (selectedIds?.length !== 0 && !singleSelectedItem.value) {
159
- const selectedItem = filterFormattedDataById(
160
- formattedData,
161
- selectedIds[0]
162
- );
150
+ const selectedItem = filterFormattedDataById(formattedData, selectedIds[0])
163
151
 
164
152
  if (!selectedItem.length) {
165
- setSingleSelectedItem({ id: [], value: "", item: [] });
153
+ setSingleSelectedItem({ id: [], value: "", item: []})
166
154
  } else {
167
- const { id, value } = selectedItem[0];
168
- setSingleSelectedItem({ id: [id], value, item: selectedItem });
155
+ const { id, value } = selectedItem[0]
156
+ setSingleSelectedItem({ id: [id], value, item: selectedItem})
169
157
  }
170
158
  }
171
159
  }
172
160
  }
173
- }, [treeData, selectedIds]);
161
+ }, [treeData, selectedIds])
174
162
 
175
163
  useEffect(() => {
176
164
  if (returnAllSelected) {
177
- setReturnedArray(getCheckedItems(formattedData));
165
+ setReturnedArray(getCheckedItems(formattedData))
178
166
  } else if (variant === "single") {
179
- setDefaultReturn(singleSelectedItem.item);
167
+ setDefaultReturn(singleSelectedItem.item)
180
168
  } else {
181
- setDefaultReturn(getDefaultCheckedItems(formattedData));
169
+ setDefaultReturn(getDefaultCheckedItems(formattedData))
182
170
  }
183
- }, [formattedData]);
171
+ }, [formattedData])
184
172
 
185
173
  useEffect(() => {
186
174
  // Function to handle clicks outside the dropdown
187
175
  const handleClickOutside = (event: any) => {
188
- if (
189
- dropdownRef.current &&
190
- !dropdownRef.current.contains(event.target) &&
191
- event.target.id !== arrowDownElementId &&
192
- event.target.id !== arrowUpElementId
193
- ) {
176
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
194
177
  setIsDropdownClosed(true)
195
178
  }
196
- };
179
+ }
197
180
  // Attach the event listener
198
- window.addEventListener("click", handleClickOutside);
181
+ window.addEventListener("click", handleClickOutside)
199
182
  // Clean up the event listener on unmount
200
183
  return () => {
201
- window.removeEventListener("click", handleClickOutside);
202
- };
203
- }, []);
184
+ window.removeEventListener("click", handleClickOutside)
185
+ }
186
+ }, [])
187
+
188
+
204
189
 
205
190
  // Iterate over tree, find item and set checked or unchecked
206
191
  const modifyValue = (
@@ -209,182 +194,234 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
209
194
  check: boolean
210
195
  ) => {
211
196
  if (!Array.isArray(tree)) {
212
- return;
197
+ return
213
198
  }
214
199
  return tree.map((item: any) => {
215
- if (item.id != id) item.children = modifyValue(id, item.children, check);
200
+ if (item.id != id) item.children = modifyValue(id, item.children, check)
216
201
  else {
217
- item.checked = check;
202
+ item.checked = check
218
203
 
219
204
  if (variant === "single") {
220
205
  // Single select: no children should be checked
221
- item.children = modifyRecursive(item.children, !check);
206
+ item.children = modifyRecursive(item.children, !check)
222
207
  } else {
223
- item.children = modifyRecursive(item.children, check);
208
+ item.children = modifyRecursive(item.children, check)
224
209
  }
225
210
  }
226
211
 
227
- return item;
228
- });
229
- };
212
+ return item
213
+ })
214
+ }
230
215
 
231
216
  // Clone tree, check items + children
232
217
  const checkItem = (item: { [key: string]: any }) => {
233
- const tree = cloneDeep(formattedData);
218
+ const tree = cloneDeep(formattedData)
234
219
  if (returnAllSelected) {
235
- return modifyValue(item.id, tree, true);
220
+ return modifyValue(item.id, tree, true)
236
221
  } else {
237
- const checkedTree = modifyValue(item.id, tree, true);
238
- return recursiveCheckParent(item, checkedTree);
222
+ const checkedTree = modifyValue(item.id, tree, true)
223
+ return recursiveCheckParent(item, checkedTree)
239
224
  }
240
- };
225
+ }
241
226
 
242
227
  // Clone tree, uncheck items + children
243
228
  const unCheckItem = (item: { [key: string]: any }) => {
244
- const tree = cloneDeep(formattedData);
229
+ const tree = cloneDeep(formattedData)
245
230
  if (returnAllSelected) {
246
- return modifyValue(item.id, tree, false);
231
+ return modifyValue(item.id, tree, false)
247
232
  } else {
248
- const uncheckedTree = modifyValue(item.id, tree, false);
249
- return getAncestorsOfUnchecked(uncheckedTree, item);
233
+ const uncheckedTree = modifyValue(item.id, tree, false)
234
+ return getAncestorsOfUnchecked(uncheckedTree, item)
250
235
  }
251
- };
236
+ }
252
237
 
253
238
  // setFormattedData with proper properties
254
239
  const changeItem = (item: { [key: string]: any }, check: boolean) => {
255
- const tree = check ? checkItem(item) : unCheckItem(item);
256
- setFormattedData(tree);
240
+ const tree = check ? checkItem(item) : unCheckItem(item)
241
+ setFormattedData(tree)
257
242
 
258
- return tree;
259
- };
243
+ return tree
244
+ }
245
+
246
+
260
247
 
261
248
  // Click event for x on form pill
262
249
  const handlePillClose = (event: any, clickedItem: { [key: string]: any }) => {
263
250
  // Prevents the dropdown from closing when clicking on the pill
264
- event.stopPropagation();
265
- const updatedTree = changeItem(clickedItem, false);
251
+ event.stopPropagation()
252
+ const updatedTree = changeItem(clickedItem, false)
266
253
  // Logic for removing items from returnArray or defaultReturn when pills clicked
267
254
  if (returnAllSelected) {
268
- onSelect(getCheckedItems(updatedTree));
255
+ onSelect(getCheckedItems(updatedTree))
269
256
  } else {
270
- onSelect(getDefaultCheckedItems(updatedTree));
257
+ onSelect(getDefaultCheckedItems(updatedTree))
271
258
  }
272
- };
259
+ }
273
260
 
274
261
  // Handle click on input wrapper(entire div with pills, typeahead, etc) so it doesn't close when input or form pill is clicked
275
262
  const handleInputWrapperClick = (e: any) => {
263
+ e.stopPropagation()
276
264
  if (
277
265
  e.target.id === "multiselect_input" ||
278
266
  e.target.classList.contains("pb_form_pill_tag")
279
267
  ) {
280
- return;
268
+ return
281
269
  }
282
- setIsDropdownClosed(!isDropdownClosed);
283
- };
270
+ setIsDropdownClosed(!isDropdownClosed)
271
+ }
284
272
 
285
273
  // Main function to handle any click inside dropdown
286
274
  const handledropdownItemClick = (e: any, check: boolean) => {
287
- const clickedItem = e.target.parentNode.id;
275
+ const clickedItem = e.target.parentNode.id
288
276
  // Setting filterItem to "" will clear textinput and clear typeahead
289
- setFilterItem("");
277
+ setFilterItem("")
290
278
 
291
- const filtered = filterFormattedDataById(formattedData, clickedItem);
292
- const updatedTree = changeItem(filtered[0], check);
279
+ const filtered = filterFormattedDataById(formattedData, clickedItem)
280
+ const updatedTree = changeItem(filtered[0], check)
293
281
  if (returnAllSelected) {
294
- onSelect(getCheckedItems(updatedTree));
282
+ onSelect(getCheckedItems(updatedTree))
295
283
  } else {
296
- onSelect(getDefaultCheckedItems(updatedTree));
284
+ onSelect(getDefaultCheckedItems(updatedTree))
297
285
  }
298
- };
286
+ }
299
287
 
300
288
  // Single select
301
- const handleRadioButtonClick = (e: React.ChangeEvent<HTMLInputElement>) => {
302
- const { id, value: inputText } = e.target;
289
+ const handleRadioButtonClick = (
290
+ e: React.ChangeEvent<HTMLInputElement>,
291
+ ) => {
292
+ const { id, value: inputText } = e.target
303
293
  // The radio button needs a unique ID, this grabs the ID before the hyphen
304
- const selectedItemID = id.match(/^[^-]*/)[0];
294
+ const selectedItemID = id.match(/^[^-]*/)[0]
305
295
  // Reset tree checked state, triggering useEffect
306
- const treeWithNoSelections = modifyRecursive(formattedData, false);
296
+ const treeWithNoSelections = modifyRecursive(formattedData, false)
307
297
  // Update tree with single selection
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
- });
298
+ const treeWithSelectedItem = modifyValue(selectedItemID, treeWithNoSelections, true)
299
+ const selectedItem = filterFormattedDataById(treeWithSelectedItem, selectedItemID)
300
+
301
+ setFormattedData(treeWithSelectedItem)
302
+ setSingleSelectedItem({id: [selectedItemID], value: inputText, item: selectedItem})
324
303
  // Reset the filter to always display dropdown options on click
325
- setFilterItem("");
326
- setIsDropdownClosed(true);
304
+ setFilterItem("")
305
+ setIsDropdownClosed(true)
327
306
 
328
- onSelect(selectedItem);
307
+ onSelect(selectedItem)
329
308
  };
330
309
 
331
310
  // Single select: reset the tree state upon typing
332
311
  const handleRadioInputChange = (inputText: string) => {
333
- modifyRecursive(formattedData, false);
334
- setDefaultReturn([]);
335
- setSingleSelectedItem({ id: [], value: inputText, item: [] });
336
- setFilterItem(inputText);
312
+ modifyRecursive(formattedData, false)
313
+ setDefaultReturn([])
314
+ setSingleSelectedItem({id: [], value: inputText, item: []})
315
+ setFilterItem(inputText)
337
316
  };
338
317
 
339
- const isTreeRowExpanded = (item: any) => expanded.indexOf(item.id) > -1;
318
+ const isTreeRowExpanded = (item: any) => expanded.indexOf(item.id) > -1
340
319
 
341
320
  // Handle click on chevron toggles in dropdown
342
321
  const handleToggleClick = (id: string, event: React.MouseEvent) => {
343
- event.stopPropagation();
344
- const clickedItem = filterFormattedDataById(formattedData, id);
322
+ event.stopPropagation()
323
+ const clickedItem = filterFormattedDataById(formattedData, id)
345
324
  if (clickedItem) {
346
- let expandedArray = [...expanded];
347
- const itemExpanded = isTreeRowExpanded(clickedItem[0]);
325
+ let expandedArray = [...expanded]
326
+ const itemExpanded = isTreeRowExpanded(clickedItem[0])
348
327
 
349
328
  if (itemExpanded)
350
- expandedArray = expandedArray.filter((i) => i != clickedItem[0].id);
351
- else expandedArray.push(clickedItem[0].id);
329
+ expandedArray = expandedArray.filter((i) => i != clickedItem[0].id)
330
+ else expandedArray.push(clickedItem[0].id)
352
331
 
353
- setExpanded(expandedArray);
332
+ setExpanded(expandedArray)
354
333
  }
355
- };
334
+ }
356
335
 
357
336
  const itemsSelectedLength = () => {
358
- let items;
337
+ let items
359
338
  if (returnAllSelected && returnedArray && returnedArray.length) {
360
- items = returnedArray.length;
339
+ items = returnedArray.length
361
340
  } else if (!returnAllSelected && defaultReturn && defaultReturn.length) {
362
- items = defaultReturn.length;
341
+ items = defaultReturn.length
363
342
  }
364
- return items;
365
- };
343
+ return items
344
+ }
366
345
 
367
346
  // Rendering formattedData to UI based on typeahead
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
-
347
+ const renderNestedOptions = (items: { [key: string]: any }[]) => {
348
+ return (
349
+ <ul>
350
+ {Array.isArray(items) &&
351
+ items.map((item: { [key: string]: any }) => {
352
+ return (
353
+ <div key={item.id}>
354
+ <li
355
+ className={"dropdown_item"}
356
+ data-name={item.id}
357
+ >
358
+ <div className="dropdown_item_checkbox_row">
359
+ { !item.parent_id && !item.children ? null :
360
+ <div
361
+ key={isTreeRowExpanded(item) ? "chevron-down" : "chevron-right"}
362
+ >
363
+ <CircleIconButton
364
+ className={
365
+ item.children && item.children.length > 0
366
+ ? ""
367
+ : "toggle_icon"
368
+ }
369
+ icon={
370
+ isTreeRowExpanded(item) ? "chevron-down" : "chevron-right"
371
+ }
372
+ onClick={(event: any) =>
373
+ handleToggleClick(item.id, event)
374
+ }
375
+ variant="link"
376
+ />
377
+ </div>
378
+ }
379
+ { variant === "single" ? (
380
+ item.hideRadio ? (
381
+ <Body>{item.label}</Body>
382
+ ) :
383
+ <Radio
384
+ checked={item.checked}
385
+ id={`${item.id}-${item.label}`}
386
+ label={item.label}
387
+ name={inputName}
388
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => (
389
+ handleRadioButtonClick(e)
390
+ )}
391
+ padding={item.children ? 'none' : 'xs'}
392
+ type="radio"
393
+ value={item.label}
394
+ />
395
+ ) : (
396
+ <Checkbox
397
+ id={item.id}
398
+ text={item.label}
399
+ >
400
+ <input
401
+ checked={item.checked}
402
+ name={item.label}
403
+ onChange={(e) => {
404
+ handledropdownItemClick(e, !item.checked)
405
+ }}
406
+ type="checkbox"
407
+ value={item.label}
408
+ />
409
+ </Checkbox>
410
+ )}
411
+ </div>
412
+ {isTreeRowExpanded(item) &&
413
+ item.children &&
414
+ item.children.length > 0 &&
415
+ (variant === "single" || !filterItem) && ( // Show children if expanded is true
416
+ <div>{renderNestedOptions(item.children)}</div>
417
+ )}
418
+ </li>
419
+ </div>
420
+ )
421
+ })}
422
+ </ul>
423
+ )
424
+ }
388
425
 
389
426
  return (
390
427
  <div
@@ -394,20 +431,12 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
394
431
  className={classes}
395
432
  id={id}
396
433
  >
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"
434
+ <div
435
+ className="wrapper"
408
436
  ref={dropdownRef}
409
437
  >
410
- <div className="input_wrapper"
438
+ <div
439
+ className="input_wrapper"
411
440
  onClick={handleInputWrapperClick}
412
441
  >
413
442
  <div className="input_inner_container">
@@ -473,17 +502,15 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
473
502
 
474
503
  <input
475
504
  id="multiselect_input"
476
- onChange={(e) => {
505
+ onChange={(e) =>{
477
506
  variant === "single"
478
507
  ? handleRadioInputChange(e.target.value)
479
- : setFilterItem(e.target.value);
508
+ : setFilterItem(e.target.value)
480
509
  }}
481
510
  onClick={() => setIsDropdownClosed(false)}
482
511
  placeholder={
483
512
  inputDisplay === "none" && itemsSelectedLength()
484
- ? `${itemsSelectedLength()} ${
485
- itemsSelectedLength() === 1 ? "item" : "items"
486
- } selected`
513
+ ? `${itemsSelectedLength()} ${itemsSelectedLength() === 1 ? "item" : "items"} selected`
487
514
  : "Start typing..."
488
515
  }
489
516
  value={singleSelectedItem.value || filterItem}
@@ -491,20 +518,16 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
491
518
  </div>
492
519
 
493
520
  {isDropdownClosed ? (
494
- <div id={arrowDownElementId}
495
- key="chevron-down">
521
+ <div key="chevron-down">
496
522
  <Icon
497
523
  icon="chevron-down"
498
- id={arrowDownElementId}
499
524
  size="xs"
500
525
  />
501
526
  </div>
502
527
  ) : (
503
- <div id={arrowUpElementId}
504
- key="chevron-up">
528
+ <div key="chevron-up">
505
529
  <Icon
506
530
  icon="chevron-up"
507
- id={arrowUpElementId}
508
531
  size="xs"
509
532
  />
510
533
  </div>
@@ -512,16 +535,15 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
512
535
  </div>
513
536
 
514
537
  <div className={`dropdown_menu ${isDropdownClosed ? "close" : "open"}`}>
515
- {renderNestedOptions(
516
- filterItem ? findByFilter(formattedData, filterItem) : formattedData
517
- )}
538
+ {renderNestedOptions(
539
+ filterItem
540
+ ? findByFilter(formattedData, filterItem)
541
+ : formattedData
542
+ )}
518
543
  </div>
519
544
  </div>
520
- </MultiLevelSelectContext.Provider>
521
545
  </div>
522
- );
523
- };
524
-
525
- MultiLevelSelect.Options = MultiLevelSelectOptions;
546
+ )
547
+ }
526
548
 
527
- export default MultiLevelSelect;
549
+ export default MultiLevelSelect