playbook_ui 14.15.0.pre.rc.4 → 14.15.0
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/RegularTableView.tsx +127 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +55 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/TablePagination.tsx +33 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/VirtualizedTableView.tsx +275 -0
- data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +143 -3
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +66 -0
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +195 -0
- data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +45 -99
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/CellRendererUtils.tsx +73 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/RowUtils.ts +52 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/TableContainerStyles.ts +80 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +123 -7
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +153 -299
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_infinite_scroll.jsx +50 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_mock_data_infinite_scroll.json +152002 -0
- data/app/pb_kits/playbook/pb_card/_card.tsx +2 -1
- data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +4 -1
- data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +2 -0
- data/app/pb_kits/playbook/pb_date_picker/index.ts +38 -0
- data/app/pb_kits/playbook/pb_drawer/_drawer.scss +19 -3
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_borders.jsx +3 -3
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_breakpoints.jsx +20 -37
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_menu.jsx +6 -6
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_overlay.jsx +1 -0
- data/app/pb_kits/playbook/pb_drawer/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_filter/Filter/CurrentFilters.tsx +5 -4
- data/app/pb_kits/playbook/pb_filter/Filter/FilterSingle.tsx +2 -2
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -1
- data/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +9 -2
- data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +4 -0
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_wrapped.html.erb +40 -0
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_wrapped.jsx +50 -0
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_wrapped.md +3 -0
- data/app/pb_kits/playbook/pb_form_pill/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_form_pill/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_form_pill/form_pill.rb +7 -1
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss +7 -0
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +13 -3
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.html.erb +72 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.jsx +91 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +2 -1
- data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb +6 -0
- data/app/pb_kits/playbook/pb_popover/_popover.tsx +1 -1
- data/app/pb_kits/playbook/pb_radio/_radio.tsx +85 -74
- data/app/pb_kits/playbook/pb_radio/docs/_radio_react_hook.jsx +60 -0
- data/app/pb_kits/playbook/pb_radio/docs/_radio_react_hook.md +1 -0
- data/app/pb_kits/playbook/pb_radio/docs/example.yml +2 -1
- data/app/pb_kits/playbook/pb_radio/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_radio/radio.test.js +16 -0
- data/app/pb_kits/playbook/pb_select/docs/_select_react_hook.jsx +58 -0
- data/app/pb_kits/playbook/pb_select/docs/_select_react_hook.md +1 -0
- data/app/pb_kits/playbook/pb_select/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_select/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_select/select.html.erb +3 -5
- data/app/pb_kits/playbook/pb_selectable_card/selectable_card.html.erb +1 -5
- data/app/pb_kits/playbook/pb_selectable_card_icon/selectable_card_icon.html.erb +1 -4
- data/app/pb_kits/playbook/pb_selectable_icon/selectable_icon.html.erb +1 -5
- data/app/pb_kits/playbook/pb_timeline/_timeline.scss +2 -2
- data/app/pb_kits/playbook/pb_title/_title.scss +32 -0
- data/app/pb_kits/playbook/pb_title/_title.tsx +10 -1
- data/app/pb_kits/playbook/pb_title/docs/_title_default.html.erb +1 -2
- data/app/pb_kits/playbook/pb_title/docs/_title_default.jsx +1 -1
- data/app/pb_kits/playbook/pb_title/docs/_title_display_size.html.erb +7 -0
- data/app/pb_kits/playbook/pb_title/docs/_title_display_size.jsx +54 -0
- data/app/pb_kits/playbook/pb_title/docs/_title_display_size.md +1 -0
- data/app/pb_kits/playbook/pb_title/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_title/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_title/title.rb +10 -1
- data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +25 -0
- data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_sizing.jsx +69 -0
- data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_sizing.md +3 -0
- data/app/pb_kits/playbook/pb_tooltip/docs/example.yml +1 -1
- data/app/pb_kits/playbook/pb_tooltip/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +2 -1
- data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +5 -1
- data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +4 -1
- data/app/pb_kits/playbook/utilities/object.test.js +99 -0
- data/app/pb_kits/playbook/utilities/object.ts +29 -1
- data/dist/chunks/_typeahead-BhfaW1J9.js +36 -0
- data/dist/chunks/_weekday_stacked-CKRIELiF.js +45 -0
- data/dist/chunks/lazysizes-DHz07jlL.js +1 -0
- data/dist/chunks/{lib-Dmay5Z6U.js → lib-5OzNgeeu.js} +2 -2
- data/dist/chunks/{pb_form_validation-DdP7BnVX.js → pb_form_validation-DGhKbZtO.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-doc.js +1 -1
- 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 +34 -7
- data/dist/chunks/_typeahead-NXKDTf__.js +0 -36
- data/dist/chunks/_weekday_stacked-DtCYkCXM.js +0 -45
- data/dist/chunks/lazysizes-B7xYodB-.js +0 -1
@@ -0,0 +1,66 @@
|
|
1
|
+
import { useCallback, useEffect } from 'react';
|
2
|
+
import { Row } from "@tanstack/react-table";
|
3
|
+
import { GenericObject } from "../../types";
|
4
|
+
import { updateExpandAndCollapseState } from "../Utilities/ExpansionControlHelpers";
|
5
|
+
|
6
|
+
interface UseTableActionsProps {
|
7
|
+
table: any;
|
8
|
+
expanded: GenericObject;
|
9
|
+
setExpanded: (expanded: GenericObject) => void;
|
10
|
+
onToggleExpansionClick?: (arg: Row<GenericObject>) => void;
|
11
|
+
onRowSelectionChange?: (rowSelection: any) => void;
|
12
|
+
}
|
13
|
+
|
14
|
+
export function useTableActions({
|
15
|
+
table,
|
16
|
+
expanded,
|
17
|
+
setExpanded,
|
18
|
+
onToggleExpansionClick,
|
19
|
+
onRowSelectionChange
|
20
|
+
}: UseTableActionsProps) {
|
21
|
+
|
22
|
+
// Handle expand/collapse
|
23
|
+
const handleExpandOrCollapse = useCallback(async (row: Row<GenericObject>) => {
|
24
|
+
onToggleExpansionClick && onToggleExpansionClick(row);
|
25
|
+
|
26
|
+
const expandedState = expanded;
|
27
|
+
const targetParent = row?.parentId;
|
28
|
+
const updatedRows = await updateExpandAndCollapseState(table.getRowModel(), expandedState, targetParent);
|
29
|
+
setExpanded(updatedRows);
|
30
|
+
}, [expanded, setExpanded, onToggleExpansionClick, table]);
|
31
|
+
|
32
|
+
// Handle pagination
|
33
|
+
const onPageChange = useCallback((page: number) => {
|
34
|
+
table.setPageIndex(page - 1);
|
35
|
+
}, [table]);
|
36
|
+
|
37
|
+
// Handle scroll detection for infinite scroll/virtualization
|
38
|
+
const fetchMoreOnBottomReached = useCallback((
|
39
|
+
containerRefElement: HTMLDivElement | null,
|
40
|
+
fetchNextPage: () => void,
|
41
|
+
isFetching: boolean,
|
42
|
+
totalFetched: number,
|
43
|
+
totalDBRowCount: number
|
44
|
+
) => {
|
45
|
+
if (containerRefElement) {
|
46
|
+
const { scrollHeight, scrollTop, clientHeight } = containerRefElement;
|
47
|
+
// If user scrolls near bottom, fetch more data
|
48
|
+
if (scrollHeight - scrollTop - clientHeight < 500 && !isFetching && totalFetched < totalDBRowCount) {
|
49
|
+
fetchNextPage();
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}, []);
|
53
|
+
|
54
|
+
// Update selection state
|
55
|
+
useEffect(() => {
|
56
|
+
if (onRowSelectionChange) {
|
57
|
+
onRowSelectionChange(table.getState().rowSelection);
|
58
|
+
}
|
59
|
+
}, [table.getState().rowSelection, onRowSelectionChange]);
|
60
|
+
|
61
|
+
return {
|
62
|
+
handleExpandOrCollapse,
|
63
|
+
onPageChange,
|
64
|
+
fetchMoreOnBottomReached
|
65
|
+
};
|
66
|
+
}
|
@@ -0,0 +1,195 @@
|
|
1
|
+
import { useState, useCallback, useMemo } from 'react';
|
2
|
+
import {
|
3
|
+
useReactTable,
|
4
|
+
getCoreRowModel,
|
5
|
+
getExpandedRowModel,
|
6
|
+
getPaginationRowModel,
|
7
|
+
getSortedRowModel,
|
8
|
+
RowSelectionState,
|
9
|
+
Row
|
10
|
+
} from "@tanstack/react-table";
|
11
|
+
import { GenericObject } from "../../types";
|
12
|
+
import { createColumnHelper } from "@tanstack/react-table";
|
13
|
+
import { createCellFunction } from "../Utilities/CellRendererUtils";
|
14
|
+
|
15
|
+
interface UseTableStateProps {
|
16
|
+
tableData: GenericObject[];
|
17
|
+
columnDefinitions: GenericObject[];
|
18
|
+
expandedControl?: GenericObject;
|
19
|
+
sortControl?: GenericObject;
|
20
|
+
onRowToggleClick?: (arg: Row<GenericObject>) => void;
|
21
|
+
selectableRows?: boolean;
|
22
|
+
initialLoadingRowsCount?: number;
|
23
|
+
loading?: boolean | string;
|
24
|
+
pagination?: boolean;
|
25
|
+
paginationProps?: GenericObject;
|
26
|
+
virtualizedRows?: boolean;
|
27
|
+
tableOptions?: GenericObject;
|
28
|
+
onRowSelectionChange?: (arg: RowSelectionState) => void;
|
29
|
+
}
|
30
|
+
|
31
|
+
export function useTableState({
|
32
|
+
tableData,
|
33
|
+
columnDefinitions,
|
34
|
+
expandedControl,
|
35
|
+
sortControl,
|
36
|
+
onRowToggleClick,
|
37
|
+
selectableRows,
|
38
|
+
initialLoadingRowsCount = 10,
|
39
|
+
loading,
|
40
|
+
pagination = false,
|
41
|
+
paginationProps,
|
42
|
+
virtualizedRows = false,
|
43
|
+
tableOptions
|
44
|
+
}: UseTableStateProps) {
|
45
|
+
// Create a local state for expanded and setExpanded if expandedControl not used
|
46
|
+
const [localExpanded, setLocalExpanded] = useState({});
|
47
|
+
const [loadingStateRowCount, setLoadingStateRowCount] = useState(initialLoadingRowsCount);
|
48
|
+
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
49
|
+
|
50
|
+
// Determine whether to use the prop or the local state
|
51
|
+
const expanded = expandedControl ? expandedControl.value : localExpanded;
|
52
|
+
const setExpanded = expandedControl ? expandedControl.onChange : setLocalExpanded;
|
53
|
+
|
54
|
+
// Virtualized data handling (chunked loading)
|
55
|
+
const fetchSize = 20; // Number of rows per "page"
|
56
|
+
const [fullData] = useState(tableData); // All data from the JSON file
|
57
|
+
const [dataChunk, setDataChunk] = useState(fullData.slice(0, fetchSize)); // Initial chunk
|
58
|
+
const [totalFetched, setTotalFetched] = useState(fetchSize); // Track loaded rows
|
59
|
+
const [isFetching, setIsFetching] = useState(false);
|
60
|
+
|
61
|
+
// Create column structure
|
62
|
+
const columnHelper = createColumnHelper();
|
63
|
+
|
64
|
+
// Build columns with proper cell renderers
|
65
|
+
const buildColumns = useCallback((columnDefinitions: GenericObject[], isRoot = true): any[] => {
|
66
|
+
return columnDefinitions?.map((column, index) => {
|
67
|
+
const isFirstColumn = isRoot && index === 0;
|
68
|
+
|
69
|
+
// Handle grouped columns
|
70
|
+
if (column.columns && column.columns.length > 0) {
|
71
|
+
return {
|
72
|
+
header: column.label || "",
|
73
|
+
columns: buildColumns(column.columns, false),
|
74
|
+
};
|
75
|
+
}
|
76
|
+
|
77
|
+
// Define the base column structure
|
78
|
+
const columnStructure = {
|
79
|
+
...columnHelper.accessor(column.accessor, {
|
80
|
+
header: column.label || "",
|
81
|
+
}),
|
82
|
+
};
|
83
|
+
|
84
|
+
if (column.cellAccessors || column.customRenderer) {
|
85
|
+
columnStructure.cell = createCellFunction(
|
86
|
+
column.cellAccessors || [],
|
87
|
+
column.customRenderer,
|
88
|
+
isFirstColumn,
|
89
|
+
onRowToggleClick,
|
90
|
+
selectableRows
|
91
|
+
);
|
92
|
+
}
|
93
|
+
|
94
|
+
return columnStructure;
|
95
|
+
}) || [];
|
96
|
+
}, [columnHelper, onRowToggleClick, selectableRows]);
|
97
|
+
|
98
|
+
const columns = useMemo(() => buildColumns(columnDefinitions), [buildColumns, columnDefinitions]);
|
99
|
+
|
100
|
+
// Sorting configuration
|
101
|
+
const sorting = useMemo(() => ([{
|
102
|
+
id: columnDefinitions[0].accessor,
|
103
|
+
desc: sortControl && sortControl.value !== null ? !sortControl.value.desc : false,
|
104
|
+
}]), [columnDefinitions, sortControl]);
|
105
|
+
|
106
|
+
// 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]);
|
118
|
+
|
119
|
+
// Pagination configuration
|
120
|
+
const paginationInitializer = useMemo(() => {
|
121
|
+
if (!pagination) return {};
|
122
|
+
|
123
|
+
return {
|
124
|
+
getPaginationRowModel: getPaginationRowModel(),
|
125
|
+
paginateExpandedRows: false,
|
126
|
+
initialState: {
|
127
|
+
pagination: {
|
128
|
+
pageIndex: paginationProps?.pageIndex ?? 0,
|
129
|
+
pageSize: paginationProps?.pageSize ?? 20,
|
130
|
+
},
|
131
|
+
},
|
132
|
+
};
|
133
|
+
}, [pagination, paginationProps]);
|
134
|
+
|
135
|
+
// Initialize the table
|
136
|
+
const table = useReactTable({
|
137
|
+
data: loading ? Array(loadingStateRowCount).fill({}) : (virtualizedRows ? dataChunk : tableData),
|
138
|
+
columns,
|
139
|
+
onExpandedChange: setExpanded,
|
140
|
+
getSubRows: (row: GenericObject) => row.children,
|
141
|
+
getCoreRowModel: getCoreRowModel(),
|
142
|
+
getExpandedRowModel: getExpandedRowModel(),
|
143
|
+
getSortedRowModel: getSortedRowModel(),
|
144
|
+
enableSortingRemoval: false,
|
145
|
+
sortDescFirst: true,
|
146
|
+
onRowSelectionChange: setRowSelection,
|
147
|
+
getRowId: selectableRows ? row => row.id : undefined,
|
148
|
+
meta: {
|
149
|
+
columnDefinitions
|
150
|
+
},
|
151
|
+
...customState(),
|
152
|
+
...paginationInitializer,
|
153
|
+
...tableOptions,
|
154
|
+
});
|
155
|
+
|
156
|
+
// Check if table has any sub-rows
|
157
|
+
const hasAnySubRows = table.getRowModel().rows.some(row => row.subRows && row.subRows.length > 0);
|
158
|
+
const selectedRowsLength = Object.keys(table.getState().rowSelection).length;
|
159
|
+
|
160
|
+
// Data fetching for virtualized view
|
161
|
+
const fetchNextPage = useCallback(() => {
|
162
|
+
if (isFetching || totalFetched >= fullData.length) return;
|
163
|
+
|
164
|
+
setIsFetching(true);
|
165
|
+
// Simulate API call delay
|
166
|
+
setTimeout(() => {
|
167
|
+
const nextChunk = fullData.slice(totalFetched, totalFetched + fetchSize);
|
168
|
+
setDataChunk(prev => [...prev, ...nextChunk]);
|
169
|
+
setTotalFetched(prev => prev + nextChunk.length);
|
170
|
+
setIsFetching(false);
|
171
|
+
}, 500);
|
172
|
+
}, [isFetching, totalFetched, fullData, fetchSize]);
|
173
|
+
|
174
|
+
// Update row count for loading state
|
175
|
+
const updateLoadingStateRowCount = useCallback(() => {
|
176
|
+
const rowsCount = table.getRowModel().rows.length;
|
177
|
+
if (rowsCount !== loadingStateRowCount && rowsCount !== 0) {
|
178
|
+
setLoadingStateRowCount(rowsCount);
|
179
|
+
}
|
180
|
+
}, [loadingStateRowCount, table]);
|
181
|
+
|
182
|
+
return {
|
183
|
+
table,
|
184
|
+
expanded,
|
185
|
+
setExpanded,
|
186
|
+
hasAnySubRows,
|
187
|
+
selectedRowsLength,
|
188
|
+
fetchNextPage,
|
189
|
+
updateLoadingStateRowCount,
|
190
|
+
rowSelection,
|
191
|
+
fullData,
|
192
|
+
totalFetched,
|
193
|
+
isFetching
|
194
|
+
};
|
195
|
+
}
|
@@ -1,21 +1,14 @@
|
|
1
1
|
import React, { useContext } from "react"
|
2
2
|
import classnames from "classnames"
|
3
|
-
import { flexRender, Row } from "@tanstack/react-table"
|
4
3
|
|
5
4
|
import { GenericObject } from "../../types"
|
6
5
|
|
7
6
|
import { buildCss } from "../../utilities/props"
|
8
7
|
import { globalProps } from "../../utilities/globalProps"
|
9
|
-
import { isChrome } from "../Utilities/BrowserCheck"
|
10
|
-
|
11
|
-
import LoadingInline from "../../pb_loading_inline/_loading_inline"
|
12
|
-
import Checkbox from "../../pb_checkbox/_checkbox"
|
13
|
-
|
14
|
-
import { SubRowHeaderRow } from "../Components/SubRowHeaderRow"
|
15
|
-
import { LoadingCell } from "../Components/LoadingCell"
|
16
|
-
import { renderCollapsibleTrail } from "../Components/CollapsibleTrail"
|
17
8
|
|
18
9
|
import AdvancedTableContext from "../Context/AdvancedTableContext"
|
10
|
+
import { RegularTableView } from "../Components/RegularTableView"
|
11
|
+
import { VirtualizedTableView } from "../Components/VirtualizedTableView"
|
19
12
|
|
20
13
|
type TableBodyProps = {
|
21
14
|
className?: string
|
@@ -35,18 +28,15 @@ export const TableBody = ({
|
|
35
28
|
}: TableBodyProps) => {
|
36
29
|
|
37
30
|
const {
|
38
|
-
columnDefinitions,
|
39
|
-
enableToggleExpansion,
|
40
|
-
handleExpandOrCollapse,
|
41
|
-
isPinnedLeft = false,
|
42
|
-
inlineRowLoading,
|
43
|
-
loading,
|
44
31
|
responsive,
|
45
|
-
|
46
|
-
|
47
|
-
|
32
|
+
isPinnedLeft = false,
|
33
|
+
virtualizer,
|
34
|
+
virtualizedRows,
|
35
|
+
enableVirtualization
|
48
36
|
} = useContext(AdvancedTableContext)
|
49
37
|
|
38
|
+
const isVirtualized = virtualizedRows || enableVirtualization;
|
39
|
+
|
50
40
|
const classes = classnames(
|
51
41
|
buildCss("pb_advanced_table_body"),
|
52
42
|
{ 'pinned-left': responsive === "scroll" && isPinnedLeft },
|
@@ -54,93 +44,49 @@ export const TableBody = ({
|
|
54
44
|
className
|
55
45
|
)
|
56
46
|
|
57
|
-
|
47
|
+
// Style for virtualized table container
|
48
|
+
const style: React.CSSProperties = virtualizer ? {
|
49
|
+
height: `${virtualizer.getTotalSize()}px`, // tells scrollbar how big the table is
|
50
|
+
position: 'relative', // needed for absolute positioning of rows
|
51
|
+
width: '100%',
|
52
|
+
} : {};
|
58
53
|
|
59
54
|
return (
|
60
55
|
<>
|
61
|
-
<tbody
|
56
|
+
<tbody
|
57
|
+
className={classes}
|
58
|
+
data-virtualized={isVirtualized ? 'true' : 'false'}
|
62
59
|
id={id}
|
60
|
+
style={style}
|
63
61
|
>
|
64
|
-
{
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
{
|
75
|
-
|
76
|
-
|
77
|
-
enableToggleExpansion={enableToggleExpansion}
|
78
|
-
onClick={handleExpandOrCollapse}
|
79
|
-
row={row}
|
80
|
-
subRowHeaders={subRowHeaders}
|
81
|
-
table={table}
|
82
|
-
/>
|
83
|
-
)}
|
84
|
-
<tr
|
85
|
-
className={`${rowColor} ${
|
86
|
-
row.depth > 0 ? `depth-sub-row-${row.depth}` : ""
|
87
|
-
}`}
|
88
|
-
id={`${row.index}-${row.id}-${row.depth}-row`}
|
89
|
-
>
|
90
|
-
{/* Render custom checkbox column when we want selectableRows for non-expanding tables */}
|
91
|
-
{selectableRows && !hasAnySubRows && (
|
92
|
-
<td className="checkbox-cell">
|
93
|
-
<Checkbox
|
94
|
-
checked={row.getIsSelected()}
|
95
|
-
disabled={!row.getCanSelect()}
|
96
|
-
indeterminate={row.getIsSomeSelected()}
|
97
|
-
name={row.id}
|
98
|
-
onChange={row.getToggleSelectedHandler()}
|
99
|
-
/>
|
100
|
-
</td>
|
101
|
-
)}
|
102
|
-
{row.getVisibleCells().map((cell, i) => {
|
103
|
-
const isPinnedLeft = columnPinning.left.includes(cell.column.id)
|
104
|
-
const isLastCell = cell.column.parent?.columns.at(-1)?.id === cell.column.id
|
105
|
-
|
106
|
-
return (
|
107
|
-
<td
|
108
|
-
align="right"
|
109
|
-
className={classnames(
|
110
|
-
`${cell.id}-cell position_relative`,
|
111
|
-
isChrome() ? "chrome-styles" : "",
|
112
|
-
isPinnedLeft && 'pinned-left',
|
113
|
-
isLastCell && 'last-cell',
|
114
|
-
)}
|
115
|
-
key={`${cell.id}-data`}
|
116
|
-
>
|
117
|
-
{collapsibleTrail && i === 0 && row.depth > 0 && renderCollapsibleTrail(row.depth)}
|
118
|
-
<span id={`${cell.id}-span`}>
|
119
|
-
{loading ? (
|
120
|
-
<LoadingCell />
|
121
|
-
) : (
|
122
|
-
flexRender(cell.column.columnDef.cell, cell.getContext())
|
123
|
-
)}
|
124
|
-
</span>
|
125
|
-
</td>
|
126
|
-
)
|
127
|
-
})}
|
128
|
-
</tr>
|
62
|
+
{isVirtualized && virtualizer ? (
|
63
|
+
// Virtualized table view
|
64
|
+
<VirtualizedTableView
|
65
|
+
collapsibleTrail={collapsibleTrail}
|
66
|
+
subRowHeaders={subRowHeaders}
|
67
|
+
/>
|
68
|
+
) : (
|
69
|
+
// Regular non-virtualized table view
|
70
|
+
<RegularTableView
|
71
|
+
collapsibleTrail={collapsibleTrail}
|
72
|
+
subRowHeaders={subRowHeaders}
|
73
|
+
/>
|
74
|
+
)}
|
129
75
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
)
|
142
|
-
})}
|
76
|
+
{/* Fallback for when virtualization should be enabled but virtualizer isn't available */}
|
77
|
+
{isVirtualized && !virtualizer && (
|
78
|
+
<tr>
|
79
|
+
<td
|
80
|
+
colSpan={999}
|
81
|
+
style={{ padding: '10px', textAlign: 'center' }}
|
82
|
+
>
|
83
|
+
<div>No data to display.</div>
|
84
|
+
</td>
|
85
|
+
</tr>
|
86
|
+
)}
|
143
87
|
</tbody>
|
144
88
|
</>
|
145
|
-
)
|
89
|
+
);
|
146
90
|
}
|
91
|
+
|
92
|
+
export default TableBody;
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import { Row, Getter } from "@tanstack/react-table";
|
3
|
+
import { GenericObject } from "../../types";
|
4
|
+
import { CustomCell } from "../Components/CustomCell";
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Creates a cell render function for table columns
|
8
|
+
*
|
9
|
+
* @param cellAccessors Array of accessors to use based on row depth
|
10
|
+
* @param customRenderer Optional custom renderer function
|
11
|
+
* @param isFirstColumn Whether this is the first column (special handling)
|
12
|
+
* @param onRowToggleClick Optional callback for row toggle
|
13
|
+
* @param selectableRows Whether rows are selectable
|
14
|
+
*/
|
15
|
+
export const createCellFunction = (
|
16
|
+
cellAccessors: string[],
|
17
|
+
customRenderer?: (row: Row<GenericObject>, value: any) => JSX.Element,
|
18
|
+
isFirstColumn?: boolean,
|
19
|
+
onRowToggleClick?: (row: Row<GenericObject>) => void,
|
20
|
+
selectableRows?: boolean
|
21
|
+
) => {
|
22
|
+
// Add display name to the returned function
|
23
|
+
const cellRenderer = ({
|
24
|
+
row,
|
25
|
+
getValue,
|
26
|
+
}: {
|
27
|
+
row: Row<GenericObject>
|
28
|
+
getValue: Getter<string>
|
29
|
+
}) => {
|
30
|
+
const rowData = row.original;
|
31
|
+
|
32
|
+
if (isFirstColumn) {
|
33
|
+
switch (row.depth) {
|
34
|
+
case 0: {
|
35
|
+
return (
|
36
|
+
<CustomCell
|
37
|
+
customRenderer={customRenderer}
|
38
|
+
getValue={getValue}
|
39
|
+
onRowToggleClick={onRowToggleClick}
|
40
|
+
row={row}
|
41
|
+
selectableRows={selectableRows}
|
42
|
+
/>
|
43
|
+
);
|
44
|
+
}
|
45
|
+
default: {
|
46
|
+
// Handle other depths based on cellAccessors
|
47
|
+
const depthAccessor = cellAccessors[row.depth - 1]; // Adjust index for depth
|
48
|
+
const accessorValue = rowData[depthAccessor];
|
49
|
+
return accessorValue ? (
|
50
|
+
<CustomCell
|
51
|
+
customRenderer={customRenderer}
|
52
|
+
onRowToggleClick={onRowToggleClick}
|
53
|
+
row={row}
|
54
|
+
selectableRows={selectableRows}
|
55
|
+
value={accessorValue}
|
56
|
+
/>
|
57
|
+
) : (
|
58
|
+
"N/A"
|
59
|
+
);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
return customRenderer
|
65
|
+
? customRenderer(row, getValue())
|
66
|
+
: getValue();
|
67
|
+
};
|
68
|
+
|
69
|
+
// Add a display name to the function to fix the react/display-name warning
|
70
|
+
cellRenderer.displayName = 'CellRenderer';
|
71
|
+
|
72
|
+
return cellRenderer;
|
73
|
+
};
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import { Row } from "@tanstack/react-table"
|
2
|
+
import { GenericObject } from "../../types"
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Determines the background color class for a row
|
6
|
+
*/
|
7
|
+
export const getRowColorClass = (
|
8
|
+
row: Row<GenericObject>,
|
9
|
+
inlineRowLoading: boolean
|
10
|
+
): string => {
|
11
|
+
const isExpandable = row.getIsExpanded();
|
12
|
+
const rowHasNoChildren = row.original?.children && !row.original.children.length ? true : false;
|
13
|
+
const rowBackground = isExpandable && ((!inlineRowLoading && row.getCanExpand()) || (inlineRowLoading && rowHasNoChildren));
|
14
|
+
|
15
|
+
return row.getIsSelected() ? "bg-row-selection" : rowBackground ? "bg-silver" : "bg-white";
|
16
|
+
}
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Determines if loading indicator should be shown for a row
|
20
|
+
*/
|
21
|
+
export const shouldShowLoadingIndicator = (
|
22
|
+
row: Row<GenericObject>,
|
23
|
+
inlineRowLoading: boolean,
|
24
|
+
cellAccessorsLength: number
|
25
|
+
): boolean => {
|
26
|
+
const isExpandable = row.getIsExpanded();
|
27
|
+
const rowHasNoChildren = row.original?.children && !row.original.children.length ? true : false;
|
28
|
+
|
29
|
+
return isExpandable &&
|
30
|
+
(inlineRowLoading && rowHasNoChildren) &&
|
31
|
+
(row.depth < cellAccessorsLength);
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Creates a virtual item style object for virtualized rows
|
36
|
+
*/
|
37
|
+
export const createVirtualItemStyle = (startPosition: number): React.CSSProperties => {
|
38
|
+
return {
|
39
|
+
position: 'absolute',
|
40
|
+
top: 0,
|
41
|
+
left: 0,
|
42
|
+
width: '100%',
|
43
|
+
transform: `translateY(${startPosition}px)`,
|
44
|
+
};
|
45
|
+
}
|
46
|
+
|
47
|
+
/**
|
48
|
+
* Calculates padding left based on row depth
|
49
|
+
*/
|
50
|
+
export const getDepthPaddingLeft = (depth: number): string => {
|
51
|
+
return `${depth === 0 ? 0.5 : (depth * 2)}em`;
|
52
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
/**
|
2
|
+
* Utility functions to generate styles for table container
|
3
|
+
*/
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Creates styles for a virtualized table container
|
7
|
+
* These styles are critical for the virtualizer to work properly
|
8
|
+
*/
|
9
|
+
export const getVirtualizedContainerStyles = (maxHeight?: string): React.CSSProperties => {
|
10
|
+
// Calculate height based on maxHeight prop or use default
|
11
|
+
let heightValue = '600px'; // Default height
|
12
|
+
|
13
|
+
if (maxHeight) {
|
14
|
+
switch (maxHeight) {
|
15
|
+
case 'xs':
|
16
|
+
heightValue = '200px';
|
17
|
+
break;
|
18
|
+
case 'sm':
|
19
|
+
heightValue = '300px';
|
20
|
+
break;
|
21
|
+
case 'md':
|
22
|
+
heightValue = '400px';
|
23
|
+
break;
|
24
|
+
case 'lg':
|
25
|
+
heightValue = '500px';
|
26
|
+
break;
|
27
|
+
case 'xl':
|
28
|
+
heightValue = '600px';
|
29
|
+
break;
|
30
|
+
case 'xxl':
|
31
|
+
heightValue = '700px';
|
32
|
+
break;
|
33
|
+
case 'xxxl':
|
34
|
+
heightValue = '800px';
|
35
|
+
break;
|
36
|
+
default:
|
37
|
+
if (maxHeight !== 'auto') {
|
38
|
+
heightValue = maxHeight; // Use custom value if provided
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
return {
|
44
|
+
overflow: 'auto', // Critical: must have overflow:auto to enable scrolling
|
45
|
+
position: 'relative', // Required for absolute positioning of virtualized rows
|
46
|
+
height: heightValue, // Must have fixed height (not auto) for virtualization
|
47
|
+
width: '100%', // Fill container width
|
48
|
+
};
|
49
|
+
};
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Creates consistent row styles for virtualized table rows
|
53
|
+
* Matches the virtualized row height to the standard table
|
54
|
+
*/
|
55
|
+
export const getVirtualizedRowStyle = (startPosition: number): React.CSSProperties => {
|
56
|
+
return {
|
57
|
+
position: 'absolute',
|
58
|
+
top: 0,
|
59
|
+
left: 0,
|
60
|
+
width: '100%',
|
61
|
+
height: '40px', // Match standard table row height
|
62
|
+
transform: `translateY(${startPosition}px)`,
|
63
|
+
tableLayout: 'fixed',
|
64
|
+
};
|
65
|
+
};
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Get height estimates for different row types
|
69
|
+
*/
|
70
|
+
export const getRowHeightEstimate = (rowType: 'header' | 'row' | 'loading') => {
|
71
|
+
switch (rowType) {
|
72
|
+
case 'header':
|
73
|
+
return 40; // Header height
|
74
|
+
case 'loading':
|
75
|
+
return 30; // Loading indicator height
|
76
|
+
case 'row':
|
77
|
+
default:
|
78
|
+
return 40; // Standard row height - match this to your design system
|
79
|
+
}
|
80
|
+
};
|