playbook_ui 14.8.0 → 14.9.0.pre.alpha.PBNTR702stickyleftcolrails4806

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +2 -0
  3. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +61 -17
  4. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.html.erb +1 -1
  5. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb +1 -1
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell_rails.html.erb +53 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell_rails.md +5 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination.jsx +50 -0
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination.md +1 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination_with_props.jsx +57 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination_with_props.md +5 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_pagination_mock_data.json +5600 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +3 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +3 -1
  16. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +15 -0
  17. data/app/pb_kits/playbook/pb_background/_background.tsx +8 -2
  18. data/app/pb_kits/playbook/pb_button/_button.scss +6 -0
  19. data/app/pb_kits/playbook/pb_button/_button.tsx +1 -3
  20. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +15 -0
  21. data/app/pb_kits/playbook/pb_button/button.rb +1 -1
  22. data/app/pb_kits/playbook/pb_button/docs/_button_default.html.erb +1 -0
  23. data/app/pb_kits/playbook/pb_button/docs/_button_default.jsx +8 -0
  24. data/app/pb_kits/playbook/pb_button/docs/_button_default.md +1 -1
  25. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +2 -2
  26. data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +0 -4
  27. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.html.erb +84 -7
  28. data/app/pb_kits/playbook/pb_collapsible/_collapsible.tsx +3 -1
  29. data/app/pb_kits/playbook/pb_currency/_currency.tsx +7 -3
  30. data/app/pb_kits/playbook/pb_currency/currency.html.erb +2 -2
  31. data/app/pb_kits/playbook/pb_currency/currency.rb +17 -1
  32. data/app/pb_kits/playbook/pb_currency/currency.test.js +40 -3
  33. data/app/pb_kits/playbook/pb_currency/docs/_currency_negative.html.erb +4 -0
  34. data/app/pb_kits/playbook/pb_currency/docs/_currency_negative.jsx +16 -0
  35. data/app/pb_kits/playbook/pb_currency/docs/example.yml +2 -0
  36. data/app/pb_kits/playbook/pb_currency/docs/index.js +1 -0
  37. data/app/pb_kits/playbook/pb_drawer/_drawer.scss +1 -0
  38. data/app/pb_kits/playbook/pb_drawer/_drawer.tsx +159 -45
  39. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_menu.jsx +31 -0
  40. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_menu.md +6 -0
  41. data/app/pb_kits/playbook/pb_drawer/docs/example.yml +1 -1
  42. data/app/pb_kits/playbook/pb_drawer/docs/index.js +1 -0
  43. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +1 -0
  44. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.html.erb +0 -1
  45. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.rb +0 -4
  46. data/app/pb_kits/playbook/pb_dropdown/utilities/subComponentHelper.tsx +13 -2
  47. data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +2 -2
  48. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb +1 -1
  49. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +63 -12
  50. data/app/pb_kits/playbook/pb_image/_image.tsx +3 -1
  51. data/app/pb_kits/playbook/pb_layout/_layout.tsx +6 -3
  52. data/app/pb_kits/playbook/pb_overlay/_overlay.tsx +3 -1
  53. data/app/pb_kits/playbook/pb_pagination/_pagination.tsx +2 -2
  54. data/app/pb_kits/playbook/pb_progress_simple/_progress_simple.tsx +5 -3
  55. data/app/pb_kits/playbook/pb_progress_simple/progress_simple.html.erb +3 -2
  56. data/app/pb_kits/playbook/pb_progress_simple/progress_simple.rb +5 -0
  57. data/app/pb_kits/playbook/pb_section_separator/_section_separator.tsx +3 -1
  58. data/app/pb_kits/playbook/pb_selectable_card/docs/_selectable_card_default.html.erb +2 -1
  59. data/app/pb_kits/playbook/pb_table/_table.tsx +109 -25
  60. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns.html.erb +95 -0
  61. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns.jsx +87 -0
  62. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns_react.md +2 -0
  63. data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
  64. data/app/pb_kits/playbook/pb_table/index.ts +100 -26
  65. data/app/pb_kits/playbook/pb_table/styles/_all.scss +2 -0
  66. data/app/pb_kits/playbook/pb_table/styles/_scroll.scss +4 -0
  67. data/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss +18 -0
  68. data/app/pb_kits/playbook/pb_table/table.html.erb +1 -1
  69. data/app/pb_kits/playbook/pb_table/table.rb +17 -2
  70. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.html.erb +47 -0
  71. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.jsx +59 -0
  72. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +3 -0
  73. data/app/pb_kits/playbook/pb_typeahead/index.ts +29 -3
  74. data/app/pb_kits/playbook/pb_typeahead/typeahead.html.erb +5 -2
  75. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +4 -0
  76. data/app/pb_kits/playbook/tokens/_height.scss +19 -0
  77. data/app/pb_kits/playbook/tokens/exports/_height.module.scss +37 -0
  78. data/app/pb_kits/playbook/utilities/_height.scss +33 -0
  79. data/app/pb_kits/playbook/utilities/_max_width.scss +29 -9
  80. data/app/pb_kits/playbook/utilities/_min_width.scss +6 -2
  81. data/app/pb_kits/playbook/utilities/_width.scss +45 -0
  82. data/app/pb_kits/playbook/utilities/globalPropNames.mjs +1 -1
  83. data/app/pb_kits/playbook/utilities/globalProps.ts +37 -4
  84. data/dist/chunks/_typeahead-CCDoUmRR.js +22 -0
  85. data/dist/chunks/_weekday_stacked-CxjKLoMr.js +45 -0
  86. data/dist/chunks/{lib-BC6ESsxG.js → lib-CVPInSs5.js} +2 -2
  87. data/dist/chunks/{pb_form_validation-B_Z9rEbg.js → pb_form_validation-CDLJ5eAG.js} +1 -1
  88. data/dist/chunks/vendor.js +1 -1
  89. data/dist/menu.yml +321 -0
  90. data/dist/playbook-doc.js +1 -1
  91. data/dist/playbook-rails-react-bindings.js +1 -1
  92. data/dist/playbook-rails.js +1 -1
  93. data/dist/playbook.css +1 -1
  94. data/lib/playbook/classnames.rb +4 -0
  95. data/lib/playbook/forms/builder/typeahead_field.rb +13 -0
  96. data/lib/playbook/height.rb +29 -0
  97. data/lib/playbook/kit_base.rb +16 -1
  98. data/lib/playbook/max_height.rb +29 -0
  99. data/lib/playbook/min_height.rb +29 -0
  100. data/lib/playbook/spacing.rb +21 -0
  101. data/lib/playbook/version.rb +2 -2
  102. metadata +32 -9
  103. data/dist/chunks/_typeahead-D0PihN_3.js +0 -22
  104. data/dist/chunks/_weekday_stacked-uMIX8f-A.js +0 -45
@@ -1,7 +1,9 @@
1
1
  import React from 'react'
2
2
  import classnames from 'classnames'
3
3
  import { buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
4
- import { globalProps } from '../utilities/globalProps'
4
+ import { globalProps, GlobalProps } from '../utilities/globalProps'
5
+
6
+ type ModifiedGlobalProps = Omit<GlobalProps, 'width'>
5
7
 
6
8
  type ProgressSimpleProps = {
7
9
  align?: "left" | "center" | "right",
@@ -16,7 +18,7 @@ type ProgressSimpleProps = {
16
18
  value: number,
17
19
  variant?: "default" | "positive" | "negative" | "warning",
18
20
  width: string,
19
- }
21
+ } & ModifiedGlobalProps
20
22
 
21
23
  const ProgressSimple = (props: ProgressSimpleProps): React.ReactElement => {
22
24
  const {
@@ -56,7 +58,7 @@ const ProgressSimple = (props: ProgressSimpleProps): React.ReactElement => {
56
58
  )
57
59
 
58
60
  return (
59
- <div
61
+ <div
60
62
  {...dataProps}
61
63
  {...htmlProps}
62
64
  className={wrapperClass}
@@ -1,9 +1,10 @@
1
- <%= content_tag(:div, class: object.wrapper_classname) do %>
1
+ <%= content_tag(:div,
2
+ class: object.wrapper_classname,
3
+ style: object.style) do %>
2
4
  <%= content_tag(:div,
3
5
  id: object.id,
4
6
  data: object.data_values,
5
7
  class: object.classname,
6
- style: object.style,
7
8
  **combined_html_options) do %>
8
9
  <%= content_tag(:div, "",
9
10
  class: "progress_simple_value",
@@ -21,6 +21,11 @@ module Playbook
21
21
  values: %w[default positive negative warning],
22
22
  default: "default"
23
23
 
24
+ # Explicitly defining the width prop here so the local prop takes precedence over global width prop
25
+ def width
26
+ prop(:width)
27
+ end
28
+
24
29
  def number_value
25
30
  validate_required_progress_props
26
31
 
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import classnames from 'classnames'
3
3
 
4
4
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
- import { globalProps } from '../utilities/globalProps'
5
+ import { globalProps, globalInlineProps } from '../utilities/globalProps'
6
6
 
7
7
  import Caption from '../pb_caption/_caption'
8
8
 
@@ -38,6 +38,7 @@ const SectionSeparator = (props: SectionSeparatorProps): React.ReactElement => {
38
38
  const dataProps = buildDataProps(data)
39
39
  const htmlProps = buildHtmlProps(htmlOptions)
40
40
  const classes = classnames(buildCss('pb_section_separator_kit', variant, orientation, lineStyle === "dashed" ? lineStyle : ""), globalProps(props), className)
41
+ const dynamicInlineProps = globalInlineProps(props)
41
42
 
42
43
  return (
43
44
 
@@ -47,6 +48,7 @@ const SectionSeparator = (props: SectionSeparatorProps): React.ReactElement => {
47
48
  {...htmlProps}
48
49
  className={classes}
49
50
  id={id}
51
+ style={dynamicInlineProps}
50
52
  >
51
53
  {
52
54
  children && children ||
@@ -6,6 +6,7 @@
6
6
  value: "selected_with_icon",
7
7
  checked: true,
8
8
  icon: true,
9
+
9
10
  }) do %>
10
11
  Selected, with icon
11
12
  <% end %>
@@ -36,4 +37,4 @@
36
37
  Disabled
37
38
  <% end %>
38
39
 
39
- </div>
40
+ </div>
@@ -1,14 +1,14 @@
1
1
  import React, { useEffect } from 'react'
2
2
  import classnames from 'classnames'
3
3
  import { buildAriaProps, buildDataProps, buildHtmlProps } from '../utilities/props'
4
- import { globalProps, GlobalProps } from '../utilities/globalProps'
4
+ import { globalProps, GlobalProps, globalInlineProps } from '../utilities/globalProps'
5
5
  import PbTable from '.'
6
6
  import {
7
- TableHead,
8
- TableHeader,
9
- TableBody,
10
- TableRow,
11
- TableCell,
7
+ TableHead,
8
+ TableHeader,
9
+ TableBody,
10
+ TableRow,
11
+ TableCell,
12
12
  } from "./subcomponents";
13
13
 
14
14
  type TableProps = {
@@ -28,6 +28,7 @@ type TableProps = {
28
28
  singleLine?: boolean,
29
29
  size?: "sm" | "md" | "lg",
30
30
  sticky?: boolean,
31
+ stickyLeftcolumn?: string[],
31
32
  striped?: boolean,
32
33
  tag?: "table" | "div",
33
34
  verticalBorder?: boolean,
@@ -51,6 +52,7 @@ const Table = (props: TableProps): React.ReactElement => {
51
52
  singleLine = false,
52
53
  size = 'sm',
53
54
  sticky = false,
55
+ stickyLeftcolumn = [],
54
56
  striped = false,
55
57
  tag = 'table',
56
58
  verticalBorder = false,
@@ -64,6 +66,7 @@ const Table = (props: TableProps): React.ReactElement => {
64
66
  const spaceCssName = outerPadding !== 'none' ? 'space_' : ''
65
67
  const outerPaddingCss = outerPadding ? `outer_padding_${spaceCssName}${outerPadding}` : ''
66
68
  const isTableTag = tag === 'table'
69
+ const dynamicInlineProps = globalInlineProps(props)
67
70
 
68
71
  const classNames = classnames(
69
72
  'pb_table',
@@ -76,6 +79,7 @@ const Table = (props: TableProps): React.ReactElement => {
76
79
  'single-line': singleLine,
77
80
  'no-hover': disableHover,
78
81
  'sticky-header': sticky,
82
+ 'sticky-left-column': stickyLeftcolumn,
79
83
  'striped': striped,
80
84
  [outerPaddingCss]: outerPadding !== '',
81
85
  },
@@ -85,6 +89,56 @@ const Table = (props: TableProps): React.ReactElement => {
85
89
  className
86
90
  )
87
91
 
92
+ useEffect(() => {
93
+ const handleStickyColumns = () => {
94
+ let accumulatedWidth = 0;
95
+
96
+ stickyLeftcolumn.forEach((colId, index) => {
97
+ const isLastColumn = index === stickyLeftcolumn.length - 1;
98
+ const header = document.querySelector(`th[id="${colId}"]`);
99
+ const cells = document.querySelectorAll(`td[id="${colId}"]`);
100
+
101
+ if (header) {
102
+ header.classList.add('sticky');
103
+ (header as HTMLElement).style.left = `${accumulatedWidth}px`;
104
+
105
+ if (!isLastColumn) {
106
+ header.classList.add('with-border');
107
+ header.classList.remove('sticky-shadow');
108
+ } else {
109
+ header.classList.remove('with-border');
110
+ header.classList.add('sticky-shadow');
111
+ }
112
+
113
+ accumulatedWidth += (header as HTMLElement).offsetWidth;
114
+ }
115
+
116
+ cells.forEach((cell) => {
117
+ cell.classList.add('sticky');
118
+ (cell as HTMLElement).style.left = `${accumulatedWidth - (header as HTMLElement).offsetWidth}px`;
119
+
120
+ if (!isLastColumn) {
121
+ cell.classList.add('with-border');
122
+ cell.classList.remove('sticky-shadow');
123
+ } else {
124
+ cell.classList.remove('with-border');
125
+ cell.classList.add('sticky-shadow');
126
+ }
127
+ });
128
+ });
129
+ };
130
+
131
+ setTimeout(() => {
132
+ handleStickyColumns();
133
+ }, 10);
134
+
135
+ window.addEventListener('resize', handleStickyColumns);
136
+
137
+ return () => {
138
+ window.removeEventListener('resize', handleStickyColumns);
139
+ };
140
+ }, [stickyLeftcolumn]);
141
+
88
142
  useEffect(() => {
89
143
  const instance = new PbTable()
90
144
  instance.connect()
@@ -92,26 +146,56 @@ const Table = (props: TableProps): React.ReactElement => {
92
146
 
93
147
  return (
94
148
  <>
95
- {isTableTag ? (
96
- <table
97
- {...ariaProps}
98
- {...dataProps}
99
- {...htmlProps}
100
- className={classNames}
101
- id={id}
102
- >
103
- {children}
104
- </table>
105
- ) : (
106
- <div
107
- {...ariaProps}
108
- {...dataProps}
109
- {...htmlProps}
110
- className={classNames}
111
- id={id}
112
- >
113
- {children}
149
+ {responsive === 'scroll' ? (
150
+ <div className='table-responsive-scroll'>
151
+ {isTableTag ? (
152
+ <table
153
+ {...ariaProps}
154
+ {...dataProps}
155
+ {...htmlProps}
156
+ className={classNames}
157
+ id={id}
158
+ style={dynamicInlineProps}
159
+ >
160
+ {children}
161
+ </table>
162
+ ) : (
163
+ <div
164
+ {...ariaProps}
165
+ {...dataProps}
166
+ {...htmlProps}
167
+ className={classNames}
168
+ id={id}
169
+ style={dynamicInlineProps}
170
+ >
171
+ {children}
172
+ </div>
173
+ )}
114
174
  </div>
175
+ ) : (
176
+ isTableTag ? (
177
+ <table
178
+ {...ariaProps}
179
+ {...dataProps}
180
+ {...htmlProps}
181
+ className={classNames}
182
+ id={id}
183
+ style={dynamicInlineProps}
184
+ >
185
+ {children}
186
+ </table>
187
+ ) : (
188
+ <div
189
+ {...ariaProps}
190
+ {...dataProps}
191
+ {...htmlProps}
192
+ className={classNames}
193
+ id={id}
194
+ style={dynamicInlineProps}
195
+ >
196
+ {children}
197
+ </div>
198
+ )
115
199
  )}
116
200
  </>
117
201
  )
@@ -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 %>
@@ -0,0 +1,87 @@
1
+ import React from 'react'
2
+ import Table from '../_table'
3
+
4
+ const TableStickyLeftColumns = () => {
5
+ return (
6
+ <Table
7
+ responsive="scroll"
8
+ size="md"
9
+ stickyLeftcolumn={["1", "2", "3"]}
10
+ >
11
+ <thead>
12
+ <tr>
13
+ <th id="1">{'Column 1'}</th>
14
+ <th id="2">{'Column 2'}</th>
15
+ <th id="3">{'Column 3'}</th>
16
+ <th>{'Column 4'}</th>
17
+ <th>{'Column 5'}</th>
18
+ <th>{'Column 6'}</th>
19
+ <th>{'Column 7'}</th>
20
+ <th>{'Column 8'}</th>
21
+ <th>{'Column 9'}</th>
22
+ <th>{'Column 10'}</th>
23
+ <th>{'Column 11'}</th>
24
+ <th>{'Column 12'}</th>
25
+ <th>{'Column 13'}</th>
26
+ <th>{'Column 14'}</th>
27
+ <th>{'Column 15'}</th>
28
+ </tr>
29
+ </thead>
30
+ <tbody>
31
+ <tr>
32
+ <td id="1">{'Value 1'}</td>
33
+ <td id="2">{'Value 2'}</td>
34
+ <td id="3">{'Value 3'}</td>
35
+ <td>{'Value 4'}</td>
36
+ <td>{'Value 5'}</td>
37
+ <td>{'Value 6'}</td>
38
+ <td>{'Value 7'}</td>
39
+ <td>{'Value 8'}</td>
40
+ <td>{'Value 9'}</td>
41
+ <td>{'Value 10'}</td>
42
+ <td>{'Value 11'}</td>
43
+ <td>{'Value 12'}</td>
44
+ <td>{'Value 13'}</td>
45
+ <td>{'Value 14'}</td>
46
+ <td>{'Value 15'}</td>
47
+ </tr>
48
+ <tr>
49
+ <td id="1">{'Value 1'}</td>
50
+ <td id="2">{'Value 2'}</td>
51
+ <td id="3">{'Value 3'}</td>
52
+ <td>{'Value 4'}</td>
53
+ <td>{'Value 5'}</td>
54
+ <td>{'Value 6'}</td>
55
+ <td>{'Value 7'}</td>
56
+ <td>{'Value 8'}</td>
57
+ <td>{'Value 9'}</td>
58
+ <td>{'Value 10'}</td>
59
+ <td>{'Value 11'}</td>
60
+ <td>{'Value 12'}</td>
61
+ <td>{'Value 13'}</td>
62
+ <td>{'Value 14'}</td>
63
+ <td>{'Value 15'}</td>
64
+ </tr>
65
+ <tr>
66
+ <td id="1">{'Value 1'}</td>
67
+ <td id="2">{'Value 2'}</td>
68
+ <td id="3">{'Value 3'}</td>
69
+ <td>{'Value 4'}</td>
70
+ <td>{'Value 5'}</td>
71
+ <td>{'Value 6'}</td>
72
+ <td>{'Value 7'}</td>
73
+ <td>{'Value 8'}</td>
74
+ <td>{'Value 9'}</td>
75
+ <td>{'Value 10'}</td>
76
+ <td>{'Value 11'}</td>
77
+ <td>{'Value 12'}</td>
78
+ <td>{'Value 13'}</td>
79
+ <td>{'Value 14'}</td>
80
+ <td>{'Value 15'}</td>
81
+ </tr>
82
+ </tbody>
83
+ </Table>
84
+ )
85
+ }
86
+
87
+ export default TableStickyLeftColumns
@@ -0,0 +1,2 @@
1
+ The `stickyLeftColumn` prop expects an array of the column ids you want to be sticky. Make sure to add the corresponding id to the `<th>` and `<td>`.
2
+ If you are using the sub-component variant, then you will pass the id to `<Table.Header>` and `<Table.Cell>`
@@ -25,3 +25,4 @@ export { default as TableDiv } from './_table_div.jsx'
25
25
  export { default as TableWithSubcomponents } from './_table_with_subcomponents.jsx'
26
26
  export { default as TableWithSubcomponentsAsDivs } from './_table_with_subcomponents_as_divs.jsx'
27
27
  export { default as TableOuterPadding } from './_table_outer_padding.jsx'
28
+ export { default as TableStickyLeftColumns } from './_table_sticky_left_columns.jsx'
@@ -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
+ }
@@ -20,3 +20,5 @@
20
20
  @import "table_header";
21
21
  @import "striped";
22
22
  @import "outer_padding";
23
+ @import "sticky_columns";
24
+ @import "scroll";
@@ -0,0 +1,4 @@
1
+ .table-responsive-scroll {
2
+ display: block;
3
+ overflow-x: auto;
4
+ }
@@ -0,0 +1,18 @@
1
+ @import "../../tokens/colors";
2
+
3
+ [class^="pb_table"] {
4
+ .sticky {
5
+ position: sticky !important;
6
+ left: 0;
7
+ z-index: 1;
8
+ background-color: white;
9
+ }
10
+
11
+ .with-border {
12
+ border-right: 1px solid $border_light !important;
13
+ }
14
+
15
+ .sticky-shadow {
16
+ box-shadow: 4px 0 10px rgba(60, 106, 172, 0.16) !important;
17
+ }
18
+ }
@@ -18,4 +18,4 @@
18
18
  <%= content.presence %>
19
19
  <% end %>
20
20
  <% end %>
21
- <% end %>
21
+ <% end %>