pixelize-design-library 2.2.192 → 2.2.194
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.
- package/dist/Components/Table/Components/TableBody.d.ts +1 -1
- package/dist/Components/Table/Components/TableBody.js +60 -3
- package/dist/Components/Table/Components/TableBody.virtualize.test.d.ts +1 -0
- package/dist/Components/Table/Components/TableBody.virtualize.test.js +93 -0
- package/dist/Components/Table/Table.js +1 -1
- package/dist/Components/Table/TableProps.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { TableBodyPageProps } from "../TableProps";
|
|
3
|
-
declare const TableBody: ({ data, isCheckbox, columns, startRow, columnWidths, freezedBgColor, freezedTextColor, noBorders, handleCheckbox, selections, isLoading, onRowClick, isContent, isLink, isActionFreeze, loadingSkeletonRows, }: TableBodyPageProps) => React.JSX.Element;
|
|
3
|
+
declare const TableBody: ({ data, isCheckbox, columns, startRow, columnWidths, freezedBgColor, freezedTextColor, noBorders, handleCheckbox, selections, isLoading, onRowClick, isContent, isLink, isActionFreeze, loadingSkeletonRows, scrollContainerRef, }: TableBodyPageProps) => React.JSX.Element;
|
|
4
4
|
export default TableBody;
|
|
@@ -84,10 +84,62 @@ var TableRow = react_2.default.memo(function (_a) {
|
|
|
84
84
|
});
|
|
85
85
|
var TableBody = function (_a) {
|
|
86
86
|
var _b, _c, _d, _e, _f, _g, _h;
|
|
87
|
-
var data = _a.data, isCheckbox = _a.isCheckbox, columns = _a.columns, startRow = _a.startRow, columnWidths = _a.columnWidths, freezedBgColor = _a.freezedBgColor, freezedTextColor = _a.freezedTextColor, noBorders = _a.noBorders, handleCheckbox = _a.handleCheckbox, selections = _a.selections, isLoading = _a.isLoading, onRowClick = _a.onRowClick, isContent = _a.isContent, isLink = _a.isLink, isActionFreeze = _a.isActionFreeze, loadingSkeletonRows = _a.loadingSkeletonRows;
|
|
87
|
+
var data = _a.data, isCheckbox = _a.isCheckbox, columns = _a.columns, startRow = _a.startRow, columnWidths = _a.columnWidths, freezedBgColor = _a.freezedBgColor, freezedTextColor = _a.freezedTextColor, noBorders = _a.noBorders, handleCheckbox = _a.handleCheckbox, selections = _a.selections, isLoading = _a.isLoading, onRowClick = _a.onRowClick, isContent = _a.isContent, isLink = _a.isLink, isActionFreeze = _a.isActionFreeze, loadingSkeletonRows = _a.loadingSkeletonRows, scrollContainerRef = _a.scrollContainerRef;
|
|
88
88
|
var theme = (0, useCustomTheme_1.useCustomTheme)();
|
|
89
89
|
var _j = (0, react_2.useState)(new Set()), expandedRows = _j[0], setExpandedRows = _j[1];
|
|
90
90
|
var selectionsSet = (0, react_2.useMemo)(function () { return new Set(selections); }, [selections]);
|
|
91
|
+
// --- Row virtualization ---------------------------------------------------
|
|
92
|
+
// Rows are a fixed 45px tall (see the `height={45}` on every <Td/> below),
|
|
93
|
+
// and the scroll viewport is capped at ~500px, so only ~11 rows are ever
|
|
94
|
+
// visible. Mounting all 50/100 page rows is what makes paging freeze. We
|
|
95
|
+
// render only the rows inside the viewport (+ overscan) and reserve the
|
|
96
|
+
// remaining height with empty spacer rows. Spacer rows (rather than CSS
|
|
97
|
+
// transforms) keep the table in normal flow so the sticky header and
|
|
98
|
+
// `position: sticky` frozen columns keep working.
|
|
99
|
+
// Disabled when expandable content rows are present, since those break the
|
|
100
|
+
// fixed-height assumption.
|
|
101
|
+
var ROW_HEIGHT = 45;
|
|
102
|
+
var OVERSCAN = 6;
|
|
103
|
+
var VIRTUALIZE_THRESHOLD = 30;
|
|
104
|
+
var shouldVirtualize = !isContent && data.length > VIRTUALIZE_THRESHOLD;
|
|
105
|
+
var _k = (0, react_2.useState)(0), scrollTop = _k[0], setScrollTop = _k[1];
|
|
106
|
+
var _l = (0, react_2.useState)(0), viewportH = _l[0], setViewportH = _l[1];
|
|
107
|
+
(0, react_2.useEffect)(function () {
|
|
108
|
+
var el = scrollContainerRef === null || scrollContainerRef === void 0 ? void 0 : scrollContainerRef.current;
|
|
109
|
+
if (!el || !shouldVirtualize)
|
|
110
|
+
return;
|
|
111
|
+
var onScroll = function () { return setScrollTop(el.scrollTop); };
|
|
112
|
+
var measure = function () { return setViewportH(el.clientHeight); };
|
|
113
|
+
measure();
|
|
114
|
+
setScrollTop(el.scrollTop);
|
|
115
|
+
el.addEventListener("scroll", onScroll, { passive: true });
|
|
116
|
+
window.addEventListener("resize", measure);
|
|
117
|
+
return function () {
|
|
118
|
+
el.removeEventListener("scroll", onScroll);
|
|
119
|
+
window.removeEventListener("resize", measure);
|
|
120
|
+
};
|
|
121
|
+
}, [scrollContainerRef, shouldVirtualize, data.length]);
|
|
122
|
+
// New page: jump back to the top so the window recomputes from row 0.
|
|
123
|
+
(0, react_2.useEffect)(function () {
|
|
124
|
+
if (!shouldVirtualize)
|
|
125
|
+
return;
|
|
126
|
+
var el = scrollContainerRef === null || scrollContainerRef === void 0 ? void 0 : scrollContainerRef.current;
|
|
127
|
+
if (el)
|
|
128
|
+
el.scrollTop = 0;
|
|
129
|
+
setScrollTop(0);
|
|
130
|
+
}, [startRow, shouldVirtualize, scrollContainerRef]);
|
|
131
|
+
var total = data.length;
|
|
132
|
+
var firstIndex = 0;
|
|
133
|
+
var lastIndex = total;
|
|
134
|
+
if (shouldVirtualize) {
|
|
135
|
+
var vh = viewportH || 500;
|
|
136
|
+
firstIndex = Math.max(0, Math.floor(scrollTop / ROW_HEIGHT) - OVERSCAN);
|
|
137
|
+
var count = Math.ceil(vh / ROW_HEIGHT) + OVERSCAN * 2;
|
|
138
|
+
lastIndex = Math.min(total, firstIndex + count);
|
|
139
|
+
}
|
|
140
|
+
var visibleRows = shouldVirtualize ? data.slice(firstIndex, lastIndex) : data;
|
|
141
|
+
var topPad = firstIndex * ROW_HEIGHT;
|
|
142
|
+
var bottomPad = (total - lastIndex) * ROW_HEIGHT;
|
|
91
143
|
var toggleRowExpansion = (0, react_2.useCallback)(function (rowIndex) {
|
|
92
144
|
setExpandedRows(function (prev) {
|
|
93
145
|
var newSet = new Set(prev);
|
|
@@ -133,12 +185,17 @@ var TableBody = function (_a) {
|
|
|
133
185
|
react_2.default.createElement(react_1.Td, { colSpan: totalVisibleColumns, p: 0, border: "none", position: "relative", height: 0 },
|
|
134
186
|
react_2.default.createElement(react_1.Box, { position: "absolute", top: 4, left: "50%", transform: "translateX(-50%)", zIndex: 10 },
|
|
135
187
|
react_2.default.createElement(react_1.Spinner, { size: "sm", color: ((_h = (_g = theme.colors) === null || _g === void 0 ? void 0 : _g.primary) === null || _h === void 0 ? void 0 : _h[500]) || "blue.500" }))))),
|
|
136
|
-
|
|
188
|
+
shouldVirtualize && topPad > 0 && (react_2.default.createElement("tr", { "aria-hidden": "true", style: { height: topPad } },
|
|
189
|
+
react_2.default.createElement("td", { colSpan: totalVisibleColumns, style: { padding: 0, border: "none", height: topPad } }))),
|
|
190
|
+
visibleRows.map(function (row, i) {
|
|
137
191
|
var _a;
|
|
192
|
+
var index = firstIndex + i;
|
|
138
193
|
var rowIndex = startRow + index;
|
|
139
194
|
var isExpanded = expandedRows.has(rowIndex);
|
|
140
195
|
var isChecked = selectionsSet.has(row.id);
|
|
141
196
|
return (react_2.default.createElement(TableRow, { key: (_a = row.id) !== null && _a !== void 0 ? _a : rowIndex, row: row, rowIndex: rowIndex, index: index, isChecked: isChecked, isExpanded: isExpanded, isContent: isContent, isLink: isLink, isCheckbox: isCheckbox, isLoading: isLoading, isActionFreeze: isActionFreeze, columns: columns, leftOffsets: leftOffsets, noBorders: noBorders, freezedBgColor: freezedBgColor, freezedTextColor: freezedTextColor, theme: theme, borderStyle: borderStyle, hoverStyle: hoverStyle, handleCheckbox: handleCheckbox, onRowClick: onRowClick, toggleRowExpansion: toggleRowExpansion }));
|
|
142
|
-
})
|
|
197
|
+
}),
|
|
198
|
+
shouldVirtualize && bottomPad > 0 && (react_2.default.createElement("tr", { "aria-hidden": "true", style: { height: bottomPad } },
|
|
199
|
+
react_2.default.createElement("td", { colSpan: totalVisibleColumns, style: { padding: 0, border: "none", height: bottomPad } })))));
|
|
143
200
|
};
|
|
144
201
|
exports.default = TableBody;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
var react_1 = __importStar(require("react"));
|
|
40
|
+
var react_2 = require("@testing-library/react");
|
|
41
|
+
require("@testing-library/jest-dom");
|
|
42
|
+
var react_3 = require("@chakra-ui/react");
|
|
43
|
+
var TableBody_1 = __importDefault(require("./TableBody"));
|
|
44
|
+
jest.mock("../../../Theme/useCustomTheme", function () { return ({
|
|
45
|
+
useCustomTheme: function () { return ({
|
|
46
|
+
colors: {
|
|
47
|
+
background: { 50: "#fff", 100: "#f9f9f9" },
|
|
48
|
+
backgroundColor: { light: "#fafafa", secondary: "#eee", muted: "#f3f3f3" },
|
|
49
|
+
disabled: { 100: "#eee" },
|
|
50
|
+
gray: { 100: "#f0f0f0", 200: "#eee", 300: "#ddd", 400: "#ccc", 500: "#bbb", 600: "#666" },
|
|
51
|
+
border: { 500: "#ddd" },
|
|
52
|
+
primary: { 500: "#3182ce" },
|
|
53
|
+
text: { 500: "#555" },
|
|
54
|
+
secondary: { opacity: { 4: "rgba(0,0,0,0.04)" } },
|
|
55
|
+
white: "#fff",
|
|
56
|
+
},
|
|
57
|
+
shadows: { lg: "0 0 0" },
|
|
58
|
+
}); },
|
|
59
|
+
}); });
|
|
60
|
+
var columns = [{ id: "name", label: "Name" }];
|
|
61
|
+
var makeData = function (n) {
|
|
62
|
+
return Array.from({ length: n }, function (_, i) { return ({ id: i, name: "Row ".concat(i) }); });
|
|
63
|
+
};
|
|
64
|
+
var Harness = function (_a) {
|
|
65
|
+
var count = _a.count;
|
|
66
|
+
var ref = (0, react_1.useRef)(null);
|
|
67
|
+
return (react_1.default.createElement(react_3.ChakraProvider, null,
|
|
68
|
+
react_1.default.createElement("div", { ref: ref },
|
|
69
|
+
react_1.default.createElement(react_3.Table, null,
|
|
70
|
+
react_1.default.createElement(react_3.Tbody, null,
|
|
71
|
+
react_1.default.createElement(TableBody_1.default, { data: makeData(count), columns: columns, startRow: 0, endRow: count, columnWidths: [120], isCheckbox: false, isContent: false, isLink: false, isActionFreeze: false, noBorders: false, selections: [], handleCheckbox: function () { }, scrollContainerRef: ref }))))));
|
|
72
|
+
};
|
|
73
|
+
describe("TableBody virtualization", function () {
|
|
74
|
+
it("windows large pages and reserves height with spacer rows", function () {
|
|
75
|
+
var _a = (0, react_2.render)(react_1.default.createElement(Harness, { count: 100 })), container = _a.container, queryByText = _a.queryByText;
|
|
76
|
+
// jsdom clientHeight=0 -> 500px fallback -> ceil(500/45)+12 = 24 rows
|
|
77
|
+
expect(queryByText("Row 0")).toBeInTheDocument();
|
|
78
|
+
expect(queryByText("Row 23")).toBeInTheDocument();
|
|
79
|
+
// Rows beyond the window are not mounted.
|
|
80
|
+
expect(queryByText("Row 50")).not.toBeInTheDocument();
|
|
81
|
+
expect(queryByText("Row 99")).not.toBeInTheDocument();
|
|
82
|
+
// A trailing spacer reserves the height of the unrendered rows.
|
|
83
|
+
var spacers = container.querySelectorAll('tr[aria-hidden="true"]');
|
|
84
|
+
expect(spacers.length).toBe(1);
|
|
85
|
+
expect(spacers[0]).toHaveStyle({ height: "".concat((100 - 24) * 45, "px") });
|
|
86
|
+
});
|
|
87
|
+
it("renders every row and no spacers below the threshold", function () {
|
|
88
|
+
var _a = (0, react_2.render)(react_1.default.createElement(Harness, { count: 30 })), container = _a.container, queryByText = _a.queryByText;
|
|
89
|
+
expect(queryByText("Row 0")).toBeInTheDocument();
|
|
90
|
+
expect(queryByText("Row 29")).toBeInTheDocument();
|
|
91
|
+
expect(container.querySelectorAll('tr[aria-hidden="true"]').length).toBe(0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -278,5 +278,5 @@ function Table(_a) {
|
|
|
278
278
|
? false
|
|
279
279
|
: "indeterminate", isContent: isContent, isLink: isLink, isActionFreeze: isActionFreeze, setColumnsSearch: setColumnsSearch, columnsSearch: columnsSearch, isSelecting: isSelecting })),
|
|
280
280
|
react_1.default.createElement(react_3.Tbody, null,
|
|
281
|
-
react_1.default.createElement(TableBody_1.default, { data: _filteredData, columns: columnsList, startRow: startRow, endRow: endRow, isCheckbox: isCheckbox, columnWidths: columnWidths, noBorders: noBorders, freezedBgColor: freezedBgColor !== null && freezedBgColor !== void 0 ? freezedBgColor : theme.colors.backgroundColor.secondary, freezedTextColor: freezedTextColor !== null && freezedTextColor !== void 0 ? freezedTextColor : (_z = theme.colors) === null || _z === void 0 ? void 0 : _z.gray[600], handleCheckbox: handleCheckbox, selections: selection, isLoading: isTableLoading, loadingSkeletonRows: loadingSkeletonRows, onRowClick: onRowClick, isContent: isContent, isLink: isLink, isActionFreeze: isActionFreeze }))))))));
|
|
281
|
+
react_1.default.createElement(TableBody_1.default, { data: _filteredData, columns: columnsList, startRow: startRow, endRow: endRow, scrollContainerRef: tableContainerRef, isCheckbox: isCheckbox, columnWidths: columnWidths, noBorders: noBorders, freezedBgColor: freezedBgColor !== null && freezedBgColor !== void 0 ? freezedBgColor : theme.colors.backgroundColor.secondary, freezedTextColor: freezedTextColor !== null && freezedTextColor !== void 0 ? freezedTextColor : (_z = theme.colors) === null || _z === void 0 ? void 0 : _z.gray[600], handleCheckbox: handleCheckbox, selections: selection, isLoading: isTableLoading, loadingSkeletonRows: loadingSkeletonRows, onRowClick: onRowClick, isContent: isContent, isLink: isLink, isActionFreeze: isActionFreeze }))))))));
|
|
282
282
|
}
|
|
@@ -118,6 +118,7 @@ export type TableBodyPageProps = Pick<TableProps, "columns" | "isCheckbox" | "da
|
|
|
118
118
|
selections: (string | number)[];
|
|
119
119
|
isContent: boolean;
|
|
120
120
|
isLink: boolean;
|
|
121
|
+
scrollContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
|
121
122
|
};
|
|
122
123
|
export type TableFiltersProps = {
|
|
123
124
|
header: DataObject;
|