ng-virtual-list 17.3.2 → 17.4.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.
@@ -42,7 +42,8 @@ var SnappingMethods;
42
42
  })(SnappingMethods || (SnappingMethods = {}));
43
43
 
44
44
  const DEFAULT_ITEM_SIZE = 24;
45
- const DEFAULT_ITEMS_OFFSET = 2;
45
+ const DEFAULT_BUFFER_SIZE = 2;
46
+ const DEFAULT_MAX_BUFFER_SIZE = 100;
46
47
  const DEFAULT_LIST_SIZE = 400;
47
48
  const DEFAULT_SNAP = false;
48
49
  const DEFAULT_ENABLED_BUFFER_OPTIMIZATION = false;
@@ -209,29 +210,15 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
209
210
  styles.zIndex = HIDDEN_ZINDEX;
210
211
  }
211
212
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgVirtualListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
212
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NgVirtualListItemComponent, selector: "ng-virtual-list-item", host: { classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@if (data(); as item) {\r\n <li #listItem part=\"item\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut}\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, config: item.config}\" />\r\n }\r\n </li>\r\n}", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;will-change:scroll-position}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
213
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NgVirtualListItemComponent, selector: "ng-virtual-list-item", host: { classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@if (data(); as item) {\r\n <li #listItem part=\"item\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut}\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, config: item.config}\" />\r\n }\r\n </li>\r\n}", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
213
214
  }
214
215
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgVirtualListItemComponent, decorators: [{
215
216
  type: Component,
216
217
  args: [{ selector: 'ng-virtual-list-item', standalone: false, host: {
217
218
  'class': 'ngvl__item',
218
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (data(); as item) {\r\n <li #listItem part=\"item\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut}\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, config: item.config}\" />\r\n }\r\n </li>\r\n}", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden;will-change:scroll-position}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"] }]
219
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (data(); as item) {\r\n <li #listItem part=\"item\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut}\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, config: item.config}\" />\r\n }\r\n </li>\r\n}", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"] }]
219
220
  }], ctorParameters: () => [] });
220
221
 
221
- const HORIZONTAL_ALIASES = [Directions.HORIZONTAL, 'horizontal'], VERTICAL_ALIASES = [Directions.VERTICAL, 'vertical'];
222
- /**
223
- * Determines the axis membership of a virtual list
224
- * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/isDirection.ts
225
- * @author Evgenii Grebennikov
226
- * @email djonnyx@gmail.com
227
- */
228
- const isDirection = (src, expected) => {
229
- if (HORIZONTAL_ALIASES.includes(expected)) {
230
- return HORIZONTAL_ALIASES.includes(src);
231
- }
232
- return VERTICAL_ALIASES.includes(src);
233
- };
234
-
235
222
  /**
236
223
  * Simple debounce function.
237
224
  * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/debounce.ts
@@ -279,137 +266,44 @@ const toggleClassName = (el, className, removeClassName) => {
279
266
  };
280
267
 
281
268
  /**
282
- * Tracks display items by property
283
- * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/tracker.ts
269
+ * Scroll event.
270
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/scrollEvent.ts
284
271
  * @author Evgenii Grebennikov
285
272
  * @email djonnyx@gmail.com
286
273
  */
287
- class Tracker {
288
- /**
289
- * display objects dictionary of indexes by id
290
- */
291
- _displayObjectIndexMapById = {};
292
- set displayObjectIndexMapById(v) {
293
- if (this._displayObjectIndexMapById === v) {
294
- return;
295
- }
296
- this._displayObjectIndexMapById = v;
297
- }
298
- get displayObjectIndexMapById() {
299
- return this._displayObjectIndexMapById;
300
- }
301
- /**
302
- * Dictionary displayItems propertyNameId by items propertyNameId
303
- */
304
- _trackMap = {};
305
- get trackMap() {
306
- return this._trackMap;
307
- }
308
- _trackingPropertyName;
309
- set trackingPropertyName(v) {
310
- this._trackingPropertyName = v;
311
- }
312
- constructor(trackingPropertyName) {
313
- this._trackingPropertyName = trackingPropertyName;
314
- }
315
- /**
316
- * tracking by propName
317
- */
318
- track(items, components, snapedComponent, direction) {
319
- if (!items) {
320
- return;
321
- }
322
- const idPropName = this._trackingPropertyName, untrackedItems = [...components], isDown = direction === 0 || direction === 1;
323
- let isRegularSnapped = false;
324
- for (let i = isDown ? 0 : items.length - 1, l = isDown ? items.length : 0; isDown ? i < l : i >= l; isDown ? i++ : i--) {
325
- const item = items[i], itemTrackingProperty = item[idPropName];
326
- if (this._trackMap) {
327
- if (this._trackMap.hasOwnProperty(itemTrackingProperty)) {
328
- const diId = this._trackMap[itemTrackingProperty], compIndex = this._displayObjectIndexMapById[diId], comp = components[compIndex];
329
- const compId = comp?.instance?.id;
330
- if (comp !== undefined && compId === diId) {
331
- const indexByUntrackedItems = untrackedItems.findIndex(v => {
332
- return v.instance.id === compId;
333
- });
334
- if (indexByUntrackedItems > -1) {
335
- if (snapedComponent) {
336
- if (item['config']['snapped'] || item['config']['snappedOut']) {
337
- isRegularSnapped = true;
338
- snapedComponent.instance.item = item;
339
- snapedComponent.instance.show();
340
- }
341
- }
342
- comp.instance.item = item;
343
- if (snapedComponent) {
344
- if (item['config']['snapped'] || item['config']['snappedOut']) {
345
- comp.instance.hide();
346
- }
347
- else {
348
- comp.instance.show();
349
- }
350
- }
351
- else {
352
- comp.instance.show();
353
- }
354
- untrackedItems.splice(indexByUntrackedItems, 1);
355
- continue;
356
- }
357
- }
358
- delete this._trackMap[itemTrackingProperty];
359
- }
360
- }
361
- if (untrackedItems.length > 0) {
362
- const comp = untrackedItems.shift(), item = items[i];
363
- if (comp) {
364
- if (snapedComponent) {
365
- if (item['config']['snapped'] || item['config']['snappedOut']) {
366
- isRegularSnapped = true;
367
- snapedComponent.instance.item = item;
368
- snapedComponent.instance.show();
369
- }
370
- }
371
- comp.instance.item = item;
372
- if (snapedComponent) {
373
- if (item['config']['snapped'] || item['config']['snappedOut']) {
374
- comp.instance.hide();
375
- }
376
- else {
377
- comp.instance.show();
378
- }
379
- }
380
- else {
381
- comp.instance.show();
382
- }
383
- if (this._trackMap) {
384
- this._trackMap[itemTrackingProperty] = comp.instance.id;
385
- }
386
- }
387
- }
388
- }
389
- if (untrackedItems.length) {
390
- for (let i = 0, l = untrackedItems.length; i < l; i++) {
391
- const comp = untrackedItems[i];
392
- comp.instance.hide();
393
- }
394
- }
395
- if (!isRegularSnapped) {
396
- if (snapedComponent) {
397
- snapedComponent.instance.item = null;
398
- snapedComponent.instance.hide();
399
- }
400
- }
401
- }
402
- untrackComponentByIdProperty(component) {
403
- if (!component) {
404
- return;
405
- }
406
- const propertyIdName = this._trackingPropertyName;
407
- if (this._trackMap && component[propertyIdName] !== undefined) {
408
- delete this._trackMap[propertyIdName];
409
- }
410
- }
411
- dispose() {
412
- this._trackMap = null;
274
+ class ScrollEvent {
275
+ _direction = 1;
276
+ get direction() { return this._direction; }
277
+ _scrollSize = 0;
278
+ get scrollSize() { return this._scrollSize; }
279
+ _scrollWeight = 0;
280
+ get scrollWeight() { return this._scrollWeight; }
281
+ _isVertical = true;
282
+ get isVertical() { return this._isVertical; }
283
+ _listSize = 0;
284
+ get listSize() { return this._listSize; }
285
+ _size = 0;
286
+ get size() { return this._size; }
287
+ _isStart = true;
288
+ get isStart() { return this._isStart; }
289
+ _isEnd = false;
290
+ get isEnd() { return this._isEnd; }
291
+ _delta = 0;
292
+ get delta() { return this._delta; }
293
+ _scrollDelta = 0;
294
+ get scrollDelta() { return this._scrollDelta; }
295
+ constructor(params) {
296
+ const { direction, isVertical, container, list, delta, scrollDelta } = params;
297
+ this._direction = direction;
298
+ this._isVertical = isVertical;
299
+ this._scrollSize = isVertical ? container.scrollTop : container.scrollLeft;
300
+ this._scrollWeight = isVertical ? container.scrollHeight : container.scrollWidth;
301
+ this._listSize = isVertical ? list.offsetHeight : list.offsetWidth;
302
+ this._size = isVertical ? container.offsetHeight : container.offsetWidth;
303
+ this._isEnd = (this._scrollSize + this._size) === this._scrollWeight;
304
+ this._delta = delta;
305
+ this._scrollDelta = scrollDelta;
306
+ this._isStart = this._scrollSize === 0;
413
307
  }
414
308
  }
415
309
 
@@ -684,6 +578,168 @@ class CacheMap extends EventEmitter {
684
578
  }
685
579
  }
686
580
 
581
+ /**
582
+ * Tracks display items by property
583
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/tracker.ts
584
+ * @author Evgenii Grebennikov
585
+ * @email djonnyx@gmail.com
586
+ */
587
+ class Tracker {
588
+ /**
589
+ * display objects dictionary of indexes by id
590
+ */
591
+ _displayObjectIndexMapById = {};
592
+ set displayObjectIndexMapById(v) {
593
+ if (this._displayObjectIndexMapById === v) {
594
+ return;
595
+ }
596
+ this._displayObjectIndexMapById = v;
597
+ }
598
+ get displayObjectIndexMapById() {
599
+ return this._displayObjectIndexMapById;
600
+ }
601
+ /**
602
+ * Dictionary displayItems propertyNameId by items propertyNameId
603
+ */
604
+ _trackMap = {};
605
+ get trackMap() {
606
+ return this._trackMap;
607
+ }
608
+ _trackingPropertyName;
609
+ set trackingPropertyName(v) {
610
+ this._trackingPropertyName = v;
611
+ }
612
+ constructor(trackingPropertyName) {
613
+ this._trackingPropertyName = trackingPropertyName;
614
+ }
615
+ /**
616
+ * tracking by propName
617
+ */
618
+ track(items, components, snapedComponent, direction) {
619
+ if (!items) {
620
+ return;
621
+ }
622
+ const idPropName = this._trackingPropertyName, untrackedItems = [...components], isDown = direction === 0 || direction === 1;
623
+ let isRegularSnapped = false;
624
+ for (let i = isDown ? 0 : items.length - 1, l = isDown ? items.length : 0; isDown ? i < l : i >= l; isDown ? i++ : i--) {
625
+ const item = items[i], itemTrackingProperty = item[idPropName];
626
+ if (this._trackMap) {
627
+ if (this._trackMap.hasOwnProperty(itemTrackingProperty)) {
628
+ const diId = this._trackMap[itemTrackingProperty], compIndex = this._displayObjectIndexMapById[diId], comp = components[compIndex];
629
+ const compId = comp?.instance?.id;
630
+ if (comp !== undefined && compId === diId) {
631
+ const indexByUntrackedItems = untrackedItems.findIndex(v => {
632
+ return v.instance.id === compId;
633
+ });
634
+ if (indexByUntrackedItems > -1) {
635
+ if (snapedComponent) {
636
+ if (item['config']['snapped'] || item['config']['snappedOut']) {
637
+ isRegularSnapped = true;
638
+ snapedComponent.instance.item = item;
639
+ snapedComponent.instance.show();
640
+ }
641
+ }
642
+ comp.instance.item = item;
643
+ if (snapedComponent) {
644
+ if (item['config']['snapped'] || item['config']['snappedOut']) {
645
+ comp.instance.hide();
646
+ }
647
+ else {
648
+ comp.instance.show();
649
+ }
650
+ }
651
+ else {
652
+ comp.instance.show();
653
+ }
654
+ untrackedItems.splice(indexByUntrackedItems, 1);
655
+ continue;
656
+ }
657
+ }
658
+ delete this._trackMap[itemTrackingProperty];
659
+ }
660
+ }
661
+ if (untrackedItems.length > 0) {
662
+ const comp = untrackedItems.shift(), item = items[i];
663
+ if (comp) {
664
+ if (snapedComponent) {
665
+ if (item['config']['snapped'] || item['config']['snappedOut']) {
666
+ isRegularSnapped = true;
667
+ snapedComponent.instance.item = item;
668
+ snapedComponent.instance.show();
669
+ }
670
+ }
671
+ comp.instance.item = item;
672
+ if (snapedComponent) {
673
+ if (item['config']['snapped'] || item['config']['snappedOut']) {
674
+ comp.instance.hide();
675
+ }
676
+ else {
677
+ comp.instance.show();
678
+ }
679
+ }
680
+ else {
681
+ comp.instance.show();
682
+ }
683
+ if (this._trackMap) {
684
+ this._trackMap[itemTrackingProperty] = comp.instance.id;
685
+ }
686
+ }
687
+ }
688
+ }
689
+ if (untrackedItems.length) {
690
+ for (let i = 0, l = untrackedItems.length; i < l; i++) {
691
+ const comp = untrackedItems[i];
692
+ comp.instance.hide();
693
+ }
694
+ }
695
+ if (!isRegularSnapped) {
696
+ if (snapedComponent) {
697
+ snapedComponent.instance.item = null;
698
+ snapedComponent.instance.hide();
699
+ }
700
+ }
701
+ }
702
+ untrackComponentByIdProperty(component) {
703
+ if (!component) {
704
+ return;
705
+ }
706
+ const propertyIdName = this._trackingPropertyName;
707
+ if (this._trackMap && component[propertyIdName] !== undefined) {
708
+ delete this._trackMap[propertyIdName];
709
+ }
710
+ }
711
+ dispose() {
712
+ this._trackMap = null;
713
+ }
714
+ }
715
+
716
+ const DEFAULT_EXTRA = {
717
+ extremumThreshold: 2,
718
+ bufferSize: 10,
719
+ };
720
+ const bufferInterpolation = (currentBufferValue, array, value, extra) => {
721
+ const { extremumThreshold = DEFAULT_EXTRA.extremumThreshold, bufferSize = DEFAULT_EXTRA.bufferSize, } = extra ?? DEFAULT_EXTRA;
722
+ if (currentBufferValue < value) {
723
+ let i = 0;
724
+ while (i < extremumThreshold) {
725
+ array.push(value);
726
+ i++;
727
+ }
728
+ }
729
+ else {
730
+ array.push(value);
731
+ }
732
+ while (array.length >= bufferSize) {
733
+ array.shift();
734
+ }
735
+ const l = array.length;
736
+ let buffer = 0;
737
+ for (let i = 0; i < l; i++) {
738
+ buffer += array[i];
739
+ }
740
+ return Math.ceil(buffer / l);
741
+ };
742
+
687
743
  const TRACK_BOX_CHANGE_EVENT_NAME = 'change';
688
744
  var ItemDisplayMethods;
689
745
  (function (ItemDisplayMethods) {
@@ -692,6 +748,7 @@ var ItemDisplayMethods;
692
748
  ItemDisplayMethods[ItemDisplayMethods["DELETE"] = 2] = "DELETE";
693
749
  ItemDisplayMethods[ItemDisplayMethods["NOT_CHANGED"] = 3] = "NOT_CHANGED";
694
750
  })(ItemDisplayMethods || (ItemDisplayMethods = {}));
751
+ const DEFAULT_BUFFER_EXTREMUM_THRESHOLD = 15, DEFAULT_MAX_BUFFER_SEQUENCE_LENGTH = 30, DEFAULT_RESET_BUFFER_SIZE_TIMEOUT = 10000;
695
752
  /**
696
753
  * An object that performs tracking, calculations and caching.
697
754
  * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/trackBox.ts
@@ -732,11 +789,16 @@ class TrackBox extends CacheMap {
732
789
  * Set the trackBy property
733
790
  */
734
791
  set trackingPropertyName(v) {
735
- this._tracker.trackingPropertyName = v;
792
+ this._trackingPropertyName = this._tracker.trackingPropertyName = v;
736
793
  }
794
+ _trackingPropertyName = TRACK_BY_PROPERTY_NAME;
737
795
  constructor(trackingPropertyName) {
738
796
  super();
739
- this._tracker = new Tracker(trackingPropertyName);
797
+ this._trackingPropertyName = trackingPropertyName;
798
+ this.initialize();
799
+ }
800
+ initialize() {
801
+ this._tracker = new Tracker(this._trackingPropertyName);
740
802
  }
741
803
  set(id, bounds) {
742
804
  if (this._map.has(id)) {
@@ -761,6 +823,16 @@ class TrackBox extends CacheMap {
761
823
  _previousTotalSize = 0;
762
824
  _scrollDelta = 0;
763
825
  get scrollDelta() { return this._scrollDelta; }
826
+ isAdaptiveBuffer = true;
827
+ _bufferSequenceExtraThreshold = DEFAULT_BUFFER_EXTREMUM_THRESHOLD;
828
+ _maxBufferSequenceLength = DEFAULT_MAX_BUFFER_SEQUENCE_LENGTH;
829
+ _bufferSizeSequence = [];
830
+ _bufferSize = 0;
831
+ get bufferSize() { return this._bufferSize; }
832
+ _defaultBufferSize = 0;
833
+ _maxBufferSize = this._defaultBufferSize;
834
+ _resetBufferSizeTimeout = DEFAULT_RESET_BUFFER_SIZE_TIMEOUT;
835
+ _resetBufferSizeTimer;
764
836
  lifeCircle() {
765
837
  this.fireChangeIfNeed();
766
838
  this.lifeCircleDo();
@@ -854,6 +926,8 @@ class TrackBox extends CacheMap {
854
926
  */
855
927
  getItemPosition(id, stickyMap, options) {
856
928
  const opt = { fromItemId: id, stickyMap, ...options };
929
+ this._defaultBufferSize = opt.bufferSize;
930
+ this._maxBufferSize = opt.maxBufferSize;
857
931
  const { scrollSize, isFromItemIdFound } = this.recalculateMetrics({
858
932
  ...opt,
859
933
  dynamicSize: this._crudDetected || opt.dynamicSize,
@@ -871,6 +945,8 @@ class TrackBox extends CacheMap {
871
945
  if (opt.dynamicSize) {
872
946
  this.cacheElements();
873
947
  }
948
+ this._defaultBufferSize = opt.bufferSize;
949
+ this._maxBufferSize = opt.maxBufferSize;
874
950
  const metrics = this.recalculateMetrics({
875
951
  ...opt,
876
952
  collection: items,
@@ -879,6 +955,7 @@ class TrackBox extends CacheMap {
879
955
  deletedItemsMap,
880
956
  });
881
957
  this._delta += metrics.delta;
958
+ this.updateAdaptiveBufferParams(metrics, items.length);
882
959
  this._previousTotalSize = metrics.totalSize;
883
960
  this._deletedItemsMap = {};
884
961
  this._crudDetected = false;
@@ -894,6 +971,27 @@ class TrackBox extends CacheMap {
894
971
  getNearestItem(scrollSize, items, itemSize, isVertical) {
895
972
  return this.getElementFromStart(scrollSize, items, this._map, itemSize, isVertical);
896
973
  }
974
+ _previousScrollSize = 0;
975
+ updateAdaptiveBufferParams(metrics, totalItemsLength) {
976
+ this.disposeClearBufferSizeTimer();
977
+ const scrollSize = metrics.scrollSize + this._delta, delta = Math.abs(this._previousScrollSize - scrollSize);
978
+ this._previousScrollSize = scrollSize;
979
+ const bufferRawSize = Math.min(Math.floor(delta / metrics.typicalItemSize) * 5, totalItemsLength), minBufferSize = bufferRawSize < this._defaultBufferSize ? this._defaultBufferSize : bufferRawSize, bufferValue = minBufferSize > this._maxBufferSize ? this._maxBufferSize : minBufferSize;
980
+ this._bufferSize = bufferInterpolation(this._bufferSize, this._bufferSizeSequence, bufferValue, {
981
+ extremumThreshold: this._bufferSequenceExtraThreshold,
982
+ bufferSize: this._maxBufferSequenceLength,
983
+ });
984
+ this.startResetBufferSizeTimer();
985
+ }
986
+ startResetBufferSizeTimer() {
987
+ this._resetBufferSizeTimer = setTimeout(() => {
988
+ this._bufferSize = this._defaultBufferSize;
989
+ this._bufferSizeSequence = [];
990
+ }, this._resetBufferSizeTimeout);
991
+ }
992
+ disposeClearBufferSizeTimer() {
993
+ clearTimeout(this._resetBufferSizeTimer);
994
+ }
897
995
  /**
898
996
  * Calculates the position of an element based on the given scrollSize
899
997
  */
@@ -945,30 +1043,30 @@ class TrackBox extends CacheMap {
945
1043
  * Calculates list metrics
946
1044
  */
947
1045
  recalculateMetrics(options) {
948
- const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, itemsOffset, scrollSize, snap, stickyMap, enabledBufferOptimization, previousTotalSize, crudDetected, deletedItemsMap } = options;
949
- const { 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, checkOverscrollItemsLimit = Math.ceil(size / typicalItemSize), snippedPos = Math.floor(scrollSize), leftItemsWeights = [], isFromId = fromItemId !== undefined && (typeof fromItemId === 'number' && fromItemId > -1)
1046
+ const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, bufferSize: minBufferSize, scrollSize, snap, stickyMap, enabledBufferOptimization, previousTotalSize, crudDetected, deletedItemsMap } = options;
1047
+ const 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, checkOverscrollItemsLimit = Math.ceil(size / typicalItemSize), snippedPos = Math.floor(scrollSize), leftItemsWeights = [], isFromId = fromItemId !== undefined && (typeof fromItemId === 'number' && fromItemId > -1)
950
1048
  || (typeof fromItemId === 'string' && fromItemId > '-1');
951
1049
  let leftItemsOffset = 0, rightItemsOffset = 0;
952
1050
  if (enabledBufferOptimization) {
953
1051
  switch (this.scrollDirection) {
954
1052
  case 1: {
955
1053
  leftItemsOffset = 0;
956
- rightItemsOffset = itemsOffset;
1054
+ rightItemsOffset = bufferSize;
957
1055
  break;
958
1056
  }
959
1057
  case -1: {
960
- leftItemsOffset = itemsOffset;
1058
+ leftItemsOffset = bufferSize;
961
1059
  rightItemsOffset = 0;
962
1060
  break;
963
1061
  }
964
1062
  case 0:
965
1063
  default: {
966
- leftItemsOffset = rightItemsOffset = itemsOffset;
1064
+ leftItemsOffset = rightItemsOffset = bufferSize;
967
1065
  }
968
1066
  }
969
1067
  }
970
1068
  else {
971
- leftItemsOffset = rightItemsOffset = itemsOffset;
1069
+ leftItemsOffset = rightItemsOffset = bufferSize;
972
1070
  }
973
1071
  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;
974
1072
  // If the list is dynamic or there are new elements in the collection, then it switches to the long algorithm.
@@ -1143,9 +1241,9 @@ class TrackBox extends CacheMap {
1143
1241
  }
1144
1242
  itemsFromStartToScrollEnd = Math.floor(scrollSize / typicalItemSize);
1145
1243
  itemsFromStartToDisplayEnd = Math.ceil((scrollSize + size) / typicalItemSize);
1146
- leftItemLength = Math.min(itemsFromStartToScrollEnd, itemsOffset);
1147
- rightItemLength = itemsFromStartToDisplayEnd + itemsOffset > totalLength
1148
- ? totalLength - itemsFromStartToDisplayEnd : itemsOffset;
1244
+ leftItemLength = Math.min(itemsFromStartToScrollEnd, bufferSize);
1245
+ rightItemLength = itemsFromStartToDisplayEnd + bufferSize > totalLength
1246
+ ? totalLength - itemsFromStartToDisplayEnd : bufferSize;
1149
1247
  leftItemsWeight = leftItemLength * typicalItemSize;
1150
1248
  rightItemsWeight = rightItemLength * typicalItemSize;
1151
1249
  leftHiddenItemsWeight = itemsFromStartToScrollEnd * typicalItemSize;
@@ -1242,6 +1340,9 @@ class TrackBox extends CacheMap {
1242
1340
  if (snap) {
1243
1341
  const startIndex = itemsFromStartToScrollEnd + itemsOnDisplayLength - 1;
1244
1342
  for (let i = Math.min(startIndex, totalLength > 0 ? totalLength - 1 : 0), l = totalLength; i < l; i++) {
1343
+ if (!items[i]) {
1344
+ continue;
1345
+ }
1245
1346
  const id = items[i].id, sticky = stickyMap[id], size = dynamicSize
1246
1347
  ? this.get(id)?.[sizeProperty] || typicalItemSize
1247
1348
  : typicalItemSize;
@@ -1276,6 +1377,9 @@ class TrackBox extends CacheMap {
1276
1377
  if (i >= totalLength) {
1277
1378
  break;
1278
1379
  }
1380
+ if (!items[i]) {
1381
+ continue;
1382
+ }
1279
1383
  const id = items[i].id, size = dynamicSize ? this.get(id)?.[sizeProperty] || typicalItemSize : typicalItemSize;
1280
1384
  if (id !== stickyItem?.id && id !== endStickyItem?.id) {
1281
1385
  const snapped = snap && (stickyMap[id] === 1 && pos <= scrollSize || stickyMap[id] === 2 && pos >= scrollSize + boundsSize - size), measures = {
@@ -1387,54 +1491,13 @@ class TrackBox extends CacheMap {
1387
1491
  }
1388
1492
  dispose() {
1389
1493
  super.dispose();
1494
+ this.disposeClearBufferSizeTimer();
1390
1495
  if (this._tracker) {
1391
1496
  this._tracker.dispose();
1392
1497
  }
1393
1498
  }
1394
1499
  }
1395
1500
 
1396
- /**
1397
- * Scroll event.
1398
- * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/scrollEvent.ts
1399
- * @author Evgenii Grebennikov
1400
- * @email djonnyx@gmail.com
1401
- */
1402
- class ScrollEvent {
1403
- _direction = 1;
1404
- get direction() { return this._direction; }
1405
- _scrollSize = 0;
1406
- get scrollSize() { return this._scrollSize; }
1407
- _scrollWeight = 0;
1408
- get scrollWeight() { return this._scrollWeight; }
1409
- _isVertical = true;
1410
- get isVertical() { return this._isVertical; }
1411
- _listSize = 0;
1412
- get listSize() { return this._listSize; }
1413
- _size = 0;
1414
- get size() { return this._size; }
1415
- _isStart = true;
1416
- get isStart() { return this._isStart; }
1417
- _isEnd = false;
1418
- get isEnd() { return this._isEnd; }
1419
- _delta = 0;
1420
- get delta() { return this._delta; }
1421
- _scrollDelta = 0;
1422
- get scrollDelta() { return this._scrollDelta; }
1423
- constructor(params) {
1424
- const { direction, isVertical, container, list, delta, scrollDelta } = params;
1425
- this._direction = direction;
1426
- this._isVertical = isVertical;
1427
- this._scrollSize = isVertical ? container.scrollTop : container.scrollLeft;
1428
- this._scrollWeight = isVertical ? container.scrollHeight : container.scrollWidth;
1429
- this._listSize = isVertical ? list.offsetHeight : list.offsetWidth;
1430
- this._size = isVertical ? container.offsetHeight : container.offsetWidth;
1431
- this._isEnd = (this._scrollSize + this._size) === this._scrollWeight;
1432
- this._delta = delta;
1433
- this._scrollDelta = scrollDelta;
1434
- this._isStart = this._scrollSize === 0;
1435
- }
1436
- }
1437
-
1438
1501
  const ADVANCED_PATTERNS = [SnappingMethods.ADVANCED, 'advanced'], DEFAULT_PATTERN = [SnappingMethods.NORMAL, 'normal'];
1439
1502
  const isSnappingMethodAdvenced = (method) => {
1440
1503
  return ADVANCED_PATTERNS.includes(method);
@@ -1446,6 +1509,20 @@ const isSnappingMethodDefault = (method) => {
1446
1509
  const IS_FIREFOX = navigator.userAgent.toLowerCase().includes('firefox');
1447
1510
  const FIREFOX_SCROLLBAR_OVERLAP_SIZE = 12;
1448
1511
 
1512
+ const HORIZONTAL_ALIASES = [Directions.HORIZONTAL, 'horizontal'], VERTICAL_ALIASES = [Directions.VERTICAL, 'vertical'];
1513
+ /**
1514
+ * Determines the axis membership of a virtual list
1515
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/isDirection.ts
1516
+ * @author Evgenii Grebennikov
1517
+ * @email djonnyx@gmail.com
1518
+ */
1519
+ const isDirection = (src, expected) => {
1520
+ if (HORIZONTAL_ALIASES.includes(expected)) {
1521
+ return HORIZONTAL_ALIASES.includes(src);
1522
+ }
1523
+ return VERTICAL_ALIASES.includes(src);
1524
+ };
1525
+
1449
1526
  /**
1450
1527
  * Virtual list component.
1451
1528
  * Maximum performance for extremely large lists.
@@ -1530,10 +1607,35 @@ class NgVirtualListComponent {
1530
1607
  * Determines the direction in which elements are placed. Default value is "vertical".
1531
1608
  */
1532
1609
  direction = input(DEFAULT_DIRECTION);
1610
+ _itemOffsetTransform = {
1611
+ transform: (v) => {
1612
+ throw Error('"itemOffset" parameter is deprecated. Use "bufferSize" and "maxBufferSize".');
1613
+ }
1614
+ };
1615
+ /**
1616
+ * Number of elements outside the scope of visibility. Default value is 2.
1617
+ * @deprecated "itemOffset" parameter is deprecated. Use "bufferSize" and "maxBufferSize".
1618
+ */
1619
+ itemsOffset = input(DEFAULT_BUFFER_SIZE, { ...this._itemOffsetTransform });
1533
1620
  /**
1534
1621
  * Number of elements outside the scope of visibility. Default value is 2.
1535
1622
  */
1536
- itemsOffset = input(DEFAULT_ITEMS_OFFSET);
1623
+ bufferSize = input(DEFAULT_BUFFER_SIZE);
1624
+ _maxBufferSizeTransform = {
1625
+ transform: (v) => {
1626
+ const bufferSize = this.bufferSize();
1627
+ if (v === undefined || v <= bufferSize) {
1628
+ return bufferSize;
1629
+ }
1630
+ return v;
1631
+ }
1632
+ };
1633
+ /**
1634
+ * Maximum number of elements outside the scope of visibility. Default value is 100.
1635
+ * If maxBufferSize is set to be greater than bufferSize, then adaptive buffer mode is enabled.
1636
+ * The greater the scroll size, the more elements are allocated for rendering.
1637
+ */
1638
+ maxBufferSize = input(DEFAULT_MAX_BUFFER_SIZE, { ...this._maxBufferSizeTransform });
1537
1639
  /**
1538
1640
  * Snapping method.
1539
1641
  * 'default' - Normal group rendering.
@@ -1637,7 +1739,7 @@ class NgVirtualListComponent {
1637
1739
  $trackBy.pipe(takeUntilDestroyed(), tap(v => {
1638
1740
  this._trackBox.trackingPropertyName = v;
1639
1741
  })).subscribe();
1640
- 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)), $itemsOffset = toObservable(this.itemsOffset).pipe(map(v => v < 0 ? DEFAULT_ITEMS_OFFSET : v)), $stickyMap = toObservable(this.stickyMap).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))), $cacheVersion = toObservable(this._cacheVersion);
1742
+ 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)), $stickyMap = toObservable(this.stickyMap).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))), $cacheVersion = toObservable(this._cacheVersion);
1641
1743
  $isVertical.pipe(takeUntilDestroyed(), tap(v => {
1642
1744
  this._isVertical = v;
1643
1745
  const el = this._elementRef.nativeElement;
@@ -1650,12 +1752,12 @@ class NgVirtualListComponent {
1650
1752
  this.listenCacheChangesIfNeed(dynamicSize);
1651
1753
  })).subscribe();
1652
1754
  combineLatest([this.$initialized, $bounds, $items, $stickyMap, $scrollSize, $itemSize,
1653
- $itemsOffset, $snap, $isVertical, $dynamicSize, $enabledBufferOptimization, $cacheVersion,
1654
- ]).pipe(takeUntilDestroyed(), distinctUntilChanged(), filter(([initialized]) => !!initialized), switchMap(([, bounds, items, stickyMap, scrollSize, itemSize, itemsOffset, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,]) => {
1755
+ $bufferSize, $maxBufferSize, $snap, $isVertical, $dynamicSize, $enabledBufferOptimization, $cacheVersion,
1756
+ ]).pipe(takeUntilDestroyed(), distinctUntilChanged(), filter(([initialized]) => !!initialized), switchMap(([, bounds, items, stickyMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,]) => {
1655
1757
  let actualScrollSize = (this._isVertical ? this._container()?.nativeElement.scrollTop ?? 0 : this._container()?.nativeElement.scrollLeft) ?? 0;
1656
1758
  const { width, height } = bounds, opts = {
1657
1759
  bounds: { width, height }, dynamicSize, isVertical, itemSize,
1658
- itemsOffset, scrollSize: actualScrollSize, snap, enabledBufferOptimization,
1760
+ bufferSize, maxBufferSize, scrollSize: actualScrollSize, snap, enabledBufferOptimization,
1659
1761
  }, { displayItems, totalSize } = this._trackBox.updateCollection(items, stickyMap, opts);
1660
1762
  this.resetBoundsSize(isVertical, totalSize);
1661
1763
  this.createDisplayComponentsIfNeed(displayItems);
@@ -1678,9 +1780,6 @@ class NgVirtualListComponent {
1678
1780
  }
1679
1781
  return of(displayItems);
1680
1782
  })).subscribe();
1681
- this.setupRenderer();
1682
- }
1683
- setupRenderer() {
1684
1783
  const $itemRenderer = toObservable(this.itemRenderer);
1685
1784
  $itemRenderer.pipe(takeUntilDestroyed(), distinctUntilChanged(), filter(v => !!v), tap(v => {
1686
1785
  this._itemRenderer.set(v);
@@ -1802,7 +1901,8 @@ class NgVirtualListComponent {
1802
1901
  }
1803
1902
  const { width, height } = this._bounds() || { width: DEFAULT_LIST_SIZE, height: DEFAULT_LIST_SIZE }, stickyMap = this.stickyMap(), items = this.items(), isVertical = this._isVertical, delta = this._trackBox.delta, opts = {
1804
1903
  bounds: { width, height }, collection: items, dynamicSize, isVertical: this._isVertical, itemSize,
1805
- itemsOffset: this.itemsOffset(), scrollSize: (isVertical ? container.nativeElement.scrollTop : container.nativeElement.scrollLeft) + delta,
1904
+ bufferSize: this.bufferSize(), maxBufferSize: this.maxBufferSize(),
1905
+ scrollSize: (isVertical ? container.nativeElement.scrollTop : container.nativeElement.scrollLeft) + delta,
1806
1906
  snap: this.snap(), fromItemId: id, enabledBufferOptimization: this.enabledBufferOptimization(),
1807
1907
  }, scrollSize = this._trackBox.getItemPosition(id, stickyMap, opts), params = { [isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollSize, behavior };
1808
1908
  if (scrollSize === -1) {
@@ -1933,7 +2033,7 @@ class NgVirtualListComponent {
1933
2033
  }
1934
2034
  }
1935
2035
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgVirtualListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1936
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NgVirtualListComponent, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, 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 }, stickyMap: { classPropertyName: "stickyMap", publicName: "stickyMap", 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 }, itemsOffset: { classPropertyName: "itemsOffset", publicName: "itemsOffset", isSignal: true, isRequired: false, transformFunction: null }, snappingMethod: { classPropertyName: "snappingMethod", publicName: "snappingMethod", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onScroll: "onScroll", onScrollEnd: "onScrollEnd" }, 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 <ul #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </ul>\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 });
2036
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NgVirtualListComponent, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, 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 }, stickyMap: { classPropertyName: "stickyMap", publicName: "stickyMap", 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 }, itemsOffset: { classPropertyName: "itemsOffset", publicName: "itemsOffset", 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 }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onScroll: "onScroll", onScrollEnd: "onScrollEnd" }, 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 <ul #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </ul>\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 });
1937
2037
  }
1938
2038
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgVirtualListComponent, decorators: [{
1939
2039
  type: Component,
@@ -1969,5 +2069,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1969
2069
  * Generated bundle index. Do not edit.
1970
2070
  */
1971
2071
 
1972
- export { BaseVirtualListItemComponent, Directions, NgVirtualListComponent, NgVirtualListItemComponent, NgVirtualListModule, SnappingMethods };
2072
+ export { Directions, NgVirtualListComponent, NgVirtualListItemComponent, NgVirtualListModule, ScrollEvent, SnappingMethods, debounce, toggleClassName };
1973
2073
  //# sourceMappingURL=ng-virtual-list.mjs.map