ng-virtual-list 20.12.0-beta-09 → 20.12.1

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 CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ⚡A powerful API for implementing lists of varying functionality and complexity.
6
6
 
7
- ✨Flexible, and actively maintained Angular library that excels with high-performance, feature-rich virtualized lists—including grouping, sticky headers, snapping, animations, collapsing group elements, single and multiple selection of elements and both scroll directions, lists with scrolling bindings for elements, galleries of varying complexity, including 3D transformations of elements and effects such as MotionBlur, DOF ​​(Depth Of Field) and Fog. Whether you're rendering millions of items or building interactive list components, it delivers scalability and customization. Angular (14–21) compatibility.
7
+ ✨Flexible, and actively maintained Angular library that excels with high-performance, feature-rich virtualized lists—including grouping, sticky headers, snapping, animations, collapsing group elements, single and multiple selection of elements and both scroll directions, lists with scrolling bindings for elements, galleries of varying complexity, including 3D transformations of elements and effects such as MotionBlur, DOF ​​(Depth Of Field) and Fog. Whether you're rendering millions of items or building interactive list components, it delivers scalability and customization. Angular (14–22) compatibility.
8
8
 
9
9
  🧬The main advantage of this solution is the elimination of the "empty spaces" effect during fast scrolling, which occurs in the classic implementation of virtualized lists. Visualization is as close as possible to native lists.
10
10
 
@@ -20,7 +20,7 @@
20
20
  ![npm downloads](https://img.shields.io/npm/dm/ng-virtual-list)
21
21
  ![npm total downloads](https://img.shields.io/npm/dt/ng-virtual-list)
22
22
 
23
- [Documentation](https://ng-virtual-list-x12.eugene-grebennikov.pro/)
23
+ [Documentation](https://ng-virtual-list.eugene-grebennikov.pro/)
24
24
 
25
25
  <br/>
26
26
 
@@ -612,11 +612,7 @@ Inputs
612
612
  | itemSize | number \| 'viewport' = 24 | If direction = 'vertical', then the height of a typical element. If direction = 'horizontal', then the width of a typical element. If the dynamicSize property is true, the items in the list can have different sizes, and you must specify the itemSize property to adjust the sizes of the items in the unallocated area. If the value is 'viewport', the sizes of elements are automatically resized to fit the viewport size. |
613
613
  | itemTransform | [ItemTransform](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/types/item-transform.ts) \| null = null | Custom transformation of element's position, rotation, scale, opacity and zIndex. The default value is `null`. |
614
614
  | itemRenderer | TemplateRef | Rendering element template. |
615
- | itemConfigMap | [IVirtualListItemConfigMap?](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/models/item-config-map.model.ts) | Sets `sticky` position, `fullSize`, `collapsable` and `selectable` for the list item element. If `sticky` position is greater than `0`, then `sticky` position is applied.
616
- If the `sticky` value is greater than `0`, then the `sticky` position mode is enabled for the element. `1` - position start, `2` - position end. Default value is `0`.
617
- `selectable` determines whether an element can be selected or not. Default value is `true`.
618
- `collapsable` determines whether an element with a `sticky` property greater than zero can collapse and collapse elements in front that do not have a `sticky` property.
619
- `fullSize` determines the size of an element when rendering lists with cell divisions. If sticky is 1 or 2, fullSize automatically becomes true. The default value is false. |
615
+ | itemConfigMap | [IVirtualListItemConfigMap?](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/models/item-config-map.model.ts) | Sets `sticky` position, `fullSize`, `collapsable` and `selectable` for the list item element. If `sticky` position is greater than `0`, then `sticky` position is applied. If the `sticky` value is greater than `0`, then the `sticky` position mode is enabled for the element. `1` - position start, `2` - position end. Default value is `0`. `selectable` determines whether an element can be selected or not. Default value is `true`. `collapsable` determines whether an element with a `sticky` property greater than zero can collapse and collapse elements in front that do not have a `sticky` property. `fullSize` determines the size of an element when rendering lists with cell divisions. If sticky is 1 or 2, fullSize automatically becomes true. The default value is false. |
620
616
  | langTextDir | [TextDirection? = 'ltr'](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/enums/text-direction.ts) | A string indicating the direction of text for the locale. Can be either "ltr" (left-to-right) or "rtl" (right-to-left). |
621
617
  | loading | boolean? = false | If `true`, the scrollBar goes into loading state. The default value is `false`. |
622
618
  | maxBufferSize | number? = 10 | Maximum number of elements outside the scope of visibility. Default value is 10. If maxBufferSize is set to be greater than bufferSize, then adaptive buffer mode is enabled. The greater the scroll size, the more elements are allocated for rendering. |
@@ -705,7 +701,7 @@ Properties
705
701
 
706
702
  <br/>
707
703
 
708
- ### [VirtualClickModule](https://github.com/DjonnyX/ng-virtual-list/blob/18.x/projects/ng-virtual-list/src/lib/directives/item-click/item-click.module.ts)
704
+ ### [VirtualClickModule](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/directives/item-click/item-click.module.ts)
709
705
 
710
706
  ### Virtual click directive
711
707
 
@@ -730,12 +726,6 @@ import { NgVirtualListModule, VirtualClickModule } from 'ng-virtual-list';
730
726
  </ng-template>
731
727
  ```
732
728
 
733
- ## 🤝 Contributing
734
-
735
- PRs and feature requests are welcome!
736
- Open an issue or start a discussion to shape the future of [ng-virtual-list](https://github.com/DjonnyX/ng-virtual-list/).
737
- Try it out, star ⭐ the repo, and let us know what you’re building.
738
-
739
729
  <br/>
740
730
 
741
731
  ## 📄 License
@@ -1399,7 +1399,7 @@ const DEFAULT_MAX_DISTANCE = 40;
1399
1399
  * VirtualClickDirective
1400
1400
  * Maximum performance for extremely large lists.
1401
1401
  * It is based on algorithms for virtualization of screen objects.
1402
- * @link https://github.com/DjonnyX/ng-virtual-list/blob/18.x/projects/ng-virtual-list/src/lib/directives/item-click/item-click.directive.ts
1402
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/directives/item-click/item-click.directive.ts
1403
1403
  * @author Evgenii Alexandrovich Grebennikov
1404
1404
  * @email djonnyx@gmail.com
1405
1405
  */
@@ -1626,14 +1626,14 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
1626
1626
  this._service.virtualClick(this._data);
1627
1627
  }
1628
1628
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NgVirtualListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1629
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: NgVirtualListItemComponent, isStandalone: false, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@let renderer = itemRenderer();\r\n@let class = classes();\r\n<div #item class=\"ngvl-item\" [ngClass]=\"class\" [attr.ngvl-index]=\"index()\" [attr.ngvl-visibility]=\"visibility\" tabindex=\"-1\">\r\n @if (_blendColor) {\r\n <div class=\"ngvl-item__blend-color\" [style.--blend-color]=\"_blendColor\"></div>\r\n }\r\n <div #container virtualClick [part]=\"fxPart()\" [maxClickDistance]=\"maxClickDistance()\" class=\"ngvl-item__container\"\r\n [ngClass]=\"class\" (onVirtualClick)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"templateContext()\" />\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;text-rendering:optimizeSpeed;image-rendering:auto}.ngvl-item{position:relative;margin:0;padding:0;overflow:hidden;outline:none;width:inherit;height:inherit;box-sizing:border-box}.ngvl-item__blend-color{position:absolute;left:0;top:0;width:100%;height:100%;background-color:var(--blend-color);z-index:-1}.ngvl-item__container{margin:0;padding:0;width:100%;height:100%;box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: VirtualClickDirective, selector: "[virtualClick]", inputs: ["maxClickDistance"], outputs: ["onVirtualClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1629
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: NgVirtualListItemComponent, isStandalone: false, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@let renderer = itemRenderer();\r\n@let class = classes();\r\n<div #item class=\"ngvl-item\" [ngClass]=\"class\" [part]=\"part()\" [attr.ngvl-index]=\"index()\" [attr.ngvl-visibility]=\"visibility\" tabindex=\"-1\">\r\n @if (_blendColor) {\r\n <div class=\"ngvl-item__blend-color\" [style.--blend-color]=\"_blendColor\"></div>\r\n }\r\n <div #container virtualClick [part]=\"fxPart()\" [maxClickDistance]=\"maxClickDistance()\" class=\"ngvl-item__container\"\r\n [ngClass]=\"class\" (onVirtualClick)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"templateContext()\" />\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;text-rendering:optimizeSpeed;image-rendering:auto}.ngvl-item{position:relative;margin:0;padding:0;overflow:hidden;outline:none;width:inherit;height:inherit;box-sizing:border-box}.ngvl-item__blend-color{position:absolute;left:0;top:0;width:100%;height:100%;background-color:var(--blend-color);z-index:-1}.ngvl-item__container{margin:0;padding:0;width:100%;height:100%;box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: VirtualClickDirective, selector: "[virtualClick]", inputs: ["maxClickDistance"], outputs: ["onVirtualClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1630
1630
  }
1631
1631
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NgVirtualListItemComponent, decorators: [{
1632
1632
  type: Component,
1633
1633
  args: [{ selector: 'ng-virtual-list-item', host: {
1634
1634
  'class': 'ngvl__item',
1635
1635
  'role': 'listitem',
1636
- }, standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let renderer = itemRenderer();\r\n@let class = classes();\r\n<div #item class=\"ngvl-item\" [ngClass]=\"class\" [attr.ngvl-index]=\"index()\" [attr.ngvl-visibility]=\"visibility\" tabindex=\"-1\">\r\n @if (_blendColor) {\r\n <div class=\"ngvl-item__blend-color\" [style.--blend-color]=\"_blendColor\"></div>\r\n }\r\n <div #container virtualClick [part]=\"fxPart()\" [maxClickDistance]=\"maxClickDistance()\" class=\"ngvl-item__container\"\r\n [ngClass]=\"class\" (onVirtualClick)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"templateContext()\" />\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;text-rendering:optimizeSpeed;image-rendering:auto}.ngvl-item{position:relative;margin:0;padding:0;overflow:hidden;outline:none;width:inherit;height:inherit;box-sizing:border-box}.ngvl-item__blend-color{position:absolute;left:0;top:0;width:100%;height:100%;background-color:var(--blend-color);z-index:-1}.ngvl-item__container{margin:0;padding:0;width:100%;height:100%;box-sizing:border-box}\n"] }]
1636
+ }, standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let renderer = itemRenderer();\r\n@let class = classes();\r\n<div #item class=\"ngvl-item\" [ngClass]=\"class\" [part]=\"part()\" [attr.ngvl-index]=\"index()\" [attr.ngvl-visibility]=\"visibility\" tabindex=\"-1\">\r\n @if (_blendColor) {\r\n <div class=\"ngvl-item__blend-color\" [style.--blend-color]=\"_blendColor\"></div>\r\n }\r\n <div #container virtualClick [part]=\"fxPart()\" [maxClickDistance]=\"maxClickDistance()\" class=\"ngvl-item__container\"\r\n [ngClass]=\"class\" (onVirtualClick)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"templateContext()\" />\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;text-rendering:optimizeSpeed;image-rendering:auto}.ngvl-item{position:relative;margin:0;padding:0;overflow:hidden;outline:none;width:inherit;height:inherit;box-sizing:border-box}.ngvl-item__blend-color{position:absolute;left:0;top:0;width:100%;height:100%;background-color:var(--blend-color);z-index:-1}.ngvl-item__container{margin:0;padding:0;width:100%;height:100%;box-sizing:border-box}\n"] }]
1637
1637
  }], ctorParameters: () => [] });
1638
1638
 
1639
1639
  /**
@@ -1762,7 +1762,7 @@ class ScrollEvent {
1762
1762
 
1763
1763
  /**
1764
1764
  * Event emitter
1765
- * @link https://github.com/DjonnyX/data-channel-router/blob/main/library/src/utils/event-emitter/event-emitter.ts
1765
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/main/library/src/utils/event-emitter/event-emitter.ts
1766
1766
  * @author Evgenii Alexandrovich Grebennikov
1767
1767
  * @email djonnyx@gmail.com
1768
1768
  */
@@ -2065,7 +2065,7 @@ class Tracker {
2065
2065
  }
2066
2066
  const untrackedItems = [...components], newTrackItems = [], untrackedComponentsByTypeMap = {}, isDown = direction === 0 || direction === 1, snapped = !!snappedComponents ? [...snappedComponents] : [];
2067
2067
  let isRegularSnapped = false;
2068
- const serviceIdProp = getServiceIdProp(trackBy);
2068
+ const serviceIdProp = getServiceIdProp(trackBy), snappedItems = new Array();
2069
2069
  for (let i = isDown ? 0 : items.length - 1, l = isDown ? items.length : 0; isDown ? i < l : i >= l; isDown ? i++ : i--) {
2070
2070
  const item = items[i], isDummy = item?.data?.[SERVICE_PROP_DUMMY] && (item?.data?.[SERVICE_PROP_DUMMY] === SERVICE_PROP_DUMMY_ENABLED);
2071
2071
  if (isDummy) {
@@ -2088,6 +2088,7 @@ class Tracker {
2088
2088
  isRegularSnapped = true;
2089
2089
  snappedComponent.instance.item = item;
2090
2090
  snappedComponent.instance.show();
2091
+ snappedItems.push(snappedComponent);
2091
2092
  }
2092
2093
  }
2093
2094
  }
@@ -2153,6 +2154,7 @@ class Tracker {
2153
2154
  if (!!snappedComponent) {
2154
2155
  snappedComponent.instance.item = item;
2155
2156
  snappedComponent.instance.show();
2157
+ snappedItems.push(snappedComponent);
2156
2158
  }
2157
2159
  }
2158
2160
  }
@@ -2183,13 +2185,14 @@ class Tracker {
2183
2185
  comp.instance.hide();
2184
2186
  }
2185
2187
  }
2186
- if (!isRegularSnapped) {
2187
- for (let i = 0, l = snapped.length; i < l; i++) {
2188
- const snappedComponent = snapped[i];
2189
- if (!!snappedComponent) {
2190
- snappedComponent.instance.item = null;
2191
- snappedComponent.instance.hide();
2192
- }
2188
+ for (let i = 0, l = snapped.length; i < l; i++) {
2189
+ const snappedComponent = snapped[i];
2190
+ if (snappedItems.indexOf(snappedComponent) > -1) {
2191
+ continue;
2192
+ }
2193
+ if (!!snappedComponent) {
2194
+ snappedComponent.instance.item = null;
2195
+ snappedComponent.instance.hide();
2193
2196
  }
2194
2197
  }
2195
2198
  }
@@ -2669,7 +2672,7 @@ class TrackBox extends CacheMap {
2669
2672
  * Calculates list metrics
2670
2673
  */
2671
2674
  recalculateMetrics(options) {
2672
- const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, minItemSize, maxItemSize, bufferSize: minBufferSize, scrollSize, stickyEnabled, itemConfigMap, enabledBufferOptimization, previousTotalSize, snapToItem, snapToItemAlign, deletedItemsMap, itemTransform } = options, roundedScrollSize = Math.round(scrollSize);
2675
+ const { alignment, fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, minItemSize, maxItemSize, bufferSize: minBufferSize, scrollSize, stickyEnabled, itemConfigMap, enabledBufferOptimization, previousTotalSize, snapToItem, snapToItemAlign, deletedItemsMap, itemTransform } = options, roundedScrollSize = Math.round(scrollSize);
2673
2676
  const trackBy = this._trackingPropertyName, bufferSize = Math.max(minBufferSize, this._bufferSize), { width, height } = bounds, sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME, size = isVertical ? height : width, totalLength = collection.length, typicalItemSize = itemSize, w = isVertical ? width : typicalItemSize, h = isVertical ? typicalItemSize : height, map = this._map, snapshot = this._snapshot, divides = this._divides, stickyPos = Math.floor(scrollSize) + this._scrollStartOffset, leftItemsOrRowsWeights = [], isFromId = fromItemId !== undefined && (typeof fromItemId === 'number' && fromItemId > -1)
2674
2677
  || (typeof fromItemId === 'string' && fromItemId > '-1');
2675
2678
  let leftItemsOffset = 0, rightItemsOffset = 0;
@@ -2809,15 +2812,17 @@ class TrackBox extends CacheMap {
2809
2812
  }
2810
2813
  if (id == fromItemId) {
2811
2814
  isFromItemIdFound = true;
2812
- const { num, offset } = this.getElementNumToEnd(i, collection, map, typicalItemSize, size, isVertical), leftViewportSize = size - offset;
2813
- if (leftViewportSize > 0) {
2814
- const { num: num1, offset: offset1 } = this.getElementNumToEnd(i + num, collection, map, typicalItemSize, size, isVertical, 0, true), deltaNum = (num1 - num), deltaOffset = (offset1 - offset);
2815
- totalItemsToDisplayEndWeight += offset;
2816
- itemsFromStartToScrollEnd -= deltaNum;
2817
- rightItemsWeight = rightItemLength = 0;
2818
- leftHiddenItemsWeight -= deltaOffset;
2819
- leftItemsOrRowsWeights.splice(leftItemsOrRowsWeights.length - deltaNum, deltaNum);
2820
- y -= deltaOffset;
2815
+ if (alignment !== Alignments.CENTER) {
2816
+ const { num, offset } = this.getElementNumToEnd(i, collection, map, typicalItemSize, size, isVertical), leftViewportSize = size - offset;
2817
+ if (leftViewportSize > 0) {
2818
+ const { num: num1, offset: offset1 } = this.getElementNumToEnd(i + num, collection, map, typicalItemSize, size, isVertical, 0, true), deltaNum = (num1 - num), deltaOffset = (offset1 - offset);
2819
+ totalItemsToDisplayEndWeight += offset;
2820
+ itemsFromStartToScrollEnd -= deltaNum;
2821
+ rightItemsWeight = rightItemLength = 0;
2822
+ leftHiddenItemsWeight -= deltaOffset;
2823
+ leftItemsOrRowsWeights.splice(leftItemsOrRowsWeights.length - deltaNum, deltaNum);
2824
+ y -= deltaOffset;
2825
+ }
2821
2826
  }
2822
2827
  itemById = collectionItem;
2823
2828
  itemByIdPos = y;
@@ -3004,7 +3009,7 @@ class TrackBox extends CacheMap {
3004
3009
  rightItemsWeight = Math.floor(rightItemLength * dividedTypicalItemSize / typicalItemSize) * typicalItemSize;
3005
3010
  leftHiddenItemsWeight = Math.floor(itemsFromStartToScrollEnd * dividedTypicalItemSize / typicalItemSize) * typicalItemSize;
3006
3011
  totalItemsToDisplayEndWeight = Math.floor(itemsFromStartToDisplayEnd * dividedTypicalItemSize / typicalItemSize) * typicalItemSize;
3007
- totalSize = (totalLength * dividedTypicalItemSize) + this._scrollStartOffset + this._scrollEndOffset;
3012
+ totalSize = (Math.ceil(totalLength / divides) * divides * dividedTypicalItemSize) + this._scrollStartOffset + this._scrollEndOffset;
3008
3013
  const k = totalSize !== 0 ? previousTotalSize / totalSize : 0;
3009
3014
  if (isFromId) {
3010
3015
  const index = collection.findIndex(item => item[trackBy] == fromItemId);
@@ -3380,7 +3385,7 @@ class TrackBox extends CacheMap {
3380
3385
  }
3381
3386
  if (!isDummy) {
3382
3387
  if ((isSnappingMethodAdvanced || id !== stickyItem?.id) && id !== endStickyItem?.id) {
3383
- const isOdd = (items.length - layoutIndexOffset + i) % 2 != 0, sticky = itemConfigMap[id]?.sticky ?? 0, fullSize = itemConfigMap[id]?.fullSize ?? false, selectable = itemConfigMap[id]?.selectable ?? true, collapsable = itemConfigMap[id]?.collapsable ?? false, snapped = stickyEnabled && (sticky === 1 && (pos <= scrollSize + this._scrollStartOffset) || sticky === 2 && (pos >= scrollSize + boundsSize - size)), absoluteStartPosition = pos - scrollSize, ratio = size !== 0 ? boundsSize / size : 0, absoluteStartPositionPercent = -(boundsSize !== 0 ? absoluteStartPosition / boundsSize : 0) * ratio, absoluteEndPosition = boundsSize - (absoluteStartPositionPercent + size), absoluteEndPositionPercent = (absoluteStartPositionPercent + (boundsSize !== 0 ? (absoluteEndPosition + size) / boundsSize : 0) * ratio), x = isVertical ? divSize * ((sticky || fullSize) ? 0 : ci) : pos, y = isVertical ? pos : divSize * ((sticky || fullSize) ? 0 : ci), measures = {
3388
+ const isOdd = (items.length - layoutIndexOffset + i) % 2 != 0, sticky = itemConfigMap[id]?.sticky ?? 0, fullSize = itemConfigMap[id]?.fullSize ?? false, selectable = itemConfigMap[id]?.selectable ?? true, collapsable = itemConfigMap[id]?.collapsable ?? false, snapped = stickyEnabled && ((sticky === 1 && (pos <= scrollSize + this._scrollStartOffset)) || (sticky === 2 && (pos >= scrollSize + boundsSize - size))), absoluteStartPosition = pos - scrollSize, ratio = size !== 0 ? boundsSize / size : 0, absoluteStartPositionPercent = -(boundsSize !== 0 ? absoluteStartPosition / boundsSize : 0) * ratio, absoluteEndPosition = boundsSize - (absoluteStartPositionPercent + size), absoluteEndPositionPercent = (absoluteStartPositionPercent + (boundsSize !== 0 ? (absoluteEndPosition + size) / boundsSize : 0) * ratio), x = isVertical ? divSize * ((sticky || fullSize) ? 0 : ci) : pos, y = isVertical ? pos : divSize * ((sticky || fullSize) ? 0 : ci), measures = {
3384
3389
  x,
3385
3390
  y,
3386
3391
  transformedX: x,
@@ -3408,7 +3413,7 @@ class TrackBox extends CacheMap {
3408
3413
  maxWidth: maxItemSize,
3409
3414
  maxHeight: maxItemSize,
3410
3415
  scrollDirection,
3411
- delta: sticky === 1 ? actualSnippedPosition : sticky === 2 ? actualEndSnippedPosition - deltaOffet - size : 0,
3416
+ delta: sticky === 1 ? actualSnippedPosition : (sticky === 2 ? (actualEndSnippedPosition - deltaOffet - size) : 0),
3412
3417
  }, config = {
3413
3418
  isFirst: i === layoutIndexOffset,
3414
3419
  isLast: i === li,
@@ -3418,7 +3423,7 @@ class TrackBox extends CacheMap {
3418
3423
  isVertical,
3419
3424
  collapsable,
3420
3425
  selectable,
3421
- sticky: sticky,
3426
+ sticky,
3422
3427
  snap: stickyEnabled,
3423
3428
  snapped: false,
3424
3429
  snappedOut: false,
@@ -3471,9 +3476,9 @@ class TrackBox extends CacheMap {
3471
3476
  i++;
3472
3477
  }
3473
3478
  const axis = isVertical ? Y_PROP_NAME : X_PROP_NAME;
3474
- if (!!nextSticky && !!stickyItem && nextSticky.measures[axis] <= actualSnippedPosition + stickyItemSize) {
3475
- if (nextSticky.measures[axis] > scrollSize - stickyItemSize) {
3476
- stickyItem.measures[axis] = nextSticky.measures[axis] - stickyItemSize;
3479
+ if (!!nextSticky && !!stickyItem && nextSticky.measures[axis] <= actualSnippedPosition + stickyItem.measures[sizeProperty]) {
3480
+ if (nextSticky.measures[axis] > actualSnippedPosition) {
3481
+ stickyItem.measures[axis] = nextSticky.measures[axis] - stickyItem.measures[sizeProperty];
3477
3482
  stickyItem.config.snapped = nextSticky.config.snapped = false;
3478
3483
  stickyItem.config.snappedOut = true;
3479
3484
  stickyItem.config.sticky = 1;
@@ -3482,7 +3487,8 @@ class TrackBox extends CacheMap {
3482
3487
  else {
3483
3488
  nextSticky.config.snapped = true;
3484
3489
  nextSticky.measures.delta = (isVertical ? nextSticky.measures.y : nextSticky.measures.x) - scrollSize;
3485
- stickyItem.measures[axis] = stickyItem.measures[axis] + stickyItem.measures[sizeProperty];
3490
+ stickyItem.measures[axis] = nextSticky.measures[axis] - stickyItem.measures[sizeProperty];
3491
+ stickyItem.measures.delta = (isVertical ? stickyItem.measures.y : stickyItem.measures.x) - scrollSize;
3486
3492
  }
3487
3493
  }
3488
3494
  if (!!nextEndSticky && !!endStickyItem &&
@@ -3499,6 +3505,7 @@ class TrackBox extends CacheMap {
3499
3505
  nextEndSticky.measures[axis] = actualEndSnippedPosition - nextEndSticky.measures[sizeProperty];
3500
3506
  nextEndSticky.measures.delta = (isVertical ? nextEndSticky.measures.y : nextEndSticky.measures.x) - scrollSize;
3501
3507
  endStickyItem.measures[axis] = nextEndSticky.measures[axis] + nextEndSticky.measures[sizeProperty];
3508
+ endStickyItem.measures.delta = (isVertical ? endStickyItem.measures.y : endStickyItem.measures.x) - scrollSize;
3502
3509
  }
3503
3510
  }
3504
3511
  if (itemTransform !== null) {
@@ -3556,10 +3563,10 @@ class TrackBox extends CacheMap {
3556
3563
  if (!!components) {
3557
3564
  for (const comp of components) {
3558
3565
  const id = comp.instance.itemId ?? null, isVertical = comp.instance.item?.config?.isVertical, x = comp.instance.item?.measures?.x ?? 0, y = comp.instance.item?.measures?.y ?? 0, isFirst = comp.instance.item?.config?.isFirst ?? false, isLast = comp.instance.item?.config?.isLast ?? false, { width, height } = comp.instance.getBounds(), pos = position;
3559
- if (isVertical && comp.instance.zIndex !== Z_INDEX_NONE && (pos >= y && pos < y + height)) {
3566
+ if (isVertical && (pos >= y && pos < y + height)) {
3560
3567
  return { id, x, y, width, height, isFirst, isLast };
3561
3568
  }
3562
- else if (!isVertical && comp.instance.zIndex !== Z_INDEX_NONE && (pos >= x && pos < x + width)) {
3569
+ else if (!isVertical && (pos >= x && pos < x + width)) {
3563
3570
  return { id, x, y, width, height, isFirst, isLast };
3564
3571
  }
3565
3572
  if (isFirst) {
@@ -3954,7 +3961,7 @@ const easeLinear = (t) => {
3954
3961
 
3955
3962
  /**
3956
3963
  * Animator
3957
- * @link https://github.com/DjonnyX/data-channel-router/blob/main/library/src/utils/animator/animator.ts
3964
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/main/library/src/utils/animator/animator.ts
3958
3965
  * @author Evgenii Alexandrovich Grebennikov
3959
3966
  * @email djonnyx@gmail.com
3960
3967
  */
@@ -4826,7 +4833,7 @@ class NgScrollView extends BaseScrollView {
4826
4833
  }
4827
4834
  animate(startValue, endValue, duration = ANIMATION_DURATION, easingFunction = easeOutQuad, userAction = false, alignmentAtComplete = true, skipOverridedCoordinates = false) {
4828
4835
  const isVertical = this.isVertical();
4829
- let iteration = 0, position = startValue;
4836
+ let position = startValue;
4830
4837
  this._isAlignmentAnimation = !alignmentAtComplete;
4831
4838
  this._animator.animate({
4832
4839
  withDelta: this._service.dynamic && !this.isInfinity(),
@@ -4843,17 +4850,16 @@ class NgScrollView extends BaseScrollView {
4843
4850
  this.animate(currentCoordinate, currentCoordinate + delta, duration - elapsed, easingFunction, userAction, alignmentAtComplete);
4844
4851
  return;
4845
4852
  }
4846
- const v0 = calculateVelocity(position, value, timestamp) ?? this.averageVelocity;
4853
+ const v0 = calculateVelocity(position, value - this._delta, timestamp) ?? this.averageVelocity;
4847
4854
  position = value;
4848
4855
  if (alignmentAtComplete && !this._isAlignmentAnimation && !skipOverridedCoordinates) {
4849
- if (iteration < MAX_ITERATIONS_FOR_AVERAGE_CALCULATIONS || !this.snapIfNecessary(v0)) {
4856
+ if (!this.snapIfNecessary(v0)) {
4850
4857
  this.move(isVertical, value, false, userAction);
4851
4858
  }
4852
4859
  }
4853
4860
  else {
4854
4861
  this.move(isVertical, value, false, userAction);
4855
4862
  }
4856
- iteration++;
4857
4863
  this._service.update(true);
4858
4864
  }, onComplete: ({ value, timestamp }) => {
4859
4865
  this._isAlignmentAnimation = false;
@@ -4905,10 +4911,9 @@ class NgScrollView extends BaseScrollView {
4905
4911
  return size;
4906
4912
  }
4907
4913
  alignPosition(animated = true, force = false) {
4908
- if (!this.snapToItem() || this._isAlignmentAnimation) {
4914
+ if (!this.snapToItem() || (this._isAlignmentAnimation && !force)) {
4909
4915
  return false;
4910
4916
  }
4911
- this.stopScrolling(true);
4912
4917
  const scrollDirection = this._scrollDirection.get() || (force ? 1 : 0);
4913
4918
  if (scrollDirection === 0) {
4914
4919
  return false;
@@ -5323,7 +5328,7 @@ const RIGHT = 'right', DIR = 'dir';
5323
5328
  * LocaleSensitiveDirective
5324
5329
  * Maximum performance for extremely large lists.
5325
5330
  * It is based on algorithms for virtualization of screen objects.
5326
- * @link https://github.com/DjonnyX/ng-virtual-list/blob/18.x/projects/ng-virtual-list/src/lib/directives/locale-sensitive/locale-sensitive.directive.ts
5331
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/directives/locale-sensitive/locale-sensitive.directive.ts
5327
5332
  * @author Evgenii Alexandrovich Grebennikov
5328
5333
  * @email djonnyx@gmail.com
5329
5334
  */
@@ -5919,10 +5924,10 @@ class PrerenderTrackBox extends EventEmitter {
5919
5924
  }
5920
5925
 
5921
5926
  /**
5922
- * Virtual list component.
5927
+ * NgPrerenderVirtualListItemComponent
5923
5928
  * Maximum performance for extremely large lists.
5924
5929
  * It is based on algorithms for virtualization of screen objects.
5925
- * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/components/ng-prerender-container/components/ng-prerender-list-item.component.ts
5930
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/components/ng-prerender-container/components/ng-prerender-list-item/ng-prerender-list-item.component.ts
5926
5931
  * @author Evgenii Alexandrovich Grebennikov
5927
5932
  * @email djonnyx@gmail.com
5928
5933
  */
@@ -5997,21 +6002,21 @@ class NgPrerenderVirtualListItemComponent extends NgVirtualListItemComponent {
5997
6002
  }
5998
6003
  }
5999
6004
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NgPrerenderVirtualListItemComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
6000
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: NgPrerenderVirtualListItemComponent, isStandalone: false, selector: "ng-prerender-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@let renderer = itemRenderer();\r\n@let class = classes();\r\n<div #item class=\"ngvl-item\" [ngClass]=\"class\" [attr.ngvl-index]=\"index()\" [attr.ngvl-visibility]=\"visibility\" tabindex=\"-1\">\r\n @if (_blendColor) {\r\n <div class=\"ngvl-item__blend-color\" [style.--blend-color]=\"_blendColor\"></div>\r\n }\r\n <div #container virtualClick [part]=\"fxPart()\" [maxClickDistance]=\"maxClickDistance()\" class=\"ngvl-item__container\"\r\n [ngClass]=\"class\" (onVirtualClick)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"templateContext()\" />\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;text-rendering:optimizeSpeed;image-rendering:auto}.ngvl-item{position:relative;margin:0;padding:0;overflow:hidden;outline:none;width:inherit;height:inherit;box-sizing:border-box}.ngvl-item__blend-color{position:absolute;left:0;top:0;width:100%;height:100%;background-color:var(--blend-color);z-index:-1}.ngvl-item__container{margin:0;padding:0;width:100%;height:100%;box-sizing:border-box}\n", ":host{display:block;position:absolute!important;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;pointer-events:none;-webkit-user-select:none;user-select:none;text-rendering:optimizeSpeed;image-rendering:pixelated}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: VirtualClickDirective, selector: "[virtualClick]", inputs: ["maxClickDistance"], outputs: ["onVirtualClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6005
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: NgPrerenderVirtualListItemComponent, isStandalone: false, selector: "ng-prerender-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@let renderer = itemRenderer();\r\n@let class = classes();\r\n<div #item class=\"ngvl-item\" [ngClass]=\"class\" [part]=\"part()\" [attr.ngvl-index]=\"index()\" [attr.ngvl-visibility]=\"visibility\" tabindex=\"-1\">\r\n @if (_blendColor) {\r\n <div class=\"ngvl-item__blend-color\" [style.--blend-color]=\"_blendColor\"></div>\r\n }\r\n <div #container virtualClick [part]=\"fxPart()\" [maxClickDistance]=\"maxClickDistance()\" class=\"ngvl-item__container\"\r\n [ngClass]=\"class\" (onVirtualClick)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"templateContext()\" />\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;text-rendering:optimizeSpeed;image-rendering:auto}.ngvl-item{position:relative;margin:0;padding:0;overflow:hidden;outline:none;width:inherit;height:inherit;box-sizing:border-box}.ngvl-item__blend-color{position:absolute;left:0;top:0;width:100%;height:100%;background-color:var(--blend-color);z-index:-1}.ngvl-item__container{margin:0;padding:0;width:100%;height:100%;box-sizing:border-box}\n", ":host{display:block;position:absolute!important;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;pointer-events:none;-webkit-user-select:none;user-select:none;text-rendering:optimizeSpeed;image-rendering:pixelated}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: VirtualClickDirective, selector: "[virtualClick]", inputs: ["maxClickDistance"], outputs: ["onVirtualClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6001
6006
  }
6002
6007
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NgPrerenderVirtualListItemComponent, decorators: [{
6003
6008
  type: Component,
6004
6009
  args: [{ selector: 'ng-prerender-virtual-list-item', host: {
6005
6010
  'class': 'ngvl__item',
6006
6011
  'role': 'listitem',
6007
- }, standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let renderer = itemRenderer();\r\n@let class = classes();\r\n<div #item class=\"ngvl-item\" [ngClass]=\"class\" [attr.ngvl-index]=\"index()\" [attr.ngvl-visibility]=\"visibility\" tabindex=\"-1\">\r\n @if (_blendColor) {\r\n <div class=\"ngvl-item__blend-color\" [style.--blend-color]=\"_blendColor\"></div>\r\n }\r\n <div #container virtualClick [part]=\"fxPart()\" [maxClickDistance]=\"maxClickDistance()\" class=\"ngvl-item__container\"\r\n [ngClass]=\"class\" (onVirtualClick)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"templateContext()\" />\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;text-rendering:optimizeSpeed;image-rendering:auto}.ngvl-item{position:relative;margin:0;padding:0;overflow:hidden;outline:none;width:inherit;height:inherit;box-sizing:border-box}.ngvl-item__blend-color{position:absolute;left:0;top:0;width:100%;height:100%;background-color:var(--blend-color);z-index:-1}.ngvl-item__container{margin:0;padding:0;width:100%;height:100%;box-sizing:border-box}\n", ":host{display:block;position:absolute!important;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;pointer-events:none;-webkit-user-select:none;user-select:none;text-rendering:optimizeSpeed;image-rendering:pixelated}\n"] }]
6012
+ }, standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let renderer = itemRenderer();\r\n@let class = classes();\r\n<div #item class=\"ngvl-item\" [ngClass]=\"class\" [part]=\"part()\" [attr.ngvl-index]=\"index()\" [attr.ngvl-visibility]=\"visibility\" tabindex=\"-1\">\r\n @if (_blendColor) {\r\n <div class=\"ngvl-item__blend-color\" [style.--blend-color]=\"_blendColor\"></div>\r\n }\r\n <div #container virtualClick [part]=\"fxPart()\" [maxClickDistance]=\"maxClickDistance()\" class=\"ngvl-item__container\"\r\n [ngClass]=\"class\" (onVirtualClick)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"templateContext()\" />\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;text-rendering:optimizeSpeed;image-rendering:auto}.ngvl-item{position:relative;margin:0;padding:0;overflow:hidden;outline:none;width:inherit;height:inherit;box-sizing:border-box}.ngvl-item__blend-color{position:absolute;left:0;top:0;width:100%;height:100%;background-color:var(--blend-color);z-index:-1}.ngvl-item__container{margin:0;padding:0;width:100%;height:100%;box-sizing:border-box}\n", ":host{display:block;position:absolute!important;left:0;top:0;box-sizing:border-box;overflow:hidden;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-moz-user-drag:none;pointer-events:none;-webkit-user-select:none;user-select:none;text-rendering:optimizeSpeed;image-rendering:pixelated}\n"] }]
6008
6013
  }] });
6009
6014
 
6010
6015
  /**
6011
- * PrerenderScrollerComponent.
6016
+ * NgPrerenderScrollerComponent
6012
6017
  * Maximum performance for extremely large lists.
6013
6018
  * It is based on algorithms for virtualization of screen objects.
6014
- * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/components/prerender-container/prerender-scroller/prerender-scroller.component.ts
6019
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/components/ng-prerender-container/components/ng-prerender-scroller/ng-prerender-scroller.component.ts
6015
6020
  * @author Evgenii Alexandrovich Grebennikov
6016
6021
  * @email djonnyx@gmail.com
6017
6022
  */
@@ -6115,10 +6120,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
6115
6120
  }], scrollbarEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarEnabled", required: false }] }], classes: [{ type: i0.Input, args: [{ isSignal: true, alias: "classes", required: false }] }] } });
6116
6121
 
6117
6122
  /**
6118
- * PrerenderList.
6123
+ * NgPrerenderList
6119
6124
  * Maximum performance for extremely large lists.
6120
6125
  * It is based on algorithms for virtualization of screen objects.
6121
- * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/prerender-container/components/prerender-list/prerender-list.component.ts
6126
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/components/ng-prerender-container/components/ng-prerender-list/ng-prerender-list.component.ts
6122
6127
  * @author Evgenii Alexandrovich Grebennikov
6123
6128
  * @email djonnyx@gmail.com
6124
6129
  */
@@ -6261,10 +6266,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
6261
6266
  }], enabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "enabled", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], isVertical: [{ type: i0.Input, args: [{ isSignal: true, alias: "isVertical", required: false }] }], scrollbarEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarEnabled", required: false }] }], startOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "startOffset", required: false }] }], endOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "endOffset", required: false }] }], bounds: [{ type: i0.Input, args: [{ isSignal: true, alias: "bounds", required: true }] }], dynamic: [{ type: i0.Input, args: [{ isSignal: true, alias: "dynamic", required: false }] }], itemSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemSize", required: false }] }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }], divides: [{ type: i0.Input, args: [{ isSignal: true, alias: "divides", required: false }] }], itemRenderer: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemRenderer", required: false }] }], itemComponentClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemComponentClass", required: false }] }] } });
6262
6267
 
6263
6268
  /**
6264
- * Prerender container.
6269
+ * NgPrerenderContainer
6265
6270
  * Maximum performance for extremely large lists.
6266
6271
  * It is based on algorithms for virtualization of screen objects.
6267
- * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/ng-prerender-container/ng-prerender-container.component.ts
6272
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/components/ng-prerender-container/ng-prerender-container.component.ts
6268
6273
  * @author Evgenii Alexandrovich Grebennikov
6269
6274
  * @email djonnyx@gmail.com
6270
6275
  */
@@ -7519,7 +7524,10 @@ class NgVirtualListComponent {
7519
7524
  this._$initialized.next(true);
7520
7525
  })).subscribe();
7521
7526
  this._service.initialize(this._id, this._trackBox);
7522
- this._service.animationParams = this.animationParams();
7527
+ const $animationParams = toObservable(this.animationParams);
7528
+ $animationParams.pipe(takeUntilDestroyed(), tap(v => {
7529
+ this._service.animationParams = v;
7530
+ })).subscribe();
7523
7531
  this._isInfinity = computed(() => {
7524
7532
  const mode = this.spreadingMode();
7525
7533
  return isSpreadingMode(mode, SpreadingModes.INFINITY);
@@ -8089,7 +8097,7 @@ class NgVirtualListComponent {
8089
8097
  this._isLoading = false;
8090
8098
  })).subscribe();
8091
8099
  const update = (params) => {
8092
- const { alignment, precalculatedScrollStartOffset, precalculatedScrollEndOffset, trackBy, isInfinity, snapScrollToStart, snapScrollToEnd, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize, minItemSize, maxItemSize, divides, bufferSize, maxBufferSize, stickyEnabled, isVertical, dynamicSize, enabledBufferOptimization, snapToItem, snapToItemAlign, cacheVersion, userAction, collapsedIds, itemTransform, } = params;
8100
+ const { alignment, snapScrollToStart, snapScrollToEnd, bounds, items, itemConfigMap, scrollSize, itemSize, minItemSize, maxItemSize, bufferSize, maxBufferSize, stickyEnabled, isVertical, dynamicSize, enabledBufferOptimization, snapToItem, snapToItemAlign, userAction, collapsedIds, itemTransform, } = params;
8093
8101
  const scroller = this._scrollerComponent();
8094
8102
  let totalSize = 0;
8095
8103
  if (!!scroller) {
@@ -8099,7 +8107,7 @@ class NgVirtualListComponent {
8099
8107
  let actualScrollSize = !this._readyForShow && snapScrollToEnd ? (isVertical ? scroller.scrollHeight : scroller.scrollWidth) :
8100
8108
  (isVertical ? scroller.scrollTop : scroller.scrollLeft), leftLayoutOffset = 0, displayItems;
8101
8109
  const { width, height } = bounds, viewportSize = (isVertical ? height : width), opts = {
8102
- bounds: { width, height }, dynamicSize, isVertical, itemSize, minItemSize, maxItemSize, bufferSize, maxBufferSize,
8110
+ alignment, bounds: { width, height }, dynamicSize, isVertical, itemSize, minItemSize, maxItemSize, bufferSize, maxBufferSize,
8103
8111
  scrollSize: actualScrollSize, stickyEnabled, enabledBufferOptimization, snapToItem, snapToItemAlign, itemTransform,
8104
8112
  };
8105
8113
  if (snapScrollToEnd && !this._readyForShow) {
@@ -8107,12 +8115,24 @@ class NgVirtualListComponent {
8107
8115
  displayItems = calculatedDisplayItems;
8108
8116
  totalSize = calculatedTotalSize1;
8109
8117
  leftLayoutOffset = leftLayoutOffset1;
8118
+ if (!!itemTransform && dynamicSize && this._trackBox.delta !== 0) {
8119
+ const { displayItems: calculatedDisplayItems, totalSize: calculatedTotalSize1, leftLayoutOffset: leftLayoutOffset1 } = this._trackBox.updateCollection(items, itemConfigMap, { ...opts, scrollSize: actualScrollSize + this._trackBox.delta });
8120
+ displayItems = calculatedDisplayItems;
8121
+ totalSize = calculatedTotalSize1;
8122
+ leftLayoutOffset = leftLayoutOffset1;
8123
+ }
8110
8124
  }
8111
8125
  else {
8112
8126
  const { displayItems: calculatedDisplayItems, totalSize: calculatedTotalSize, leftLayoutOffset: leftLayoutOffset1 } = this._trackBox.updateCollection(items, itemConfigMap, opts);
8113
8127
  displayItems = calculatedDisplayItems;
8114
8128
  totalSize = calculatedTotalSize;
8115
8129
  leftLayoutOffset = leftLayoutOffset1;
8130
+ if (!!itemTransform && dynamicSize && this._trackBox.delta !== 0) {
8131
+ const { displayItems: calculatedDisplayItems, totalSize: calculatedTotalSize, leftLayoutOffset: leftLayoutOffset1 } = this._trackBox.updateCollection(items, itemConfigMap, { ...opts, scrollSize: actualScrollSize + this._trackBox.delta });
8132
+ displayItems = calculatedDisplayItems;
8133
+ totalSize = calculatedTotalSize;
8134
+ leftLayoutOffset = leftLayoutOffset1;
8135
+ }
8116
8136
  }
8117
8137
  scroller.totalSize = totalSize;
8118
8138
  scroller.startLayoutOffset = leftLayoutOffset;
@@ -8129,23 +8149,7 @@ class NgVirtualListComponent {
8129
8149
  if (this._isSnappingMethodAdvanced) {
8130
8150
  this.updateRegularRenderer();
8131
8151
  }
8132
- switch (alignment) {
8133
- case Alignments.NONE: {
8134
- this._actualScrollStartOffset.set(precalculatedScrollStartOffset);
8135
- this._actualScrollEndOffset.set(precalculatedScrollEndOffset);
8136
- break;
8137
- }
8138
- case Alignments.CENTER: {
8139
- const firstItemId = items.length > 0 ? (items[0]?.[trackBy] ?? null) : null, endItemId = items.length > 0 ? (items?.[items.length - 1]?.[trackBy] ?? null) : null, alignmentStartOffset = viewportSize * .5 - (firstItemId !== null ? (isVertical ? (this._service.getItemBounds(firstItemId)?.height ?? 0) :
8140
- (this._service.getItemBounds(firstItemId)?.width ?? 0)) : 0) * (isInfinity ? 0 : .5), alignmentEndOffset = viewportSize * .5 - (endItemId !== null ? (isVertical ? (this._service.getItemBounds(endItemId)?.height ?? 0) :
8141
- (this._service.getItemBounds(endItemId)?.width ?? 0)) : 0) * (isInfinity ? 0 : .5);
8142
- this._alignmentScrollStartOffset.set(alignmentStartOffset);
8143
- this._alignmentScrollEndOffset.set(alignmentEndOffset);
8144
- this._actualScrollStartOffset.set(precalculatedScrollStartOffset + alignmentStartOffset);
8145
- this._actualScrollEndOffset.set(precalculatedScrollEndOffset + alignmentEndOffset);
8146
- break;
8147
- }
8148
- }
8152
+ this.updateOffsetsByAllignment();
8149
8153
  scroller.delta = delta;
8150
8154
  if ((snapScrollToStart && this._trackBox.isSnappedToStart && scroller.scrollable) ||
8151
8155
  (snapScrollToStart && currentScrollSize <= MIN_PIXELS_FOR_PREVENT_SNAPPING)) {
@@ -8324,6 +8328,7 @@ class NgVirtualListComponent {
8324
8328
  const dynamicSize = this.dynamicSize(), itemSize = this._actualItemSize(), minItemSize = this._actualMinItemSize(), maxItemSize = this._actualMaxItemSize(), snapScrollToEnd = this.snapScrollToEnd();
8325
8329
  if (dynamicSize) {
8326
8330
  const { width, height } = this._bounds() || { width: DEFAULT_LIST_SIZE, height: DEFAULT_LIST_SIZE }, itemConfigMap = this.itemConfigMap(), isVertical = this._isVertical, currentScrollSize = isVertical ? scrollerComponent.scrollTop : scrollerComponent.scrollLeft, opts = {
8331
+ alignment: this.actualAlignment(),
8327
8332
  bounds: { width, height }, collection: items, dynamicSize, isVertical: this._isVertical, itemSize, minItemSize, maxItemSize,
8328
8333
  bufferSize: this.bufferSize(), maxBufferSize: this.maxBufferSize(), itemTransform: this.itemTransform(),
8329
8334
  scrollSize: (isVertical ? scrollerComponent.scrollTop : scrollerComponent.scrollLeft),
@@ -8349,21 +8354,8 @@ class NgVirtualListComponent {
8349
8354
  this.createDisplayComponentsIfNeed(displayItems);
8350
8355
  this.tracking();
8351
8356
  this.snappingHandler();
8357
+ this.updateOffsetsByAllignment();
8352
8358
  scrollSize = this._trackBox.getItemPosition(id, itemConfigMap, { ...opts, scrollSize: actualScrollSize, fromItemId: id });
8353
- if (this._isInfinity()) {
8354
- if (this.snapToItem()) {
8355
- const itemBounds = this._trackBox.getItemBounds(id);
8356
- if (!!itemBounds) {
8357
- const itemSize = isVertical ? itemBounds.height : itemBounds.width;
8358
- switch (this.snapToItemAlign()) {
8359
- case SnapToItemAligns.CENTER: {
8360
- scrollSize += itemSize * .5;
8361
- break;
8362
- }
8363
- }
8364
- }
8365
- }
8366
- }
8367
8359
  if (scrollSize === -1) {
8368
8360
  return of([finished, { id, blending, iteration: nextIteration, cb }]).pipe(delay(0));
8369
8361
  }
@@ -8388,11 +8380,11 @@ class NgVirtualListComponent {
8388
8380
  else {
8389
8381
  const index = items.findIndex(item => item[trackBy] === id);
8390
8382
  if (index > -1) {
8391
- const isVertical = this._isVertical, itemSize = this._actualItemSize();
8383
+ const isVertical = this._isVertical, itemSize = this._actualItemSize(), isInfinity = this._isInfinity(), snapToItem = this.snapToItem(), snapToItemAlign = this.snapToItemAlign();
8392
8384
  let scrollSize = index * itemSize;
8393
- if (this._isInfinity()) {
8394
- if (this.snapToItem()) {
8395
- switch (this.snapToItemAlign()) {
8385
+ if (isInfinity) {
8386
+ if (snapToItem) {
8387
+ switch (snapToItemAlign) {
8396
8388
  case SnapToItemAligns.CENTER: {
8397
8389
  scrollSize += itemSize * .5;
8398
8390
  break;
@@ -8401,11 +8393,12 @@ class NgVirtualListComponent {
8401
8393
  }
8402
8394
  }
8403
8395
  const { width, height } = this._bounds() || { width: DEFAULT_LIST_SIZE, height: DEFAULT_LIST_SIZE }, itemConfigMap = this.itemConfigMap(), items = this._actualItems(), opts = {
8396
+ alignment: this._actualAlignment(),
8404
8397
  bounds: { width, height }, collection: items, dynamicSize, isVertical: this._isVertical, itemSize, minItemSize, maxItemSize,
8405
8398
  bufferSize: this.bufferSize(), maxBufferSize: this.maxBufferSize(), itemTransform: this.itemTransform(),
8406
8399
  scrollSize: (isVertical ? scrollerComponent.scrollTop : scrollerComponent.scrollLeft),
8407
- snapToItem: this.snapToItem(), snapToItemAlign: this.snapToItemAlign(),
8408
- stickyEnabled: this.stickyEnabled(), fromItemId: id, enabledBufferOptimization: this.enabledBufferOptimization(),
8400
+ snapToItem, snapToItemAlign, stickyEnabled: this.stickyEnabled(), fromItemId: id,
8401
+ enabledBufferOptimization: this.enabledBufferOptimization(),
8409
8402
  };
8410
8403
  this._trackBox.clearDelta();
8411
8404
  const viewportSize = (isVertical ? height : width), { displayItems, totalSize, leftLayoutOffset } = this._trackBox.updateCollection(items, itemConfigMap, {
@@ -8420,6 +8413,7 @@ class NgVirtualListComponent {
8420
8413
  this.createDisplayComponentsIfNeed(displayItems);
8421
8414
  this.tracking();
8422
8415
  this.snappingHandler();
8416
+ this.updateOffsetsByAllignment();
8423
8417
  this._$preventScrollSnapping.next(true);
8424
8418
  const params = {
8425
8419
  [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollSize, fireUpdate: false,
@@ -8446,7 +8440,7 @@ class NgVirtualListComponent {
8446
8440
  this.emitScrollEvent(true, false, true);
8447
8441
  const scrollParams = params;
8448
8442
  scrollParams?.cb?.();
8449
- }), delay(100), tap(([finished]) => {
8443
+ }), delay(0), tap(([finished]) => {
8450
8444
  if (finished) {
8451
8445
  this._scrollerComponent()?.snapIfNeed();
8452
8446
  }
@@ -8487,6 +8481,14 @@ class NgVirtualListComponent {
8487
8481
  }
8488
8482
  }));
8489
8483
  })).subscribe();
8484
+ combineLatest([$itemConfigMap, $dynamicSize, $divides]).pipe(takeUntilDestroyed(), filter$1(([itemConfigMap, dynamicSize, divides]) => !!itemConfigMap && !dynamicSize && divides > 1), tap(([itemConfigMap]) => {
8485
+ for (const id in itemConfigMap) {
8486
+ const metaData = itemConfigMap[id];
8487
+ if (metaData?.fullSize || metaData?.sticky === 1 || metaData?.sticky === 2) {
8488
+ throw Error('The accelerated rendering algorithm `[dynamicSize]="false"` cannot correctly handle non-uniform lists (the itemConfigMap specifies full-size elements). For correct rendering, specify `[dynamicSize]="true"`.');
8489
+ }
8490
+ }
8491
+ })).subscribe();
8490
8492
  combineLatest([$collapsingMode, $items, $itemConfigMap, $trackBy]).pipe(takeUntilDestroyed(), tap(([collapsingMode, items, itemConfigMap, trackBy]) => {
8491
8493
  const isAccordion = isCollapseMode(collapsingMode, CollapsingModes.ACCORDION);
8492
8494
  if (isAccordion) {
@@ -8690,6 +8692,26 @@ class NgVirtualListComponent {
8690
8692
  this._trackBox.setDisplayObjectIndexMapById(doMap);
8691
8693
  }
8692
8694
  }
8695
+ updateOffsetsByAllignment() {
8696
+ const alignment = this._actualAlignment(), items = this._actualItems(), trackBy = this.trackBy(), isInfinity = this._isInfinity(), isVertical = this._isVertical, { width, height } = this._bounds() || { width: DEFAULT_LIST_SIZE, height: DEFAULT_LIST_SIZE }, viewportSize = isVertical ? height : width, precalculatedScrollStartOffset = this._precalculatedScrollStartOffset(), precalculatedScrollEndOffset = this._precalculatedScrollEndOffset();
8697
+ switch (alignment) {
8698
+ case Alignments.NONE: {
8699
+ this._actualScrollStartOffset.set(precalculatedScrollStartOffset);
8700
+ this._actualScrollEndOffset.set(precalculatedScrollEndOffset);
8701
+ break;
8702
+ }
8703
+ case Alignments.CENTER: {
8704
+ const firstItemId = items.length > 0 ? (items[0]?.[trackBy] ?? null) : null, endItemId = items.length > 0 ? (items?.[items.length - 1]?.[trackBy] ?? null) : null, alignmentStartOffset = viewportSize * .5 - (firstItemId !== null ? (isVertical ? (this._service.getItemBounds(firstItemId)?.height ?? 0) :
8705
+ (this._service.getItemBounds(firstItemId)?.width ?? 0)) : 0) * (isInfinity ? 0 : .5), alignmentEndOffset = viewportSize * .5 - (endItemId !== null ? (isVertical ? (this._service.getItemBounds(endItemId)?.height ?? 0) :
8706
+ (this._service.getItemBounds(endItemId)?.width ?? 0)) : 0) * (isInfinity ? 0 : .5);
8707
+ this._alignmentScrollStartOffset.set(alignmentStartOffset);
8708
+ this._alignmentScrollEndOffset.set(alignmentEndOffset);
8709
+ this._actualScrollStartOffset.set(precalculatedScrollStartOffset + alignmentStartOffset);
8710
+ this._actualScrollEndOffset.set(precalculatedScrollEndOffset + alignmentEndOffset);
8711
+ break;
8712
+ }
8713
+ }
8714
+ }
8693
8715
  updateRegularRenderer() {
8694
8716
  this._resizeSnappedComponentHandler();
8695
8717
  }