@reforgium/data-grid 3.2.2 → 3.2.3
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/CHANGELOG.md +14 -0
- package/fesm2022/{reforgium-data-grid-grid-overlay-scroll.feature-CaO2mnI-.mjs → reforgium-data-grid-grid-overlay-scroll.feature-DQp-sU6c.mjs} +2 -2
- package/fesm2022/{reforgium-data-grid-reforgium-data-grid-MQb2oHWO.mjs → reforgium-data-grid-reforgium-data-grid-DUpCJ9P0.mjs} +56 -22
- package/fesm2022/reforgium-data-grid.mjs +1 -1
- package/package.json +1 -1
- package/types/reforgium-data-grid.d.ts +8 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [3.2.3]: 13.05.2026
|
|
2
|
+
|
|
3
|
+
### Fix:
|
|
4
|
+
- `DataGrid`: source/infinity — `totalRowCount` no longer collapses to `0` (empty state) after the internal page buffer evicts early pages on long scrolls when the source does not return `totalElements`; row-count knowledge is now tracked via a monotonic high-water mark (`knownRowCount`) plus end-of-data state (`endReached` / `confirmedTotal`) updated when each page lands, instead of walking the eviction-bound `sourcePages` map
|
|
5
|
+
- `DataGrid`: source/infinity — buffer eviction now anchors `pageBase` and never evicts it, so `localToAbsolutePage` and contiguous-loaded-row accounting stay correct after scrolling past `MAX_BUFFERED_PAGES`
|
|
6
|
+
|
|
7
|
+
### Test:
|
|
8
|
+
- added regression coverage: monotonic `totalRowCount` without `totalElements` (optimistic probe page, fixed end after short page, post-end full page does not unwind the total), 120-page scroll past `MAX_BUFFERED_PAGES` keeps `totalRowCount` stable, and anchor page survives eviction
|
|
9
|
+
|
|
10
|
+
### Docs:
|
|
11
|
+
- `GridPagedDataSource.version`: tightened JSDoc — without `totalElements` the grid pins end-of-data on the first short/empty page, so the source must bump `version` on dataset growth/replacement to clear the pin; mutating `items()` in place without a bump leaves the grid with a stale row count
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
1
15
|
## [3.2.1]: 17.04.2026
|
|
2
16
|
|
|
3
17
|
### Fix:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as computeScrollbarState, a as clampThumbTop, m as mapThumbTopToScrollTop } from './reforgium-data-grid-reforgium-data-grid-
|
|
1
|
+
import { c as computeScrollbarState, a as clampThumbTop, m as mapThumbTopToScrollTop } from './reforgium-data-grid-reforgium-data-grid-DUpCJ9P0.mjs';
|
|
2
2
|
|
|
3
3
|
function createGridOverlayScrollFeature(ctx) {
|
|
4
4
|
const showScrollbar = () => {
|
|
@@ -76,4 +76,4 @@ function createGridOverlayScrollFeature(ctx) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
export { createGridOverlayScrollFeature };
|
|
79
|
-
//# sourceMappingURL=reforgium-data-grid-grid-overlay-scroll.feature-
|
|
79
|
+
//# sourceMappingURL=reforgium-data-grid-grid-overlay-scroll.feature-DQp-sU6c.mjs.map
|
|
@@ -2162,6 +2162,12 @@ function createGridSourceDataFeature(ctx) {
|
|
|
2162
2162
|
let requestGeneration = 0;
|
|
2163
2163
|
let hasReceivedData = false;
|
|
2164
2164
|
let pageBase = 0;
|
|
2165
|
+
// Row knowledge accounting. Decoupled from `sourcePages` so that buffer eviction
|
|
2166
|
+
// (MAX_BUFFERED_PAGES) cannot collapse totalRowCount back to 0 once a source
|
|
2167
|
+
// without `totalElements` has scrolled past the buffer window.
|
|
2168
|
+
let knownRowCount = 0;
|
|
2169
|
+
let endReached = false;
|
|
2170
|
+
let confirmedTotal = null;
|
|
2165
2171
|
const hasSessionState = () => sourcePages.size > 0 || pendingPages.size > 0 || queuedPages.length > 0 || activeRequests > 0 || hasReceivedData;
|
|
2166
2172
|
const resolvedLoading = () => ctx.getSource()?.loading() ?? ctx.getFallbackLoading();
|
|
2167
2173
|
const totalRowCount = () => {
|
|
@@ -2177,14 +2183,13 @@ function createGridSourceDataFeature(ctx) {
|
|
|
2177
2183
|
const shiftedTotal = Math.max(0, knownTotal - pageBase * pageSize);
|
|
2178
2184
|
return shiftedTotal > 0 ? shiftedTotal : (source.items()?.length ?? 0);
|
|
2179
2185
|
}
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
return 0;
|
|
2186
|
+
if (endReached) {
|
|
2187
|
+
return confirmedTotal ?? 0;
|
|
2183
2188
|
}
|
|
2184
|
-
if (
|
|
2185
|
-
return
|
|
2189
|
+
if (knownRowCount <= 0) {
|
|
2190
|
+
return 0;
|
|
2186
2191
|
}
|
|
2187
|
-
return
|
|
2192
|
+
return knownRowCount + Math.max(1, source.pageSize || ctx.getFallbackPageSize());
|
|
2188
2193
|
}
|
|
2189
2194
|
const knownTotal = resolvedTotalElements(source);
|
|
2190
2195
|
if (knownTotal !== null) {
|
|
@@ -2341,7 +2346,10 @@ function createGridSourceDataFeature(ctx) {
|
|
|
2341
2346
|
}
|
|
2342
2347
|
pageBase = sourcePages.size === 0 ? Math.max(0, source.page || 0) : pageBase;
|
|
2343
2348
|
const pageItems = source.items() ?? [];
|
|
2344
|
-
|
|
2349
|
+
const sourcePage = Math.max(0, source.page || 0);
|
|
2350
|
+
const pageSize = Math.max(1, source.pageSize || ctx.getFallbackPageSize());
|
|
2351
|
+
sourcePages.set(sourcePage, pageItems);
|
|
2352
|
+
recordPageKnowledge(sourcePage, pageItems, pageSize);
|
|
2345
2353
|
if (!hasReceivedData && pageItems.length > 0) {
|
|
2346
2354
|
hasReceivedData = true;
|
|
2347
2355
|
}
|
|
@@ -2363,8 +2371,37 @@ function createGridSourceDataFeature(ctx) {
|
|
|
2363
2371
|
pendingPages.clear();
|
|
2364
2372
|
activeRequests = 0;
|
|
2365
2373
|
sourcePages.clear();
|
|
2374
|
+
knownRowCount = 0;
|
|
2375
|
+
endReached = false;
|
|
2376
|
+
confirmedTotal = null;
|
|
2366
2377
|
bufferVersion.update((current) => current + 1);
|
|
2367
2378
|
};
|
|
2379
|
+
const recordPageKnowledge = (sourcePage, pageItems, pageSize) => {
|
|
2380
|
+
if (sourcePage < pageBase) {
|
|
2381
|
+
return;
|
|
2382
|
+
}
|
|
2383
|
+
const relPage = sourcePage - pageBase;
|
|
2384
|
+
if (pageItems.length === 0) {
|
|
2385
|
+
// Empty page at or beyond the first known page implies the dataset ends here.
|
|
2386
|
+
// For the initial empty sync (relPage === 0) we stay non-committal so that a
|
|
2387
|
+
// later in-place items() update can still surface real rows.
|
|
2388
|
+
if (relPage > 0) {
|
|
2389
|
+
endReached = true;
|
|
2390
|
+
const total = relPage * pageSize;
|
|
2391
|
+
confirmedTotal = confirmedTotal === null ? total : Math.min(confirmedTotal, total);
|
|
2392
|
+
}
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
if (pageItems.length < pageSize) {
|
|
2396
|
+
endReached = true;
|
|
2397
|
+
const total = relPage * pageSize + pageItems.length;
|
|
2398
|
+
confirmedTotal = confirmedTotal === null ? total : Math.min(confirmedTotal, total);
|
|
2399
|
+
return;
|
|
2400
|
+
}
|
|
2401
|
+
if (!endReached) {
|
|
2402
|
+
knownRowCount = Math.max(knownRowCount, (relPage + 1) * pageSize);
|
|
2403
|
+
}
|
|
2404
|
+
};
|
|
2368
2405
|
const pushPage = (pages, page, maxPage) => {
|
|
2369
2406
|
if (page < 0 || page > maxPage || pages.includes(page)) {
|
|
2370
2407
|
return;
|
|
@@ -2404,7 +2441,10 @@ function createGridSourceDataFeature(ctx) {
|
|
|
2404
2441
|
// только последнюю из страниц, если несколько запросов завершились до
|
|
2405
2442
|
// того, как эффект успел выполниться, и все промежуточные страницы теряются.
|
|
2406
2443
|
if (ctx.getMode() === 'infinity' && !sourcePages.has(nextPage)) {
|
|
2407
|
-
|
|
2444
|
+
const capturedItems = activeSource.items() ?? [];
|
|
2445
|
+
const pageSize = Math.max(1, activeSource.pageSize || ctx.getFallbackPageSize());
|
|
2446
|
+
sourcePages.set(nextPage, capturedItems);
|
|
2447
|
+
recordPageKnowledge(nextPage, capturedItems, pageSize);
|
|
2408
2448
|
}
|
|
2409
2449
|
})
|
|
2410
2450
|
.finally(() => {
|
|
@@ -2431,18 +2471,6 @@ function createGridSourceDataFeature(ctx) {
|
|
|
2431
2471
|
}
|
|
2432
2472
|
return loaded;
|
|
2433
2473
|
};
|
|
2434
|
-
const hasReachedInfinityEnd = (source) => {
|
|
2435
|
-
const pageSize = Math.max(1, source.pageSize || ctx.getFallbackPageSize());
|
|
2436
|
-
let page = pageBase;
|
|
2437
|
-
while (sourcePages.has(page)) {
|
|
2438
|
-
const items = sourcePages.get(page) ?? [];
|
|
2439
|
-
if (items.length < pageSize) {
|
|
2440
|
-
return true;
|
|
2441
|
-
}
|
|
2442
|
-
page++;
|
|
2443
|
-
}
|
|
2444
|
-
return false;
|
|
2445
|
-
};
|
|
2446
2474
|
const resolvedTotalElements = (source) => {
|
|
2447
2475
|
if (typeof source.totalElements !== 'number' || !Number.isFinite(source.totalElements)) {
|
|
2448
2476
|
return null;
|
|
@@ -2465,6 +2493,12 @@ function createGridSourceDataFeature(ctx) {
|
|
|
2465
2493
|
if (sourcePages.size <= MAX_BUFFERED_PAGES) {
|
|
2466
2494
|
break;
|
|
2467
2495
|
}
|
|
2496
|
+
// Never evict the anchor page: `localToAbsolutePage` and the contiguous-loaded
|
|
2497
|
+
// walk both start from `pageBase`, so dropping it would cascade into wrong
|
|
2498
|
+
// request-progress numbers even though totalRowCount is now buffer-independent.
|
|
2499
|
+
if (page === pageBase) {
|
|
2500
|
+
continue;
|
|
2501
|
+
}
|
|
2468
2502
|
if (!keepPages.has(page)) {
|
|
2469
2503
|
sourcePages.delete(page);
|
|
2470
2504
|
}
|
|
@@ -4087,7 +4121,7 @@ class DataGrid {
|
|
|
4087
4121
|
if (this.overlayScrollFeaturePromise) {
|
|
4088
4122
|
return this.overlayScrollFeaturePromise;
|
|
4089
4123
|
}
|
|
4090
|
-
this.overlayScrollFeaturePromise = import('./reforgium-data-grid-grid-overlay-scroll.feature-
|
|
4124
|
+
this.overlayScrollFeaturePromise = import('./reforgium-data-grid-grid-overlay-scroll.feature-DQp-sU6c.mjs').then(({ createGridOverlayScrollFeature }) => {
|
|
4091
4125
|
const feature = createGridOverlayScrollFeature({
|
|
4092
4126
|
getScrollElement: () => this.scrollEl()?.nativeElement ?? null,
|
|
4093
4127
|
getThumbTop: () => this.vm.thumbTopPx(),
|
|
@@ -4212,4 +4246,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
4212
4246
|
*/
|
|
4213
4247
|
|
|
4214
4248
|
export { DataGridTypeCellTemplateDirective as D, clampThumbTop as a, DataGridCellTemplateDirective as b, computeScrollbarState as c, DataGridHeaderTemplateDirective as d, DataGridRowDirective as e, DataGridDeclarativeColumn as f, DataGridDeclarativeHeaderDirective as g, DataGridDeclarativeCellDirective as h, DataGridCellEmptyDirective as i, DataGridCellLoadingDirective as j, DataGridStickyRowDirective as k, DataGridSortIconDirective as l, mapThumbTopToScrollTop as m, DataGridExpanderIconDirective as n, DATA_GRID_CONFIG as o, DATA_GRID_HEADER_TEXT_RESOLVER as p, DATA_GRID_TYPE_RENDERERS as q, DATA_GRID_TYPE_TRANSFORMERS as r, DEFAULT_DATA_GRID_DEFAULTS as s, provideDataGridDefaults as t, provideDataGridHeaderTextResolver as u, provideDataGridHeaderTextResolverWithParent as v, provideDataGridTypeRenderers as w, provideDataGridTypeTransformers as x, DataGrid as y };
|
|
4215
|
-
//# sourceMappingURL=reforgium-data-grid-reforgium-data-grid-
|
|
4249
|
+
//# sourceMappingURL=reforgium-data-grid-reforgium-data-grid-DUpCJ9P0.mjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { o as DATA_GRID_CONFIG, p as DATA_GRID_HEADER_TEXT_RESOLVER, q as DATA_GRID_TYPE_RENDERERS, r as DATA_GRID_TYPE_TRANSFORMERS, s as DEFAULT_DATA_GRID_DEFAULTS, y as DataGrid, i as DataGridCellEmptyDirective, j as DataGridCellLoadingDirective, b as DataGridCellTemplateDirective, h as DataGridDeclarativeCellDirective, f as DataGridDeclarativeColumn, g as DataGridDeclarativeHeaderDirective, n as DataGridExpanderIconDirective, d as DataGridHeaderTemplateDirective, e as DataGridRowDirective, l as DataGridSortIconDirective, k as DataGridStickyRowDirective, D as DataGridTypeCellTemplateDirective, t as provideDataGridDefaults, u as provideDataGridHeaderTextResolver, v as provideDataGridHeaderTextResolverWithParent, w as provideDataGridTypeRenderers, x as provideDataGridTypeTransformers } from './reforgium-data-grid-reforgium-data-grid-
|
|
1
|
+
export { o as DATA_GRID_CONFIG, p as DATA_GRID_HEADER_TEXT_RESOLVER, q as DATA_GRID_TYPE_RENDERERS, r as DATA_GRID_TYPE_TRANSFORMERS, s as DEFAULT_DATA_GRID_DEFAULTS, y as DataGrid, i as DataGridCellEmptyDirective, j as DataGridCellLoadingDirective, b as DataGridCellTemplateDirective, h as DataGridDeclarativeCellDirective, f as DataGridDeclarativeColumn, g as DataGridDeclarativeHeaderDirective, n as DataGridExpanderIconDirective, d as DataGridHeaderTemplateDirective, e as DataGridRowDirective, l as DataGridSortIconDirective, k as DataGridStickyRowDirective, D as DataGridTypeCellTemplateDirective, t as provideDataGridDefaults, u as provideDataGridHeaderTextResolver, v as provideDataGridHeaderTextResolverWithParent, w as provideDataGridTypeRenderers, x as provideDataGridTypeTransformers } from './reforgium-data-grid-reforgium-data-grid-DUpCJ9P0.mjs';
|
|
2
2
|
//# sourceMappingURL=reforgium-data-grid.mjs.map
|
package/package.json
CHANGED
|
@@ -768,7 +768,14 @@ interface GridPagedDataSource<Data extends AnyDict = AnyDict> {
|
|
|
768
768
|
* after the next request returns a short page.
|
|
769
769
|
*/
|
|
770
770
|
totalElements?: number;
|
|
771
|
-
/**
|
|
771
|
+
/**
|
|
772
|
+
* Optional dataset revision signal. Increment to force the grid to clear its local page buffer.
|
|
773
|
+
*
|
|
774
|
+
* Required (when present) to be incremented on any dataset growth, replacement, or filter/sort change:
|
|
775
|
+
* in `infinity` mode without `totalElements` the grid pins end-of-data state on the first short/empty
|
|
776
|
+
* page it sees, and only a version bump clears that pin. Mutating `items()` in place without bumping
|
|
777
|
+
* `version` will leave the grid with a stale row count.
|
|
778
|
+
*/
|
|
772
779
|
version?: Signal<number>;
|
|
773
780
|
/** Current source-side sort state. */
|
|
774
781
|
sort?: ReadonlyArray<GridSortItem<Data>>;
|