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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +5 -2
- data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +20 -4
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +25 -5
- data/app/pb_kits/playbook/pb_advanced_table/Components/VirtualizedTableView.tsx +36 -16
- data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +18 -5
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +37 -17
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +5 -2
- data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +91 -40
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/CellRendererUtils.tsx +4 -1
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/ColumnStylingHelper.ts +15 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/TableContainerStyles.ts +3 -2
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +49 -4
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +36 -18
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +105 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_subrow_headers.html.erb +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_border_color_rails.html.erb +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.jsx +51 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.md +7 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers.jsx +77 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers_rails.html.erb +63 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers_rails.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_rails.html.erb +38 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_rails.md +7 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_infinite_scroll.md +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_loading.html.erb +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_row_styling.jsx +64 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_row_styling.md +7 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions.jsx +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions_rails.html.erb +3 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.html.erb +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +6 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +4 -0
- data/app/pb_kits/playbook/pb_advanced_table/index.js +21 -0
- data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +33 -0
- data/dist/chunks/_typeahead-BXD634Vm.js +22 -0
- data/dist/chunks/_weekday_stacked--dPf0i--.js +45 -0
- data/dist/chunks/lazysizes-B7xYodB-.js +1 -0
- data/dist/chunks/lib-9VvC3Rp0.js +29 -0
- data/dist/chunks/{pb_form_validation-DSkdRDMf.js → pb_form_validation-CbyL4Bqa.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-doc.js +3 -3
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +19 -7
- data/dist/chunks/_typeahead-CoOpeYom.js +0 -22
- data/dist/chunks/_weekday_stacked-BitxTXxk.js +0 -45
- data/dist/chunks/lazysizes-DHz07jlL.js +0 -1
- data/dist/chunks/lib-D7Va7yqa.js +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0bd6938603e3b7ea37cd0dfa7a480f3ee6f27a9df349325f0f755ffe5254fd5c
|
4
|
+
data.tar.gz: c7d9933a4f2fd4b525d4b570d47ff79274f2a3ddecf7b0f42273b09f9b45c31f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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=
|
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=
|
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 (
|
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
|
-
|
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
|
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
|
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
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
46
|
+
containerRef: HTMLDivElement | null,
|
47
|
+
fetchNextPage: () => void,
|
48
|
+
isFetching: boolean,
|
49
|
+
totalFetched: number,
|
50
|
+
totalDBRowCount: number
|
43
51
|
) => {
|
44
|
-
if (
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
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
|
}
|