playbook_ui 14.5.0.pre.alpha.PLAY1485selectablecardoverflowoutlinebug4216 → 14.5.0.pre.alpha.PLAY1486highchartscssdrivenPOC3930

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +7 -25
  3. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +0 -2
  4. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +0 -1
  5. data/app/pb_kits/playbook/pb_advanced_table/index.js +0 -60
  6. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +9 -1
  7. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.html.erb +9 -1
  8. data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.scss +54 -0
  9. data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx +5 -184
  10. data/app/pb_kits/playbook/pb_bar_graph/barGraph.test.js +1 -1
  11. data/app/pb_kits/playbook/pb_card/_card.tsx +1 -5
  12. data/app/pb_kits/playbook/pb_card/_card_mixin.scss +2 -1
  13. data/app/pb_kits/playbook/pb_circle_chart/_circle_chart.tsx +5 -216
  14. data/app/pb_kits/playbook/pb_circle_chart/circleChart.test.js +1 -1
  15. data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +1 -5
  16. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.html.erb +7 -30
  17. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.md +2 -0
  18. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +3 -84
  19. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +5 -28
  20. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +0 -5
  21. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +0 -3
  22. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +1 -10
  23. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +1 -1
  24. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +2 -2
  25. data/app/pb_kits/playbook/pb_filter/Filter/FilterDouble.tsx +0 -2
  26. data/app/pb_kits/playbook/pb_filter/Filter/FilterSingle.tsx +0 -2
  27. data/app/pb_kits/playbook/pb_filter/Filter/FiltersPopover.tsx +1 -4
  28. data/app/pb_kits/playbook/pb_filter/Filter/ResultsCount.tsx +2 -4
  29. data/app/pb_kits/playbook/pb_filter/docs/_filter_default.jsx +1 -1
  30. data/app/pb_kits/playbook/pb_filter/docs/example.yml +0 -3
  31. data/app/pb_kits/playbook/pb_filter/docs/index.js +0 -1
  32. data/app/pb_kits/playbook/pb_filter/filter.html.erb +2 -2
  33. data/app/pb_kits/playbook/pb_filter/filter.rb +0 -2
  34. data/app/pb_kits/playbook/pb_flex/_flex.tsx +1 -3
  35. data/app/pb_kits/playbook/pb_flex/_flex_item.tsx +2 -8
  36. data/app/pb_kits/playbook/pb_flex/flex_item.html.erb +6 -3
  37. data/app/pb_kits/playbook/pb_flex/flex_item.rb +2 -7
  38. data/app/pb_kits/playbook/pb_form/docs/example.yml +0 -1
  39. data/app/pb_kits/playbook/pb_form/form.rb +0 -2
  40. data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +1 -9
  41. data/app/pb_kits/playbook/pb_form_pill/docs/example.yml +0 -2
  42. data/app/pb_kits/playbook/pb_form_pill/docs/index.js +0 -1
  43. data/app/pb_kits/playbook/pb_gantt_chart/_gantt_chart.tsx +3 -64
  44. data/app/pb_kits/playbook/pb_gauge/_gauge.tsx +5 -203
  45. data/app/pb_kits/playbook/pb_gauge/gauge.test.js +1 -1
  46. data/app/pb_kits/playbook/pb_line_graph/_line_graph.tsx +5 -154
  47. data/app/pb_kits/playbook/pb_line_graph/lineGraph.test.js +1 -1
  48. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +227 -211
  49. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +1 -1
  50. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +0 -4
  51. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +0 -2
  52. data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.scss +65 -169
  53. data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.test.js +5 -5
  54. data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.tsx +9 -15
  55. data/app/pb_kits/playbook/pb_multiple_users_stacked/docs/example.yml +0 -2
  56. data/app/pb_kits/playbook/pb_multiple_users_stacked/docs/index.js +0 -1
  57. data/app/pb_kits/playbook/pb_multiple_users_stacked/multiple_users_stacked.html.erb +6 -28
  58. data/app/pb_kits/playbook/pb_multiple_users_stacked/multiple_users_stacked.rb +1 -31
  59. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +18 -86
  60. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +6 -15
  61. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_preferred_countries.md +1 -1
  62. data/app/pb_kits/playbook/pb_phone_number_input/intlTelInput.scss +931 -849
  63. data/app/pb_kits/playbook/pb_phone_number_input/types.d.ts +1 -4
  64. data/app/pb_kits/playbook/pb_popover/_popover.tsx +2 -6
  65. data/app/pb_kits/playbook/pb_popover/docs/_popover_default.html.erb +1 -1
  66. data/app/pb_kits/playbook/pb_popover/popover.rb +1 -3
  67. data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.scss +1 -67
  68. data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.tsx +0 -1
  69. data/app/pb_kits/playbook/pb_selectable_card/selectable_card.html.erb +1 -1
  70. data/app/pb_kits/playbook/pb_selectable_card/selectable_card.rb +1 -5
  71. data/app/pb_kits/playbook/pb_treemap_chart/_treemap_chart.tsx +5 -113
  72. data/app/pb_kits/playbook/pb_treemap_chart/treemapChart.test.js +1 -1
  73. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +1 -4
  74. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +1 -3
  75. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +1 -3
  76. data/app/pb_kits/playbook/utilities/globalPropNames.mjs +0 -3
  77. data/app/pb_kits/playbook/utilities/globalProps.ts +2 -39
  78. data/dist/chunks/_typeahead-BywvWGAm.js +22 -0
  79. data/dist/chunks/_weekday_stacked-5OGZKZeo.js +45 -0
  80. data/dist/chunks/lib-DMOmCoAX.js +29 -0
  81. data/dist/chunks/{pb_form_validation-BkWGwJsl.js → pb_form_validation-Dna2I7fw.js} +1 -1
  82. data/dist/chunks/vendor.js +1 -1
  83. data/dist/playbook-doc.js +1 -1
  84. data/dist/playbook-rails-react-bindings.js +1 -1
  85. data/dist/playbook-rails.js +1 -1
  86. data/dist/playbook.css +1 -1
  87. data/lib/playbook/kit_base.rb +1 -21
  88. data/lib/playbook/pb_doc_helper.rb +5 -5
  89. data/lib/playbook/pb_forms_helper.rb +1 -3
  90. data/lib/playbook/version.rb +1 -1
  91. metadata +6 -35
  92. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell.jsx +0 -72
  93. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell.md +0 -5
  94. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_clear_selection.jsx +0 -45
  95. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_clear_selection.md +0 -1
  96. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_separators_hidden.html.erb +0 -9
  97. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_separators_hidden.jsx +0 -33
  98. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subtle_variant.html.erb +0 -10
  99. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subtle_variant.jsx +0 -34
  100. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subtle_variant.md +0 -1
  101. data/app/pb_kits/playbook/pb_filter/docs/_filter_popover_props.html.erb +0 -41
  102. data/app/pb_kits/playbook/pb_filter/docs/_filter_popover_props.jsx +0 -71
  103. data/app/pb_kits/playbook/pb_filter/docs/_filter_popover_props_rails.md +0 -1
  104. data/app/pb_kits/playbook/pb_filter/docs/_filter_popover_props_react.md +0 -1
  105. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb +0 -39
  106. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.md +0 -1
  107. data/app/pb_kits/playbook/pb_form/formHelper.js +0 -27
  108. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb +0 -19
  109. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx +0 -27
  110. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.md +0 -1
  111. data/app/pb_kits/playbook/pb_multi_level_select/context/index.tsx +0 -5
  112. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_reset.html.erb +0 -93
  113. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_reset.md +0 -1
  114. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx +0 -105
  115. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.md +0 -1
  116. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +0 -106
  117. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.md +0 -1
  118. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx +0 -149
  119. data/app/pb_kits/playbook/pb_multiple_users_stacked/docs/_multiple_users_stacked_size.html.erb +0 -336
  120. data/app/pb_kits/playbook/pb_multiple_users_stacked/docs/_multiple_users_stacked_size.jsx +0 -97
  121. data/dist/chunks/_typeahead-BhHnXJjy.js +0 -22
  122. data/dist/chunks/_weekday_stacked-B9Sy5PN8.js +0 -45
  123. data/dist/chunks/lib-D-mTv-kp.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,132 +52,126 @@ 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
- });
88
+ item: []
89
+ })
94
90
 
95
91
  const arrowDownElementId = `arrow_down_${id}`
96
92
  const arrowUpElementId = `arrow_up_${id}`
97
93
 
98
94
  const modifyRecursive = (tree: { [key: string]: any }[], check: boolean) => {
99
95
  if (!Array.isArray(tree)) {
100
- return;
96
+ return
101
97
  }
102
98
  return tree.map((item: { [key: string]: any }) => {
103
- item.checked = check;
104
- item.children = modifyRecursive(item.children, check);
105
- return item;
106
- });
107
- };
99
+ item.checked = check
100
+ item.children = modifyRecursive(item.children, check)
101
+ return item
102
+ })
103
+ }
108
104
 
109
- // Function to map over data and add parent_id + depth property to each item
105
+ // Function to map over data and add parent_id + depth property to each item
110
106
  const addCheckedAndParentProperty = (
111
107
  treeData: { [key: string]: any }[],
112
108
  selectedIds: string[],
113
- parent_id: string | null = null,
114
- depth = 0
109
+ parent_id: string = null,
110
+ depth = 0,
115
111
  ) => {
116
112
  if (!Array.isArray(treeData)) {
117
- return;
113
+ return
118
114
  }
119
115
  return treeData.map((item: { [key: string]: any } | any) => {
120
116
  const newItem = {
121
117
  ...item,
122
- checked: Boolean(
123
- selectedIds && selectedIds.length && selectedIds.includes(item.id)
124
- ),
118
+ checked: Boolean(selectedIds && selectedIds.length && selectedIds.includes(item.id)),
125
119
  parent_id,
126
120
  depth,
127
- };
121
+ }
128
122
  if (newItem.children && newItem.children.length > 0) {
129
123
  const children =
130
124
  item.checked && !returnAllSelected
131
125
  ? modifyRecursive(item.children, true)
132
- : item.children;
126
+ : item.children
133
127
  newItem.children = addCheckedAndParentProperty(
134
128
  children,
135
129
  selectedIds,
136
130
  newItem.id,
137
131
  depth + 1
138
- );
132
+ )
139
133
  }
140
- return newItem;
141
- });
142
- };
134
+ return newItem
135
+ })
136
+ }
143
137
 
144
138
  useEffect(() => {
145
139
  const formattedData = addCheckedAndParentProperty(
146
140
  treeData,
147
141
  variant === "single" ? [selectedIds?.[0]] : selectedIds
148
- );
142
+ )
149
143
 
150
- setFormattedData(formattedData);
144
+ setFormattedData(formattedData)
151
145
 
152
146
  if (variant === "single") {
153
147
  // No selectedIds, reset state
154
148
  if (selectedIds?.length === 0 || !selectedIds?.length) {
155
- setSingleSelectedItem({ id: [], value: "", item: [] });
149
+ setSingleSelectedItem({ id: [], value: "", item: []})
156
150
  } else {
157
151
  // If there is a selectedId but no current item, set the selectedItem
158
152
  if (selectedIds?.length !== 0 && !singleSelectedItem.value) {
159
- const selectedItem = filterFormattedDataById(
160
- formattedData,
161
- selectedIds[0]
162
- );
153
+ const selectedItem = filterFormattedDataById(formattedData, selectedIds[0])
163
154
 
164
155
  if (!selectedItem.length) {
165
- setSingleSelectedItem({ id: [], value: "", item: [] });
156
+ setSingleSelectedItem({ id: [], value: "", item: []})
166
157
  } else {
167
- const { id, value } = selectedItem[0];
168
- setSingleSelectedItem({ id: [id], value, item: selectedItem });
158
+ const { id, value } = selectedItem[0]
159
+ setSingleSelectedItem({ id: [id], value, item: selectedItem})
169
160
  }
170
161
  }
171
162
  }
172
163
  }
173
- }, [treeData, selectedIds]);
164
+ }, [treeData, selectedIds])
174
165
 
175
166
  useEffect(() => {
176
167
  if (returnAllSelected) {
177
- setReturnedArray(getCheckedItems(formattedData));
168
+ setReturnedArray(getCheckedItems(formattedData))
178
169
  } else if (variant === "single") {
179
- setDefaultReturn(singleSelectedItem.item);
170
+ setDefaultReturn(singleSelectedItem.item)
180
171
  } else {
181
- setDefaultReturn(getDefaultCheckedItems(formattedData));
172
+ setDefaultReturn(getDefaultCheckedItems(formattedData))
182
173
  }
183
- }, [formattedData]);
174
+ }, [formattedData])
184
175
 
185
176
  useEffect(() => {
186
177
  // Function to handle clicks outside the dropdown
@@ -193,31 +184,16 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
193
184
  ) {
194
185
  setIsDropdownClosed(true)
195
186
  }
196
- };
187
+ }
197
188
  // Attach the event listener
198
- window.addEventListener("click", handleClickOutside);
189
+ window.addEventListener("click", handleClickOutside)
199
190
  // Clean up the event listener on unmount
200
191
  return () => {
201
- window.removeEventListener("click", handleClickOutside);
202
- };
203
- }, []);
204
-
205
- useEffect(() => {
206
- if (id) {
207
- // Attach the clear function to the window, scoped by the id
208
- (window as any)[`clearMultiLevelSelect_${id}`] = () => {
209
- const resetData = modifyRecursive(formattedData, false);
210
- setFormattedData(resetData);
211
- setReturnedArray([]);
212
- setDefaultReturn([]);
213
- setSingleSelectedItem({ id: [], value: "", item: [] });
214
- onSelect([]);
215
- };
216
- return () => {
217
- delete (window as any)[`clearMultiLevelSelect_${id}`];
218
- };
192
+ window.removeEventListener("click", handleClickOutside)
219
193
  }
220
- }, [formattedData, id, onSelect]);
194
+ }, [])
195
+
196
+
221
197
 
222
198
  // Iterate over tree, find item and set checked or unchecked
223
199
  const modifyValue = (
@@ -226,67 +202,69 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
226
202
  check: boolean
227
203
  ) => {
228
204
  if (!Array.isArray(tree)) {
229
- return;
205
+ return
230
206
  }
231
207
  return tree.map((item: any) => {
232
- if (item.id != id) item.children = modifyValue(id, item.children, check);
208
+ if (item.id != id) item.children = modifyValue(id, item.children, check)
233
209
  else {
234
- item.checked = check;
210
+ item.checked = check
235
211
 
236
212
  if (variant === "single") {
237
213
  // Single select: no children should be checked
238
- item.children = modifyRecursive(item.children, !check);
214
+ item.children = modifyRecursive(item.children, !check)
239
215
  } else {
240
- item.children = modifyRecursive(item.children, check);
216
+ item.children = modifyRecursive(item.children, check)
241
217
  }
242
218
  }
243
219
 
244
- return item;
245
- });
246
- };
220
+ return item
221
+ })
222
+ }
247
223
 
248
224
  // Clone tree, check items + children
249
225
  const checkItem = (item: { [key: string]: any }) => {
250
- const tree = cloneDeep(formattedData);
226
+ const tree = cloneDeep(formattedData)
251
227
  if (returnAllSelected) {
252
- return modifyValue(item.id, tree, true);
228
+ return modifyValue(item.id, tree, true)
253
229
  } else {
254
- const checkedTree = modifyValue(item.id, tree, true);
255
- return recursiveCheckParent(item, checkedTree);
230
+ const checkedTree = modifyValue(item.id, tree, true)
231
+ return recursiveCheckParent(item, checkedTree)
256
232
  }
257
- };
233
+ }
258
234
 
259
235
  // Clone tree, uncheck items + children
260
236
  const unCheckItem = (item: { [key: string]: any }) => {
261
- const tree = cloneDeep(formattedData);
237
+ const tree = cloneDeep(formattedData)
262
238
  if (returnAllSelected) {
263
- return modifyValue(item.id, tree, false);
239
+ return modifyValue(item.id, tree, false)
264
240
  } else {
265
- const uncheckedTree = modifyValue(item.id, tree, false);
266
- return getAncestorsOfUnchecked(uncheckedTree, item);
241
+ const uncheckedTree = modifyValue(item.id, tree, false)
242
+ return getAncestorsOfUnchecked(uncheckedTree, item)
267
243
  }
268
- };
244
+ }
269
245
 
270
246
  // setFormattedData with proper properties
271
247
  const changeItem = (item: { [key: string]: any }, check: boolean) => {
272
- const tree = check ? checkItem(item) : unCheckItem(item);
273
- setFormattedData(tree);
248
+ const tree = check ? checkItem(item) : unCheckItem(item)
249
+ setFormattedData(tree)
274
250
 
275
- return tree;
276
- };
251
+ return tree
252
+ }
253
+
254
+
277
255
 
278
256
  // Click event for x on form pill
279
257
  const handlePillClose = (event: any, clickedItem: { [key: string]: any }) => {
280
258
  // Prevents the dropdown from closing when clicking on the pill
281
- event.stopPropagation();
282
- const updatedTree = changeItem(clickedItem, false);
259
+ event.stopPropagation()
260
+ const updatedTree = changeItem(clickedItem, false)
283
261
  // Logic for removing items from returnArray or defaultReturn when pills clicked
284
262
  if (returnAllSelected) {
285
- onSelect(getCheckedItems(updatedTree));
263
+ onSelect(getCheckedItems(updatedTree))
286
264
  } else {
287
- onSelect(getDefaultCheckedItems(updatedTree));
265
+ onSelect(getDefaultCheckedItems(updatedTree))
288
266
  }
289
- };
267
+ }
290
268
 
291
269
  // Handle click on input wrapper(entire div with pills, typeahead, etc) so it doesn't close when input or form pill is clicked
292
270
  const handleInputWrapperClick = (e: any) => {
@@ -294,114 +272,163 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
294
272
  e.target.id === "multiselect_input" ||
295
273
  e.target.classList.contains("pb_form_pill_tag")
296
274
  ) {
297
- return;
275
+ return
298
276
  }
299
- setIsDropdownClosed(!isDropdownClosed);
300
- };
277
+ setIsDropdownClosed(!isDropdownClosed)
278
+ }
301
279
 
302
280
  // Main function to handle any click inside dropdown
303
281
  const handledropdownItemClick = (e: any, check: boolean) => {
304
- const clickedItem = e.target.parentNode.id;
282
+ const clickedItem = e.target.parentNode.id
305
283
  // Setting filterItem to "" will clear textinput and clear typeahead
306
- setFilterItem("");
284
+ setFilterItem("")
307
285
 
308
- const filtered = filterFormattedDataById(formattedData, clickedItem);
309
- const updatedTree = changeItem(filtered[0], check);
286
+ const filtered = filterFormattedDataById(formattedData, clickedItem)
287
+ const updatedTree = changeItem(filtered[0], check)
310
288
  if (returnAllSelected) {
311
- onSelect(getCheckedItems(updatedTree));
289
+ onSelect(getCheckedItems(updatedTree))
312
290
  } else {
313
- onSelect(getDefaultCheckedItems(updatedTree));
291
+ onSelect(getDefaultCheckedItems(updatedTree))
314
292
  }
315
- };
293
+ }
316
294
 
317
295
  // Single select
318
- const handleRadioButtonClick = (e: React.ChangeEvent<HTMLInputElement>) => {
319
- const { id, value: inputText } = e.target;
296
+ const handleRadioButtonClick = (
297
+ e: React.ChangeEvent<HTMLInputElement>,
298
+ ) => {
299
+ const { id, value: inputText } = e.target
320
300
  // The radio button needs a unique ID, this grabs the ID before the hyphen
321
- const selectedItemID = id.match(/^[^-]*/)[0];
301
+ const selectedItemID = id.match(/^[^-]*/)[0]
322
302
  // Reset tree checked state, triggering useEffect
323
- const treeWithNoSelections = modifyRecursive(formattedData, false);
303
+ const treeWithNoSelections = modifyRecursive(formattedData, false)
324
304
  // Update tree with single selection
325
- const treeWithSelectedItem = modifyValue(
326
- selectedItemID,
327
- treeWithNoSelections,
328
- true
329
- );
330
- const selectedItem = filterFormattedDataById(
331
- treeWithSelectedItem,
332
- selectedItemID
333
- );
334
-
335
- setFormattedData(treeWithSelectedItem);
336
- setSingleSelectedItem({
337
- id: [selectedItemID],
338
- value: inputText,
339
- item: selectedItem,
340
- });
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})
341
310
  // Reset the filter to always display dropdown options on click
342
- setFilterItem("");
343
- setIsDropdownClosed(true);
311
+ setFilterItem("")
312
+ setIsDropdownClosed(true)
344
313
 
345
- onSelect(selectedItem);
314
+ onSelect(selectedItem)
346
315
  };
347
316
 
348
317
  // Single select: reset the tree state upon typing
349
318
  const handleRadioInputChange = (inputText: string) => {
350
- modifyRecursive(formattedData, false);
351
- setDefaultReturn([]);
352
- setSingleSelectedItem({ id: [], value: inputText, item: [] });
353
- setFilterItem(inputText);
319
+ modifyRecursive(formattedData, false)
320
+ setDefaultReturn([])
321
+ setSingleSelectedItem({id: [], value: inputText, item: []})
322
+ setFilterItem(inputText)
354
323
  };
355
324
 
356
- const isTreeRowExpanded = (item: any) => expanded.indexOf(item.id) > -1;
325
+ const isTreeRowExpanded = (item: any) => expanded.indexOf(item.id) > -1
357
326
 
358
327
  // Handle click on chevron toggles in dropdown
359
328
  const handleToggleClick = (id: string, event: React.MouseEvent) => {
360
- event.stopPropagation();
361
- const clickedItem = filterFormattedDataById(formattedData, id);
329
+ event.stopPropagation()
330
+ const clickedItem = filterFormattedDataById(formattedData, id)
362
331
  if (clickedItem) {
363
- let expandedArray = [...expanded];
364
- const itemExpanded = isTreeRowExpanded(clickedItem[0]);
332
+ let expandedArray = [...expanded]
333
+ const itemExpanded = isTreeRowExpanded(clickedItem[0])
365
334
 
366
335
  if (itemExpanded)
367
- expandedArray = expandedArray.filter((i) => i != clickedItem[0].id);
368
- else expandedArray.push(clickedItem[0].id);
336
+ expandedArray = expandedArray.filter((i) => i != clickedItem[0].id)
337
+ else expandedArray.push(clickedItem[0].id)
369
338
 
370
- setExpanded(expandedArray);
339
+ setExpanded(expandedArray)
371
340
  }
372
- };
341
+ }
373
342
 
374
343
  const itemsSelectedLength = () => {
375
- let items;
344
+ let items
376
345
  if (returnAllSelected && returnedArray && returnedArray.length) {
377
- items = returnedArray.length;
346
+ items = returnedArray.length
378
347
  } else if (!returnAllSelected && defaultReturn && defaultReturn.length) {
379
- items = defaultReturn.length;
348
+ items = defaultReturn.length
380
349
  }
381
- return items;
382
- };
350
+ return items
351
+ }
383
352
 
384
353
  // Rendering formattedData to UI based on typeahead
385
- const renderNestedOptions = (items: { [key: string]: string; }[] | any ) => {
386
- const hasOptionsChild = React.Children.toArray(props.children).some(
387
- (child: any) => child.type === MultiLevelSelect.Options
388
- );
389
-
390
- if (hasOptionsChild) {
391
- return React.Children.map(props.children, (child) => {
392
- if (child.type === MultiLevelSelect.Options) {
393
- return React.cloneElement(child, { items });
394
- }
395
- return null;
396
- });
397
- } else {
398
- // If no children, use the default rendering
399
- return (
400
- <MultiLevelSelectOptions items={items} />
401
- );
402
- }
403
- };
404
-
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
+ }
405
432
 
406
433
  return (
407
434
  <div
@@ -411,20 +438,12 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
411
438
  className={classes}
412
439
  id={id}
413
440
  >
414
- <MultiLevelSelectContext.Provider value={{
415
- variant,
416
- inputName,
417
- renderNestedOptions,
418
- isTreeRowExpanded,
419
- handleToggleClick,
420
- handleRadioButtonClick,
421
- handledropdownItemClick,
422
- filterItem,
423
- }}>
424
- <div className="wrapper"
441
+ <div
442
+ className="wrapper"
425
443
  ref={dropdownRef}
426
444
  >
427
- <div className="input_wrapper"
445
+ <div
446
+ className="input_wrapper"
428
447
  onClick={handleInputWrapperClick}
429
448
  >
430
449
  <div className="input_inner_container">
@@ -490,17 +509,15 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
490
509
 
491
510
  <input
492
511
  id="multiselect_input"
493
- onChange={(e) => {
512
+ onChange={(e) =>{
494
513
  variant === "single"
495
514
  ? handleRadioInputChange(e.target.value)
496
- : setFilterItem(e.target.value);
515
+ : setFilterItem(e.target.value)
497
516
  }}
498
517
  onClick={() => setIsDropdownClosed(false)}
499
518
  placeholder={
500
519
  inputDisplay === "none" && itemsSelectedLength()
501
- ? `${itemsSelectedLength()} ${
502
- itemsSelectedLength() === 1 ? "item" : "items"
503
- } selected`
520
+ ? `${itemsSelectedLength()} ${itemsSelectedLength() === 1 ? "item" : "items"} selected`
504
521
  : "Start typing..."
505
522
  }
506
523
  value={singleSelectedItem.value || filterItem}
@@ -529,16 +546,15 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
529
546
  </div>
530
547
 
531
548
  <div className={`dropdown_menu ${isDropdownClosed ? "close" : "open"}`}>
532
- {renderNestedOptions(
533
- filterItem ? findByFilter(formattedData, filterItem) : formattedData
534
- )}
549
+ {renderNestedOptions(
550
+ filterItem
551
+ ? findByFilter(formattedData, filterItem)
552
+ : formattedData
553
+ )}
535
554
  </div>
536
555
  </div>
537
- </MultiLevelSelectContext.Provider>
538
556
  </div>
539
- );
540
- };
541
-
542
- MultiLevelSelect.Options = MultiLevelSelectOptions;
557
+ )
558
+ }
543
559
 
544
- export default MultiLevelSelect;
560
+ export default MultiLevelSelect
@@ -87,4 +87,4 @@ const MultiLevelSelectDefault = (props) => {
87
87
  )
88
88
  };
89
89
 
90
- export default MultiLevelSelectDefault;
90
+ export default MultiLevelSelectDefault;