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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 %>