playbook_ui 14.20.0.pre.rc.2 → 14.20.0
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 +4 -4
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +61 -35
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +36 -22
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +6 -19
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.jsx +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md +3 -1
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +1 -1
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +77 -19
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.html.erb +31 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.md +5 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.jsx +56 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.jsx +58 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.html.erb +20 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.html.erb +19 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.html.erb +20 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.jsx +57 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.html.erb +50 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.jsx +105 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.html.erb +22 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.jsx +67 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +11 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +5 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +3 -3
- data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +16 -2
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +34 -13
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +3 -1
- data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +0 -6
- data/app/pb_kits/playbook/pb_dropdown/index.js +334 -41
- data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +39 -12
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +16 -12
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +78 -12
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +58 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +1 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +73 -3
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.jsx +23 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.md +1 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
- data/dist/chunks/_typeahead-MUu4QW0I.js +22 -0
- data/dist/chunks/_weekday_stacked-CZJor-EY.js +45 -0
- data/dist/chunks/lazysizes-DHz07jlL.js +1 -0
- data/dist/chunks/lib-DFF1N868.js +29 -0
- data/dist/chunks/{pb_form_validation-WWvUXPKD.js → pb_form_validation-D1Bwm-op.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-doc.js +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/kit_base.rb +3 -3
- data/lib/playbook/version.rb +1 -1
- metadata +27 -8
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.html.erb +0 -10
- data/dist/chunks/_typeahead-B9-s4j4U.js +0 -22
- data/dist/chunks/_weekday_stacked-CvzpmXD5.js +0 -45
- data/dist/chunks/lazysizes-B7xYodB-.js +0 -1
- data/dist/chunks/lib-B20MXZcW.js +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df6a61095071691d0b05f1fbec7ec814d97410e945a2c9eeb88df6b7aee7f17d
|
4
|
+
data.tar.gz: d01d8fd76b9a504da0600a42d869c7de35fcfac17ce0bfa449459356f74c3089
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a95beeddd9ec8ad5f6684eaff098098230c6f8d21e4b1037b7c56a51f2b87bbb67ab004a9c66843ca556f3c54bfda704cf69c27295678db816692b01814eadbd
|
7
|
+
data.tar.gz: ac4605915f1fce8c69d50fa1faf599bb4e2ec9a90faafc8f17e959787d2a0f831c4720597f186d78602b635165ea5309f47222aaa6887494f781d73178a4d4e9
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useEffect, useRef, useContext } from "react";
|
1
|
+
import React, { useEffect, useRef, useContext, useState } from "react";
|
2
2
|
|
3
3
|
import AdvancedTableContext from "../Context/AdvancedTableContext";
|
4
4
|
import { buildVisibilityTree } from "../Utilities/VisibilityTree";
|
@@ -7,13 +7,11 @@ import Card from "../../pb_card/_card";
|
|
7
7
|
import Caption from "../../pb_caption/_caption";
|
8
8
|
import Flex from "../../pb_flex/_flex";
|
9
9
|
import FlexItem from "../../pb_flex/_flex_item";
|
10
|
-
import Dropdown from "../../pb_dropdown/_dropdown";
|
11
|
-
import DropdownContainer from "../../pb_dropdown/subcomponents/DropdownContainer";
|
12
|
-
import DropdownTrigger from "../../pb_dropdown/subcomponents/DropdownTrigger";
|
13
10
|
import Icon from "../../pb_icon/_icon";
|
14
11
|
import Checkbox from "../../pb_checkbox/_checkbox";
|
15
12
|
import SectionSeparator from "../../pb_section_separator/_section_separator";
|
16
13
|
import Tooltip from "../../pb_tooltip/_tooltip";
|
14
|
+
import PbReactPopover from "../../pb_popover/_popover";
|
17
15
|
|
18
16
|
import {
|
19
17
|
showActionBar,
|
@@ -56,11 +54,24 @@ const TableActionBar: React.FC<TableActionBarProps> = ({
|
|
56
54
|
const col = table.getColumn(id);
|
57
55
|
const show = col.getIsVisible();
|
58
56
|
|
57
|
+
const handleVisibilityChange = () => {
|
58
|
+
col.toggleVisibility();
|
59
|
+
if (columnVisibilityControl?.onColumnVisibilityChange) {
|
60
|
+
const updatedVisibilityState = {
|
61
|
+
...table.getAllColumns().reduce((acc: { [x: string]: any; }, col: { id: string | number; getIsVisible: () => any; }) => {
|
62
|
+
acc[col.id] = col.getIsVisible();
|
63
|
+
return acc;
|
64
|
+
}, {}),
|
65
|
+
};
|
66
|
+
columnVisibilityControl?.onColumnVisibilityChange(updatedVisibilityState);
|
67
|
+
}
|
68
|
+
};
|
69
|
+
|
59
70
|
return (
|
60
71
|
<Checkbox
|
61
72
|
checked={show}
|
62
73
|
key={id}
|
63
|
-
onChange={
|
74
|
+
onChange={handleVisibilityChange}
|
64
75
|
paddingBottom="xs"
|
65
76
|
text={label}
|
66
77
|
/>
|
@@ -80,16 +91,24 @@ const TableActionBar: React.FC<TableActionBarProps> = ({
|
|
80
91
|
const allOn = visibleArray.every(Boolean);
|
81
92
|
const someOn = visibleArray.some(Boolean);
|
82
93
|
|
94
|
+
const handleGroupVisibilityChange = () => {
|
95
|
+
leaves.forEach((id) => table.getColumn(id).toggleVisibility(!allOn));
|
96
|
+
if (columnVisibilityControl?.onColumnVisibilityChange) {
|
97
|
+
const updatedVisibilityState = {
|
98
|
+
...table.getAllColumns().reduce((acc: { [x: string]: any; }, col: { id: string | number; getIsVisible: () => any; }) => {
|
99
|
+
acc[col.id] = col.getIsVisible();
|
100
|
+
return acc;
|
101
|
+
}, {}),
|
102
|
+
};
|
103
|
+
columnVisibilityControl?.onColumnVisibilityChange(updatedVisibilityState);
|
104
|
+
}
|
105
|
+
};
|
83
106
|
return (
|
84
107
|
<>
|
85
108
|
<Checkbox
|
86
109
|
checked={allOn}
|
87
110
|
indeterminate={!allOn && someOn}
|
88
|
-
onChange={
|
89
|
-
leaves.forEach((id) =>
|
90
|
-
table.getColumn(id).toggleVisibility(!allOn),
|
91
|
-
)
|
92
|
-
}
|
111
|
+
onChange={handleGroupVisibilityChange}
|
93
112
|
paddingBottom="xs"
|
94
113
|
text={node.label}
|
95
114
|
/>
|
@@ -113,7 +132,28 @@ const TableActionBar: React.FC<TableActionBarProps> = ({
|
|
113
132
|
hideActionBar(cardRef.current);
|
114
133
|
}
|
115
134
|
}
|
116
|
-
}, [isVisible]);
|
135
|
+
}, [isVisible, type]);
|
136
|
+
|
137
|
+
const [showPopover, setShowPopover] = useState(false)
|
138
|
+
|
139
|
+
const togglePopover = () => setShowPopover((prev) => !prev)
|
140
|
+
const handleShouldClose = (shouldClose: boolean) =>
|
141
|
+
setShowPopover(!shouldClose)
|
142
|
+
|
143
|
+
const popoverReference = (
|
144
|
+
<Tooltip
|
145
|
+
placement="top"
|
146
|
+
text="Column Configuration"
|
147
|
+
>
|
148
|
+
<div onClick={togglePopover}>
|
149
|
+
<Icon
|
150
|
+
color="primary"
|
151
|
+
cursor="pointer"
|
152
|
+
icon="sliders-h"
|
153
|
+
/>
|
154
|
+
</div>
|
155
|
+
</Tooltip>
|
156
|
+
)
|
117
157
|
|
118
158
|
return (
|
119
159
|
<Card
|
@@ -139,30 +179,17 @@ const TableActionBar: React.FC<TableActionBarProps> = ({
|
|
139
179
|
<FlexItem>{actions}</FlexItem>
|
140
180
|
</>
|
141
181
|
) : (
|
142
|
-
<
|
143
|
-
|
144
|
-
|
182
|
+
<PbReactPopover
|
183
|
+
closeOnClick="outside"
|
184
|
+
placement="bottom-end"
|
185
|
+
reference={popoverReference}
|
186
|
+
shouldClosePopover={handleShouldClose}
|
187
|
+
show={showPopover}
|
188
|
+
zIndex={3}
|
145
189
|
>
|
146
|
-
|
147
|
-
<Tooltip
|
148
|
-
placement='top'
|
149
|
-
text="Column Configuration"
|
150
|
-
zIndex={10}
|
151
|
-
>
|
152
|
-
<Icon
|
153
|
-
color="primary"
|
154
|
-
cursor="pointer"
|
155
|
-
icon="sliders-h"
|
156
|
-
/>
|
157
|
-
</Tooltip>
|
158
|
-
</DropdownTrigger>
|
159
|
-
<DropdownContainer
|
160
|
-
className="column-visibility-dropdown"
|
161
|
-
paddingTop="sm"
|
162
|
-
>
|
163
|
-
<>
|
190
|
+
<>
|
164
191
|
<Caption
|
165
|
-
|
192
|
+
paddingY="sm"
|
166
193
|
text="Columns Config"
|
167
194
|
textAlign="center"
|
168
195
|
/>
|
@@ -177,8 +204,7 @@ const TableActionBar: React.FC<TableActionBarProps> = ({
|
|
177
204
|
</Flex>
|
178
205
|
))}
|
179
206
|
</>
|
180
|
-
|
181
|
-
</Dropdown>
|
207
|
+
</PbReactPopover>
|
182
208
|
)}
|
183
209
|
</Flex>
|
184
210
|
</Card>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useContext } from "react"
|
1
|
+
import React, { useContext, useState } from "react"
|
2
2
|
import classnames from "classnames"
|
3
3
|
import { flexRender, Header, Table, RowModel } from "@tanstack/react-table"
|
4
4
|
|
@@ -8,10 +8,8 @@ import { GlobalProps } from "../../utilities/globalProps"
|
|
8
8
|
|
9
9
|
import Flex from "../../pb_flex/_flex"
|
10
10
|
import Checkbox from "../../pb_checkbox/_checkbox"
|
11
|
-
import
|
12
|
-
import
|
13
|
-
import DropdownOption from "../../pb_dropdown/subcomponents/DropdownOption"
|
14
|
-
import DropdownContainer from "../../pb_dropdown/subcomponents/DropdownContainer"
|
11
|
+
import SectionSeparator from "../../pb_section_separator/_section_separator"
|
12
|
+
import PbReactPopover from "../../pb_popover/_popover";
|
15
13
|
import Icon from "../../pb_icon/_icon"
|
16
14
|
|
17
15
|
import { SortIconButton } from "./SortIconButton"
|
@@ -136,6 +134,20 @@ const isToggleExpansionEnabled =
|
|
136
134
|
justifyHeader = isLeafColumn ? "end" : "center";
|
137
135
|
}
|
138
136
|
|
137
|
+
const [showPopover, setShowPopover] = useState(false)
|
138
|
+
|
139
|
+
const togglePopover = () => setShowPopover((prev) => !prev)
|
140
|
+
const handleShouldClose = (shouldClose: boolean) =>
|
141
|
+
setShowPopover(!shouldClose)
|
142
|
+
|
143
|
+
const popoverReference = (
|
144
|
+
<div className="gray-icon toggle-all-icon"
|
145
|
+
onClick={togglePopover}
|
146
|
+
>
|
147
|
+
<Icon icon={displayIcon(toggleExpansionIcon)[0]} />
|
148
|
+
</div>
|
149
|
+
)
|
150
|
+
|
139
151
|
const handleExpandDepth = (depth: number) => {
|
140
152
|
if (onExpandByDepthClick) {
|
141
153
|
const flatRows = table?.getRowModel().flatRows
|
@@ -191,31 +203,33 @@ const isToggleExpansionEnabled =
|
|
191
203
|
<ToggleIconButton onClick={handleExpandOrCollapse} />
|
192
204
|
)}
|
193
205
|
{isToggleExpansionEnabled && hasAnySubRows && expandByDepth && (
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
<DropdownOption
|
203
|
-
key={index}
|
204
|
-
option={option}
|
205
|
-
padding="none"
|
206
|
+
|
207
|
+
<PbReactPopover
|
208
|
+
closeOnClick="any"
|
209
|
+
placement="bottom-start"
|
210
|
+
reference={popoverReference}
|
211
|
+
shouldClosePopover={handleShouldClose}
|
212
|
+
show={showPopover}
|
213
|
+
zIndex={3}
|
206
214
|
>
|
215
|
+
{expandByDepth.map((option:{ [key: string]: any }, index: number) => (
|
216
|
+
<>
|
207
217
|
<Flex
|
208
218
|
alignItems="center"
|
219
|
+
className="pb-advanced-table-popover-option"
|
220
|
+
cursor="pointer"
|
209
221
|
htmlOptions={{onClick: () => {handleExpandDepth(option.depth)} }}
|
210
222
|
paddingX="sm"
|
211
223
|
paddingY="xs"
|
212
224
|
>
|
213
225
|
{option.label}
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
226
|
+
</Flex>
|
227
|
+
{index !== expandByDepth.length - 1 && <SectionSeparator/>}
|
228
|
+
</>
|
229
|
+
))}
|
230
|
+
</PbReactPopover>
|
231
|
+
|
232
|
+
|
219
233
|
)}
|
220
234
|
|
221
235
|
{isToggleExpansionEnabledLoading &&(
|
@@ -53,15 +53,6 @@
|
|
53
53
|
width: 100%;
|
54
54
|
}
|
55
55
|
|
56
|
-
.column-visibility-dropdown-wrapper {
|
57
|
-
position: unset !important;
|
58
|
-
}
|
59
|
-
.column-visibility-dropdown {
|
60
|
-
width: unset !important;
|
61
|
-
right: $space_xxs;
|
62
|
-
text-align: left;
|
63
|
-
}
|
64
|
-
|
65
56
|
// Virtualized table styles
|
66
57
|
.virtualized-table-row {
|
67
58
|
display: table !important;
|
@@ -159,13 +150,6 @@
|
|
159
150
|
box-sizing: border-box !important;
|
160
151
|
}
|
161
152
|
}
|
162
|
-
.expand-by-depth-dropdown-wrapper {
|
163
|
-
position: unset !important;
|
164
|
-
}
|
165
|
-
.expand-by-depth-dropdown {
|
166
|
-
width: unset !important;
|
167
|
-
text-align: left;
|
168
|
-
}
|
169
153
|
}
|
170
154
|
|
171
155
|
.pb_advanced_table_body {
|
@@ -554,14 +538,12 @@
|
|
554
538
|
background-color: $white;
|
555
539
|
box-shadow: $shadow_deep;
|
556
540
|
}
|
541
|
+
|
557
542
|
@include advanced-table-sticky-mixin(
|
558
543
|
$border_light,
|
559
544
|
$white,
|
560
545
|
lighten($silver, $opacity_7)
|
561
546
|
);
|
562
|
-
|
563
|
-
// Apply border colors for sticky columns
|
564
|
-
@include apply-sticky-colors("light");
|
565
547
|
}
|
566
548
|
|
567
549
|
// Responsive Styles
|
@@ -827,3 +809,8 @@
|
|
827
809
|
}
|
828
810
|
}
|
829
811
|
}
|
812
|
+
|
813
|
+
// Outside of the pb_advanced_table class for popover
|
814
|
+
.pb-advanced-table-popover-option:hover {
|
815
|
+
background-color: $bg_light;
|
816
|
+
}
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md
CHANGED
@@ -1 +1,3 @@
|
|
1
|
-
The `columnVisibilityControl` prop also allows for greater control over the columnVisibility state. Devs can manage state themselves by passing in `value` and `onChange` as shown.
|
1
|
+
The `columnVisibilityControl` prop also allows for greater control over the columnVisibility state. Devs can manage state themselves by passing in `value` and `onChange` as shown.
|
2
|
+
|
3
|
+
The additional `onColumnVisibilityChange` provides a callback with the current state as the argument if needed.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from "react";
|
1
|
+
import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle, useMemo } from "react";
|
2
2
|
import classnames from "classnames";
|
3
3
|
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
|
4
4
|
import { globalProps } from "../utilities/globalProps";
|
@@ -25,6 +25,7 @@ type DropdownProps = {
|
|
25
25
|
blankSelection?: string;
|
26
26
|
children?: React.ReactChild[] | React.ReactChild | React.ReactElement[];
|
27
27
|
className?: string;
|
28
|
+
formPillProps?: GenericObject;
|
28
29
|
dark?: boolean;
|
29
30
|
data?: { [key: string]: string };
|
30
31
|
defaultValue?: GenericObject;
|
@@ -33,6 +34,7 @@ type DropdownProps = {
|
|
33
34
|
id?: string;
|
34
35
|
isClosed?: boolean;
|
35
36
|
label?: string;
|
37
|
+
multiSelect?: boolean;
|
36
38
|
onSelect?: (arg: GenericObject) => null;
|
37
39
|
options: GenericObject;
|
38
40
|
separators?: boolean;
|
@@ -61,6 +63,8 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
61
63
|
id,
|
62
64
|
isClosed = true,
|
63
65
|
label,
|
66
|
+
multiSelect = false,
|
67
|
+
formPillProps,
|
64
68
|
onSelect,
|
65
69
|
options,
|
66
70
|
separators = true,
|
@@ -80,7 +84,20 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
80
84
|
const [isDropDownClosed, setIsDropDownClosed, toggleDropdown] = useDropdown(isClosed);
|
81
85
|
|
82
86
|
const [filterItem, setFilterItem] = useState("");
|
83
|
-
const
|
87
|
+
const initialSelected = useMemo(() => {
|
88
|
+
if (multiSelect) {
|
89
|
+
if (Array.isArray(defaultValue)) return defaultValue;
|
90
|
+
return defaultValue && Object.keys(defaultValue).length
|
91
|
+
? [defaultValue]
|
92
|
+
: [];
|
93
|
+
}
|
94
|
+
return defaultValue || {};
|
95
|
+
}, [multiSelect, defaultValue]);
|
96
|
+
|
97
|
+
const [selected, setSelected] = useState<GenericObject | GenericObject[]>(
|
98
|
+
initialSelected
|
99
|
+
);
|
100
|
+
|
84
101
|
const [isInputFocused, setIsInputFocused] = useState(false);
|
85
102
|
const [hasTriggerSubcomponent, setHasTriggerSubcomponent] = useState(true);
|
86
103
|
const [hasContainerSubcomponent, setHasContainerSubcomponent] =
|
@@ -93,6 +110,12 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
93
110
|
const inputWrapperRef = useRef(null);
|
94
111
|
const dropdownContainerRef = useRef(null);
|
95
112
|
|
113
|
+
const selectedArray = Array.isArray(selected)
|
114
|
+
? selected
|
115
|
+
: selected && Object.keys(selected).length
|
116
|
+
? [selected]
|
117
|
+
: [];
|
118
|
+
|
96
119
|
const { trigger, container, otherChildren } =
|
97
120
|
separateChildComponents(children);
|
98
121
|
|
@@ -124,16 +147,23 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
124
147
|
|
125
148
|
const blankSelectionOption: GenericObject = blankSelection ? [{ label: blankSelection, value: "" }] : [];
|
126
149
|
const optionsWithBlankSelection = blankSelectionOption.concat(options);
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
150
|
+
|
151
|
+
const availableOptions = useMemo(()=> {
|
152
|
+
if (!multiSelect) return optionsWithBlankSelection;
|
153
|
+
return optionsWithBlankSelection.filter((option: GenericObject) => !selectedArray.some((sel) => sel.label === option.label));
|
154
|
+
}, [optionsWithBlankSelection, selectedArray, multiSelect]);
|
155
|
+
|
156
|
+
const filteredOptions = useMemo(() => {
|
157
|
+
return availableOptions.filter((opt: GenericObject) =>
|
158
|
+
String(opt.label).toLowerCase().includes(filterItem.toLowerCase())
|
159
|
+
);
|
160
|
+
}, [availableOptions, filterItem]);
|
131
161
|
|
132
162
|
// For keyboard accessibility: Set focus within dropdown to selected item if it exists
|
133
163
|
useEffect(() => {
|
134
164
|
if (!isDropDownClosed) {
|
135
165
|
let newIndex = 0;
|
136
|
-
if (selected && selected
|
166
|
+
if (selected && !Array.isArray(selected) && selected.label) {
|
137
167
|
const selectedIndex = filteredOptions.findIndex((option: GenericObject) => option.label === selected.label);
|
138
168
|
if (selectedIndex >= 0) {
|
139
169
|
newIndex = selectedIndex;
|
@@ -149,12 +179,27 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
149
179
|
setIsDropDownClosed(false);
|
150
180
|
};
|
151
181
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
182
|
+
|
183
|
+
const handleOptionClick = (clickedItem: GenericObject) => {
|
184
|
+
if (multiSelect) {
|
185
|
+
setSelected((prev) => {
|
186
|
+
const list = prev as GenericObject[];
|
187
|
+
const exists = list.find((option) => option.value === clickedItem.value);
|
188
|
+
const next = exists
|
189
|
+
? list.filter((option) => option.value !== clickedItem.value)
|
190
|
+
: [...list, clickedItem];
|
191
|
+
onSelect && onSelect(next);
|
192
|
+
return next;
|
193
|
+
});
|
194
|
+
setFilterItem("");
|
195
|
+
setIsDropDownClosed(true);
|
196
|
+
} else {
|
197
|
+
setSelected(clickedItem);
|
198
|
+
setFilterItem("");
|
199
|
+
setIsDropDownClosed(true);
|
200
|
+
onSelect && onSelect(clickedItem);
|
201
|
+
}
|
202
|
+
};
|
158
203
|
|
159
204
|
const handleWrapperClick = () => {
|
160
205
|
autocomplete && inputRef?.current?.focus();
|
@@ -162,9 +207,14 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
162
207
|
};
|
163
208
|
|
164
209
|
const handleBackspace = () => {
|
210
|
+
if (multiSelect) {
|
211
|
+
setSelected([]);
|
212
|
+
onSelect && onSelect([]);
|
213
|
+
} else {
|
165
214
|
setSelected({});
|
166
215
|
onSelect && onSelect(null);
|
167
216
|
setFocusedOptionIndex(-1);
|
217
|
+
}
|
168
218
|
};
|
169
219
|
|
170
220
|
const componentsToRender = prepareSubcomponents({
|
@@ -178,12 +228,17 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
178
228
|
});
|
179
229
|
|
180
230
|
useImperativeHandle(ref, () => ({
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
231
|
+
clearSelected: () => {
|
232
|
+
if (multiSelect) {
|
233
|
+
setSelected([]);
|
234
|
+
onSelect && onSelect([]);
|
235
|
+
} else {
|
236
|
+
setSelected({});
|
237
|
+
onSelect && onSelect(null);
|
238
|
+
}
|
239
|
+
setFilterItem("");
|
240
|
+
setIsDropDownClosed(true);
|
241
|
+
},
|
187
242
|
}));
|
188
243
|
|
189
244
|
return (
|
@@ -201,6 +256,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
201
256
|
filteredOptions,
|
202
257
|
filterItem,
|
203
258
|
focusedOptionIndex,
|
259
|
+
formPillProps,
|
204
260
|
handleBackspace,
|
205
261
|
handleChange,
|
206
262
|
handleOptionClick,
|
@@ -209,6 +265,8 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
209
265
|
inputWrapperRef,
|
210
266
|
isDropDownClosed,
|
211
267
|
isInputFocused,
|
268
|
+
multiSelect,
|
269
|
+
onSelect,
|
212
270
|
optionsWithBlankSelection,
|
213
271
|
selected,
|
214
272
|
setFocusedOptionIndex,
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<%
|
2
|
+
options = [
|
3
|
+
{ label: 'United States', value: 'United States', id: 'us' },
|
4
|
+
{ label: 'Canada', value: 'Canada', id: 'ca' },
|
5
|
+
{ label: 'Pakistan', value: 'Pakistan', id: 'pk' },
|
6
|
+
]
|
7
|
+
|
8
|
+
%>
|
9
|
+
|
10
|
+
<%
|
11
|
+
options2 = [
|
12
|
+
{ label: 'India', value: 'India', id: 'in' },
|
13
|
+
{ label: 'Mexico', value: 'Mexico', id: 'mx' },
|
14
|
+
{ label: 'Brazil', value: 'Brazil', id: 'br' },
|
15
|
+
{ label: 'Argentina', value: 'Argentina', id: 'ar' },
|
16
|
+
{ label: 'Colombia', value: 'Colombia', id: 'co' },
|
17
|
+
{ label: 'Chile', value: 'Chile', id: 'cl' },
|
18
|
+
{ label: 'Peru', value: 'Peru', id: 'pe' },
|
19
|
+
]
|
20
|
+
|
21
|
+
%>
|
22
|
+
|
23
|
+
<%= pb_rails("dropdown", props: {options: options}) %>
|
24
|
+
|
25
|
+
<script>
|
26
|
+
document.addEventListener("pb:dropdown:selected", (e) => {
|
27
|
+
const option = e.detail;
|
28
|
+
const dropdown = e.target;
|
29
|
+
console.log("Selected option:", option);
|
30
|
+
})
|
31
|
+
</script>
|
@@ -0,0 +1,5 @@
|
|
1
|
+
This kit's `options` prop requires an array of objects, each of which will be used as the selectable options within the dropdown. Each option object can support any number of key-value pairs, but each MUST contain `label`, `value` and `id`.
|
2
|
+
|
3
|
+
The kit also comes with a custom event called "pb:dropdown:selected" which updates dynamically with the selection as it changes. See code snippet to see this in action.
|
4
|
+
|
5
|
+
In addition, a data attribute called `data-option-selected` with the selection is also rendered on the parent dropdown div.
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import Dropdown from '../../pb_dropdown/_dropdown'
|
3
|
+
|
4
|
+
const DropdownMultiSelect = (props) => {
|
5
|
+
|
6
|
+
const options = [
|
7
|
+
{
|
8
|
+
label: "United States",
|
9
|
+
value: "United States",
|
10
|
+
},
|
11
|
+
{
|
12
|
+
label: "United Kingdom",
|
13
|
+
value: "United Kingdom",
|
14
|
+
},
|
15
|
+
{
|
16
|
+
label: "Canada",
|
17
|
+
value: "Canada",
|
18
|
+
},
|
19
|
+
{
|
20
|
+
label: "Pakistan",
|
21
|
+
value: "Pakistan",
|
22
|
+
},
|
23
|
+
{
|
24
|
+
label: "India",
|
25
|
+
value: "India",
|
26
|
+
},
|
27
|
+
{
|
28
|
+
label: "Australia",
|
29
|
+
value: "Australia",
|
30
|
+
},
|
31
|
+
{
|
32
|
+
label: "New Zealand",
|
33
|
+
value: "New Zealand",
|
34
|
+
},
|
35
|
+
{
|
36
|
+
label: "Italy",
|
37
|
+
value: "Italy",
|
38
|
+
},
|
39
|
+
{
|
40
|
+
label: "Spain",
|
41
|
+
value: "Spain",
|
42
|
+
}
|
43
|
+
];
|
44
|
+
|
45
|
+
return (
|
46
|
+
<div>
|
47
|
+
<Dropdown
|
48
|
+
multiSelect
|
49
|
+
options={options}
|
50
|
+
{...props}
|
51
|
+
/>
|
52
|
+
</div>
|
53
|
+
)
|
54
|
+
}
|
55
|
+
|
56
|
+
export default DropdownMultiSelect
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import Dropdown from '../../pb_dropdown/_dropdown'
|
3
|
+
|
4
|
+
const DropdownMultiSelectDisplay = (props) => {
|
5
|
+
|
6
|
+
const options = [
|
7
|
+
{
|
8
|
+
label: "United States",
|
9
|
+
value: "United States",
|
10
|
+
},
|
11
|
+
{
|
12
|
+
label: "United Kingdom",
|
13
|
+
value: "United Kingdom",
|
14
|
+
},
|
15
|
+
{
|
16
|
+
label: "Canada",
|
17
|
+
value: "Canada",
|
18
|
+
},
|
19
|
+
{
|
20
|
+
label: "Pakistan",
|
21
|
+
value: "Pakistan",
|
22
|
+
},
|
23
|
+
{
|
24
|
+
label: "India",
|
25
|
+
value: "India",
|
26
|
+
},
|
27
|
+
{
|
28
|
+
label: "Australia",
|
29
|
+
value: "Australia",
|
30
|
+
},
|
31
|
+
{
|
32
|
+
label: "New Zealand",
|
33
|
+
value: "New Zealand",
|
34
|
+
},
|
35
|
+
{
|
36
|
+
label: "Italy",
|
37
|
+
value: "Italy",
|
38
|
+
},
|
39
|
+
{
|
40
|
+
label: "Spain",
|
41
|
+
value: "Spain",
|
42
|
+
}
|
43
|
+
];
|
44
|
+
|
45
|
+
|
46
|
+
return (
|
47
|
+
<div>
|
48
|
+
<Dropdown
|
49
|
+
formPillProps={{size:"small", color:"neutral"}}
|
50
|
+
multiSelect
|
51
|
+
options={options}
|
52
|
+
{...props}
|
53
|
+
/>
|
54
|
+
</div>
|
55
|
+
)
|
56
|
+
}
|
57
|
+
|
58
|
+
export default DropdownMultiSelectDisplay
|