playbook_ui 13.23.0 → 13.24.0.pre.alpha.PBNTR261NewKitDropdown2681

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +2 -0
  3. data/app/pb_kits/playbook/index.js +1 -0
  4. data/app/pb_kits/playbook/pb_avatar/avatar.html.erb +1 -6
  5. data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx +41 -6
  6. data/app/pb_kits/playbook/pb_bar_graph/bar_graph.rb +4 -0
  7. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_negative_numbers.html.erb +23 -0
  8. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_negative_numbers.jsx +35 -0
  9. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_secondary_y_axis.html.erb +26 -0
  10. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_secondary_y_axis.jsx +36 -0
  11. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_secondary_y_axis.md +3 -0
  12. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_stacked.html.erb +22 -0
  13. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_stacked.jsx +34 -0
  14. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_stacked.md +1 -0
  15. data/app/pb_kits/playbook/pb_bar_graph/docs/example.yml +6 -0
  16. data/app/pb_kits/playbook/pb_bar_graph/docs/index.js +3 -0
  17. data/app/pb_kits/playbook/pb_body/_body.scss +3 -3
  18. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +92 -0
  19. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +152 -0
  20. data/app/pb_kits/playbook/pb_dropdown/context/index.tsx +5 -0
  21. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.jsx +53 -0
  22. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.jsx +104 -0
  23. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_options.jsx +69 -0
  24. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_trigger.jsx +78 -0
  25. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +9 -0
  26. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +4 -0
  27. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +17 -0
  28. data/app/pb_kits/playbook/pb_dropdown/hooks/useDropdown.tsx +17 -0
  29. data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +53 -0
  30. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +95 -0
  31. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +91 -0
  32. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +118 -0
  33. data/app/pb_kits/playbook/pb_list/_list_item.tsx +2 -2
  34. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +27 -19
  35. data/app/pb_kits/playbook/pb_typeahead/components/MenuList.tsx +4 -2
  36. data/app/pb_kits/playbook/pb_typeahead/components/index.tsx +19 -0
  37. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_custom_menu_list.jsx +51 -0
  38. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_highlight.jsx +1 -1
  39. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +1 -0
  40. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
  41. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  42. data/app/pb_kits/playbook/tokens/_colors.scss +1 -1
  43. data/dist/menu.yml +5 -1
  44. data/dist/playbook-rails.js +6 -6
  45. data/lib/playbook/kit_base.rb +21 -1
  46. data/lib/playbook/version.rb +2 -2
  47. metadata +30 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 452a03b346d2fe5cd79019537fb3bc6ac4bfbdaa621b3e552d898bdaaf1e7c00
4
- data.tar.gz: fd5127e3deb4e55449b11d1d989335e3b48cfda1d0064b353d615749eef417c6
3
+ metadata.gz: e7befd6847de7d677af4be77be96824572a5fc0cb5a643ea35570064fe156ccb
4
+ data.tar.gz: 67dea2e25b7861d71730c3ad905df0316806517c70f663077e506bdee9be471f
5
5
  SHA512:
6
- metadata.gz: 48edcdfd01a13c5082b670efa0a5d689cd3e3793ce9adacb1789f047bc1514f8f428194d2ea43e1e9bdef4b11d62a496a0b064d6009fed455287ca770ddb81fa
7
- data.tar.gz: 37f2323fd3f2a3b4ea76822e139a9bc2c627f7c3bc6817f1f6092c7d9ea9159db7c9916bd0737baab951f7b4aeae28f17dfe5025282ad678898b5eb40bf05ffb
6
+ metadata.gz: 18d436e20297a673fbcaa699ce41a884d43859dd76482409ffb822b1dc803ceda9b78045642ccea169fd63645b73948e96d52343f76098ac8847415f57344e59
7
+ data.tar.gz: 16b5c21300347386fc574a61fa56a46c5b3e25c38bfb3f48f9b42ddc411b4f5a5d2c9121adbaa5e69384e189dcf24c896dcdf4892d41ff0078e3eea445f7edbb
@@ -1,5 +1,6 @@
1
1
 
2
2
 
3
+
3
4
  @import 'pb_advanced_table/advanced_table';
4
5
  @import 'pb_avatar/avatar';
5
6
  @import 'pb_avatar_action_button/avatar_action_button';
@@ -30,6 +31,7 @@
30
31
  @import 'pb_detail/detail';
31
32
  @import 'pb_dialog/dialog';
32
33
  @import 'pb_distribution_bar/distribution_bar';
34
+ @import 'pb_dropdown/dropdown';
33
35
  @import 'pb_file_upload/file_upload';
34
36
  @import 'pb_filter/filter';
35
37
  @import 'pb_fixed_confirmation_toast/fixed_confirmation_toast';
@@ -35,6 +35,7 @@ export { default as DateYearStacked } from './pb_date_year_stacked/_date_year_st
35
35
  export { default as Detail} from './pb_detail/_detail'
36
36
  export { default as Dialog } from './pb_dialog/_dialog'
37
37
  export { default as DistributionBar } from './pb_distribution_bar/_distribution_bar'
38
+ export { default as Dropdown} from './pb_dropdown/_dropdown'
38
39
  export { default as FileUpload } from './pb_file_upload/_file_upload'
39
40
  export { default as Filter } from './pb_filter/_filter'
40
41
  export { default as FixedConfirmationToast } from './pb_fixed_confirmation_toast/_fixed_confirmation_toast'
@@ -1,9 +1,4 @@
1
- <%= content_tag(:div,
2
- id: object.id,
3
- data: object.data.merge(initials: object.initials),
4
- class: object.classname,
5
- aria: object.aria,
6
- **combined_html_options) do %>
1
+ <%= object.pb_content_tag(:div, data: object.data.merge(initials: object.initials)) do %>
7
2
  <%= content_tag(:div, data: { initials: object.initials }, class: "avatar_wrapper") do %>
8
3
  <%= pb_rails("image", props: { alt: object.alt_text, url: object.image_url, on_error: object.handle_img_error }) if object.image_url.present? %>
9
4
  <% end %>
@@ -13,12 +13,12 @@ import classnames from "classnames";
13
13
 
14
14
  type BarGraphProps = {
15
15
  align?: "left" | "right" | "center";
16
- axisTitle: string;
16
+ axisTitle: { name: string; }[] | string;
17
17
  dark?: boolean;
18
18
  xAxisCategories: [];
19
19
  yAxisMin: number;
20
20
  yAxisMax: number;
21
- chartData: { name: string; data: number[] }[];
21
+ chartData: { name: string; data: number[], yAxis: number }[];
22
22
  className?: string;
23
23
  customOptions?: Partial<Highcharts.Options>;
24
24
  id: string;
@@ -37,6 +37,8 @@ type BarGraphProps = {
37
37
  y?: number;
38
38
  aria?: { [key: string]: string };
39
39
  data?: { [key: string]: string };
40
+ stacking?: "normal" | "percent"
41
+ axisFormat?: { format: string; }[] | string;
40
42
  };
41
43
 
42
44
 
@@ -51,8 +53,10 @@ const BarGraph = ({
51
53
  colors,
52
54
  htmlOptions = {},
53
55
  customOptions = {},
56
+ axisFormat,
54
57
  id,
55
58
  pointStart,
59
+ stacking,
56
60
  subTitle,
57
61
  type = "column",
58
62
  title = "Title",
@@ -67,7 +71,7 @@ const BarGraph = ({
67
71
  x = 0,
68
72
  y = 0,
69
73
  ...props
70
- }: BarGraphProps): React.ReactElement => {
74
+ }: BarGraphProps): React.ReactElement => {
71
75
  const ariaProps = buildAriaProps(aria);
72
76
  const dataProps = buildDataProps(data)
73
77
  const htmlProps = buildHtmlProps(htmlOptions);
@@ -89,13 +93,23 @@ const BarGraph = ({
89
93
  subtitle: {
90
94
  text: subTitle,
91
95
  },
92
- yAxis: {
96
+ yAxis: [{
97
+ labels: {
98
+ format: typeof axisFormat === 'string' ? axisFormat : (axisFormat && axisFormat[0] ? axisFormat[0].format : "")
99
+
100
+ },
93
101
  min: yAxisMin,
94
102
  max: yAxisMax,
103
+ opposite: false,
95
104
  title: {
96
- text: axisTitle,
105
+ text: typeof axisTitle === 'string' ? axisTitle : axisTitle[0].name,
97
106
  },
98
- },
107
+ plotLines: typeof yAxisMin !== 'undefined' && yAxisMin !== null ? [] : [{
108
+ value: 0,
109
+ zIndex: 10,
110
+ color: "#E4E8F0"
111
+ }],
112
+ }],
99
113
  xAxis: {
100
114
  categories: xAxisCategories,
101
115
  },
@@ -113,7 +127,9 @@ const BarGraph = ({
113
127
  : highchartsTheme.colors,
114
128
  plotOptions: {
115
129
  series: {
130
+ stacking: stacking,
116
131
  pointStart: pointStart,
132
+ borderWidth: stacking ? 0 : "",
117
133
  events: {},
118
134
  dataLabels: {
119
135
  enabled: false,
@@ -124,6 +140,25 @@ const BarGraph = ({
124
140
  credits: false,
125
141
  };
126
142
 
143
+ if (Array.isArray(axisTitle) && axisTitle.length > 1 && axisTitle[1].name) {
144
+ staticOptions.yAxis.push({
145
+ labels: {
146
+ format: typeof axisFormat === 'string' ? axisFormat : axisFormat[1].format,
147
+ },
148
+ min: yAxisMin,
149
+ max: yAxisMax,
150
+ opposite: true,
151
+ title: {
152
+ text: axisTitle[1].name,
153
+ },
154
+ plotLines: typeof yAxisMin !== 'undefined' && yAxisMin !== null ? [] : [{
155
+ value: 0,
156
+ zIndex: 10,
157
+ color: "#E4E8F0"
158
+ }],
159
+ });
160
+ }
161
+
127
162
  if (!toggleLegendClick) {
128
163
  staticOptions.plotOptions.series.events = { legendItemClick: () => false };
129
164
  }
@@ -7,6 +7,7 @@ module Playbook
7
7
  values: %w[left right center],
8
8
  default: "center"
9
9
  prop :axis_title
10
+ prop :axis_format
10
11
  prop :chart_data, type: Playbook::Props::Array,
11
12
  default: []
12
13
  prop :custom_options, default: {}
@@ -14,6 +15,7 @@ module Playbook
14
15
  values: %w[vertical horizontal],
15
16
  default: "vertical"
16
17
  prop :point_start, type: Playbook::Props::Numeric
18
+ prop :stacking
17
19
  prop :subtitle
18
20
  prop :title
19
21
  prop :x_axis_categories, type: Playbook::Props::Array,
@@ -49,8 +51,10 @@ module Playbook
49
51
  dark: dark ? "dark" : "",
50
52
  type: chart_type,
51
53
  title: title,
54
+ stacking: stacking,
52
55
  subTitle: subtitle,
53
56
  axisTitle: axis_title,
57
+ axisFormat: axis_format,
54
58
  pointStart: point_start,
55
59
  xAxisCategories: x_axis_categories,
56
60
  yAxisMin: y_axis_min,
@@ -0,0 +1,23 @@
1
+ <% data = [{
2
+ name: 'Installation',
3
+ data: [-475, 400, -1000, 354, -856],
4
+ threshold: 0
5
+ }, {
6
+ name: 'Manufacturing',
7
+ data: [1475, 200, 1000, 654, -656],
8
+ threshold: 0
9
+ },
10
+ {
11
+ name: 'Sales & Distribution',
12
+ data: [1270, 100, -1200, 554, 756],
13
+ threshold: 0
14
+ }] %>
15
+
16
+ <%= pb_rails("bar_graph", props: {
17
+ axis_title: 'Number of Employees',
18
+ chart_data: data,
19
+ id: "bar-default",
20
+ x_axis_categories:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
21
+ title: 'Bar Graph with Negative Numbers',
22
+ legend: true,
23
+ }) %>
@@ -0,0 +1,35 @@
1
+ import React from 'react'
2
+
3
+ import BarGraph from '../_bar_graph'
4
+
5
+ const chartData = [{
6
+ name: 'Installation',
7
+ data: [-475, 400, -1000, 354, -856],
8
+ threshold: 0
9
+ }, {
10
+ name: 'Manufacturing',
11
+ data: [1475, 200, 1000, 654, -656],
12
+ threshold: 0
13
+ },
14
+ {
15
+ name: 'Sales & Distribution',
16
+ data: [1270, 100, -1200, 554, 756],
17
+ threshold: 0
18
+ }]
19
+
20
+
21
+ const BarGraphStacked = (props) => (
22
+ <div>
23
+ <BarGraph
24
+ axisTitle="Number of Employees"
25
+ chartData={chartData}
26
+ id="bar-default"
27
+ legend
28
+ title="Bar Graph with Negative Numbers"
29
+ xAxisCategories={['Jan', 'Feb', 'Mar', 'Apr', 'May']}
30
+ {...props}
31
+ />
32
+ </div>
33
+ )
34
+
35
+ export default BarGraphStacked
@@ -0,0 +1,26 @@
1
+ <% data = [{
2
+ name: 'Number of Installations',
3
+ data: [1475,200,3000,654,656]
4
+ }, {
5
+ type: 'spline',
6
+ name: 'Percentage',
7
+ data: [48, 70, 25, 55, 72],
8
+ color: '#F9BB00',
9
+ yAxis: 1
10
+ }] %>
11
+
12
+ <% axis_titles = [{name: "Number of Installations"}, {name: "Percentage"}] %>
13
+
14
+ <% axis_formats = [{format: ""}, {format: "{value}%"}] %>
15
+
16
+ <%= pb_rails("bar_graph", props: {
17
+ axis_format: axis_formats,
18
+ axis_title: axis_titles,
19
+ chart_data: data,
20
+ id: "bar-spline",
21
+ y_axis_min: 0,
22
+ x_axis_categories:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
23
+ subtitle: 'Source: thesolarfoundation.com',
24
+ title: 'Bar Graph with Secondary Y-axis',
25
+ legend: true,
26
+ }) %>
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+
3
+ import BarGraph from '../_bar_graph'
4
+
5
+ const chartData = [{
6
+ name: 'Number of Installations',
7
+ data: [1475, 200, 3000, 654, 656],
8
+ }, {
9
+ type: 'spline',
10
+ name: 'Percentage',
11
+ data: [48, 70, 25, 55, 72],
12
+ color: '#F9BB00',
13
+ yAxis: 1
14
+ }]
15
+
16
+ const axisTitles = [ {name: "Number of Installations"}, {name: "Percentage"}]
17
+
18
+ const axisFormats = [{format: ""}, {format: "{value}%"}]
19
+
20
+ const BarGraphSecondaryYAxis= (props) => (
21
+ <div>
22
+ <BarGraph
23
+ axisFormat={axisFormats}
24
+ axisTitle={axisTitles}
25
+ chartData={chartData}
26
+ id="bar-spline"
27
+ legend
28
+ title="Bar Graph with Secondary Y-axis"
29
+ xAxisCategories={['Jan', 'Feb', 'Mar', 'Apr', 'May']}
30
+ yAxisMin={0}
31
+ {...props}
32
+ />
33
+ </div>
34
+ )
35
+
36
+ export default BarGraphSecondaryYAxis
@@ -0,0 +1,3 @@
1
+ Optionally add a second yAxis to support secondary datasets (e.x., a spline) by passing` yAxis: 1` to the second node of your `chartData` array.
2
+
3
+ To customize the format and/or title of your secondary yAxis, pass your desired values as arrays through the `axisFormat` and `axisTitle` props, respectively.
@@ -0,0 +1,22 @@
1
+ <% data = [{
2
+ name: 'Installation',
3
+ data: [1475, 200, 3000, 654, 656],
4
+ },
5
+ {
6
+ name: 'Manufacturing',
7
+ data: [1270, 800, 200, 454, 956],
8
+ }, {
9
+ name: 'Sales & Distribution',
10
+ data: [975, 1600, 1500, 924, 500],
11
+ }] %>
12
+
13
+ <%= pb_rails("bar_graph", props: {
14
+ axis_title: 'Number of Employees',
15
+ chart_data: data,
16
+ id: "bar-default",
17
+ y_axis_min: 0,
18
+ x_axis_categories:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
19
+ stacking: "normal",
20
+ title: 'Bar Graph with Stacked Columns',
21
+ legend: true,
22
+ }) %>
@@ -0,0 +1,34 @@
1
+ import React from 'react'
2
+
3
+ import BarGraph from '../_bar_graph'
4
+
5
+ const chartData = [{
6
+ name: 'Installation',
7
+ data: [1475, 200, 3000, 654, 656],
8
+ },
9
+ {
10
+ name: 'Manufacturing',
11
+ data: [1270, 800, 200, 454, 956],
12
+ }, {
13
+ name: 'Sales & Distribution',
14
+ data: [975, 1600, 1500, 924, 500],
15
+ }]
16
+
17
+
18
+ const BarGraphStacked = (props) => (
19
+ <div>
20
+ <BarGraph
21
+ axisTitle="Number Of Employees"
22
+ chartData={chartData}
23
+ id="bar-default"
24
+ legend
25
+ stacking="normal"
26
+ title="Bar Graph with Stacked Columns"
27
+ xAxisCategories={['Jan', 'Feb', 'Mar', 'Apr', 'May']}
28
+ yAxisMin={0}
29
+ {...props}
30
+ />
31
+ </div>
32
+ )
33
+
34
+ export default BarGraphStacked
@@ -0,0 +1 @@
1
+ The `stacking` prop can be used for a stacked bar graph. The prop allows for `normal` or `percent` as options.
@@ -9,6 +9,9 @@ examples:
9
9
  - bar_graph_spline: Spline
10
10
  - bar_graph_colors: Color Overrides
11
11
  - bar_graph_custom: Custom Overrides
12
+ - bar_graph_stacked: Stacked
13
+ - bar_graph_negative_numbers: Negative Numbers
14
+ - bar_graph_secondary_y_axis: Secondary Y-Axis
12
15
 
13
16
 
14
17
  react:
@@ -20,3 +23,6 @@ examples:
20
23
  - bar_graph_spline: Spline
21
24
  - bar_graph_colors: Color Overrides
22
25
  - bar_graph_custom: Custom Overrides
26
+ - bar_graph_stacked: Stacked
27
+ - bar_graph_negative_numbers: Negative Numbers
28
+ - bar_graph_secondary_y_axis: Secondary Y-Axis
@@ -6,3 +6,6 @@ export { default as BarGraphHeight } from './_bar_graph_height.jsx'
6
6
  export { default as BarGraphSpline } from './_bar_graph_spline.jsx'
7
7
  export { default as BarGraphColors } from './_bar_graph_colors.jsx'
8
8
  export { default as BarGraphCustom } from './_bar_graph_custom.jsx'
9
+ export { default as BarGraphStacked } from './_bar_graph_stacked.jsx'
10
+ export { default as BarGraphNegativeNumbers } from './_bar_graph_negative_numbers.jsx'
11
+ export { default as BarGraphSecondaryYAxis } from './_bar_graph_secondary_y_axis.jsx'
@@ -19,7 +19,7 @@
19
19
  }
20
20
  }
21
21
  b, strong {
22
- @include pb_title_4
22
+ font-weight: $bold;
23
23
  }
24
24
 
25
25
  a {
@@ -29,8 +29,8 @@
29
29
  }
30
30
  }
31
31
 
32
- em {
33
- font-weight: $bold;
32
+ em, i {
33
+ font-style: italic;
34
34
  }
35
35
 
36
36
  small {
@@ -0,0 +1,92 @@
1
+ @import "../tokens/colors";
2
+ @import "../tokens/spacing";
3
+ @import "../tokens/typography";
4
+ @import "../tokens/border_radius";
5
+ @import "../tokens/shadows";
6
+ @import "../tokens/positioning";
7
+ @import "../pb_body/body_mixins";
8
+
9
+ .pb_dropdown {
10
+ .dropdown_wrapper {
11
+ position: relative;
12
+ .dropdown_trigger_wrapper {
13
+ @include pb_body;
14
+ border: 1px solid $border_light;
15
+ background-color: $white;
16
+ &:hover {
17
+ background-color: rgba($focus_input_light, $opacity_5);
18
+ input {
19
+ background-color: rgba($focus_input_light, $opacity_5);
20
+ }
21
+ }
22
+
23
+ .dropdown_input {
24
+ @include pb_body;
25
+ border: unset;
26
+ border-radius: $border_rad_heavier;
27
+ padding: 0;
28
+
29
+ &:focus-visible {
30
+ outline: none;
31
+ }
32
+ }
33
+ &:focus {
34
+ box-shadow: 0px 0px 0 1px $primary;
35
+ outline: unset;
36
+ transition: box-shadow .15s ease-in-out;
37
+ }
38
+ }
39
+
40
+ .dropdown_trigger_wrapper_focus {
41
+ box-shadow: 0px 0px 0 1px $primary;
42
+ transition: box-shadow .10s ease-in-out;
43
+ }
44
+
45
+ .pb_dropdown_container {
46
+ background-color: $white;
47
+ overflow:hidden;
48
+ box-shadow: $shadow_deep;
49
+ border-radius: $border_rad_heavier;
50
+ border: 1px solid $border_light;
51
+ margin-top: $space_xs;
52
+ position: absolute;
53
+ z-index: $z_1;
54
+ width: 100%;
55
+ transition: opacity .25s ease-in-out;
56
+
57
+ .pb_dropdown_option {
58
+ :hover {
59
+ background-color: $border_light;
60
+ }
61
+ }
62
+
63
+ .dropdown_option_focused {
64
+ background-color: $border_light;
65
+ }
66
+
67
+ .dropdown_option {
68
+ width: 100%;
69
+ }
70
+
71
+ .dropdown_option_list {
72
+ border-bottom: 1px solid $border_light;
73
+ }
74
+ .dropdown_option_selected {
75
+ background-color: $primary;
76
+ [class^="pb_body"], [class^="pb_title_kit"] {
77
+ color: $white !important;
78
+ }
79
+ :hover {
80
+ background-color: unset;
81
+ }
82
+ }
83
+ }
84
+ .close {
85
+ display: none;
86
+ }
87
+
88
+ .open {
89
+ display: block;
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,152 @@
1
+ import React, {useState, useRef, useEffect} from 'react'
2
+ import classnames from 'classnames'
3
+ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
4
+ import { globalProps } from '../utilities/globalProps'
5
+
6
+ import Body from '../pb_body/_body'
7
+
8
+ import DropdownContainer from './subcomponents/DropdownContainer'
9
+ import DropdownOption from './subcomponents/DropdownOption'
10
+ import DropdownTrigger from './subcomponents/DropdownTrigger'
11
+ import DropdownContext from './context'
12
+ import useDropdown from './hooks/useDropdown'
13
+ import { GenericObject } from '../types'
14
+
15
+ type DropdownProps = {
16
+ aria?: { [key: string]: string },
17
+ className?: string,
18
+ data?: { [key: string]: string },
19
+ id?: string,
20
+ children?: React.ReactChild[] | React.ReactChild,
21
+ options?: GenericObject,
22
+ onSelect?: (arg:GenericObject) => null
23
+ }
24
+
25
+ const Dropdown = (props: DropdownProps) => {
26
+ const {
27
+ aria = {},
28
+ children,
29
+ className,
30
+ data = {},
31
+ id,
32
+ options,
33
+ onSelect
34
+ } = props
35
+
36
+ const ariaProps = buildAriaProps(aria)
37
+ const dataProps = buildDataProps(data)
38
+ const classes = classnames(buildCss('pb_dropdown'), globalProps(props), className)
39
+
40
+ const [ isDropDownClosed, setIsDropDownClosed, toggleDropdown ] = useDropdown()
41
+
42
+ const [filterItem, setFilterItem] = useState("");
43
+ const [selected, setSelected] = useState({});
44
+ const [isInputFocused, setIsInputFocused] = useState(false);
45
+ //state for keyboard events
46
+ const [focusedOptionIndex, setFocusedOptionIndex] = useState(-1);
47
+
48
+ const dropdownRef = useRef(null);
49
+ const inputRef = useRef(null);
50
+
51
+ // useEffect to handle clicks outside the dropdown
52
+ useEffect(() => {
53
+ const handleClickOutside = (event: any) => {
54
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
55
+ setIsDropDownClosed(true);
56
+ setIsInputFocused(false)
57
+ }
58
+ };
59
+ window.addEventListener("click", handleClickOutside);
60
+ return () => {
61
+ window.removeEventListener("click", handleClickOutside);
62
+ };
63
+ }, []);
64
+
65
+
66
+ const handleChange = (e: any) => {
67
+ setFilterItem(e.target.value);
68
+ setIsDropDownClosed(false);
69
+ };
70
+
71
+ const handleOptionClick = (selectedItem: GenericObject) => {
72
+ setSelected(selectedItem);
73
+ setFilterItem("");
74
+ setIsDropDownClosed(true);
75
+ onSelect(selectedItem);
76
+ };
77
+
78
+
79
+ const handleWrapperClick = () => {
80
+ inputRef.current.focus();
81
+ toggleDropdown();
82
+ };
83
+
84
+ const handleBackspace = () => {
85
+ setSelected({})
86
+ onSelect(null)
87
+ setFocusedOptionIndex(-1)
88
+ }
89
+
90
+ const filteredOptions = options?.filter((option: GenericObject) =>
91
+ option.label.toLowerCase().includes(filterItem.toLowerCase())
92
+ );
93
+
94
+ return (
95
+ <div
96
+ {...ariaProps}
97
+ {...dataProps}
98
+ className={classes}
99
+ id={id}
100
+ >
101
+ <DropdownContext.Provider
102
+ value={{
103
+ filteredOptions,
104
+ filterItem,
105
+ focusedOptionIndex,
106
+ handleBackspace,
107
+ handleChange,
108
+ handleOptionClick,
109
+ handleWrapperClick,
110
+ inputRef,
111
+ isInputFocused,
112
+ options,
113
+ selected,
114
+ setFocusedOptionIndex,
115
+ setIsInputFocused,
116
+ setSelected,
117
+ isDropDownClosed,
118
+ setIsDropDownClosed,
119
+ toggleDropdown
120
+
121
+ }}
122
+ >
123
+ <div className="dropdown_wrapper"
124
+ ref={dropdownRef}
125
+ >
126
+ {children ? (
127
+ children
128
+ ) : (
129
+ <>
130
+ <DropdownTrigger />
131
+ <DropdownContainer>
132
+ {options && options?.map((option: GenericObject) => (
133
+ <Dropdown.Option key={option.id}
134
+ option={option}
135
+ >
136
+ <Body text={option.label}/>
137
+ </Dropdown.Option>
138
+ ))}
139
+ </DropdownContainer>
140
+ </>
141
+ )}
142
+ </div>
143
+ </DropdownContext.Provider>
144
+ </div>
145
+ )
146
+ }
147
+
148
+ Dropdown.Option = DropdownOption;
149
+ Dropdown.Trigger = DropdownTrigger;
150
+ Dropdown.Container = DropdownContainer;
151
+
152
+ export default Dropdown
@@ -0,0 +1,5 @@
1
+ import { createContext } from "react";
2
+
3
+ const DropdownContext = createContext<any>({});
4
+
5
+ export default DropdownContext;