playbook_ui 16.3.0 → 16.4.0.pre.alpha.PLAY2864circleiconbuttonloadingalignrails15138

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +17 -4
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +3 -1
  4. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +21 -9
  5. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +5 -2
  6. data/app/pb_kits/playbook/pb_advanced_table/Utilities/ExpansionControlHelpers.tsx +25 -1
  7. data/app/pb_kits/playbook/pb_advanced_table/Utilities/RowModelUtils.ts +100 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +46 -1
  9. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +9 -2
  10. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +2 -2
  11. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +2 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +109 -2
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_cascade_collapse.jsx +50 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_cascade_collapse.md +1 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows_rails.html.erb +57 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows_rails.md +7 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_parent_only.jsx +175 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_parent_only.md +5 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +3 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +3 -1
  21. data/app/pb_kits/playbook/pb_advanced_table/index.js +130 -29
  22. data/app/pb_kits/playbook/pb_advanced_table/table_body.html.erb +21 -4
  23. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +115 -9
  24. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +3 -1
  25. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +12 -1
  26. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.html.erb +4 -1
  27. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.rb +9 -1
  28. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +6 -1
  29. data/app/pb_kits/playbook/pb_circle_icon_button/_circle_icon_button.scss +5 -0
  30. data/app/pb_kits/playbook/pb_circle_icon_button/docs/_circle_icon_button_loading.html.erb +25 -0
  31. data/app/pb_kits/playbook/pb_circle_icon_button/docs/_circle_icon_button_loading.jsx +97 -38
  32. data/app/pb_kits/playbook/pb_collapsible/index.js +15 -26
  33. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +3 -1
  34. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.html.erb +1 -1
  35. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.jsx +6 -3
  36. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height.html.erb +3 -3
  37. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height.jsx +6 -3
  38. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height_placement.html.erb +3 -3
  39. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height_placement.jsx +6 -3
  40. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +3 -0
  41. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +1 -0
  42. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_closing_options_rails.html.erb +16 -0
  43. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_closing_options_rails.md +1 -0
  44. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_custom_event_type.html.erb +224 -0
  45. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_custom_event_type.md +7 -0
  46. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +2 -0
  47. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +8 -1
  48. data/app/pb_kits/playbook/pb_dropdown/index.js +255 -46
  49. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +19 -14
  50. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.scss +4 -0
  51. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.tsx +3 -0
  52. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin.html.erb +46 -0
  53. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin.jsx +42 -0
  54. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin_rails.md +1 -0
  55. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin_react.md +1 -0
  56. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/example.yml +2 -0
  57. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/index.js +2 -1
  58. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.rb +7 -1
  59. data/app/pb_kits/playbook/pb_icon/icon.rb +7 -1
  60. data/app/pb_kits/playbook/pb_list/_list_mixin.scss +4 -4
  61. data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +1 -1
  62. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +24 -15
  63. data/app/pb_kits/playbook/pb_popover/docs/_popover_placement.jsx +81 -0
  64. data/app/pb_kits/playbook/pb_popover/docs/_popover_placement_react.md +1 -0
  65. data/app/pb_kits/playbook/pb_popover/docs/_popover_position.html.erb +128 -0
  66. data/app/pb_kits/playbook/pb_popover/docs/_popover_position_rails.md +1 -0
  67. data/app/pb_kits/playbook/pb_popover/docs/example.yml +2 -0
  68. data/app/pb_kits/playbook/pb_popover/docs/index.js +2 -1
  69. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +35 -134
  70. data/app/pb_kits/playbook/pb_rich_text_editor/_tiptap_editor.tsx +51 -0
  71. data/app/pb_kits/playbook/pb_rich_text_editor/_trix_editor.tsx +206 -0
  72. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_default.jsx +56 -0
  73. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_default.md +1 -0
  74. data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +13 -21
  75. data/app/pb_kits/playbook/pb_rich_text_editor/docs/index.js +0 -10
  76. data/app/pb_kits/playbook/pb_rich_text_editor/inlineFocus.ts +5 -4
  77. data/app/pb_kits/playbook/pb_selectable_list/_selectable_list.scss +19 -1
  78. data/app/pb_kits/playbook/pb_table/_table.tsx +24 -21
  79. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props.jsx +152 -0
  80. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props.md +17 -0
  81. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props_rails.html.erb +121 -0
  82. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props_rails.md +17 -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 +1 -0
  85. data/app/pb_kits/playbook/pb_table/table.html.erb +12 -11
  86. data/app/pb_kits/playbook/pb_table/table.rb +4 -0
  87. data/app/pb_kits/playbook/pb_table/table.test.js +33 -0
  88. data/app/pb_kits/playbook/pb_textarea/_textarea.scss +4 -1
  89. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +105 -3
  90. data/app/pb_kits/playbook/utilities/domHelpers.ts +50 -0
  91. data/dist/chunks/{_pb_line_graph-CKBPxTmM.js → _pb_line_graph-D6s5rymw.js} +1 -1
  92. data/dist/chunks/_typeahead-Bh0RF1X-.js +1 -0
  93. data/dist/chunks/componentRegistry-DRSp5D_e.js +1 -0
  94. data/dist/chunks/{globalProps-DLCfJwiU.js → globalProps-Ds_6HBhX.js} +1 -1
  95. data/dist/chunks/lib-BaO72ugL.js +29 -0
  96. data/dist/chunks/vendor.js +5 -5
  97. data/dist/menu.yml +3 -2
  98. data/dist/playbook-rails-react-bindings.js +1 -1
  99. data/dist/playbook-rails.js +1 -1
  100. data/dist/playbook.css +1 -1
  101. data/lib/playbook/pb_forms_helper.rb +3 -0
  102. data/lib/playbook/version.rb +2 -2
  103. metadata +34 -31
  104. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_attributes.html.erb +0 -5
  105. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_attributes.jsx +0 -15
  106. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_default.html.erb +0 -1
  107. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_focus.html.erb +0 -3
  108. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_focus.jsx +0 -17
  109. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_inline.html.erb +0 -6
  110. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_inline.jsx +0 -16
  111. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_label.jsx +0 -28
  112. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_label.md +0 -1
  113. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_preview.html.erb +0 -35
  114. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_preview.jsx +0 -45
  115. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.html.erb +0 -10
  116. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.jsx +0 -22
  117. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.md +0 -3
  118. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_simple.html.erb +0 -1
  119. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_simple.jsx +0 -13
  120. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_sticky.html.erb +0 -1
  121. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_sticky.jsx +0 -15
  122. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_templates.html.erb +0 -115
  123. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_templates.jsx +0 -42
  124. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_toolbar_bottom.html.erb +0 -4
  125. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_toolbar_bottom.jsx +0 -14
  126. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.html.erb +0 -5
  127. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.rb +0 -63
  128. data/dist/chunks/_typeahead-B7bktFm6.js +0 -1
  129. data/dist/chunks/componentRegistry-DzmmLR2x.js +0 -1
  130. data/dist/chunks/lib-QT_7rPYf.js +0 -29
@@ -0,0 +1,7 @@
1
+ Use the `pinned_rows` prop to pin specific rows to the top of an Advanced Table. Pinned rows will remain at the top when scrolling through table data and will not change position if sorting is used.
2
+
3
+ **NOTE:**
4
+ - Sticky header required: Pinned rows must be used with `sticky: true` via `table_props` (works with both responsive and non-responsive tables)
5
+ - Row ids required: Each object within the `table_data` array must contain a unique `id` in order to attach an id to all Rows for this to function.
6
+ - `pinned_rows` takes a hash with a `top` key containing an array of row ids, as shown in the code snippet below.
7
+ - For expandable rows, use the parent id in `pinned_rows[:top]`; all its children will automatically be pinned with it. If a child id is passed without the parent being pinned, nothing will be pinned.
@@ -0,0 +1,175 @@
1
+ import React from "react"
2
+ import AdvancedTable from '../../pb_advanced_table/_advanced_table'
3
+ import MOCK_DATA from "./advanced_table_mock_data.json"
4
+
5
+ import Caption from "../../pb_caption/_caption"
6
+
7
+ const sharedColumnDefinitions = [
8
+ {
9
+ accessor: "year",
10
+ label: "Year",
11
+ cellAccessors: ["quarter", "month", "day"],
12
+ },
13
+ {
14
+ accessor: "newEnrollments",
15
+ label: "New Enrollments",
16
+ },
17
+ {
18
+ accessor: "scheduledMeetings",
19
+ label: "Scheduled Meetings",
20
+ },
21
+ {
22
+ accessor: "attendanceRate",
23
+ label: "Attendance Rate",
24
+ },
25
+ {
26
+ accessor: "completedClasses",
27
+ label: "Completed Classes",
28
+ },
29
+ {
30
+ accessor: "classCompletionRate",
31
+ label: "Class Completion Rate",
32
+ },
33
+ {
34
+ accessor: "graduatedStudents",
35
+ label: "Graduated Students",
36
+ },
37
+ ]
38
+
39
+ const sortByColumnDefinitions = [
40
+ {
41
+ accessor: "year",
42
+ label: "Year",
43
+ cellAccessors: ["quarter", "month", "day"],
44
+ },
45
+ {
46
+ accessor: "newEnrollments",
47
+ label: "New Enrollments",
48
+ enableSort: true,
49
+ },
50
+ {
51
+ accessor: "scheduledMeetings",
52
+ label: "Scheduled Meetings",
53
+ },
54
+ {
55
+ accessor: "attendanceRate",
56
+ label: "Attendance Rate",
57
+ enableSort: true,
58
+ },
59
+ {
60
+ accessor: "completedClasses",
61
+ label: "Completed Classes",
62
+ },
63
+ {
64
+ accessor: "classCompletionRate",
65
+ label: "Class Completion Rate",
66
+ },
67
+ {
68
+ accessor: "graduatedStudents",
69
+ label: "Graduated Students",
70
+ },
71
+ ]
72
+
73
+ const sortByColumnMultiDefinitions = [
74
+ {
75
+ accessor: "year",
76
+ label: "Year",
77
+ cellAccessors: ["quarter", "month", "day"],
78
+ },
79
+ {
80
+ label: "Enrollment Data",
81
+ columns: [
82
+ {
83
+ label: "Enrollment Stats",
84
+ columns: [
85
+ {
86
+ accessor: "newEnrollments",
87
+ label: "New Enrollments",
88
+ enableSort: true,
89
+ },
90
+ {
91
+ accessor: "scheduledMeetings",
92
+ label: "Scheduled Meetings",
93
+ },
94
+ ],
95
+ },
96
+ ],
97
+ },
98
+ {
99
+ label: "Performance Data",
100
+ columns: [
101
+ {
102
+ label: "Completion Metrics",
103
+ columns: [
104
+ {
105
+ accessor: "completedClasses",
106
+ label: "Completed Classes",
107
+ enableSort: true,
108
+ },
109
+ {
110
+ accessor: "classCompletionRate",
111
+ label: "Class Completion Rate",
112
+ },
113
+ ],
114
+ },
115
+ {
116
+ label: "Attendance",
117
+ columns: [
118
+ {
119
+ accessor: "attendanceRate",
120
+ label: "Attendance Rate",
121
+ },
122
+ {
123
+ accessor: "scheduledMeetings",
124
+ label: "Scheduled Meetings",
125
+ },
126
+ ],
127
+ },
128
+ ],
129
+ },
130
+ ]
131
+
132
+ const AdvancedTableSortParentOnly = (props) => {
133
+ return (
134
+ <div>
135
+ <Caption text="Enable Sorting (first column) + sortParentOnly" />
136
+ <AdvancedTable
137
+ columnDefinitions={sharedColumnDefinitions}
138
+ sortParentOnly
139
+ tableData={MOCK_DATA}
140
+ {...props}
141
+ >
142
+ <AdvancedTable.Header enableSorting />
143
+ <AdvancedTable.Body />
144
+ </AdvancedTable>
145
+ <Caption marginTop="md"
146
+ text="Sort by column + sortParentOnly"
147
+ />
148
+ <AdvancedTable
149
+ columnDefinitions={sortByColumnDefinitions}
150
+ enableSortingRemoval
151
+ sortParentOnly
152
+ tableData={MOCK_DATA}
153
+ {...props}
154
+ >
155
+ <AdvancedTable.Header />
156
+ <AdvancedTable.Body />
157
+ </AdvancedTable>
158
+ <Caption marginTop="md"
159
+ text="Sort by column (multi-column) + sortParentOnly"
160
+ />
161
+ <AdvancedTable
162
+ columnDefinitions={sortByColumnMultiDefinitions}
163
+ enableSortingRemoval
164
+ sortParentOnly
165
+ tableData={MOCK_DATA}
166
+ {...props}
167
+ >
168
+ <AdvancedTable.Header enableSorting />
169
+ <AdvancedTable.Body />
170
+ </AdvancedTable>
171
+ </div>
172
+ )
173
+ }
174
+
175
+ export default AdvancedTableSortParentOnly
@@ -0,0 +1,5 @@
1
+ The `sortParentOnly` prop is a boolean set to `false` by default. When set to `true`, only parent (depth-0) rows are re-ordered when sorting; children and grandchildren stay grouped under their parent and keep their original order.
2
+
3
+ `sortParentOnly` works with every sorting mode: `enableSorting` on the header, per-column `enableSort: true`, and sortable leaf columns in the multi-header variant. Sort indicators behave as usual.
4
+
5
+ When omitted or `false`, sorting applies to all levels.
@@ -7,6 +7,7 @@ examples:
7
7
  - advanced_table_table_props: Table Props
8
8
  - advanced_table_sticky_header_rails: Sticky Header
9
9
  - advanced_table_table_props_sticky_header: Sticky Header for Responsive Table
10
+ - advanced_table_pinned_rows_rails: Pinned Rows
10
11
  - advanced_table_beta_sort: Enable Sorting
11
12
  - advanced_table_responsive: Responsive Tables
12
13
  - advanced_table_custom_cell_rails: Custom Components for Cells
@@ -39,9 +40,11 @@ examples:
39
40
  - advanced_table_sort_per_column: Enable Sort By Column
40
41
  - advanced_table_sort_per_column_for_multi_column: Enable Sort By Column (Multi-Column)
41
42
  - advanced_table_custom_sort: Custom Sort
43
+ - advanced_table_sort_parent_only: Sort Parent Only
42
44
  - advanced_table_expanded_control: Expanded Control
43
45
  - advanced_table_expand_by_depth: Expand by Depth
44
46
  - advanced_table_subrow_headers: SubRow Headers
47
+ - advanced_table_cascade_collapse: Cascade Collapse
45
48
  - advanced_table_collapsible_trail: Collapsible Trail
46
49
  - advanced_table_table_options: Table Options
47
50
  - advanced_table_table_props: Table Props
@@ -48,4 +48,6 @@ export { default as AdvancedTablePaddingControl } from './_advanced_table_paddin
48
48
  export { default as AdvancedTablePaddingControlPerRow } from './_advanced_table_padding_control_per_row.jsx'
49
49
  export { default as AdvancedTableColumnStylingBackground } from './_advanced_table_column_styling_background.jsx'
50
50
  export { default as AdvancedTableColumnStylingBackgroundMulti } from './_advanced_table_column_styling_background_multi.jsx'
51
- export { default as AdvancedTableColumnStylingBackgroundCustom } from './_advanced_table_column_styling_background_custom.jsx'
51
+ export { default as AdvancedTableColumnStylingBackgroundCustom } from './_advanced_table_column_styling_background_custom.jsx'
52
+ export { default as AdvancedTableCascadeCollapse } from './_advanced_table_cascade_collapse.jsx'
53
+ export { default as AdvancedTableSortParentOnly } from './_advanced_table_sort_parent_only.jsx'
@@ -1,5 +1,6 @@
1
1
  import PbEnhancedElement from "../pb_enhanced_element";
2
2
  import { updateSelectionActionBar } from "./advanced_table_action_bar";
3
+ import { setArrowVisibility, toggleVisibility } from "../utilities/domHelpers";
3
4
 
4
5
  const ADVANCED_TABLE_SELECTOR = "[data-advanced-table]";
5
6
  const DOWN_ARROW_SELECTOR = "#advanced-table_open_icon";
@@ -20,10 +21,18 @@ export default class PbAdvancedTable extends PbEnhancedElement {
20
21
  this.childRowsMap = new Map();
21
22
  }
22
23
 
24
+ get table() {
25
+ return this.cachedTable || (this.cachedTable = this.element.closest("table"));
26
+ }
27
+
28
+ get mainTable() {
29
+ return this.cachedMainTable || (this.cachedMainTable = this.element.closest(".pb_advanced_table"));
30
+ }
31
+
23
32
  // Fetch and cache child rows for a given parent row ID
24
33
  childRowsFor(parentId) {
25
34
  if (!this.childRowsMap.has(parentId)) {
26
- const table = this.element.closest("table");
35
+ const table = this.table;
27
36
  const rows = Array.from(
28
37
  table.querySelectorAll(`tr[data-row-parent="${parentId}"]`)
29
38
  );
@@ -33,7 +42,8 @@ export default class PbAdvancedTable extends PbEnhancedElement {
33
42
  }
34
43
 
35
44
  updateTableSelectedRowsAttribute() {
36
- const mainTable = this.element.closest(".pb_advanced_table");
45
+ const mainTable = this.mainTable;
46
+ if (!mainTable) return;
37
47
  mainTable.dataset.selectedRows = JSON.stringify(
38
48
  Array.from(PbAdvancedTable.selectedRows)
39
49
  );
@@ -41,7 +51,8 @@ export default class PbAdvancedTable extends PbEnhancedElement {
41
51
 
42
52
  // Recalculate selected count based on all checked checkboxes
43
53
  recalculateSelectedCount() {
44
- const table = this.element.closest("table");
54
+ const table = this.table;
55
+ if (!table) return;
45
56
 
46
57
  // Get all checkboxes that could be part of the selection
47
58
  // This includes row checkboxes and any parent checkboxes that might be programmatically checked
@@ -95,7 +106,7 @@ export default class PbAdvancedTable extends PbEnhancedElement {
95
106
  });
96
107
 
97
108
  this.updateTableSelectedRowsAttribute();
98
- updateSelectionActionBar(table.closest(".pb_advanced_table"), PbAdvancedTable.selectedRows.size);
109
+ updateSelectionActionBar(this.mainTable, PbAdvancedTable.selectedRows.size);
99
110
 
100
111
  // Sync header select-all state
101
112
  if (selectAllCheckbox) {
@@ -139,7 +150,7 @@ export default class PbAdvancedTable extends PbEnhancedElement {
139
150
 
140
151
  this.updateTableSelectedRowsAttribute();
141
152
 
142
- const table = checkbox.closest("table");
153
+ const table = this.table;
143
154
  const selectAllCheckbox = table.querySelector("#select-all-rows");
144
155
 
145
156
  if (selectAllCheckbox) {
@@ -153,7 +164,7 @@ export default class PbAdvancedTable extends PbEnhancedElement {
153
164
  );
154
165
  selectAllInput.checked = allChecked;
155
166
  }
156
- updateSelectionActionBar(table.closest(".pb_advanced_table"), PbAdvancedTable.selectedRows.size);
167
+ updateSelectionActionBar(this.mainTable, PbAdvancedTable.selectedRows.size);
157
168
  }
158
169
 
159
170
  get target() {
@@ -161,10 +172,11 @@ export default class PbAdvancedTable extends PbEnhancedElement {
161
172
  }
162
173
 
163
174
  connect() {
164
- const table = this.element.closest("table");
175
+ const table = this.table;
176
+ if (!table) return;
165
177
 
166
178
  this.hideCloseIcon();
167
- const mainTable = this.element.closest(".pb_advanced_table");
179
+ const mainTable = this.mainTable;
168
180
 
169
181
  // This so it is hidden on first render
170
182
  if (mainTable) {
@@ -184,6 +196,17 @@ export default class PbAdvancedTable extends PbEnhancedElement {
184
196
  if (table.dataset.pbAdvancedTableInitialized) return;
185
197
  table.dataset.pbAdvancedTableInitialized = "true";
186
198
 
199
+ // Measure header height so pinned rows don't overlap when header wraps (e.g. mobile)
200
+ if (mainTable) {
201
+ PbAdvancedTable.updateStickyHeaderRowHeights(mainTable);
202
+ const resizeObserver = new ResizeObserver(() => {
203
+ PbAdvancedTable.updateStickyHeaderRowHeights(mainTable);
204
+ PbAdvancedTable.updatePinnedRowsStickyTops(mainTable);
205
+ });
206
+ resizeObserver.observe(table);
207
+ mainTable._advancedTableHeaderResizeObserver = resizeObserver;
208
+ }
209
+
187
210
  // Delegate checkbox changes
188
211
  table.addEventListener("change", (event) => {
189
212
  const checkbox = event.target.closest('input[type="checkbox"]');
@@ -271,9 +294,7 @@ export default class PbAdvancedTable extends PbEnhancedElement {
271
294
  }
272
295
 
273
296
  // Find direct child rows
274
- const childRows = Array.from(
275
- table.querySelectorAll(`[data-row-parent="${toggleBtn.id}"]`)
276
- );
297
+ const childRows = this.childRowsFor(toggleBtn.id);
277
298
  this.toggleElement(childRows);
278
299
 
279
300
  // Restore original element context
@@ -284,7 +305,8 @@ export default class PbAdvancedTable extends PbEnhancedElement {
284
305
  }
285
306
 
286
307
  addBorderRadiusOnLastVisibleRow() {
287
- const parentElement = this.element.closest(".pb_advanced_table");
308
+ const parentElement = this.mainTable;
309
+ if (!parentElement) return;
288
310
 
289
311
  const table = document.getElementById(parentElement.id);
290
312
 
@@ -304,9 +326,64 @@ export default class PbAdvancedTable extends PbEnhancedElement {
304
326
  lastVisibleRow.classList.add("last-visible-row");
305
327
  lastVisibleRow.classList.add("last-row-cell");
306
328
  }
329
+
330
+ PbAdvancedTable.updateStickyHeaderRowHeights(parentElement);
331
+ PbAdvancedTable.updatePinnedRowsStickyTops(table);
307
332
  }
308
333
  }
309
334
 
335
+ /**
336
+ * Measure thead height and set --advanced-table-header-height so pinned rows and
337
+ * multi-row sticky headers use the correct offset. Re-run when header wraps (e.g. mobile).
338
+ */
339
+ static updateStickyHeaderRowHeights(advancedTableWrapper) {
340
+ if (!advancedTableWrapper) return;
341
+ const table = advancedTableWrapper.querySelector("table.pb_table");
342
+ const thead = table?.querySelector("thead");
343
+ if (!thead) return;
344
+
345
+ const rows = Array.from(thead.querySelectorAll("tr"));
346
+ let totalHeight = 0;
347
+ rows.forEach((tr, index) => {
348
+ const h = tr.offsetHeight;
349
+ if (index === 0) {
350
+ advancedTableWrapper.style.setProperty(
351
+ "--advanced-table-header-row-0-height",
352
+ `${h}px`
353
+ );
354
+ } else if (index === 1) {
355
+ advancedTableWrapper.style.setProperty(
356
+ "--advanced-table-header-row-1-height",
357
+ `${h}px`
358
+ );
359
+ }
360
+ totalHeight += h;
361
+ });
362
+ advancedTableWrapper.style.setProperty(
363
+ "--advanced-table-header-height",
364
+ `${totalHeight}px`
365
+ );
366
+ }
367
+
368
+ /**
369
+ * Recompute sticky top for visible pinned rows so collapsed rows don't leave a gap.
370
+ * Call after expand/collapse and on load.
371
+ */
372
+ static updatePinnedRowsStickyTops(advancedTableWrapper) {
373
+ const pinnedTbody = advancedTableWrapper?.querySelector("tbody.pinned-rows-tbody");
374
+ if (!pinnedTbody) return;
375
+
376
+ const pinnedRows = Array.from(pinnedTbody.querySelectorAll("tr.pinned-row"));
377
+ const visibleRows = pinnedRows.filter(
378
+ (tr) => tr.style.display !== "none" && tr.offsetParent !== null
379
+ );
380
+
381
+ const headerOffset = "var(--advanced-table-header-height, 44px)";
382
+ visibleRows.forEach((tr, index) => {
383
+ tr.style.top = `calc(${headerOffset} + 2.5em * ${index})`;
384
+ });
385
+ }
386
+
310
387
  hideCloseIcon() {
311
388
  const closeIcon = this.element.querySelector(UP_ARROW_SELECTOR);
312
389
  closeIcon.style.display = "none";
@@ -316,11 +393,9 @@ export default class PbAdvancedTable extends PbEnhancedElement {
316
393
  elements.forEach((elem) => {
317
394
  elem.style.display = "table-row";
318
395
  elem.classList.add("is-visible");
319
- const childRowsAll = this.element
320
- .closest("table")
321
- .querySelectorAll(
322
- `[data-advanced-table-content^="${elem.dataset.advancedTableContent}-"]`
323
- );
396
+ const childRowsAll = this.table.querySelectorAll(
397
+ `[data-advanced-table-content^="${elem.dataset.advancedTableContent}-"]`
398
+ );
324
399
 
325
400
  childRowsAll.forEach((childRow) => {
326
401
  const dataContent = childRow.dataset.advancedTableContent;
@@ -382,8 +457,7 @@ export default class PbAdvancedTable extends PbEnhancedElement {
382
457
  const currentDepth = parseInt(elem.dataset.rowDepth);
383
458
  if (childrenArray.length > currentDepth) {
384
459
  // Find the child rows corresponding to this parent row
385
- const childRows = this.element
386
- .closest("table")
460
+ const childRows = this.table
387
461
  .querySelectorAll(
388
462
  `[data-advanced-table-content^="${elem.dataset.advancedTableContent}-"]`
389
463
  );
@@ -401,28 +475,39 @@ export default class PbAdvancedTable extends PbEnhancedElement {
401
475
 
402
476
  const isVisible = elements[0].classList.contains("is-visible");
403
477
 
404
- isVisible ? this.hideElement(elements) : this.showElement(elements);
405
- isVisible ? this.displayDownArrow() : this.displayUpArrow();
478
+ const isExpanded = toggleVisibility({
479
+ isVisible,
480
+ onHide: () => this.hideElement(elements),
481
+ onShow: () => this.showElement(elements),
482
+ });
483
+
484
+ isExpanded ? this.displayUpArrow() : this.displayDownArrow();
406
485
 
407
486
  const row = this.element.closest("tr");
408
487
  if (row) {
409
- row.classList.toggle("bg-silver", !isVisible);
410
- row.classList.toggle("pb-bg-row-white", isVisible);
488
+ row.classList.toggle("bg-silver", isExpanded);
489
+ row.classList.toggle("pb-bg-row-white", !isExpanded);
411
490
  }
412
491
 
413
492
  this.addBorderRadiusOnLastVisibleRow();
414
493
  }
415
494
 
416
495
  displayDownArrow() {
417
- this.element.querySelector(DOWN_ARROW_SELECTOR).style.display =
418
- "inline-block";
419
- this.element.querySelector(UP_ARROW_SELECTOR).style.display = "none";
496
+ setArrowVisibility({
497
+ rootElement: this.element,
498
+ downSelector: DOWN_ARROW_SELECTOR,
499
+ upSelector: UP_ARROW_SELECTOR,
500
+ showDownArrow: true,
501
+ });
420
502
  }
421
503
 
422
504
  displayUpArrow() {
423
- this.element.querySelector(UP_ARROW_SELECTOR).style.display =
424
- "inline-block";
425
- this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = "none";
505
+ setArrowVisibility({
506
+ rootElement: this.element,
507
+ downSelector: DOWN_ARROW_SELECTOR,
508
+ upSelector: UP_ARROW_SELECTOR,
509
+ showDownArrow: false,
510
+ });
426
511
  }
427
512
 
428
513
  static handleToggleAllHeaders(element) {
@@ -500,3 +585,19 @@ window.expandAllRows = (element) => {
500
585
  window.expandAllSubRows = (element, rowDepth) => {
501
586
  PbAdvancedTable.handleToggleAllSubRows(element, rowDepth);
502
587
  };
588
+
589
+ // Fix header height and pinned row sticky tops on load (header wrap + collapsed rows)
590
+ function updateAllAdvancedTableStickyHeights() {
591
+ document.querySelectorAll(".pb_advanced_table").forEach((wrapper) => {
592
+ PbAdvancedTable.updateStickyHeaderRowHeights(wrapper);
593
+ PbAdvancedTable.updatePinnedRowsStickyTops(wrapper);
594
+ });
595
+ }
596
+
597
+ if (typeof document !== "undefined") {
598
+ if (document.readyState === "loading") {
599
+ document.addEventListener("DOMContentLoaded", updateAllAdvancedTableStickyHeights);
600
+ } else {
601
+ updateAllAdvancedTableStickyHeights();
602
+ }
603
+ }
@@ -1,5 +1,22 @@
1
- <%= pb_content_tag(:tbody) do %>
2
- <% object.table_data.each do |row| %>
3
- <%= render_row_and_children(row, object.column_definitions, 0, false) %>
4
- <% end %>
1
+ <% table_data = object.table_data || [] %>
2
+ <% if object.has_pinned_rows? %>
3
+ <%= pb_content_tag(:tbody, class: "pinned-rows-tbody") do %>
4
+ <% next_index = 0 %>
5
+ <% object.pinned_root_rows.each do |root_info| %>
6
+ <% row_output, next_index = object.render_row_and_children(root_info[:row], object.column_definitions, root_info[:depth], root_info[:depth] > 0, root_info[:ancestor_ids] || [], root_info[:ancestor_ids]&.first, immediate_parent_row_id: object.row_id_for(root_info[:parent_row]), is_pinned_row: true, pinned_index: next_index, initial_table_data_attributes: root_info[:depth].to_i > 0 ? object.pinned_root_initial_data_attributes(root_info) : nil) %>
7
+ <%= row_output %>
8
+ <% end %>
9
+ <% end %>
10
+ <%= pb_content_tag(:tbody) do %>
11
+ <% table_data.each do |row| %>
12
+ <% result = object.render_row_and_children(row, object.column_definitions, 0, false, skip_pinned_ids: object.pinned_ids_set) %>
13
+ <%= result.is_a?(Array) ? result[0] : result %>
14
+ <% end %>
15
+ <% end %>
16
+ <% else %>
17
+ <%= pb_content_tag(:tbody) do %>
18
+ <% table_data.each do |row| %>
19
+ <%= object.render_row_and_children(row, object.column_definitions, 0, false) %>
20
+ <% end %>
21
+ <% end %>
5
22
  <% end %>