playbook_ui 12.26.1.pre.alpha.railsmultilevelimprovements842 → 12.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 326f8eff50b791dc21ab3ec0bdb295adef8d14d3957277f4f92d8abdfe445686
4
- data.tar.gz: 0a9d5b6672174df0cb045cc3aea6b017d0e30f1a978df27e0529b7f1d3cb3472
3
+ metadata.gz: 7fbc9b56c02a9915257f3a1169f85773e8a063c14de44a2492a250f9015dee65
4
+ data.tar.gz: f70c024e4feae26b0767595ad538df87eb08e78453a56c6ca22de07552d60d5d
5
5
  SHA512:
6
- metadata.gz: 1b079256265e6bcdea4576a6930b527b944044f0064936376278147aad59cf1a5b311ba25632ca3878bb50e3fd62a33ccdf17cf805d7dd60eaece7d5d3e640fe
7
- data.tar.gz: fa05822858223b65f2a3a2755a1f7fcecea6946d7a1f31ea40a32ad10ebd5b3df128cc3736fdab16b6329ba283e50d201412a8d79c6027745a646d8c6c94ac05
6
+ metadata.gz: e40a155458785168e1fb5f5f63efe8c5bcd7dca3d1b8c618557d86453d5008336454d205330742fc029e6593e05e566610eb853577b42a993934eeb20408ffa5
7
+ data.tar.gz: 9acc8dcd73190cc433572b49bdef61cb4e425304125aaf8d5b61c7426f5f4c2a314f1e2b38e9b55a5f37b6f45b56cb8079ec9b82070c461699ae9b2357689a2d
@@ -1,12 +1,12 @@
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 } from "../utilities/props"
5
- import Checkbox from "../pb_checkbox/_checkbox"
6
- import Icon from "../pb_icon/_icon"
7
- import FormPill from "../pb_form_pill/_form_pill"
8
- import CircleIconButton from "../pb_circle_icon_button/_circle_icon_button"
9
- import { cloneDeep } from "lodash"
1
+ import React, { useState, useEffect, useRef } from "react";
2
+ import classnames from "classnames";
3
+ import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
4
+ import { globalProps, GlobalProps } from "../utilities/globalProps";
5
+ import Icon from "../pb_icon/_icon";
6
+ import Checkbox from "../pb_checkbox/_checkbox";
7
+ import FormPill from "../pb_form_pill/_form_pill";
8
+ import CircleIconButton from "../pb_circle_icon_button/_circle_icon_button";
9
+ import { cloneDeep } from "lodash";
10
10
 
11
11
  import {
12
12
  getAncestorsOfUnchecked,
@@ -15,18 +15,17 @@ import {
15
15
  getCheckedItems,
16
16
  getDefaultCheckedItems,
17
17
  recursiveCheckParent,
18
- } from "./_helper_functions"
18
+ } from "./_helper_functions";
19
19
 
20
20
  type MultiLevelSelectProps = {
21
- aria?: { [key: string]: string }
22
- className?: string
23
- data?: { [key: string]: string }
24
- id?: string
25
- name?: string
26
- returnAllSelected?: boolean
27
- treeData?: { [key: string]: string }[]
28
- onSelect?: (prop: { [key: string]: any }) => void
29
- } & GlobalProps
21
+ aria?: { [key: string]: string };
22
+ className?: string;
23
+ data?: { [key: string]: string };
24
+ id?: string;
25
+ returnAllSelected?: boolean;
26
+ treeData?: { [key: string]: string }[];
27
+ onSelect?: (prop: { [key: string]: any }) => void;
28
+ } & GlobalProps;
30
29
 
31
30
  const MultiLevelSelect = (props: MultiLevelSelectProps) => {
32
31
  const {
@@ -34,74 +33,71 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
34
33
  className,
35
34
  data = {},
36
35
  id,
37
- name,
38
36
  returnAllSelected = false,
39
37
  treeData,
40
38
  onSelect = () => {},
41
- } = props
39
+ } = props;
42
40
 
43
- const ariaProps = buildAriaProps(aria)
44
- const dataProps = buildDataProps(data)
41
+ const ariaProps = buildAriaProps(aria);
42
+ const dataProps = buildDataProps(data);
45
43
  const classes = classnames(
46
44
  buildCss("pb_multi_level_select"),
47
45
  globalProps(props),
48
46
  className
49
- )
50
-
51
- const dropdownRef = useRef(null)
47
+ );
52
48
 
49
+ const dropdownRef = useRef(null);
53
50
 
54
51
  //state for expanded property
55
- const [expanded, setExpanded] = useState([])
52
+ const [expanded, setExpanded] = useState([]);
56
53
  //state for whether dropdown is open or closed
57
- const [isClosed, setIsClosed] = useState(true)
54
+ const [isClosed, setIsClosed] = useState(true);
58
55
  //state from onchange for textinput, to use for filtering to create typeahead
59
- const [filterItem, setFilterItem] = useState("")
56
+ const [filterItem, setFilterItem] = useState("");
60
57
  //this is essentially the return that the user will get when they use the kit
61
- const [returnedArray, setReturnedArray] = useState([])
58
+ const [returnedArray, setReturnedArray] = useState([]);
62
59
  //formattedData with checked and parent_id added
63
- const [formattedData, setFormattedData] = useState([])
60
+ const [formattedData, setFormattedData] = useState([]);
64
61
  //state for return for default
65
- const [defaultReturn, setDefaultReturn] = useState([])
66
-
62
+ const [defaultReturn, setDefaultReturn] = useState([]);
67
63
 
68
64
  useEffect(() => {
69
- setFormattedData(addCheckedAndParentProperty(treeData))
70
- }, [treeData])
65
+ setFormattedData(addCheckedAndParentProperty(treeData));
66
+ }, [treeData]);
71
67
 
72
68
  useEffect(() => {
73
69
  if (returnAllSelected) {
74
- setReturnedArray(getCheckedItems(formattedData))
70
+ setReturnedArray(getCheckedItems(formattedData));
75
71
  } else {
76
- setDefaultReturn(getDefaultCheckedItems(formattedData))
72
+ setDefaultReturn(getDefaultCheckedItems(formattedData));
77
73
  }
78
- }, [formattedData])
74
+ }, [formattedData]);
79
75
 
80
76
  useEffect(() => {
81
77
  // Function to handle clicks outside the dropdown
82
78
  const handleClickOutside = (event: any) => {
83
79
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
84
- setIsClosed(true)
80
+ setIsClosed(true);
85
81
  }
86
- }
82
+ };
87
83
  // Attach the event listener
88
- window.addEventListener("click", handleClickOutside)
84
+ window.addEventListener("click", handleClickOutside);
89
85
  // Clean up the event listener on unmount
90
86
  return () => {
91
- window.removeEventListener("click", handleClickOutside)
92
- }
93
- }, [])
87
+ window.removeEventListener("click", handleClickOutside);
88
+ };
89
+ }, []);
94
90
 
95
91
  const modifyRecursive = (tree: { [key: string]: any }[], check: boolean) => {
96
92
  if (!Array.isArray(tree)) {
97
- return
93
+ return;
98
94
  }
99
95
  return tree.map((item: { [key: string]: any }) => {
100
- item.checked = check
101
- item.children = modifyRecursive(item.children, check)
102
- return item
103
- })
104
- }
96
+ item.checked = check;
97
+ item.children = modifyRecursive(item.children, check);
98
+ return item;
99
+ });
100
+ };
105
101
 
106
102
  //iterate over tree, find item and set checked or unchecked
107
103
  const modifyValue = (
@@ -110,48 +106,48 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
110
106
  check: boolean
111
107
  ) => {
112
108
  if (!Array.isArray(tree)) {
113
- return
109
+ return;
114
110
  }
115
111
  return tree.map((item: any) => {
116
- if (item.id != id) item.children = modifyValue(id, item.children, check)
112
+ if (item.id != id) item.children = modifyValue(id, item.children, check);
117
113
  else {
118
- item.checked = check
119
- item.children = modifyRecursive(item.children, check)
114
+ item.checked = check;
115
+ item.children = modifyRecursive(item.children, check);
120
116
  }
121
117
 
122
- return item
123
- })
124
- }
118
+ return item;
119
+ });
120
+ };
125
121
 
126
122
  //clone tree, check items + children
127
123
  const checkItem = (item: { [key: string]: any }) => {
128
- const tree = cloneDeep(formattedData)
124
+ const tree = cloneDeep(formattedData);
129
125
  if (returnAllSelected) {
130
- return modifyValue(item.id, tree, true)
126
+ return modifyValue(item.id, tree, true);
131
127
  } else {
132
- const checkedTree = modifyValue(item.id, tree, true)
133
- return recursiveCheckParent(item, checkedTree)
128
+ const checkedTree = modifyValue(item.id, tree, true);
129
+ return recursiveCheckParent(item, checkedTree);
134
130
  }
135
- }
131
+ };
136
132
 
137
133
  //clone tree, uncheck items + children
138
134
  const unCheckItem = (item: { [key: string]: any }) => {
139
- const tree = cloneDeep(formattedData)
135
+ const tree = cloneDeep(formattedData);
140
136
  if (returnAllSelected) {
141
- return modifyValue(item.id, tree, false)
137
+ return modifyValue(item.id, tree, false);
142
138
  } else {
143
- const uncheckedTree = modifyValue(item.id, tree, false)
144
- return getAncestorsOfUnchecked(uncheckedTree, item)
139
+ const uncheckedTree = modifyValue(item.id, tree, false);
140
+ return getAncestorsOfUnchecked(uncheckedTree, item);
145
141
  }
146
- }
142
+ };
147
143
 
148
144
  //setformattedData with proper properties
149
145
  const changeItem = (item: { [key: string]: any }, check: boolean) => {
150
- const tree = check ? checkItem(item) : unCheckItem(item)
151
- setFormattedData(tree)
146
+ const tree = check ? checkItem(item) : unCheckItem(item);
147
+ setFormattedData(tree);
152
148
 
153
- return tree
154
- }
149
+ return tree;
150
+ };
155
151
 
156
152
  //function to map over data and add parent_id + depth property to each item
157
153
  const addCheckedAndParentProperty = (
@@ -160,86 +156,87 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
160
156
  depth: number = 0
161
157
  ) => {
162
158
  if (!Array.isArray(treeData)) {
163
- return
159
+ return;
164
160
  }
165
161
  return treeData.map((item: { [key: string]: any } | any) => {
166
162
  const newItem = {
167
163
  ...item,
168
164
  parent_id,
169
165
  depth,
170
- }
166
+ };
171
167
  if (newItem.children && newItem.children.length > 0) {
172
168
  const children =
173
169
  item.checked && !returnAllSelected
174
170
  ? modifyRecursive(item.children, true)
175
- : item.children
171
+ : item.children;
176
172
  newItem.children = addCheckedAndParentProperty(
177
173
  children,
178
174
  newItem.id,
179
175
  depth + 1
180
- )
176
+ );
181
177
  }
182
- return newItem
183
- })
184
- }
178
+ return newItem;
179
+ });
180
+ };
185
181
 
186
182
  //click event for x on form pill
187
183
  const handlePillClose = (event: any, clickedItem: { [key: string]: any }) => {
188
184
  // prevents the dropdown from closing when clicking on the pill
189
- event.stopPropagation()
190
- const updatedTree = changeItem(clickedItem, false)
185
+ event.stopPropagation();
186
+ const updatedTree = changeItem(clickedItem, false);
191
187
  //logic for removing items from returnArray or defaultReturn when pills clicked
192
188
  if (returnAllSelected) {
193
- onSelect(getCheckedItems(updatedTree))
189
+ onSelect(getCheckedItems(updatedTree));
194
190
  } else {
195
- onSelect(getDefaultCheckedItems(updatedTree))
191
+ onSelect(getDefaultCheckedItems(updatedTree));
196
192
  }
197
- }
193
+ };
198
194
 
199
195
  //handle click on input wrapper(entire div with pills, typeahead, etc) so it doesn't close when input or form pill is clicked
200
196
  const handleInputWrapperClick = (e: any) => {
201
- e.stopPropagation()
197
+ e.stopPropagation();
202
198
  if (
203
199
  e.target.id === "multiselect_input" ||
204
200
  e.target.classList.contains("pb_form_pill_tag")
205
201
  ) {
206
- return
202
+ return;
207
203
  }
208
- setIsClosed(!isClosed)
209
- }
204
+ setIsClosed(!isClosed);
205
+ };
210
206
 
211
207
  //Main function to handle any click inside dropdown
212
208
  const handledropdownItemClick = (e: any, check: boolean) => {
213
- const clickedItem = e.target.parentNode.id
209
+ const clickedItem = e.target.parentNode.id;
214
210
  //setting filterItem to "" will clear textinput and clear typeahead
215
- setFilterItem("")
211
+ setFilterItem("");
216
212
 
217
- const filtered = filterFormattedDataById(formattedData, clickedItem)
218
- const updatedTree = changeItem(filtered[0], check)
213
+ const filtered = filterFormattedDataById(formattedData, clickedItem);
214
+ const updatedTree = changeItem(filtered[0], check);
215
+ console.log(updatedTree);
219
216
  if (returnAllSelected) {
220
- onSelect(getCheckedItems(updatedTree))
217
+ onSelect(getCheckedItems(updatedTree));
221
218
  } else {
222
- onSelect(getDefaultCheckedItems(updatedTree))
219
+ onSelect(getDefaultCheckedItems(updatedTree));
223
220
  }
224
- }
221
+ };
225
222
 
226
- const isExpanded = (item: any) => expanded.indexOf(item.id) > -1
223
+ const isExpanded = (item: any) => expanded.indexOf(item.id) > -1;
227
224
 
228
225
  //handle click on chevron toggles in dropdown
229
226
  const handleToggleClick = (id: string, event: React.MouseEvent) => {
230
- event.stopPropagation()
231
- const clickedItem = filterFormattedDataById(formattedData, id)
227
+ event.stopPropagation();
228
+ const clickedItem = filterFormattedDataById(formattedData, id);
232
229
  if (clickedItem) {
233
- let expandedArray = [...expanded]
234
- const itemExpanded = isExpanded(clickedItem[0])
230
+ let expandedArray = [...expanded];
231
+ const itemExpanded = isExpanded(clickedItem[0]);
235
232
 
236
233
  if (itemExpanded)
237
- expandedArray = expandedArray.filter((i) => i != clickedItem[0].id)
238
- else expandedArray.push(clickedItem[0].id)
234
+ expandedArray = expandedArray.filter((i) => i != clickedItem[0].id);
235
+ else expandedArray.push(clickedItem[0].id);
239
236
 
240
- setExpanded(expandedArray)
237
+ setExpanded(expandedArray);
241
238
  }
242
- }
239
+ };
243
240
 
244
241
  //rendering formattedData to UI based on typeahead
245
242
  const renderNestedOptions = (items: { [key: string]: any }[]) => {
@@ -248,9 +245,9 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
248
245
  {Array.isArray(items) &&
249
246
  items.map((item: { [key: string]: any }) => {
250
247
  return (
251
- <div key={item.id}>
252
- <li className='dropdown_item' data-name={item.id}>
253
- <div className='dropdown_item_checkbox_row'>
248
+ <>
249
+ <li key={item.id} className="dropdown_item" data-name={item.id}>
250
+ <div className="dropdown_item_checkbox_row">
254
251
  <div
255
252
  key={isExpanded(item) ? "chevron-down" : "chevron-right"}
256
253
  >
@@ -266,17 +263,17 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
266
263
  onClick={(event: any) =>
267
264
  handleToggleClick(item.id, event)
268
265
  }
269
- variant='link'
266
+ variant="link"
270
267
  />
271
268
  </div>
272
269
  <Checkbox text={item.label} id={item.id}>
273
270
  <input
274
271
  checked={item.checked}
275
- type='checkbox'
272
+ type="checkbox"
276
273
  name={item.label}
277
274
  value={item.label}
278
275
  onChange={(e) => {
279
- handledropdownItemClick(e, !item.checked)
276
+ handledropdownItemClick(e, !item.checked);
280
277
  }}
281
278
  />
282
279
  </Checkbox>
@@ -288,30 +285,24 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
288
285
  <div>{renderNestedOptions(item.children)}</div>
289
286
  )}
290
287
  </li>
291
- </div>
292
- )
288
+ </>
289
+ );
293
290
  })}
294
291
  </ul>
295
- )
296
- }
292
+ );
293
+ };
297
294
 
298
295
  return (
299
296
  <div {...ariaProps} {...dataProps} className={classes} id={id}>
300
- <div ref={dropdownRef} className='wrapper'>
301
- <div className='input_wrapper' onClick={handleInputWrapperClick}>
302
- <div className='input_inner_container'>
303
- {returnedArray.length !== 0 && returnAllSelected
304
- ? returnedArray.map((item) => (
305
- <input type='hidden' name={`${name}[]`} value={item.id} />
306
- ))
307
- : null}
308
-
297
+ <div ref={dropdownRef} className="wrapper">
298
+ <div className="input_wrapper" onClick={handleInputWrapperClick}>
299
+ <div className="input_inner_container">
309
300
  {returnedArray.length !== 0 && returnAllSelected
310
301
  ? returnedArray.map((item, index) => (
311
302
  <FormPill
312
303
  key={index}
313
304
  text={item.label}
314
- size='small'
305
+ size="small"
315
306
  onClick={(event: any) => handlePillClose(event, item)}
316
307
  />
317
308
  ))
@@ -322,29 +313,29 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
322
313
  <FormPill
323
314
  key={index}
324
315
  text={item.label}
325
- size='small'
316
+ size="small"
326
317
  onClick={(event: any) => handlePillClose(event, item)}
327
318
  />
328
319
  ))}
329
320
  {returnedArray.length !== 0 && returnAllSelected && <br />}
330
321
  {defaultReturn.length !== 0 && !returnAllSelected && <br />}
331
322
  <input
332
- id='multiselect_input'
323
+ id="multiselect_input"
333
324
  onChange={(e) => {
334
- setFilterItem(e.target.value)
325
+ setFilterItem(e.target.value);
335
326
  }}
336
- placeholder='Start typing...'
327
+ placeholder="Start typing..."
337
328
  value={filterItem}
338
329
  onClick={() => setIsClosed(false)}
339
330
  />
340
331
  </div>
341
332
  {isClosed ? (
342
- <div key='chevron-down'>
343
- <Icon icon='chevron-down' />
333
+ <div key="chevron-down">
334
+ <Icon icon="chevron-down" />
344
335
  </div>
345
336
  ) : (
346
- <div key='chevron-up'>
347
- <Icon icon='chevron-up' />
337
+ <div key="chevron-up">
338
+ <Icon icon="chevron-up" />
348
339
  </div>
349
340
  )}
350
341
  </div>
@@ -355,7 +346,7 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
355
346
  </div>
356
347
  </div>
357
348
  </div>
358
- )
359
- }
349
+ );
350
+ };
360
351
 
361
- export default MultiLevelSelect
352
+ export default MultiLevelSelect;
@@ -1,72 +1,72 @@
1
1
  <% treeData = [{
2
2
  label: "Power Home Remodeling",
3
3
  value: "Power Home Remodeling",
4
- id: "100",
4
+ id: "powerhome1",
5
5
  expanded: true,
6
6
  children: [
7
7
  {
8
8
  label: "People",
9
9
  value: "People",
10
- id: "101",
10
+ id: "people1",
11
11
  children: [
12
12
  {
13
13
  label: "Talent Acquisition",
14
14
  value: "Talent Acquisition",
15
- id: "102",
15
+ id: "talent1",
16
16
  },
17
17
  {
18
18
  label: "Business Affairs",
19
19
  value: "Business Affairs",
20
- id: "103",
20
+ id: "business1",
21
21
  children: [
22
22
  {
23
23
  label: "Initiatives",
24
24
  value: "Initiatives",
25
- id: "104",
25
+ id: "initiative1",
26
26
  },
27
27
  {
28
28
  label: "Learning & Development",
29
29
  value: "Learning & Development",
30
- id: "105",
30
+ id: "development1",
31
31
  },
32
32
  ],
33
33
  },
34
34
  {
35
35
  label: "People Experience",
36
36
  value: "People Experience",
37
- id: "106",
37
+ id: "experience1",
38
38
  },
39
39
  ],
40
40
  },
41
41
  {
42
42
  label: "Contact Center",
43
43
  value: "Contact Center",
44
- id: "107",
44
+ id: "contact1",
45
45
  children: [
46
46
  {
47
47
  label: "Appointment Management",
48
48
  value: "Appointment Management",
49
- id: "108",
49
+ id: "appointment1",
50
50
  },
51
51
  {
52
52
  label: "Customer Service",
53
53
  value: "Customer Service",
54
- id: "109",
54
+ id: "customer1",
55
55
  },
56
56
  {
57
57
  label: "Energy",
58
58
  value: "Energy",
59
- id: "110",
59
+ id: "energy1",
60
60
  },
61
61
  ],
62
62
  },
63
63
  ],
64
- }] %>
64
+ }] %>
65
65
 
66
66
 
67
+ <%= pb_rails("multi_level_select", props: {
68
+ id: "default-multi-level-select",
69
+ tree_data:treeData
70
+ }) %>
71
+
67
72
 
68
- <%= pb_rails("multi_level_select", props: {
69
- id: "multi-level-select-default-rails",
70
- name: "my_array",
71
- tree_data: treeData
72
- }) %>
@@ -72,18 +72,15 @@ const MultiLevelSelectDefault = (props) => {
72
72
  return (
73
73
  <div>
74
74
  <MultiLevelSelect
75
- id='multiselect-default'
75
+ id="multiselect-default"
76
76
  onSelect={(selectedNodes) =>
77
- console.log(
78
- "Selected Items",
79
- selectedNodes
80
- )
81
- }
77
+ console.log("Selected Items", selectedNodes)
78
+ }
82
79
  treeData={treeData}
83
80
  {...props}
84
81
  />
85
82
  </div>
86
- )
83
+ );
87
84
  };
88
85
 
89
86
  export default MultiLevelSelectDefault;
@@ -1,5 +1,5 @@
1
1
  The MultiLevelSelect kit renders a multi leveled select dropdown based on data from the user. `treeData` is a required prop that is expected to contain the data in the form of an array of objects. See code snippet for an example data array.
2
2
 
3
- For the React version of the kit, the `onSelect` prop returns an array of objects. This array contains all checked items irrespective of whether it is a parent, child or grandchild. Open the console on this example and check and uncheck checkboxes to see this is action!
3
+ For the React version of the kit, the `onSelect` prop returns an array of all checked items, irrespective of whether it is a parent, child or grandchild. Open the console on this example and check and uncheck checkboxes to see this is action!
4
4
 
5
- For the Rails version of the kit, there is no onselect. The form submits as a array of strings, following the typical rails pattern of utilizing hidden inputs. The strings are the values of the selected items' ids. For example, ["103", "106", "107"].
5
+ For the Rails version, the array of checked items is attached to the DOM in a data attribute titled `data-tree` on the wrapping div around the MultiLevelSelect.