playbook_ui 14.20.0.pre.rc.2 → 14.21.0.pre.alpha.PLAY2167advtablenitrorowborderdoubling8097

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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +1 -1
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +116 -49
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +61 -35
  5. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +37 -23
  6. data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +58 -2
  7. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +1 -1
  8. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +16 -4
  9. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +7 -3
  10. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +46 -21
  11. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +13 -3
  12. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +16 -8
  13. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +16 -1
  14. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +61 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.md +6 -2
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.jsx +1 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md +3 -1
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +1 -1
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_no_subrows.html.erb +33 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_no_subrows.jsx +0 -1
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows.jsx +57 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows_react.md +5 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_scrollbar_none.html.erb +33 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_scrollbar_none.jsx +53 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions_rails.html.erb +137 -0
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions_rails.md +3 -0
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header_rails.html.erb +40 -0
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header_rails.md +1 -0
  29. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +8 -2
  30. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +3 -1
  31. data/app/pb_kits/playbook/pb_advanced_table/index.js +157 -12
  32. data/app/pb_kits/playbook/pb_advanced_table/table_action_bar.html.erb +23 -0
  33. data/app/pb_kits/playbook/pb_advanced_table/table_action_bar.rb +19 -0
  34. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +4 -0
  35. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +4 -11
  36. data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +10 -6
  37. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.html.erb +2 -48
  38. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate_rails.md +1 -0
  39. data/app/pb_kits/playbook/pb_checkbox/index.js +56 -0
  40. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_date_display.html.erb +13 -0
  41. data/app/pb_kits/playbook/pb_draggable/context/index.tsx +17 -58
  42. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +1 -1
  43. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +86 -19
  44. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_close_on_select.jsx +42 -0
  45. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_close_on_select.md +1 -0
  46. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.html.erb +31 -0
  47. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.md +5 -0
  48. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.jsx +56 -0
  49. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.md +3 -0
  50. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.jsx +58 -0
  51. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.md +3 -0
  52. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.html.erb +20 -0
  53. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.md +1 -0
  54. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.html.erb +19 -0
  55. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.md +3 -0
  56. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.html.erb +20 -0
  57. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.jsx +57 -0
  58. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.md +1 -0
  59. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.html.erb +50 -0
  60. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.jsx +105 -0
  61. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.html.erb +22 -0
  62. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.jsx +67 -0
  63. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +13 -1
  64. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +6 -0
  65. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +3 -3
  66. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +16 -2
  67. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +108 -2
  68. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +34 -13
  69. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +3 -1
  70. data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +0 -6
  71. data/app/pb_kits/playbook/pb_dropdown/index.js +357 -40
  72. data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +39 -12
  73. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +26 -18
  74. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +96 -19
  75. data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +58 -0
  76. data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +1 -0
  77. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -0
  78. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +4 -0
  79. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_exclude_countries.html.erb +4 -0
  80. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_exclude_countries.jsx +15 -0
  81. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_exclude_countries.md +1 -0
  82. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_only_countries.jsx +1 -1
  83. data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +4 -3
  84. data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +1 -0
  85. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +3 -0
  86. data/app/pb_kits/playbook/pb_popover/index.ts +9 -4
  87. data/app/pb_kits/playbook/pb_select/docs/_select_custom_select_subheaders.html.erb +12 -0
  88. data/app/pb_kits/playbook/pb_select/docs/_select_custom_select_subheaders.jsx +31 -0
  89. data/app/pb_kits/playbook/pb_select/docs/_select_custom_select_subheaders.md +1 -0
  90. data/app/pb_kits/playbook/pb_select/docs/example.yml +2 -0
  91. data/app/pb_kits/playbook/pb_select/docs/index.js +1 -0
  92. data/app/pb_kits/playbook/pb_table/docs/_table_with_selectable_rows.html.erb +3 -51
  93. data/app/pb_kits/playbook/pb_table/styles/_mobile_collapse.scss +1 -1
  94. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +73 -3
  95. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.jsx +23 -0
  96. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.md +1 -0
  97. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +1 -0
  98. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
  99. data/dist/chunks/_typeahead-CoOpeYom.js +22 -0
  100. data/dist/chunks/_weekday_stacked-B_jpa2Rz.js +45 -0
  101. data/dist/chunks/lib-D7Va7yqa.js +29 -0
  102. data/dist/chunks/{pb_form_validation-WWvUXPKD.js → pb_form_validation-DSkdRDMf.js} +1 -1
  103. data/dist/chunks/vendor.js +1 -1
  104. data/dist/menu.yml +1 -1
  105. data/dist/playbook-doc.js +2 -2
  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/kit_base.rb +3 -3
  110. data/lib/playbook/version.rb +2 -2
  111. metadata +48 -7
  112. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.html.erb +0 -10
  113. data/dist/chunks/_typeahead-B9-s4j4U.js +0 -22
  114. data/dist/chunks/_weekday_stacked-CvzpmXD5.js +0 -45
  115. data/dist/chunks/lib-B20MXZcW.js +0 -29
@@ -0,0 +1,137 @@
1
+ <% column_definitions = [
2
+ {
3
+ accessor: "year",
4
+ label: "Year",
5
+ cellAccessors: ["quarter", "month", "day"],
6
+ },
7
+ {
8
+ accessor: "newEnrollments",
9
+ label: "New Enrollments",
10
+ },
11
+ {
12
+ accessor: "scheduledMeetings",
13
+ label: "Scheduled Meetings",
14
+ },
15
+ {
16
+ accessor: "attendanceRate",
17
+ label: "Attendance Rate",
18
+ },
19
+ {
20
+ accessor: "completedClasses",
21
+ label: "Completed Classes",
22
+ },
23
+ {
24
+ accessor: "classCompletionRate",
25
+ label: "Class Completion Rate",
26
+ },
27
+ {
28
+ accessor: "graduatedStudents",
29
+ label: "Graduated Students",
30
+ }
31
+ ]
32
+
33
+ actions = [
34
+ pb_rails("circle_icon_button", props: {
35
+ icon: "file-csv",
36
+ variant: "link",
37
+ id: "export-selected-rows-btn",
38
+ data: {
39
+ action_type: "export"
40
+ }
41
+ }),
42
+ pb_rails("circle_icon_button", props: {
43
+ icon: "trash-alt",
44
+ variant: "link",
45
+ id: "delete-selected-rows-btn",
46
+ data: {
47
+ action_type: "delete"
48
+ }
49
+ })
50
+ ]
51
+ %>
52
+
53
+ <%= pb_rails("advanced_table", props: {
54
+ id: "selectable_rows_with_actions",
55
+ table_data: @table_data_no_subrows,
56
+ column_definitions: column_definitions,
57
+ selectable_rows: true,
58
+ enable_toggle_expansion: "none",
59
+ actions: actions
60
+ }) %>
61
+
62
+ <script>
63
+ // Handle action clicks using the data-selected-rows attribute
64
+ window.handleActionClick = function(actionType) {
65
+ const tableContainer = document.getElementById('selectable_rows_with_actions');
66
+ if (!tableContainer) return;
67
+
68
+ // Get selected rows from the data attribute
69
+ const selectedRowsJSON = tableContainer.getAttribute('data-selected-rows');
70
+ let selectedRowIds = [];
71
+
72
+ try {
73
+ // Parse the JSON string from the data attribute
74
+ if (selectedRowsJSON) {
75
+ selectedRowIds = JSON.parse(selectedRowsJSON);
76
+ }
77
+ } catch (e) {
78
+ // Fallback if JSON parsing fails
79
+ const checkboxes = tableContainer.querySelectorAll('input[type="checkbox"]:checked');
80
+ const selectedCheckboxes = Array.from(checkboxes).filter(checkbox =>
81
+ checkbox.id !== 'select-all-rows' &&
82
+ !checkbox.closest('#select-all-rows')
83
+ );
84
+ selectedRowIds = selectedCheckboxes.map(checkbox => checkbox.id);
85
+ }
86
+
87
+ // Show appropriate message
88
+ if (!selectedRowIds || selectedRowIds.length === 0) {
89
+ alert('No Selection Made');
90
+ } else {
91
+ if (actionType === 'export') {
92
+ alert(`Row ids ${selectedRowIds.join(', ')} will be exported!`);
93
+ } else if (actionType === 'delete') {
94
+ alert(`Row ids ${selectedRowIds.join(', ')} will be deleted!`);
95
+ }
96
+ }
97
+ };
98
+
99
+ // Add event listeners when the DOM is ready
100
+ document.addEventListener('DOMContentLoaded', function() {
101
+ // Get the buttons
102
+ const exportBtn = document.getElementById('export-selected-rows-btn');
103
+ const deleteBtn = document.getElementById('delete-selected-rows-btn');
104
+
105
+ // Add click event listeners
106
+ if (exportBtn) {
107
+ exportBtn.addEventListener('click', function(e) {
108
+ e.preventDefault();
109
+ window.handleActionClick('export');
110
+ });
111
+ }
112
+
113
+ if (deleteBtn) {
114
+ deleteBtn.addEventListener('click', function(e) {
115
+ e.preventDefault();
116
+ window.handleActionClick('delete');
117
+ });
118
+ }
119
+
120
+ // Optional: Event delegation through the action bar
121
+ const actionBar = document.querySelector('.row-selection-actions-card');
122
+ if (actionBar) {
123
+ actionBar.addEventListener('click', function(e) {
124
+ const exportButton = e.target.closest('#export-selected-rows-btn');
125
+ const deleteButton = e.target.closest('#delete-selected-rows-btn');
126
+
127
+ if (exportButton) {
128
+ e.preventDefault();
129
+ window.handleActionClick('export');
130
+ } else if (deleteButton) {
131
+ e.preventDefault();
132
+ window.handleActionClick('delete');
133
+ }
134
+ });
135
+ }
136
+ });
137
+ </script>
@@ -0,0 +1,3 @@
1
+ Custom actions content can be rendered within the Actions Bar as shown in this doc example. The component passed to `actions` will be rendered on the right of the actionsBar.
2
+
3
+ You can utilize script tags with your actions to provide your buttons with any clickable events needed.
@@ -0,0 +1,40 @@
1
+ <% column_definitions = [
2
+ {
3
+ accessor: "year",
4
+ label: "Year",
5
+ cellAccessors: ["quarter", "month", "day"],
6
+ },
7
+ {
8
+ accessor: "newEnrollments",
9
+ label: "New Enrollments",
10
+ },
11
+ {
12
+ accessor: "scheduledMeetings",
13
+ label: "Scheduled Meetings",
14
+ },
15
+ {
16
+ accessor: "attendanceRate",
17
+ label: "Attendance Rate",
18
+ },
19
+ {
20
+ accessor: "completedClasses",
21
+ label: "Completed Classes",
22
+ },
23
+ {
24
+ accessor: "classCompletionRate",
25
+ label: "Class Completion Rate",
26
+ },
27
+ {
28
+ accessor: "graduatedStudents",
29
+ label: "Graduated Students",
30
+ }
31
+ ] %>
32
+
33
+ <%= pb_rails("advanced_table", props: {
34
+ id: "selectable_rows_with_actions",
35
+ table_data: @table_data_no_subrows,
36
+ column_definitions: column_definitions,
37
+ selectable_rows: true,
38
+ enable_toggle_expansion: "none",
39
+ show_actions_bar: false
40
+ }) %>
@@ -0,0 +1 @@
1
+ `show_actions_bar` is an optional prop that renders the header at the top showing the row count. This is set to `true` by default but can be toggled off by setting it to `false`
@@ -13,8 +13,12 @@ examples:
13
13
  - advanced_table_column_headers: Multi-Header Columns
14
14
  - advanced_table_column_headers_multiple: Multi-Header Columns (Multiple Levels)
15
15
  - advanced_table_column_border_color_rails: Column Group Border Color
16
+ - advanced_table_no_subrows: Table with No Subrows or Expansion
16
17
  - advanced_table_selectable_rows_rails: Selectable Rows
17
18
  - advanced_table_selectable_rows_no_subrows_rails: Selectable Rows (No Subrows)
19
+ - advanced_table_selectable_rows_actions_rails: Selectable Rows (With Actions)
20
+ - advanced_table_selectable_rows_header_rails: Selectable Rows (No Actions Bar)
21
+ - advanced_table_scrollbar_none: Advanced Table Scrollbar None
18
22
 
19
23
  react:
20
24
  - advanced_table_default: Default (Required Props)
@@ -40,7 +44,7 @@ examples:
40
44
  - advanced_table_column_headers_multiple: Multi-Header Columns (Multiple Levels)
41
45
  - advanced_table_column_headers_custom_cell: Multi-Header Columns with Custom Cells
42
46
  - advanced_table_column_border_color: Column Group Border Color
43
- # - advanced_table_no_subrows: Table with No Subrows
47
+ - advanced_table_no_subrows: Table with No Subrows or Expansion
44
48
  - advanced_table_selectable_rows: Selectable Rows
45
49
  - advanced_table_selectable_rows_no_subrows_react: Selectable Rows (No Subrows)
46
50
  - advanced_table_selectable_rows_actions: Selectable Rows (With Actions)
@@ -50,4 +54,6 @@ examples:
50
54
  - advanced_table_column_visibility: Column Visibility Control
51
55
  - advanced_table_column_visibility_with_state: Column Visibility Control With State
52
56
  - advanced_table_column_visibility_custom: Column Visibility Control with Custom Dropdown
53
- - advanced_table_column_visibility_multi: Column Visibility Control with Multi-Header Columns
57
+ - advanced_table_column_visibility_multi: Column Visibility Control with Multi-Header Columns
58
+ - advanced_table_pinned_rows: Pinned Rows
59
+ - advanced_table_scrollbar_none: Advanced Table Scrollbar None
@@ -31,4 +31,6 @@ export { default as AdvancedTableColumnBorderColor} from './_advanced_table_colu
31
31
  export { default as AdvancedTableColumnVisibility } from './_advanced_table_column_visibility.jsx'
32
32
  export { default as AdvancedTableColumnVisibilityCustom } from './_advanced_table_column_visibility_custom.jsx'
33
33
  export { default as AdvancedTableColumnVisibilityMulti } from './_advanced_table_column_visibility_multi.jsx'
34
- export { default as AdvancedTableColumnVisibilityWithState } from './_advanced_table_column_visibility_with_state.jsx'
34
+ export { default as AdvancedTableColumnVisibilityWithState } from './_advanced_table_column_visibility_with_state.jsx'
35
+ export { default as AdvancedTablePinnedRows } from './_advanced_table_pinned_rows.jsx'
36
+ export { default as AdvancedTableScrollbarNone} from './_advanced_table_scrollbar_none.jsx'
@@ -79,7 +79,7 @@ export default class PbAdvancedTable extends PbEnhancedElement {
79
79
  }
80
80
  if (!allChildrenChecked) {
81
81
  parentRow.classList.remove("bg-row-selection");
82
-
82
+
83
83
  if (this.isRowExpanded(parentRow)) {
84
84
  parentRow.classList.remove("bg-silver");
85
85
  parentRow.classList.add("bg-white");
@@ -201,15 +201,15 @@ export default class PbAdvancedTable extends PbEnhancedElement {
201
201
  this.toggleElement(this.target);
202
202
  }
203
203
  });
204
-
204
+
205
205
  this.hideCloseIcon();
206
-
206
+
207
207
  const table = this.element.closest("table");
208
-
208
+
209
209
  // Prevent duplicate initialization
210
210
  if (table.dataset.pbAdvancedTableInitialized) return;
211
211
  table.dataset.pbAdvancedTableInitialized = "true";
212
-
212
+
213
213
  // Bind checkbox change handlers for all row checkboxes
214
214
  const checkboxLabels = table.querySelectorAll("label[data-row-id]");
215
215
  checkboxLabels.forEach((label) => {
@@ -219,7 +219,7 @@ export default class PbAdvancedTable extends PbEnhancedElement {
219
219
  this.handleCheckboxClick(event);
220
220
  });
221
221
  });
222
-
222
+
223
223
  // Bind nested row expansion logic
224
224
  const nestedButtons = table.querySelectorAll("[data-advanced-table]");
225
225
  nestedButtons.forEach((button) => {
@@ -233,18 +233,18 @@ export default class PbAdvancedTable extends PbEnhancedElement {
233
233
  }
234
234
  });
235
235
  });
236
-
236
+
237
237
  // Bind select-all logic for this table
238
238
  const selectAllCheckbox = table.querySelector("#select-all-rows");
239
239
  if (selectAllCheckbox) {
240
240
  selectAllCheckbox.addEventListener("change", () => {
241
241
  const checkboxInput = selectAllCheckbox.querySelector('input[type="checkbox"]');
242
242
  const checkAll = checkboxInput.checked;
243
-
243
+
244
244
  const checkboxes = Array.from(
245
245
  table.querySelectorAll("label[data-row-id] input[type='checkbox']")
246
246
  );
247
-
247
+
248
248
  checkboxes.forEach((cb) => {
249
249
  cb.checked = checkAll;
250
250
  const rowId = cb.id;
@@ -260,14 +260,14 @@ export default class PbAdvancedTable extends PbEnhancedElement {
260
260
  rowEl?.classList.add("bg-white");
261
261
  }
262
262
  });
263
-
263
+
264
264
  checkboxes.forEach((cb) => this.updateParentCheckboxes(cb));
265
-
265
+
266
266
  this.updateTableSelectedRowsAttribute();
267
267
  });
268
268
  }
269
269
  }
270
-
270
+
271
271
 
272
272
  hideCloseIcon() {
273
273
  const closeIcon = this.element.querySelector(UP_ARROW_SELECTOR);
@@ -449,6 +449,151 @@ export default class PbAdvancedTable extends PbEnhancedElement {
449
449
  }
450
450
  }
451
451
 
452
+ // Isolate action bar functionality so it doesn't mix with existing functionality
453
+ class PbAdvancedTableActionBar {
454
+ constructor() {
455
+ this.init();
456
+ }
457
+
458
+ init() {
459
+ // Initialize action bars for all advanced tables with action bars
460
+ document.addEventListener('DOMContentLoaded', () => {
461
+ this.setupActionBars();
462
+ });
463
+
464
+ // Also run immediately in case DOM is already loaded
465
+ if (document.readyState === 'loading') {
466
+ // DOM is still loading
467
+ } else {
468
+ // DOM is already loaded
469
+ this.setupActionBars();
470
+ }
471
+ }
472
+
473
+ setupActionBars() {
474
+ const advancedTables = document.querySelectorAll('.pb_advanced_table');
475
+
476
+ advancedTables.forEach(table => {
477
+ // Only proceed if this table has both selectable rows AND an action bar
478
+ if (!this.shouldEnableActionBar(table)) return;
479
+
480
+ const actionBar = table.querySelector('.row-selection-actions-card');
481
+ if (!actionBar) return; // Skip tables without action bars
482
+
483
+ // Initialize action bar styles
484
+ this.initializeActionBar(actionBar);
485
+
486
+ // Set up checkbox listeners for this table
487
+ this.setupCheckboxListeners(table, actionBar);
488
+ });
489
+ }
490
+
491
+ shouldEnableActionBar(table) {
492
+ // Check if the table has selectable rows
493
+ const hasSelectableRows = table.querySelector('input[type="checkbox"]') !== null;
494
+
495
+ // Check if the table has a row selection action bar (not other types of action bars)
496
+ const hasRowSelectionActionBar = table.querySelector('.row-selection-actions-card') !== null;
497
+
498
+ // Additional check: look for the presence of row checkboxes with data-row-id
499
+ const hasRowCheckboxes = table.querySelector('label[data-row-id] input[type="checkbox"]') !== null;
500
+
501
+ // Only enable if ALL conditions are met:
502
+ // 1. Has selectable checkboxes
503
+ // 2. Has the specific row selection action bar
504
+ // 3. Has row checkboxes (not just other types of checkboxes)
505
+ return hasSelectableRows && hasRowSelectionActionBar && hasRowCheckboxes;
506
+ }
507
+
508
+ initializeActionBar(actionBar) {
509
+ // Set initial hidden state
510
+ Object.assign(actionBar.style, {
511
+ height: '0px',
512
+ overflow: 'hidden',
513
+ display: 'block',
514
+ opacity: '0'
515
+ });
516
+
517
+ // Remove any visibility classes
518
+ actionBar.classList.remove("p_xs", "is-visible", "show-action-card");
519
+ actionBar.classList.add("p_none");
520
+ }
521
+
522
+ setupCheckboxListeners(table, actionBar) {
523
+ // Only listen to row checkboxes (those with data-row-id), not all checkboxes
524
+ const rowCheckboxes = table.querySelectorAll('label[data-row-id] input[type="checkbox"]');
525
+
526
+ rowCheckboxes.forEach(checkbox => {
527
+ checkbox.addEventListener('change', () => {
528
+ // Use setTimeout to ensure this runs after the main checkbox logic
529
+ setTimeout(() => {
530
+ this.updateActionBarVisibility(table, actionBar);
531
+ }, 0);
532
+ });
533
+ });
534
+
535
+ // Special handling for select-all checkbox (only if it exists)
536
+ const selectAllCheckbox = table.querySelector("#select-all-rows");
537
+ if (selectAllCheckbox) {
538
+ const selectAllInput = selectAllCheckbox.querySelector('input[type="checkbox"]');
539
+ if (selectAllInput) {
540
+ selectAllInput.addEventListener('change', () => {
541
+ // Use setTimeout to ensure this runs after the main select-all logic
542
+ setTimeout(() => {
543
+ this.updateActionBarVisibility(table, actionBar);
544
+ }, 10); // Slightly longer delay for select-all to ensure all row checkboxes are updated
545
+ });
546
+ }
547
+ }
548
+ }
549
+
550
+ updateActionBarVisibility(table, actionBar) {
551
+ // Only count row checkboxes (those with data-row-id), not all checkboxes
552
+ const rowCheckboxes = table.querySelectorAll('label[data-row-id] input[type="checkbox"]');
553
+
554
+ // Get all checked row checkboxes
555
+ const selectedRowCheckboxes = Array.from(rowCheckboxes).filter(cb => cb.checked);
556
+
557
+ // Get the selected count
558
+ const selectedCount = selectedRowCheckboxes.length;
559
+
560
+ if (selectedCount > 0) {
561
+ this.showActionBar(actionBar, selectedCount);
562
+ } else {
563
+ this.hideActionBar(actionBar);
564
+ }
565
+ }
566
+
567
+ showActionBar(actionBar, selectedCount) {
568
+ // Show action bar directly
569
+ actionBar.style.height = 'auto';
570
+ actionBar.style.overflow = 'visible';
571
+ actionBar.style.opacity = '1';
572
+ actionBar.style.transitionProperty = 'all';
573
+ actionBar.style.transitionTimingFunction = 'ease-in-out';
574
+ actionBar.classList.remove("p_none");
575
+ actionBar.classList.add("p_xs", "is-visible", "show-action-card");
576
+
577
+ // Update the count
578
+ const countElement = actionBar.querySelector(".selected-count");
579
+ if (countElement) {
580
+ countElement.textContent = `${selectedCount} Selected`;
581
+ }
582
+ }
583
+
584
+ hideActionBar(actionBar) {
585
+ // Hide action bar directly
586
+ actionBar.style.height = '0px';
587
+ actionBar.style.overflow = 'hidden';
588
+ actionBar.style.opacity = '0';
589
+ actionBar.classList.add("p_none");
590
+ actionBar.classList.remove("p_xs", "is-visible", "show-action-card");
591
+ }
592
+ }
593
+
594
+ // Initialize the isolated action bar functionality
595
+ new PbAdvancedTableActionBar();
596
+
452
597
  window.expandAllRows = (element) => {
453
598
  PbAdvancedTable.handleToggleAllHeaders(element);
454
599
  };
@@ -0,0 +1,23 @@
1
+ <%= pb_rails("card", props: {
2
+ border_none: object.is_visible,
3
+ classname: object.classname,
4
+ padding: object.is_visible ? "xs" : "none",
5
+ data: {
6
+ action_bar: true
7
+ }
8
+ }) do %>
9
+ <%= pb_rails("flex", props: { align_items: "center", justify: "between" }) do %>
10
+ <%= pb_rails("caption", props: { color: "light", padding_left: "xs", size: "xs" }) do %>
11
+ <span class="selected-count"><%= object.selected_count %> Selected</span>
12
+ <% end %>
13
+ <%= pb_rails("flex/flex_item") do %>
14
+ <%= pb_rails("flex") do %>
15
+ <% if object.actions.present? %>
16
+ <% object.actions.each do |action| %>
17
+ <%= action %>
18
+ <% end %>
19
+ <% end %>
20
+ <% end %>
21
+ <% end %>
22
+ <% end %>
23
+ <% end %>
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbAdvancedTable
5
+ class TableActionBar < Playbook::KitBase
6
+ prop :actions, type: Playbook::Props::Array,
7
+ default: []
8
+ prop :is_visible, type: Playbook::Props::Boolean,
9
+ default: false
10
+ prop :selected_count, type: Playbook::Props::Number,
11
+ default: 0
12
+
13
+ def classname
14
+ # Just use row-selection-actions-card as the base class
15
+ generate_classname("row-selection-actions-card", separator: " ")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -15,6 +15,8 @@ module Playbook
15
15
  default: "scroll"
16
16
  prop :selectable_rows, type: Playbook::Props::Boolean,
17
17
  default: false
18
+ prop :show_actions_bar, type: Playbook::Props::Boolean,
19
+ default: true
18
20
 
19
21
  def classname
20
22
  additional_classes = []
@@ -27,6 +29,7 @@ module Playbook
27
29
  def th_classname(is_first_column: false)
28
30
  additional_classes = []
29
31
  additional_classes << "pinned-left" if is_first_column && responsive == "scroll" && !selectable_rows
32
+ additional_classes << "header-cells-with-actions" if selectable_rows && show_actions_bar
30
33
 
31
34
  generate_classname("table-header-cells", *additional_classes, separator: " ")
32
35
  end
@@ -46,6 +49,7 @@ module Playbook
46
49
  if selectable_rows
47
50
  additional_classes = []
48
51
  additional_classes << "table-header-cells-custom"
52
+ additional_classes << "header-cells-with-actions" if show_actions_bar
49
53
  additional_classes << "checkbox-cell-header"
50
54
  additional_classes << "pinned-left" if responsive == "scroll"
51
55
  pb_rails("table/table_header", props: {
@@ -1,16 +1,9 @@
1
1
  <%= pb_content_tag(:label) do %>
2
2
  <%= content.presence || object.input %>
3
- <% if object.indeterminate %>
4
- <span data-pb-checkbox-icon-span="true" class="pb_checkbox_indeterminate">
5
- <%= pb_rails("icon", props: { icon: "minus", classname: "indeterminate_icon", fixed_width: true}) %>
6
- <%= pb_rails("icon", props: { icon: "check", classname: "check_icon hidden", fixed_width: true}) %>
7
- </span>
8
- <% else %>
9
- <span data-pb-checkbox-icon-span="true" class="pb_checkbox_checkmark">
10
- <%= pb_rails("icon", props: { icon: "check", classname: "check_icon", fixed_width: true}) %>
11
- <%= pb_rails("icon", props: { icon: "minus", classname: "indeterminate_icon hidden", fixed_width: true}) %>
12
- </span>
13
- <% end %>
3
+ <span data-pb-checkbox-icon-span="true" class="pb_checkbox_checkmark">
4
+ <%= pb_rails("icon", props: { icon: "check", classname: "check_icon", fixed_width: true}) %>
5
+ <%= pb_rails("icon", props: { icon: "minus", classname: "indeterminate_icon hidden", fixed_width: true}) %>
6
+ </span>
14
7
  <span class="pb_checkbox_label">
15
8
  <%= pb_rails("body", props: { status: object.checkbox_label_status, text: object.text, dark: object.dark, margin_right: object.form_spacing ? "xs" : "" }) %>
16
9
  </span>
@@ -5,7 +5,8 @@ module Playbook
5
5
  class Checkbox < Playbook::KitBase
6
6
  prop :error, type: Playbook::Props::Boolean, default: false
7
7
  prop :checked, type: Playbook::Props::Boolean, default: false
8
- prop :indeterminate, type: Playbook::Props::Boolean, default: false
8
+ prop :indeterminate_main, type: Playbook::Props::Boolean, default: false
9
+ prop :indeterminate_parent
9
10
  prop :text
10
11
  prop :value
11
12
  prop :name
@@ -19,7 +20,7 @@ module Playbook
19
20
  default: false
20
21
 
21
22
  def classname
22
- generate_classname("pb_checkbox_kit", checked_class) + indeterminate_class + error_class
23
+ generate_classname("pb_checkbox_kit", checked_class) + error_class
23
24
  end
24
25
 
25
26
  def input
@@ -30,6 +31,13 @@ module Playbook
30
31
  error ? "negative" : nil
31
32
  end
32
33
 
34
+ def data
35
+ Hash(prop(:data)).merge(
36
+ pb_checkbox_indeterminate_main: indeterminate_main,
37
+ pb_checkbox_indeterminate_parent: indeterminate_parent
38
+ )
39
+ end
40
+
33
41
  private
34
42
 
35
43
  def error_class
@@ -39,10 +47,6 @@ module Playbook
39
47
  def checked_class
40
48
  checked ? "on" : "off"
41
49
  end
42
-
43
- def indeterminate_class
44
- indeterminate ? " indeterminate" : ""
45
- end
46
50
  end
47
51
  end
48
52
  end
@@ -9,11 +9,10 @@
9
9
  <tr>
10
10
  <th>
11
11
  <%= pb_rails("checkbox", props: {
12
- checked: true,
13
12
  text: "Uncheck All",
14
13
  value: "checkbox-value",
15
14
  name: "main-checkbox",
16
- indeterminate: true,
15
+ indeterminate_main: true,
17
16
  id: "indeterminate-checkbox"
18
17
  }) %>
19
18
  </th>
@@ -30,55 +29,10 @@
30
29
  value: checkbox[:id],
31
30
  name: "#{checkbox[:id]}-indeterminate-checkbox",
32
31
  id: "#{checkbox[:id]}-indeterminate-checkbox",
32
+ indeterminate_parent: "indeterminate-checkbox",
33
33
  }) %>
34
34
  </td>
35
35
  </tr>
36
36
  <% end %>
37
37
  </tbody>
38
38
  <% end %>
39
-
40
- <script>
41
- document.addEventListener('DOMContentLoaded', function() {
42
- const mainCheckboxWrapper = document.getElementById('indeterminate-checkbox');
43
- const mainCheckbox = document.getElementsByName("main-checkbox")[0];
44
- const childCheckboxes = document.querySelectorAll('input[type="checkbox"][id$="indeterminate-checkbox"]');
45
-
46
- const updateMainCheckbox = () => {
47
- // Count the number of checked child checkboxes
48
- const checkedCount = Array.from(childCheckboxes).filter(cb => cb.checked).length;
49
- // Determine if the main checkbox should be in an indeterminate state
50
- const indeterminate = checkedCount > 0 && checkedCount < childCheckboxes.length;
51
-
52
- // Set the main checkbox states
53
- mainCheckbox.indeterminate = indeterminate;
54
- mainCheckbox.checked = checkedCount > 0;
55
-
56
- // Determine the main checkbox label based on the number of checked checkboxes
57
- const text = checkedCount === 0 ? 'Check All' : 'Uncheck All';
58
-
59
- // Determine the icon class to add and remove based on the number of checked checkboxes
60
- const iconClassToAdd = checkedCount === 0 ? 'pb_checkbox_checkmark' : 'pb_checkbox_indeterminate';
61
- const iconClassToRemove = checkedCount === 0 ? 'pb_checkbox_indeterminate' : 'pb_checkbox_checkmark';
62
-
63
- // Update main checkbox label
64
- mainCheckboxWrapper.getElementsByClassName('pb_body_kit')[0].textContent = text;
65
-
66
- // Add and remove the icon class to the main checkbox wrapper
67
- mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.add(iconClassToAdd);
68
- mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.remove(iconClassToRemove);
69
-
70
- // Toggle the visibility of the checkbox icon based on the indeterminate state
71
- mainCheckboxWrapper.getElementsByClassName("indeterminate_icon")[0].classList.toggle('hidden', !indeterminate);
72
- mainCheckboxWrapper.getElementsByClassName("check_icon")[0].classList.toggle('hidden', indeterminate);
73
- };
74
-
75
- mainCheckbox.addEventListener('change', function() {
76
- childCheckboxes.forEach(cb => cb.checked = this.checked);
77
- updateMainCheckbox();
78
- });
79
-
80
- childCheckboxes.forEach(cb => {
81
- cb.addEventListener('change', updateMainCheckbox);
82
- });
83
- });
84
- </script>
@@ -0,0 +1 @@
1
+ If you want to use indeterminate, "check/uncheck all" checkboxes, add `indeterminate_main: true` and an `id` to the main checkbox. Then, add an `indeterminate_parent` prop with the main checkbox's `id` to the children checkboxes.