playbook_ui 13.28.0.pre.alpha.PBNTR296dropdownwithform2941 → 13.28.0.pre.alpha.PBNTR297gradientoverlay3029

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +3 -3
  3. data/app/pb_kits/playbook/index.js +3 -0
  4. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +2 -2
  5. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_subrow_headers.html.erb +40 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_subrow_headers.md +3 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_subrow_headers.md +1 -1
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +1 -1
  9. data/app/pb_kits/playbook/pb_advanced_table/table_body.html.erb +1 -1
  10. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +14 -4
  11. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +10 -2
  12. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +1 -1
  13. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +2 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.html.erb +34 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.rb +31 -0
  16. data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx +4 -1
  17. data/app/pb_kits/playbook/pb_bar_graph/barGraph.test.js +31 -0
  18. data/app/pb_kits/playbook/pb_bar_graph/bar_graph.rb +16 -0
  19. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_custom.md +2 -1
  20. data/app/pb_kits/playbook/pb_bar_graph/docs/{_bar_graph_custom.html.erb → _bar_graph_custom_rails.html.erb} +3 -3
  21. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_custom_rails.md +2 -0
  22. data/app/pb_kits/playbook/pb_bar_graph/docs/example.yml +1 -1
  23. data/app/pb_kits/playbook/pb_card/_card_mixin.scss +2 -1
  24. data/app/pb_kits/playbook/pb_checkbox/_checkbox.scss +1 -2
  25. data/app/pb_kits/playbook/pb_circle_chart/_circle_chart.tsx +9 -3
  26. data/app/pb_kits/playbook/pb_circle_chart/circleChart.test.js +45 -0
  27. data/app/pb_kits/playbook/pb_circle_chart/circle_chart.rb +22 -1
  28. data/app/pb_kits/playbook/pb_collapsible/__snapshots__/collapsible.test.js.snap +53 -0
  29. data/app/pb_kits/playbook/pb_collapsible/_collapsible.tsx +14 -8
  30. data/app/pb_kits/playbook/pb_collapsible/collapsible.test.js +24 -0
  31. data/app/pb_kits/playbook/pb_dashboard/pbChartsDarkTheme.ts +7 -1
  32. data/app/pb_kits/playbook/pb_dashboard/pbChartsLightTheme.ts +9 -1
  33. data/app/pb_kits/playbook/pb_draggable/_draggable.scss +10 -0
  34. data/app/pb_kits/playbook/pb_draggable/_draggable.tsx +53 -0
  35. data/app/pb_kits/playbook/pb_draggable/context/index.tsx +92 -0
  36. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default.jsx +53 -0
  37. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_multiple_containers.jsx +159 -0
  38. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards.jsx +121 -0
  39. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +9 -0
  40. data/app/pb_kits/playbook/pb_draggable/docs/index.js +3 -0
  41. data/app/pb_kits/playbook/pb_draggable/draggable.test.jsx +65 -0
  42. data/app/pb_kits/playbook/pb_draggable/subcomponents/DraggableContainer.tsx +54 -0
  43. data/app/pb_kits/playbook/pb_draggable/subcomponents/DraggableItem.tsx +57 -0
  44. data/app/pb_kits/playbook/pb_form_group/_form_group.scss +2 -2
  45. data/app/pb_kits/playbook/pb_gauge/_gauge.tsx +4 -1
  46. data/app/pb_kits/playbook/pb_gauge/gauge.rb +6 -1
  47. data/app/pb_kits/playbook/pb_gauge/gauge.test.js +35 -0
  48. data/app/pb_kits/playbook/pb_line_graph/_line_graph.tsx +8 -2
  49. data/app/pb_kits/playbook/pb_line_graph/lineGraph.test.js +52 -0
  50. data/app/pb_kits/playbook/pb_line_graph/line_graph.rb +22 -1
  51. data/app/pb_kits/playbook/pb_overlay/_overlay.scss +12 -0
  52. data/app/pb_kits/playbook/pb_overlay/_overlay.tsx +93 -0
  53. data/app/pb_kits/playbook/pb_overlay/docs/_overlay_default.jsx +40 -0
  54. data/app/pb_kits/playbook/pb_overlay/docs/_overlay_default.md +7 -0
  55. data/app/pb_kits/playbook/pb_overlay/docs/_overlay_multi_directional.jsx +36 -0
  56. data/app/pb_kits/playbook/pb_overlay/docs/_overlay_multi_directional.md +5 -0
  57. data/app/pb_kits/playbook/pb_overlay/docs/example.yml +4 -0
  58. data/app/pb_kits/playbook/pb_overlay/docs/index.js +2 -0
  59. data/app/pb_kits/playbook/pb_overlay/overlay.test.jsx +66 -0
  60. data/app/pb_kits/playbook/pb_pill/docs/_description.md +1 -1
  61. data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.scss +1 -0
  62. data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.tsx +30 -32
  63. data/app/pb_kits/playbook/pb_selectable_card/selectable_card.html.erb +0 -2
  64. data/app/pb_kits/playbook/pb_table/_table.tsx +5 -0
  65. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_column.jsx +33 -32
  66. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_column.md +1 -1
  67. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_column_rails.md +2 -0
  68. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_row.jsx +33 -33
  69. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_row.md +1 -1
  70. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_row_rails.html.erb +34 -0
  71. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_row_rails.md +2 -0
  72. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data.jsx +51 -50
  73. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data.md +1 -1
  74. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data_rails.html.erb +54 -0
  75. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data_rails.md +2 -0
  76. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row.jsx +37 -38
  77. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row.md +1 -0
  78. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row_rails.html.erb +53 -0
  79. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row_rails.md +1 -0
  80. data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_row.html.erb → _table_outer_padding.html.erb} +7 -7
  81. data/app/pb_kits/playbook/pb_table/docs/_table_outer_padding.jsx +76 -0
  82. data/app/pb_kits/playbook/pb_table/docs/_table_outer_padding.md +1 -0
  83. data/app/pb_kits/playbook/pb_table/docs/example.yml +9 -9
  84. data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
  85. data/app/pb_kits/playbook/pb_table/styles/_all.scss +1 -0
  86. data/app/pb_kits/playbook/pb_table/styles/_outer_padding.scss +21 -0
  87. data/app/pb_kits/playbook/pb_table/table.rb +14 -1
  88. data/app/pb_kits/playbook/pb_table/table.test.js +5 -1
  89. data/app/pb_kits/playbook/pb_tooltip/index.js +1 -0
  90. data/app/pb_kits/playbook/pb_treemap_chart/_treemap_chart.tsx +12 -9
  91. data/app/pb_kits/playbook/pb_treemap_chart/treemapChart.test.js +61 -0
  92. data/app/pb_kits/playbook/pb_treemap_chart/treemap_chart.rb +6 -1
  93. data/app/pb_kits/playbook/playbook-doc.js +4 -0
  94. data/app/pb_kits/playbook/tokens/_vertical_align.scss +18 -0
  95. data/app/pb_kits/playbook/utilities/_vertical_align.scss +16 -0
  96. data/app/pb_kits/playbook/utilities/globalProps.ts +12 -1
  97. data/dist/menu.yml +7 -2
  98. data/dist/playbook-rails.js +6 -6
  99. data/lib/playbook/classnames.rb +1 -0
  100. data/lib/playbook/kit_base.rb +2 -0
  101. data/lib/playbook/version.rb +1 -1
  102. data/lib/playbook/vertical_align.rb +37 -0
  103. metadata +50 -7
  104. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data.html.erb +0 -63
  105. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row.html.erb +0 -52
  106. /data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_column.html.erb → _table_alignment_column_rails.html.erb} +0 -0
@@ -0,0 +1,65 @@
1
+ import React, {useState} from "react"
2
+ import { render, screen } from "../utilities/test-utils"
3
+
4
+ import { Draggable, DraggableProvider, SelectableList } from '../'
5
+
6
+ const testId = 'draggable'
7
+
8
+ const data = [
9
+ {
10
+ id: "1",
11
+ text: "Task 1",
12
+ },
13
+ {
14
+ id: "2",
15
+ text: "Task 2",
16
+ },
17
+ {
18
+ id: "3",
19
+ text: "Task 3",
20
+ },
21
+ {
22
+ id: "4",
23
+ text: "Task 4",
24
+ },
25
+ ];
26
+
27
+
28
+ const DefaultDraggableKit = () => {
29
+ const [initialState, setInitialState] = useState(data);
30
+
31
+ return (
32
+ <DraggableProvider
33
+ initialItems={data}
34
+ onChange={(items) => setInitialState(items)}
35
+ >
36
+ <Draggable
37
+ data={{ testid: testId }}
38
+ draggableItems={data}
39
+ onDragChange={(items) => setInitialItems(items)}
40
+ >
41
+ <Draggable.Container>
42
+ <SelectableList variant="checkbox">
43
+ {initialState.map(({ id, text }) => (
44
+ <Draggable.Item id={id}
45
+ key={id}
46
+ >
47
+ <SelectableList.Item label={text}
48
+ name={id}
49
+ value={id}
50
+ />
51
+ </Draggable.Item>
52
+ ))}
53
+ </SelectableList>
54
+ </Draggable.Container>
55
+ </Draggable>
56
+ </DraggableProvider>
57
+ );
58
+ };
59
+
60
+ test('generated default kit and classname', () => {
61
+ render(<DefaultDraggableKit/>)
62
+ const kit = screen.getByTestId(testId)
63
+ expect(kit).toBeInTheDocument()
64
+ expect(kit).toHaveClass('pb_draggable')
65
+ })
@@ -0,0 +1,54 @@
1
+ import React from "react";
2
+ import classnames from "classnames";
3
+ import {
4
+ buildAriaProps,
5
+ buildCss,
6
+ buildDataProps,
7
+ buildHtmlProps
8
+ } from "../../utilities/props";
9
+ import { globalProps } from "../../utilities/globalProps";
10
+ import { DraggableContext } from "../context";
11
+
12
+ type DraggableContainerProps = {
13
+ aria?: { [key: string]: string };
14
+ children?: React.ReactNode;
15
+ className?: string;
16
+ container?: any;
17
+ data?: { [key: string]: string };
18
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
19
+ id?: string;
20
+ };
21
+
22
+ const DraggableContainer = (props: DraggableContainerProps) => {
23
+ const { aria = {}, children, className, container, data = {}, htmlOptions = {}, id } = props;
24
+
25
+ const { handleDragOver, handleDrop, activeContainer } = DraggableContext();
26
+
27
+ const ariaProps = buildAriaProps(aria);
28
+ const dataProps = buildDataProps(data);
29
+ const htmlProps = buildHtmlProps(htmlOptions);
30
+
31
+ const classes = classnames(
32
+ buildCss("pb_draggable_container"),
33
+ `${activeContainer === container ? "active" : ""}`,
34
+ globalProps(props),
35
+ className
36
+ );
37
+
38
+ return (
39
+ <div
40
+ {...ariaProps}
41
+ {...dataProps}
42
+ {...htmlProps}
43
+ className={classes}
44
+ id={id}
45
+ key={container}
46
+ onDragOver={(e) => handleDragOver(e, container)}
47
+ onDrop={() => handleDrop(container)}
48
+ >
49
+ {children}
50
+ </div>
51
+ );
52
+ };
53
+
54
+ export default DraggableContainer;
@@ -0,0 +1,57 @@
1
+ import React from "react";
2
+ import classnames from "classnames";
3
+ import {
4
+ buildAriaProps,
5
+ buildCss,
6
+ buildDataProps,
7
+ buildHtmlProps
8
+ } from "../../utilities/props";
9
+ import { globalProps } from "../../utilities/globalProps";
10
+ import { DraggableContext } from "../context";
11
+
12
+ type DraggableItemProps = {
13
+ aria?: { [key: string]: string };
14
+ children?: React.ReactNode;
15
+ className?: string;
16
+ container?: any;
17
+ data?: { [key: string]: string };
18
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
19
+ id?: string;
20
+ };
21
+
22
+ const DraggableItem = (props: DraggableItemProps) => {
23
+ const { aria = {}, children, className, container, data = {}, htmlOptions = {}, id } = props;
24
+
25
+ const { isDragging, handleDragStart, handleDragEnter, handleDragEnd } =
26
+ DraggableContext();
27
+
28
+ const ariaProps = buildAriaProps(aria);
29
+ const dataProps = buildDataProps(data);
30
+ const htmlProps = buildHtmlProps(htmlOptions);
31
+
32
+ const classes = classnames(
33
+ buildCss("pb_draggable_item"),
34
+ `${isDragging === id ? "is_dragging" : ""}`,
35
+ globalProps(props),
36
+ className
37
+ );
38
+
39
+ return (
40
+ <div
41
+ {...ariaProps}
42
+ {...dataProps}
43
+ {...htmlProps}
44
+ className={classes}
45
+ draggable
46
+ id={id}
47
+ key={id}
48
+ onDragEnd={() => handleDragEnd()}
49
+ onDragEnter={() => handleDragEnter(id, container)}
50
+ onDragStart={() => handleDragStart(id, container)}
51
+ >
52
+ {children}
53
+ </div>
54
+ );
55
+ };
56
+
57
+ export default DraggableItem;
@@ -107,7 +107,7 @@
107
107
  }
108
108
 
109
109
  & > [class^=pb_date_picker_kit]:not(:last-child) {
110
- .text_input_wrapper input, [class^=pb_text_input_kit] .text_input_wrapper .flatpickr-wrapper {
110
+ .input_wrapper input, [class^=pb_text_input_kit] .date_picker_input_wrapper .flatpickr-wrapper {
111
111
  border-bottom-right-radius: 0;
112
112
  border-top-right-radius: 0;
113
113
  border-right-width: 0;
@@ -115,7 +115,7 @@
115
115
  }
116
116
 
117
117
  & > [class^=pb_date_picker_kit]:not(:first-child) {
118
- .text_input_wrapper input, [class^=pb_text_input_kit] .text_input_wrapper .flatpickr-wrapper {
118
+ .input_wrapper input, [class^=pb_text_input_kit] .date_picker_input_wrapper .flatpickr-wrapper {
119
119
  border-bottom-left-radius: 0;
120
120
  border-top-left-radius: 0;
121
121
  }
@@ -13,11 +13,13 @@ import typography from "../tokens/exports/_typography.scss";
13
13
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
14
14
  import { globalProps } from "../utilities/globalProps";
15
15
  import { GenericObject } from "../types";
16
+ import { merge } from 'lodash'
16
17
 
17
18
  type GaugeProps = {
18
19
  aria: { [key: string]: string };
19
20
  className?: string;
20
21
  chartData?: { name: string; value: number[] | number }[];
22
+ customOptions?: Partial<Highcharts.Options>;
21
23
  dark?: boolean;
22
24
  data?: { [key: string]: string };
23
25
  disableAnimation?: boolean;
@@ -41,6 +43,7 @@ type GaugeProps = {
41
43
  const Gauge = ({
42
44
  aria = {},
43
45
  chartData,
46
+ customOptions = {},
44
47
  dark = false,
45
48
  data = {},
46
49
  disableAnimation = false,
@@ -175,7 +178,7 @@ const Gauge = ({
175
178
  },
176
179
  };
177
180
 
178
- setOptions({ ...staticOptions });
181
+ setOptions(merge(staticOptions, customOptions));
179
182
 
180
183
  if (document.querySelector(".prefix")) {
181
184
  document.querySelectorAll(".prefix").forEach((prefix) => {
@@ -5,6 +5,7 @@ module Playbook
5
5
  class Gauge < Playbook::KitBase
6
6
  prop :chart_data, type: Playbook::Props::Array,
7
7
  default: [{ name: "Name", value: 0 }]
8
+ prop :custom_options, default: {}
8
9
  prop :style, type: Playbook::Props::Enum,
9
10
  values: %w[solidgauge],
10
11
  default: "solidgauge"
@@ -22,7 +23,7 @@ module Playbook
22
23
  prop :max, type: Playbook::Props::Numeric, default: 100
23
24
  prop :colors, type: Playbook::Props::Array, default: []
24
25
 
25
- def chart_options
26
+ def standard_options
26
27
  {
27
28
  id: id,
28
29
  chartData: chart_data,
@@ -43,6 +44,10 @@ module Playbook
43
44
  }
44
45
  end
45
46
 
47
+ def chart_options
48
+ standard_options.deep_merge(custom_options)
49
+ end
50
+
46
51
  def classname
47
52
  generate_classname("pb_gauge_kit")
48
53
  end
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { render, screen } from '../utilities/test-utils';
3
+ import Gauge from './_gauge';
4
+
5
+ beforeEach(() => {
6
+ // Silences error logs within the test suite.
7
+ jest.spyOn(console, 'error');
8
+ jest.spyOn(console, 'warn');
9
+ console.error.mockImplementation(() => {});
10
+ console.warn.mockImplementation(() => {});
11
+ });
12
+
13
+ afterEach(() => {
14
+ console.error.mockRestore();
15
+ console.warn.mockRestore();
16
+ });
17
+
18
+ const testId = 'gauge1';
19
+
20
+ test('uses exact classname', () => {
21
+ const data = [
22
+ { name: 'Name', value: 45 },
23
+ ]
24
+ render(
25
+ <Gauge
26
+ chartData={data}
27
+ data={{ testid: testId }}
28
+ id='gaugeid'
29
+ />
30
+ );
31
+
32
+ const kit = screen.getByTestId(testId);
33
+ expect(kit).toHaveClass('pb_gauge_kit');
34
+ });
35
+
@@ -8,6 +8,7 @@ import Highcharts from "highcharts";
8
8
  import { highchartsTheme } from "../pb_dashboard/pbChartsLightTheme";
9
9
  import { highchartsDarkTheme } from "../pb_dashboard/pbChartsDarkTheme";
10
10
  import mapColors from "../pb_dashboard/pbChartsColorsHelper";
11
+ import { merge } from 'lodash'
11
12
 
12
13
  type LineGraphProps = {
13
14
  align?: "left" | "right" | "center";
@@ -21,6 +22,7 @@ type LineGraphProps = {
21
22
  name: string;
22
23
  data: number[];
23
24
  }[];
25
+ customOptions?: Partial<Highcharts.Options>;
24
26
  gradient?: boolean;
25
27
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
26
28
  id: string;
@@ -45,6 +47,7 @@ const LineGraph = ({
45
47
  data = {},
46
48
  align = "center",
47
49
  className = "pb_bar_graph",
50
+ customOptions = {},
48
51
  dark = false,
49
52
  gradient = false,
50
53
  type = "line",
@@ -130,16 +133,19 @@ const LineGraph = ({
130
133
  staticOptions.plotOptions.series.events = { legendItemClick: () => false };
131
134
  }
132
135
 
136
+ const filteredProps: any = {...props};
137
+ delete filteredProps.verticalAlign;
138
+
133
139
  const [options, setOptions] = useState({});
134
140
 
135
141
  useEffect(() => {
136
- setOptions({ ...staticOptions });
142
+ setOptions(merge(staticOptions, customOptions));
137
143
  }, [chartData]);
138
144
 
139
145
  return (
140
146
  <HighchartsReact
141
147
  containerProps={{
142
- className: classnames(globalProps(props), className),
148
+ className: classnames(globalProps(filteredProps), className),
143
149
  id: id,
144
150
  ...ariaProps,
145
151
  ...dataProps,
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import { render, screen } from '../utilities/test-utils';
3
+ import LineGraph from './_line_graph';
4
+
5
+ beforeEach(() => {
6
+ // Silences error logs within the test suite.
7
+ jest.spyOn(console, 'error');
8
+ jest.spyOn(console, 'warn');
9
+ console.error.mockImplementation(() => {});
10
+ console.warn.mockImplementation(() => {});
11
+ });
12
+
13
+ afterEach(() => {
14
+ console.error.mockRestore();
15
+ console.warn.mockRestore();
16
+ });
17
+
18
+ const testId = 'linechart1';
19
+
20
+ test('uses exact classname', () => {
21
+ const data = [{
22
+ name: 'Installation',
23
+ data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175],
24
+ }, {
25
+ name: 'Manufacturing',
26
+ data: [24916, 24064, 29742, 29851, 32490, 30282, 38121, 40434],
27
+ }, {
28
+ name: 'Sales & Distribution',
29
+ data: [11744, 17722, 16005, 19771, 20185, 24377, 32147, 39387],
30
+ }, {
31
+ name: 'Project Development',
32
+ data: [null, null, 7988, 12169, 15112, 22452, 34400, 34227],
33
+ }, {
34
+ name: 'Other',
35
+ data: [12908, 5948, 8105, 11248, 8989, 11816, 18274, 18111],
36
+ }]
37
+ render(
38
+ <LineGraph
39
+ axisTitle="Number of Employees"
40
+ chartData={data}
41
+ data={{ testid: testId }}
42
+ id="line-default"
43
+ subTitle="Source: thesolarfoundation.com"
44
+ title="Solar Employment Growth by Sector, 2010-2016"
45
+ xAxisCategories={['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']}
46
+ yAxisMin={0}
47
+ />
48
+ );
49
+
50
+ const kit = screen.getByTestId(testId);
51
+ expect(kit).toHaveClass('pb_bar_graph');
52
+ });
@@ -9,6 +9,7 @@ module Playbook
9
9
  prop :axis_title
10
10
  prop :chart_data, type: Playbook::Props::Array,
11
11
  default: []
12
+ prop :custom_options, default: {}
12
13
  prop :gradient, type: Playbook::Props::Boolean,
13
14
  default: false
14
15
  prop :point_start, type: Playbook::Props::Numeric
@@ -38,7 +39,7 @@ module Playbook
38
39
  gradient ? "area" : "line"
39
40
  end
40
41
 
41
- def chart_options
42
+ def standard_options
42
43
  {
43
44
  align: align,
44
45
  id: id,
@@ -64,6 +65,26 @@ module Playbook
64
65
  }
65
66
  end
66
67
 
68
+ def chart_options
69
+ standard_options.deep_merge(custom_options)
70
+ end
71
+
72
+ def vertical_align_props
73
+ if vertical_align
74
+ if object.vertical_align
75
+ original_result = super
76
+ class_to_remove = "vertical_align_#{object.vertical_align}"
77
+
78
+ modified_result = original_result.gsub(class_to_remove, "").strip
79
+ modified_result.empty? ? nil : modified_result
80
+ else
81
+ super
82
+ end
83
+ else
84
+ super
85
+ end
86
+ end
87
+
67
88
  def classname
68
89
  generate_classname("pb_line_graph")
69
90
  end
@@ -0,0 +1,12 @@
1
+ [class^=pb_overlay] {
2
+ .overlay-container {
3
+ position: relative;
4
+ }
5
+
6
+ .overlay {
7
+ position: absolute;
8
+ inset: 0;
9
+ pointer-events: none;
10
+ z-index: 1;
11
+ }
12
+ }
@@ -0,0 +1,93 @@
1
+ import React from 'react'
2
+ import classnames from 'classnames'
3
+ import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
4
+ import { globalProps } from '../utilities/globalProps'
5
+ import defaultColors from "../tokens/exports/_colors.scss";
6
+
7
+ type OverlayProps = {
8
+ aria?: { [key: string]: string },
9
+ className?: string,
10
+ children: React.ReactNode[] | React.ReactNode,
11
+ color: "white" | "bg_light" | "card_dark" | "bg_dark",
12
+ data?: { [key: string]: string },
13
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
14
+ id?: string,
15
+ layout: { [key: string]: string },
16
+ }
17
+
18
+ const previousOverlayDirectionMap: { [key: string]: string } = {
19
+ "bottom": "to top",
20
+ "top": "to bottom",
21
+ "left-right": "to right",
22
+ "top-bottom": "to top",
23
+ }
24
+
25
+ const subsequentOverlayDirectionMap: { [key: string]: string } = {
26
+ "bottom": "to top",
27
+ "top": "to bottom",
28
+ "left-right": "to left",
29
+ "top-bottom": "to bottom",
30
+ }
31
+
32
+ const Overlay = (props: OverlayProps) => {
33
+ const {
34
+ aria = {},
35
+ className,
36
+ children,
37
+ color = "white",
38
+ data = {},
39
+ htmlOptions = {},
40
+ id,
41
+ layout = { "bottom": "100%" },
42
+ } = props
43
+
44
+ const ariaProps = buildAriaProps(aria)
45
+ const dataProps = buildDataProps(data)
46
+ const classes = classnames(buildCss('pb_overlay'), globalProps(props), className)
47
+ const htmlProps = buildHtmlProps(htmlOptions)
48
+
49
+ const getPosition = () => {
50
+ return Object.keys(layout)[0]
51
+ }
52
+
53
+ const getSize = () => {
54
+ return Object.values(layout)[0]
55
+ }
56
+
57
+ const getPreviousOverlayDirection = () => {
58
+ return previousOverlayDirectionMap[getPosition()]
59
+ }
60
+
61
+ const getSubsequentOverlayDirection = () => {
62
+ return subsequentOverlayDirectionMap[getPosition()]
63
+ }
64
+
65
+ const hasSubsequentOverlay = getPosition() === "left-right" || getPosition() === "top-bottom"
66
+
67
+ const previousOverlay = `linear-gradient(${getPreviousOverlayDirection()}, ${defaultColors[color]} 0%, transparent ${getSize()})`
68
+ const subsequentOverlay = `linear-gradient(${getSubsequentOverlayDirection()}, ${defaultColors[color]} 0%, transparent ${getSize()})`
69
+
70
+ return (
71
+ <div
72
+ {...ariaProps}
73
+ {...dataProps}
74
+ {...htmlProps}
75
+ className={classes}
76
+ id={id}
77
+ >
78
+ <div className="overlay-container">
79
+ <div className="overlay"
80
+ style={{ background: previousOverlay }} />
81
+
82
+ {children}
83
+
84
+ { hasSubsequentOverlay &&
85
+ <div className="overlay"
86
+ style={{ background: subsequentOverlay }} />
87
+ }
88
+ </div>
89
+ </div>
90
+ )
91
+ }
92
+
93
+ export default Overlay
@@ -0,0 +1,40 @@
1
+ import React from 'react'
2
+ import {
3
+ Overlay,
4
+ Table,
5
+ } from '../..'
6
+
7
+ const TableExample = () => {
8
+ return (
9
+ <Table size="sm">
10
+ <thead>
11
+ <tr>
12
+ <th>{'Column 1'}</th>
13
+ <th>{'Column 2'}</th>
14
+ <th>{'Column 3'}</th>
15
+ <th>{'Column 4'}</th>
16
+ <th>{'Column 5'}</th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ {Array.from({ length: 7 }, (_, index) => (
21
+ <tr key={index}>
22
+ {Array.from({ length: 5 }, (_, columnIndex) => (
23
+ <td key={columnIndex}>{`Value ${columnIndex + 1}`}</td>
24
+ ))}
25
+ </tr>
26
+ ))}
27
+ </tbody>
28
+ </Table>
29
+ )
30
+ }
31
+
32
+ const OverlayDefault = () => (
33
+ <>
34
+ <Overlay>
35
+ <TableExample />
36
+ </Overlay>
37
+ </>
38
+ )
39
+
40
+ export default OverlayDefault
@@ -0,0 +1,7 @@
1
+ Overlays require a `color`, which sets the "start" (opaque) color of a gradient mask. Because this overlay is intended to reveal underlying content, the "end" color is fixed to transparent.
2
+
3
+ The optional `layout` prop accepts a `position` and a `size` as a key:value pair object.
4
+
5
+ The `position` prop sets the side where the `color` overlay starts. The direction of the overlay is always toward the opposite side of the position. For example, the default position of `bottom` starts the overlay on the bottom edge of your container and extends it toward the opposite side: the top.
6
+
7
+ The `size` prop accepts a percentage value as a string and literally translates to how much of the container is covered by the overlay. By default, `size` is set to `100%` so that your overlay covers the entire container with a smooth fade from `color` at its starting edge, fading to transparent and ending at the containers opposite edge.
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+ import {
3
+ Overlay,
4
+ Card,
5
+ Flex,
6
+ FlexItem,
7
+ } from '../..'
8
+
9
+ const InlineCardsExample = () => {
10
+ return (
11
+ <Flex
12
+ columnGap="lg"
13
+ orientation="row"
14
+ overflowX="auto"
15
+ >
16
+ {Array.from({ length: 15 }, (_, index) => (
17
+ <FlexItem key={index}>
18
+ <Card>{"Card Content"}</Card>
19
+ </FlexItem>
20
+ ))}
21
+ </Flex>
22
+ )
23
+ }
24
+
25
+ const OverlayMultiDirectional = () => (
26
+ <>
27
+ <Overlay
28
+ color="white"
29
+ layout={{"left-right": "10%"}}
30
+ >
31
+ <InlineCardsExample />
32
+ </Overlay>
33
+ </>
34
+ )
35
+
36
+ export default OverlayMultiDirectional
@@ -0,0 +1,5 @@
1
+ Optionally, you can pass multi-directional options (`left-right` or `top-bottom`) to the `position` prop, which create multiple overlays.
2
+
3
+ Your `color` is still applied as the starting edge to both overlays, and each mask will fade to transparent moving toward its opposite edge, ending at the `size` percentage you set.
4
+
5
+ NOTE: Multi-directional overlays share the available container space, so passing a size greater than "50%" to a multi-directional overlay will cause your masks to overlap at the midline of your container. As a best practice, we do not recommend exceeding a size of 25% when using multi-directional overlays.
@@ -0,0 +1,4 @@
1
+ examples:
2
+ react:
3
+ - overlay_default: Default
4
+ - overlay_multi_directional: Multi-directional
@@ -0,0 +1,2 @@
1
+ export { default as OverlayDefault } from './_overlay_default.jsx'
2
+ export { default as OverlayMultiDirectional } from './_overlay_multi_directional.jsx'