playbook_ui 14.19.0 → 14.20.0.pre.alpha.PLAY2178advancedtablerowpinning7978

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 (162) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +92 -5
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +175 -16
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +56 -25
  5. data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +58 -2
  6. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +1 -1
  7. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +34 -15
  8. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +7 -3
  9. data/app/pb_kits/playbook/pb_advanced_table/Utilities/VisibilityTree.ts +47 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +11 -10
  11. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +13 -4
  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 +9 -0
  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.jsx +57 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.md +4 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.jsx +62 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.md +1 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.jsx +82 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.md +1 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.jsx +66 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md +3 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +1 -1
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows.jsx +57 -0
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows_react.md +5 -0
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions_rails.html.erb +137 -0
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions_rails.md +3 -0
  29. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header_rails.html.erb +40 -0
  30. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header_rails.md +1 -0
  31. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +7 -0
  32. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +6 -1
  33. data/app/pb_kits/playbook/pb_advanced_table/index.js +155 -12
  34. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/advanced_table_sticky_mixin.scss +1 -0
  35. data/app/pb_kits/playbook/pb_advanced_table/table_action_bar.html.erb +23 -0
  36. data/app/pb_kits/playbook/pb_advanced_table/table_action_bar.rb +19 -0
  37. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +4 -0
  38. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +1 -1
  39. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +77 -19
  40. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.html.erb +31 -0
  41. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.md +5 -0
  42. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.jsx +56 -0
  43. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.md +3 -0
  44. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.jsx +58 -0
  45. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.md +3 -0
  46. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.html.erb +20 -0
  47. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.md +1 -0
  48. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.html.erb +19 -0
  49. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.md +3 -0
  50. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.html.erb +20 -0
  51. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.jsx +57 -0
  52. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.md +1 -0
  53. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.html.erb +50 -0
  54. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.jsx +105 -0
  55. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.html.erb +22 -0
  56. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.jsx +67 -0
  57. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.jsx +11 -0
  58. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.md +1 -1
  59. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.html.erb +33 -2
  60. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.md +3 -1
  61. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +11 -1
  62. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +5 -0
  63. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +3 -3
  64. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +16 -2
  65. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +108 -2
  66. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +34 -13
  67. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +3 -1
  68. data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +0 -6
  69. data/app/pb_kits/playbook/pb_dropdown/index.js +336 -30
  70. data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +39 -12
  71. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +2 -2
  72. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +16 -12
  73. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +79 -13
  74. data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +58 -0
  75. data/app/pb_kits/playbook/pb_file_upload/_file_upload.scss +13 -0
  76. data/app/pb_kits/playbook/pb_file_upload/_file_upload.tsx +11 -1
  77. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.html.erb +1 -0
  78. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.jsx +41 -0
  79. data/app/pb_kits/playbook/pb_file_upload/docs/example.yml +2 -0
  80. data/app/pb_kits/playbook/pb_file_upload/docs/index.js +1 -0
  81. data/app/pb_kits/playbook/pb_file_upload/file_upload.html.erb +1 -0
  82. data/app/pb_kits/playbook/pb_file_upload/file_upload.rb +7 -1
  83. data/app/pb_kits/playbook/pb_file_upload/fileupload.test.js +18 -0
  84. data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +1 -0
  85. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -0
  86. data/app/pb_kits/playbook/pb_form_group/_error_state_mixin.scss +2 -2
  87. data/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +19 -12
  88. data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.tsx +13 -7
  89. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +2 -2
  90. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_color.html.erb +11 -11
  91. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_color.jsx +11 -11
  92. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.html.erb +11 -11
  93. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +11 -11
  94. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.html.erb +11 -11
  95. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.jsx +11 -11
  96. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.html.erb +11 -11
  97. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.jsx +11 -11
  98. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.html.erb +11 -11
  99. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.jsx +11 -11
  100. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.html.erb +11 -11
  101. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.jsx +11 -11
  102. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.html.erb +11 -11
  103. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.jsx +11 -11
  104. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_error.html.erb +11 -11
  105. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_error.jsx +11 -11
  106. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.html.erb +11 -11
  107. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.jsx +11 -11
  108. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_react_hook.jsx +11 -11
  109. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_reset.html.erb +11 -11
  110. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.html.erb +11 -11
  111. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.jsx +11 -11
  112. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids.html.erb +11 -11
  113. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids.md +2 -0
  114. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids_react.jsx +11 -11
  115. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids_react.md +3 -1
  116. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single.html.erb +22 -22
  117. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single.jsx +22 -22
  118. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single_children_only.html.erb +22 -22
  119. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single_children_only.jsx +22 -22
  120. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx +11 -11
  121. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +11 -11
  122. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_form.html.erb +11 -11
  123. data/app/pb_kits/playbook/pb_person/_person.tsx +12 -2
  124. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +9 -9
  125. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +4 -0
  126. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_exclude_countries.html.erb +4 -0
  127. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_exclude_countries.jsx +15 -0
  128. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_exclude_countries.md +1 -0
  129. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_only_countries.jsx +1 -1
  130. data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +4 -3
  131. data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +1 -0
  132. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +3 -0
  133. data/app/pb_kits/playbook/pb_section_separator/_section_separator.tsx +2 -2
  134. data/app/pb_kits/playbook/pb_select/docs/_select_custom_select_subheaders.html.erb +12 -0
  135. data/app/pb_kits/playbook/pb_select/docs/_select_custom_select_subheaders.jsx +31 -0
  136. data/app/pb_kits/playbook/pb_select/docs/_select_custom_select_subheaders.md +1 -0
  137. data/app/pb_kits/playbook/pb_select/docs/example.yml +2 -0
  138. data/app/pb_kits/playbook/pb_select/docs/index.js +1 -0
  139. data/app/pb_kits/playbook/pb_text_input/_text_input.scss +4 -2
  140. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +73 -3
  141. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.jsx +23 -0
  142. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.md +1 -0
  143. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +1 -0
  144. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
  145. data/dist/chunks/_typeahead-CRW6dJbW.js +22 -0
  146. data/dist/chunks/_weekday_stacked-yWpUc_c0.js +45 -0
  147. data/dist/chunks/lazysizes-B7xYodB-.js +1 -0
  148. data/dist/chunks/lib-D5R1BjUn.js +29 -0
  149. data/dist/chunks/{pb_form_validation-BioH7DWv.js → pb_form_validation-BZ2AVAi_.js} +1 -1
  150. data/dist/chunks/vendor.js +1 -1
  151. data/dist/playbook-doc.js +2 -2
  152. data/dist/playbook-rails-react-bindings.js +1 -1
  153. data/dist/playbook-rails.js +1 -1
  154. data/dist/playbook.css +1 -1
  155. data/lib/playbook/kit_base.rb +3 -3
  156. data/lib/playbook/version.rb +2 -2
  157. metadata +52 -8
  158. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.html.erb +0 -10
  159. data/dist/chunks/_typeahead-D62OcwsT.js +0 -22
  160. data/dist/chunks/_weekday_stacked-Ceh9N0ow.js +0 -45
  161. data/dist/chunks/lazysizes-DHz07jlL.js +0 -1
  162. data/dist/chunks/lib-CeKZrPmu.js +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 242dea3f908e8ab1063890e221e4a5a52ab48694d7cba5ce7d20223b05ebece5
4
- data.tar.gz: 2b8a758c373ac4796e6f7bfaf5b1df93f0a0289272df3dd3dbd5c758c84380f9
3
+ metadata.gz: c8e79a2664649f32a2195a4e9199e868f6c1ebac20764479066f12c2dbbd7e9c
4
+ data.tar.gz: da415e2485131587cc6a32a03c8145152df934616500a008ef06b4e49c6c049a
5
5
  SHA512:
6
- metadata.gz: f2aff5a100ae75592c9f06769d1773a5c053b9aaabf107b6861e36c7892d7a8239a7da9fbc82dfbaf1cc37dd58b1dd1ba580390d1e0dd21dcb6f496040ae3f33
7
- data.tar.gz: f144555056550a5abc69c7a9efd94ab207530c7d3263e18da5263cb26382b34f07b55b30a68834617f8e7bf57e5c8e724457e7f77225dbc31aa5a8b625515bcb
6
+ metadata.gz: fd7c9331ca4274f9e6e95d186ada4456ddfa8240d1cc48249dd0b899931bf3db83576abfbfed0ebd4105e2159d57cc9efb75a3a16e2d33cc6a37262dede08746
7
+ data.tar.gz: 9072a56af0c016514dd3a3f3d5b0e20fbdbaea20ca5b25d258f3c31c859fc0d4edc855c58ed297089453525b67df0789c6ff216b9dd500eaa5115664a4bba396
@@ -28,11 +28,14 @@ export const RegularTableView = ({
28
28
  handleExpandOrCollapse,
29
29
  inlineRowLoading,
30
30
  loading,
31
- responsive,
32
31
  table,
33
32
  selectableRows,
34
33
  hasAnySubRows,
35
- stickyLeftColumn
34
+ stickyLeftColumn,
35
+ pinnedRows,
36
+ headerHeight,
37
+ rowHeight,
38
+ sampleRowRef,
36
39
  } = useContext(AdvancedTableContext)
37
40
 
38
41
 
@@ -50,9 +53,81 @@ export const RegularTableView = ({
50
53
  const columnPinning = table.getState().columnPinning || { left: [] };
51
54
  const columnDefinitions = table.options.meta?.columnDefinitions || [];
52
55
 
56
+ // Row pinning
57
+ function PinnedRow({ row }: { row: Row<any> }) {
58
+ return (
59
+ <tr
60
+ className={classnames(
61
+ `pinned-row`,
62
+ )}
63
+ style={{
64
+ backgroundColor: 'white',
65
+ position: 'sticky',
66
+ top:
67
+ row.getIsPinned() === 'top'
68
+ ? `${row.getPinnedIndex() * rowHeight + headerHeight}px`
69
+ : undefined,
70
+ zIndex: '3'
71
+ }}
72
+ >
73
+ {row.getVisibleCells().map((cell: Cell<GenericObject, unknown>, i: number) => {
74
+ const isPinnedLeft = columnPinning.left.includes(cell.column.id);
75
+ const isLastCell = (() => {
76
+ const parent = cell.column.parent;
77
+ if (!parent) {
78
+ const last = row.getVisibleCells().at(-1);
79
+ return last?.column.id === cell.column.id;
80
+ }
81
+
82
+ const visibleSiblings = parent.columns.filter(col => col.getIsVisible());
83
+ return visibleSiblings.at(-1)?.id === cell.column.id;
84
+ })();
85
+
86
+ const { column } = cell;
87
+ return (
88
+ <td
89
+ align="right"
90
+ className={classnames(
91
+ `${cell.id}-cell position_relative`,
92
+ isChrome() ? "chrome-styles" : "",
93
+ isPinnedLeft && 'pinned-left',
94
+ stickyLeftColumn && stickyLeftColumn.length > 0 && isPinnedLeft && 'sticky-left',
95
+ isLastCell && 'last-cell',
96
+ )}
97
+ key={`${cell.id}-data`}
98
+ style={{
99
+ left: isPinnedLeft
100
+ ? i === 1 //Accounting for set min-width for first column
101
+ ? '180px'
102
+ : `${column.getStart("left")}px`
103
+ : undefined,
104
+ }}
105
+ >
106
+ {collapsibleTrail && i === 0 && row.depth > 0 && renderCollapsibleTrail(row.depth)}
107
+ <span id={`${cell.id}-span`}>
108
+ {loading ? (
109
+ <LoadingCell />
110
+ ) : (
111
+ flexRender(cell.column.columnDef.cell, cell.getContext())
112
+ )}
113
+ </span>
114
+ </td>
115
+ );
116
+ })}
117
+ </tr>
118
+ )
119
+ }
120
+
121
+ const totalRows = pinnedRows ? table.getCenterRows() : table.getRowModel().rows
122
+
53
123
  return (
54
124
  <>
55
- {table.getRowModel().rows.map((row: Row<GenericObject>) => {
125
+ {pinnedRows && table.getTopRows().map((row: Row<GenericObject>) => (
126
+ <PinnedRow key={row.id}
127
+ row={row}
128
+ />
129
+ ))}
130
+ {totalRows.map((row: Row<GenericObject>, rowIndex: number) => {
56
131
  const isExpandable = row.getIsExpanded();
57
132
  const isFirstChildofSubrow = row.depth > 0 && row.index === 0;
58
133
  const rowHasNoChildren = row.original?.children && !row.original.children.length ? true : false;
@@ -60,6 +135,7 @@ export const RegularTableView = ({
60
135
  const isDataLoading = isExpandable && (inlineRowLoading && rowHasNoChildren) && (row.depth < columnDefinitions[0]?.cellAccessors?.length);
61
136
  const rowBackground = isExpandable && ((!inlineRowLoading && row.getCanExpand()) || (inlineRowLoading && rowHasNoChildren));
62
137
  const rowColor = row.getIsSelected() ? "bg-row-selection" : rowBackground ? "bg-silver" : "bg-white";
138
+ const isFirstRegularRow = rowIndex === 0 && !row.getIsPinned();
63
139
 
64
140
  return (
65
141
  <React.Fragment key={`${row.index}-${row.id}-${row.depth}-row`}>
@@ -77,6 +153,7 @@ export const RegularTableView = ({
77
153
  <tr
78
154
  className={`${rowColor} ${row.depth > 0 ? `depth-sub-row-${row.depth}` : ""}`}
79
155
  id={`${row.index}-${row.id}-${row.depth}-row`}
156
+ ref={isFirstRegularRow ? sampleRowRef : null}
80
157
  >
81
158
  {/* Render custom checkbox column when we want selectableRows for non-expanding tables */}
82
159
  {selectableRows && !hasAnySubRows && (
@@ -93,7 +170,17 @@ export const RegularTableView = ({
93
170
 
94
171
  {row.getVisibleCells().map((cell: Cell<GenericObject, unknown>, i: number) => {
95
172
  const isPinnedLeft = columnPinning.left.includes(cell.column.id);
96
- const isLastCell = cell.column.parent?.columns?.at(-1)?.id === cell.column.id;
173
+ const isLastCell = (() => {
174
+ const parent = cell.column.parent;
175
+ if (!parent) {
176
+ const last = row.getVisibleCells().at(-1);
177
+ return last?.column.id === cell.column.id;
178
+ }
179
+
180
+ const visibleSiblings = parent.columns.filter(col => col.getIsVisible());
181
+ return visibleSiblings.at(-1)?.id === cell.column.id;
182
+ })();
183
+
97
184
  const { column } = cell;
98
185
  return (
99
186
  <td
@@ -144,4 +231,4 @@ export const RegularTableView = ({
144
231
  );
145
232
  }
146
233
 
147
- export default RegularTableView;
234
+ export default RegularTableView;
@@ -1,52 +1,211 @@
1
- import React, { useEffect, useRef } from "react";
1
+ import React, { useEffect, useRef, useContext, useState } from "react";
2
+
3
+ import AdvancedTableContext from "../Context/AdvancedTableContext";
4
+ import { buildVisibilityTree } from "../Utilities/VisibilityTree";
5
+
2
6
  import Card from "../../pb_card/_card";
3
7
  import Caption from "../../pb_caption/_caption";
4
8
  import Flex from "../../pb_flex/_flex";
5
9
  import FlexItem from "../../pb_flex/_flex_item";
6
- import { showActionBar, hideActionBar } from "../Utilities/ActionBarAnimationHelper";
10
+ import Icon from "../../pb_icon/_icon";
11
+ import Checkbox from "../../pb_checkbox/_checkbox";
12
+ import SectionSeparator from "../../pb_section_separator/_section_separator";
13
+ import Tooltip from "../../pb_tooltip/_tooltip";
14
+ import PbReactPopover from "../../pb_popover/_popover";
15
+
16
+ import {
17
+ showActionBar,
18
+ hideActionBar,
19
+ } from "../Utilities/ActionBarAnimationHelper";
20
+ import { GenericObject } from "../../types";
7
21
 
8
22
  interface TableActionBarProps {
9
- isVisible: boolean;
23
+ isVisible: boolean | GenericObject | undefined;
10
24
  selectedCount: number;
11
25
  actions?: React.ReactNode[] | React.ReactNode;
26
+ type?: string;
27
+ }
28
+
29
+ interface VisibilityNode {
30
+ id?: string | undefined;
31
+ label?: string | undefined;
32
+ children?: VisibilityNode[];
12
33
  }
13
34
 
14
35
  const TableActionBar: React.FC<TableActionBarProps> = ({
15
36
  isVisible,
16
37
  selectedCount,
17
- actions
38
+ actions,
39
+ type = "row-selection",
18
40
  }) => {
19
41
  const cardRef = useRef(null);
42
+ const { table, columnVisibilityControl, columnDefinitions } =
43
+ useContext(AdvancedTableContext);
44
+
45
+ // ----------- Column visibility logic -----------
46
+ const includeIds = columnVisibilityControl?.includeIds;
47
+ const firstLeafId = table.getAllLeafColumns()[0]?.id;
48
+ // Get the first leaf column ID to exclude it from the visibility tree
49
+ // This is to avoid showing the first column in the dropdown
50
+ // as toggling it's visibility breaks the expanded row functionality
51
+ const tree = buildVisibilityTree(columnDefinitions, includeIds).filter(node => node.id !== firstLeafId);
52
+
53
+ const renderLeaf = (id: string, label: string) => {
54
+ const col = table.getColumn(id);
55
+ const show = col.getIsVisible();
56
+
57
+ const handleVisibilityChange = () => {
58
+ col.toggleVisibility();
59
+ if (columnVisibilityControl?.onColumnVisibilityChange) {
60
+ const updatedVisibilityState = {
61
+ ...table.getAllColumns().reduce((acc: { [x: string]: any; }, col: { id: string | number; getIsVisible: () => any; }) => {
62
+ acc[col.id] = col.getIsVisible();
63
+ return acc;
64
+ }, {}),
65
+ };
66
+ columnVisibilityControl?.onColumnVisibilityChange(updatedVisibilityState);
67
+ }
68
+ };
69
+
70
+ return (
71
+ <Checkbox
72
+ checked={show}
73
+ key={id}
74
+ onChange={handleVisibilityChange}
75
+ paddingBottom="xs"
76
+ text={label}
77
+ />
78
+ );
79
+ };
80
+
81
+ const gatherLeafIds = (node: VisibilityNode): string[] =>
82
+ node.children && node.children.length
83
+ ? node.children.flatMap(gatherLeafIds)
84
+ : node.id
85
+ ? [node.id]
86
+ : [];
87
+
88
+ const renderGroup = (node: VisibilityNode ) => {
89
+ const leaves = gatherLeafIds(node);
90
+ const visibleArray = leaves.map((id) => table.getColumn(id).getIsVisible());
91
+ const allOn = visibleArray.every(Boolean);
92
+ const someOn = visibleArray.some(Boolean);
93
+
94
+ const handleGroupVisibilityChange = () => {
95
+ leaves.forEach((id) => table.getColumn(id).toggleVisibility(!allOn));
96
+ if (columnVisibilityControl?.onColumnVisibilityChange) {
97
+ const updatedVisibilityState = {
98
+ ...table.getAllColumns().reduce((acc: { [x: string]: any; }, col: { id: string | number; getIsVisible: () => any; }) => {
99
+ acc[col.id] = col.getIsVisible();
100
+ return acc;
101
+ }, {}),
102
+ };
103
+ columnVisibilityControl?.onColumnVisibilityChange(updatedVisibilityState);
104
+ }
105
+ };
106
+ return (
107
+ <>
108
+ <Checkbox
109
+ checked={allOn}
110
+ indeterminate={!allOn && someOn}
111
+ onChange={handleGroupVisibilityChange}
112
+ paddingBottom="xs"
113
+ text={node.label}
114
+ />
115
+ <Flex flexDirection="column"
116
+ paddingLeft="lg"
117
+ >
118
+ {node?.children?.map((child) =>
119
+ child.children ? renderGroup(child) : renderLeaf(child.id, child.label),
120
+ )}
121
+ </Flex>
122
+ </>
123
+ );
124
+ };
125
+ // ------------ End of column visibility logic --------
20
126
 
21
127
  useEffect(() => {
22
- if (cardRef.current) {
128
+ if (cardRef.current && type === "row-selection") {
23
129
  if (isVisible) {
24
130
  showActionBar(cardRef.current);
25
131
  } else {
26
132
  hideActionBar(cardRef.current);
27
133
  }
28
134
  }
29
- }, [isVisible]);
135
+ }, [isVisible, type]);
136
+
137
+ const [showPopover, setShowPopover] = useState(false)
138
+
139
+ const togglePopover = () => setShowPopover((prev) => !prev)
140
+ const handleShouldClose = (shouldClose: boolean) =>
141
+ setShowPopover(!shouldClose)
142
+
143
+ const popoverReference = (
144
+ <Tooltip
145
+ placement="top"
146
+ text="Column Configuration"
147
+ >
148
+ <div onClick={togglePopover}>
149
+ <Icon
150
+ color="primary"
151
+ cursor="pointer"
152
+ icon="sliders-h"
153
+ />
154
+ </div>
155
+ </Tooltip>
156
+ )
30
157
 
31
158
  return (
32
159
  <Card
33
160
  borderNone={!isVisible}
34
- className={`${isVisible && "show-action-card row-selection-actions-card"}`}
161
+ className={`${
162
+ isVisible && "show-action-card row-selection-actions-card"
163
+ }`}
35
164
  htmlOptions={{ ref: cardRef as any }}
36
165
  padding={`${isVisible ? "xs" : "none"}`}
37
166
  >
38
167
  <Flex
39
168
  alignItems="center"
40
- justify="between"
169
+ justify={type === "row-selection" ? "between" : "end"}
41
170
  >
42
- <Caption
43
- color="light"
44
- paddingLeft="xs"
45
- size="xs"
46
- >
47
- {selectedCount} Selected
48
- </Caption>
49
- <FlexItem>{actions}</FlexItem>
171
+ {type === "row-selection" ? (
172
+ <>
173
+ <Caption color="light"
174
+ paddingLeft="xs"
175
+ size="xs"
176
+ >
177
+ {selectedCount} Selected
178
+ </Caption>
179
+ <FlexItem>{actions}</FlexItem>
180
+ </>
181
+ ) : (
182
+ <PbReactPopover
183
+ closeOnClick="outside"
184
+ placement="bottom-end"
185
+ reference={popoverReference}
186
+ shouldClosePopover={handleShouldClose}
187
+ show={showPopover}
188
+ zIndex={3}
189
+ >
190
+ <>
191
+ <Caption
192
+ paddingY="sm"
193
+ text="Columns Config"
194
+ textAlign="center"
195
+ />
196
+ <SectionSeparator paddingBottom="xs" />
197
+ {tree.map((node: VisibilityNode) => (
198
+ <Flex cursor="pointer"
199
+ flexDirection="column"
200
+ key={node.id}
201
+ paddingX="xs"
202
+ >
203
+ {node.children ? renderGroup(node) : renderLeaf(node.id, node.label)}
204
+ </Flex>
205
+ ))}
206
+ </>
207
+ </PbReactPopover>
208
+ )}
50
209
  </Flex>
51
210
  </Card>
52
211
  );
@@ -1,4 +1,4 @@
1
- import React, { useContext } from "react"
1
+ import React, { useContext, useState } from "react"
2
2
  import classnames from "classnames"
3
3
  import { flexRender, Header, Table, RowModel } from "@tanstack/react-table"
4
4
 
@@ -8,10 +8,8 @@ import { GlobalProps } from "../../utilities/globalProps"
8
8
 
9
9
  import Flex from "../../pb_flex/_flex"
10
10
  import Checkbox from "../../pb_checkbox/_checkbox"
11
- import Dropdown from "../../pb_dropdown/_dropdown"
12
- import DropdownTrigger from "../../pb_dropdown/subcomponents/DropdownTrigger"
13
- import DropdownOption from "../../pb_dropdown/subcomponents/DropdownOption"
14
- import DropdownContainer from "../../pb_dropdown/subcomponents/DropdownContainer"
11
+ import SectionSeparator from "../../pb_section_separator/_section_separator"
12
+ import PbReactPopover from "../../pb_popover/_popover";
15
13
  import Icon from "../../pb_icon/_icon"
16
14
 
17
15
  import { SortIconButton } from "./SortIconButton"
@@ -79,9 +77,26 @@ export const TableHeaderCell = ({
79
77
  header?.column.getLeafColumns().length === 1 &&
80
78
  header?.column.getLeafColumns()[0].id === header.column.id
81
79
 
82
- const isLastHeaderCell =
83
- header?.column.parent?.columns.at(-1) === header?.column ||
84
- (header?.colSpan > 1 && header?.column.parent !== undefined);
80
+ const columnHasVisibleLeaf = (col: any): boolean =>
81
+ col.getIsVisible?.() ||
82
+ (Array.isArray(col.columns) &&
83
+ col.columns.some((child: any) => columnHasVisibleLeaf(child)));
84
+
85
+ // Check on column position in stack + visibility to add the vertical border
86
+ const isLastHeaderCell = (() => {
87
+ if (!header) return false;
88
+
89
+ if (header.colSpan > 1 && header.column.parent !== undefined) return true;
90
+
91
+ const parent = header.column.parent;
92
+
93
+ if (!parent) {
94
+ const topHeaders = table?.getHeaderGroups()[0].headers.filter((h: any) => columnHasVisibleLeaf(h.column));
95
+ return topHeaders?.at(-1)?.id === header.id;
96
+ }
97
+ const visibleSiblings = parent.columns.filter(columnHasVisibleLeaf);
98
+ return visibleSiblings.at(-1) === header.column;
99
+ })();
85
100
 
86
101
  const cellClassName = classnames(
87
102
  "table-header-cells",
@@ -119,6 +134,20 @@ const isToggleExpansionEnabled =
119
134
  justifyHeader = isLeafColumn ? "end" : "center";
120
135
  }
121
136
 
137
+ const [showPopover, setShowPopover] = useState(false)
138
+
139
+ const togglePopover = () => setShowPopover((prev) => !prev)
140
+ const handleShouldClose = (shouldClose: boolean) =>
141
+ setShowPopover(!shouldClose)
142
+
143
+ const popoverReference = (
144
+ <div className="gray-icon toggle-all-icon"
145
+ onClick={togglePopover}
146
+ >
147
+ <Icon icon={displayIcon(toggleExpansionIcon)[0]} />
148
+ </div>
149
+ )
150
+
122
151
  const handleExpandDepth = (depth: number) => {
123
152
  if (onExpandByDepthClick) {
124
153
  const flatRows = table?.getRowModel().flatRows
@@ -174,31 +203,33 @@ const isToggleExpansionEnabled =
174
203
  <ToggleIconButton onClick={handleExpandOrCollapse} />
175
204
  )}
176
205
  {isToggleExpansionEnabled && hasAnySubRows && expandByDepth && (
177
- <Dropdown className="expand-by-depth-dropdown-wrapper"
178
- options={expandByDepth}
179
- >
180
- <DropdownTrigger className="gray-icon toggle-all-icon">
181
- <Icon icon={displayIcon(toggleExpansionIcon)[0]} />
182
- </DropdownTrigger>
183
- <DropdownContainer className="expand-by-depth-dropdown">
184
- {expandByDepth.map((option:{ [key: string]: any }, index: number) => (
185
- <DropdownOption
186
- key={index}
187
- option={option}
188
- padding="none"
206
+
207
+ <PbReactPopover
208
+ closeOnClick="any"
209
+ placement="bottom-start"
210
+ reference={popoverReference}
211
+ shouldClosePopover={handleShouldClose}
212
+ show={showPopover}
213
+ zIndex={3}
189
214
  >
215
+ {expandByDepth.map((option:{ [key: string]: any }, index: number) => (
216
+ <>
190
217
  <Flex
191
218
  alignItems="center"
219
+ className="pb-advanced-table-popover-option"
220
+ cursor="pointer"
192
221
  htmlOptions={{onClick: () => {handleExpandDepth(option.depth)} }}
193
222
  paddingX="sm"
194
223
  paddingY="xs"
195
224
  >
196
225
  {option.label}
197
- </Flex>
198
- </DropdownOption>
199
- ))}
200
- </DropdownContainer>
201
- </Dropdown>
226
+ </Flex>
227
+ {index !== expandByDepth.length - 1 && <SectionSeparator/>}
228
+ </>
229
+ ))}
230
+ </PbReactPopover>
231
+
232
+
202
233
  )}
203
234
 
204
235
  {isToggleExpansionEnabledLoading &&(
@@ -1,4 +1,4 @@
1
- import React, { createContext, useRef, useMemo, useEffect } from 'react';
1
+ import React, { createContext, useRef, useMemo, useEffect, useState, useCallback } from 'react';
2
2
  import { useVirtualizer } from '@tanstack/react-virtual';
3
3
 
4
4
  import { Row } from "@tanstack/react-table";
@@ -23,6 +23,54 @@ export const AdvancedTableProvider = ({ children, ...props }: {
23
23
 
24
24
  const table = props.table;
25
25
  const isVirtualized = props.virtualizedRows || props.enableVirtualization;
26
+
27
+ // Pinned Row: height calculations for Header and Row
28
+ const headerRef = useRef(null);
29
+ const sampleRowRef = useRef(null);
30
+
31
+ const [headerHeight, setHeaderHeight] = useState(44);
32
+ const [rowHeight, setRowHeight] = useState(38);
33
+
34
+ const measureHeights = useCallback(() => {
35
+ if (headerRef.current) {
36
+ const headerRect = headerRef.current.getBoundingClientRect();
37
+ if (headerRect.height > 0) {
38
+ setHeaderHeight(headerRect.height);
39
+ }
40
+ }
41
+ if (sampleRowRef.current) {
42
+ const rowRect = sampleRowRef.current.getBoundingClientRect();
43
+ if (rowRect.height > 0) {
44
+ setRowHeight(rowRect.height);
45
+ }
46
+ }
47
+ }, []);
48
+
49
+ useEffect(() => {
50
+ const resizeObserver = new ResizeObserver(() => {
51
+ measureHeights();
52
+ });
53
+
54
+ if (headerRef.current) {
55
+ resizeObserver.observe(headerRef.current);
56
+ }
57
+
58
+ if (sampleRowRef.current) {
59
+ resizeObserver.observe(sampleRowRef.current);
60
+ }
61
+
62
+ const timeoutId = setTimeout(measureHeights, 100);
63
+
64
+ return () => {
65
+ resizeObserver.disconnect();
66
+ clearTimeout(timeoutId);
67
+ };
68
+ }, [measureHeights]);
69
+
70
+ useEffect(() => {
71
+ measureHeights();
72
+ }, [table?.getRowModel().rows.length, measureHeights]);
73
+
26
74
 
27
75
  // Create a flattened data array that includes ALL components for virtualization
28
76
  const flattenedItems = useMemo(() => {
@@ -132,7 +180,15 @@ export const AdvancedTableProvider = ({ children, ...props }: {
132
180
  virtualizer: isVirtualized ? virtualizer : null,
133
181
  flattenedItems,
134
182
  virtualizedRows: isVirtualized,
135
- enableVirtualization: isVirtualized
183
+ enableVirtualization: isVirtualized,
184
+ rowPinning: props.rowPinning,
185
+ setRowPinning: props.setRowPinning,
186
+ keepPinnedRows: props.keepPinnedRows,
187
+ headerHeight,
188
+ rowHeight,
189
+ headerRef,
190
+ sampleRowRef,
191
+ measureHeights,
136
192
  };
137
193
 
138
194
  return (
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useEffect } from 'react';
2
- import { Row } from "@tanstack/react-table";
2
+ import { Row, RowPinningState } from "@tanstack/react-table";
3
3
  import { GenericObject } from "../../types";
4
4
  import { updateExpandAndCollapseState } from "../Utilities/ExpansionControlHelpers";
5
5
 
@@ -6,7 +6,8 @@ import {
6
6
  getPaginationRowModel,
7
7
  getSortedRowModel,
8
8
  RowSelectionState,
9
- Row
9
+ Row,
10
+ RowPinningState
10
11
  } from "@tanstack/react-table";
11
12
  import { GenericObject } from "../../types";
12
13
  import { createColumnHelper } from "@tanstack/react-table";
@@ -23,9 +24,11 @@ interface UseTableStateProps {
23
24
  loading?: boolean | string;
24
25
  pagination?: boolean;
25
26
  paginationProps?: GenericObject;
27
+ pinnedRows?: any;
26
28
  virtualizedRows?: boolean;
27
29
  tableOptions?: GenericObject;
28
30
  onRowSelectionChange?: (arg: RowSelectionState) => void;
31
+ columnVisibilityControl?: GenericObject;
29
32
  }
30
33
 
31
34
  export function useTableState({
@@ -40,16 +43,25 @@ export function useTableState({
40
43
  pagination = false,
41
44
  paginationProps,
42
45
  virtualizedRows = false,
43
- tableOptions
46
+ tableOptions,
47
+ columnVisibilityControl,
48
+ pinnedRows,
44
49
  }: UseTableStateProps) {
45
50
  // Create a local state for expanded and setExpanded if expandedControl not used
46
51
  const [localExpanded, setLocalExpanded] = useState({});
47
52
  const [loadingStateRowCount, setLoadingStateRowCount] = useState(initialLoadingRowsCount);
48
53
  const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
49
-
54
+ const [localColumnVisibility, setLocalColumnVisibility] = useState({});
55
+ const [localRowPinning, setLocalRowPinning] = useState<RowPinningState>({
56
+ top: [],
57
+ });
50
58
  // Determine whether to use the prop or the local state
51
59
  const expanded = expandedControl ? expandedControl.value : localExpanded;
52
60
  const setExpanded = expandedControl ? expandedControl.onChange : setLocalExpanded;
61
+ const columnVisibility = (columnVisibilityControl && columnVisibilityControl.value) ? columnVisibilityControl.value : localColumnVisibility;
62
+ const setColumnVisibility = (columnVisibilityControl && columnVisibilityControl.onChange) ? columnVisibilityControl.onChange : setLocalColumnVisibility;
63
+ const rowPinning = pinnedRows && pinnedRows.value || localRowPinning;
64
+ const setRowPinning = (pinnedRows && pinnedRows.onChange) ? pinnedRows.onChange : setLocalRowPinning;
53
65
 
54
66
  // Virtualized data handling (chunked loading)
55
67
  const fetchSize = 20; // Number of rows per "page"
@@ -104,17 +116,23 @@ export function useTableState({
104
116
  }]), [columnDefinitions, sortControl]);
105
117
 
106
118
  // Custom state based on features enabled
107
- const customState = useCallback(() => {
108
- if (sortControl && selectableRows) {
109
- return { state: { expanded, sorting, rowSelection } };
110
- } else if (sortControl) {
111
- return { state: { expanded, sorting } };
112
- } else if (selectableRows) {
113
- return { state: { expanded, rowSelection } };
114
- } else {
115
- return { state: { expanded } };
116
- }
117
- }, [expanded, rowSelection, sortControl, selectableRows, sorting]);
119
+ const customState = useCallback(() => ({
120
+ state: {
121
+ expanded,
122
+ ...(sortControl && { sorting }),
123
+ ...(selectableRows && { rowSelection }),
124
+ ...(columnVisibility && { columnVisibility }),
125
+ ...(pinnedRows && { rowPinning }),
126
+ },
127
+ }), [
128
+ expanded,
129
+ sortControl,
130
+ sorting,
131
+ selectableRows,
132
+ rowSelection,
133
+ columnVisibility,
134
+ rowPinning,
135
+ ]);
118
136
 
119
137
  // Pagination configuration
120
138
  const paginationInitializer = useMemo(() => {
@@ -144,7 +162,8 @@ export function useTableState({
144
162
  enableSortingRemoval: false,
145
163
  sortDescFirst: true,
146
164
  onRowSelectionChange: setRowSelection,
147
- getRowId: selectableRows ? row => row.id : undefined,
165
+ getRowId: (selectableRows || pinnedRows) ? row => row.id : undefined,
166
+ onColumnVisibilityChange: setColumnVisibility,
148
167
  meta: {
149
168
  columnDefinitions
150
169
  },