@pallasoft/ps-table-components 1.19.0 → 1.20.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.
- package/dist/components/ps-data-table.js +16 -18
- package/dist/components/ps-table-pagination.d.ts +2 -1
- package/dist/components/ps-table-pagination.js +3 -2
- package/dist/esm/components/ps-data-table.js +16 -18
- package/dist/esm/components/ps-table-pagination.js +3 -2
- package/dist/esm/hooks/use-ps-scroll-anchor.js +26 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/interfaces/table-scroll-anchor-target.js +1 -0
- package/dist/esm/interfaces/table-scroll-anchor.js +1 -0
- package/dist/esm/services/ps-table-scroll-anchor-service.js +17 -0
- package/dist/hooks/use-ps-scroll-anchor.d.ts +2 -0
- package/dist/hooks/use-ps-scroll-anchor.js +30 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interfaces/table-scroll-anchor-target.d.ts +10 -0
- package/dist/interfaces/table-scroll-anchor-target.js +2 -0
- package/dist/interfaces/table-scroll-anchor.d.ts +4 -0
- package/dist/interfaces/table-scroll-anchor.js +2 -0
- package/dist/services/ps-table-scroll-anchor-service.d.ts +7 -0
- package/dist/services/ps-table-scroll-anchor-service.js +21 -0
- package/package.json +1 -1
|
@@ -10,6 +10,8 @@ const ps_motion_components_1 = require("@pallasoft/ps-motion-components");
|
|
|
10
10
|
const react_virtual_1 = require("@tanstack/react-virtual");
|
|
11
11
|
const table_config_1 = require("../constants/table-config");
|
|
12
12
|
const use_ps_incremental_count_1 = require("../hooks/use-ps-incremental-count");
|
|
13
|
+
const use_ps_scroll_anchor_1 = require("../hooks/use-ps-scroll-anchor");
|
|
14
|
+
const use_ps_table_stream_status_1 = require("../hooks/use-ps-table-stream-status");
|
|
13
15
|
const ps_table_cell_tooltip_service_1 = require("../services/ps-table-cell-tooltip-service");
|
|
14
16
|
const ps_table_column_size_service_1 = require("../services/ps-table-column-size-service");
|
|
15
17
|
const ps_table_group_service_1 = require("../services/ps-table-group-service");
|
|
@@ -67,27 +69,21 @@ const PsDataTable = ({ caption, className, columns, defaultSort, density = 'norm
|
|
|
67
69
|
const hasToolbar = isSearchable || hasFilters || Boolean(toolbarActions);
|
|
68
70
|
const isSelectable = Boolean(getBulkActions);
|
|
69
71
|
const columnCount = visibleColumns.length + (isSelectable ? 1 : 0);
|
|
70
|
-
const deferredRows = (0, react_1.useDeferredValue)(rows);
|
|
71
|
-
const deferredFilters = (0, react_1.useDeferredValue)(filters);
|
|
72
72
|
const deferredSearch = (0, react_1.useDeferredValue)(search);
|
|
73
|
-
const deferredSort = (0, react_1.useDeferredValue)(sort);
|
|
74
73
|
const queriedRows = (0, react_1.useMemo)(() => isServerPaginated
|
|
75
|
-
?
|
|
76
|
-
: ps_table_query_service_1.PsTableQueryService.apply(
|
|
77
|
-
|
|
78
|
-
deferredFilters,
|
|
79
|
-
deferredRows,
|
|
80
|
-
deferredSearch,
|
|
81
|
-
deferredSort,
|
|
82
|
-
getSearchText,
|
|
83
|
-
isServerPaginated,
|
|
84
|
-
]);
|
|
85
|
-
const currentPage = page !== null && page !== undefined ? page : uncontrolledPage;
|
|
86
|
-
const rowCount = isServerPaginated ? totalRows : queriedRows.length;
|
|
87
|
-
const pageCount = pageSize ? Math.max(Math.ceil(rowCount / pageSize), 1) : 1;
|
|
88
|
-
const safePage = Math.min(Math.max(currentPage, 1), pageCount);
|
|
74
|
+
? rows
|
|
75
|
+
: ps_table_query_service_1.PsTableQueryService.apply(rows, columns, filters, deferredSearch, getSearchText, sort), [columns, filters, rows, deferredSearch, sort, getSearchText, isServerPaginated]);
|
|
76
|
+
const streamStatus = (0, use_ps_table_stream_status_1.usePsTableStreamStatus)();
|
|
89
77
|
const isQueried = search.trim() !== '' ||
|
|
90
78
|
Object.values(filters).some((value) => ps_table_query_service_1.PsTableQueryService.isActive(value));
|
|
79
|
+
const currentPage = page !== null && page !== undefined ? page : uncontrolledPage;
|
|
80
|
+
const loadedRowCount = isServerPaginated ? totalRows : queriedRows.length;
|
|
81
|
+
const rowCount = streamStatus !== null && !isServerPaginated && !isQueried
|
|
82
|
+
? Math.max(streamStatus.total, loadedRowCount)
|
|
83
|
+
: loadedRowCount;
|
|
84
|
+
const pageCountOf = (count) => (pageSize ? Math.max(Math.ceil(count / pageSize), 1) : 1);
|
|
85
|
+
const pageCount = pageCountOf(rowCount);
|
|
86
|
+
const safePage = Math.min(Math.max(currentPage, 1), pageCountOf(loadedRowCount));
|
|
91
87
|
const groups = (0, react_1.useMemo)(() => (grouping ? ps_table_group_service_1.PsTableGroupService.group(queriedRows, grouping.getGroupKey) : []), [grouping, queriedRows]);
|
|
92
88
|
const initialExpandedCount = grouping && grouping.initialExpandedCount !== undefined ? grouping.initialExpandedCount : 1;
|
|
93
89
|
const isGroupExpanded = (groupKey, groupIndex) => isQueried || groupIndex < initialExpandedCount !== toggledGroupKeys.includes(groupKey);
|
|
@@ -200,6 +196,8 @@ const PsDataTable = ({ caption, className, columns, defaultSort, density = 'norm
|
|
|
200
196
|
});
|
|
201
197
|
const virtualizer = scrollParent === null ? windowVirtualizer : elementVirtualizer;
|
|
202
198
|
const virtualItems = shouldVirtualize ? virtualizer.getVirtualItems() : [];
|
|
199
|
+
const visibleRowIds = (0, react_1.useMemo)(() => (shouldVirtualize ? visibleRows.map((row) => getRowId(row)) : []), [getRowId, shouldVirtualize, visibleRows]);
|
|
200
|
+
(0, use_ps_scroll_anchor_1.usePsScrollAnchor)(virtualizer, visibleRowIds, shouldVirtualize && streamStatus !== null);
|
|
203
201
|
const virtualTop = virtualItems.length > 0 ? virtualItems[0].start - scrollMargin : 0;
|
|
204
202
|
const virtualBottom = virtualItems.length > 0
|
|
205
203
|
? virtualizer.getTotalSize() - (virtualItems[virtualItems.length - 1].end - scrollMargin)
|
|
@@ -277,6 +275,6 @@ const PsDataTable = ({ caption, className, columns, defaultSort, density = 'norm
|
|
|
277
275
|
]
|
|
278
276
|
: visibleRows.map((row) => renderRow(row))] }), hasFooter ? ((0, jsx_runtime_1.jsx)("tfoot", { className: 'border-t-2 border-line bg-mist/50 text-sm font-semibold text-ink', children: (0, jsx_runtime_1.jsxs)("tr", { children: [isSelectable ? (0, jsx_runtime_1.jsx)("td", {}) : null, visibleColumns.map((column) => ((0, jsx_runtime_1.jsx)("td", { className: ps_design_system_1.PallasoftClassNameService.merge(densityClassNames[density].cell, alignClassNames[column.align !== null && column.align !== undefined
|
|
279
277
|
? column.align
|
|
280
|
-
: 'left'], 'whitespace-nowrap'), children: column.footer }, column.id)))] }) })) : null] }) }), pageSize && (!grouping || isServerPaginated) ? ((0, jsx_runtime_1.jsx)(ps_table_pagination_1.PsTablePagination, { onPageChange: changePage, page: safePage, pageCount: pageCount, pageSize: pageSize, totalRows: rowCount })) : null] })] }));
|
|
278
|
+
: 'left'], 'whitespace-nowrap'), children: column.footer }, column.id)))] }) })) : null] }) }), pageSize && (!grouping || isServerPaginated) ? ((0, jsx_runtime_1.jsx)(ps_table_pagination_1.PsTablePagination, { loadedPageCount: pageCountOf(loadedRowCount), onPageChange: changePage, page: safePage, pageCount: pageCount, pageSize: pageSize, totalRows: rowCount })) : null] })] }));
|
|
281
279
|
};
|
|
282
280
|
exports.PsDataTable = PsDataTable;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export interface PsTablePaginationProps {
|
|
2
2
|
className?: string;
|
|
3
|
+
loadedPageCount?: number;
|
|
3
4
|
onPageChange: (page: number) => void;
|
|
4
5
|
page: number;
|
|
5
6
|
pageCount: number;
|
|
6
7
|
pageSize: number;
|
|
7
8
|
totalRows: number;
|
|
8
9
|
}
|
|
9
|
-
export declare const PsTablePagination: ({ className, onPageChange, page, pageCount, pageSize, totalRows, }: PsTablePaginationProps) => import("react").JSX.Element;
|
|
10
|
+
export declare const PsTablePagination: ({ className, loadedPageCount, onPageChange, page, pageCount, pageSize, totalRows, }: PsTablePaginationProps) => import("react").JSX.Element;
|
|
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PsTablePagination = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const ps_design_system_1 = require("@pallasoft/ps-design-system");
|
|
6
|
-
const PsTablePagination = ({ className, onPageChange, page, pageCount, pageSize, totalRows, }) => {
|
|
6
|
+
const PsTablePagination = ({ className, loadedPageCount, onPageChange, page, pageCount, pageSize, totalRows, }) => {
|
|
7
7
|
const firstRow = totalRows === 0 ? 0 : (page - 1) * pageSize + 1;
|
|
8
8
|
const lastRow = Math.min(page * pageSize, totalRows);
|
|
9
9
|
const buttonClassName = 'ps-focus-ring inline-flex min-h-9 items-center rounded-full border border-line px-3.5 text-sm font-semibold text-ink transition-colors disabled:cursor-not-allowed disabled:opacity-40 enabled:hover:border-primary/40';
|
|
10
|
-
return ((0, jsx_runtime_1.jsxs)("nav", { "aria-label": 'Pagination', className: ps_design_system_1.PallasoftClassNameService.merge('flex flex-wrap items-center justify-between gap-3 border-t border-line px-4 py-3', className), children: [(0, jsx_runtime_1.jsx)("p", { className: 'text-sm text-ink/55', children: totalRows === 0 ? 'No rows' : `${firstRow}–${lastRow} of ${totalRows}` }), (0, jsx_runtime_1.jsxs)("div", { className: 'flex items-center gap-2', children: [(0, jsx_runtime_1.jsx)("button", { className: buttonClassName, disabled: page <= 1, onClick: () => onPageChange(page - 1), type: 'button', children: "Previous" }), (0, jsx_runtime_1.jsxs)("span", { className: 'hidden text-sm text-ink/65 sm:inline', children: ["Page ", Math.min(page, pageCount), " of ", pageCount] }), (0, jsx_runtime_1.jsx)("button", { className: buttonClassName, disabled: page >=
|
|
10
|
+
return ((0, jsx_runtime_1.jsxs)("nav", { "aria-label": 'Pagination', className: ps_design_system_1.PallasoftClassNameService.merge('flex flex-wrap items-center justify-between gap-3 border-t border-line px-4 py-3', className), children: [(0, jsx_runtime_1.jsx)("p", { className: 'text-sm text-ink/55', children: totalRows === 0 ? 'No rows' : `${firstRow}–${lastRow} of ${totalRows}` }), (0, jsx_runtime_1.jsxs)("div", { className: 'flex items-center gap-2', children: [(0, jsx_runtime_1.jsx)("button", { className: buttonClassName, disabled: page <= 1, onClick: () => onPageChange(page - 1), type: 'button', children: "Previous" }), (0, jsx_runtime_1.jsxs)("span", { className: 'hidden text-sm text-ink/65 sm:inline', children: ["Page ", Math.min(page, pageCount), " of ", pageCount] }), (0, jsx_runtime_1.jsx)("button", { className: buttonClassName, disabled: page >=
|
|
11
|
+
(loadedPageCount === undefined ? pageCount : Math.min(loadedPageCount, pageCount)), onClick: () => onPageChange(page + 1), type: 'button', children: "Next" })] })] }));
|
|
11
12
|
};
|
|
12
13
|
exports.PsTablePagination = PsTablePagination;
|
|
@@ -7,6 +7,8 @@ import { PsCollapse } from '@pallasoft/ps-motion-components';
|
|
|
7
7
|
import { useVirtualizer, useWindowVirtualizer } from '@tanstack/react-virtual';
|
|
8
8
|
import { PsTableConfig } from '../constants/table-config';
|
|
9
9
|
import { usePsIncrementalCount } from '../hooks/use-ps-incremental-count';
|
|
10
|
+
import { usePsScrollAnchor } from '../hooks/use-ps-scroll-anchor';
|
|
11
|
+
import { usePsTableStreamStatus } from '../hooks/use-ps-table-stream-status';
|
|
10
12
|
import { PsTableCellTooltipService } from '../services/ps-table-cell-tooltip-service';
|
|
11
13
|
import { PsTableColumnSizeService } from '../services/ps-table-column-size-service';
|
|
12
14
|
import { PsTableGroupService } from '../services/ps-table-group-service';
|
|
@@ -64,27 +66,21 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
64
66
|
const hasToolbar = isSearchable || hasFilters || Boolean(toolbarActions);
|
|
65
67
|
const isSelectable = Boolean(getBulkActions);
|
|
66
68
|
const columnCount = visibleColumns.length + (isSelectable ? 1 : 0);
|
|
67
|
-
const deferredRows = useDeferredValue(rows);
|
|
68
|
-
const deferredFilters = useDeferredValue(filters);
|
|
69
69
|
const deferredSearch = useDeferredValue(search);
|
|
70
|
-
const deferredSort = useDeferredValue(sort);
|
|
71
70
|
const queriedRows = useMemo(() => isServerPaginated
|
|
72
|
-
?
|
|
73
|
-
: PsTableQueryService.apply(
|
|
74
|
-
|
|
75
|
-
deferredFilters,
|
|
76
|
-
deferredRows,
|
|
77
|
-
deferredSearch,
|
|
78
|
-
deferredSort,
|
|
79
|
-
getSearchText,
|
|
80
|
-
isServerPaginated,
|
|
81
|
-
]);
|
|
82
|
-
const currentPage = page !== null && page !== undefined ? page : uncontrolledPage;
|
|
83
|
-
const rowCount = isServerPaginated ? totalRows : queriedRows.length;
|
|
84
|
-
const pageCount = pageSize ? Math.max(Math.ceil(rowCount / pageSize), 1) : 1;
|
|
85
|
-
const safePage = Math.min(Math.max(currentPage, 1), pageCount);
|
|
71
|
+
? rows
|
|
72
|
+
: PsTableQueryService.apply(rows, columns, filters, deferredSearch, getSearchText, sort), [columns, filters, rows, deferredSearch, sort, getSearchText, isServerPaginated]);
|
|
73
|
+
const streamStatus = usePsTableStreamStatus();
|
|
86
74
|
const isQueried = search.trim() !== '' ||
|
|
87
75
|
Object.values(filters).some((value) => PsTableQueryService.isActive(value));
|
|
76
|
+
const currentPage = page !== null && page !== undefined ? page : uncontrolledPage;
|
|
77
|
+
const loadedRowCount = isServerPaginated ? totalRows : queriedRows.length;
|
|
78
|
+
const rowCount = streamStatus !== null && !isServerPaginated && !isQueried
|
|
79
|
+
? Math.max(streamStatus.total, loadedRowCount)
|
|
80
|
+
: loadedRowCount;
|
|
81
|
+
const pageCountOf = (count) => (pageSize ? Math.max(Math.ceil(count / pageSize), 1) : 1);
|
|
82
|
+
const pageCount = pageCountOf(rowCount);
|
|
83
|
+
const safePage = Math.min(Math.max(currentPage, 1), pageCountOf(loadedRowCount));
|
|
88
84
|
const groups = useMemo(() => (grouping ? PsTableGroupService.group(queriedRows, grouping.getGroupKey) : []), [grouping, queriedRows]);
|
|
89
85
|
const initialExpandedCount = grouping && grouping.initialExpandedCount !== undefined ? grouping.initialExpandedCount : 1;
|
|
90
86
|
const isGroupExpanded = (groupKey, groupIndex) => isQueried || groupIndex < initialExpandedCount !== toggledGroupKeys.includes(groupKey);
|
|
@@ -197,6 +193,8 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
197
193
|
});
|
|
198
194
|
const virtualizer = scrollParent === null ? windowVirtualizer : elementVirtualizer;
|
|
199
195
|
const virtualItems = shouldVirtualize ? virtualizer.getVirtualItems() : [];
|
|
196
|
+
const visibleRowIds = useMemo(() => (shouldVirtualize ? visibleRows.map((row) => getRowId(row)) : []), [getRowId, shouldVirtualize, visibleRows]);
|
|
197
|
+
usePsScrollAnchor(virtualizer, visibleRowIds, shouldVirtualize && streamStatus !== null);
|
|
200
198
|
const virtualTop = virtualItems.length > 0 ? virtualItems[0].start - scrollMargin : 0;
|
|
201
199
|
const virtualBottom = virtualItems.length > 0
|
|
202
200
|
? virtualizer.getTotalSize() - (virtualItems[virtualItems.length - 1].end - scrollMargin)
|
|
@@ -274,5 +272,5 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
274
272
|
]
|
|
275
273
|
: visibleRows.map((row) => renderRow(row))] }), hasFooter ? (_jsx("tfoot", { className: 'border-t-2 border-line bg-mist/50 text-sm font-semibold text-ink', children: _jsxs("tr", { children: [isSelectable ? _jsx("td", {}) : null, visibleColumns.map((column) => (_jsx("td", { className: PallasoftClassNameService.merge(densityClassNames[density].cell, alignClassNames[column.align !== null && column.align !== undefined
|
|
276
274
|
? column.align
|
|
277
|
-
: 'left'], 'whitespace-nowrap'), children: column.footer }, column.id)))] }) })) : null] }) }), pageSize && (!grouping || isServerPaginated) ? (_jsx(PsTablePagination, { onPageChange: changePage, page: safePage, pageCount: pageCount, pageSize: pageSize, totalRows: rowCount })) : null] })] }));
|
|
275
|
+
: 'left'], 'whitespace-nowrap'), children: column.footer }, column.id)))] }) })) : null] }) }), pageSize && (!grouping || isServerPaginated) ? (_jsx(PsTablePagination, { loadedPageCount: pageCountOf(loadedRowCount), onPageChange: changePage, page: safePage, pageCount: pageCount, pageSize: pageSize, totalRows: rowCount })) : null] })] }));
|
|
278
276
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
3
|
-
export const PsTablePagination = ({ className, onPageChange, page, pageCount, pageSize, totalRows, }) => {
|
|
3
|
+
export const PsTablePagination = ({ className, loadedPageCount, onPageChange, page, pageCount, pageSize, totalRows, }) => {
|
|
4
4
|
const firstRow = totalRows === 0 ? 0 : (page - 1) * pageSize + 1;
|
|
5
5
|
const lastRow = Math.min(page * pageSize, totalRows);
|
|
6
6
|
const buttonClassName = 'ps-focus-ring inline-flex min-h-9 items-center rounded-full border border-line px-3.5 text-sm font-semibold text-ink transition-colors disabled:cursor-not-allowed disabled:opacity-40 enabled:hover:border-primary/40';
|
|
7
|
-
return (_jsxs("nav", { "aria-label": 'Pagination', className: PallasoftClassNameService.merge('flex flex-wrap items-center justify-between gap-3 border-t border-line px-4 py-3', className), children: [_jsx("p", { className: 'text-sm text-ink/55', children: totalRows === 0 ? 'No rows' : `${firstRow}–${lastRow} of ${totalRows}` }), _jsxs("div", { className: 'flex items-center gap-2', children: [_jsx("button", { className: buttonClassName, disabled: page <= 1, onClick: () => onPageChange(page - 1), type: 'button', children: "Previous" }), _jsxs("span", { className: 'hidden text-sm text-ink/65 sm:inline', children: ["Page ", Math.min(page, pageCount), " of ", pageCount] }), _jsx("button", { className: buttonClassName, disabled: page >=
|
|
7
|
+
return (_jsxs("nav", { "aria-label": 'Pagination', className: PallasoftClassNameService.merge('flex flex-wrap items-center justify-between gap-3 border-t border-line px-4 py-3', className), children: [_jsx("p", { className: 'text-sm text-ink/55', children: totalRows === 0 ? 'No rows' : `${firstRow}–${lastRow} of ${totalRows}` }), _jsxs("div", { className: 'flex items-center gap-2', children: [_jsx("button", { className: buttonClassName, disabled: page <= 1, onClick: () => onPageChange(page - 1), type: 'button', children: "Previous" }), _jsxs("span", { className: 'hidden text-sm text-ink/65 sm:inline', children: ["Page ", Math.min(page, pageCount), " of ", pageCount] }), _jsx("button", { className: buttonClassName, disabled: page >=
|
|
8
|
+
(loadedPageCount === undefined ? pageCount : Math.min(loadedPageCount, pageCount)), onClick: () => onPageChange(page + 1), type: 'button', children: "Next" })] })] }));
|
|
8
9
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from 'react';
|
|
2
|
+
import { PsTableScrollAnchorService } from '../services/ps-table-scroll-anchor-service';
|
|
3
|
+
export const usePsScrollAnchor = (target, rowIds, isActive) => {
|
|
4
|
+
const anchor = useRef(null);
|
|
5
|
+
const previousRowIds = useRef(rowIds);
|
|
6
|
+
useLayoutEffect(() => {
|
|
7
|
+
const offset = target.scrollOffset;
|
|
8
|
+
if (!isActive || offset === null || offset <= 0) {
|
|
9
|
+
anchor.current = null;
|
|
10
|
+
previousRowIds.current = rowIds;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const previous = anchor.current;
|
|
14
|
+
if (previous !== null && previousRowIds.current !== rowIds) {
|
|
15
|
+
const index = PsTableScrollAnchorService.movedTo(previous, previousRowIds.current, rowIds);
|
|
16
|
+
const start = index === null ? undefined : target.getOffsetForIndex(index, 'start');
|
|
17
|
+
previousRowIds.current = rowIds;
|
|
18
|
+
if (start !== undefined) {
|
|
19
|
+
target.scrollToOffset(PsTableScrollAnchorService.offset(start[0], previous));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
previousRowIds.current = rowIds;
|
|
24
|
+
anchor.current = PsTableScrollAnchorService.capture(target.getVirtualItems(), rowIds, offset);
|
|
25
|
+
});
|
|
26
|
+
};
|
package/dist/esm/index.js
CHANGED
|
@@ -31,3 +31,4 @@ export * from './services/ps-table-stream-service';
|
|
|
31
31
|
export * from './components/ps-table-export-button';
|
|
32
32
|
export * from './constants/ps-table-download-config';
|
|
33
33
|
export * from './services/ps-table-download-service';
|
|
34
|
+
export * from './services/ps-table-scroll-anchor-service';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class PsTableScrollAnchorService {
|
|
2
|
+
static capture(items, rowIds, scrollOffset) {
|
|
3
|
+
const item = items.find((candidate) => candidate.start >= scrollOffset);
|
|
4
|
+
const anchored = item === undefined ? items[0] : item;
|
|
5
|
+
if (anchored === undefined || rowIds[anchored.index] === undefined)
|
|
6
|
+
return null;
|
|
7
|
+
return { distance: anchored.start - scrollOffset, id: rowIds[anchored.index] };
|
|
8
|
+
}
|
|
9
|
+
static movedTo(anchor, previousRowIds, rowIds) {
|
|
10
|
+
const previousIndex = previousRowIds.indexOf(anchor.id);
|
|
11
|
+
const index = rowIds.indexOf(anchor.id);
|
|
12
|
+
return index < 0 || previousIndex < 0 || index === previousIndex ? null : index;
|
|
13
|
+
}
|
|
14
|
+
static offset(rowStart, anchor) {
|
|
15
|
+
return Math.max(rowStart - anchor.distance, 0);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.usePsScrollAnchor = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const ps_table_scroll_anchor_service_1 = require("../services/ps-table-scroll-anchor-service");
|
|
6
|
+
const usePsScrollAnchor = (target, rowIds, isActive) => {
|
|
7
|
+
const anchor = (0, react_1.useRef)(null);
|
|
8
|
+
const previousRowIds = (0, react_1.useRef)(rowIds);
|
|
9
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
10
|
+
const offset = target.scrollOffset;
|
|
11
|
+
if (!isActive || offset === null || offset <= 0) {
|
|
12
|
+
anchor.current = null;
|
|
13
|
+
previousRowIds.current = rowIds;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const previous = anchor.current;
|
|
17
|
+
if (previous !== null && previousRowIds.current !== rowIds) {
|
|
18
|
+
const index = ps_table_scroll_anchor_service_1.PsTableScrollAnchorService.movedTo(previous, previousRowIds.current, rowIds);
|
|
19
|
+
const start = index === null ? undefined : target.getOffsetForIndex(index, 'start');
|
|
20
|
+
previousRowIds.current = rowIds;
|
|
21
|
+
if (start !== undefined) {
|
|
22
|
+
target.scrollToOffset(ps_table_scroll_anchor_service_1.PsTableScrollAnchorService.offset(start[0], previous));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
previousRowIds.current = rowIds;
|
|
27
|
+
anchor.current = ps_table_scroll_anchor_service_1.PsTableScrollAnchorService.capture(target.getVirtualItems(), rowIds, offset);
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
exports.usePsScrollAnchor = usePsScrollAnchor;
|
package/dist/index.d.ts
CHANGED
|
@@ -31,3 +31,4 @@ export * from './services/ps-table-stream-service';
|
|
|
31
31
|
export * from './components/ps-table-export-button';
|
|
32
32
|
export * from './constants/ps-table-download-config';
|
|
33
33
|
export * from './services/ps-table-download-service';
|
|
34
|
+
export * from './services/ps-table-scroll-anchor-service';
|
package/dist/index.js
CHANGED
|
@@ -47,3 +47,4 @@ __exportStar(require("./services/ps-table-stream-service"), exports);
|
|
|
47
47
|
__exportStar(require("./components/ps-table-export-button"), exports);
|
|
48
48
|
__exportStar(require("./constants/ps-table-download-config"), exports);
|
|
49
49
|
__exportStar(require("./services/ps-table-download-service"), exports);
|
|
50
|
+
__exportStar(require("./services/ps-table-scroll-anchor-service"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface PsTableScrollAnchorItem {
|
|
2
|
+
index: number;
|
|
3
|
+
start: number;
|
|
4
|
+
}
|
|
5
|
+
export interface PsTableScrollAnchorTarget {
|
|
6
|
+
getOffsetForIndex: (index: number, align: 'start') => readonly [number, string] | undefined;
|
|
7
|
+
getVirtualItems: () => PsTableScrollAnchorItem[];
|
|
8
|
+
scrollOffset: number | null;
|
|
9
|
+
scrollToOffset: (offset: number) => void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PsTableScrollAnchor } from '../interfaces/table-scroll-anchor';
|
|
2
|
+
import type { PsTableScrollAnchorItem } from '../interfaces/table-scroll-anchor-target';
|
|
3
|
+
export declare class PsTableScrollAnchorService {
|
|
4
|
+
static capture(items: PsTableScrollAnchorItem[], rowIds: string[], scrollOffset: number): PsTableScrollAnchor | null;
|
|
5
|
+
static movedTo(anchor: PsTableScrollAnchor, previousRowIds: string[], rowIds: string[]): number | null;
|
|
6
|
+
static offset(rowStart: number, anchor: PsTableScrollAnchor): number;
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsTableScrollAnchorService = void 0;
|
|
4
|
+
class PsTableScrollAnchorService {
|
|
5
|
+
static capture(items, rowIds, scrollOffset) {
|
|
6
|
+
const item = items.find((candidate) => candidate.start >= scrollOffset);
|
|
7
|
+
const anchored = item === undefined ? items[0] : item;
|
|
8
|
+
if (anchored === undefined || rowIds[anchored.index] === undefined)
|
|
9
|
+
return null;
|
|
10
|
+
return { distance: anchored.start - scrollOffset, id: rowIds[anchored.index] };
|
|
11
|
+
}
|
|
12
|
+
static movedTo(anchor, previousRowIds, rowIds) {
|
|
13
|
+
const previousIndex = previousRowIds.indexOf(anchor.id);
|
|
14
|
+
const index = rowIds.indexOf(anchor.id);
|
|
15
|
+
return index < 0 || previousIndex < 0 || index === previousIndex ? null : index;
|
|
16
|
+
}
|
|
17
|
+
static offset(rowStart, anchor) {
|
|
18
|
+
return Math.max(rowStart - anchor.distance, 0);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.PsTableScrollAnchorService = PsTableScrollAnchorService;
|