@shival99/z-ui 2.0.79 → 2.0.80
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.
|
@@ -6701,8 +6701,8 @@ class ZTableComponent {
|
|
|
6701
6701
|
},
|
|
6702
6702
|
];
|
|
6703
6703
|
_bulkBarExitDuration = 140;
|
|
6704
|
-
/** Stable identity key per virtual index (group
|
|
6705
|
-
* heights follow row identity —
|
|
6704
|
+
/** Stable identity key per virtual index (row/group id, not array index) so cached measured
|
|
6705
|
+
* heights follow row identity — prevents height jitter when scrolling fast. */
|
|
6706
6706
|
_virtualItemKeys = computed(() => {
|
|
6707
6707
|
if (!this.isVirtual()) {
|
|
6708
6708
|
return [];
|
|
@@ -6717,6 +6717,10 @@ class ZTableComponent {
|
|
|
6717
6717
|
}
|
|
6718
6718
|
return Array.from({ length: this._virtualGroupCount() }, (_, index) => index);
|
|
6719
6719
|
}, ...(ngDevMode ? [{ debugName: "_virtualItemKeys" }] : []));
|
|
6720
|
+
/** Estimate height learned from real rendered rows (dynamicSize); `virtual.size` is the fallback
|
|
6721
|
+
* until a row is measured. Lets not-yet-measured rows estimate close to reality, reducing layout
|
|
6722
|
+
* shift. Plain field (non-reactive) so updating it won't rebuild the virtualizer. */
|
|
6723
|
+
_dynamicEstimateHeight = null;
|
|
6720
6724
|
/** Virtualizer instance — operates on groups rather than individual rows */
|
|
6721
6725
|
virtualizer = injectVirtualizer(() => {
|
|
6722
6726
|
const groups = this.dynamicGroups();
|
|
@@ -6727,6 +6731,9 @@ class ZTableComponent {
|
|
|
6727
6731
|
const flatItems = this.virtualGroupedFlatItems();
|
|
6728
6732
|
const isGrouping = flatItems.length > 0;
|
|
6729
6733
|
const itemKeys = this._virtualItemKeys();
|
|
6734
|
+
const isDynamic = this.dynamicSize();
|
|
6735
|
+
// Estimate for not-yet-measured rows: learned height if available, else virtual.size.
|
|
6736
|
+
const dynamicRowEstimate = isDynamic && this._dynamicEstimateHeight !== null ? this._dynamicEstimateHeight : rowHeight;
|
|
6730
6737
|
return {
|
|
6731
6738
|
scrollElement,
|
|
6732
6739
|
count: isGrouping ? flatItems.length : groups.length > 0 ? groups.length : this._virtualGroupCount(),
|
|
@@ -6737,16 +6744,16 @@ class ZTableComponent {
|
|
|
6737
6744
|
if (isGrouping) {
|
|
6738
6745
|
return flatItems[index]?.type === 'group-header'
|
|
6739
6746
|
? Math.max(rowHeight, Z_VIRTUAL_GROUP_HEADER_HEIGHT)
|
|
6740
|
-
:
|
|
6747
|
+
: dynamicRowEstimate;
|
|
6741
6748
|
}
|
|
6742
6749
|
if (groups.length > 0 && groups[index]) {
|
|
6743
6750
|
const groupHeight = groups[index].height;
|
|
6744
6751
|
if (groupHeight !== null) {
|
|
6745
6752
|
return groupHeight;
|
|
6746
6753
|
}
|
|
6747
|
-
return groups[index].rowCount *
|
|
6754
|
+
return groups[index].rowCount * dynamicRowEstimate;
|
|
6748
6755
|
}
|
|
6749
|
-
return groupSize *
|
|
6756
|
+
return groupSize * dynamicRowEstimate;
|
|
6750
6757
|
},
|
|
6751
6758
|
scrollToFn: (offset, options, instance) => {
|
|
6752
6759
|
instance.scrollOffset = offset;
|
|
@@ -6775,14 +6782,45 @@ class ZTableComponent {
|
|
|
6775
6782
|
if (!view) {
|
|
6776
6783
|
return;
|
|
6777
6784
|
}
|
|
6778
|
-
//
|
|
6785
|
+
// Only sample heights until the estimate is locked; afterwards just measure (no extra reads).
|
|
6786
|
+
const needsEstimate = this._dynamicEstimateHeight === null;
|
|
6787
|
+
// Batch measurements into the next frame to avoid repositioning multiple times per scroll frame.
|
|
6779
6788
|
const frameId = view.requestAnimationFrame(() => {
|
|
6789
|
+
let measuredSum = 0;
|
|
6790
|
+
let measuredCount = 0;
|
|
6780
6791
|
for (const el of elements) {
|
|
6781
|
-
|
|
6792
|
+
const node = el.nativeElement;
|
|
6793
|
+
this.virtualizer.measureElement(node);
|
|
6794
|
+
if (needsEstimate) {
|
|
6795
|
+
// Layout already flushed by measureElement above, so this read hits the cache (no reflow).
|
|
6796
|
+
const { height } = node.getBoundingClientRect();
|
|
6797
|
+
if (height > 0) {
|
|
6798
|
+
measuredSum += height;
|
|
6799
|
+
measuredCount++;
|
|
6800
|
+
}
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
if (needsEstimate) {
|
|
6804
|
+
this._learnDynamicEstimate(measuredSum, measuredCount);
|
|
6782
6805
|
}
|
|
6783
6806
|
});
|
|
6784
6807
|
onCleanup(() => view.cancelAnimationFrame(frameId));
|
|
6785
6808
|
}, ...(ngDevMode ? [{ debugName: "_measureVirtualItems" }] : []));
|
|
6809
|
+
/** Learn estimate height from rendered rows. Locks ONCE so the estimate doesn't jump every scroll
|
|
6810
|
+
* frame (each row is still measured exactly on render). Re-flows via virtualizer.measure(). */
|
|
6811
|
+
_learnDynamicEstimate(measuredSum, measuredCount) {
|
|
6812
|
+
if (this._dynamicEstimateHeight !== null || measuredCount === 0) {
|
|
6813
|
+
return;
|
|
6814
|
+
}
|
|
6815
|
+
const average = Math.round(measuredSum / measuredCount);
|
|
6816
|
+
// Skip re-flow when already equal to the default size.
|
|
6817
|
+
if (average <= 0 || average === this.virtualRowHeight()) {
|
|
6818
|
+
this._dynamicEstimateHeight = average > 0 ? average : null;
|
|
6819
|
+
return;
|
|
6820
|
+
}
|
|
6821
|
+
this._dynamicEstimateHeight = average;
|
|
6822
|
+
this.virtualizer.measure();
|
|
6823
|
+
}
|
|
6786
6824
|
_rowDragAutoScroll = effect(onCleanup => {
|
|
6787
6825
|
const scrollbar = this.tbodyScrollbar();
|
|
6788
6826
|
if (!scrollbar?.adapter.initialized()) {
|
|
@@ -7038,6 +7076,8 @@ class ZTableComponent {
|
|
|
7038
7076
|
}
|
|
7039
7077
|
});
|
|
7040
7078
|
explicitEffect([this.columnFilters, this.globalFilter, this.pagination, this.sorting, this._data], () => {
|
|
7079
|
+
// New dataset may have different row heights -> relearn the estimate.
|
|
7080
|
+
this._dynamicEstimateHeight = null;
|
|
7041
7081
|
queueMicrotask(() => {
|
|
7042
7082
|
this._checkVerticalScroll();
|
|
7043
7083
|
this._checkHorizontalScroll();
|