playbook_ui 14.21.2.pre.alpha.PLAY18938263 → 14.21.2.pre.alpha.PLAY22358326

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/VirtualizedTableView.tsx +36 -16
  3. data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +18 -5
  4. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +37 -17
  5. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +25 -3
  6. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +3 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +91 -40
  8. data/app/pb_kits/playbook/pb_advanced_table/Utilities/TableContainerStyles.ts +3 -2
  9. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +49 -4
  10. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +32 -18
  11. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +20 -1
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb +1 -1
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_subrow_headers.html.erb +1 -1
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_border_color_rails.html.erb +1 -1
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_infinite_scroll.md +3 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_loading.html.erb +1 -1
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows.jsx +1 -1
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows_react.md +5 -3
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions.jsx +2 -2
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions_rails.html.erb +3 -2
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.html.erb +1 -1
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +1 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -1
  24. data/app/pb_kits/playbook/pb_advanced_table/index.js +21 -0
  25. data/app/pb_kits/playbook/pb_filter/Filter/FilterSection.tsx +49 -0
  26. data/app/pb_kits/playbook/pb_filter/Filter/FilterSidebar.tsx +69 -0
  27. data/app/pb_kits/playbook/pb_filter/Filter/index.tsx +13 -0
  28. data/app/pb_kits/playbook/pb_filter/_filter.scss +4 -0
  29. data/app/pb_kits/playbook/pb_filter/docs/_filter_sidebar.jsx +224 -0
  30. data/app/pb_kits/playbook/pb_filter/docs/example.yml +1 -0
  31. data/app/pb_kits/playbook/pb_filter/docs/index.js +1 -0
  32. data/dist/chunks/{_typeahead-CoOpeYom.js → _typeahead-CVIBi3oA.js} +2 -2
  33. data/dist/chunks/_weekday_stacked-BknM0ZnU.js +45 -0
  34. data/dist/chunks/vendor.js +1 -1
  35. data/dist/playbook-doc.js +1 -1
  36. data/dist/playbook-rails-react-bindings.js +1 -1
  37. data/dist/playbook-rails.js +1 -1
  38. data/dist/playbook.css +1 -1
  39. data/lib/playbook/version.rb +1 -1
  40. metadata +8 -4
  41. data/dist/chunks/_weekday_stacked-JnoR3mIy.js +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79e1418032e3a7ddebd1c367b0623b34c597d5f3bdd150dcf1b674fc37249634
4
- data.tar.gz: 745eed5d73220bcf2599935c70f19a103c52344f640afad7ad9fb0baceba5e79
3
+ metadata.gz: 775191059b582c0fb74cc6d654e3b563226fbe855b9b9f267fa4cd982955fa2f
4
+ data.tar.gz: fca502f3f539f439b6471b266cc211b46bb0fcba13d00189e89ce0893df0a9be
5
5
  SHA512:
6
- metadata.gz: 3e048fea08b7564b2886bcad5151b1528a92f55e35bd7661fc058582be2b64851353f9c398634021197e860550ea0f7cb13d0bafefc7e5b1a9bc92ee15c7d431
7
- data.tar.gz: a34cc6f295dcf69a9315853f1ba9c079154b83cd4f94e49b06ffbb810d405b522850ebd4673843ae580b862522cd038ddc4acfd4f05aeb3917b06ad61ec80225
6
+ metadata.gz: 61fc896c9d0a0a65db99048f13c0ac4fe70a1bd3a036a807759a699bbdf7a10589898f04760eed3b77fab43f664d798bf9a7731dd20f761255d9f86be68317f5
7
+ data.tar.gz: 923bafc7292dbf1cd30e529e20add0175ca391d4e1630c9cacb1a4f26f2696209f80acc8aca8ba96e344c60eb7ef73e211778204a9aaab0b5159403a92bad7d5
@@ -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(() => {
@@ -1,4 +1,4 @@
1
- import { useState, useCallback, useMemo } from 'react';
1
+ import { useState, useCallback, useMemo, useEffect } from 'react';
2
2
  import {
3
3
  useReactTable,
4
4
  getCoreRowModel,
@@ -50,6 +50,7 @@ export function useTableState({
50
50
  columnVisibilityControl,
51
51
  pinnedRows,
52
52
  }: UseTableStateProps) {
53
+
53
54
  // Create a local state for expanded and setExpanded if expandedControl not used
54
55
  const [localExpanded, setLocalExpanded] = useState({});
55
56
  const [loadingStateRowCount, setLoadingStateRowCount] = useState(initialLoadingRowsCount);
@@ -63,8 +64,8 @@ export function useTableState({
63
64
  const setExpanded = expandedControl ? expandedControl.onChange : setLocalExpanded;
64
65
  const columnVisibility = (columnVisibilityControl && columnVisibilityControl.value) ? columnVisibilityControl.value : localColumnVisibility;
65
66
  const setColumnVisibility = (columnVisibilityControl && columnVisibilityControl.onChange) ? columnVisibilityControl.onChange : setLocalColumnVisibility;
66
- const rowPinning = pinnedRows && pinnedRows.value || localRowPinning;
67
- const setRowPinning = (pinnedRows && pinnedRows.onChange) ? pinnedRows.onChange : setLocalRowPinning;
67
+ const rowPinning = pinnedRows?.value ?? localRowPinning
68
+ const onRowPinningChange = pinnedRows?.onChange ?? setLocalRowPinning
68
69
 
69
70
  // Virtualized data handling (chunked loading)
70
71
  const fetchSize = 20; // Number of rows per "page"
@@ -165,6 +166,7 @@ export function useTableState({
165
166
  enableSortingRemoval: false,
166
167
  sortDescFirst: true,
167
168
  onRowSelectionChange: setRowSelection,
169
+ onRowPinningChange,
168
170
  getRowId: (selectableRows || pinnedRows) ? row => row.id : undefined,
169
171
  onColumnVisibilityChange: setColumnVisibility,
170
172
  meta: {
@@ -175,6 +177,26 @@ export function useTableState({
175
177
  ...tableOptions,
176
178
  });
177
179
 
180
+ // Handle row pinning changes
181
+ useEffect(() => {
182
+ const topPins = pinnedRows?.value?.top ?? [];
183
+ if (topPins.length === 0) {
184
+ onRowPinningChange({ top: [] });
185
+ return;
186
+ }
187
+ const rows = table.getRowModel().rows;
188
+ const collectAllDescendantIds = (subs: Row<GenericObject>[]): string[] =>
189
+ subs.flatMap(r => [r.id, ...collectAllDescendantIds(r.subRows)]);
190
+ const allPinned: string[] = [];
191
+ topPins.forEach(id => {
192
+ const parent = rows.find(r => r.id === id && r.depth === 0);
193
+ if (parent) {
194
+ allPinned.push(parent.id, ...collectAllDescendantIds(parent.subRows));
195
+ }
196
+ });
197
+ onRowPinningChange({ top: allPinned });
198
+ }, [table, pinnedRows?.value?.top?.join(',')]);
199
+
178
200
  // Check if table has any sub-rows
179
201
  const hasAnySubRows = table.getRowModel().rows.some(row => row.subRows && row.subRows.length > 0);
180
202
  const selectedRowsLength = Object.keys(table.getState().rowSelection).length;
@@ -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
  }
@@ -57,7 +57,6 @@ export const getVirtualizedContainerStyles = (maxHeight?: string): React.CSSProp
57
57
  position: 'absolute',
58
58
  top: 0,
59
59
  left: 0,
60
- width: '100%',
61
60
  height: '40px', // Match standard table row height
62
61
  transform: `translateY(${startPosition}px)`,
63
62
  tableLayout: 'fixed',
@@ -67,12 +66,14 @@ export const getVirtualizedContainerStyles = (maxHeight?: string): React.CSSProp
67
66
  /**
68
67
  * Get height estimates for different row types
69
68
  */
70
- export const getRowHeightEstimate = (rowType: 'header' | 'row' | 'loading') => {
69
+ export const getRowHeightEstimate = (rowType: 'header' | 'row' | 'loading' | 'footer') => {
71
70
  switch (rowType) {
72
71
  case 'header':
73
72
  return 40; // Header height
74
73
  case 'loading':
75
74
  return 30; // Loading indicator height
75
+ case 'footer':
76
+ return 40
76
77
  case 'row':
77
78
  default:
78
79
  return 40; // Standard row height - match this to your design system
@@ -63,11 +63,30 @@
63
63
  width: 100%;
64
64
  }
65
65
 
66
- // Virtualized table styles
66
+ // Virtualized Table and Rows for Infinite Scroll
67
+ scrollbar-gutter: stable right-edges;
68
+ .virtualized-header-row-header {
69
+ width: 100% !important;
70
+ .table-header-cells:first-child {
71
+ min-width: 180px;
72
+ }
73
+ }
74
+
75
+ .virtualized-footer {
76
+ width: 100% !important;
77
+ td {
78
+ border-bottom-left-radius: 4px !important;
79
+ border-bottom-right-radius: 4px !important;
80
+ display: flex;
81
+ justify-content: center;
82
+ align-items: center;
83
+ }
84
+ }
85
+
67
86
  .virtualized-table-row {
68
87
  display: table !important;
69
88
  table-layout: fixed !important;
70
- width: 100% !important;
89
+ box-sizing: border-box !important;
71
90
 
72
91
  td {
73
92
  display: table-cell !important;
@@ -104,7 +123,7 @@
104
123
 
105
124
  -ms-overflow-style: none !important;
106
125
  scrollbar-width: none !important;
107
- }
126
+ }
108
127
 
109
128
 
110
129
  .row-selection-actions-card {
@@ -193,7 +212,6 @@
193
212
 
194
213
  // Fix virtualized row borders
195
214
  tr.virtualized-table-row {
196
- border-bottom: 1px solid $border_light;
197
215
 
198
216
  &.bg-silver {
199
217
  td:first-child {
@@ -606,6 +624,16 @@
606
624
  td.sticky-left {
607
625
  border-right: 1px solid $border_light !important;
608
626
  }
627
+ // Virtualized Table in Responsive Styles
628
+ .virtualized-header,
629
+ .virtualized-header-row-header,
630
+ .virtualized-table-row,
631
+ .virtualized-footer {
632
+ border-right: 1px solid $border_light !important;
633
+ .table-header-cells:first-child {
634
+ box-shadow: 0 0 10px 0 rgba($shadow, 0.16) !important;
635
+ }
636
+ }
609
637
  }
610
638
  }
611
639
  }
@@ -621,6 +649,23 @@
621
649
  box-shadow: 0 4px 10px 0 rgba($shadow, 0.16) !important;
622
650
  }
623
651
 
652
+ // For Rails, we can't target the &:last-child since collapsed rows are display: none;
653
+ // With JS, we add a .last-visible-row class and add rounded corners to bottom row
654
+ .last-visible-row {
655
+ td, .pb_table_td {
656
+ border-width: 0 0 1px 0;
657
+
658
+ &:first-child {
659
+ border-radius: 0 0 0 4px;
660
+ border-width: 0 0 1px 1px;
661
+ }
662
+ &:last-child {
663
+ border-radius: 0 0 4px 0;
664
+ border-width: 0 1px 1px 0;
665
+ }
666
+ }
667
+ }
668
+
624
669
  &.dark {
625
670
  // Override default border color for dark mode
626
671
  --column-border-color: #{$border_dark};
@@ -266,6 +266,29 @@ const AdvancedTable = (props: AdvancedTableProps) => {
266
266
  // Visibility flag for action bar
267
267
  const isActionBarVisible = (selectableRows && showActionsBar && selectedRowsLength > 0) || columnVisibilityControl;
268
268
 
269
+ // The actual Main <Table /> element
270
+ const tableElement = (
271
+ <Table
272
+ className={`${loading ? "content-loading" : ""}`}
273
+ dark={dark}
274
+ dataTable
275
+ numberSpacing="tabular"
276
+ responsive="none"
277
+ {...tableProps}
278
+ >
279
+ {children ? (
280
+ children
281
+ ) : (
282
+ <>
283
+ <TableHeader />
284
+ <TableBody
285
+ isFetching={isFetching}
286
+ />
287
+ </>
288
+ )}
289
+ </Table>
290
+ )
291
+
269
292
  return (
270
293
  <>
271
294
  {/* Top Pagination */}
@@ -322,6 +345,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
322
345
  table={table}
323
346
  tableContainerRef={tableWrapperRef}
324
347
  toggleExpansionIcon={toggleExpansionIcon}
348
+ totalAvailableCount={fullData.length}
325
349
  virtualizedRows={virtualizedRows}
326
350
  >
327
351
  <React.Fragment>
@@ -333,24 +357,14 @@ const AdvancedTable = (props: AdvancedTableProps) => {
333
357
  type={columnVisibilityControl ? "column-visibility" : "row-selection"}
334
358
  />
335
359
 
336
- {/* Main Table */}
337
- <Table
338
- className={`${loading ? "content-loading" : ""}`}
339
- dark={dark}
340
- dataTable
341
- numberSpacing="tabular"
342
- responsive="none"
343
- {...tableProps}
344
- >
345
- {children ? (
346
- children
347
- ) : (
348
- <>
349
- <TableHeader />
350
- <TableBody />
351
- </>
352
- )}
353
- </Table>
360
+ {/* Virtualized wrapper div only if virtualizedRows is true */}
361
+ {virtualizedRows ? (
362
+ <div style={{ overflow: 'auto', width: '100%' }}>
363
+ {tableElement}
364
+ </div>
365
+ ) : (
366
+ tableElement
367
+ )}
354
368
  </React.Fragment>
355
369
  </AdvancedTableProvider>
356
370