playbook_ui 14.23.0.pre.alpha.PLAY2205atborderbug9085 → 14.23.0.pre.alpha.PLAY2283multiheaderverticalbordersdoc9335

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +0 -1
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +7 -6
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/SortIconButton.tsx +24 -25
  5. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +11 -12
  6. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +7 -4
  7. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +1 -1
  8. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +25 -1
  9. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +4 -1
  10. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +1 -1
  11. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +1 -1
  12. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +34 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers_vertical_border.html.erb +43 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers_vertical_border.jsx +64 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header_rails.html.erb +1 -1
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_rails.html.erb +1 -1
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_per_column.jsx +55 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_per_column.md +6 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_per_column_for_multi_column.jsx +80 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_per_column_for_multi_column.md +1 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_with_custom_header_multi_header.jsx +107 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_with_custom_header_multi_header.md +1 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +5 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +4 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/flat_advanced_table.js +4 -11
  26. data/app/pb_kits/playbook/pb_advanced_table/index.js +108 -125
  27. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +5 -4
  28. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +10 -4
  29. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +2 -2
  30. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +22 -5
  31. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.rb +1 -1
  32. data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +12 -1
  33. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.html.erb +1 -1
  34. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate_rails.md +2 -1
  35. data/app/pb_kits/playbook/pb_checkbox/index.js +218 -26
  36. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +17 -1
  37. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +6 -0
  38. data/app/pb_kits/playbook/pb_dropdown/_dropdown_mixin.scss +36 -0
  39. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_active_style_options.jsx +90 -0
  40. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_active_style_options_react.md +4 -0
  41. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_radio_options.jsx +1 -0
  42. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_radio_options_react.md +1 -1
  43. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +3 -2
  44. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +2 -1
  45. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +24 -0
  46. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +11 -1
  47. data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +18 -9
  48. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +3 -1
  49. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_show_checked_children.html.erb +75 -0
  50. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_show_checked_children.jsx +94 -0
  51. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_show_checked_children.md +3 -0
  52. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +1 -1
  53. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb +3 -0
  54. data/app/pb_kits/playbook/pb_pagination/_pagination.tsx +4 -0
  55. data/app/pb_kits/playbook/pb_pagination/docs/_pagination_default_rails.md +3 -1
  56. data/app/pb_kits/playbook/pb_pagination/docs/_pagination_default_react.md +3 -1
  57. data/app/pb_kits/playbook/pb_select/select.rb +4 -2
  58. data/app/pb_kits/playbook/pb_table/docs/_table_with_selectable_rows.html.erb +1 -0
  59. data/dist/chunks/{_line_graph-BfCo79KE.js → _line_graph-D7DgMqnT.js} +1 -1
  60. data/dist/chunks/{_typeahead-Db4YQA5c.js → _typeahead-BzYZCpJO.js} +2 -2
  61. data/dist/chunks/_weekday_stacked-CCn-qLh_.js +37 -0
  62. data/dist/chunks/{lib-DnQyMxO1.js → lib-CY5ZPzic.js} +2 -2
  63. data/dist/chunks/{pb_form_validation-kl-4Jv4t.js → pb_form_validation-D3b0JKHH.js} +1 -1
  64. data/dist/chunks/vendor.js +1 -1
  65. data/dist/menu.yml +3 -10
  66. data/dist/playbook-doc.js +2 -2
  67. data/dist/playbook-rails-react-bindings.js +1 -1
  68. data/dist/playbook-rails.js +1 -1
  69. data/dist/playbook.css +1 -1
  70. data/lib/playbook/version.rb +1 -1
  71. metadata +21 -18
  72. data/app/pb_kits/playbook/pb_walkthrough/_walkthrough.scss +0 -0
  73. data/app/pb_kits/playbook/pb_walkthrough/_walkthrough.tsx +0 -202
  74. data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_continuous.jsx +0 -69
  75. data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_default.jsx +0 -71
  76. data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_multi_beacon.jsx +0 -110
  77. data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_no_beacon.jsx +0 -76
  78. data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_no_overlay.jsx +0 -76
  79. data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_styled.jsx +0 -76
  80. data/app/pb_kits/playbook/pb_walkthrough/docs/example.yml +0 -10
  81. data/app/pb_kits/playbook/pb_walkthrough/docs/index.js +0 -6
  82. data/app/pb_kits/playbook/pb_walkthrough/walkthrough.test.jsx +0 -34
  83. data/dist/chunks/_weekday_stacked-BNHSKTSw.js +0 -61
@@ -0,0 +1,80 @@
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
+ const AdvancedTableSortPerColumnForMultiColumn = (props) => {
6
+ const columnDefinitions = [
7
+ {
8
+ accessor: "year",
9
+ label: "Year",
10
+ cellAccessors: ["quarter", "month", "day"],
11
+ },
12
+ {
13
+ label: "Enrollment Data",
14
+ columns: [
15
+ {
16
+ label: "Enrollment Stats",
17
+ columns: [
18
+ {
19
+ accessor: "newEnrollments",
20
+ label: "New Enrollments",
21
+ enableSort: true,
22
+ },
23
+ {
24
+ accessor: "scheduledMeetings",
25
+ label: "Scheduled Meetings",
26
+ },
27
+ ],
28
+ },
29
+ ],
30
+ },
31
+ {
32
+ label: "Performance Data",
33
+ columns: [
34
+ {
35
+ label: "Completion Metrics",
36
+ columns: [
37
+ {
38
+ accessor: "completedClasses",
39
+ label: "Completed Classes",
40
+ enableSort: true,
41
+ },
42
+ {
43
+ accessor: "classCompletionRate",
44
+ label: "Class Completion Rate",
45
+ },
46
+ ],
47
+ },
48
+ {
49
+ label: "Attendance",
50
+ columns: [
51
+ {
52
+ accessor: "attendanceRate",
53
+ label: "Attendance Rate",
54
+ },
55
+ {
56
+ accessor: "scheduledMeetings",
57
+ label: "Scheduled Meetings",
58
+ },
59
+ ],
60
+ },
61
+ ],
62
+ },
63
+ ];
64
+
65
+ return (
66
+ <div>
67
+ <AdvancedTable
68
+ columnDefinitions={columnDefinitions}
69
+ enableSortingRemoval
70
+ tableData={MOCK_DATA}
71
+ {...props}
72
+ >
73
+ <AdvancedTable.Header enableSorting />
74
+ <AdvancedTable.Body />
75
+ </AdvancedTable>
76
+ </div>
77
+ )
78
+ }
79
+
80
+ export default AdvancedTableSortPerColumnForMultiColumn;
@@ -0,0 +1 @@
1
+ Sorting on columns can also be applied to columns when using the multi-header variant, however in this case sorting can only be set on leaf columns NOT on parent columns.
@@ -0,0 +1,107 @@
1
+ import React from "react"
2
+ import AdvancedTable from '../../pb_advanced_table/_advanced_table'
3
+ import Icon from "../../pb_icon/_icon"
4
+ import Flex from "../../pb_flex/_flex"
5
+ import Caption from "../../pb_caption/_caption"
6
+ import Tooltip from "../../pb_tooltip/_tooltip"
7
+ import MOCK_DATA from "./advanced_table_mock_data.json"
8
+
9
+ const AdvancedTableWithCustomHeaderMultiHeader = (props) => {
10
+
11
+ const columnDefinitions = [
12
+ {
13
+ accessor: "year",
14
+ label: "Year",
15
+ id: "year",
16
+ cellAccessors: ["quarter", "month", "day"],
17
+ },
18
+ {
19
+ label: "Enrollment Data",
20
+ id: "enrollmentData",
21
+ header: () => (
22
+ <Flex alignItems="center"
23
+ justifyContent="center"
24
+ >
25
+ <Caption marginRight="xs">Enrollments Data</Caption>
26
+ <Tooltip placement="top"
27
+ text="Whoa. I'm a Tooltip"
28
+ zIndex={10}
29
+ >
30
+ <Icon cursor="pointer"
31
+ icon="info"
32
+ size="xs"
33
+ />
34
+ </Tooltip>
35
+ </Flex>
36
+ ),
37
+ columns: [
38
+ {
39
+ label: "Enrollment Stats",
40
+ id: "enrollmentStats",
41
+ columns: [
42
+ {
43
+ accessor: "newEnrollments",
44
+ id: "newEnrollments",
45
+ label: "New Enrollments",
46
+ },
47
+ {
48
+ accessor: "scheduledMeetings",
49
+ id: "scheduledMeetings",
50
+ label: "Scheduled Meetings",
51
+ },
52
+ ],
53
+ },
54
+ ],
55
+ },
56
+ {
57
+ label: "Performance Data",
58
+ id: "performanceData",
59
+ columns: [
60
+ {
61
+ label: "Completion Metrics",
62
+ id: "completionMetrics",
63
+ columns: [
64
+ {
65
+ accessor: "completedClasses",
66
+ label: "Completed Classes",
67
+ id: "completedClasses",
68
+ },
69
+ {
70
+ accessor: "classCompletionRate",
71
+ label: "Class Completion Rate",
72
+ id: "classCompletionRate",
73
+ },
74
+ ],
75
+ },
76
+ {
77
+ label: "Attendance",
78
+ id: "attendance",
79
+ columns: [
80
+ {
81
+ accessor: "attendanceRate",
82
+ label: "Attendance Rate",
83
+ id: "attendanceRate",
84
+ },
85
+ {
86
+ accessor: "scheduledMeetings",
87
+ label: "Scheduled Meetings",
88
+ id: "scheduledMeetings",
89
+ },
90
+ ],
91
+ },
92
+ ],
93
+ },
94
+ ];
95
+
96
+ return (
97
+ <div>
98
+ <AdvancedTable
99
+ columnDefinitions={columnDefinitions}
100
+ tableData={MOCK_DATA}
101
+ {...props}
102
+ />
103
+ </div>
104
+ )
105
+ }
106
+
107
+ export default AdvancedTableWithCustomHeaderMultiHeader;
@@ -0,0 +1 @@
1
+ The optional `header` key/value pair within `columnDefinitions` can also be used with multi headers as seen here.
@@ -13,6 +13,7 @@ examples:
13
13
  - advanced_table_with_custom_header_rails: Custom Header Cell
14
14
  - advanced_table_column_headers: Multi-Header Columns
15
15
  - advanced_table_column_headers_multiple: Multi-Header Columns (Multiple Levels)
16
+ - advanced_table_column_headers_vertical_border: Multi-Header Columns with Vertical Borders
16
17
  - advanced_table_no_subrows: Table with No Subrows or Expansion
17
18
  - advanced_table_selectable_rows_rails: Selectable Rows
18
19
  - advanced_table_selectable_rows_no_subrows_rails: Selectable Rows (No Subrows)
@@ -29,6 +30,8 @@ examples:
29
30
  - advanced_table_default: Default (Required Props)
30
31
  - advanced_table_sort: Enable Sorting
31
32
  - advanced_table_sort_control: Sort Control
33
+ - advanced_table_sort_per_column: Enable Sort By Column
34
+ - advanced_table_sort_per_column_for_multi_column: Enable Sort By Column (Multi-Column)
32
35
  - advanced_table_custom_sort: Custom Sort
33
36
  - advanced_table_expanded_control: Expanded Control
34
37
  - advanced_table_expand_by_depth: Expand by Depth
@@ -43,6 +46,7 @@ examples:
43
46
  - advanced_table_responsive: Responsive Tables
44
47
  - advanced_table_custom_cell: Custom Components for Cells
45
48
  - advanced_table_with_custom_header: Custom Header Cell
49
+ - advanced_table_with_custom_header_multi_header: Custom Header with Multiple Headers
46
50
  - advanced_table_pagination: Pagination
47
51
  - advanced_table_pagination_with_props: Pagination Props
48
52
  - advanced_table_loading: Loading State
@@ -50,6 +54,7 @@ examples:
50
54
  - advanced_table_column_headers: Multi-Header Columns
51
55
  - advanced_table_column_headers_multiple: Multi-Header Columns (Multiple Levels)
52
56
  - advanced_table_column_headers_custom_cell: Multi-Header Columns with Custom Cells
57
+ - advanced_table_column_headers_vertical_border: Multi-Header Columns with Vertical Borders
53
58
  - advanced_table_no_subrows: Table with No Subrows or Expansion
54
59
  - advanced_table_pinned_rows: Pinned Rows
55
60
  - advanced_table_selectable_rows: Selectable Rows
@@ -21,6 +21,7 @@ export { default as AdvancedTableSelectableRowsHeader } from './_advanced_table_
21
21
  export { default as AdvancedTableSelectableRowsActions } from './_advanced_table_selectable_rows_actions.jsx'
22
22
  export { default as AdvancedTableTablePropsStickyHeader } from './_advanced_table_table_props_sticky_header.jsx'
23
23
  export { default as AdvancedTableColumnHeadersCustomCell } from './_advanced_table_column_headers_custom_cell.jsx'
24
+ export { default as AdvancedTableColumnHeadersVerticalBorder } from './_advanced_table_column_headers_vertical_border.jsx'
24
25
  export { default as AdvancedTableInlineEditing } from './_advanced_table_inline_editing.jsx'
25
26
  export { default as AdvancedTableFullscreen } from './_advanced_table_fullscreen.jsx'
26
27
  export { default as AdvancedTableStickyColumns } from './_advanced_table_sticky_columns.jsx'
@@ -40,3 +41,6 @@ export { default as AdvancedTableColumnStylingColumnHeaders } from './_advanced_
40
41
  export { default as AdvancedTableInfiniteScroll} from './_advanced_table_infinite_scroll.jsx'
41
42
  export {default as AdvancedTableWithCustomHeader} from './_advanced_table_with_custom_header.jsx'
42
43
  export { default as AdvancedTableCustomSort } from './_advanced_table_custom_sort.jsx'
44
+ export { default as AdvancedTableWithCustomHeaderMultiHeader } from './_advanced_table_with_custom_header_multi_header.jsx'
45
+ export { default as AdvancedTableSortPerColumn } from './_advanced_table_sort_per_column.jsx'
46
+ export { default as AdvancedTableSortPerColumnForMultiColumn } from './_advanced_table_sort_per_column_for_multi_column.jsx'
@@ -2,7 +2,6 @@ import PbEnhancedElement from "../pb_enhanced_element";
2
2
  import { updateSelectionActionBar } from "./advanced_table_action_bar";
3
3
 
4
4
  const FLAT_SELECTOR = "[data-flat-advanced-table-select='true']";
5
- const SELECT_ALL_SELECTOR = "#select-all-rows input[type='checkbox']";
6
5
 
7
6
  export default class PbFlatAdvancedTable extends PbEnhancedElement {
8
7
  static get selector() {
@@ -37,9 +36,12 @@ export default class PbFlatAdvancedTable extends PbEnhancedElement {
37
36
  }
38
37
  };
39
38
 
39
+ const selectAllId = this.element.getAttribute('data-pb-checkbox-indeterminate-parent')
40
+ const selectAllSelector = `#${selectAllId} input[type='checkbox']`
41
+
40
42
  table.addEventListener("change", (e) => {
41
43
  const rowCb = e.target.closest(FLAT_SELECTOR + " input[type='checkbox']");
42
- const allCb = e.target.closest(SELECT_ALL_SELECTOR);
44
+ const allCb = e.target.closest(selectAllSelector);
43
45
  if (!rowCb && !allCb) return;
44
46
 
45
47
  if (rowCb) {
@@ -50,15 +52,6 @@ export default class PbFlatAdvancedTable extends PbEnhancedElement {
50
52
  const tr = rowCb.closest("tr");
51
53
  tr?.classList.toggle("bg-row-selection", rowCb.checked);
52
54
  tr?.classList.toggle("bg-white", !rowCb.checked);
53
-
54
- // Sync header checkbox
55
- const header = table.querySelector(SELECT_ALL_SELECTOR);
56
- if (header) {
57
- const all = Array.from(
58
- table.querySelectorAll(FLAT_SELECTOR + " input[type='checkbox']")
59
- ).every((cb) => cb.checked);
60
- header.checked = all;
61
- }
62
55
  }
63
56
 
64
57
  if (allCb) {
@@ -39,6 +39,70 @@ export default class PbAdvancedTable extends PbEnhancedElement {
39
39
  );
40
40
  }
41
41
 
42
+ // Recalculate selected count based on all checked checkboxes
43
+ recalculateSelectedCount() {
44
+ const table = this.element.closest("table");
45
+
46
+ // Get all checkboxes that could be part of the selection
47
+ // This includes row checkboxes and any parent checkboxes that might be programmatically checked
48
+ const rowCheckboxes = table.querySelectorAll(
49
+ 'label[data-row-id] input[type="checkbox"]'
50
+ );
51
+
52
+ // Also get any checkboxes that might be parent checkboxes (those with data-pb-checkbox-indeterminate-main)
53
+ // But exclude the select-all checkbox itself from the count
54
+ const parentCheckboxes = table.querySelectorAll(
55
+ '[data-pb-checkbox-indeterminate-main="true"] input[type="checkbox"]'
56
+ );
57
+
58
+ // Filter out the select-all checkbox from parent checkboxes
59
+ const selectAllCheckbox = table.querySelector('#select-all-rows input[type="checkbox"]');
60
+ const filteredParentCheckboxes = Array.from(parentCheckboxes).filter(checkbox =>
61
+ checkbox !== selectAllCheckbox && !checkbox.id.includes('select-all-rows')
62
+ );
63
+
64
+ // Combine all checkboxes and remove duplicates
65
+ const allCheckboxes = new Set([...rowCheckboxes, ...filteredParentCheckboxes]);
66
+
67
+ // Clear the selectedRows Set and rebuild it from checked checkboxes
68
+ PbAdvancedTable.selectedRows.clear();
69
+
70
+ allCheckboxes.forEach((checkbox) => {
71
+ const rowEl = checkbox.closest("tr");
72
+ const isChecked = checkbox.checked;
73
+
74
+ if (isChecked) {
75
+ PbAdvancedTable.selectedRows.add(checkbox.id);
76
+ // Only apply styling if the checkbox is inside a table row
77
+ if (rowEl) {
78
+ rowEl.classList.add("bg-row-selection");
79
+ rowEl.classList.remove("bg-white", "bg-silver");
80
+ }
81
+ } else {
82
+ // Only apply styling if the checkbox is inside a table row
83
+ if (rowEl) {
84
+ rowEl.classList.remove("bg-row-selection");
85
+
86
+ if (this.isRowExpanded(rowEl)) {
87
+ rowEl.classList.remove("bg-silver");
88
+ rowEl.classList.add("bg-white");
89
+ } else {
90
+ rowEl.classList.remove("bg-white");
91
+ rowEl.classList.add("bg-silver");
92
+ }
93
+ }
94
+ }
95
+ });
96
+
97
+ this.updateTableSelectedRowsAttribute();
98
+ updateSelectionActionBar(table.closest(".pb_advanced_table"), PbAdvancedTable.selectedRows.size);
99
+
100
+ // Sync header select-all state
101
+ if (selectAllCheckbox) {
102
+ selectAllCheckbox.checked = Array.from(rowCheckboxes).every((cb) => cb.checked);
103
+ }
104
+ }
105
+
42
106
  // Check if the row is expanded or collapsed
43
107
  // This is used to determine the background color of the row
44
108
  // when the checkbox is checked or unchecked
@@ -47,75 +111,6 @@ export default class PbAdvancedTable extends PbEnhancedElement {
47
111
  return closeIcon?.style.display === "none" || !closeIcon;
48
112
  }
49
113
 
50
- updateParentCheckboxes(checkbox) {
51
- const rowEl = checkbox.closest("tr");
52
- if (!rowEl) return;
53
-
54
- const table = rowEl.closest("table");
55
- if (!table) return;
56
-
57
- const contentTrail = rowEl.dataset.advancedTableContent;
58
- if (!contentTrail) return;
59
-
60
- const ancestorIds = contentTrail.split("-").slice(0, -1);
61
-
62
- ancestorIds.reverse();
63
- ancestorIds.forEach((ancestorId) => {
64
- const parentRowSelector = `[data-advanced-table-content$="${ancestorId}"]`;
65
- const parentRow = table.querySelector(parentRowSelector);
66
- if (!parentRow) return;
67
-
68
- const parentLabel = parentRow.querySelector("label[data-row-id]");
69
- if (!parentLabel) return;
70
-
71
- const parentCheckbox = parentLabel.querySelector(
72
- "input[type='checkbox']"
73
- );
74
- if (!parentCheckbox) return;
75
-
76
- // Find all immediate children of parent linked to ancestor Id, filter our subrow headers
77
- const children = Array.from(
78
- table.querySelectorAll(`tr[data-row-parent$="_${ancestorId}"]`)
79
- ).filter((child) => {
80
- const content = child.dataset.advancedTableContent;
81
- return !(content && content.endsWith("sr"));
82
- });
83
-
84
- const allChildrenChecked = Array.from(children).every((child) => {
85
- const childLabel = child.querySelector("label[data-row-id]");
86
- if (!childLabel) return false;
87
- const childCheckbox = childLabel.querySelector(
88
- "input[type='checkbox']"
89
- );
90
- if (!childCheckbox) return false;
91
- return childCheckbox.checked;
92
- });
93
-
94
- // Update parent checkbox
95
- parentCheckbox.checked = allChildrenChecked;
96
-
97
- const parentCheckboxId = parentCheckbox.id;
98
- if (allChildrenChecked) {
99
- PbAdvancedTable.selectedRows.add(parentCheckboxId);
100
- parentRow.classList.add("bg-row-selection");
101
- parentRow.classList.remove("bg-white", "bg-silver");
102
- } else {
103
- PbAdvancedTable.selectedRows.delete(parentCheckboxId);
104
- }
105
- if (!allChildrenChecked) {
106
- parentRow.classList.remove("bg-row-selection");
107
-
108
- if (this.isRowExpanded(parentRow)) {
109
- parentRow.classList.remove("bg-silver");
110
- parentRow.classList.add("bg-white");
111
- } else {
112
- parentRow.classList.remove("bg-white");
113
- parentRow.classList.add("bg-silver");
114
- }
115
- }
116
- });
117
- }
118
-
119
114
  handleCheckboxClick(event) {
120
115
  const checkbox = event.currentTarget;
121
116
  const rowId = checkbox.id;
@@ -141,49 +136,6 @@ export default class PbAdvancedTable extends PbEnhancedElement {
141
136
  rowEl.classList.add("bg-silver");
142
137
  }
143
138
  }
144
- if (rowEl) {
145
- const table = rowEl.closest("table");
146
- const rowContent = rowEl.dataset.advancedTableContent;
147
-
148
- if (rowContent) {
149
- const childRows = table.querySelectorAll(
150
- `[data-advanced-table-content^="${rowContent}-"]`
151
- );
152
-
153
- childRows.forEach((childRow) => {
154
- const label = childRow.querySelector("label[data-row-id]");
155
- if (!label) return;
156
-
157
- const childCheckbox = label.querySelector("input[type='checkbox']");
158
- if (!childCheckbox) return;
159
-
160
- childCheckbox.checked = isChecked;
161
-
162
- const childRowId = childCheckbox.id;
163
- const childRowEl = childCheckbox.closest("tr");
164
- if (isChecked) {
165
- PbAdvancedTable.selectedRows.add(childRowId);
166
- childRowEl?.classList.add("bg-row-selection");
167
- childRowEl?.classList.remove("bg-white", "bg-silver");
168
- } else {
169
- PbAdvancedTable.selectedRows.delete(childRowId);
170
- }
171
- if (!isChecked) {
172
- childRowEl?.classList.remove("bg-row-selection");
173
-
174
- if (this.isRowExpanded(childRowEl)) {
175
- childRowEl?.classList.remove("bg-silver");
176
- childRowEl?.classList.add("bg-white");
177
- } else {
178
- childRowEl?.classList.remove("bg-white");
179
- childRowEl?.classList.add("bg-silver");
180
- }
181
- }
182
- });
183
- }
184
- }
185
-
186
- this.updateParentCheckboxes(checkbox);
187
139
 
188
140
  this.updateTableSelectedRowsAttribute();
189
141
 
@@ -249,8 +201,11 @@ export default class PbAdvancedTable extends PbEnhancedElement {
249
201
  this.handleCheckboxClick({ currentTarget: cb });
250
202
  }
251
203
  });
252
- this.updateTableSelectedRowsAttribute();
253
- updateSelectionActionBar(table.closest(".pb_advanced_table"), PbAdvancedTable.selectedRows.size);
204
+
205
+ // Recalculate the count to ensure all checkboxes are properly tracked
206
+ setTimeout(() => {
207
+ this.recalculateSelectedCount();
208
+ }, 0);
254
209
  return;
255
210
  }
256
211
 
@@ -258,17 +213,41 @@ export default class PbAdvancedTable extends PbEnhancedElement {
258
213
  const rowLabel = checkbox.closest("label[data-row-id]");
259
214
  if (rowLabel) {
260
215
  this.handleCheckboxClick({ currentTarget: checkbox });
261
- this.updateTableSelectedRowsAttribute();
216
+
217
+ // Recalculate the count to ensure all checkboxes are properly tracked
218
+ setTimeout(() => {
219
+ this.recalculateSelectedCount();
220
+ }, 0);
221
+ }
222
+ });
262
223
 
263
- // Sync header select-all state
264
- const selectAllInput = table.querySelector(
265
- '#select-all-rows input[type="checkbox"]'
266
- );
267
- if (selectAllInput) {
268
- selectAllInput.checked = Array.from(
269
- table.querySelectorAll('label[data-row-id] input[type="checkbox"]')
270
- ).every((cb) => cb.checked);
271
- }
224
+ // If a parent checkbox changed a checkbox, update styling
225
+ // Listen for programmatic checkbox changes from parent-child relationships
226
+ table.addEventListener("checkbox-programmatic-change", (event) => {
227
+ const checkbox = event.target;
228
+ if (!checkbox || checkbox.type !== 'checkbox') return;
229
+
230
+ // Individual row checkbox logic
231
+ const rowLabel = checkbox.closest("label[data-row-id]");
232
+ if (rowLabel) {
233
+ this.handleCheckboxClick({ currentTarget: checkbox });
234
+ }
235
+
236
+ // Recalculate the count to ensure all programmatically changed checkboxes are included
237
+ setTimeout(() => {
238
+ this.recalculateSelectedCount();
239
+ }, 10); // Slightly longer delay to ensure all changes are processed
240
+ });
241
+
242
+
243
+ // Also listen for all checkbox changes to ensure we catch everything
244
+ table.addEventListener("change", (event) => {
245
+ const checkbox = event.target;
246
+ if (checkbox && checkbox.type === 'checkbox') {
247
+ // Force recalculation after a short delay to ensure all changes are processed
248
+ setTimeout(() => {
249
+ this.recalculateSelectedCount();
250
+ }, 50);
272
251
  }
273
252
  });
274
253
 
@@ -314,12 +293,16 @@ export default class PbAdvancedTable extends PbEnhancedElement {
314
293
  "tr.is-visible, tr:not(.toggle-content)"
315
294
  );
316
295
 
317
- visibleRows.forEach((row) => row.classList.remove("last-visible-row"));
296
+ visibleRows.forEach((row) => {
297
+ row.classList.remove("last-visible-row");
298
+ row.classList.remove("last-row-cell");
299
+ });
318
300
 
319
301
  const lastVisibleRow = visibleRows[visibleRows.length - 1];
320
302
 
321
303
  if (lastVisibleRow) {
322
304
  lastVisibleRow.classList.add("last-visible-row");
305
+ lastVisibleRow.classList.add("last-row-cell");
323
306
  }
324
307
  }
325
308
  }
@@ -40,13 +40,14 @@ module Playbook
40
40
  end.compact
41
41
  end
42
42
 
43
- def render_row_and_children(row, column_definitions, current_depth, first_parent_child, ancestor_ids = [], top_parent_id = nil, additional_classes: "", table_data_attributes: {})
43
+ def render_row_and_children(row, column_definitions, current_depth, first_parent_child, ancestor_ids = [], top_parent_id = nil, additional_classes: "", table_data_attributes: {}, immediate_parent_row_id: nil)
44
44
  top_parent_id ||= row.object_id
45
45
  new_ancestor_ids = ancestor_ids + [row.object_id]
46
46
  leaf_columns = flatten_columns(column_definitions)
47
47
 
48
48
  output = ActiveSupport::SafeBuffer.new
49
49
  is_first_child_of_subrow = current_depth.positive? && first_parent_child && subrow_headers[current_depth - 1].present?
50
+ last_row = subrow_headers.length == current_depth
50
51
 
51
52
  subrow_ancestor_ids = ancestor_ids + ["#{row.object_id}sr"]
52
53
  subrow_data_attributes = {
@@ -55,7 +56,7 @@ module Playbook
55
56
  row_parent: "#{id}_#{ancestor_ids.last}",
56
57
  }
57
58
  # Subrow header if applicable
58
- 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", responsive: responsive, subrow_data_attributes: subrow_data_attributes }) if is_first_child_of_subrow && enable_toggle_expansion == "all"
59
+ 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", responsive: responsive, subrow_data_attributes: subrow_data_attributes, last_row: last_row, immediate_parent_row_id: immediate_parent_row_id }) if is_first_child_of_subrow && enable_toggle_expansion == "all"
59
60
 
60
61
  current_data_attributes = if current_depth.zero?
61
62
  {
@@ -68,7 +69,7 @@ module Playbook
68
69
  end
69
70
 
70
71
  # Additional class and data attributes needed for toggle logic
71
- 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, responsive: responsive, loading: loading, selectable_rows: selectable_rows, row_id: row[:id], enable_toggle_expansion: enable_toggle_expansion, row_styling: row_styling })
72
+ 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, responsive: responsive, loading: loading, selectable_rows: selectable_rows, row_id: row[:id], enable_toggle_expansion: enable_toggle_expansion, row_styling: row_styling, last_row: last_row, immediate_parent_row_id: immediate_parent_row_id })
72
73
 
73
74
  if row[:children].present?
74
75
  row[:children].each do |child_row|
@@ -83,7 +84,7 @@ module Playbook
83
84
  advanced_table_content: data_content,
84
85
  }
85
86
 
86
- 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)
87
+ 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, immediate_parent_row_id: row[:id])
87
88
  end
88
89
  end
89
90
 
@@ -3,6 +3,8 @@
3
3
  module Playbook
4
4
  module PbAdvancedTable
5
5
  class TableHeader < Playbook::KitBase
6
+ prop :id, type: Playbook::Props::String,
7
+ default: ""
6
8
  prop :column_definitions, type: Playbook::Props::Array,
7
9
  default: []
8
10
  prop :enable_toggle_expansion, type: Playbook::Props::Enum,
@@ -56,8 +58,10 @@ module Playbook
56
58
  classname: additional_classes.join(" "),
57
59
  }) do
58
60
  pb_rails("checkbox", props: {
59
- id: "select-all-rows",
60
- name: "select-all-rows",
61
+ id: "#{id ? "#{id}-" : ''}select-all-rows",
62
+ indeterminate_main: true,
63
+ indeterminate_main_labels: ["", ""],
64
+ name: "#{id ? "#{id}-" : ''}select-all-rows",
61
65
  })
62
66
  end
63
67
  end
@@ -67,8 +71,10 @@ module Playbook
67
71
  def render_select_all_checkbox
68
72
  if selectable_rows
69
73
  pb_rails("checkbox", props: {
70
- id: "select-all-rows",
71
- name: "select-all-rows",
74
+ id: "#{id ? "#{id}-" : ''}select-all-rows",
75
+ indeterminate_main: true,
76
+ indeterminate_main_labels: ["", ""],
77
+ name: "#{id ? "#{id}-" : ''}select-all-rows",
72
78
  data: {
73
79
  action: "click->pb-advanced-table#toggleAllRowSelection",
74
80
  },
@@ -39,11 +39,11 @@
39
39
  style="color: <%= button_color %>"
40
40
  >
41
41
  <%= pb_rails("icon", props: { id: "advanced-table_open_icon", icon: "circle-play", cursor: "pointer" }) %>
42
- <%= pb_rails("icon", props: { id: "advanced-table_close_icon", icon: "circle-play-down", cursor: "pointer" }) %>
42
+ <%= pb_rails("icon", props: { id: "advanced-table_close_icon", icon: "circle-play", cursor: "pointer", rotation: 90 }) %>
43
43
  </button>
44
44
  <% end %>
45
45
  <% end %>
46
- <%= pb_rails("flex/flex_item") do %>
46
+ <%= pb_rails("flex/flex_item") do %>
47
47
  <% if column[:custom_renderer].present? %>
48
48
  <%= raw(column[:custom_renderer].call(object.row, custom_renderer_value(column, index))) %>
49
49
  <% elsif index.zero? %>