playbook_ui 14.10.0.pre.alpha.play16825206 → 14.10.0.pre.alpha.play16825244

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +11 -16
  3. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +1 -1
  4. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +8 -1
  5. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb +1 -3
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers.html.erb +43 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers_multiple.html.erb +58 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +4 -1
  9. data/app/pb_kits/playbook/pb_advanced_table/index.js +143 -95
  10. data/app/pb_kits/playbook/pb_advanced_table/table_body.html.erb +1 -1
  11. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +50 -8
  12. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +17 -14
  13. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +78 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +4 -3
  15. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +7 -2
  16. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.html.erb +2 -6
  17. data/app/pb_kits/playbook/pb_card/_card.scss +21 -3
  18. data/app/pb_kits/playbook/pb_card/docs/_card_header.html.erb +18 -0
  19. data/app/pb_kits/playbook/pb_card/docs/_card_header.jsx +40 -0
  20. data/app/pb_kits/playbook/pb_timeline/_timeline.tsx +5 -5
  21. data/app/pb_kits/playbook/pb_timeline/timeline.rb +6 -6
  22. data/dist/chunks/{_weekday_stacked-CEpLoHbM.js → _weekday_stacked-CNIlTH0K.js} +1 -1
  23. data/dist/chunks/vendor.js +1 -1
  24. data/dist/playbook-doc.js +1 -1
  25. data/dist/playbook-rails.js +1 -1
  26. data/dist/playbook.css +1 -1
  27. data/lib/playbook/version.rb +1 -1
  28. metadata +5 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c3686695d192a5f6435b3e5b6e8fd120a4b5910c068d87cd5308eb0af9e38a0
4
- data.tar.gz: da63348971a44ce424f553d0b5220bc10276d9110b9d7f26f59d3a8e0d446a78
3
+ metadata.gz: 0dfffe1c453fa61d9befe70785310c0af3d7ae73b4e11df5c60327a383669dea
4
+ data.tar.gz: 4860df612192c0483c35c129aacfb38e8dedafd7b789d0b4c1c567ba04e70250
5
5
  SHA512:
6
- metadata.gz: 3a48fa614326e140e32a7a1352a160de4946f2ec72a992558519613ac2e6032fbbf015109fae16cba5f16121494c9d69bd709bc646f2a8df448c4d5364f255d1
7
- data.tar.gz: 19a0afe7eef42092273a30082159872df0cd9e51304b2e5bee2df47d8f16c6d66c3fae0df0862256502ecd4e860f6f984659e282ef39623976a06942aa004ba4
6
+ metadata.gz: e8d307c69d04191dfd48f551e406c318499f7838c19c3c6046caa2036c7b66316ea32d8cb5000080b3dd32ddf1dc546314d3e62af1e1169b9dfe33d6368b1b1f
7
+ data.tar.gz: 70caf6d01823765ae863db4cb6ffe1b4941f8cadd58cc0edebf286520bdb8bf334157c88729bd8d9e83adba8ebfcd7bcf561dbfdd548dc88f533fc9a63b5f909
@@ -36,35 +36,29 @@
36
36
  .last-header-cell {
37
37
  border-right: 1px solid $border_light !important;
38
38
  }
39
-
40
39
  th {
41
40
  border-radius: 0px !important;
42
41
  border-width: 0 0 1px 0 !important;
43
42
  }
44
43
  th:first-child {
45
44
  border-left-width: 1px !important;
46
- @media only screen and (max-width: $screen-xl-min) {
47
- border-left-width: 0 !important;
48
- }
49
- }
50
- th:last-child {
51
- border-right-width: 1px !important;
52
- @media only screen and (max-width: $screen-xl-min) {
53
- border-right-width: 0 !important;
54
- }
55
45
  }
56
46
  }
57
47
  th[colspan]:not([colspan="1"]) {
58
- border-right: 1px solid $border_light;
48
+ border-right: 1px solid $border_light !important;
59
49
  }
60
-
61
-
62
50
  }
63
51
 
64
52
  .pb_advanced_table_body {
65
53
  .last-cell {
66
54
  border-right: 1px solid $border_light !important;
67
55
  }
56
+ tr td:first-child {
57
+ padding-left: 8px !important;
58
+ }
59
+ tr .pb_table_td:last-child {
60
+ padding-right: 8px !important;
61
+ }
68
62
  }
69
63
 
70
64
 
@@ -134,7 +128,7 @@
134
128
  }
135
129
 
136
130
  .toggle-content {
137
- display: none;
131
+ display: none !important;
138
132
  height: 0;
139
133
  padding-bottom: 0 !important;
140
134
  padding-top: 0 !important;
@@ -143,7 +137,7 @@
143
137
  }
144
138
 
145
139
  .toggle-content.is-visible {
146
- display: contents;
140
+ display: table-row !important;
147
141
  height: auto;
148
142
  }
149
143
 
@@ -166,7 +160,7 @@
166
160
  width: 100%;
167
161
  [class^=pb_table].table-sm.table-card thead tr th:first-child,
168
162
  [class^=pb_table].table-sm:not(.no-hover).table-card tbody tr td:first-child {
169
- border-left-width: 0px;
163
+ border-left-width: 0px !important;
170
164
  }
171
165
  [class^=pb_table].table-sm.table-card thead tr th:last-child,
172
166
  [class^=pb_table].table-sm:not(.no-hover).table-card tbody tr td:last-child {
@@ -192,6 +186,7 @@
192
186
  .bg-white td:first-child {
193
187
  background-color: $white;
194
188
  }
189
+
195
190
  }
196
191
  }
197
192
  @media only screen and (min-width: $screen-xl-min) {
@@ -1,5 +1,5 @@
1
1
  <%= pb_content_tag do %>
2
- <%= pb_rails("table", props: { size: "sm", tag:"div", data_table: true, number_spacing:"tabular", responsive:"none", dark: dark }) do %>
2
+ <%= pb_rails("table", props: { size: "sm", data_table: true, number_spacing:"tabular", responsive:"none", dark: dark }) do %>
3
3
  <% if content.present? %>
4
4
  <% content.presence %>
5
5
  <% else %>
@@ -10,9 +10,16 @@ module Playbook
10
10
  prop :enable_toggle_expansion, type: Playbook::Props::Enum,
11
11
  values: %w[all header none],
12
12
  default: "header"
13
+ prop :responsive, type: Playbook::Props::Enum,
14
+ values: %w[none scroll],
15
+ default: "none"
13
16
 
14
17
  def classname
15
- generate_classname("pb_advanced_table")
18
+ generate_classname("pb_advanced_table", responsive_classname, separator: " ")
19
+ end
20
+
21
+ def responsive_classname
22
+ responsive == "scroll" ? "advanced-table-responsive-scroll" : "advanced-table-responsive-none"
16
23
  end
17
24
  end
18
25
  end
@@ -49,11 +49,9 @@
49
49
  label: "Graduated Students",
50
50
  }
51
51
  ]
52
-
53
- subrow_headers = ["Quarter", "Month", "Day"]
54
52
  %>
55
53
 
56
54
  <%= pb_rails("advanced_table", props: { table_data: @table_data, column_definitions: column_definitions }) do %>
57
55
  <%= pb_rails("advanced_table/table_header", props: { column_definitions: column_definitions }) %>
58
- <%= pb_rails("advanced_table/table_body", props: { id: "beta_sort", table_data: @table_data, column_definitions: column_definitions, subrow_headers: subrow_headers, enable_toggle_expansion: "all" }) %>
56
+ <%= pb_rails("advanced_table/table_body", props: { id: "beta_sort", table_data: @table_data, column_definitions: column_definitions, enable_toggle_expansion: "all" }) %>
59
57
  <% end %>
@@ -0,0 +1,43 @@
1
+ <% column_definitions = [
2
+ {
3
+ accessor: "year",
4
+ label: "Year",
5
+ cellAccessors: ["quarter", "month", "day"],
6
+ },
7
+ {
8
+ label: "Enrollment Data",
9
+ columns: [
10
+ {
11
+ accessor: "newEnrollments",
12
+ label: "New Enrollments",
13
+ },
14
+ {
15
+ accessor: "scheduledMeetings",
16
+ label: "Scheduled Meetings",
17
+ },
18
+ ],
19
+ },
20
+ {
21
+ label: "Performance Data",
22
+ columns: [
23
+ {
24
+ accessor: "attendanceRate",
25
+ label: "Attendance Rate",
26
+ },
27
+ {
28
+ accessor: "completedClasses",
29
+ label: "Completed Classes",
30
+ },
31
+ {
32
+ accessor: "classCompletionRate",
33
+ label: "Class Completion Rate",
34
+ },
35
+ {
36
+ accessor: "graduatedStudents",
37
+ label: "Graduated Students",
38
+ },
39
+ ],
40
+ },
41
+ ] %>
42
+
43
+ <%= pb_rails("advanced_table", props: { id: "beta_table_with_headers", table_data: @table_data, column_definitions: column_definitions }) %>
@@ -0,0 +1,58 @@
1
+ <% column_definitions = [
2
+ {
3
+ accessor: "year",
4
+ label: "Year",
5
+ cellAccessors: ["quarter", "month", "day"],
6
+ },
7
+ {
8
+ label: "Enrollment Data",
9
+ columns: [
10
+ {
11
+ label: "Enrollment Stats",
12
+ columns: [
13
+ {
14
+ accessor: "newEnrollments",
15
+ label: "New Enrollments",
16
+ },
17
+ {
18
+ accessor: "scheduledMeetings",
19
+ label: "Scheduled Meetings",
20
+ },
21
+ ],
22
+ },
23
+ ],
24
+ },
25
+ {
26
+ label: "Performance Data",
27
+ columns: [
28
+ {
29
+ label: "Completion Metrics",
30
+ columns: [
31
+ {
32
+ accessor: "completedClasses",
33
+ label: "Completed Classes",
34
+ },
35
+ {
36
+ accessor: "classCompletionRate",
37
+ label: "Class Completion Rate",
38
+ },
39
+ ],
40
+ },
41
+ {
42
+ label: "Attendance",
43
+ columns: [
44
+ {
45
+ accessor: "attendanceRate",
46
+ label: "Attendance Rate",
47
+ },
48
+ {
49
+ accessor: "scheduledMeetings",
50
+ label: "Scheduled Meetings",
51
+ },
52
+ ],
53
+ },
54
+ ],
55
+ },
56
+ ] %>
57
+
58
+ <%= pb_rails("advanced_table", props: { id: "beta_table_with_muilti_headers", table_data: @table_data, column_definitions: column_definitions }) %>
@@ -1,10 +1,13 @@
1
1
  examples:
2
2
  rails:
3
3
  - advanced_table_beta: Default (Required Props)
4
- - advanced_table_beta_subrow_headers: SubRow Headers
4
+ # - advanced_table_beta_subrow_headers: SubRow Headers
5
5
  - advanced_table_collapsible_trail_rails: Collapsible Trail
6
6
  - advanced_table_beta_sort: Enable Sorting
7
7
  - advanced_table_custom_cell_rails: Custom Components for Cells
8
+ - advanced_table_column_headers: Multi-Header Columns
9
+ - advanced_table_column_headers_multiple: Multi-Header Columns (Multiple Levels)
10
+
8
11
 
9
12
  react:
10
13
  - advanced_table_default: Default (Required Props)
@@ -1,138 +1,186 @@
1
- import PbEnhancedElement from '../pb_enhanced_element'
1
+ import PbEnhancedElement from "../pb_enhanced_element";
2
2
 
3
- const ADVANCED_TABLE_SELECTOR = '[data-advanced-table]'
4
- const CONTENT_SELECTOR = '[data-advanced-table-content="id"]'
5
- const DOWN_ARROW_SELECTOR = '#advanced-table_open_icon'
6
- const UP_ARROW_SELECTOR = '#advanced-table_close_icon'
3
+ const ADVANCED_TABLE_SELECTOR = "[data-advanced-table]";
4
+ const DOWN_ARROW_SELECTOR = "#advanced-table_open_icon";
5
+ const UP_ARROW_SELECTOR = "#advanced-table_close_icon";
7
6
 
8
7
  export default class PbAdvancedTable extends PbEnhancedElement {
9
8
  static get selector() {
10
- return ADVANCED_TABLE_SELECTOR
9
+ return ADVANCED_TABLE_SELECTOR;
11
10
  }
12
11
 
13
12
  get target() {
14
- return document.querySelector(CONTENT_SELECTOR.replace("id", this.element.id))
13
+ const table = this.element.closest("table");
14
+ return table.querySelectorAll(`[data-row-parent="${this.element.id}"]`);
15
15
  }
16
-
17
- static expandedRows = new Set()
18
- static isCollapsing = false
16
+
17
+ static expandedRows = new Set();
18
+ static isCollapsing = false;
19
19
 
20
20
  connect() {
21
- this.element.addEventListener('click', () => {
21
+ this.element.addEventListener("click", () => {
22
22
  if (!PbAdvancedTable.isCollapsing) {
23
- const isExpanded = this.element.querySelector(UP_ARROW_SELECTOR).style.display === 'inline-block'
23
+ const isExpanded =
24
+ this.element.querySelector(UP_ARROW_SELECTOR).style.display ===
25
+ "inline-block";
24
26
  if (!isExpanded) {
25
- PbAdvancedTable.expandedRows.add(this.element.id)
27
+ PbAdvancedTable.expandedRows.add(this.element.id);
26
28
  } else {
27
- PbAdvancedTable.expandedRows.delete(this.element.id)
29
+ PbAdvancedTable.expandedRows.delete(this.element.id);
28
30
  }
31
+ this.toggleElement(this.target);
29
32
  }
30
- this.toggleElement(this.target)
31
- })
33
+ });
34
+
35
+ const nestedButtons = this.element
36
+ .closest("table")
37
+ .querySelectorAll("[data-advanced-table]");
38
+ nestedButtons.forEach((button) => {
39
+ button.addEventListener("click", () => {
40
+ const isExpanded =
41
+ button.querySelector(UP_ARROW_SELECTOR).style.display ===
42
+ "inline-block";
43
+ if (isExpanded) {
44
+ PbAdvancedTable.expandedRows.add(button.id);
45
+ } else {
46
+ PbAdvancedTable.expandedRows.delete(button.id);
47
+ }
48
+ });
49
+ });
32
50
  }
33
51
 
34
- showElement(elem) {
35
- const getHeight = () => {
36
- elem.style.display = 'block'
37
- const height = elem.scrollHeight + 'px'
38
- elem.style.display = ''
39
- return height
40
- }
52
+ showElement(elements) {
53
+ elements.forEach((elem) => {
54
+ elem.style.display = "table-row";
55
+ elem.classList.add("is-visible");
56
+ const childRowsAll = this.element
57
+ .closest("table")
58
+ .querySelectorAll(
59
+ `[data-advanced-table-content^="${elem.dataset.advancedTableContent}-"]`
60
+ );
61
+
62
+ childRowsAll.forEach((childRow) => {
63
+ const dataContent = childRow.dataset.advancedTableContent;
64
+
65
+ if (!dataContent) {
66
+ return;
67
+ }
41
68
 
42
- const height = getHeight()
43
- elem.classList.add('is-visible')
44
- elem.style.height = height
45
- elem.style.overflow = "hidden"
69
+ // Split the dataContent to get all ancestor IDs, check against simpleExpandedRows
70
+ const ancestorIds = dataContent.split("-").slice(0, -1);
46
71
 
47
- window.setTimeout(() => {
48
- elem.style.height = ''
49
- elem.style.overflow = "visible"
50
- }, 250)
72
+ const prefixedAncestorIds = ancestorIds.map(
73
+ (id) => `${childRow.id}_${id}`
74
+ );
75
+ const allAncestorsExpanded = prefixedAncestorIds.every((id) =>
76
+ PbAdvancedTable.expandedRows.has(id)
77
+ );
78
+
79
+ if (allAncestorsExpanded) {
80
+ childRow.style.display = "table-row";
81
+ childRow.classList.add("is-visible");
82
+ } else {
83
+ childRow.style.display = "none";
84
+ childRow.classList.remove("is-visible");
85
+ }
86
+ });
87
+ });
51
88
  }
52
89
 
53
- hideElement(elem) {
54
- elem.style.height = elem.scrollHeight + 'px'
90
+ hideElement(elements) {
91
+ elements.forEach((elem) => {
92
+ elem.style.display = "none";
93
+ elem.classList.remove("is-visible");
55
94
 
56
- window.setTimeout(() => {
57
- elem.style.height = '0'
58
- elem.style.paddingTop = '0'
59
- elem.style.paddingBottom = '0'
60
- elem.style.overflow = "hidden"
61
- }, 1)
95
+ // Remove the row ID from expandedRows when this row is hidden
96
+ if (PbAdvancedTable.expandedRows.has(elem.id)) {
97
+ PbAdvancedTable.expandedRows.delete(elem.id);
98
+ }
62
99
 
63
- window.setTimeout(() => {
64
- elem.classList.remove('is-visible')
65
- elem.style.overflow = ""
66
- }, 200)
100
+ const childrenArray = elem.dataset.advancedTableContent.split("-");
101
+ const currentDepth = parseInt(elem.dataset.rowDepth);
102
+ if (childrenArray.length > currentDepth) {
103
+ // Find the child rows corresponding to this parent row
104
+ const childRows = this.element
105
+ .closest("table")
106
+ .querySelectorAll(
107
+ `[data-advanced-table-content^="${elem.dataset.advancedTableContent}-"]`
108
+ );
109
+
110
+ childRows.forEach((childRow) => {
111
+ childRow.style.display = "none";
112
+ childRow.classList.remove("is-visible");
113
+ });
114
+ }
115
+ });
67
116
  }
68
117
 
69
- toggleElement(elem) {
70
- if (elem.classList.contains('is-visible')) {
71
- this.hideElement(elem)
72
- this.displayDownArrow()
73
- return
74
- }
118
+ toggleElement(elements) {
119
+ if (!elements.length) return;
75
120
 
76
- this.showElement(elem)
77
- this.displayUpArrow()
121
+ const isVisible = elements[0].classList.contains("is-visible");
122
+ if (isVisible) {
123
+ this.hideElement(elements);
124
+ this.displayDownArrow();
125
+ } else {
126
+ this.showElement(elements);
127
+ this.displayUpArrow();
128
+ }
78
129
  }
79
130
 
80
131
  displayDownArrow() {
81
- this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = 'inline-block'
82
- this.element.querySelector(UP_ARROW_SELECTOR).style.display = 'none'
132
+ this.element.querySelector(DOWN_ARROW_SELECTOR).style.display =
133
+ "inline-block";
134
+ this.element.querySelector(UP_ARROW_SELECTOR).style.display = "none";
83
135
  }
84
136
 
85
137
  displayUpArrow() {
86
- this.element.querySelector(UP_ARROW_SELECTOR).style.display = 'inline-block'
87
- this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = 'none'
138
+ this.element.querySelector(UP_ARROW_SELECTOR).style.display =
139
+ "inline-block";
140
+ this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = "none";
88
141
  }
89
142
 
90
143
  static handleToggleAllHeaders(element) {
91
- const table = element.closest('.pb_table')
92
- const firstLevelButtons = table.querySelectorAll('.pb_advanced_table_body > .pb_table_tr [data-advanced-table]')
93
-
94
- const expandedRows = Array.from(firstLevelButtons).filter(button =>
95
- button.querySelector(UP_ARROW_SELECTOR).style.display === 'inline-block'
96
- )
97
-
98
- if (expandedRows.length === firstLevelButtons.length) {
99
- expandedRows.forEach(button => {
100
- button.click()
101
- })
102
- this.expandedRows.clear()
144
+ const table = element.closest(".pb_table");
145
+ const firstLevelButtons = table.querySelectorAll(
146
+ ".pb_advanced_table_body > .pb_table_tr [data-advanced-table]"
147
+ );
148
+
149
+ const allExpanded = Array.from(firstLevelButtons).every(
150
+ (button) =>
151
+ button.querySelector(UP_ARROW_SELECTOR).style.display === "inline-block"
152
+ );
153
+
154
+ if (allExpanded) {
155
+ firstLevelButtons.forEach((button) => {
156
+ button.click();
157
+ PbAdvancedTable.expandedRows.delete(button.id);
158
+ });
103
159
  } else {
104
- firstLevelButtons.forEach(button => {
105
- if (!this.expandedRows.has(button.id)) {
106
- button.click()
160
+ firstLevelButtons.forEach((button) => {
161
+ if (!PbAdvancedTable.expandedRows.has(button.id)) {
162
+ button.click();
163
+ PbAdvancedTable.expandedRows.add(button.id);
107
164
  }
108
- })
109
- }
110
- }
111
- static handleToggleAllSubRows(element, rowDepth) {
112
- const parentElement = element.closest(".toggle-content")
113
- const subrowButtons = parentElement.querySelectorAll('.depth-sub-row-' + rowDepth + ' [data-advanced-table]')
114
-
115
- const expandedSubRows = Array.from(subrowButtons).filter(button =>
116
- button.querySelector(UP_ARROW_SELECTOR).style.display === 'inline-block'
117
- )
118
-
119
- if (expandedSubRows.length === subrowButtons.length) {
120
- expandedSubRows.forEach(button => {
121
- button.click()
122
- })
123
- } else {
124
- subrowButtons.forEach(button => {
125
- if (!this.expandedRows.has(button.id)) {
126
- button.click()
165
+ });
166
+
167
+ PbAdvancedTable.expandedRows.forEach((rowId) => {
168
+ const nestedButton = table.querySelector(
169
+ `[data-advanced-table][id="${rowId}"]`
170
+ );
171
+ if (nestedButton && !firstLevelButtons.contains(nestedButton)) {
172
+ nestedButton.click();
127
173
  }
128
- })
174
+ });
129
175
  }
130
176
  }
177
+
178
+ // static handleToggleAllSubRows(element, rowDepth) {}
131
179
  }
132
180
 
133
181
  window.expandAllRows = (element) => {
134
- PbAdvancedTable.handleToggleAllHeaders(element)
135
- }
136
- window.expandAllSubRows = (element, rowDepth) => {
137
- PbAdvancedTable.handleToggleAllSubRows(element, rowDepth)
138
- }
182
+ PbAdvancedTable.handleToggleAllHeaders(element);
183
+ };
184
+ // window.expandAllSubRows = (element, rowDepth) => {
185
+ // PbAdvancedTable.handleToggleAllSubRows(element, rowDepth);
186
+ // };
@@ -1,4 +1,4 @@
1
- <%= pb_content_tag do %>
1
+ <%= pb_content_tag(:tbody) do %>
2
2
  <% object.table_data.each do |row| %>
3
3
  <%= render_row_and_children(row, object.column_definitions, 0, false) %>
4
4
  <% end %>
@@ -17,27 +17,69 @@ module Playbook
17
17
  prop :collapsible_trail, type: Playbook::Props::Boolean,
18
18
  default: true
19
19
 
20
- def render_row_and_children(row, column_definitions, current_depth, first_parent_child)
20
+ def flatten_columns(columns)
21
+ columns.flat_map do |col|
22
+ if col[:columns]
23
+ flatten_columns(col[:columns])
24
+ elsif col[:accessor].present?
25
+ if has_grouped_headers?
26
+ col.merge(is_last_in_group: last_in_group?(columns, col))
27
+ else
28
+ col
29
+ end
30
+ end
31
+ end.compact
32
+ end
33
+
34
+ def render_row_and_children(row, column_definitions, current_depth, first_parent_child, ancestor_ids = [], top_parent_id = nil)
35
+ top_parent_id ||= row.object_id
36
+ new_ancestor_ids = ancestor_ids + [row.object_id]
37
+ leaf_columns = flatten_columns(column_definitions)
38
+
21
39
  output = ActiveSupport::SafeBuffer.new
22
40
  is_first_child_of_subrow = current_depth.positive? && first_parent_child && subrow_headers[current_depth - 1].present?
23
41
 
24
42
  output << pb_rails("advanced_table/table_subrow_header", props: { row: row, column_definitions: column_definitions, depth: current_depth, subrow_header: subrow_headers[current_depth - 1], collapsible_trail: collapsible_trail }) if is_first_child_of_subrow && enable_toggle_expansion == "all"
25
43
 
26
- output << pb_rails("advanced_table/table_row", props: { id: id, row: row, column_definitions: column_definitions, depth: current_depth, collapsible_trail: collapsible_trail })
44
+ # Pass only leaf_columns to table_row to account for multiple nested columns
45
+ output << pb_rails("advanced_table/table_row", props: {
46
+ id: id,
47
+ row: row,
48
+ column_definitions: leaf_columns,
49
+ depth: current_depth,
50
+ collapsible_trail: collapsible_trail,
51
+ })
27
52
 
28
53
  if row[:children].present?
29
- output << content_tag(:div, class: "toggle-content", data: { advanced_table_content: row.object_id.to_s + id }) do
30
- row[:children].map do |child_row|
31
- render_row_and_children(child_row, column_definitions, current_depth + 1, row.children.first == child_row)
32
- end.join.html_safe
33
- end
54
+ output << row[:children].map do |child_row|
55
+ is_first_child = row[:children].first == child_row
56
+
57
+ child_output = render_row_and_children(child_row, column_definitions, current_depth + 1, is_first_child, new_ancestor_ids, top_parent_id)
58
+
59
+ immediate_parent_id = row.object_id
60
+ top_parent = top_parent_id
61
+ # Combine ancestor_ids to build the content id
62
+ data_content = new_ancestor_ids.join("-") + "-#{child_row.object_id}"
63
+
64
+ child_output.to_str.sub("<tr", %(<tr class="toggle-content" data-top-parent="#{id}_#{top_parent}" data-row-depth="#{current_depth}" data-row-parent="#{id}_#{immediate_parent_id}" data-advanced-table-content="#{data_content}"))
65
+ end.join.html_safe
34
66
  end
35
67
 
36
68
  output
37
69
  end
38
70
 
39
71
  def classname
40
- generate_classname("pb_advanced_table_body", "pb_table_tbody", separator: " ")
72
+ generate_classname("pb_advanced_table_body", separator: " ")
73
+ end
74
+
75
+ private
76
+
77
+ def has_grouped_headers?
78
+ column_definitions.any? { |col| col.key?(:columns) }
79
+ end
80
+
81
+ def last_in_group?(columns, current_col)
82
+ columns.last[:accessor] == current_col[:accessor]
41
83
  end
42
84
  end
43
85
  end
@@ -1,18 +1,21 @@
1
- <%= pb_content_tag do %>
2
- <%= pb_rails("table/table_row", props: { tag: "div" }) do %>
3
- <% object.column_definitions.each_with_index do |item, index| %>
4
- <%= pb_rails("table/table_header", props: { tag: "div", id: item[:accessor], classname: object.th_classname, sort_menu: item[:sort_menu] }) do %>
5
- <%= pb_rails("flex", props:{ align: "center", justify: index.zero? ? "start" : "end", text_align: "end" }) do %>
6
- <% if index.zero? && (object.enable_toggle_expansion == "header" || object.enable_toggle_expansion == "all") %>
7
- <button
8
- class="gray-icon toggle-all-icon"
9
- onclick="expandAllRows(this); event.preventDefault();">
10
- <%= pb_rails("icon", props: { icon: "arrows-from-line", cursor: "pointer", fixed_width: true, padding_right: "xs" }) %>
11
- </button>
12
- <% end %>
13
- <%= item[:label] %>
1
+ <%= pb_content_tag(:thead) do %>
2
+ <% object.header_rows.each_with_index do |header_row, row_index| %>
3
+ <%= pb_rails("table/table_row") do %>
4
+ <% header_row.each_with_index do |cell, cell_index| %>
5
+ <% header_id = cell[:accessor].present? ? cell[:accessor] : "header_#{row_index}_#{cell_index}" %>
6
+ <%= pb_rails("table/table_header", props: { id: header_id, colspan: cell[:colspan], classname: [object.th_classname, ('last-header-cell' if cell[:is_last_in_group] && cell_index != 0)].compact.join(' '), sort_menu: cell[:accessor] ? cell[:sort_menu] : nil }) do %>
7
+ <%= pb_rails("flex", props:{ align: "center", justify: cell_index.zero? ? "start" : row_index === header_rows.size - 1 ? "end" : "center", text_align: "end" }) do %>
8
+ <% if cell_index.zero? && (object.enable_toggle_expansion == "header" || object.enable_toggle_expansion == "all") && row_index === header_rows.size - 1 %>
9
+ <button
10
+ class="gray-icon toggle-all-icon"
11
+ onclick="expandAllRows(this); event.preventDefault();">
12
+ <%= pb_rails("icon", props: { icon: "arrows-from-line", cursor: "pointer", fixed_width: true, padding_right: "xs" }) %>
13
+ </button>
14
14
  <% end %>
15
+ <%= cell[:label] %>
15
16
  <% end %>
16
- <% end %>
17
17
  <% end %>
18
+ <% end %>
19
+ <% end %>
20
+ <% end %>
18
21
  <% end %>