playbook_ui 13.25.0 → 13.26.0.pre.alpha.PBNTR291Dropdownrailsv22840
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/index.js +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +14 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.html.erb +33 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.md +24 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/index.js +78 -0
- data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +4 -2
- data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +3 -2
- data/app/pb_kits/playbook/pb_avatar/Utilities/GetPlacementPropsHelper.tsx +44 -0
- data/app/pb_kits/playbook/pb_avatar/_avatar.tsx +86 -21
- data/app/pb_kits/playbook/pb_avatar/avatar.html.erb +26 -3
- data/app/pb_kits/playbook/pb_avatar/avatar.rb +41 -0
- data/app/pb_kits/playbook/pb_avatar/docs/_avatar_badge_component_overlay.html.erb +71 -0
- data/app/pb_kits/playbook/pb_avatar/docs/_avatar_badge_component_overlay.jsx +77 -0
- data/app/pb_kits/playbook/pb_avatar/docs/_avatar_circle_icon_component_overlay.html.erb +71 -0
- data/app/pb_kits/playbook/pb_avatar/docs/_avatar_circle_icon_component_overlay.jsx +77 -0
- data/app/pb_kits/playbook/pb_avatar/docs/_avatar_default.jsx +20 -0
- data/app/pb_kits/playbook/pb_avatar/docs/example.yml +4 -0
- data/app/pb_kits/playbook/pb_avatar/docs/index.js +2 -0
- data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx +1 -1
- data/app/pb_kits/playbook/pb_body/_body.tsx +1 -1
- data/app/pb_kits/playbook/pb_button/_button.scss +1 -1
- data/app/pb_kits/playbook/pb_checkbox/_checkbox.scss +49 -0
- data/app/pb_kits/playbook/pb_checkbox/_checkbox.tsx +3 -0
- data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +2 -1
- data/app/pb_kits/playbook/pb_checkbox/checkbox.test.js +14 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_disabled.html.erb +23 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_disabled.jsx +29 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_currency/docs/_currency_alignment_swift.md +43 -0
- data/app/pb_kits/playbook/pb_currency/docs/_currency_props_swift.md +12 -0
- data/app/pb_kits/playbook/pb_currency/docs/_currency_size_swift.md +31 -0
- data/app/pb_kits/playbook/pb_currency/docs/example.yml +5 -0
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_change.md +3 -1
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_close.md +3 -1
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_range_limit.md +1 -1
- data/app/pb_kits/playbook/pb_date_range_stacked/docs/_date_range_stacked_default_swift.md +14 -0
- data/app/pb_kits/playbook/pb_date_range_stacked/docs/_date_range_stacked_props_swift.md +9 -0
- data/app/pb_kits/playbook/pb_date_range_stacked/docs/example.yml +4 -0
- data/app/pb_kits/playbook/pb_dialog/_dialog.scss +4 -2
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +102 -35
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +95 -26
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.html.erb +10 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.jsx +4 -22
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subcomponent_structure.html.erb +17 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subcomponent_structure.jsx +42 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subcomponent_structure.md +7 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete.jsx +84 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete_and_custom_display.jsx +101 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete_and_custom_display.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.html.erb +60 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.jsx +6 -4
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.md +5 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_options.html.erb +45 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_options.jsx +6 -9
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_options.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_padding.html.erb +17 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_padding.jsx +48 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_padding.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_trigger.html.erb +47 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_trigger.jsx +5 -5
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_trigger.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_external_control.jsx +59 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_hook.jsx +72 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.html.erb +10 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.jsx +39 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +16 -2
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +7 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +26 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +20 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +200 -10
- data/app/pb_kits/playbook/pb_dropdown/dropdown_container.html.erb +21 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown_container.rb +19 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown_option.html.erb +27 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown_option.rb +22 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +43 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +30 -0
- data/app/pb_kits/playbook/pb_dropdown/hooks/useDropdown.tsx +2 -2
- data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +14 -9
- data/app/pb_kits/playbook/pb_dropdown/index.js +153 -0
- data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +77 -0
- data/app/pb_kits/playbook/pb_dropdown/scss_partials/_dropdown_animation.scss +18 -0
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +22 -8
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +60 -31
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +130 -68
- data/app/pb_kits/playbook/pb_dropdown/utilities/clickOutsideHelper.tsx +41 -0
- data/app/pb_kits/playbook/pb_dropdown/utilities/index.ts +2 -0
- data/app/pb_kits/playbook/pb_dropdown/utilities/subComponentHelper.tsx +9 -7
- data/app/pb_kits/playbook/pb_loading_inline/_loading_inline.tsx +3 -1
- data/app/pb_kits/playbook/pb_loading_inline/docs/_loading_inline_custom.html.erb +13 -0
- data/app/pb_kits/playbook/pb_loading_inline/docs/_loading_inline_custom.jsx +26 -0
- data/app/pb_kits/playbook/pb_loading_inline/docs/{_loading_inline_light.html.erb → _loading_inline_default.html.erb} +2 -2
- data/app/pb_kits/playbook/pb_loading_inline/docs/{_loading_inline_light.jsx → _loading_inline_default.jsx} +2 -2
- data/app/pb_kits/playbook/pb_loading_inline/docs/example.yml +4 -2
- data/app/pb_kits/playbook/pb_loading_inline/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_loading_inline/loading_inline.html.erb +1 -1
- data/app/pb_kits/playbook/pb_loading_inline/loading_inline.rb +1 -0
- data/app/pb_kits/playbook/pb_loading_inline/loading_inline.test.js +14 -0
- data/app/pb_kits/playbook/pb_progress_simple/docs/_progress_simple_flex.html.erb +3 -0
- data/app/pb_kits/playbook/pb_progress_simple/docs/_progress_simple_flex.jsx +16 -0
- data/app/pb_kits/playbook/pb_progress_simple/docs/_progress_simple_flex.md +1 -0
- data/app/pb_kits/playbook/pb_progress_simple/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_progress_simple/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_progress_simple/progress_simple.rb +1 -1
- data/app/pb_kits/playbook/pb_radio/_radio.scss +35 -0
- data/app/pb_kits/playbook/pb_radio/_radio.tsx +3 -0
- data/app/pb_kits/playbook/pb_radio/docs/_radio_alignment.jsx +4 -1
- data/app/pb_kits/playbook/pb_radio/docs/_radio_default.jsx +4 -1
- data/app/pb_kits/playbook/pb_radio/docs/_radio_disabled.html.erb +26 -0
- data/app/pb_kits/playbook/pb_radio/docs/_radio_disabled.jsx +31 -0
- data/app/pb_kits/playbook/pb_radio/docs/_radio_error.jsx +2 -1
- data/app/pb_kits/playbook/pb_radio/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_radio/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_radio/radio.rb +5 -0
- data/app/pb_kits/playbook/pb_radio/radio.test.js +17 -0
- data/app/pb_kits/playbook/pb_section_separator/_section_separator.scss +6 -2
- data/app/pb_kits/playbook/pb_section_separator/_section_separator_mixin.scss +11 -1
- data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +1 -1
- data/app/pb_kits/playbook/playbook-rails.js +6 -0
- data/dist/menu.yml +1 -1
- data/dist/playbook-rails.js +6 -6
- data/lib/playbook/version.rb +2 -2
- metadata +65 -8
- data/app/pb_kits/playbook/pb_advanced_table/docs/_description.md +0 -1
@@ -5,46 +5,51 @@
|
|
5
5
|
@import "../tokens/shadows";
|
6
6
|
@import "../tokens/positioning";
|
7
7
|
@import "../pb_body/body_mixins";
|
8
|
+
@import "../pb_textarea/textarea_mixin";
|
9
|
+
|
10
|
+
@import "./scss_partials/dropdown_animation";
|
8
11
|
|
9
12
|
.pb_dropdown {
|
10
13
|
.dropdown_wrapper {
|
11
|
-
|
12
|
-
.dropdown_trigger_wrapper {
|
14
|
+
[class*="dropdown_trigger_wrapper"] {
|
13
15
|
@include pb_body;
|
14
16
|
border: 1px solid $border_light;
|
15
17
|
background-color: $white;
|
16
|
-
|
18
|
+
height: 45px;
|
17
19
|
@media (hover: hover) {
|
18
20
|
&:hover,
|
19
21
|
&:active,
|
20
22
|
&:focus {
|
21
23
|
background-color: $focus_input_light;
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
input {
|
25
|
+
background-color: $focus_input_light;
|
26
|
+
}
|
25
27
|
}
|
26
28
|
}
|
27
29
|
|
28
30
|
.dropdown_input {
|
29
31
|
@include pb_body;
|
30
32
|
border: unset;
|
31
|
-
border-radius: $border_rad_heavier;
|
32
33
|
padding: 0;
|
33
|
-
|
34
|
+
background-color: $white;
|
34
35
|
&:focus-visible {
|
35
36
|
outline: none;
|
36
37
|
}
|
37
38
|
}
|
38
39
|
&:focus {
|
39
|
-
box-shadow: 0px 0px 0 1px $primary;
|
40
|
+
box-shadow: 0px 0px 0 1px $primary !important;
|
40
41
|
outline: unset;
|
41
42
|
transition: box-shadow 0.15s ease-in-out;
|
42
43
|
}
|
43
|
-
}
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
&[class*="_select_only"] {
|
46
|
+
box-shadow: inset 0 -11px 20px rgba($primary, 0.05);
|
47
|
+
}
|
48
|
+
|
49
|
+
&[class*="_focus"] {
|
50
|
+
box-shadow: 0px 0px 0 1px $primary !important;
|
51
|
+
transition: box-shadow 0.1s ease-in-out;
|
52
|
+
}
|
48
53
|
}
|
49
54
|
|
50
55
|
.pb_dropdown_container {
|
@@ -54,45 +59,107 @@
|
|
54
59
|
border-radius: $border_rad_heavier;
|
55
60
|
border: 1px solid $border_light;
|
56
61
|
margin-top: $space_xs;
|
57
|
-
position: absolute;
|
58
62
|
z-index: $z_1;
|
59
63
|
width: 100%;
|
60
|
-
transition: opacity 0.25s ease-in-out;
|
61
64
|
|
62
|
-
|
63
|
-
:
|
65
|
+
[class*="pb_dropdown_option"] {
|
66
|
+
cursor: pointer;
|
67
|
+
&:hover {
|
64
68
|
background-color: $border_light;
|
65
69
|
}
|
66
|
-
}
|
67
|
-
|
68
|
-
.dropdown_option_focused {
|
69
|
-
background-color: $border_light;
|
70
|
-
}
|
71
70
|
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
&[class*="_focused"] {
|
72
|
+
background-color: $border_light;
|
73
|
+
}
|
75
74
|
|
76
|
-
|
77
|
-
|
78
|
-
}
|
79
|
-
.dropdown_option_selected {
|
80
|
-
background-color: $primary;
|
81
|
-
[class^="pb_body"],
|
82
|
-
[class^="pb_title_kit"] {
|
83
|
-
color: $white !important;
|
75
|
+
&[class*="_list"] {
|
76
|
+
border-bottom: 1px solid $border_light;
|
84
77
|
}
|
85
|
-
|
86
|
-
background-color:
|
78
|
+
&[class*="selected"] {
|
79
|
+
background-color: $primary;
|
80
|
+
color: $white;
|
81
|
+
[class^="pb_body"],
|
82
|
+
[class^="pb_title_kit"], a {
|
83
|
+
color: $white !important;
|
84
|
+
}
|
85
|
+
&:hover {
|
86
|
+
background-color: $primary !important;
|
87
|
+
}
|
87
88
|
}
|
88
89
|
}
|
90
|
+
|
91
|
+
.dropdown_option_wrapper {
|
92
|
+
width: 100%;
|
93
|
+
}
|
89
94
|
}
|
90
95
|
.close {
|
91
96
|
display: none;
|
97
|
+
animation-name: fadeOut;
|
98
|
+
animation-duration: 150ms;
|
99
|
+
animation-timing-function: linear;
|
100
|
+
animation-fill-mode: forwards;
|
92
101
|
}
|
93
102
|
|
94
103
|
.open {
|
95
104
|
display: block;
|
105
|
+
animation-name: fadeIn;
|
106
|
+
animation-duration: 150ms;
|
107
|
+
animation-timing-function: linear;
|
108
|
+
animation-fill-mode: forwards;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
&.dark {
|
113
|
+
.dropdown_wrapper {
|
114
|
+
[class*="dropdown_trigger_wrapper"] {
|
115
|
+
@include pb_body_light_dark;
|
116
|
+
background-color: rgba($white, 0.1) !important;
|
117
|
+
background: none;
|
118
|
+
border-color: rgba($white, 0.15);
|
119
|
+
@media (hover: hover) {
|
120
|
+
&:hover,
|
121
|
+
&:active,
|
122
|
+
&:focus {
|
123
|
+
background-color: rgba($white, 0.05) !important;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
[class^="pb_body"] {
|
127
|
+
color: $white;
|
128
|
+
}
|
129
|
+
&[class*="_select_only"] {
|
130
|
+
box-shadow: inset 0 -11px 20px rgba($white, 0.05);
|
131
|
+
}
|
132
|
+
.dropdown_input {
|
133
|
+
background-color: unset;
|
134
|
+
color: $white;
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
.pb_dropdown_container {
|
139
|
+
background-color: $bg_dark !important;
|
140
|
+
border-color: rgba($white, 0.15);
|
141
|
+
color: $white;
|
142
|
+
[class^="pb_body"],
|
143
|
+
[class^="pb_title_kit"] {
|
144
|
+
color: $white !important;
|
145
|
+
}
|
146
|
+
|
147
|
+
[class*="pb_dropdown_option"] {
|
148
|
+
&:hover {
|
149
|
+
background-color: $hover_dark;
|
150
|
+
}
|
151
|
+
|
152
|
+
&[class*="_focused"] {
|
153
|
+
background-color: $hover_dark;
|
154
|
+
}
|
155
|
+
|
156
|
+
&[class*="_list"] {
|
157
|
+
border-color: rgba($white, 0.15);
|
158
|
+
}
|
159
|
+
&[class*="selected"] {
|
160
|
+
background-color: $primary;
|
161
|
+
}
|
162
|
+
}
|
96
163
|
}
|
97
164
|
}
|
98
165
|
}
|
@@ -1,31 +1,38 @@
|
|
1
|
-
import React, { useState, useRef, useEffect
|
1
|
+
import React, { useState, useRef, useEffect } from "react";
|
2
2
|
import classnames from "classnames";
|
3
|
-
import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
|
3
|
+
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
|
4
4
|
import { globalProps } from "../utilities/globalProps";
|
5
|
+
import { GenericObject } from "../types";
|
5
6
|
|
6
7
|
import Body from "../pb_body/_body";
|
8
|
+
import Caption from "../pb_caption/_caption";
|
7
9
|
|
8
10
|
import DropdownContainer from "./subcomponents/DropdownContainer";
|
11
|
+
import DropdownContext from "./context";
|
9
12
|
import DropdownOption from "./subcomponents/DropdownOption";
|
10
13
|
import DropdownTrigger from "./subcomponents/DropdownTrigger";
|
11
|
-
import DropdownContext from "./context";
|
12
14
|
import useDropdown from "./hooks/useDropdown";
|
13
15
|
|
14
16
|
import {
|
15
17
|
separateChildComponents,
|
16
18
|
prepareSubcomponents,
|
17
|
-
|
18
|
-
|
19
|
+
handleClickOutside,
|
20
|
+
} from "./utilities";
|
19
21
|
|
20
22
|
type DropdownProps = {
|
21
23
|
aria?: { [key: string]: string };
|
22
24
|
autocomplete?: boolean;
|
25
|
+
children?: React.ReactChild[] | React.ReactChild | React.ReactElement[];
|
23
26
|
className?: string;
|
27
|
+
dark?: boolean;
|
24
28
|
data?: { [key: string]: string };
|
29
|
+
htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
|
25
30
|
id?: string;
|
26
|
-
|
27
|
-
|
31
|
+
isClosed?: boolean;
|
32
|
+
label?: string;
|
28
33
|
onSelect?: (arg: GenericObject) => null;
|
34
|
+
options: GenericObject;
|
35
|
+
triggerRef?: any;
|
29
36
|
};
|
30
37
|
|
31
38
|
const Dropdown = (props: DropdownProps) => {
|
@@ -34,49 +41,66 @@ const Dropdown = (props: DropdownProps) => {
|
|
34
41
|
autocomplete = false,
|
35
42
|
children,
|
36
43
|
className,
|
44
|
+
dark = false,
|
37
45
|
data = {},
|
46
|
+
htmlOptions = {},
|
38
47
|
id,
|
39
|
-
|
48
|
+
isClosed = true,
|
49
|
+
label,
|
40
50
|
onSelect,
|
51
|
+
options,
|
52
|
+
triggerRef
|
41
53
|
} = props;
|
42
54
|
|
43
55
|
const ariaProps = buildAriaProps(aria);
|
44
56
|
const dataProps = buildDataProps(data);
|
57
|
+
const htmlProps = buildHtmlProps(htmlOptions);
|
45
58
|
const classes = classnames(
|
46
59
|
buildCss("pb_dropdown"),
|
47
60
|
globalProps(props),
|
48
61
|
className
|
49
62
|
);
|
50
63
|
|
51
|
-
const [isDropDownClosed, setIsDropDownClosed, toggleDropdown] = useDropdown();
|
64
|
+
const [isDropDownClosed, setIsDropDownClosed, toggleDropdown] = useDropdown(isClosed);
|
52
65
|
|
53
66
|
const [filterItem, setFilterItem] = useState("");
|
54
|
-
const [selected, setSelected] = useState({});
|
67
|
+
const [selected, setSelected] = useState<GenericObject>({});
|
55
68
|
const [isInputFocused, setIsInputFocused] = useState(false);
|
56
69
|
const [hasTriggerSubcomponent, setHasTriggerSubcomponent] = useState(true);
|
57
70
|
const [hasContainerSubcomponent, setHasContainerSubcomponent] =
|
58
71
|
useState(true);
|
59
|
-
|
60
72
|
//state for keyboard events
|
61
73
|
const [focusedOptionIndex, setFocusedOptionIndex] = useState(-1);
|
62
74
|
|
63
75
|
const dropdownRef = useRef(null);
|
64
76
|
const inputRef = useRef(null);
|
77
|
+
const inputWrapperRef = useRef(null);
|
78
|
+
const dropdownContainerRef = useRef(null);
|
65
79
|
|
66
80
|
const { trigger, container, otherChildren } =
|
67
81
|
separateChildComponents(children);
|
68
82
|
|
69
|
-
// useEffect to handle clicks outside the dropdown
|
70
83
|
useEffect(() => {
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
84
|
+
// Set the parent element of the trigger to relative to allow for absolute positioning of the dropdown
|
85
|
+
//Only needed for when useDropdown hook used with external trigger
|
86
|
+
if (triggerRef?.current) {
|
87
|
+
const parentElement = triggerRef.current.parentNode;
|
88
|
+
if (parentElement) {
|
89
|
+
parentElement.style.position = 'relative';
|
75
90
|
}
|
76
|
-
|
77
|
-
|
91
|
+
}
|
92
|
+
// Handle clicks outside the dropdown
|
93
|
+
const handleClick = handleClickOutside({
|
94
|
+
inputWrapperRef,
|
95
|
+
dropdownContainerRef,
|
96
|
+
setIsDropDownClosed,
|
97
|
+
setFocusedOptionIndex,
|
98
|
+
setIsInputFocused,
|
99
|
+
});
|
100
|
+
|
101
|
+
window.addEventListener("click", handleClick);
|
78
102
|
return () => {
|
79
|
-
window.removeEventListener("click",
|
103
|
+
window.removeEventListener("click", handleClick);
|
80
104
|
};
|
81
105
|
}, []);
|
82
106
|
|
@@ -85,6 +109,32 @@ const Dropdown = (props: DropdownProps) => {
|
|
85
109
|
setHasContainerSubcomponent(!!container);
|
86
110
|
}, []);
|
87
111
|
|
112
|
+
// dropdown to toggle with external control
|
113
|
+
useEffect(()=> {
|
114
|
+
setIsDropDownClosed(isClosed)
|
115
|
+
},[isClosed])
|
116
|
+
|
117
|
+
const filteredOptions = options?.filter((option: GenericObject) => {
|
118
|
+
const label = typeof option.label === 'string' ? option.label.toLowerCase() : option.label;
|
119
|
+
return String(label).toLowerCase().includes(filterItem.toLowerCase());
|
120
|
+
}
|
121
|
+
);
|
122
|
+
|
123
|
+
// For keyboard accessibility: Set focus within dropdown to selected item if it exists
|
124
|
+
useEffect(() => {
|
125
|
+
if (!isDropDownClosed) {
|
126
|
+
let newIndex = 0;
|
127
|
+
if (selected && selected?.label) {
|
128
|
+
const selectedIndex = filteredOptions.findIndex((option: GenericObject) => option.label === selected.label);
|
129
|
+
if (selectedIndex >= 0) {
|
130
|
+
newIndex = selectedIndex;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
setFocusedOptionIndex(newIndex);
|
134
|
+
}
|
135
|
+
}, [isDropDownClosed]);
|
136
|
+
|
137
|
+
|
88
138
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
89
139
|
setFilterItem(e.target.value);
|
90
140
|
setIsDropDownClosed(false);
|
@@ -94,7 +144,7 @@ const Dropdown = (props: DropdownProps) => {
|
|
94
144
|
setSelected(selectedItem);
|
95
145
|
setFilterItem("");
|
96
146
|
setIsDropDownClosed(true);
|
97
|
-
onSelect(selectedItem);
|
147
|
+
onSelect && onSelect(selectedItem);
|
98
148
|
};
|
99
149
|
|
100
150
|
const handleWrapperClick = () => {
|
@@ -104,14 +154,10 @@ const Dropdown = (props: DropdownProps) => {
|
|
104
154
|
|
105
155
|
const handleBackspace = () => {
|
106
156
|
setSelected({});
|
107
|
-
onSelect(null);
|
157
|
+
onSelect && onSelect(null);
|
108
158
|
setFocusedOptionIndex(-1);
|
109
159
|
};
|
110
160
|
|
111
|
-
const filteredOptions = options?.filter((option: GenericObject) =>
|
112
|
-
option.label.toLowerCase().includes(filterItem.toLowerCase())
|
113
|
-
);
|
114
|
-
|
115
161
|
const componentsToRender = prepareSubcomponents({
|
116
162
|
children,
|
117
163
|
hasTriggerSubcomponent,
|
@@ -119,17 +165,22 @@ const Dropdown = (props: DropdownProps) => {
|
|
119
165
|
trigger,
|
120
166
|
container,
|
121
167
|
otherChildren,
|
168
|
+
dark
|
122
169
|
});
|
123
170
|
|
171
|
+
|
124
172
|
return (
|
125
173
|
<div {...ariaProps}
|
126
174
|
{...dataProps}
|
175
|
+
{...htmlProps}
|
127
176
|
className={classes}
|
128
177
|
id={id}
|
178
|
+
style={triggerRef ? { position: "absolute"} : { position: "relative"}}
|
129
179
|
>
|
130
180
|
<DropdownContext.Provider
|
131
181
|
value={{
|
132
182
|
autocomplete,
|
183
|
+
dropdownContainerRef,
|
133
184
|
filteredOptions,
|
134
185
|
filterItem,
|
135
186
|
focusedOptionIndex,
|
@@ -138,6 +189,7 @@ const Dropdown = (props: DropdownProps) => {
|
|
138
189
|
handleOptionClick,
|
139
190
|
handleWrapperClick,
|
140
191
|
inputRef,
|
192
|
+
inputWrapperRef,
|
141
193
|
isDropDownClosed,
|
142
194
|
isInputFocused,
|
143
195
|
options,
|
@@ -147,9 +199,26 @@ const Dropdown = (props: DropdownProps) => {
|
|
147
199
|
setIsInputFocused,
|
148
200
|
setSelected,
|
149
201
|
toggleDropdown,
|
202
|
+
triggerRef
|
150
203
|
}}
|
151
204
|
>
|
205
|
+
{label &&
|
206
|
+
<Caption
|
207
|
+
dark={dark}
|
208
|
+
marginBottom="xs"
|
209
|
+
text={label}
|
210
|
+
/>
|
211
|
+
}
|
152
212
|
<div className="dropdown_wrapper"
|
213
|
+
onBlur={() => {
|
214
|
+
// Debounce to delay the execution to prevent jumpiness in Focus state
|
215
|
+
setTimeout(() => {
|
216
|
+
if (!dropdownRef.current.contains(document.activeElement)) {
|
217
|
+
setIsInputFocused(false);
|
218
|
+
}
|
219
|
+
}, 0);
|
220
|
+
}}
|
221
|
+
onFocus={() => setIsInputFocused(true)}
|
153
222
|
ref={dropdownRef}
|
154
223
|
>
|
155
224
|
{children ? (
|
@@ -176,7 +245,7 @@ const Dropdown = (props: DropdownProps) => {
|
|
176
245
|
</div>
|
177
246
|
</DropdownContext.Provider>
|
178
247
|
</div>
|
179
|
-
)
|
248
|
+
)
|
180
249
|
};
|
181
250
|
|
182
251
|
Dropdown.Option = DropdownOption;
|
@@ -1,31 +1,20 @@
|
|
1
|
-
import React
|
1
|
+
import React from 'react'
|
2
2
|
import { Dropdown } from '../../'
|
3
3
|
|
4
4
|
const DropdownDefault = (props) => {
|
5
|
-
// eslint-disable-next-line no-unused-vars
|
6
|
-
const [selectedOption, setSelectedOption] = useState();
|
7
5
|
|
8
6
|
const options = [
|
9
7
|
{
|
10
8
|
label: "United States",
|
11
9
|
value: "United States",
|
12
|
-
areaCode: "+1",
|
13
|
-
icon: "🇺🇸",
|
14
|
-
id: "United-states"
|
15
10
|
},
|
16
11
|
{
|
17
|
-
label: "
|
18
|
-
value: "
|
19
|
-
areaCode: "+380",
|
20
|
-
icon: "🇺🇦",
|
21
|
-
id: "ukraine"
|
12
|
+
label: "Canada",
|
13
|
+
value: "Canada",
|
22
14
|
},
|
23
15
|
{
|
24
16
|
label: "Pakistan",
|
25
17
|
value: "Pakistan",
|
26
|
-
areaCode: "+92",
|
27
|
-
icon: "🇵🇰",
|
28
|
-
id: "pakistan"
|
29
18
|
}
|
30
19
|
];
|
31
20
|
|
@@ -33,16 +22,9 @@ const [selectedOption, setSelectedOption] = useState();
|
|
33
22
|
return (
|
34
23
|
<div>
|
35
24
|
<Dropdown
|
36
|
-
onSelect={(selectedItem) => setSelectedOption(selectedItem)}
|
37
25
|
options={options}
|
38
26
|
{...props}
|
39
|
-
|
40
|
-
{options.map((option) => (
|
41
|
-
<Dropdown.Option key={option.id}
|
42
|
-
option={option}
|
43
|
-
/>
|
44
|
-
))}
|
45
|
-
</Dropdown>
|
27
|
+
/>
|
46
28
|
</div>
|
47
29
|
)
|
48
30
|
}
|
@@ -0,0 +1 @@
|
|
1
|
+
The Dropdown kit accepts an `options` array and renders each object from that array as a selectable option within a dropdown container. `options` is a required prop and must be an array of objects. Each object can contain as many key/value pairs as needed but MUST contain 'label' and 'value' as the only required items within each object.
|
@@ -0,0 +1,17 @@
|
|
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
|
+
<%= pb_rails("dropdown", props: {options: options}) do %>
|
11
|
+
<%= pb_rails("dropdown/dropdown_trigger") %>
|
12
|
+
<%= pb_rails("dropdown/dropdown_container") do %>
|
13
|
+
<% options.each do |option| %>
|
14
|
+
<%= pb_rails("dropdown/dropdown_option", props: {option: option}) %>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { Dropdown } from '../..'
|
3
|
+
|
4
|
+
const DropdownSubcomponentStructure = (props) => {
|
5
|
+
|
6
|
+
|
7
|
+
const options = [
|
8
|
+
{
|
9
|
+
label: "United States",
|
10
|
+
value: "United States",
|
11
|
+
},
|
12
|
+
{
|
13
|
+
label: "Canada",
|
14
|
+
value: "Canada",
|
15
|
+
},
|
16
|
+
{
|
17
|
+
label: "Pakistan",
|
18
|
+
value: "Pakistan",
|
19
|
+
}
|
20
|
+
];
|
21
|
+
|
22
|
+
|
23
|
+
return (
|
24
|
+
<div>
|
25
|
+
<Dropdown
|
26
|
+
options={options}
|
27
|
+
{...props}
|
28
|
+
>
|
29
|
+
<Dropdown.Trigger/>
|
30
|
+
<Dropdown.Container>
|
31
|
+
{options.map((option) => (
|
32
|
+
<Dropdown.Option key={option.id}
|
33
|
+
option={option}
|
34
|
+
/>
|
35
|
+
))}
|
36
|
+
</Dropdown.Container>
|
37
|
+
</Dropdown>
|
38
|
+
</div>
|
39
|
+
)
|
40
|
+
}
|
41
|
+
|
42
|
+
export default DropdownSubcomponentStructure
|
@@ -0,0 +1,7 @@
|
|
1
|
+
The dropdown comes with the following subcomponents that can be used to achieve various levels of customization:
|
2
|
+
|
3
|
+
`Dropdown. Trigger` / `dropdown/dropdown_trigger`
|
4
|
+
`Dropdown.Container`/ `dropdown/dropdown_container`
|
5
|
+
`Dropdown.Option` / `dropdown/dropdown_option`
|
6
|
+
|
7
|
+
See the code snippet below for a visual on how to use the kit with subcomponents. Each subcomponent allows for GlobalProps in addition to any subcomponent specfic props.
|
@@ -0,0 +1,84 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { Dropdown, User, Badge, FlexItem } from '../..'
|
3
|
+
|
4
|
+
const DropdownWithAutocomplete = (props) => {
|
5
|
+
|
6
|
+
const options = [
|
7
|
+
{
|
8
|
+
label: "Jasper Furniss",
|
9
|
+
value: "Jasper Furniss",
|
10
|
+
territory: "PHL",
|
11
|
+
title: "Senior UX Engineer",
|
12
|
+
id: "jasper-furniss",
|
13
|
+
status: "Offline"
|
14
|
+
},
|
15
|
+
{
|
16
|
+
label: "Ramon Ruiz",
|
17
|
+
value: "Ramon Ruiz",
|
18
|
+
territory: "PHL",
|
19
|
+
title: "Senior UX Designer",
|
20
|
+
id: "ramon-ruiz",
|
21
|
+
status: "Away"
|
22
|
+
},
|
23
|
+
{
|
24
|
+
label: "Jason Cypret",
|
25
|
+
value: "Jason Cypret",
|
26
|
+
territory: "PHL",
|
27
|
+
title: "VP of User Experience",
|
28
|
+
id: "jason-cypret",
|
29
|
+
status: "Online"
|
30
|
+
},
|
31
|
+
{
|
32
|
+
label: "Courtney Long",
|
33
|
+
value: "Courtney Long",
|
34
|
+
territory: "PHL",
|
35
|
+
title: "UX Design Mentor",
|
36
|
+
id: "courtney-long",
|
37
|
+
status: "Online"
|
38
|
+
}
|
39
|
+
];
|
40
|
+
|
41
|
+
|
42
|
+
return (
|
43
|
+
<div>
|
44
|
+
<Dropdown autocomplete
|
45
|
+
options={options}
|
46
|
+
{...props}
|
47
|
+
>
|
48
|
+
{options.map((option) => (
|
49
|
+
<Dropdown.Option key={option.id}
|
50
|
+
option={option}
|
51
|
+
>
|
52
|
+
<>
|
53
|
+
<FlexItem>
|
54
|
+
<User
|
55
|
+
align="left"
|
56
|
+
avatar
|
57
|
+
name={option.label}
|
58
|
+
orientation="horizontal"
|
59
|
+
territory={option.territory}
|
60
|
+
title={option.title}
|
61
|
+
/>
|
62
|
+
</FlexItem>
|
63
|
+
<FlexItem>
|
64
|
+
<Badge
|
65
|
+
rounded
|
66
|
+
text={option.status}
|
67
|
+
variant={`${
|
68
|
+
option.status === "Offline"
|
69
|
+
? "neutral"
|
70
|
+
: option.status === "Online"
|
71
|
+
? "success"
|
72
|
+
: "warning"
|
73
|
+
}`}
|
74
|
+
/>
|
75
|
+
</FlexItem>
|
76
|
+
</>
|
77
|
+
</Dropdown.Option>
|
78
|
+
))}
|
79
|
+
</Dropdown>
|
80
|
+
</div>
|
81
|
+
)
|
82
|
+
}
|
83
|
+
|
84
|
+
export default DropdownWithAutocomplete
|
@@ -0,0 +1 @@
|
|
1
|
+
The `autocomplete` prop can be used to add autocomplete or typeahead functionality to the Dropdown's default Trigger. This prop is set to 'false' by default.
|