playbook_ui 14.9.0.pre.alpha.pbntr700newresettodefaultprop4736 → 14.9.0.pre.alpha.play1703errorstatealignment4889

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +61 -17
  3. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination.jsx +50 -0
  4. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination.md +1 -0
  5. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination_with_props.jsx +57 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination_with_props.md +5 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_pagination_mock_data.json +5600 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +2 -0
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +5 -3
  11. data/app/pb_kits/playbook/pb_avatar/_avatar.scss +0 -2
  12. data/app/pb_kits/playbook/pb_body/_body.scss +14 -13
  13. data/app/pb_kits/playbook/pb_body/_body_mixins.scss +22 -16
  14. data/app/pb_kits/playbook/pb_bread_crumbs/docs/_bread_crumbs_default.jsx +6 -0
  15. data/app/pb_kits/playbook/pb_caption/_caption_mixin.scss +2 -1
  16. data/app/pb_kits/playbook/pb_card/_card_mixin.scss +1 -1
  17. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +0 -5
  18. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +0 -10
  19. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +0 -1
  20. data/app/pb_kits/playbook/pb_file_upload/_file_upload.scss +5 -0
  21. data/app/pb_kits/playbook/pb_file_upload/_file_upload.tsx +7 -2
  22. data/app/pb_kits/playbook/pb_file_upload/file_upload.html.erb +8 -2
  23. data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +1 -2
  24. data/app/pb_kits/playbook/pb_form_group/_form_group.scss +15 -3
  25. data/app/pb_kits/playbook/pb_nav/_bold_mixin.scss +11 -1
  26. data/app/pb_kits/playbook/pb_nav/_collapsible_nav.scss +16 -2
  27. data/app/pb_kits/playbook/pb_nav/_vertical_nav.scss +1 -1
  28. data/app/pb_kits/playbook/pb_pagination/_pagination.tsx +2 -2
  29. data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.scss +4 -4
  30. data/app/pb_kits/playbook/pb_selectable_card/selectable_card.html.erb +1 -1
  31. data/app/pb_kits/playbook/pb_stat_change/_stat_change.tsx +44 -36
  32. data/app/pb_kits/playbook/pb_stat_change/stat_change.html.erb +4 -4
  33. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns.html.erb +95 -0
  34. data/app/pb_kits/playbook/pb_table/index.ts +100 -26
  35. data/app/pb_kits/playbook/pb_table/table.html.erb +1 -1
  36. data/app/pb_kits/playbook/pb_table/table.rb +17 -2
  37. data/app/pb_kits/playbook/pb_title/_title.scss +6 -5
  38. data/app/pb_kits/playbook/pb_title/_title_mixin.scss +13 -0
  39. data/app/pb_kits/playbook/tokens/_titles.scss +0 -8
  40. data/app/pb_kits/playbook/utilities/_hover.scss +11 -2
  41. data/app/pb_kits/playbook/utilities/globalProps.ts +2 -0
  42. data/app/pb_kits/playbook/utilities/test/globalProps/hover.test.js +15 -0
  43. data/dist/chunks/{_typeahead-DU1QgR52.js → _typeahead-4sdDeM4X.js} +2 -2
  44. data/dist/chunks/_weekday_stacked-CblTZ9cd.js +45 -0
  45. data/dist/chunks/{lib-Ce7MLbJk.js → lib-CVPInSs5.js} +2 -2
  46. data/dist/chunks/{pb_form_validation-kPWA1Z2g.js → pb_form_validation-CDLJ5eAG.js} +1 -1
  47. data/dist/chunks/vendor.js +1 -1
  48. data/dist/playbook-doc.js +1 -1
  49. data/dist/playbook-rails-react-bindings.js +1 -1
  50. data/dist/playbook-rails.js +1 -1
  51. data/dist/playbook.css +1 -1
  52. data/lib/playbook/hover.rb +7 -1
  53. data/lib/playbook/version.rb +1 -1
  54. metadata +12 -6
  55. data/dist/chunks/_weekday_stacked-BLOmRNnB.js +0 -45
@@ -1,40 +1,46 @@
1
- import React from 'react'
2
- import classnames from 'classnames'
1
+ import React from "react"
2
+ import classnames from "classnames"
3
3
 
4
- import { buildCss, buildHtmlProps } from '../utilities/props'
5
- import { globalProps } from '../utilities/globalProps'
4
+ import { buildCss, buildHtmlProps } from "../utilities/props"
5
+ import { globalProps } from "../utilities/globalProps"
6
6
 
7
- import Body from '../pb_body/_body'
8
- import Icon from '../pb_icon/_icon'
7
+ import Body from "../pb_body/_body"
8
+ import Icon from "../pb_icon/_icon"
9
9
 
10
- const statusMap: {neutral: 'neutral', decrease: 'negative' ,increase: 'positive'} = {
11
- increase: 'positive',
12
- decrease: 'negative',
13
- neutral: 'neutral',
10
+ const statusMap: {
11
+ neutral: "neutral"
12
+ decrease: "negative"
13
+ increase: "positive"
14
+ } = {
15
+ increase: "positive",
16
+ decrease: "negative",
17
+ neutral: "neutral",
14
18
  }
15
19
 
16
20
  const iconMap = {
17
- increase: 'arrow-up',
18
- decrease: 'arrow-down',
21
+ increase: "arrow-up",
22
+ decrease: "arrow-down",
19
23
  }
20
24
 
21
25
  type StatChangeProps = {
22
- change?: 'increase' | 'decrease' | 'neutral',
23
- className?: string,
24
- icon?: string,
25
- htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
26
- id?: string,
27
- value?: string | number,
26
+ change?: "increase" | "decrease" | "neutral"
27
+ className?: string
28
+ dark?: boolean
29
+ icon?: string
30
+ id?: string
31
+ htmlOptions?: { [key: string]: string | number | boolean | (() => void) }
32
+ value?: string | number
28
33
  }
29
34
 
30
35
  const StatChange = (props: StatChangeProps): React.ReactElement => {
31
- const {
32
- change = 'neutral',
33
- className,
36
+ const {
37
+ change = "neutral",
38
+ className,
39
+ dark = false,
34
40
  htmlOptions = {},
35
- icon,
36
- id,
37
- value
41
+ icon,
42
+ id,
43
+ value,
38
44
  } = props
39
45
 
40
46
  const status = statusMap[change as keyof typeof statusMap]
@@ -47,30 +53,32 @@ const StatChange = (props: StatChangeProps): React.ReactElement => {
47
53
 
48
54
  return (
49
55
  <>
50
- {value &&
56
+ {value && (
51
57
  <div
52
58
  className={classnames(
53
- buildCss('pb_stat_change_kit', status),
54
- globalProps(props),
55
- className
56
- )}
59
+ buildCss("pb_stat_change_kit", status),
60
+ globalProps(props),
61
+ className
62
+ )}
57
63
  id={id}
58
64
  {...htmlProps}
59
65
  >
60
- <Body status={status}>
61
- {returnedIcon &&
66
+ <Body dark={dark}
67
+ status={status}
68
+ >
69
+ {" "}
70
+ {returnedIcon && (
62
71
  <>
63
- <Icon
72
+ <Icon dark={dark}
64
73
  fixed_width
65
74
  icon={returnedIcon}
66
- />
67
- {' '}
75
+ />{" "}
68
76
  </>
69
- }
77
+ )}
70
78
  {`${value}%`}
71
79
  </Body>
72
80
  </div>
73
- }
81
+ )}
74
82
  </>
75
83
  )
76
84
  }
@@ -1,6 +1,6 @@
1
1
  <%= pb_content_tag do %>
2
- <%= pb_rails("body", props: { status: object.status }) do %>
3
- <%= pb_rails("icon", props: { fixed_width: true, icon: object.returned_icon }) if object.returned_icon %>
4
- <%= "#{object.value}%" if object.value %>
5
- <% end %>
2
+ <%= pb_rails("body", props: { status: object.status, dark: object.dark }) do %>
3
+ <%= pb_rails("icon", props: { fixed_width: true, icon: object.returned_icon, dark: object.dark }) if object.returned_icon %>
4
+ <%= "#{object.value}%" if object.value %>
5
+ <% end %>
6
6
  <% end %>
@@ -0,0 +1,95 @@
1
+ <%= pb_rails("table", props: { size: "md", responsive: "scroll", sticky_left_column: ["1", "2", "3"] }) do %>
2
+ <thead>
3
+ <tr>
4
+ <th id="1">Column 1</th>
5
+ <th id="2">Column 2</th>
6
+ <th id="3">Column 3</th>
7
+ <th>Column 4</th>
8
+ <th>Column 5</th>
9
+ <th>Column 6</th>
10
+ <th>Column 7</th>
11
+ <th>Column 8</th>
12
+ <th>Column 9</th>
13
+ <th>Column 10</th>
14
+ <th>Column 11</th>
15
+ <th>Column 12</th>
16
+ <th>Column 13</th>
17
+ <th>Column 14</th>
18
+ <th>Column 15</th>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <tr>
23
+ <td id="1">Value 1</td>
24
+ <td id="2">Value 2</td>
25
+ <td id="3">Value 3</td>
26
+ <td>Value 4</td>
27
+ <td>Value 5</td>
28
+ <td>Column 6</td>
29
+ <td>Column 7</td>
30
+ <td>Column 8</td>
31
+ <td>Column 9</td>
32
+ <td>Column 10</td>
33
+ <td>Column 11</td>
34
+ <td>Column 12</td>
35
+ <td>Column 13</td>
36
+ <td>Column 14</td>
37
+ <td>Column 15</td>
38
+
39
+ </tr>
40
+ <tr>
41
+ <td id="1">Value 1</td>
42
+ <td id="2">Value 2</td>
43
+ <td id="3">Value 3</td>
44
+ <td>Value 4</td>
45
+ <td>Value 5</td>
46
+ <td>Column 6</td>
47
+ <td>Column 7</td>
48
+ <td>Column 8</td>
49
+ <td>Column 9</td>
50
+ <td>Column 10</td>
51
+ <td>Column 11</td>
52
+ <td>Column 12</td>
53
+ <td>Column 13</td>
54
+ <td>Column 14</td>
55
+ <td>Column 15</td>
56
+
57
+ </tr>
58
+ <tr>
59
+ <td id="1">Value 1</td>
60
+ <td id="2">Value 2</td>
61
+ <td id="3">Value 3</td>
62
+ <td>Value 4</td>
63
+ <td>Value 5</td>
64
+ <td>Column 6</td>
65
+ <td>Column 7</td>
66
+ <td>Column 8</td>
67
+ <td>Column 9</td>
68
+ <td>Column 10</td>
69
+ <td>Column 11</td>
70
+ <td>Column 12</td>
71
+ <td>Column 13</td>
72
+ <td>Column 14</td>
73
+ <td>Column 15</td>
74
+
75
+ </tr>
76
+ <tr>
77
+ <td id="1">Value 1</td>
78
+ <td id="2">Value 2</td>
79
+ <td id="3">Value 3</td>
80
+ <td>Value 4</td>
81
+ <td>Value 5</td>
82
+ <td>Column 6</td>
83
+ <td>Column 7</td>
84
+ <td>Column 8</td>
85
+ <td>Column 9</td>
86
+ <td>Column 10</td>
87
+ <td>Column 11</td>
88
+ <td>Column 12</td>
89
+ <td>Column 13</td>
90
+ <td>Column 14</td>
91
+ <td>Column 15</td>
92
+
93
+ </tr>
94
+ </tbody>
95
+ <% end %>
@@ -1,32 +1,106 @@
1
1
  import PbEnhancedElement from '../pb_enhanced_element'
2
2
 
3
3
  export default class PbTable extends PbEnhancedElement {
4
- static get selector(): string {
5
- return '.table-responsive-collapse'
6
- }
7
-
8
- connect(): void {
9
- const tables = document.querySelectorAll('.table-responsive-collapse');
10
-
11
- // Each Table
12
- [].forEach.call(tables, (table: HTMLTableElement) => {
13
- // Header Titles
14
- const headers: string[] = [];
15
- [].forEach.call(table.querySelectorAll('th'), (header: HTMLTableCellElement) => {
16
- const colSpan = header.colSpan
17
- for (let i = 0; i < colSpan; i++) {
18
- headers.push(header.textContent.replace(/\r?\n|\r/, ''));
4
+ private stickyLeftColumns: string[] = [];
5
+ private handleStickyColumnsRef: () => void;
6
+
7
+ static get selector(): string {
8
+ return '.table-responsive-collapse'
9
+ }
10
+
11
+ connect(): void {
12
+ const tables = document.querySelectorAll('.table-responsive-collapse');
13
+ // Each Table
14
+ [].forEach.call(tables, (table: HTMLTableElement) => {
15
+ // Header Titles
16
+ const headers: string[] = [];
17
+ [].forEach.call(table.querySelectorAll('th'), (header: HTMLTableCellElement) => {
18
+ const colSpan = header.colSpan
19
+ for (let i = 0; i < colSpan; i++) {
20
+ headers.push(header.textContent.replace(/\r?\n|\r/, ''));
21
+ }
22
+ });
23
+ // for each row in tbody
24
+ [].forEach.call(table.querySelectorAll('tbody tr'), (row: HTMLTableRowElement) => {
25
+ // for each cell
26
+ [].forEach.call(row.cells, (cell: HTMLTableCellElement, headerIndex: number) => {
27
+ // apply the attribute
28
+ cell.setAttribute('data-title', headers[headerIndex])
29
+ })
30
+ })
31
+ });
32
+
33
+ // New sticky columns logic
34
+ this.initStickyColumns();
35
+ }
36
+
37
+ private initStickyColumns(): void {
38
+ // Find tables with sticky-left-column class
39
+ const tables = document.querySelectorAll('.sticky-left-column');
40
+
41
+ tables.forEach((table) => {
42
+ // Extract sticky left column IDs by looking at the component's class
43
+ const classList = Array.from(table.classList);
44
+
45
+ // Look for classes in the format sticky-left-column-{ids}
46
+ const stickyColumnClass = classList.find(cls => cls.startsWith('sticky-columns-'));
47
+ if (stickyColumnClass) {
48
+ // Extract the IDs from the class name
49
+ this.stickyLeftColumns = stickyColumnClass
50
+ .replace('sticky-columns-', '')
51
+ .split('-');
52
+
53
+ if (this.stickyLeftColumns.length > 0) {
54
+ this.handleStickyColumnsRef = this.handleStickyColumns.bind(this);
55
+ this.handleStickyColumns();
56
+ window.addEventListener('resize', this.handleStickyColumnsRef);
57
+ }
19
58
  }
20
59
  });
60
+ }
21
61
 
22
- // for each row in tbody
23
- [].forEach.call(table.querySelectorAll('tbody tr'), (row: HTMLTableRowElement) => {
24
- // for each cell
25
- [].forEach.call(row.cells, (cell: HTMLTableCellElement, headerIndex: number) => {
26
- // apply the attribute
27
- cell.setAttribute('data-title', headers[headerIndex])
28
- })
29
- })
30
- })
31
- }
32
- }
62
+ private handleStickyColumns(): void {
63
+ let accumulatedWidth = 0;
64
+
65
+ this.stickyLeftColumns.forEach((colId, index) => {
66
+ const isLastColumn = index === this.stickyLeftColumns.length - 1;
67
+ const header = document.querySelector(`th[id="${colId}"]`);
68
+ const cells = document.querySelectorAll(`td[id="${colId}"]`);
69
+
70
+ if (header) {
71
+ header.classList.add('sticky');
72
+ (header as HTMLElement).style.left = `${accumulatedWidth}px`;
73
+
74
+ if (!isLastColumn) {
75
+ header.classList.add('with-border');
76
+ header.classList.remove('sticky-shadow');
77
+ } else {
78
+ header.classList.remove('with-border');
79
+ header.classList.add('sticky-shadow');
80
+ }
81
+
82
+ accumulatedWidth += (header as HTMLElement).offsetWidth;
83
+ }
84
+
85
+ cells.forEach((cell) => {
86
+ cell.classList.add('sticky');
87
+ (cell as HTMLElement).style.left = `${accumulatedWidth - (header as HTMLElement).offsetWidth}px`;
88
+
89
+ if (!isLastColumn) {
90
+ cell.classList.add('with-border');
91
+ cell.classList.remove('sticky-shadow');
92
+ } else {
93
+ cell.classList.remove('with-border');
94
+ cell.classList.add('sticky-shadow');
95
+ }
96
+ });
97
+ });
98
+ }
99
+
100
+ // Cleanup method to remove event listener
101
+ disconnect(): void {
102
+ if (this.handleStickyColumnsRef) {
103
+ window.removeEventListener('resize', this.handleStickyColumnsRef);
104
+ }
105
+ }
106
+ }
@@ -18,4 +18,4 @@
18
18
  <%= content.presence %>
19
19
  <% end %>
20
20
  <% end %>
21
- <% end %>
21
+ <% end %>
@@ -23,6 +23,8 @@ module Playbook
23
23
  prop :text
24
24
  prop :sticky, type: Playbook::Props::Boolean,
25
25
  default: false
26
+ prop :sticky_left_column, type: Playbook::Props::Array,
27
+ default: []
26
28
  prop :vertical_border, type: Playbook::Props::Boolean,
27
29
  default: false
28
30
  prop :striped, type: Playbook::Props::Boolean,
@@ -37,8 +39,8 @@ module Playbook
37
39
  def classname
38
40
  generate_classname(
39
41
  "pb_table", "table-#{size}", single_line_class, dark_class,
40
- disable_hover_class, container_class, data_table_class, sticky_class, collapse_class,
41
- vertical_border_class, striped_class, outer_padding_class,
42
+ disable_hover_class, container_class, data_table_class, sticky_class, sticky_left_column_class,
43
+ collapse_class, vertical_border_class, striped_class, outer_padding_class,
42
44
  "table-responsive-#{responsive}", separator: " "
43
45
  )
44
46
  end
@@ -73,6 +75,19 @@ module Playbook
73
75
  sticky ? "sticky-header" : nil
74
76
  end
75
77
 
78
+ def sticky_left_column_class
79
+ if sticky_left_column.empty?
80
+ nil
81
+ else
82
+ sticky_col_classname = "sticky-left-column sticky-columns"
83
+ sticky_left_column.each do |id|
84
+ sticky_col_classname += "-#{id}"
85
+ end
86
+
87
+ sticky_col_classname
88
+ end
89
+ end
90
+
76
91
  def striped_class
77
92
  striped ? "striped" : nil
78
93
  end
@@ -49,10 +49,11 @@
49
49
  }
50
50
 
51
51
  &.dark {
52
- @include pb_title_dark;
53
- }
54
-
55
- &.dark[class*=_link] {
56
- @include pb_title_dark_link;
52
+ @include title_dark;
53
+ @each $name, $color in $pb_dark_title_colors {
54
+ &[class*="_#{$name}"] {
55
+ color: $color;
56
+ }
57
+ }
57
58
  }
58
59
  }
@@ -9,6 +9,15 @@ $pb_title_colors: (
9
9
  link: $primary
10
10
  );
11
11
 
12
+ $pb_dark_title_colors: (
13
+ default: $text_dk_default,
14
+ light: $text_dk_light,
15
+ lighter: $text_dk_lighter,
16
+ success: $success,
17
+ error: $error_dark,
18
+ link: $active_dark
19
+ );
20
+
12
21
  @mixin title_colors {
13
22
  @each $name, $color in $pb_title_colors {
14
23
  &[class*=_#{$name}] {
@@ -16,3 +25,7 @@ $pb_title_colors: (
16
25
  }
17
26
  }
18
27
  }
28
+
29
+ @mixin title_dark {
30
+ color: $text_dk_default;
31
+ }
@@ -33,14 +33,6 @@
33
33
  @include pb_title($heading_4, $bolder, $letterSpacing: $lspace_normal);
34
34
  }
35
35
 
36
- @mixin pb_title_dark {
37
- color: $text_dk_default;
38
- }
39
-
40
- @mixin pb_title_dark_link {
41
- color: $active_dark;
42
- }
43
-
44
36
  @mixin pb_title_bold {
45
37
  font-weight: $bolder;
46
38
  }
@@ -20,6 +20,13 @@
20
20
  }
21
21
  }
22
22
 
23
+ @mixin hover-underline {
24
+ .hover_underline:hover {
25
+ text-decoration: underline;
26
+ transition: text-decoration $transition-speed ease;
27
+ }
28
+ }
29
+
23
30
  @mixin hover-color-classes($colors-list) {
24
31
  @each $name, $color in $colors-list {
25
32
  .hover_background-#{"" + $name}:hover {
@@ -32,7 +39,9 @@
32
39
  }
33
40
  }
34
41
  }
35
-
42
+
43
+
44
+ @include hover-underline;
36
45
  @include hover-scale-classes($scales);
37
46
  @include hover-shadow-classes($box_shadows);
38
47
  @include hover-color-classes($product_colors);
@@ -64,4 +73,4 @@
64
73
  .group_hover.hover_visibility {
65
74
  opacity: 1;
66
75
  }
67
- }
76
+ }
@@ -64,6 +64,7 @@ type Hover = Shadow & {
64
64
  background?: string,
65
65
  color?: string,
66
66
  scale?: "sm" | "md" | "lg",
67
+ underline?: boolean,
67
68
  visibility?: boolean,
68
69
  }
69
70
 
@@ -236,6 +237,7 @@ const PROP_CATEGORIES: {[key:string]: (props: {[key: string]: any}) => string} =
236
237
  if (!hover) return css;
237
238
  css += hover.shadow ? `hover_shadow_${hover.shadow} ` : '';
238
239
  css += hover.background ? `hover_background-${hover.background } ` : '';
240
+ css += hover.underline ? `hover_underline ` : '';
239
241
  css += hover.scale ? `hover_scale_${hover.scale} ` : '';
240
242
  css += hover.color ? `hover_color-${hover.color } ` : '';
241
243
  css += hover.visibility ? `hover_visibility` : '';
@@ -57,6 +57,19 @@ test('Hover Props: returns proper class name', () => {
57
57
  expectedClassName = `hover_scale_xl`;
58
58
  expect(kit).toHaveClass(expectedClassName);
59
59
 
60
+ const testIdUnderline = `${testSubject}-hover-underline`;
61
+ render(
62
+ <Body
63
+ data={{ testid: testIdUnderline }}
64
+ hover={{ underline: true }}
65
+ text="Hi"
66
+ />
67
+ );
68
+
69
+ kit = screen.getByTestId(testIdUnderline);
70
+ expectedClassName = `hover_underline`;
71
+ expect(kit).toHaveClass(expectedClassName);
72
+
60
73
  const testIdMultiple = `${testSubject}-hover-multiple`;
61
74
  render(
62
75
  <Body
@@ -66,6 +79,7 @@ test('Hover Props: returns proper class name', () => {
66
79
  background: 'error',
67
80
  shadow: 'deeper',
68
81
  scale: 'xl',
82
+ underline: true,
69
83
  }}
70
84
  text="Hi"
71
85
  />
@@ -76,4 +90,5 @@ test('Hover Props: returns proper class name', () => {
76
90
  expect(kit).toHaveClass('hover_background-error');
77
91
  expect(kit).toHaveClass('hover_shadow_deeper');
78
92
  expect(kit).toHaveClass('hover_scale_xl');
93
+ expect(kit).toHaveClass('hover_underline');
79
94
  });