ng-virtual-list 18.7.12 → 18.7.13
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/README.md +9 -8
- package/esm2022/lib/const/index.mjs +3 -2
- package/esm2022/lib/enums/collection-mode.mjs +2 -0
- package/esm2022/lib/enums/collection-modes.mjs +18 -0
- package/esm2022/lib/enums/index.mjs +3 -2
- package/esm2022/lib/ng-virtual-list.component.mjs +58 -17
- package/esm2022/lib/utils/isCollectionMode.mjs +15 -0
- package/esm2022/lib/utils/trackBox.mjs +45 -16
- package/fesm2022/ng-virtual-list.mjs +131 -29
- package/fesm2022/ng-virtual-list.mjs.map +1 -1
- package/lib/const/index.d.ts +2 -1
- package/lib/enums/collection-mode.d.ts +8 -0
- package/lib/enums/collection-modes.d.ts +16 -0
- package/lib/enums/index.d.ts +4 -2
- package/lib/ng-virtual-list.component.d.ts +11 -2
- package/lib/utils/isCollectionMode.d.ts +8 -0
- package/lib/utils/trackBox.d.ts +17 -9
- package/package.json +1 -1
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Injectable, inject, ChangeDetectorRef, signal, ElementRef, Component, ChangeDetectionStrategy, viewChild, output, input, ViewContainerRef, ViewEncapsulation, ViewChild, NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
|
|
3
|
-
import { Subject, tap, fromEvent, combineLatest, map, filter, distinctUntilChanged,
|
|
3
|
+
import { Subject, tap, fromEvent, combineLatest, map, filter, distinctUntilChanged, switchMap, of } from 'rxjs';
|
|
4
4
|
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
|
5
5
|
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
6
6
|
import * as i1 from '@angular/common';
|
|
7
7
|
import { CommonModule } from '@angular/common';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Action modes for collection elements.
|
|
11
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/18.x/projects/ng-virtual-list/src/lib/enums/collection-modes.ts
|
|
12
|
+
* @author Evgenii Grebennikov
|
|
13
|
+
* @email djonnyx@gmail.com
|
|
14
|
+
*/
|
|
15
|
+
var CollectionModes;
|
|
16
|
+
(function (CollectionModes) {
|
|
17
|
+
/**
|
|
18
|
+
* When adding elements to the beginning of the collection, the scroll remains at the current position.
|
|
19
|
+
*/
|
|
20
|
+
CollectionModes["NORMAL"] = "normal";
|
|
21
|
+
/**
|
|
22
|
+
* When adding elements to the beginning of the collection, the scroll is shifted by the sum of the sizes of the new elements.
|
|
23
|
+
*/
|
|
24
|
+
CollectionModes["LAZY"] = "lazy";
|
|
25
|
+
})(CollectionModes || (CollectionModes = {}));
|
|
26
|
+
|
|
9
27
|
/**
|
|
10
28
|
* Axis of the arrangement of virtual list elements.
|
|
11
29
|
* @link https://github.com/DjonnyX/ng-virtual-list/blob/18.x/projects/ng-virtual-list/src/lib/enums/directions.ts
|
|
@@ -75,6 +93,7 @@ const DEFAULT_ENABLED_BUFFER_OPTIMIZATION = false;
|
|
|
75
93
|
const DEFAULT_DYNAMIC_SIZE = false;
|
|
76
94
|
const TRACK_BY_PROPERTY_NAME = 'id';
|
|
77
95
|
const DEFAULT_DIRECTION = Directions.VERTICAL;
|
|
96
|
+
const DEFAULT_COLLECTION_MODE = CollectionModes.NORMAL;
|
|
78
97
|
const DISPLAY_OBJECTS_LENGTH_MESUREMENT_ERROR = 1;
|
|
79
98
|
const MAX_SCROLL_TO_ITERATIONS = 5;
|
|
80
99
|
const DEFAULT_SNAPPING_METHOD = SnappingMethods.NORMAL;
|
|
@@ -1244,7 +1263,11 @@ const bufferInterpolation = (currentBufferValue, array, value, extra) => {
|
|
|
1244
1263
|
return Math.ceil(buffer / l);
|
|
1245
1264
|
};
|
|
1246
1265
|
|
|
1247
|
-
|
|
1266
|
+
var TrackBoxEvents;
|
|
1267
|
+
(function (TrackBoxEvents) {
|
|
1268
|
+
TrackBoxEvents["CHANGE"] = "change";
|
|
1269
|
+
TrackBoxEvents["RESET"] = "reset";
|
|
1270
|
+
})(TrackBoxEvents || (TrackBoxEvents = {}));
|
|
1248
1271
|
var ItemDisplayMethods;
|
|
1249
1272
|
(function (ItemDisplayMethods) {
|
|
1250
1273
|
ItemDisplayMethods[ItemDisplayMethods["CREATE"] = 0] = "CREATE";
|
|
@@ -1252,7 +1275,7 @@ var ItemDisplayMethods;
|
|
|
1252
1275
|
ItemDisplayMethods[ItemDisplayMethods["DELETE"] = 2] = "DELETE";
|
|
1253
1276
|
ItemDisplayMethods[ItemDisplayMethods["NOT_CHANGED"] = 3] = "NOT_CHANGED";
|
|
1254
1277
|
})(ItemDisplayMethods || (ItemDisplayMethods = {}));
|
|
1255
|
-
const DEFAULT_BUFFER_EXTREMUM_THRESHOLD = 15, DEFAULT_MAX_BUFFER_SEQUENCE_LENGTH = 30, DEFAULT_RESET_BUFFER_SIZE_TIMEOUT = 10000;
|
|
1278
|
+
const DEFAULT_BUFFER_EXTREMUM_THRESHOLD = 15, DEFAULT_MAX_BUFFER_SEQUENCE_LENGTH = 30, DEFAULT_RESET_BUFFER_SIZE_TIMEOUT = 10000, IS_NEW = 'isNew';
|
|
1256
1279
|
/**
|
|
1257
1280
|
* An object that performs tracking, calculations and caching.
|
|
1258
1281
|
* @link https://github.com/DjonnyX/ng-virtual-list/blob/18.x/projects/ng-virtual-list/src/lib/utils/trackBox.ts
|
|
@@ -1289,6 +1312,13 @@ class TrackBox extends CacheMap {
|
|
|
1289
1312
|
}
|
|
1290
1313
|
this._isSnappingMethodAdvanced = v;
|
|
1291
1314
|
}
|
|
1315
|
+
_isLazy = false;
|
|
1316
|
+
set isLazy(v) {
|
|
1317
|
+
if (this._isLazy === v) {
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
this._isLazy = v;
|
|
1321
|
+
}
|
|
1292
1322
|
/**
|
|
1293
1323
|
* Set the trackBy property
|
|
1294
1324
|
*/
|
|
@@ -1321,7 +1351,7 @@ class TrackBox extends CacheMap {
|
|
|
1321
1351
|
get crudDetected() { return this._crudDetected; }
|
|
1322
1352
|
fireChangeIfNeed() {
|
|
1323
1353
|
if (this.changesDetected()) {
|
|
1324
|
-
this.dispatch(
|
|
1354
|
+
this.dispatch(TrackBoxEvents.CHANGE, this._version);
|
|
1325
1355
|
}
|
|
1326
1356
|
}
|
|
1327
1357
|
_previousTotalSize = 0;
|
|
@@ -1337,7 +1367,7 @@ class TrackBox extends CacheMap {
|
|
|
1337
1367
|
_maxBufferSize = this._defaultBufferSize;
|
|
1338
1368
|
_resetBufferSizeTimeout = DEFAULT_RESET_BUFFER_SIZE_TIMEOUT;
|
|
1339
1369
|
_resetBufferSizeTimer;
|
|
1340
|
-
|
|
1370
|
+
isReseted = true;
|
|
1341
1371
|
lifeCircle() {
|
|
1342
1372
|
this.fireChangeIfNeed();
|
|
1343
1373
|
this.lifeCircleDo();
|
|
@@ -1350,11 +1380,19 @@ class TrackBox extends CacheMap {
|
|
|
1350
1380
|
console.warn('Attention! The collection must be immutable.');
|
|
1351
1381
|
return;
|
|
1352
1382
|
}
|
|
1353
|
-
|
|
1354
|
-
|
|
1383
|
+
let reseted = this.isReseted;
|
|
1384
|
+
if (reseted) {
|
|
1385
|
+
if (!(!this._previousCollection || this._previousCollection.length === 0)) {
|
|
1386
|
+
reseted = false;
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
if (!reseted && (!currentCollection || currentCollection.length === 0)) {
|
|
1390
|
+
reseted = true;
|
|
1355
1391
|
}
|
|
1392
|
+
this.isReseted = reseted;
|
|
1393
|
+
this.dispatch(TrackBoxEvents.RESET, reseted);
|
|
1356
1394
|
this.updateCache(this._previousCollection, currentCollection, itemSize);
|
|
1357
|
-
this._previousCollection = currentCollection;
|
|
1395
|
+
this._previousCollection = [...(currentCollection || [])];
|
|
1358
1396
|
}
|
|
1359
1397
|
/**
|
|
1360
1398
|
* Update the cache of items from the list
|
|
@@ -1577,9 +1615,10 @@ class TrackBox extends CacheMap {
|
|
|
1577
1615
|
leftItemsOffset = rightItemsOffset = bufferSize;
|
|
1578
1616
|
}
|
|
1579
1617
|
let itemsFromStartToScrollEnd = -1, itemsFromDisplayEndToOffsetEnd = 0, itemsFromStartToDisplayEnd = -1, leftItemLength = 0, rightItemLength = 0, leftItemsWeight = 0, rightItemsWeight = 0, leftHiddenItemsWeight = 0, totalItemsToDisplayEndWeight = 0, leftSizeOfAddedItems = 0, leftSizeOfUpdatedItems = 0, leftSizeOfDeletedItems = 0, itemById = undefined, itemByIdPos = 0, targetDisplayItemIndex = -1, isTargetInOverscroll = false, actualScrollSize = itemByIdPos, totalSize = 0, startIndex, isFromItemIdFound = false, deltaFromStartCreation = 0;
|
|
1618
|
+
let isNew = !this.isReseted && (scrollSize === 0);
|
|
1580
1619
|
// If the list is dynamic or there are new elements in the collection, then it switches to the long algorithm.
|
|
1581
1620
|
if (dynamicSize) {
|
|
1582
|
-
let y = 0, stickyCollectionItem = undefined, stickyComponentSize = 0
|
|
1621
|
+
let y = 0, stickyCollectionItem = undefined, stickyComponentSize = 0;
|
|
1583
1622
|
for (let i = 0, l = collection.length; i < l; i++) {
|
|
1584
1623
|
const ii = i + 1, collectionItem = collection[i], id = collectionItem.id;
|
|
1585
1624
|
let componentSize = 0, componentSizeDelta = 0, itemDisplayMethod = ItemDisplayMethods.NOT_CHANGED;
|
|
@@ -1587,8 +1626,8 @@ class TrackBox extends CacheMap {
|
|
|
1587
1626
|
const bounds = map.get(id) || { width: typicalItemSize, height: typicalItemSize };
|
|
1588
1627
|
componentSize = bounds[sizeProperty];
|
|
1589
1628
|
itemDisplayMethod = bounds?.method ?? ItemDisplayMethods.UPDATE;
|
|
1590
|
-
const isItemNew = bounds
|
|
1591
|
-
if (
|
|
1629
|
+
const isItemNew = bounds?.[IS_NEW] ?? this._isLazy;
|
|
1630
|
+
if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0].id]?.sticky)) {
|
|
1592
1631
|
isNew = false;
|
|
1593
1632
|
}
|
|
1594
1633
|
switch (itemDisplayMethod) {
|
|
@@ -1725,8 +1764,15 @@ class TrackBox extends CacheMap {
|
|
|
1725
1764
|
if (map.has(id)) {
|
|
1726
1765
|
const bounds = map.get(id);
|
|
1727
1766
|
itemDisplayMethod = bounds?.method ?? ItemDisplayMethods.UPDATE;
|
|
1767
|
+
const isItemNew = bounds?.[IS_NEW] ?? this._isLazy;
|
|
1768
|
+
if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0].id]?.sticky)) {
|
|
1769
|
+
isNew = false;
|
|
1770
|
+
}
|
|
1728
1771
|
if (itemDisplayMethod === ItemDisplayMethods.CREATE) {
|
|
1729
|
-
|
|
1772
|
+
if (isNew) {
|
|
1773
|
+
deltaFromStartCreation += componentSize;
|
|
1774
|
+
}
|
|
1775
|
+
map.set(id, { ...bounds, method: ItemDisplayMethods.NOT_CHANGED, isNew });
|
|
1730
1776
|
}
|
|
1731
1777
|
}
|
|
1732
1778
|
if (deletedItemsMap.hasOwnProperty(i)) {
|
|
@@ -1738,7 +1784,9 @@ class TrackBox extends CacheMap {
|
|
|
1738
1784
|
if (y < scrollSize - componentSize) {
|
|
1739
1785
|
switch (itemDisplayMethod) {
|
|
1740
1786
|
case ItemDisplayMethods.CREATE: {
|
|
1741
|
-
|
|
1787
|
+
if (!isNew) {
|
|
1788
|
+
leftSizeOfUpdatedItems += componentSize;
|
|
1789
|
+
}
|
|
1742
1790
|
break;
|
|
1743
1791
|
}
|
|
1744
1792
|
case ItemDisplayMethods.UPDATE: {
|
|
@@ -1834,7 +1882,7 @@ class TrackBox extends CacheMap {
|
|
|
1834
1882
|
height: isVertical ? size : normalizedItemHeight,
|
|
1835
1883
|
delta: 0,
|
|
1836
1884
|
}, config = {
|
|
1837
|
-
new: cache
|
|
1885
|
+
new: cache?.[IS_NEW] === true,
|
|
1838
1886
|
odd: isOdd,
|
|
1839
1887
|
even: !isOdd,
|
|
1840
1888
|
isVertical,
|
|
@@ -1876,7 +1924,7 @@ class TrackBox extends CacheMap {
|
|
|
1876
1924
|
height: h,
|
|
1877
1925
|
delta: 0,
|
|
1878
1926
|
}, config = {
|
|
1879
|
-
new: cache
|
|
1927
|
+
new: cache?.[IS_NEW] === true,
|
|
1880
1928
|
odd: isOdd,
|
|
1881
1929
|
even: !isOdd,
|
|
1882
1930
|
isVertical,
|
|
@@ -1917,7 +1965,7 @@ class TrackBox extends CacheMap {
|
|
|
1917
1965
|
height: isVertical ? size : normalizedItemHeight,
|
|
1918
1966
|
delta: 0,
|
|
1919
1967
|
}, config = {
|
|
1920
|
-
new: cache
|
|
1968
|
+
new: cache?.[IS_NEW] === true,
|
|
1921
1969
|
odd: isOdd,
|
|
1922
1970
|
even: !isOdd,
|
|
1923
1971
|
isVertical,
|
|
@@ -2103,6 +2151,20 @@ const copyValueAsReadonly = (source) => {
|
|
|
2103
2151
|
return source;
|
|
2104
2152
|
};
|
|
2105
2153
|
|
|
2154
|
+
const NORMAL_ALIASES = [CollectionModes.NORMAL, 'normal'], LAZY_ALIASES = [CollectionModes.LAZY, 'lazy'];
|
|
2155
|
+
/**
|
|
2156
|
+
* Determines the axis membership of a virtual list
|
|
2157
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/18.x/projects/ng-virtual-list/src/lib/utils/isCollectionMode.ts
|
|
2158
|
+
* @author Evgenii Grebennikov
|
|
2159
|
+
* @email djonnyx@gmail.com
|
|
2160
|
+
*/
|
|
2161
|
+
const isCollectionMode = (src, expected) => {
|
|
2162
|
+
if (LAZY_ALIASES.includes(expected)) {
|
|
2163
|
+
return LAZY_ALIASES.includes(src);
|
|
2164
|
+
}
|
|
2165
|
+
return NORMAL_ALIASES.includes(src);
|
|
2166
|
+
};
|
|
2167
|
+
|
|
2106
2168
|
const ROLE_LIST = 'list', ROLE_LIST_BOX = 'listbox';
|
|
2107
2169
|
const validateScrollIteration = (value) => {
|
|
2108
2170
|
return Number.isNaN(value) || (value < 0) ? 0 : value > MAX_SCROLL_TO_ITERATIONS ? MAX_SCROLL_TO_ITERATIONS : value;
|
|
@@ -2411,6 +2473,20 @@ class NgVirtualListComponent {
|
|
|
2411
2473
|
* Determines the direction in which elements are placed. Default value is "vertical".
|
|
2412
2474
|
*/
|
|
2413
2475
|
direction = input(DEFAULT_DIRECTION, { ...this._directionOptions });
|
|
2476
|
+
_collectionModeOptions = {
|
|
2477
|
+
transform: (v) => {
|
|
2478
|
+
const valid = validateString(v) && (v === 'normal' || v === 'lazy');
|
|
2479
|
+
if (!valid) {
|
|
2480
|
+
console.error('The "direction" parameter must have the value `normal` or `lazy`.');
|
|
2481
|
+
return DEFAULT_COLLECTION_MODE;
|
|
2482
|
+
}
|
|
2483
|
+
return v;
|
|
2484
|
+
},
|
|
2485
|
+
};
|
|
2486
|
+
/**
|
|
2487
|
+
* Determines the action modes for collection elements. Default value is "normal".
|
|
2488
|
+
*/
|
|
2489
|
+
collectionMode = input(DEFAULT_COLLECTION_MODE, { ...this._collectionModeOptions });
|
|
2414
2490
|
_bufferSizeOptions = {
|
|
2415
2491
|
transform: (v) => {
|
|
2416
2492
|
const valid = validateInt(v);
|
|
@@ -2501,6 +2577,7 @@ class NgVirtualListComponent {
|
|
|
2501
2577
|
get isMultiSelecting() { return this._isMultiSelecting; }
|
|
2502
2578
|
_isSnappingMethodAdvanced = this.getIsSnappingMethodAdvanced();
|
|
2503
2579
|
get isSnappingMethodAdvanced() { return this._isSnappingMethodAdvanced; }
|
|
2580
|
+
_isLazy = this.getIsLazy();
|
|
2504
2581
|
_isVertical = this.getIsVertical();
|
|
2505
2582
|
get orientation() {
|
|
2506
2583
|
return this._isVertical ? Directions.VERTICAL : Directions.HORIZONTAL;
|
|
@@ -2597,10 +2674,25 @@ class NgVirtualListComponent {
|
|
|
2597
2674
|
this._cacheVersion.set(v);
|
|
2598
2675
|
};
|
|
2599
2676
|
_cacheVersion = signal(-1);
|
|
2677
|
+
_isResetedReachStart = true;
|
|
2678
|
+
_onTrackBoxResetHandler = (v) => {
|
|
2679
|
+
if (v) {
|
|
2680
|
+
this._isResetedReachStart = true;
|
|
2681
|
+
const container = this._container()?.nativeElement;
|
|
2682
|
+
if (container) {
|
|
2683
|
+
const params = {
|
|
2684
|
+
[this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: 0,
|
|
2685
|
+
behavior: BEHAVIOR_INSTANT,
|
|
2686
|
+
};
|
|
2687
|
+
container.scrollTo(params);
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
};
|
|
2600
2691
|
constructor() {
|
|
2601
2692
|
NgVirtualListComponent.__nextId = NgVirtualListComponent.__nextId + 1 === Number.MAX_SAFE_INTEGER
|
|
2602
2693
|
? 0 : NgVirtualListComponent.__nextId + 1;
|
|
2603
2694
|
this._id = NgVirtualListComponent.__nextId;
|
|
2695
|
+
this._trackBox.addEventListener(TrackBoxEvents.RESET, this._onTrackBoxResetHandler);
|
|
2604
2696
|
this._service.initialize(this._trackBox);
|
|
2605
2697
|
this._service.itemToFocus = this.itemToFocus;
|
|
2606
2698
|
this._initialized = signal(false);
|
|
@@ -2613,12 +2705,13 @@ class NgVirtualListComponent {
|
|
|
2613
2705
|
this._service.listElement = v.nativeElement;
|
|
2614
2706
|
})).subscribe();
|
|
2615
2707
|
const $trackBy = toObservable(this.trackBy), $selectByClick = toObservable(this.selectByClick), $collapseByClick = toObservable(this.collapseByClick), $isScrollStart = toObservable(this._isScrollStart), $isScrollFinished = toObservable(this._isScrollFinished);
|
|
2616
|
-
$isScrollStart.pipe(takeUntilDestroyed(), distinctUntilChanged(),
|
|
2617
|
-
if (v) {
|
|
2708
|
+
$isScrollStart.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
|
|
2709
|
+
if (v && !this._isResetedReachStart) {
|
|
2618
2710
|
this.onScrollReachStart.emit();
|
|
2619
2711
|
}
|
|
2712
|
+
this._isResetedReachStart = false;
|
|
2620
2713
|
})).subscribe();
|
|
2621
|
-
$isScrollFinished.pipe(takeUntilDestroyed(), distinctUntilChanged(),
|
|
2714
|
+
$isScrollFinished.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
|
|
2622
2715
|
if (v) {
|
|
2623
2716
|
this.onScrollReachEnd.emit();
|
|
2624
2717
|
}
|
|
@@ -2632,7 +2725,10 @@ class NgVirtualListComponent {
|
|
|
2632
2725
|
$trackBy.pipe(takeUntilDestroyed(), tap(v => {
|
|
2633
2726
|
this._trackBox.trackingPropertyName = v;
|
|
2634
2727
|
})).subscribe();
|
|
2635
|
-
const $bounds = toObservable(this._bounds).pipe(filter(b => !!b)), $items = toObservable(this.items).pipe(map(i => !i ? [] : i)), $scrollSize = toObservable(this._scrollSize), $itemSize = toObservable(this.itemSize).pipe(map(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $bufferSize = toObservable(this.bufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $maxBufferSize = toObservable(this.maxBufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $itemConfigMap = toObservable(this.itemConfigMap).pipe(map(v => !v ? {} : v)), $snap = toObservable(this.snap), $isVertical = toObservable(this.direction).pipe(map(v => this.getIsVertical(v || DEFAULT_DIRECTION))), $dynamicSize = toObservable(this.dynamicSize), $enabledBufferOptimization = toObservable(this.enabledBufferOptimization), $snappingMethod = toObservable(this.snappingMethod).pipe(map(v => this.getIsSnappingMethodAdvanced(v || DEFAULT_SNAPPING_METHOD))), $methodForSelecting = toObservable(this.methodForSelecting), $selectedIds = toObservable(this.selectedIds), $collapsedIds = toObservable(this.collapsedIds).pipe(map(v => Array.isArray(v) ? v : [])), $collapsedItemIds = toObservable(this._collapsedItemIds).pipe(map(v => Array.isArray(v) ? v : [])), $actualItems = toObservable(this._actualItems), $cacheVersion = toObservable(this._cacheVersion);
|
|
2728
|
+
const $bounds = toObservable(this._bounds).pipe(filter(b => !!b)), $items = toObservable(this.items).pipe(map(i => !i ? [] : i)), $scrollSize = toObservable(this._scrollSize), $itemSize = toObservable(this.itemSize).pipe(map(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $bufferSize = toObservable(this.bufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $maxBufferSize = toObservable(this.maxBufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $itemConfigMap = toObservable(this.itemConfigMap).pipe(map(v => !v ? {} : v)), $snap = toObservable(this.snap), $isVertical = toObservable(this.direction).pipe(map(v => this.getIsVertical(v || DEFAULT_DIRECTION))), $isLazy = toObservable(this.collectionMode).pipe(map(v => this.getIsLazy(v || DEFAULT_COLLECTION_MODE))), $dynamicSize = toObservable(this.dynamicSize), $enabledBufferOptimization = toObservable(this.enabledBufferOptimization), $snappingMethod = toObservable(this.snappingMethod).pipe(map(v => this.getIsSnappingMethodAdvanced(v || DEFAULT_SNAPPING_METHOD))), $methodForSelecting = toObservable(this.methodForSelecting), $selectedIds = toObservable(this.selectedIds), $collapsedIds = toObservable(this.collapsedIds).pipe(map(v => Array.isArray(v) ? v : [])), $collapsedItemIds = toObservable(this._collapsedItemIds).pipe(map(v => Array.isArray(v) ? v : [])), $actualItems = toObservable(this._actualItems), $cacheVersion = toObservable(this._cacheVersion);
|
|
2729
|
+
$isLazy.pipe(takeUntilDestroyed(), tap(v => {
|
|
2730
|
+
this._trackBox.isLazy = v;
|
|
2731
|
+
})).subscribe();
|
|
2636
2732
|
combineLatest([$items, $itemSize]).pipe(takeUntilDestroyed(), map(([items, itemSize]) => ({ items, itemSize })), tap(({ items, itemSize }) => {
|
|
2637
2733
|
this._trackBox.resetCollection(items, itemSize);
|
|
2638
2734
|
})).subscribe();
|
|
@@ -2710,9 +2806,11 @@ class NgVirtualListComponent {
|
|
|
2710
2806
|
this.resetBoundsSize(isVertical, totalSize);
|
|
2711
2807
|
this.createDisplayComponentsIfNeed(displayItems);
|
|
2712
2808
|
this.tracking();
|
|
2713
|
-
const scrollLength = (this._isVertical ? this._container()?.nativeElement.scrollHeight ?? 0 : this._container()?.nativeElement.scrollWidth) ?? 0, actualScrollLength = scrollLength === 0 ? 0 : scrollLength - (this._isVertical ? height : width), scrollPosition = actualScrollSize + this._trackBox.delta;
|
|
2714
|
-
|
|
2715
|
-
|
|
2809
|
+
const scrollLength = (this._isVertical ? this._container()?.nativeElement.scrollHeight ?? 0 : this._container()?.nativeElement.scrollWidth) ?? 0, actualScrollLength = scrollLength === 0 ? 0 : Math.round(scrollLength - (this._isVertical ? height : width)), scrollPosition = actualScrollSize + this._trackBox.delta;
|
|
2810
|
+
if (actualScrollLength > 0) {
|
|
2811
|
+
this._isScrollStart.set(scrollPosition === 0);
|
|
2812
|
+
this._isScrollFinished.set(scrollPosition === actualScrollLength);
|
|
2813
|
+
}
|
|
2716
2814
|
if (this._isSnappingMethodAdvanced) {
|
|
2717
2815
|
this.updateRegularRenderer();
|
|
2718
2816
|
}
|
|
@@ -2781,13 +2879,13 @@ class NgVirtualListComponent {
|
|
|
2781
2879
|
}
|
|
2782
2880
|
listenCacheChangesIfNeed(value) {
|
|
2783
2881
|
if (value) {
|
|
2784
|
-
if (!this._trackBox.hasEventListener(
|
|
2785
|
-
this._trackBox.addEventListener(
|
|
2882
|
+
if (!this._trackBox.hasEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler)) {
|
|
2883
|
+
this._trackBox.addEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler);
|
|
2786
2884
|
}
|
|
2787
2885
|
}
|
|
2788
2886
|
else {
|
|
2789
|
-
if (this._trackBox.hasEventListener(
|
|
2790
|
-
this._trackBox.removeEventListener(
|
|
2887
|
+
if (this._trackBox.hasEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler)) {
|
|
2888
|
+
this._trackBox.removeEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler);
|
|
2791
2889
|
}
|
|
2792
2890
|
}
|
|
2793
2891
|
}
|
|
@@ -2811,6 +2909,10 @@ class NgVirtualListComponent {
|
|
|
2811
2909
|
const dir = d || this.direction();
|
|
2812
2910
|
return isDirection(dir, Directions.VERTICAL);
|
|
2813
2911
|
}
|
|
2912
|
+
getIsLazy(m) {
|
|
2913
|
+
const mode = m || this.collectionMode();
|
|
2914
|
+
return isCollectionMode(mode, CollectionModes.LAZY);
|
|
2915
|
+
}
|
|
2814
2916
|
createDisplayComponentsIfNeed(displayItems) {
|
|
2815
2917
|
if (!displayItems || !this._listContainerRef) {
|
|
2816
2918
|
this._trackBox.setDisplayObjectIndexMapById({});
|
|
@@ -3037,7 +3139,7 @@ class NgVirtualListComponent {
|
|
|
3037
3139
|
}
|
|
3038
3140
|
}
|
|
3039
3141
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgVirtualListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3040
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: NgVirtualListComponent, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, collapsedIds: { classPropertyName: "collapsedIds", publicName: "collapsedIds", isSignal: true, isRequired: false, transformFunction: null }, selectByClick: { classPropertyName: "selectByClick", publicName: "selectByClick", isSignal: true, isRequired: false, transformFunction: null }, collapseByClick: { classPropertyName: "collapseByClick", publicName: "collapseByClick", isSignal: true, isRequired: false, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null }, enabledBufferOptimization: { classPropertyName: "enabledBufferOptimization", publicName: "enabledBufferOptimization", isSignal: true, isRequired: false, transformFunction: null }, itemRenderer: { classPropertyName: "itemRenderer", publicName: "itemRenderer", isSignal: true, isRequired: true, transformFunction: null }, itemConfigMap: { classPropertyName: "itemConfigMap", publicName: "itemConfigMap", isSignal: true, isRequired: false, transformFunction: null }, itemSize: { classPropertyName: "itemSize", publicName: "itemSize", isSignal: true, isRequired: false, transformFunction: null }, dynamicSize: { classPropertyName: "dynamicSize", publicName: "dynamicSize", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, maxBufferSize: { classPropertyName: "maxBufferSize", publicName: "maxBufferSize", isSignal: true, isRequired: false, transformFunction: null }, snappingMethod: { classPropertyName: "snappingMethod", publicName: "snappingMethod", isSignal: true, isRequired: false, transformFunction: null }, methodForSelecting: { classPropertyName: "methodForSelecting", publicName: "methodForSelecting", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onScroll: "onScroll", onScrollEnd: "onScrollEnd", onViewportChange: "onViewportChange", onItemClick: "onItemClick", onSelect: "onSelect", onCollapse: "onCollapse", onScrollReachStart: "onScrollReachStart", onScrollReachEnd: "onScrollReachEnd" }, host: { styleAttribute: "position: relative;" }, providers: [NgVirtualListService], viewQueries: [{ propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, isSignal: true }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "@if (snap()) {\r\n <div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n </div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" [attr.aria-activedescendant]=\"focusedElement()\" #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </div>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
|
|
3142
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: NgVirtualListComponent, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, collapsedIds: { classPropertyName: "collapsedIds", publicName: "collapsedIds", isSignal: true, isRequired: false, transformFunction: null }, selectByClick: { classPropertyName: "selectByClick", publicName: "selectByClick", isSignal: true, isRequired: false, transformFunction: null }, collapseByClick: { classPropertyName: "collapseByClick", publicName: "collapseByClick", isSignal: true, isRequired: false, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null }, enabledBufferOptimization: { classPropertyName: "enabledBufferOptimization", publicName: "enabledBufferOptimization", isSignal: true, isRequired: false, transformFunction: null }, itemRenderer: { classPropertyName: "itemRenderer", publicName: "itemRenderer", isSignal: true, isRequired: true, transformFunction: null }, itemConfigMap: { classPropertyName: "itemConfigMap", publicName: "itemConfigMap", isSignal: true, isRequired: false, transformFunction: null }, itemSize: { classPropertyName: "itemSize", publicName: "itemSize", isSignal: true, isRequired: false, transformFunction: null }, dynamicSize: { classPropertyName: "dynamicSize", publicName: "dynamicSize", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, collectionMode: { classPropertyName: "collectionMode", publicName: "collectionMode", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, maxBufferSize: { classPropertyName: "maxBufferSize", publicName: "maxBufferSize", isSignal: true, isRequired: false, transformFunction: null }, snappingMethod: { classPropertyName: "snappingMethod", publicName: "snappingMethod", isSignal: true, isRequired: false, transformFunction: null }, methodForSelecting: { classPropertyName: "methodForSelecting", publicName: "methodForSelecting", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onScroll: "onScroll", onScrollEnd: "onScrollEnd", onViewportChange: "onViewportChange", onItemClick: "onItemClick", onSelect: "onSelect", onCollapse: "onCollapse", onScrollReachStart: "onScrollReachStart", onScrollReachEnd: "onScrollReachEnd" }, host: { styleAttribute: "position: relative;" }, providers: [NgVirtualListService], viewQueries: [{ propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, isSignal: true }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "@if (snap()) {\r\n <div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n </div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" [attr.aria-activedescendant]=\"focusedElement()\" #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </div>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
|
|
3041
3143
|
}
|
|
3042
3144
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgVirtualListComponent, decorators: [{
|
|
3043
3145
|
type: Component,
|
|
@@ -3075,5 +3177,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
3075
3177
|
* Generated bundle index. Do not edit.
|
|
3076
3178
|
*/
|
|
3077
3179
|
|
|
3078
|
-
export { Directions, MethodsForSelecting, NgVirtualListComponent, NgVirtualListItemComponent, NgVirtualListModule, ScrollEvent, SnappingMethods, debounce, toggleClassName };
|
|
3180
|
+
export { CollectionModes, Directions, MethodsForSelecting, NgVirtualListComponent, NgVirtualListItemComponent, NgVirtualListModule, ScrollEvent, SnappingMethods, debounce, toggleClassName };
|
|
3079
3181
|
//# sourceMappingURL=ng-virtual-list.mjs.map
|