ng-virtual-list 17.7.13 → 17.7.15

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.
Files changed (34) hide show
  1. package/README.md +29 -9
  2. package/esm2022/lib/components/ng-virtual-list-item.component.mjs +41 -19
  3. package/esm2022/lib/const/index.mjs +3 -2
  4. package/esm2022/lib/enums/collection-mode.mjs +2 -0
  5. package/esm2022/lib/enums/collection-modes.mjs +18 -0
  6. package/esm2022/lib/enums/focus-alignments.mjs +14 -0
  7. package/esm2022/lib/enums/index.mjs +4 -2
  8. package/esm2022/lib/models/display-object-config.model.mjs +2 -0
  9. package/esm2022/lib/models/display-object-measures.model.mjs +2 -0
  10. package/esm2022/lib/models/index.mjs +1 -1
  11. package/esm2022/lib/ng-virtual-list.component.mjs +103 -22
  12. package/esm2022/lib/ng-virtual-list.service.mjs +6 -5
  13. package/esm2022/lib/types/focus-alignment.mjs +2 -0
  14. package/esm2022/lib/types/index.mjs +1 -1
  15. package/esm2022/lib/utils/isCollectionMode.mjs +15 -0
  16. package/esm2022/lib/utils/trackBox.mjs +45 -16
  17. package/fesm2022/ng-virtual-list.mjs +231 -54
  18. package/fesm2022/ng-virtual-list.mjs.map +1 -1
  19. package/lib/components/ng-virtual-list-item.component.d.ts +7 -35
  20. package/lib/const/index.d.ts +2 -1
  21. package/lib/enums/collection-mode.d.ts +8 -0
  22. package/lib/enums/collection-modes.d.ts +16 -0
  23. package/lib/enums/focus-alignments.d.ts +12 -0
  24. package/lib/enums/index.d.ts +5 -2
  25. package/lib/models/display-object-config.model.d.ts +35 -0
  26. package/lib/models/display-object-measures.model.d.ts +13 -0
  27. package/lib/models/index.d.ts +3 -1
  28. package/lib/ng-virtual-list.component.d.ts +16 -3
  29. package/lib/ng-virtual-list.service.d.ts +4 -4
  30. package/lib/types/focus-alignment.d.ts +8 -0
  31. package/lib/types/index.d.ts +2 -1
  32. package/lib/utils/isCollectionMode.d.ts +8 -0
  33. package/lib/utils/trackBox.d.ts +17 -9
  34. package/package.json +1 -1
@@ -1,11 +1,29 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, inject, ChangeDetectorRef, signal, ElementRef, ChangeDetectionStrategy, Component, viewChild, output, input, ViewContainerRef, ViewChild, ViewEncapsulation, NO_ERRORS_SCHEMA, NgModule } from '@angular/core';
3
- import { Subject, tap, fromEvent, combineLatest, map, filter, distinctUntilChanged, skip, switchMap, of } from 'rxjs';
4
- import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
5
3
  import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
4
+ import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
5
+ import { Subject, tap, fromEvent, combineLatest, map, filter, distinctUntilChanged, switchMap, of } from 'rxjs';
6
6
  import * as i1 from '@angular/common';
7
7
  import { CommonModule } from '@angular/common';
8
8
 
9
+ /**
10
+ * Action modes for collection elements.
11
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/enums/collection-modes.ts
12
+ * @author Evgenii Grebennikov
13
+ * @email djonnyx@gmail.com
14
+ */
15
+ var CollectionModes;
16
+ (function (CollectionModes) {
17
+ /**
18
+ * When adding elements to the beginning of the collection, the scroll remains at the current position.
19
+ */
20
+ CollectionModes["NORMAL"] = "normal";
21
+ /**
22
+ * When adding elements to the beginning of the collection, the scroll is shifted by the sum of the sizes of the new elements.
23
+ */
24
+ CollectionModes["LAZY"] = "lazy";
25
+ })(CollectionModes || (CollectionModes = {}));
26
+
9
27
  /**
10
28
  * Axis of the arrangement of virtual list elements.
11
29
  * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/enums/directions.ts
@@ -64,6 +82,20 @@ var SnappingMethods;
64
82
  SnappingMethods["ADVANCED"] = "advanced";
65
83
  })(SnappingMethods || (SnappingMethods = {}));
66
84
 
85
+ /**
86
+ * Focus Alignments.
87
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/enums/focus-alignments.ts
88
+ * @author Evgenii Grebennikov
89
+ * @email djonnyx@gmail.com
90
+ */
91
+ var FocusAlignments;
92
+ (function (FocusAlignments) {
93
+ FocusAlignments["NONE"] = "none";
94
+ FocusAlignments["START"] = "start";
95
+ FocusAlignments["CENTER"] = "center";
96
+ FocusAlignments["END"] = "end";
97
+ })(FocusAlignments || (FocusAlignments = {}));
98
+
67
99
  const DEFAULT_ITEM_SIZE = 24;
68
100
  const DEFAULT_BUFFER_SIZE = 2;
69
101
  const DEFAULT_MAX_BUFFER_SIZE = 10;
@@ -75,6 +107,7 @@ const DEFAULT_ENABLED_BUFFER_OPTIMIZATION = false;
75
107
  const DEFAULT_DYNAMIC_SIZE = false;
76
108
  const TRACK_BY_PROPERTY_NAME = 'id';
77
109
  const DEFAULT_DIRECTION = Directions.VERTICAL;
110
+ const DEFAULT_COLLECTION_MODE = CollectionModes.NORMAL;
78
111
  const DISPLAY_OBJECTS_LENGTH_MESUREMENT_ERROR = 1;
79
112
  const MAX_SCROLL_TO_ITERATIONS = 5;
80
113
  const DEFAULT_SNAPPING_METHOD = SnappingMethods.NORMAL;
@@ -308,11 +341,11 @@ class NgVirtualListService {
308
341
  }
309
342
  }
310
343
  itemToFocus;
311
- focus(element) {
344
+ focus(element, align = FocusAlignments.CENTER) {
312
345
  element.focus({ preventScroll: true });
313
346
  if (element.parentElement) {
314
347
  const pos = parseFloat(element.parentElement?.getAttribute('position') ?? '0');
315
- this.itemToFocus?.(element, pos);
348
+ this.itemToFocus?.(element, pos, align);
316
349
  }
317
350
  }
318
351
  areaFocus(id) {
@@ -391,7 +424,7 @@ const validateFunction = (value, undefinable = false, nullable = false) => {
391
424
  return (undefinable && isUndefinable(value)) || (nullable && isNullable(value)) || typeof value === 'function';
392
425
  };
393
426
 
394
- const ATTR_AREA_SELECTED = 'area-selected', TABINDEX = 'ng-vl-index', KEY_SPACE = " ", KEY_ARR_LEFT = "ArrowLeft", KEY_ARR_UP = "ArrowUp", KEY_ARR_RIGHT = "ArrowRight", KEY_ARR_DOWN = "ArrowDown", EVENT_FOCUS_IN = 'focusin', EVENT_FOCUS_OUT = 'focusout', EVENT_KEY_DOWN = 'keydown';
427
+ const ATTR_AREA_SELECTED = 'area-selected', TABINDEX = 'ng-vl-index', POSITION = 'position', POSITION_ZERO = '0', ID = 'item-id', KEY_SPACE = " ", KEY_ARR_LEFT = "ArrowLeft", KEY_ARR_UP = "ArrowUp", KEY_ARR_RIGHT = "ArrowRight", KEY_ARR_DOWN = "ArrowDown", EVENT_FOCUS_IN = 'focusin', EVENT_FOCUS_OUT = 'focusout', EVENT_KEY_DOWN = 'keydown';
395
428
  const getElementByIndex = (index) => {
396
429
  return `[${TABINDEX}="${index}"]`;
397
430
  };
@@ -412,7 +445,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
412
445
  _isCollapsed = false;
413
446
  config = signal({});
414
447
  measures = signal(undefined);
415
- focus = signal(false);
448
+ focused = signal(false);
416
449
  part = signal(PART_DEFAULT_ITEM);
417
450
  regular = false;
418
451
  data = signal(undefined);
@@ -478,21 +511,28 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
478
511
  }
479
512
  this._service.collapse(data, collapsed);
480
513
  };
514
+ _focusHandler = () =>
515
+ /**
516
+ * Focus a list item
517
+ */
518
+ (align = FocusAlignments.CENTER) => {
519
+ this.focus(align);
520
+ };
481
521
  constructor() {
482
522
  super();
483
523
  this._id = this._service.generateComponentId();
484
524
  this._elementRef.nativeElement.setAttribute('id', String(this._id));
485
- const $data = toObservable(this.data), $focus = toObservable(this.focus);
486
- $focus.pipe(takeUntilDestroyed(), tap(v => {
525
+ const $data = toObservable(this.data), $focused = toObservable(this.focused);
526
+ $focused.pipe(takeUntilDestroyed(), tap(v => {
487
527
  this._service.areaFocus(v ? this._id : this._service.focusedId === this._id ? null : this._service.focusedId);
488
528
  })).subscribe();
489
529
  fromEvent(this.element, EVENT_FOCUS_IN).pipe(takeUntilDestroyed(), tap(e => {
490
- this.focus.set(true);
530
+ this.focused.set(true);
491
531
  this.updateConfig(this._data);
492
532
  this.updatePartStr(this._data, this._isSelected, this._isCollapsed);
493
533
  })).subscribe(),
494
534
  fromEvent(this.element, EVENT_FOCUS_OUT).pipe(takeUntilDestroyed(), tap(e => {
495
- this.focus.set(false);
535
+ this.focused.set(false);
496
536
  this.updateConfig(this._data);
497
537
  this.updatePartStr(this._data, this._isSelected, this._isCollapsed);
498
538
  })).subscribe(),
@@ -595,23 +635,34 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
595
635
  }
596
636
  }
597
637
  }
638
+ focus(align = FocusAlignments.CENTER) {
639
+ if (this._service.listElement) {
640
+ const tabIndex = this._data?.config?.tabIndex ?? 0;
641
+ let index = tabIndex;
642
+ const el = this._service.listElement.querySelector(getElementByIndex(index));
643
+ if (el) {
644
+ this._service.focus(el, align);
645
+ }
646
+ }
647
+ }
598
648
  updateMeasures(v) {
599
649
  this.measures.set(v?.measures ? { ...v.measures } : undefined);
600
650
  }
601
651
  updateConfig(v) {
602
652
  this.config.set({
603
- ...v?.config || {}, selected: this._isSelected, collapsed: this._isCollapsed, focus: this.focus(),
604
- collapse: this._collapseHandler(v), select: this._selectHandler(v)
653
+ ...v?.config || {}, selected: this._isSelected, collapsed: this._isCollapsed, focused: this.focused(),
654
+ collapse: this._collapseHandler(v), select: this._selectHandler(v), focus: this._focusHandler(),
605
655
  });
606
656
  }
607
657
  update() {
608
658
  const data = this._data, regular = this.regular, length = this._regularLength;
609
659
  if (data) {
660
+ this._elementRef.nativeElement.setAttribute(ID, `${data.id}`);
610
661
  const styles = this._elementRef.nativeElement.style;
611
662
  styles.zIndex = data.config.zIndex;
612
663
  if (data.config.snapped) {
613
- this._elementRef.nativeElement.setAttribute('position', data.config.sticky === 1 ? '0' : `${data.config.isVertical ? data.measures.y : data.measures.x}`);
614
- styles.transform = data.config.sticky === 1 ? ZEROS_TRANSLATE_3D : `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.x}${PX}, ${data.config.isVertical ? data.measures.y : 0}${PX} , 0)`;
664
+ this._elementRef.nativeElement.setAttribute(POSITION, data.config.sticky === 1 ? POSITION_ZERO : `${data.config.isVertical ? data.measures.y : data.measures.x}`);
665
+ styles.transform = data.config.sticky === 1 ? ZEROS_TRANSLATE_3D : `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.x}${PX}, ${data.config.isVertical ? data.measures.y : 0}${PX}, ${POSITION_ZERO})`;
615
666
  ;
616
667
  if (!data.config.isSnappingMethodAdvanced) {
617
668
  styles.position = POSITION_STICKY;
@@ -620,17 +671,20 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
620
671
  else {
621
672
  styles.position = POSITION_ABSOLUTE;
622
673
  if (regular) {
623
- this._elementRef.nativeElement.setAttribute('position', '0');
624
- styles.transform = `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.delta}${PX}, ${data.config.isVertical ? data.measures.delta : 0}${PX} , 0)`;
674
+ this._elementRef.nativeElement.setAttribute(POSITION, POSITION_ZERO);
675
+ styles.transform = `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.delta}${PX}, ${data.config.isVertical ? data.measures.delta : 0}${PX}, ${POSITION_ZERO})`;
625
676
  }
626
677
  else {
627
- this._elementRef.nativeElement.setAttribute('position', `${data.config.isVertical ? data.measures.y : data.measures.x}`);
628
- styles.transform = `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.x}${PX}, ${data.config.isVertical ? data.measures.y : 0}${PX} , 0)`;
678
+ this._elementRef.nativeElement.setAttribute(POSITION, `${data.config.isVertical ? data.measures.y : data.measures.x}`);
679
+ styles.transform = `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.x}${PX}, ${data.config.isVertical ? data.measures.y : 0}${PX}, ${POSITION_ZERO})`;
629
680
  }
630
681
  }
631
682
  styles.height = data.config.isVertical ? data.config.dynamic ? SIZE_AUTO : `${data.measures.height}${PX}` : regular ? length : SIZE_100_PERSENT;
632
683
  styles.width = data.config.isVertical ? regular ? length : SIZE_100_PERSENT : data.config.dynamic ? SIZE_AUTO : `${data.measures.width}${PX}`;
633
684
  }
685
+ else {
686
+ this._elementRef.nativeElement.removeAttribute(ID);
687
+ }
634
688
  this._cdr.markForCheck();
635
689
  }
636
690
  updatePartStr(v, isSelected, isCollapsed) {
@@ -652,7 +706,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
652
706
  if (v ? v.config.new : false) {
653
707
  part += PART_ITEM_NEW;
654
708
  }
655
- if (this.focus()) {
709
+ if (this.focused()) {
656
710
  part += PART_ITEM_FOCUSED;
657
711
  }
658
712
  this.part.set(part);
@@ -699,14 +753,14 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
699
753
  this._service.itemClick(this._data);
700
754
  }
701
755
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgVirtualListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
702
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NgVirtualListItemComponent, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@if (data(); as item) {\r\n <div #listItem [part]=\"part()\" class=\"ngvl-item__container\" [attr.ng-vl-index]=\"item.config.tabIndex || -1\" tabindex=\"0\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut, 'focus': focus()}\" (click)=\"onClickHandler()\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, measures: measures(), config: config()}\" />\r\n }\r\n </div>\r\n}\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;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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
756
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NgVirtualListItemComponent, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@if (data(); as item) {\r\n <div #listItem [part]=\"part()\" class=\"ngvl-item__container\" [attr.ng-vl-index]=\"item.config.tabIndex || -1\" tabindex=\"0\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut, 'focus': focused()}\" (click)=\"onClickHandler()\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, measures: measures(), config: config()}\" />\r\n }\r\n </div>\r\n}\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;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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
703
757
  }
704
758
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgVirtualListItemComponent, decorators: [{
705
759
  type: Component,
706
760
  args: [{ selector: 'ng-virtual-list-item', standalone: false, host: {
707
761
  'class': 'ngvl__item',
708
762
  'role': 'listitem',
709
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (data(); as item) {\r\n <div #listItem [part]=\"part()\" class=\"ngvl-item__container\" [attr.ng-vl-index]=\"item.config.tabIndex || -1\" tabindex=\"0\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut, 'focus': focus()}\" (click)=\"onClickHandler()\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, measures: measures(), config: config()}\" />\r\n }\r\n </div>\r\n}\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;box-sizing:border-box}\n"] }]
763
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (data(); as item) {\r\n <div #listItem [part]=\"part()\" class=\"ngvl-item__container\" [attr.ng-vl-index]=\"item.config.tabIndex || -1\" tabindex=\"0\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut, 'focus': focused()}\" (click)=\"onClickHandler()\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, measures: measures(), config: config()}\" />\r\n }\r\n </div>\r\n}\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;box-sizing:border-box}\n"] }]
710
764
  }], ctorParameters: () => [] });
711
765
 
712
766
  /**
@@ -1244,7 +1298,11 @@ const bufferInterpolation = (currentBufferValue, array, value, extra) => {
1244
1298
  return Math.ceil(buffer / l);
1245
1299
  };
1246
1300
 
1247
- const TRACK_BOX_CHANGE_EVENT_NAME = 'change';
1301
+ var TrackBoxEvents;
1302
+ (function (TrackBoxEvents) {
1303
+ TrackBoxEvents["CHANGE"] = "change";
1304
+ TrackBoxEvents["RESET"] = "reset";
1305
+ })(TrackBoxEvents || (TrackBoxEvents = {}));
1248
1306
  var ItemDisplayMethods;
1249
1307
  (function (ItemDisplayMethods) {
1250
1308
  ItemDisplayMethods[ItemDisplayMethods["CREATE"] = 0] = "CREATE";
@@ -1252,7 +1310,7 @@ var ItemDisplayMethods;
1252
1310
  ItemDisplayMethods[ItemDisplayMethods["DELETE"] = 2] = "DELETE";
1253
1311
  ItemDisplayMethods[ItemDisplayMethods["NOT_CHANGED"] = 3] = "NOT_CHANGED";
1254
1312
  })(ItemDisplayMethods || (ItemDisplayMethods = {}));
1255
- const DEFAULT_BUFFER_EXTREMUM_THRESHOLD = 15, DEFAULT_MAX_BUFFER_SEQUENCE_LENGTH = 30, DEFAULT_RESET_BUFFER_SIZE_TIMEOUT = 10000;
1313
+ const DEFAULT_BUFFER_EXTREMUM_THRESHOLD = 15, DEFAULT_MAX_BUFFER_SEQUENCE_LENGTH = 30, DEFAULT_RESET_BUFFER_SIZE_TIMEOUT = 10000, IS_NEW = 'isNew';
1256
1314
  /**
1257
1315
  * An object that performs tracking, calculations and caching.
1258
1316
  * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/trackBox.ts
@@ -1289,6 +1347,13 @@ class TrackBox extends CacheMap {
1289
1347
  }
1290
1348
  this._isSnappingMethodAdvanced = v;
1291
1349
  }
1350
+ _isLazy = false;
1351
+ set isLazy(v) {
1352
+ if (this._isLazy === v) {
1353
+ return;
1354
+ }
1355
+ this._isLazy = v;
1356
+ }
1292
1357
  /**
1293
1358
  * Set the trackBy property
1294
1359
  */
@@ -1321,7 +1386,7 @@ class TrackBox extends CacheMap {
1321
1386
  get crudDetected() { return this._crudDetected; }
1322
1387
  fireChangeIfNeed() {
1323
1388
  if (this.changesDetected()) {
1324
- this.dispatch(TRACK_BOX_CHANGE_EVENT_NAME, this._version);
1389
+ this.dispatch(TrackBoxEvents.CHANGE, this._version);
1325
1390
  }
1326
1391
  }
1327
1392
  _previousTotalSize = 0;
@@ -1337,7 +1402,7 @@ class TrackBox extends CacheMap {
1337
1402
  _maxBufferSize = this._defaultBufferSize;
1338
1403
  _resetBufferSizeTimeout = DEFAULT_RESET_BUFFER_SIZE_TIMEOUT;
1339
1404
  _resetBufferSizeTimer;
1340
- isInit = true;
1405
+ isReseted = true;
1341
1406
  lifeCircle() {
1342
1407
  this.fireChangeIfNeed();
1343
1408
  this.lifeCircleDo();
@@ -1350,11 +1415,19 @@ class TrackBox extends CacheMap {
1350
1415
  console.warn('Attention! The collection must be immutable.');
1351
1416
  return;
1352
1417
  }
1353
- if (this.isInit && !(!this._previousCollection || this._previousCollection.length === 0)) {
1354
- this.isInit = false;
1418
+ let reseted = this.isReseted;
1419
+ if (reseted) {
1420
+ if (!(!this._previousCollection || this._previousCollection.length === 0)) {
1421
+ reseted = false;
1422
+ }
1423
+ }
1424
+ if (!reseted && (!currentCollection || currentCollection.length === 0)) {
1425
+ reseted = true;
1355
1426
  }
1427
+ this.isReseted = reseted;
1428
+ this.dispatch(TrackBoxEvents.RESET, reseted);
1356
1429
  this.updateCache(this._previousCollection, currentCollection, itemSize);
1357
- this._previousCollection = currentCollection;
1430
+ this._previousCollection = [...(currentCollection || [])];
1358
1431
  }
1359
1432
  /**
1360
1433
  * Update the cache of items from the list
@@ -1577,9 +1650,10 @@ class TrackBox extends CacheMap {
1577
1650
  leftItemsOffset = rightItemsOffset = bufferSize;
1578
1651
  }
1579
1652
  let itemsFromStartToScrollEnd = -1, itemsFromDisplayEndToOffsetEnd = 0, itemsFromStartToDisplayEnd = -1, leftItemLength = 0, rightItemLength = 0, leftItemsWeight = 0, rightItemsWeight = 0, leftHiddenItemsWeight = 0, totalItemsToDisplayEndWeight = 0, leftSizeOfAddedItems = 0, leftSizeOfUpdatedItems = 0, leftSizeOfDeletedItems = 0, itemById = undefined, itemByIdPos = 0, targetDisplayItemIndex = -1, isTargetInOverscroll = false, actualScrollSize = itemByIdPos, totalSize = 0, startIndex, isFromItemIdFound = false, deltaFromStartCreation = 0;
1653
+ let isNew = !this.isReseted && (scrollSize === 0);
1580
1654
  // If the list is dynamic or there are new elements in the collection, then it switches to the long algorithm.
1581
1655
  if (dynamicSize) {
1582
- let y = 0, stickyCollectionItem = undefined, stickyComponentSize = 0, isNew = true;
1656
+ let y = 0, stickyCollectionItem = undefined, stickyComponentSize = 0;
1583
1657
  for (let i = 0, l = collection.length; i < l; i++) {
1584
1658
  const ii = i + 1, collectionItem = collection[i], id = collectionItem.id;
1585
1659
  let componentSize = 0, componentSizeDelta = 0, itemDisplayMethod = ItemDisplayMethods.NOT_CHANGED;
@@ -1587,8 +1661,8 @@ class TrackBox extends CacheMap {
1587
1661
  const bounds = map.get(id) || { width: typicalItemSize, height: typicalItemSize };
1588
1662
  componentSize = bounds[sizeProperty];
1589
1663
  itemDisplayMethod = bounds?.method ?? ItemDisplayMethods.UPDATE;
1590
- const isItemNew = bounds.isNew ?? true;
1591
- if (isNew && (this.isInit || (!isItemNew && i > 0))) {
1664
+ const isItemNew = (bounds)?.[IS_NEW] ?? this._isLazy;
1665
+ if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0].id]?.sticky)) {
1592
1666
  isNew = false;
1593
1667
  }
1594
1668
  switch (itemDisplayMethod) {
@@ -1725,8 +1799,15 @@ class TrackBox extends CacheMap {
1725
1799
  if (map.has(id)) {
1726
1800
  const bounds = map.get(id);
1727
1801
  itemDisplayMethod = bounds?.method ?? ItemDisplayMethods.UPDATE;
1802
+ const isItemNew = (bounds)?.[IS_NEW] ?? this._isLazy;
1803
+ if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0].id]?.sticky)) {
1804
+ isNew = false;
1805
+ }
1728
1806
  if (itemDisplayMethod === ItemDisplayMethods.CREATE) {
1729
- map.set(id, { ...bounds, method: ItemDisplayMethods.NOT_CHANGED });
1807
+ if (isNew) {
1808
+ deltaFromStartCreation += componentSize;
1809
+ }
1810
+ map.set(id, { ...bounds, method: ItemDisplayMethods.NOT_CHANGED, isNew });
1730
1811
  }
1731
1812
  }
1732
1813
  if (deletedItemsMap.hasOwnProperty(i)) {
@@ -1738,7 +1819,9 @@ class TrackBox extends CacheMap {
1738
1819
  if (y < scrollSize - componentSize) {
1739
1820
  switch (itemDisplayMethod) {
1740
1821
  case ItemDisplayMethods.CREATE: {
1741
- leftSizeOfUpdatedItems += componentSize;
1822
+ if (!isNew) {
1823
+ leftSizeOfUpdatedItems += componentSize;
1824
+ }
1742
1825
  break;
1743
1826
  }
1744
1827
  case ItemDisplayMethods.UPDATE: {
@@ -1834,7 +1917,7 @@ class TrackBox extends CacheMap {
1834
1917
  height: isVertical ? size : normalizedItemHeight,
1835
1918
  delta: 0,
1836
1919
  }, config = {
1837
- new: cache.isNew === true,
1920
+ new: (cache)?.[IS_NEW] === true,
1838
1921
  odd: isOdd,
1839
1922
  even: !isOdd,
1840
1923
  isVertical,
@@ -1876,7 +1959,7 @@ class TrackBox extends CacheMap {
1876
1959
  height: h,
1877
1960
  delta: 0,
1878
1961
  }, config = {
1879
- new: cache.isNew === true,
1962
+ new: (cache)?.[IS_NEW] === true,
1880
1963
  odd: isOdd,
1881
1964
  even: !isOdd,
1882
1965
  isVertical,
@@ -1917,7 +2000,7 @@ class TrackBox extends CacheMap {
1917
2000
  height: isVertical ? size : normalizedItemHeight,
1918
2001
  delta: 0,
1919
2002
  }, config = {
1920
- new: cache.isNew === true,
2003
+ new: (cache)?.[IS_NEW] === true,
1921
2004
  odd: isOdd,
1922
2005
  even: !isOdd,
1923
2006
  isVertical,
@@ -2103,7 +2186,21 @@ const copyValueAsReadonly = (source) => {
2103
2186
  return source;
2104
2187
  };
2105
2188
 
2106
- const ROLE_LIST = 'list', ROLE_LIST_BOX = 'listbox';
2189
+ const NORMAL_ALIASES = [CollectionModes.NORMAL, 'normal'], LAZY_ALIASES = [CollectionModes.LAZY, 'lazy'];
2190
+ /**
2191
+ * Determines the axis membership of a virtual list
2192
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/isCollectionMode.ts
2193
+ * @author Evgenii Grebennikov
2194
+ * @email djonnyx@gmail.com
2195
+ */
2196
+ const isCollectionMode = (src, expected) => {
2197
+ if (LAZY_ALIASES.includes(expected)) {
2198
+ return LAZY_ALIASES.includes(src);
2199
+ }
2200
+ return NORMAL_ALIASES.includes(src);
2201
+ };
2202
+
2203
+ const ROLE_LIST = 'list', ROLE_LIST_BOX = 'listbox', ITEM_ID = 'item-id', ITEM_CONTAINER = 'ngvl-item__container';
2107
2204
  const validateScrollIteration = (value) => {
2108
2205
  return Number.isNaN(value) || (value < 0) ? 0 : value > MAX_SCROLL_TO_ITERATIONS ? MAX_SCROLL_TO_ITERATIONS : value;
2109
2206
  }, validateId = (id) => {
@@ -2121,6 +2218,11 @@ const validateScrollIteration = (value) => {
2121
2218
  if (!valid) {
2122
2219
  throw Error('The "iteration" parameter must be of type `number`.');
2123
2220
  }
2221
+ }, validateFocusAlignment = (align) => {
2222
+ const valid = validateString(align) && (align === 'none' || align === 'start' || align === 'center' || align === 'end');
2223
+ if (!valid) {
2224
+ throw Error('The "align" parameter must have the value `none`, `start`, `center` or `end`.');
2225
+ }
2124
2226
  };
2125
2227
  /**
2126
2228
  * Virtual list component.
@@ -2411,6 +2513,20 @@ class NgVirtualListComponent {
2411
2513
  * Determines the direction in which elements are placed. Default value is "vertical".
2412
2514
  */
2413
2515
  direction = input(DEFAULT_DIRECTION, { ...this._directionOptions });
2516
+ _collectionModeOptions = {
2517
+ transform: (v) => {
2518
+ const valid = validateString(v) && (v === 'normal' || v === 'lazy');
2519
+ if (!valid) {
2520
+ console.error('The "direction" parameter must have the value `normal` or `lazy`.');
2521
+ return DEFAULT_COLLECTION_MODE;
2522
+ }
2523
+ return v;
2524
+ },
2525
+ };
2526
+ /**
2527
+ * Determines the action modes for collection elements. Default value is "normal".
2528
+ */
2529
+ collectionMode = input(DEFAULT_COLLECTION_MODE, { ...this._collectionModeOptions });
2414
2530
  _bufferSizeOptions = {
2415
2531
  transform: (v) => {
2416
2532
  const valid = validateInt(v);
@@ -2501,6 +2617,7 @@ class NgVirtualListComponent {
2501
2617
  get isMultiSelecting() { return this._isMultiSelecting; }
2502
2618
  _isSnappingMethodAdvanced = this.getIsSnappingMethodAdvanced();
2503
2619
  get isSnappingMethodAdvanced() { return this._isSnappingMethodAdvanced; }
2620
+ _isLazy = this.getIsLazy();
2504
2621
  _isVertical = this.getIsVertical();
2505
2622
  get orientation() {
2506
2623
  return this._isVertical ? Directions.VERTICAL : Directions.HORIZONTAL;
@@ -2570,12 +2687,33 @@ class NgVirtualListComponent {
2570
2687
  this._scrollSize.set(actualScrollSize);
2571
2688
  }
2572
2689
  };
2573
- itemToFocus = (element, position) => {
2690
+ itemToFocus = (element, position, align = FocusAlignments.CENTER) => {
2574
2691
  const container = this._container()?.nativeElement;
2575
2692
  if (container) {
2576
- const { width, height } = this._bounds(), { width: elementWidth, height: elementHeight } = element.getBoundingClientRect(), isVertical = this._isVertical, pos = isVertical ? position - (height - elementHeight) * .5 : position - (width - elementWidth) * .5;
2577
- const params = { [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: pos, behavior: 'instant' };
2578
- container.scrollTo(params);
2693
+ const { width, height } = this._bounds(), { width: elementWidth, height: elementHeight } = element.getBoundingClientRect(), isVertical = this._isVertical;
2694
+ let pos = Number.NaN;
2695
+ switch (align) {
2696
+ case FocusAlignments.START: {
2697
+ pos = isVertical ? position : position;
2698
+ break;
2699
+ }
2700
+ case FocusAlignments.CENTER: {
2701
+ pos = isVertical ? position - (height - elementHeight) * .5 : position - (width - elementWidth) * .5;
2702
+ break;
2703
+ }
2704
+ case FocusAlignments.END: {
2705
+ pos = isVertical ? position - (height - elementHeight) : position - (width - elementWidth);
2706
+ break;
2707
+ }
2708
+ case FocusAlignments.NONE:
2709
+ default: {
2710
+ break;
2711
+ }
2712
+ }
2713
+ if (!Number.isNaN(pos)) {
2714
+ const params = { [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: pos, behavior: 'instant' };
2715
+ container.scrollTo(params);
2716
+ }
2579
2717
  }
2580
2718
  };
2581
2719
  _elementRef = inject((ElementRef));
@@ -2597,10 +2735,25 @@ class NgVirtualListComponent {
2597
2735
  this._cacheVersion.set(v);
2598
2736
  };
2599
2737
  _cacheVersion = signal(-1);
2738
+ _isResetedReachStart = true;
2739
+ _onTrackBoxResetHandler = (v) => {
2740
+ if (v) {
2741
+ this._isResetedReachStart = true;
2742
+ const container = this._container()?.nativeElement;
2743
+ if (container) {
2744
+ const params = {
2745
+ [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: 0,
2746
+ behavior: BEHAVIOR_INSTANT,
2747
+ };
2748
+ container.scrollTo(params);
2749
+ }
2750
+ }
2751
+ };
2600
2752
  constructor() {
2601
2753
  NgVirtualListComponent.__nextId = NgVirtualListComponent.__nextId + 1 === Number.MAX_SAFE_INTEGER
2602
2754
  ? 0 : NgVirtualListComponent.__nextId + 1;
2603
2755
  this._id = NgVirtualListComponent.__nextId;
2756
+ this._trackBox.addEventListener(TrackBoxEvents.RESET, this._onTrackBoxResetHandler);
2604
2757
  this._service.initialize(this._trackBox);
2605
2758
  this._service.itemToFocus = this.itemToFocus;
2606
2759
  this._initialized = signal(false);
@@ -2613,12 +2766,13 @@ class NgVirtualListComponent {
2613
2766
  this._service.listElement = v.nativeElement;
2614
2767
  })).subscribe();
2615
2768
  const $trackBy = toObservable(this.trackBy), $selectByClick = toObservable(this.selectByClick), $collapseByClick = toObservable(this.collapseByClick), $isScrollStart = toObservable(this._isScrollStart), $isScrollFinished = toObservable(this._isScrollFinished);
2616
- $isScrollStart.pipe(takeUntilDestroyed(), distinctUntilChanged(), skip(1), tap(v => {
2617
- if (v) {
2769
+ $isScrollStart.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
2770
+ if (v && !this._isResetedReachStart) {
2618
2771
  this.onScrollReachStart.emit();
2619
2772
  }
2773
+ this._isResetedReachStart = false;
2620
2774
  })).subscribe();
2621
- $isScrollFinished.pipe(takeUntilDestroyed(), distinctUntilChanged(), skip(1), tap(v => {
2775
+ $isScrollFinished.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
2622
2776
  if (v) {
2623
2777
  this.onScrollReachEnd.emit();
2624
2778
  }
@@ -2632,7 +2786,10 @@ class NgVirtualListComponent {
2632
2786
  $trackBy.pipe(takeUntilDestroyed(), tap(v => {
2633
2787
  this._trackBox.trackingPropertyName = v;
2634
2788
  })).subscribe();
2635
- const $bounds = toObservable(this._bounds).pipe(filter(b => !!b)), $items = toObservable(this.items).pipe(map(i => !i ? [] : i)), $scrollSize = toObservable(this._scrollSize), $itemSize = toObservable(this.itemSize).pipe(map(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $bufferSize = toObservable(this.bufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $maxBufferSize = toObservable(this.maxBufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $itemConfigMap = toObservable(this.itemConfigMap).pipe(map(v => !v ? {} : v)), $snap = toObservable(this.snap), $isVertical = toObservable(this.direction).pipe(map(v => this.getIsVertical(v || DEFAULT_DIRECTION))), $dynamicSize = toObservable(this.dynamicSize), $enabledBufferOptimization = toObservable(this.enabledBufferOptimization), $snappingMethod = toObservable(this.snappingMethod).pipe(map(v => this.getIsSnappingMethodAdvanced(v || DEFAULT_SNAPPING_METHOD))), $methodForSelecting = toObservable(this.methodForSelecting), $selectedIds = toObservable(this.selectedIds), $collapsedIds = toObservable(this.collapsedIds).pipe(map(v => Array.isArray(v) ? v : [])), $collapsedItemIds = toObservable(this._collapsedItemIds).pipe(map(v => Array.isArray(v) ? v : [])), $actualItems = toObservable(this._actualItems), $cacheVersion = toObservable(this._cacheVersion);
2789
+ const $bounds = toObservable(this._bounds).pipe(filter(b => !!b)), $items = toObservable(this.items).pipe(map(i => !i ? [] : i)), $scrollSize = toObservable(this._scrollSize), $itemSize = toObservable(this.itemSize).pipe(map(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $bufferSize = toObservable(this.bufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $maxBufferSize = toObservable(this.maxBufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $itemConfigMap = toObservable(this.itemConfigMap).pipe(map(v => !v ? {} : v)), $snap = toObservable(this.snap), $isVertical = toObservable(this.direction).pipe(map(v => this.getIsVertical(v || DEFAULT_DIRECTION))), $isLazy = toObservable(this.collectionMode).pipe(map(v => this.getIsLazy(v || DEFAULT_COLLECTION_MODE))), $dynamicSize = toObservable(this.dynamicSize), $enabledBufferOptimization = toObservable(this.enabledBufferOptimization), $snappingMethod = toObservable(this.snappingMethod).pipe(map(v => this.getIsSnappingMethodAdvanced(v || DEFAULT_SNAPPING_METHOD))), $methodForSelecting = toObservable(this.methodForSelecting), $selectedIds = toObservable(this.selectedIds), $collapsedIds = toObservable(this.collapsedIds).pipe(map(v => Array.isArray(v) ? v : [])), $collapsedItemIds = toObservable(this._collapsedItemIds).pipe(map(v => Array.isArray(v) ? v : [])), $actualItems = toObservable(this._actualItems), $cacheVersion = toObservable(this._cacheVersion);
2790
+ $isLazy.pipe(takeUntilDestroyed(), tap(v => {
2791
+ this._trackBox.isLazy = v;
2792
+ })).subscribe();
2636
2793
  combineLatest([$items, $itemSize]).pipe(takeUntilDestroyed(), map(([items, itemSize]) => ({ items, itemSize })), tap(({ items, itemSize }) => {
2637
2794
  this._trackBox.resetCollection(items, itemSize);
2638
2795
  })).subscribe();
@@ -2710,9 +2867,11 @@ class NgVirtualListComponent {
2710
2867
  this.resetBoundsSize(isVertical, totalSize);
2711
2868
  this.createDisplayComponentsIfNeed(displayItems);
2712
2869
  this.tracking();
2713
- const scrollLength = (this._isVertical ? this._container()?.nativeElement.scrollHeight ?? 0 : this._container()?.nativeElement.scrollWidth) ?? 0, actualScrollLength = scrollLength === 0 ? 0 : scrollLength - (this._isVertical ? height : width), scrollPosition = actualScrollSize + this._trackBox.delta;
2714
- this._isScrollStart.set(scrollPosition === 0);
2715
- this._isScrollFinished.set(scrollPosition === actualScrollLength);
2870
+ const scrollLength = (this._isVertical ? this._container()?.nativeElement.scrollHeight ?? 0 : this._container()?.nativeElement.scrollWidth) ?? 0, actualScrollLength = scrollLength === 0 ? 0 : Math.round(scrollLength - (this._isVertical ? height : width)), scrollPosition = actualScrollSize + this._trackBox.delta;
2871
+ if (actualScrollLength > 0) {
2872
+ this._isScrollStart.set(scrollPosition === 0);
2873
+ this._isScrollFinished.set(scrollPosition === actualScrollLength);
2874
+ }
2716
2875
  if (this._isSnappingMethodAdvanced) {
2717
2876
  this.updateRegularRenderer();
2718
2877
  }
@@ -2781,13 +2940,13 @@ class NgVirtualListComponent {
2781
2940
  }
2782
2941
  listenCacheChangesIfNeed(value) {
2783
2942
  if (value) {
2784
- if (!this._trackBox.hasEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler)) {
2785
- this._trackBox.addEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler);
2943
+ if (!this._trackBox.hasEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler)) {
2944
+ this._trackBox.addEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler);
2786
2945
  }
2787
2946
  }
2788
2947
  else {
2789
- if (this._trackBox.hasEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler)) {
2790
- this._trackBox.removeEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler);
2948
+ if (this._trackBox.hasEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler)) {
2949
+ this._trackBox.removeEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler);
2791
2950
  }
2792
2951
  }
2793
2952
  }
@@ -2811,6 +2970,10 @@ class NgVirtualListComponent {
2811
2970
  const dir = d || this.direction();
2812
2971
  return isDirection(dir, Directions.VERTICAL);
2813
2972
  }
2973
+ getIsLazy(m) {
2974
+ const mode = m || this.collectionMode();
2975
+ return isCollectionMode(mode, CollectionModes.LAZY);
2976
+ }
2814
2977
  createDisplayComponentsIfNeed(displayItems) {
2815
2978
  if (!displayItems || !this._listContainerRef) {
2816
2979
  this._trackBox.setDisplayObjectIndexMapById({});
@@ -2876,6 +3039,20 @@ class NgVirtualListComponent {
2876
3039
  validateId(id);
2877
3040
  return this._trackBox.getItemBounds(id);
2878
3041
  }
3042
+ /**
3043
+ * Focus an list item by a given id.
3044
+ */
3045
+ focus(id, align = FocusAlignments.NONE) {
3046
+ validateId(id);
3047
+ validateFocusAlignment(align);
3048
+ const el = this._list()?.nativeElement.querySelector(`[${ITEM_ID}="${id}"]`);
3049
+ if (el) {
3050
+ const focusedEl = el.querySelector(`.${ITEM_CONTAINER}`);
3051
+ if (focusedEl) {
3052
+ this._service.focus(focusedEl, align);
3053
+ }
3054
+ }
3055
+ }
2879
3056
  /**
2880
3057
  * The method scrolls the list to the element with the given id and returns the value of the scrolled area.
2881
3058
  * Behavior accepts the values ​​"auto", "instant" and "smooth".
@@ -3037,7 +3214,7 @@ class NgVirtualListComponent {
3037
3214
  }
3038
3215
  }
3039
3216
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgVirtualListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3040
- 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 }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, collapsedIds: { classPropertyName: "collapsedIds", publicName: "collapsedIds", isSignal: true, isRequired: false, transformFunction: null }, selectByClick: { classPropertyName: "selectByClick", publicName: "selectByClick", isSignal: true, isRequired: false, transformFunction: null }, collapseByClick: { classPropertyName: "collapseByClick", publicName: "collapseByClick", isSignal: true, isRequired: false, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null }, enabledBufferOptimization: { classPropertyName: "enabledBufferOptimization", publicName: "enabledBufferOptimization", isSignal: true, isRequired: false, transformFunction: null }, itemRenderer: { classPropertyName: "itemRenderer", publicName: "itemRenderer", isSignal: true, isRequired: true, transformFunction: null }, itemConfigMap: { classPropertyName: "itemConfigMap", publicName: "itemConfigMap", isSignal: true, isRequired: false, transformFunction: null }, itemSize: { classPropertyName: "itemSize", publicName: "itemSize", isSignal: true, isRequired: false, transformFunction: null }, dynamicSize: { classPropertyName: "dynamicSize", publicName: "dynamicSize", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, maxBufferSize: { classPropertyName: "maxBufferSize", publicName: "maxBufferSize", isSignal: true, isRequired: false, transformFunction: null }, snappingMethod: { classPropertyName: "snappingMethod", publicName: "snappingMethod", isSignal: true, isRequired: false, transformFunction: null }, methodForSelecting: { classPropertyName: "methodForSelecting", publicName: "methodForSelecting", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onScroll: "onScroll", onScrollEnd: "onScrollEnd", onViewportChange: "onViewportChange", onItemClick: "onItemClick", onSelect: "onSelect", onCollapse: "onCollapse", onScrollReachStart: "onScrollReachStart", onScrollReachEnd: "onScrollReachEnd" }, host: { styleAttribute: "position: relative;" }, providers: [NgVirtualListService], viewQueries: [{ propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, isSignal: true }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "@if (snap()) {\r\n <div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n </div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" [attr.aria-activedescendant]=\"focusedElement()\" #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </div>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
3217
+ 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 }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, collapsedIds: { classPropertyName: "collapsedIds", publicName: "collapsedIds", isSignal: true, isRequired: false, transformFunction: null }, selectByClick: { classPropertyName: "selectByClick", publicName: "selectByClick", isSignal: true, isRequired: false, transformFunction: null }, collapseByClick: { classPropertyName: "collapseByClick", publicName: "collapseByClick", isSignal: true, isRequired: false, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null }, enabledBufferOptimization: { classPropertyName: "enabledBufferOptimization", publicName: "enabledBufferOptimization", isSignal: true, isRequired: false, transformFunction: null }, itemRenderer: { classPropertyName: "itemRenderer", publicName: "itemRenderer", isSignal: true, isRequired: true, transformFunction: null }, itemConfigMap: { classPropertyName: "itemConfigMap", publicName: "itemConfigMap", isSignal: true, isRequired: false, transformFunction: null }, itemSize: { classPropertyName: "itemSize", publicName: "itemSize", isSignal: true, isRequired: false, transformFunction: null }, dynamicSize: { classPropertyName: "dynamicSize", publicName: "dynamicSize", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, collectionMode: { classPropertyName: "collectionMode", publicName: "collectionMode", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, maxBufferSize: { classPropertyName: "maxBufferSize", publicName: "maxBufferSize", isSignal: true, isRequired: false, transformFunction: null }, snappingMethod: { classPropertyName: "snappingMethod", publicName: "snappingMethod", isSignal: true, isRequired: false, transformFunction: null }, methodForSelecting: { classPropertyName: "methodForSelecting", publicName: "methodForSelecting", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onScroll: "onScroll", onScrollEnd: "onScrollEnd", onViewportChange: "onViewportChange", onItemClick: "onItemClick", onSelect: "onSelect", onCollapse: "onCollapse", onScrollReachStart: "onScrollReachStart", onScrollReachEnd: "onScrollReachEnd" }, host: { styleAttribute: "position: relative;" }, providers: [NgVirtualListService], viewQueries: [{ propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, isSignal: true }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "@if (snap()) {\r\n <div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n </div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" [attr.aria-activedescendant]=\"focusedElement()\" #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </div>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
3041
3218
  }
3042
3219
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgVirtualListComponent, decorators: [{
3043
3220
  type: Component,
@@ -3075,5 +3252,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3075
3252
  * Generated bundle index. Do not edit.
3076
3253
  */
3077
3254
 
3078
- export { Directions, MethodsForSelecting, NgVirtualListComponent, NgVirtualListItemComponent, NgVirtualListModule, ScrollEvent, SnappingMethods, debounce, toggleClassName };
3255
+ export { CollectionModes, Directions, FocusAlignments, MethodsForSelecting, NgVirtualListComponent, NgVirtualListItemComponent, NgVirtualListModule, ScrollEvent, SnappingMethods, debounce, toggleClassName };
3079
3256
  //# sourceMappingURL=ng-virtual-list.mjs.map