playbook_ui 14.21.2.pre.alpha.PLAY2020sidebarfilterPOC8265 → 14.21.2.pre.alpha.PLAY2179playbookiconsupdate8389

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +5 -2
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +20 -4
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +25 -5
  5. data/app/pb_kits/playbook/pb_advanced_table/Components/VirtualizedTableView.tsx +36 -16
  6. data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +18 -5
  7. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +37 -17
  8. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +5 -2
  9. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +3 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +91 -40
  11. data/app/pb_kits/playbook/pb_advanced_table/Utilities/CellRendererUtils.tsx +4 -1
  12. data/app/pb_kits/playbook/pb_advanced_table/Utilities/ColumnStylingHelper.ts +15 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/Utilities/TableContainerStyles.ts +3 -2
  14. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +49 -4
  15. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +36 -18
  16. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +105 -2
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb +1 -1
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_subrow_headers.html.erb +1 -1
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_border_color_rails.html.erb +1 -1
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.jsx +51 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.md +7 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers.jsx +77 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers.md +1 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers_rails.html.erb +63 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers_rails.md +1 -0
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_rails.html.erb +38 -0
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_rails.md +7 -0
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_infinite_scroll.md +3 -0
  29. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_loading.html.erb +1 -1
  30. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_row_styling.jsx +64 -0
  31. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_row_styling.md +7 -0
  32. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions.jsx +2 -2
  33. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions_rails.html.erb +3 -2
  34. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.html.erb +1 -1
  35. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +6 -0
  36. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +4 -0
  37. data/app/pb_kits/playbook/pb_advanced_table/index.js +21 -0
  38. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +1 -1
  39. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +5 -0
  40. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +2 -2
  41. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +33 -0
  42. data/dist/chunks/_typeahead-BXD634Vm.js +22 -0
  43. data/dist/chunks/_weekday_stacked--dPf0i--.js +45 -0
  44. data/dist/chunks/lazysizes-B7xYodB-.js +1 -0
  45. data/dist/chunks/lib-9VvC3Rp0.js +29 -0
  46. data/dist/chunks/{pb_form_validation-DSkdRDMf.js → pb_form_validation-CbyL4Bqa.js} +1 -1
  47. data/dist/chunks/vendor.js +1 -1
  48. data/dist/playbook-doc.js +3 -3
  49. data/dist/playbook-rails-react-bindings.js +1 -1
  50. data/dist/playbook-rails.js +1 -1
  51. data/dist/playbook.css +1 -1
  52. data/lib/playbook/version.rb +1 -1
  53. metadata +19 -7
  54. data/dist/chunks/_typeahead-CoOpeYom.js +0 -22
  55. data/dist/chunks/_weekday_stacked-BitxTXxk.js +0 -45
  56. data/dist/chunks/lazysizes-DHz07jlL.js +0 -1
  57. data/dist/chunks/lib-D7Va7yqa.js +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 110027cf4b6fc7f41901f5d8a95eeee3cabd472a0f64d95870e83cac6155d44f
4
- data.tar.gz: 96c09cbb3a87483920bfd554a727e6663767bc3447cc2e363af5adcb09d6a5c7
3
+ metadata.gz: 0bd6938603e3b7ea37cd0dfa7a480f3ee6f27a9df349325f0f755ffe5254fd5c
4
+ data.tar.gz: c7d9933a4f2fd4b525d4b570d47ff79274f2a3ddecf7b0f42273b09f9b45c31f
5
5
  SHA512:
6
- metadata.gz: 14c26029d6c5254a2f62b2ea222c4cd5d06ffb3e6586d36d506dfaeed57c4f824e41418e9ce5533838e720d94c1257bace7f55a78da5a2d6ee6dd6768d066fdf
7
- data.tar.gz: 0cd5c076dfb211d337b2de733d3b4a94b09c208b00261b74bcd2eeae88c255b59cd6849025ad1f3548be3f1a910244d6b8e6f689dd413b210a8903855b656a90
6
+ metadata.gz: a8a312ffe4b64d4c8022434a53a616a1d5dc764a84d9f61ffab69117a2039dbe56ce674e71a561019a71e1be09014c858e85e252db2cfe59e20d212eb68e9487
7
+ data.tar.gz: edb82b3cf90dac74c811461b13bce6c530382efaed70ca641c1214bcc1d25cd5781debe9d8f79748f936fbc402f1eff7823fa36c125d013b4be49dd223576632
@@ -19,6 +19,7 @@ interface CustomCellProps {
19
19
  value?: string
20
20
  customRenderer?: (row: Row<GenericObject>, value: string | undefined) => React.ReactNode
21
21
  selectableRows?: boolean
22
+ customStyle?: GenericObject
22
23
  }
23
24
 
24
25
  export const CustomCell = ({
@@ -28,6 +29,7 @@ export const CustomCell = ({
28
29
  value,
29
30
  customRenderer,
30
31
  selectableRows,
32
+ customStyle = {},
31
33
  }: CustomCellProps & GlobalProps) => {
32
34
  const { setExpanded, expanded, expandedControl, inlineRowLoading, hasAnySubRows } = useContext(AdvancedTableContext);
33
35
 
@@ -43,11 +45,11 @@ export const CustomCell = ({
43
45
  const renderButton = inlineRowLoading ? RowHasChildren : row.getCanExpand()
44
46
 
45
47
  return (
46
- <div style={{ paddingLeft: `${row.depth * 1.25}em` }}>
48
+ <div style={{ paddingLeft: `${row.depth * 1.25}em`}}>
47
49
  <Flex
48
50
  alignItems="center"
49
51
  columnGap="xs"
50
- justify={"start"}
52
+ justify="start"
51
53
  orientation="row"
52
54
  >
53
55
  {
@@ -65,6 +67,7 @@ export const CustomCell = ({
65
67
  <button
66
68
  className="gray-icon expand-toggle-icon"
67
69
  onClick={() => handleOnExpand(row)}
70
+ style={{ color: customStyle?.expandButtonColor }}
68
71
  >
69
72
  {row.getIsExpanded() ? (
70
73
  <Icon cursor="pointer"
@@ -4,6 +4,7 @@ import { flexRender, Row, Cell } from "@tanstack/react-table"
4
4
 
5
5
  import { GenericObject } from "../../types"
6
6
  import { isChrome } from "../Utilities/BrowserCheck"
7
+ import { findColumnDefByAccessor } from "../Utilities/ColumnStylingHelper"
7
8
 
8
9
  import LoadingInline from "../../pb_loading_inline/_loading_inline"
9
10
  import Checkbox from "../../pb_checkbox/_checkbox"
@@ -25,13 +26,17 @@ const TableCellRenderer = ({
25
26
  collapsibleTrail = true,
26
27
  loading = false,
27
28
  stickyLeftColumn,
28
- columnPinning
29
+ columnPinning,
30
+ customRowStyle,
31
+ columnDefinitions,
29
32
  }: {
30
33
  row: Row<GenericObject>
31
34
  collapsibleTrail?: boolean
32
35
  loading?: boolean | string
33
36
  stickyLeftColumn?: string[]
34
37
  columnPinning: { left: string[] }
38
+ customRowStyle?: GenericObject
39
+ columnDefinitions?: {[key:string]:any}[]
35
40
  }) => {
36
41
  return (
37
42
  <>
@@ -49,10 +54,14 @@ const TableCellRenderer = ({
49
54
  })();
50
55
 
51
56
  const { column } = cell;
52
-
57
+
58
+ // Find the “owning” colDefinition by accessor. Needed for multi column logic
59
+ const colDef = findColumnDefByAccessor(columnDefinitions ?? [], column.id)
60
+ const cellAlignment = colDef?.columnStyling?.cellAlignment ?? "right"
61
+
53
62
  return (
54
63
  <td
55
- align="right"
64
+ align={cellAlignment}
56
65
  className={classnames(
57
66
  `${cell.id}-cell position_relative`,
58
67
  isChrome() ? "chrome-styles" : "",
@@ -67,6 +76,8 @@ const TableCellRenderer = ({
67
76
  ? '180px'
68
77
  : `${column.getStart("left")}px`
69
78
  : undefined,
79
+ backgroundColor: i === 0 && customRowStyle?.backgroundColor,
80
+ color: customRowStyle?.fontColor,
70
81
  }}
71
82
  >
72
83
  {collapsibleTrail && i === 0 && row.depth > 0 && renderCollapsibleTrail(row.depth)}
@@ -100,6 +111,7 @@ export const RegularTableView = ({
100
111
  pinnedRows,
101
112
  headerHeight,
102
113
  rowHeight,
114
+ rowStyling = [],
103
115
  sampleRowRef,
104
116
  } = useContext(AdvancedTableContext)
105
117
 
@@ -117,7 +129,6 @@ export const RegularTableView = ({
117
129
 
118
130
  const columnPinning = table.getState().columnPinning || { left: [] };
119
131
  const columnDefinitions = table.options.meta?.columnDefinitions || [];
120
-
121
132
  // Row pinning
122
133
  function PinnedRow({ row }: { row: Row<any> }) {
123
134
  return (
@@ -137,6 +148,7 @@ export const RegularTableView = ({
137
148
  >
138
149
  <TableCellRenderer
139
150
  collapsibleTrail={collapsibleTrail}
151
+ columnDefinitions={columnDefinitions}
140
152
  columnPinning={columnPinning}
141
153
  loading={loading}
142
154
  row={row}
@@ -164,6 +176,7 @@ export const RegularTableView = ({
164
176
  const rowBackground = isExpandable && ((!inlineRowLoading && row.getCanExpand()) || (inlineRowLoading && rowHasNoChildren));
165
177
  const rowColor = row.getIsSelected() ? "bg-row-selection" : rowBackground ? "bg-silver" : "bg-white";
166
178
  const isFirstRegularRow = rowIndex === 0 && !row.getIsPinned();
179
+ const customRowStyle = rowStyling?.length > 0 && rowStyling?.find((s: GenericObject) => s?.rowId === row.id);
167
180
 
168
181
  return (
169
182
  <React.Fragment key={`${row.index}-${row.id}-${row.depth}-row`}>
@@ -182,6 +195,7 @@ export const RegularTableView = ({
182
195
  className={`${rowColor} ${row.depth > 0 ? `depth-sub-row-${row.depth}` : ""}`}
183
196
  id={`${row.index}-${row.id}-${row.depth}-row`}
184
197
  ref={isFirstRegularRow ? sampleRowRef : null}
198
+ style={{backgroundColor: customRowStyle?.backgroundColor, color: customRowStyle?.fontColor}}
185
199
  >
186
200
  {/* Render custom checkbox column when we want selectableRows for non-expanding tables */}
187
201
  {selectableRows && !hasAnySubRows && (
@@ -197,7 +211,9 @@ export const RegularTableView = ({
197
211
  )}
198
212
  <TableCellRenderer
199
213
  collapsibleTrail={collapsibleTrail}
214
+ columnDefinitions={columnDefinitions}
200
215
  columnPinning={columnPinning}
216
+ customRowStyle={customRowStyle}
201
217
  loading={loading}
202
218
  row={row}
203
219
  stickyLeftColumn={stickyLeftColumn}
@@ -15,6 +15,7 @@ import Icon from "../../pb_icon/_icon"
15
15
  import { SortIconButton } from "./SortIconButton"
16
16
  import { ToggleIconButton } from "./ToggleIconButton"
17
17
  import { displayIcon } from "../Utilities/IconHelpers"
18
+ import { findColumnDefByAccessor } from "../Utilities/ColumnStylingHelper"
18
19
  import { updateExpandAndCollapseState } from "../Utilities/ExpansionControlHelpers"
19
20
 
20
21
  import { isChrome } from "../Utilities/BrowserCheck"
@@ -45,6 +46,7 @@ export const TableHeaderCell = ({
45
46
  table
46
47
  }: TableHeaderCellProps) => {
47
48
  const {
49
+ columnDefinitions,
48
50
  expanded,
49
51
  setExpanded,
50
52
  expandByDepth,
@@ -72,6 +74,18 @@ export const TableHeaderCell = ({
72
74
  header?.column.getToggleSortingHandler()(event)
73
75
  }
74
76
  }
77
+ const alignmentMap: Record<string, "start" | "center" | "end"> = {
78
+ left: "start",
79
+ center: "center",
80
+ right: "end",
81
+ };
82
+
83
+ // Look up the “owning” columnDefinition by accessor. Needed for multi column logic
84
+ const colDef = header
85
+ ? findColumnDefByAccessor(columnDefinitions, header.column.id)
86
+ : undefined
87
+
88
+ const headerAlignment = colDef?.columnStyling?.headerAlignment ?? colDef?.columnStyling?.headerAligment
75
89
 
76
90
  const isLeafColumn =
77
91
  header?.column.getLeafColumns().length === 1 &&
@@ -126,9 +140,15 @@ const isToggleExpansionEnabled =
126
140
  (enableToggleExpansion === "all" || "header") &&
127
141
  enableToggleExpansion !== "none"
128
142
 
129
- let justifyHeader:justifyTypes;
143
+ let justifyHeader: justifyTypes;
130
144
 
131
- if (header?.index === 0 && hasAnySubRows || (header?.index === 0 && inlineRowLoading) || (header?.index === 0 && isToggleExpansionEnabled)) {
145
+ if (headerAlignment && alignmentMap[headerAlignment]) {
146
+ justifyHeader = alignmentMap[headerAlignment];
147
+ } else if (
148
+ (header?.index === 0 && hasAnySubRows) ||
149
+ (header?.index === 0 && inlineRowLoading) ||
150
+ (header?.index === 0 && isToggleExpansionEnabled)
151
+ ) {
132
152
  justifyHeader = enableSorting ? "between" : "start";
133
153
  } else {
134
154
  justifyHeader = isLeafColumn ? "end" : "center";
@@ -165,7 +185,7 @@ const isToggleExpansionEnabled =
165
185
 
166
186
  return (
167
187
  <th
168
- align="right"
188
+ align={headerAlignment ? headerAlignment : "right"}
169
189
  className={cellClassName}
170
190
  colSpan={header?.colSpan}
171
191
  id={cellId}
@@ -253,8 +273,8 @@ const isToggleExpansionEnabled =
253
273
  tabIndex: 0,
254
274
  },
255
275
  })}
256
- justify={header?.index === 0 && enableSorting ? "between" : "none"}
257
- paddingLeft={enableSorting ? "xxs" : "xs"}
276
+ justify={header?.index === 0 && enableSorting ? "between" : headerAlignment ? alignmentMap[headerAlignment] : "none"}
277
+ paddingLeft={header?.index === 0 ? enableSorting ? "xxs" : "xs" : "none"}
258
278
  >
259
279
  <div>
260
280
  {flexRender(header?.column.columnDef.header, header?.getContext())}
@@ -1,6 +1,6 @@
1
- import React, { useContext, useLayoutEffect, useState, useEffect } from "react"
1
+ import React, { useContext, useLayoutEffect, useState, useEffect, useRef } from "react"
2
2
  import classnames from "classnames"
3
- import { flexRender, Cell } from "@tanstack/react-table"
3
+ import { flexRender, Cell, Row } from "@tanstack/react-table"
4
4
  import { VirtualItem } from "@tanstack/react-virtual"
5
5
 
6
6
  import { GenericObject } from "../../types"
@@ -10,6 +10,8 @@ import { getVirtualizedRowStyle } from "../Utilities/TableContainerStyles"
10
10
 
11
11
  import LoadingInline from "../../pb_loading_inline/_loading_inline"
12
12
  import Checkbox from "../../pb_checkbox/_checkbox"
13
+ import Detail from "../../pb_detail/_detail"
14
+ import Flex from "../../pb_flex/_flex"
13
15
 
14
16
  import { SubRowHeaderRow } from "../Components/SubRowHeaderRow"
15
17
  import { LoadingCell } from "../Components/LoadingCell"
@@ -20,11 +22,13 @@ import AdvancedTableContext from "../Context/AdvancedTableContext"
20
22
  type VirtualizedTableViewProps = {
21
23
  collapsibleTrail?: boolean
22
24
  subRowHeaders?: string[]
25
+ isFetching: boolean
23
26
  }
24
27
 
25
28
  export const VirtualizedTableView = ({
26
29
  collapsibleTrail = true,
27
30
  subRowHeaders,
31
+ isFetching,
28
32
  }: VirtualizedTableViewProps) => {
29
33
  const {
30
34
  enableToggleExpansion,
@@ -36,6 +40,7 @@ export const VirtualizedTableView = ({
36
40
  hasAnySubRows,
37
41
  virtualizer,
38
42
  flattenedItems,
43
+ totalAvailableCount,
39
44
  } = useContext(AdvancedTableContext)
40
45
 
41
46
  const columnPinning = table.getState().columnPinning || { left: [] };
@@ -121,19 +126,7 @@ export const VirtualizedTableView = ({
121
126
  }
122
127
 
123
128
  // Get virtual items
124
- let virtualItems: VirtualItem[] = [];
125
- try {
126
- virtualItems = virtualizer.getVirtualItems();
127
- } catch (err) {
128
- return (
129
- <tr>
130
- <td colSpan={table.getAllFlatColumns().length || 1}>
131
- Error loading virtualized data.
132
- </td>
133
- </tr>
134
- );
135
- }
136
-
129
+ const virtualItems: VirtualItem[] = virtualizer.getVirtualItems?.() || [];
137
130
  if (!virtualItems.length) {
138
131
  return (
139
132
  <tr>
@@ -143,6 +136,9 @@ export const VirtualizedTableView = ({
143
136
  </tr>
144
137
  );
145
138
  }
139
+
140
+ // Establish # of Parent Rows (so that Footer count does not include every single row)
141
+ const topLevelRowCount = table.getRowModel().flatRows.filter((row: Row<GenericObject>) => row.depth === 0).length;
146
142
 
147
143
  return (
148
144
  <>
@@ -177,7 +173,7 @@ export const VirtualizedTableView = ({
177
173
  if (item.type === 'row') {
178
174
  const row = item.row;
179
175
  const isExpandable = row.getIsExpanded();
180
- const rowHasNoChildren = row.original?.children && !row.original.children.length ? true : false;
176
+ const rowHasNoChildren = row.original?.children && !row.original.children.length;
181
177
  const rowBackground = isExpandable && ((!inlineRowLoading && row.getCanExpand()) || (inlineRowLoading && rowHasNoChildren));
182
178
  const rowColor = row.getIsSelected() ? "bg-row-selection" : rowBackground ? "bg-silver" : "bg-white";
183
179
 
@@ -266,6 +262,30 @@ export const VirtualizedTableView = ({
266
262
  );
267
263
  }
268
264
 
265
+ if (item.type === 'footer') {
266
+ // Render footer
267
+ return (
268
+ <tr
269
+ className="virtualized-table-row virtualized-footer"
270
+ key={`footer-row`}
271
+ style={virtualItemStyle}
272
+ >
273
+ <td colSpan={table.getAllFlatColumns().length}>
274
+ <Flex align="center"
275
+ justify="center"
276
+ >
277
+
278
+ {isFetching ? (
279
+ <LoadingInline />
280
+ ) : (
281
+ <Detail text={`Showing ${topLevelRowCount} of ${totalAvailableCount} rows`} />
282
+ )}
283
+ </Flex>
284
+ </td>
285
+ </tr>
286
+ )
287
+ }
288
+
269
289
  return null;
270
290
  })}
271
291
  </>
@@ -8,7 +8,7 @@ import { getRowHeightEstimate } from '../Utilities/TableContainerStyles';
8
8
  const AdvancedTableContext = createContext<any>({});
9
9
 
10
10
  interface FlattenedItem {
11
- type: 'header' | 'row' | 'loading';
11
+ type: 'header' | 'row' | 'loading' | 'footer';
12
12
  row: Row<GenericObject>;
13
13
  id: string;
14
14
  }
@@ -116,6 +116,17 @@ export const AdvancedTableProvider = ({ children, ...props }: {
116
116
  }
117
117
  });
118
118
 
119
+ const isFetching = props.isFetching || false;
120
+ const shouldAddFooter = table && !isFetching && tableRows.length > 0
121
+
122
+ if (shouldAddFooter) {
123
+ items.push({
124
+ type: 'footer',
125
+ row: {} as Row<GenericObject>,
126
+ id: `footer-row`,
127
+ });
128
+ }
129
+
119
130
  return items;
120
131
  }, [
121
132
  isVirtualized,
@@ -159,10 +170,11 @@ export const AdvancedTableProvider = ({ children, ...props }: {
159
170
  useEffect(() => {
160
171
  if (isVirtualized && virtualizer && table && containerRef.current) {
161
172
  // Force recalculation of all virtual items
173
+ virtualizer.setOptions({
174
+ ...virtualizer.options,
175
+ count: flattenedItems.length,
176
+ });
162
177
  virtualizer.measure();
163
-
164
- // Reset scroll position when sorting changes
165
- containerRef.current.scrollTop = 0;
166
178
  }
167
179
  }, [
168
180
  isVirtualized,
@@ -170,7 +182,8 @@ export const AdvancedTableProvider = ({ children, ...props }: {
170
182
  table,
171
183
  containerRef,
172
184
  JSON.stringify(table?.getState().sorting || []),
173
- JSON.stringify(table?.getState().expanded || {})
185
+ JSON.stringify(table?.getState().expanded || {}),
186
+ flattenedItems.length,
174
187
  ]);
175
188
 
176
189
  const contextValue = {
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect } from 'react';
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { Row, RowPinningState } from "@tanstack/react-table";
3
3
  import { GenericObject } from "../../types";
4
4
  import { updateExpandAndCollapseState } from "../Utilities/ExpansionControlHelpers";
@@ -19,13 +19,21 @@ export function useTableActions({
19
19
  onRowSelectionChange
20
20
  }: UseTableActionsProps) {
21
21
 
22
+ // State to achieve 1 second delay before fetching more rows
23
+ const [bottomReached, setBottomReached] = useState(false)
24
+ const bottomTimeout = useRef<NodeJS.Timeout | null>(null)
25
+
22
26
  // Handle expand/collapse
23
27
  const handleExpandOrCollapse = useCallback(async (row: Row<GenericObject>) => {
24
- onToggleExpansionClick && onToggleExpansionClick(row);
25
- const expandedState = expanded;
26
- const targetParent = row?.parentId;
27
- const updatedRows = await updateExpandAndCollapseState(table.getRowModel(), expandedState, targetParent, undefined);
28
- setExpanded(updatedRows);
28
+ if (onToggleExpansionClick) onToggleExpansionClick(row)
29
+ const updatedExpandedState = await updateExpandAndCollapseState(
30
+ table.getRowModel(),
31
+ expanded,
32
+ row?.parentId,
33
+ undefined
34
+ )
35
+
36
+ setExpanded(updatedExpandedState)
29
37
  }, [expanded, setExpanded, onToggleExpansionClick, table]);
30
38
 
31
39
  // Handle pagination
@@ -35,20 +43,32 @@ export function useTableActions({
35
43
 
36
44
  // Handle scroll detection for infinite scroll/virtualization
37
45
  const fetchMoreOnBottomReached = useCallback((
38
- containerRefElement: HTMLDivElement | null,
39
- fetchNextPage: () => void,
40
- isFetching: boolean,
41
- totalFetched: number,
42
- totalDBRowCount: number
46
+ containerRef: HTMLDivElement | null,
47
+ fetchNextPage: () => void,
48
+ isFetching: boolean,
49
+ totalFetched: number,
50
+ totalDBRowCount: number
43
51
  ) => {
44
- if (containerRefElement) {
45
- const { scrollHeight, scrollTop, clientHeight } = containerRefElement;
46
- // If user scrolls near bottom, fetch more data
47
- if (scrollHeight - scrollTop - clientHeight < 500 && !isFetching && totalFetched < totalDBRowCount) {
48
- fetchNextPage();
52
+ if (!containerRef || isFetching || totalFetched >= totalDBRowCount) return
53
+ const { scrollTop, scrollHeight, clientHeight } = containerRef
54
+ const distanceFromBottom = scrollHeight - scrollTop - clientHeight
55
+ // If user scrolls near bottom, fetch more data after 1 second delay
56
+ if (distanceFromBottom < 50) {
57
+ if (!bottomReached) {
58
+ setBottomReached(true)
59
+ bottomTimeout.current = setTimeout(() => {
60
+ fetchNextPage()
61
+ setBottomReached(false)
62
+ }, 1000)
63
+ }
64
+ } else {
65
+ setBottomReached(false)
66
+ if (bottomTimeout.current) {
67
+ clearTimeout(bottomTimeout.current)
68
+ bottomTimeout.current = null
49
69
  }
50
70
  }
51
- }, []);
71
+ },[bottomReached]);
52
72
 
53
73
  // Update selection state
54
74
  useEffect(() => {
@@ -32,6 +32,7 @@ interface UseTableStateProps {
32
32
  tableOptions?: GenericObject;
33
33
  onRowSelectionChange?: (arg: RowSelectionState) => void;
34
34
  columnVisibilityControl?: GenericObject;
35
+ rowStyling?: GenericObject;
35
36
  }
36
37
 
37
38
  export function useTableState({
@@ -49,6 +50,7 @@ export function useTableState({
49
50
  tableOptions,
50
51
  columnVisibilityControl,
51
52
  pinnedRows,
53
+ rowStyling
52
54
  }: UseTableStateProps) {
53
55
  // Create a local state for expanded and setExpanded if expandedControl not used
54
56
  const [localExpanded, setLocalExpanded] = useState({});
@@ -102,7 +104,8 @@ export function useTableState({
102
104
  column.customRenderer,
103
105
  isFirstColumn,
104
106
  onRowToggleClick,
105
- selectableRows
107
+ selectableRows,
108
+ rowStyling
106
109
  );
107
110
  }
108
111
 
@@ -165,7 +168,7 @@ export function useTableState({
165
168
  enableSortingRemoval: false,
166
169
  sortDescFirst: true,
167
170
  onRowSelectionChange: setRowSelection,
168
- getRowId: (selectableRows || pinnedRows) ? row => row.id : undefined,
171
+ getRowId: (selectableRows || pinnedRows || rowStyling) ? row => row.id : undefined,
169
172
  onColumnVisibilityChange: setColumnVisibility,
170
173
  meta: {
171
174
  columnDefinitions
@@ -16,6 +16,7 @@ type TableBodyProps = {
16
16
  dark?: boolean
17
17
  id?: string
18
18
  subRowHeaders?: string[]
19
+ isFetching: boolean
19
20
  }
20
21
 
21
22
  export const TableBody = ({
@@ -24,6 +25,7 @@ export const TableBody = ({
24
25
  dark = false,
25
26
  id,
26
27
  subRowHeaders,
28
+ isFetching,
27
29
  ...props
28
30
  }: TableBodyProps) => {
29
31
 
@@ -63,6 +65,7 @@ export const TableBody = ({
63
65
  // Virtualized table view
64
66
  <VirtualizedTableView
65
67
  collapsibleTrail={collapsibleTrail}
68
+ isFetching={isFetching}
66
69
  subRowHeaders={subRowHeaders}
67
70
  />
68
71
  ) : (
@@ -40,9 +40,13 @@ export const TableHeader = ({
40
40
  showActionsBar,
41
41
  selectableRows,
42
42
  responsive,
43
- headerRef
43
+ headerRef,
44
+ virtualizedRows,
45
+ enableVirtualization,
44
46
  } = useContext(AdvancedTableContext)
45
47
 
48
+ const isVirtualized = virtualizedRows || enableVirtualization;
49
+
46
50
  const classes = classnames(
47
51
  buildCss("pb_advanced_table_header"),
48
52
  globalProps(props),
@@ -57,46 +61,93 @@ export const TableHeader = ({
57
61
  `${isChrome() ? "chrome-styles" : ""}`,
58
62
  `${responsive === "scroll" && "pinned-left"}`,
59
63
  );
64
+
65
+ const renderRegularTableHeader = () => (
66
+ <thead className={classes}
67
+ id={id}
68
+ >
69
+ {table.getHeaderGroups().map((headerGroup: HeaderGroup<GenericObject>, index: number) => (
70
+ <tr
71
+ key={`${headerGroup.id}-headerGroup`}
72
+ ref={index === 0 ? headerRef : null}
73
+ >
74
+ {!hasAnySubRows && selectableRows && (
75
+ <th className={customCellClassnames}>
76
+ <Checkbox
77
+ checked={table?.getIsAllRowsSelected()}
78
+ indeterminate={table?.getIsSomeRowsSelected()}
79
+ onChange={table?.getToggleAllRowsSelectedHandler()}
80
+ />
81
+ </th>
82
+ )}
83
+ {headerGroup.headers.map(header => {
84
+ const isPinnedLeft = columnPinning.left.includes(header.id)
85
+ return (
86
+ <TableHeaderCell
87
+ enableSorting={enableSorting}
88
+ enableToggleExpansion={enableToggleExpansion}
89
+ handleExpandOrCollapse={handleExpandOrCollapse}
90
+ header={header}
91
+ headerChildren={children}
92
+ isPinnedLeft={isPinnedLeft}
93
+ key={`${header.id}-header`}
94
+ loading={loading}
95
+ sortIcon={sortIcon}
96
+ table={table}
97
+ />
98
+ )
99
+ })}
100
+ </tr>
101
+ ))}
102
+ </thead>
103
+ );
104
+
105
+ const renderVirtualizedTableHeader = () => (
106
+ <thead
107
+ className={classes}
108
+ data-virtualized="true"
109
+ id={id}
110
+ >
111
+ {table.getHeaderGroups().map((headerGroup: HeaderGroup<GenericObject>, index: number) => (
112
+ <tr
113
+ className="virtualized-header-row-header"
114
+ key={`${headerGroup.id}-headerGroup-virtualized`}
115
+ ref={index === 0 ? headerRef : null}
116
+ >
117
+ {!hasAnySubRows && selectableRows && (
118
+ <th className={classnames(customCellClassnames, "virtualized-header-cell")}>
119
+ <Checkbox
120
+ checked={table?.getIsAllRowsSelected()}
121
+ indeterminate={table?.getIsSomeRowsSelected()}
122
+ onChange={table?.getToggleAllRowsSelectedHandler()}
123
+ />
124
+ </th>
125
+ )}
126
+ {headerGroup.headers.map(header => {
127
+ const isPinnedLeft = columnPinning.left.includes(header.id)
128
+ return (
129
+ <TableHeaderCell
130
+ enableSorting={enableSorting}
131
+ enableToggleExpansion={enableToggleExpansion}
132
+ handleExpandOrCollapse={handleExpandOrCollapse}
133
+ header={header}
134
+ headerChildren={children}
135
+ isPinnedLeft={isPinnedLeft}
136
+ isVirtualized
137
+ key={`${header.id}-header-virtualized`}
138
+ loading={loading}
139
+ sortIcon={sortIcon}
140
+ table={table}
141
+ />
142
+ )
143
+ })}
144
+ </tr>
145
+ ))}
146
+ </thead>
147
+ );
60
148
  return (
61
- <>
62
- <thead className={classes}
63
- id={id}
64
- >
65
- {/* Get the header groups (only one in this example) */}
66
- {table.getHeaderGroups().map((headerGroup: HeaderGroup<GenericObject>, index: number) => (
67
- <tr
68
- key={`${headerGroup.id}-headerGroup`}
69
- ref={index === 0 ? headerRef : null}
70
- >
71
- {!hasAnySubRows && selectableRows && (
72
- <th className={customCellClassnames}>
73
- <Checkbox
74
- checked={table?.getIsAllRowsSelected()}
75
- indeterminate={table?.getIsSomeRowsSelected()}
76
- onChange={table?.getToggleAllRowsSelectedHandler()}
77
- />
78
- </th>
79
- )}
80
- {headerGroup.headers.map(header => {
81
- const isPinnedLeft = columnPinning.left.includes(header.id)
82
- return (
83
- <TableHeaderCell
84
- enableSorting={enableSorting}
85
- enableToggleExpansion={enableToggleExpansion}
86
- handleExpandOrCollapse={handleExpandOrCollapse}
87
- header={header}
88
- headerChildren={children}
89
- isPinnedLeft={isPinnedLeft}
90
- key={`${header.id}-header`}
91
- loading={loading}
92
- sortIcon={sortIcon}
93
- table={table}
94
- />
95
- )
96
- })}
97
- </tr>
98
- ))}
99
- </thead>
149
+ <>
150
+ {isVirtualized ? renderVirtualizedTableHeader() : renderRegularTableHeader()}
100
151
  </>
101
152
  )
102
153
  }