playbook_ui 14.10.0.pre.alpha.PBNTR775formmatingmaskdefaultvalue5137 → 14.10.0.pre.alpha.PLAY1750pbcontenttagkitbutton5308

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +1 -0
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +32 -19
  4. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +3 -1
  5. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +35 -3
  6. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +32 -18
  7. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +1 -1
  8. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +8 -1
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb +1 -3
  10. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_subrow_headers.html.erb +1 -1
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_subrow_headers.md +1 -1
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers.html.erb +43 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers.jsx +60 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers.md +1 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers_multiple.html.erb +58 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers_multiple.jsx +74 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers_multiple.md +1 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +5 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/index.js +185 -92
  21. data/app/pb_kits/playbook/pb_advanced_table/table_body.html.erb +1 -1
  22. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +55 -8
  23. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +17 -14
  24. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +78 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +4 -3
  26. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +13 -2
  27. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.html.erb +2 -6
  28. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.rb +6 -4
  29. data/app/pb_kits/playbook/pb_button/button.html.erb +2 -3
  30. data/app/pb_kits/playbook/pb_card/_card.scss +21 -3
  31. data/app/pb_kits/playbook/pb_card/docs/_card_header.html.erb +18 -0
  32. data/app/pb_kits/playbook/pb_card/docs/_card_header.jsx +40 -0
  33. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +1 -6
  34. data/app/pb_kits/playbook/pb_circle_icon_button/_circle_icon_button.tsx +3 -0
  35. data/app/pb_kits/playbook/pb_circle_icon_button/circle_icon_button.html.erb +1 -1
  36. data/app/pb_kits/playbook/pb_circle_icon_button/circle_icon_button.rb +1 -0
  37. data/app/pb_kits/playbook/pb_circle_icon_button/docs/_circle_icon_button_link.html.erb +8 -0
  38. data/app/pb_kits/playbook/pb_circle_icon_button/docs/_circle_icon_button_link.jsx +9 -0
  39. data/app/pb_kits/playbook/pb_circle_icon_button/docs/_circle_icon_button_link.md +1 -0
  40. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +1 -6
  41. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +7 -12
  42. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.html.erb +9 -14
  43. data/app/pb_kits/playbook/pb_dropdown/dropdown_option.html.erb +6 -11
  44. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +8 -14
  45. data/app/pb_kits/playbook/pb_file_upload/_file_upload.tsx +24 -15
  46. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_accept.jsx +3 -1
  47. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_custom_description.jsx +4 -1
  48. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_max_size.jsx +1 -1
  49. data/app/pb_kits/playbook/pb_icon_circle/_icon_circle.scss +1 -13
  50. data/app/pb_kits/playbook/pb_section_separator/_section_separator.scss +64 -1
  51. data/app/pb_kits/playbook/pb_section_separator/_section_separator.tsx +3 -1
  52. data/app/pb_kits/playbook/pb_section_separator/docs/_section_separator_color.html.erb +10 -0
  53. data/app/pb_kits/playbook/pb_section_separator/docs/_section_separator_color.jsx +42 -0
  54. data/app/pb_kits/playbook/pb_section_separator/docs/_section_separator_color.md +3 -0
  55. data/app/pb_kits/playbook/pb_section_separator/docs/example.yml +2 -0
  56. data/app/pb_kits/playbook/pb_section_separator/docs/index.js +1 -0
  57. data/app/pb_kits/playbook/pb_section_separator/section_separator.rb +4 -1
  58. data/app/pb_kits/playbook/pb_skeleton_loading/_skeleton_loading.scss +2 -2
  59. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_description.md +3 -0
  60. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_border_radius.html.erb +9 -0
  61. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_border_radius_rails.md +1 -0
  62. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_color.html.erb +7 -0
  63. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_default.html.erb +1 -1
  64. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_filter.html.erb +119 -0
  65. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_filter.jsx +10 -2
  66. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_height_width.html.erb +15 -0
  67. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_height_width.jsx +6 -2
  68. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_height_width_rails.md +3 -0
  69. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_layout.html.erb +3 -0
  70. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_user.html.erb +63 -0
  71. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_user.jsx +11 -3
  72. data/app/pb_kits/playbook/pb_skeleton_loading/docs/example.yml +7 -2
  73. data/app/pb_kits/playbook/pb_skeleton_loading/skeleton_loading.html.erb +8 -12
  74. data/app/pb_kits/playbook/pb_skeleton_loading/skeleton_loading.rb +48 -1
  75. data/app/pb_kits/playbook/pb_table/_table.tsx +74 -18
  76. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_columns.jsx +88 -0
  77. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_columns_react.md +3 -0
  78. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns.jsx +1 -1
  79. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns_rails.md +2 -0
  80. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns_react.md +4 -1
  81. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns.jsx +87 -0
  82. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns_react.md +5 -0
  83. data/app/pb_kits/playbook/pb_table/docs/example.yml +2 -0
  84. data/app/pb_kits/playbook/pb_table/docs/index.js +2 -0
  85. data/app/pb_kits/playbook/pb_table/index.ts +17 -17
  86. data/app/pb_kits/playbook/pb_table/styles/_scroll.scss +38 -2
  87. data/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss +17 -3
  88. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_mask.jsx +18 -0
  89. data/app/pb_kits/playbook/pb_text_input/inputMask.ts +22 -1
  90. data/app/pb_kits/playbook/pb_text_input/text_input.test.js +80 -0
  91. data/app/pb_kits/playbook/pb_timeline/_timeline.tsx +5 -5
  92. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_gap.html.erb +4 -5
  93. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_gap.jsx +4 -4
  94. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_gap.md +1 -1
  95. data/app/pb_kits/playbook/pb_timeline/timeline.rb +6 -6
  96. data/app/pb_kits/playbook/utilities/_gap.scss +29 -0
  97. data/app/pb_kits/playbook/utilities/globalPropNames.mjs +1 -0
  98. data/app/pb_kits/playbook/utilities/globalProps.ts +18 -9
  99. data/dist/chunks/_typeahead-C2iCBqxQ.js +36 -0
  100. data/dist/chunks/_weekday_stacked-CWnbnW7m.js +45 -0
  101. data/dist/chunks/{lib-sMFo2JZy.js → lib-B7sgJtGS.js} +1 -1
  102. data/dist/chunks/{pb_form_validation-CgvjWbOK.js → pb_form_validation-C5Cc0-1v.js} +1 -1
  103. data/dist/chunks/vendor.js +1 -1
  104. data/dist/menu.yml +1 -1
  105. data/dist/playbook-doc.js +1 -1
  106. data/dist/playbook-rails-react-bindings.js +1 -1
  107. data/dist/playbook-rails.js +1 -1
  108. data/dist/playbook.css +1 -1
  109. data/lib/playbook/classnames.rb +1 -0
  110. data/lib/playbook/spacing.rb +21 -0
  111. data/lib/playbook/version.rb +1 -1
  112. metadata +32 -8
  113. data/dist/chunks/_typeahead-CoIYBETL.js +0 -22
  114. data/dist/chunks/_weekday_stacked-Qj3GFYzA.js +0 -45
  115. /data/app/pb_kits/playbook/pb_skeleton_loading/docs/{_skeleton_loading_border_radius.md → _skeleton_loading_border_radius_react.md} +0 -0
  116. /data/app/pb_kits/playbook/pb_skeleton_loading/docs/{_skeleton_loading_height_width.md → _skeleton_loading_height_width_react.md} +0 -0
@@ -1,138 +1,231 @@
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
- }
41
-
42
- const height = getHeight()
43
- elem.classList.add('is-visible')
44
- elem.style.height = height
45
- elem.style.overflow = "hidden"
46
-
47
- window.setTimeout(() => {
48
- elem.style.height = ''
49
- elem.style.overflow = "visible"
50
- }, 250)
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
+ }
68
+ // Split the dataContent to get all ancestor IDs, check against ExpandedRows
69
+ const ancestorIds = dataContent.split("-").slice(0, -1);
70
+
71
+ const prefixedAncestorIds = ancestorIds.map(
72
+ (id) => `${childRow.id}_${id}`
73
+ );
74
+ const allAncestorsExpanded = prefixedAncestorIds.every((id) =>
75
+ PbAdvancedTable.expandedRows.has(id)
76
+ );
77
+
78
+ const checkIfParentIsExpanded = () => {
79
+ if (dataContent.endsWith("sr")) {
80
+ const parentRowId = childRow.dataset.rowParent;
81
+ const isParentVisible =
82
+ childRow.previousElementSibling.classList.contains("is-visible");
83
+ if (parentRowId) {
84
+ const isInSet = PbAdvancedTable.expandedRows.has(parentRowId);
85
+ if (isInSet && isParentVisible) {
86
+ return true;
87
+ }
88
+ }
89
+ }
90
+ return false;
91
+ };
92
+
93
+ if (allAncestorsExpanded || checkIfParentIsExpanded()) {
94
+ childRow.style.display = "table-row";
95
+ childRow.classList.add("is-visible");
96
+ } else {
97
+ childRow.style.display = "none";
98
+ childRow.classList.remove("is-visible");
99
+ }
100
+ });
101
+ });
51
102
  }
52
103
 
53
- hideElement(elem) {
54
- elem.style.height = elem.scrollHeight + 'px'
104
+ hideElement(elements) {
105
+ elements.forEach((elem) => {
106
+ elem.style.display = "none";
107
+ elem.classList.remove("is-visible");
55
108
 
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)
109
+ // Remove the row ID from expandedRows when this row is hidden
110
+ if (PbAdvancedTable.expandedRows.has(elem.id)) {
111
+ PbAdvancedTable.expandedRows.delete(elem.id);
112
+ }
62
113
 
63
- window.setTimeout(() => {
64
- elem.classList.remove('is-visible')
65
- elem.style.overflow = ""
66
- }, 200)
114
+ const childrenArray = elem.dataset.advancedTableContent.split("-");
115
+ const currentDepth = parseInt(elem.dataset.rowDepth);
116
+ if (childrenArray.length > currentDepth) {
117
+ // Find the child rows corresponding to this parent row
118
+ const childRows = this.element
119
+ .closest("table")
120
+ .querySelectorAll(
121
+ `[data-advanced-table-content^="${elem.dataset.advancedTableContent}-"]`
122
+ );
123
+
124
+ childRows.forEach((childRow) => {
125
+ childRow.style.display = "none";
126
+ childRow.classList.remove("is-visible");
127
+ });
128
+ }
129
+ });
67
130
  }
68
131
 
69
- toggleElement(elem) {
70
- if (elem.classList.contains('is-visible')) {
71
- this.hideElement(elem)
72
- this.displayDownArrow()
73
- return
74
- }
132
+ toggleElement(elements) {
133
+ if (!elements.length) return;
75
134
 
76
- this.showElement(elem)
77
- this.displayUpArrow()
135
+ const isVisible = elements[0].classList.contains("is-visible");
136
+ if (isVisible) {
137
+ this.hideElement(elements);
138
+ this.displayDownArrow();
139
+ } else {
140
+ this.showElement(elements);
141
+ this.displayUpArrow();
142
+ }
78
143
  }
79
144
 
80
145
  displayDownArrow() {
81
- this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = 'inline-block'
82
- this.element.querySelector(UP_ARROW_SELECTOR).style.display = 'none'
146
+ this.element.querySelector(DOWN_ARROW_SELECTOR).style.display =
147
+ "inline-block";
148
+ this.element.querySelector(UP_ARROW_SELECTOR).style.display = "none";
83
149
  }
84
150
 
85
151
  displayUpArrow() {
86
- this.element.querySelector(UP_ARROW_SELECTOR).style.display = 'inline-block'
87
- this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = 'none'
152
+ this.element.querySelector(UP_ARROW_SELECTOR).style.display =
153
+ "inline-block";
154
+ this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = "none";
88
155
  }
89
156
 
90
157
  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()
158
+ const table = element.closest(".pb_table");
159
+ const firstLevelButtons = table.querySelectorAll(
160
+ ".pb_advanced_table_body > .pb_table_tr[data-row-depth='0'] [data-advanced-table]"
161
+ );
162
+
163
+ const allExpanded = Array.from(firstLevelButtons).every(
164
+ (button) =>
165
+ button.querySelector(UP_ARROW_SELECTOR).style.display === "inline-block"
166
+ );
167
+
168
+ if (allExpanded) {
169
+ firstLevelButtons.forEach((button) => {
170
+ button.click();
171
+ PbAdvancedTable.expandedRows.delete(button.id);
172
+ });
103
173
  } else {
104
- firstLevelButtons.forEach(button => {
105
- if (!this.expandedRows.has(button.id)) {
106
- button.click()
174
+ firstLevelButtons.forEach((button) => {
175
+ if (!PbAdvancedTable.expandedRows.has(button.id)) {
176
+ button.click();
177
+ PbAdvancedTable.expandedRows.add(button.id);
178
+ }
179
+ });
180
+
181
+ PbAdvancedTable.expandedRows.forEach((rowId) => {
182
+ const nestedButton = table.querySelector(
183
+ `[data-advanced-table][id="${rowId}"]`
184
+ );
185
+ if (nestedButton && !firstLevelButtons.contains(nestedButton)) {
186
+ nestedButton.click();
107
187
  }
108
- })
188
+ });
109
189
  }
110
190
  }
191
+
111
192
  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
- })
193
+ const table = element.closest(".pb_table");
194
+ const parentRow = element.closest("tr");
195
+ if (!parentRow) {
196
+ return;
197
+ }
198
+ const rowParentId = parentRow.dataset.rowParent;
199
+ // Select all buttons that for subrows at that depth and with same rowParent
200
+ const subRowButtons = table.querySelectorAll(
201
+ `.pb_advanced_table_body > .pb_table_tr[data-row-depth='${rowDepth}'].pb_table_tr[data-row-parent='${rowParentId}'] [data-advanced-table]`
202
+ );
203
+
204
+ const allExpanded = Array.from(subRowButtons).every(
205
+ (button) =>
206
+ button.querySelector(UP_ARROW_SELECTOR).style.display === "inline-block"
207
+ );
208
+
209
+ if (allExpanded) {
210
+ subRowButtons.forEach((button) => {
211
+ button.click();
212
+ PbAdvancedTable.expandedRows.delete(button.id);
213
+ });
123
214
  } else {
124
- subrowButtons.forEach(button => {
125
- if (!this.expandedRows.has(button.id)) {
126
- button.click()
215
+ subRowButtons.forEach((button) => {
216
+ if (!PbAdvancedTable.expandedRows.has(button.id)) {
217
+ button.click();
218
+ PbAdvancedTable.expandedRows.add(button.id);
127
219
  }
128
- })
220
+ });
129
221
  }
130
222
  }
131
223
  }
132
224
 
133
225
  window.expandAllRows = (element) => {
134
- PbAdvancedTable.handleToggleAllHeaders(element)
135
- }
226
+ PbAdvancedTable.handleToggleAllHeaders(element);
227
+ };
228
+
136
229
  window.expandAllSubRows = (element, rowDepth) => {
137
- PbAdvancedTable.handleToggleAllSubRows(element, rowDepth)
138
- }
230
+ PbAdvancedTable.handleToggleAllSubRows(element, rowDepth);
231
+ };
@@ -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,19 +17,56 @@ 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, additional_classes: "", table_data_attributes: {})
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
- 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"
42
+ subrow_ancestor_ids = ancestor_ids + ["#{row.object_id}sr"]
43
+ subrow_data_attributes = {
44
+ advanced_table_content: subrow_ancestor_ids.join("-"),
45
+ row_depth: current_depth,
46
+ row_parent: "#{id}_#{ancestor_ids.last}",
47
+ }
48
+ # Subrow header if applicable
49
+ output << pb_rails("advanced_table/table_subrow_header", props: { row: row, column_definitions: leaf_columns, depth: current_depth, subrow_header: subrow_headers[current_depth - 1], collapsible_trail: collapsible_trail, classname: "toggle-content", subrow_data_attributes: subrow_data_attributes }) if is_first_child_of_subrow && enable_toggle_expansion == "all"
50
+
51
+ current_data_attributes = current_depth.zero? ? { row_depth: 0 } : table_data_attributes
25
52
 
26
- output << pb_rails("advanced_table/table_row", props: { id: id, row: row, column_definitions: column_definitions, depth: current_depth, collapsible_trail: collapsible_trail })
53
+ # Additional class and data attributes needed for toggle logic
54
+ output << pb_rails("advanced_table/table_row", props: { id: id, row: row, column_definitions: leaf_columns, depth: current_depth, collapsible_trail: collapsible_trail, classname: additional_classes, table_data_attributes: current_data_attributes })
27
55
 
28
56
  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
57
+ row[:children].each do |child_row|
58
+ is_first_child = row[:children].first == child_row
59
+ immediate_parent_id = row.object_id
60
+ data_content = new_ancestor_ids.join("-") + "-#{child_row.object_id}"
61
+
62
+ child_data_attributes = {
63
+ top_parent: "#{id}_#{top_parent_id}",
64
+ row_depth: current_depth + 1,
65
+ row_parent: "#{id}_#{immediate_parent_id}",
66
+ advanced_table_content: data_content,
67
+ }
68
+
69
+ output << render_row_and_children(child_row, column_definitions, current_depth + 1, is_first_child, new_ancestor_ids, top_parent_id, additional_classes: "toggle-content", table_data_attributes: child_data_attributes)
33
70
  end
34
71
  end
35
72
 
@@ -37,7 +74,17 @@ module Playbook
37
74
  end
38
75
 
39
76
  def classname
40
- generate_classname("pb_advanced_table_body", "pb_table_tbody", separator: " ")
77
+ generate_classname("pb_advanced_table_body", separator: " ")
78
+ end
79
+
80
+ private
81
+
82
+ def has_grouped_headers?
83
+ column_definitions.any? { |col| col.key?(:columns) }
84
+ end
85
+
86
+ def last_in_group?(columns, current_col)
87
+ columns.last[:accessor] == current_col[:accessor]
41
88
  end
42
89
  end
43
90
  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 %>
@@ -16,6 +16,84 @@ module Playbook
16
16
  def th_classname
17
17
  generate_classname("table-header-cells", separator: " ")
18
18
  end
19
+
20
+ def header_rows
21
+ wrapped_columns = wrap_leaf_columns(column_definitions)
22
+
23
+ rows = []
24
+ max_depth = compute_max_depth(wrapped_columns)
25
+ max_depth.times { rows << [] }
26
+ process_columns(wrapped_columns, rows, 0, max_depth)
27
+ rows
28
+ end
29
+
30
+ private
31
+
32
+ def compute_max_depth(columns)
33
+ columns.map do |col|
34
+ col[:columns] ? 1 + compute_max_depth(col[:columns]) : 1
35
+ end.max || 1
36
+ end
37
+
38
+ def process_columns(columns, rows, current_depth, max_depth)
39
+ total_columns = columns.size
40
+ columns.each_with_index do |col, index|
41
+ is_last = index == total_columns - 1
42
+ if col[:columns]
43
+ colspan = compute_leaf_columns(col[:columns])
44
+ rows[current_depth] << {
45
+ label: col[:label],
46
+ colspan: colspan,
47
+ is_last_in_group: is_last && current_depth.positive?,
48
+ }
49
+
50
+ process_columns(col[:columns], rows, current_depth + 1, max_depth)
51
+ else
52
+ colspan = 1
53
+ rows[current_depth] << {
54
+ label: col[:label],
55
+ colspan: colspan,
56
+ accessor: col[:accessor],
57
+ sort_menu: col[:sort_menu],
58
+ is_last_in_group: is_last && current_depth.positive?,
59
+ }
60
+ end
61
+ end
62
+ end
63
+
64
+ def compute_leaf_columns(columns)
65
+ columns.reduce(0) do |sum, col|
66
+ col[:columns] ? sum + compute_leaf_columns(col[:columns]) : sum + 1
67
+ end
68
+ end
69
+
70
+ def wrap_leaf_columns(column_definitions)
71
+ max_depth = compute_max_depth(column_definitions)
72
+
73
+ column_definitions.map do |col|
74
+ if col.key?(:columns)
75
+ {
76
+ label: col[:label],
77
+ columns: wrap_leaf_columns(col[:columns]),
78
+ }
79
+ else
80
+ # For leaf columns, wrap with empty labels up to max depth to get proper structure
81
+ wrap_leaf_column(col, max_depth)
82
+ end
83
+ end
84
+ end
85
+
86
+ def wrap_leaf_column(col, max_depth)
87
+ wrapped = {
88
+ accessor: col[:accessor],
89
+ label: col[:label] || "",
90
+ sort_menu: col[:sort_menu] || nil,
91
+ }
92
+ (max_depth - 1).times do
93
+ wrapped = { label: "", columns: [wrapped] }
94
+ end
95
+ wrapped
96
+ end
19
97
  end
20
98
  end
21
99
  end
@@ -1,6 +1,7 @@
1
- <%= pb_content_tag do %>
1
+ <%= pb_content_tag(:tr) do %>
2
2
  <% object.column_definitions.each_with_index do |column, index| %>
3
- <%= pb_rails("table/table_cell", props: { tag:"div", classname:object.td_classname}) do %>
3
+ <% next unless column[:accessor].present? %>
4
+ <%= pb_rails("table/table_cell", props: { classname:object.td_classname(column)}) do %>
4
5
  <%= pb_rails("flex", props:{ align: "center", justify: index.zero? ? "start" : "end" }) do %>
5
6
  <% if collapsible_trail && index.zero? %>
6
7
  <% (1..depth).each do |i| %>
@@ -13,7 +14,7 @@
13
14
  <div style="padding-left: <%= depth * 1.25 %>em">
14
15
  <%= pb_rails("flex", props:{align: "center", column_gap: "xs"}) do %>
15
16
  <% if index.zero? && object.row[:children].present? %>
16
- <button id="<%= object.row.object_id.to_s + object.id %>" class="gray-icon expand-toggle-icon" data-advanced-table="true" >
17
+ <button id="<%= "#{object.id}_#{object.row.object_id}" %>" class="gray-icon expand-toggle-icon" data-advanced-table="true" >
17
18
  <%= pb_rails("icon", props: { id: "advanced-table_open_icon", icon: "circle-play", cursor: "pointer" }) %>
18
19
  <%= pb_rails("icon", props: { id: "advanced-table_close_icon", display: "none", icon: "circle-play", cursor: "pointer", rotation: 90 }) %>
19
20
  </button>
@@ -11,13 +11,21 @@ module Playbook
11
11
  prop :depth
12
12
  prop :collapsible_trail, type: Playbook::Props::Boolean,
13
13
  default: true
14
+ prop :table_data_attributes, type: Playbook::Props::HashProp,
15
+ default: {}
16
+
17
+ def data
18
+ Hash(prop(:data)).merge(table_data_attributes)
19
+ end
14
20
 
15
21
  def classname
16
22
  generate_classname("pb_table_tr", "bg-white", subrow_depth_classname, separator: " ")
17
23
  end
18
24
 
19
- def td_classname
20
- generate_classname("id-cell", "chrome-styles", separator: " ")
25
+ def td_classname(column)
26
+ classes = %w[id-cell chrome-styles]
27
+ classes << "last-cell" if column[:is_last_in_group]
28
+ classes.join(" ")
21
29
  end
22
30
 
23
31
  def depth_accessors
@@ -29,6 +37,8 @@ module Playbook
29
37
  private
30
38
 
31
39
  def custom_renderer_value(column, index)
40
+ return nil unless column[:accessor].present?
41
+
32
42
  if index.zero?
33
43
  if depth.zero?
34
44
  row[column[:accessor].to_sym]
@@ -37,6 +47,7 @@ module Playbook
37
47
  key = item.to_sym
38
48
  return row[key] if depth - 1 == accessor_index
39
49
  end
50
+ nil
40
51
  end
41
52
  else
42
53
  row[column[:accessor].to_sym]
@@ -1,10 +1,6 @@
1
- <%= content_tag(:div,
2
- aria: object.aria,
3
- class: object.classname,
4
- data: object.data,
5
- id: object.id) do %>
1
+ <%= pb_content_tag(:tr) do %>
6
2
  <% object.column_definitions.each_with_index do |column, index| %>
7
- <%= pb_rails("table/table_cell", props: { tag: "div", classname: object.td_classname}) do %>
3
+ <%= pb_rails("table/table_cell", props: { classname: "id-cell chrome-styles"}) do %>
8
4
  <%= pb_rails("flex", props:{ align: "center", justify: "start" }) do %>
9
5
  <% if collapsible_trail && index.zero? %>
10
6
  <% (1..depth).each do |i| %>
@@ -14,13 +14,15 @@ module Playbook
14
14
  default: ""
15
15
  prop :collapsible_trail, type: Playbook::Props::Boolean,
16
16
  default: true
17
+ prop :subrow_data_attributes, type: Playbook::Props::HashProp,
18
+ default: {}
17
19
 
18
- def classname
19
- generate_classname("pb_table_tr", "bg-white", subrow_depth_classname, separator: " ")
20
+ def data
21
+ Hash(prop(:data)).merge(subrow_data_attributes)
20
22
  end
21
23
 
22
- def td_classname
23
- generate_classname("id-cell", "chrome-styles", separator: " ")
24
+ def classname
25
+ generate_classname("pb_table_tr", "bg-silver", "pb_subrow_header", subrow_depth_classname, separator: " ")
24
26
  end
25
27
 
26
28
  private
@@ -1,6 +1,5 @@
1
- <%= content_tag(object.tag,
2
- object.tag == "button" ? object.options : object.link_options,
3
- **combined_html_options) do %>
1
+ <%= pb_content_tag(object.tag,
2
+ object.tag == "button" ? object.options : object.link_options) do %>
4
3
  <% if object.variant === "reaction" %>
5
4
  <% if icon && object.valid_emoji(object.icon) %>
6
5
  <%= pb_rails("flex", props:{ align: "center" }) do %>