ng-virtual-list 20.7.9 → 20.7.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -599,7 +599,7 @@ Inputs
599
599
  | items | [IVirtualListCollection](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/models/collection.model.ts) | Collection of list items. The collection of elements must be immutable. |
600
600
  | itemSize | number? = 24 | If direction = 'vertical', then the height of a typical element. If direction = 'horizontal', then the width of a typical element. Ignored if the dynamicSize property is true. |
601
601
  | bufferSize | number? = 2 | Number of elements outside the scope of visibility. Default value is 2. |
602
- | maxBufferSize | number? = 100 | Maximum number of elements outside the scope of visibility. Default value is 100. If maxBufferSize is set to be greater than bufferSize, then adaptive buffer mode is enabled. The greater the scroll size, the more elements are allocated for rendering. |
602
+ | maxBufferSize | number? = 10 | Maximum number of elements outside the scope of visibility. Default value is 10. If maxBufferSize is set to be greater than bufferSize, then adaptive buffer mode is enabled. The greater the scroll size, the more elements are allocated for rendering. |
603
603
  | itemRenderer | TemplateRef | Rendering element template. |
604
604
  | methodForSelecting | [MethodForSelecting](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/enums/method-for-selecting.ts) | Method for selecting list items. Default value is 'none'. 'select' - List items are selected one by one. 'multi-select' - Multiple selection of list items. 'none' - List items are not selectable. |
605
605
  | itemConfigMap | [IVirtualListItemConfigMap?](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/models/item-config-map.model.ts) | Sets `sticky` position and `selectable` for the list item element. If `sticky` position is greater than `0`, then `sticky` position is applied. If the `sticky` value is greater than `0`, then the `sticky` position mode is enabled for the element. `1` - position start, `2` - position end. Default value is `0`. `selectable` determines whether an element can be selected or not. Default value is `true`. |
@@ -644,12 +644,12 @@ Methods
644
644
 
645
645
  | Angular version | ng-virtual-list version | git | npm |
646
646
  |--|--|--|--|
647
- | 19.x | 19.7.11 | [19.x](https://github.com/DjonnyX/ng-virtual-list/tree/19.x) | [19.7.11](https://www.npmjs.com/package/ng-virtual-list/v/19.7.11) |
648
- | 18.x | 18.7.9 | [18.x](https://github.com/DjonnyX/ng-virtual-list/tree/18.x) | [18.7.9](https://www.npmjs.com/package/ng-virtual-list/v/18.7.9) |
649
- | 17.x | 17.7.9 | [17.x](https://github.com/DjonnyX/ng-virtual-list/tree/17.x) | [17.7.9](https://www.npmjs.com/package/ng-virtual-list/v/17.7.9) |
650
- | 16.x | 16.7.8 | [16.x](https://github.com/DjonnyX/ng-virtual-list/tree/16.x) | [16.7.8](https://www.npmjs.com/package/ng-virtual-list/v/16.7.8) |
651
- | 15.x | 15.7.8 | [15.x](https://github.com/DjonnyX/ng-virtual-list/tree/15.x) | [15.7.8](https://www.npmjs.com/package/ng-virtual-list/v/15.7.8) |
652
- | 14.x | 14.7.8 | [14.x](https://github.com/DjonnyX/ng-virtual-list/tree/14.x) | [14.7.8](https://www.npmjs.com/package/ng-virtual-list/v/14.7.8) |
647
+ | 19.x | 19.7.14 | [19.x](https://github.com/DjonnyX/ng-virtual-list/tree/19.x) | [19.7.14](https://www.npmjs.com/package/ng-virtual-list/v/19.7.14) |
648
+ | 18.x | 18.7.10 | [18.x](https://github.com/DjonnyX/ng-virtual-list/tree/18.x) | [18.7.10](https://www.npmjs.com/package/ng-virtual-list/v/18.7.10) |
649
+ | 17.x | 17.7.11 | [17.x](https://github.com/DjonnyX/ng-virtual-list/tree/17.x) | [17.7.11](https://www.npmjs.com/package/ng-virtual-list/v/17.7.11) |
650
+ | 16.x | 16.7.9 | [16.x](https://github.com/DjonnyX/ng-virtual-list/tree/16.x) | [16.7.9](https://www.npmjs.com/package/ng-virtual-list/v/16.7.9) |
651
+ | 15.x | 15.7.9 | [15.x](https://github.com/DjonnyX/ng-virtual-list/tree/15.x) | [15.7.9](https://www.npmjs.com/package/ng-virtual-list/v/15.7.9) |
652
+ | 14.x | 14.7.9 | [14.x](https://github.com/DjonnyX/ng-virtual-list/tree/14.x) | [14.7.9](https://www.npmjs.com/package/ng-virtual-list/v/14.7.9) |
653
653
 
654
654
  <br/>
655
655
 
@@ -66,7 +66,7 @@ var SnappingMethods;
66
66
 
67
67
  const DEFAULT_ITEM_SIZE = 24;
68
68
  const DEFAULT_BUFFER_SIZE = 2;
69
- const DEFAULT_MAX_BUFFER_SIZE = 100;
69
+ const DEFAULT_MAX_BUFFER_SIZE = 10;
70
70
  const DEFAULT_LIST_SIZE = 400;
71
71
  const DEFAULT_SNAP = false;
72
72
  const DEFAULT_SELECT_BY_CLICK = true;
@@ -161,10 +161,14 @@ class NgVirtualListService {
161
161
  set methodOfSelecting(v) {
162
162
  this._$methodOfSelecting.next(v);
163
163
  }
164
+ _$focusedId = new BehaviorSubject(null);
165
+ $focusedId = this._$focusedId.asObservable();
166
+ get focusedId() { return this._$focusedId.getValue(); }
164
167
  selectByClick = DEFAULT_SELECT_BY_CLICK;
165
168
  collapseByClick = DEFAULT_COLLAPSE_BY_CLICK;
166
169
  _trackBox;
167
170
  listElement = null;
171
+ collection = [];
168
172
  constructor() {
169
173
  this._$methodOfSelecting.pipe(takeUntilDestroyed(), tap(v => {
170
174
  switch (v) {
@@ -208,6 +212,9 @@ class NgVirtualListService {
208
212
  this.select(data);
209
213
  }
210
214
  }
215
+ update() {
216
+ this._trackBox?.changes();
217
+ }
211
218
  /**
212
219
  * Selects a list item
213
220
  * @param data
@@ -299,6 +306,17 @@ class NgVirtualListService {
299
306
  }
300
307
  }
301
308
  }
309
+ itemToFocus;
310
+ focus(element) {
311
+ element.focus({ preventScroll: true });
312
+ if (element.parentElement) {
313
+ const pos = parseFloat(element.parentElement?.getAttribute('position') ?? '0');
314
+ this.itemToFocus?.(element, pos);
315
+ }
316
+ }
317
+ areaFocus(id) {
318
+ this._$focusedId.next(id);
319
+ }
302
320
  initialize(trackBox) {
303
321
  this._trackBox = trackBox;
304
322
  }
@@ -316,7 +334,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
316
334
  }]
317
335
  }], ctorParameters: () => [] });
318
336
 
319
- const ATTR_AREA_SELECTED = 'area-selected', TABINDEX = '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';
337
+ 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';
338
+ const getElementByIndex = (index) => {
339
+ return `[${TABINDEX}="${index}"]`;
340
+ };
320
341
  /**
321
342
  * Virtual list item component
322
343
  * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/components/ng-virtual-list-item.component.ts
@@ -390,7 +411,11 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
390
411
  constructor() {
391
412
  super();
392
413
  this._id = this._service.generateComponentId();
393
- const $data = toObservable(this.data);
414
+ this._elementRef.nativeElement.setAttribute('id', String(this._id));
415
+ const $data = toObservable(this.data), $focus = toObservable(this.focus);
416
+ $focus.pipe(takeUntilDestroyed(), tap(v => {
417
+ this._service.areaFocus(v ? this._id : this._service.focusedId === this._id ? null : this._service.focusedId);
418
+ })).subscribe();
394
419
  fromEvent(this.element, EVENT_FOCUS_IN).pipe(takeUntilDestroyed(), tap(e => {
395
420
  this.focus.set(true);
396
421
  this.updateConfig(this._data);
@@ -473,20 +498,30 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
473
498
  })).subscribe();
474
499
  }
475
500
  focusNext() {
476
- const tabIndex = this.config()?.tabIndex ?? 0;
477
- if (this._service.listElement && tabIndex > 0) {
478
- const el = this._service.listElement.querySelector(`[${TABINDEX}="${tabIndex + 1}"]`);
479
- if (el) {
480
- el.focus();
501
+ if (this._service.listElement) {
502
+ const tabIndex = this._data?.config?.tabIndex ?? 0, length = this._service.collection?.length ?? 0;
503
+ let index = tabIndex;
504
+ while (index <= length) {
505
+ index++;
506
+ const el = this._service.listElement.querySelector(getElementByIndex(index));
507
+ if (el) {
508
+ this._service.focus(el);
509
+ break;
510
+ }
481
511
  }
482
512
  }
483
513
  }
484
514
  focusPrev() {
485
- const tabIndex = this.config()?.tabIndex ?? 0;
486
- if (this._service.listElement && tabIndex > 1) {
487
- const el = this._service.listElement.querySelector(`[${TABINDEX}="${tabIndex - 1}"]`);
488
- if (el) {
489
- el.focus();
515
+ if (this._service.listElement) {
516
+ const tabIndex = this._data?.config?.tabIndex ?? 0;
517
+ let index = tabIndex;
518
+ while (index >= 0) {
519
+ index--;
520
+ const el = this._service.listElement.querySelector(getElementByIndex(index));
521
+ if (el) {
522
+ this._service.focus(el);
523
+ break;
524
+ }
490
525
  }
491
526
  }
492
527
  }
@@ -505,6 +540,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
505
540
  const styles = this._elementRef.nativeElement.style;
506
541
  styles.zIndex = data.config.zIndex;
507
542
  if (data.config.snapped) {
543
+ this._elementRef.nativeElement.setAttribute('position', data.config.sticky === 1 ? '0' : `${data.config.isVertical ? data.measures.y : data.measures.x}`);
508
544
  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)`;
509
545
  ;
510
546
  if (!data.config.isSnappingMethodAdvanced) {
@@ -514,9 +550,11 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
514
550
  else {
515
551
  styles.position = POSITION_ABSOLUTE;
516
552
  if (regular) {
553
+ this._elementRef.nativeElement.setAttribute('position', '0');
517
554
  styles.transform = `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.delta}${PX}, ${data.config.isVertical ? data.measures.delta : 0}${PX} , 0)`;
518
555
  }
519
556
  else {
557
+ this._elementRef.nativeElement.setAttribute('position', `${data.config.isVertical ? data.measures.y : data.measures.x}`);
520
558
  styles.transform = `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.x}${PX}, ${data.config.isVertical ? data.measures.y : 0}${PX} , 0)`;
521
559
  }
522
560
  }
@@ -587,14 +625,14 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
587
625
  this._service.itemClick(this._data);
588
626
  }
589
627
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgVirtualListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
590
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: NgVirtualListItemComponent, isStandalone: true, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@let item = data();\r\n@let _config = config();\r\n@let _part = part();\r\n@let _measures = measures();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n <div #listItem [part]=\"_part\" [attr.index]=\"item.config.tabIndex\" tabindex=\"0\" class=\"ngvl-item__container\"\r\n [ngClass]=\"{'snapped': item.config.snapped, 'snapped-out': item.config.snappedOut, 'focus': focus()}\" (click)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data, measures: _measures, config: _config}\" />\r\n }\r\n </div>\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: "ngmodule", type: CommonModule }, { 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 });
628
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: NgVirtualListItemComponent, isStandalone: true, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@let item = data();\r\n@let _config = config();\r\n@let _part = part();\r\n@let _measures = measures();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n <div #listItem [part]=\"_part\" [attr.ng-vl-index]=\"_config.tabIndex || -1\" tabindex=\"0\" class=\"ngvl-item__container\"\r\n [ngClass]=\"{'snapped': item.config.snapped, 'snapped-out': item.config.snappedOut, 'focus': focus()}\" (click)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data, measures: _measures, config: _config}\" />\r\n }\r\n </div>\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: "ngmodule", type: CommonModule }, { 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 });
591
629
  }
592
630
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgVirtualListItemComponent, decorators: [{
593
631
  type: Component,
594
632
  args: [{ selector: 'ng-virtual-list-item', imports: [CommonModule], host: {
595
633
  'class': 'ngvl__item',
596
634
  'role': 'listitem',
597
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let item = data();\r\n@let _config = config();\r\n@let _part = part();\r\n@let _measures = measures();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n <div #listItem [part]=\"_part\" [attr.index]=\"item.config.tabIndex\" tabindex=\"0\" class=\"ngvl-item__container\"\r\n [ngClass]=\"{'snapped': item.config.snapped, 'snapped-out': item.config.snappedOut, 'focus': focus()}\" (click)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data, measures: _measures, config: _config}\" />\r\n }\r\n </div>\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"] }]
635
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let item = data();\r\n@let _config = config();\r\n@let _part = part();\r\n@let _measures = measures();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n <div #listItem [part]=\"_part\" [attr.ng-vl-index]=\"_config.tabIndex || -1\" tabindex=\"0\" class=\"ngvl-item__container\"\r\n [ngClass]=\"{'snapped': item.config.snapped, 'snapped-out': item.config.snappedOut, 'focus': focus()}\" (click)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data, measures: _measures, config: _config}\" />\r\n }\r\n </div>\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"] }]
598
636
  }], ctorParameters: () => [] });
599
637
 
600
638
  /**
@@ -1017,22 +1055,26 @@ class Tracker {
1017
1055
  snapedComponent.instance.show();
1018
1056
  }
1019
1057
  }
1020
- comp.instance.item = item;
1021
1058
  if (snapedComponent) {
1022
1059
  if (item['config']['snapped'] || item['config']['snappedOut']) {
1060
+ comp.instance.item = null;
1023
1061
  comp.instance.hide();
1024
1062
  }
1025
1063
  else {
1064
+ comp.instance.item = item;
1026
1065
  comp.instance.show();
1027
1066
  }
1028
1067
  }
1029
1068
  else {
1069
+ comp.instance.item = item;
1030
1070
  comp.instance.show();
1031
1071
  }
1032
1072
  untrackedItems.splice(indexByUntrackedItems, 1);
1033
1073
  continue;
1034
1074
  }
1035
1075
  }
1076
+ }
1077
+ else {
1036
1078
  this._trackMap.delete(itemTrackingProperty);
1037
1079
  }
1038
1080
  }
@@ -1041,9 +1083,8 @@ class Tracker {
1041
1083
  }
1042
1084
  }
1043
1085
  for (let i = 0, l = newTrackItems.length; i < l; i++) {
1044
- const item = newTrackItems[i], itemTrackingProperty = item[idPropName];
1045
1086
  if (untrackedItems.length > 0) {
1046
- const comp = untrackedItems.shift(), item = items[i];
1087
+ const comp = untrackedItems.shift(), item = newTrackItems[i], itemTrackingProperty = item[idPropName];
1047
1088
  if (comp) {
1048
1089
  if (snapedComponent) {
1049
1090
  if (item['config']['snapped'] || item['config']['snappedOut']) {
@@ -1052,16 +1093,18 @@ class Tracker {
1052
1093
  snapedComponent.instance.show();
1053
1094
  }
1054
1095
  }
1055
- comp.instance.item = item;
1056
1096
  if (snapedComponent) {
1057
1097
  if (item['config']['snapped'] || item['config']['snappedOut']) {
1098
+ comp.instance.item = null;
1058
1099
  comp.instance.hide();
1059
1100
  }
1060
1101
  else {
1102
+ comp.instance.item = item;
1061
1103
  comp.instance.show();
1062
1104
  }
1063
1105
  }
1064
1106
  else {
1107
+ comp.instance.item = item;
1065
1108
  comp.instance.show();
1066
1109
  }
1067
1110
  if (this._trackMap) {
@@ -1073,6 +1116,7 @@ class Tracker {
1073
1116
  if (untrackedItems.length) {
1074
1117
  for (let i = 0, l = untrackedItems.length; i < l; i++) {
1075
1118
  const comp = untrackedItems[i];
1119
+ comp.instance.item = null;
1076
1120
  comp.instance.hide();
1077
1121
  }
1078
1122
  }
@@ -1757,7 +1801,7 @@ class TrackBox extends CacheMap {
1757
1801
  snappedOut: false,
1758
1802
  dynamic: dynamicSize,
1759
1803
  isSnappingMethodAdvanced,
1760
- tabIndex: count,
1804
+ tabIndex: items.length,
1761
1805
  zIndex: '1',
1762
1806
  };
1763
1807
  const itemData = items[i];
@@ -1765,7 +1809,6 @@ class TrackBox extends CacheMap {
1765
1809
  endStickyItemIndex = i;
1766
1810
  endStickyItemSize = size;
1767
1811
  displayItems.push(endStickyItem);
1768
- count++;
1769
1812
  break;
1770
1813
  }
1771
1814
  }
@@ -1801,6 +1844,7 @@ class TrackBox extends CacheMap {
1801
1844
  tabIndex: count,
1802
1845
  zIndex: '0',
1803
1846
  };
1847
+ count++;
1804
1848
  if (snapped) {
1805
1849
  config.zIndex = '2';
1806
1850
  }
@@ -1823,7 +1867,6 @@ class TrackBox extends CacheMap {
1823
1867
  nextEndSticky.measures.delta = isVertical ? (item.measures.y - scrollSize) : (item.measures.x - scrollSize);
1824
1868
  }
1825
1869
  displayItems.push(item);
1826
- count++;
1827
1870
  }
1828
1871
  renderItems -= 1;
1829
1872
  pos += size;
@@ -2116,6 +2159,7 @@ class NgVirtualListComponent {
2116
2159
  get orientation() {
2117
2160
  return this._isVertical ? Directions.VERTICAL : Directions.HORIZONTAL;
2118
2161
  }
2162
+ focusedElement = signal(undefined);
2119
2163
  _actualItems = signal([]);
2120
2164
  _collapsedItemIds = signal([]);
2121
2165
  _displayComponents = [];
@@ -2178,6 +2222,14 @@ class NgVirtualListComponent {
2178
2222
  this._scrollSize.set(actualScrollSize);
2179
2223
  }
2180
2224
  };
2225
+ itemToFocus = (element, position) => {
2226
+ const container = this._container()?.nativeElement;
2227
+ if (container) {
2228
+ const { width, height } = this._bounds(), { width: elementWidth, height: elementHeight } = element.getBoundingClientRect(), isVertical = this._isVertical, pos = isVertical ? position - (height - elementHeight) * .5 : position - (width - elementWidth) * .5;
2229
+ const params = { [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: pos, behavior: 'instant' };
2230
+ container.scrollTo(params);
2231
+ }
2232
+ };
2181
2233
  _elementRef = inject((ElementRef));
2182
2234
  _initialized;
2183
2235
  $initialized;
@@ -2206,9 +2258,13 @@ class NgVirtualListComponent {
2206
2258
  ? 0 : NgVirtualListComponent.__nextId + 1;
2207
2259
  this._id = NgVirtualListComponent.__nextId;
2208
2260
  this._service.initialize(this._trackBox);
2261
+ this._service.itemToFocus = this.itemToFocus;
2209
2262
  this._initialized = signal(false);
2210
2263
  this.$initialized = toObservable(this._initialized);
2211
2264
  this._trackBox.displayComponents = this._displayComponents;
2265
+ this._service.$focusedId.pipe(takeUntilDestroyed(), tap(v => {
2266
+ this.focusedElement.set(v ?? undefined);
2267
+ })).subscribe();
2212
2268
  toObservable(this._list).pipe(takeUntilDestroyed(), filter(v => !!v), tap(v => {
2213
2269
  this._service.listElement = v.nativeElement;
2214
2270
  })).subscribe();
@@ -2296,6 +2352,7 @@ class NgVirtualListComponent {
2296
2352
  bounds: { width, height }, dynamicSize, isVertical, itemSize,
2297
2353
  bufferSize, maxBufferSize, scrollSize: actualScrollSize, snap, enabledBufferOptimization,
2298
2354
  }, { displayItems, totalSize } = this._trackBox.updateCollection(items, itemConfigMap, opts);
2355
+ this._service.collection = displayItems;
2299
2356
  this.resetBoundsSize(isVertical, totalSize);
2300
2357
  this.createDisplayComponentsIfNeed(displayItems);
2301
2358
  this.tracking();
@@ -2499,6 +2556,7 @@ class NgVirtualListComponent {
2499
2556
  const { displayItems, totalSize } = this._trackBox.updateCollection(items, itemConfigMap, {
2500
2557
  ...opts, scrollSize, fromItemId: isLastIteration ? undefined : id,
2501
2558
  }), delta = this._trackBox.delta;
2559
+ this._service.collection = displayItems;
2502
2560
  this._trackBox.clearDelta();
2503
2561
  let actualScrollSize = scrollSize + delta;
2504
2562
  this.resetBoundsSize(isVertical, totalSize);
@@ -2616,11 +2674,13 @@ class NgVirtualListComponent {
2616
2674
  }
2617
2675
  }
2618
2676
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgVirtualListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2619
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: NgVirtualListComponent, isStandalone: true, 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" }, 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\" #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"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
2677
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: NgVirtualListComponent, isStandalone: true, 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" }, 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()\" tabindex=\"0\" #list\r\n 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"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
2620
2678
  }
2621
2679
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgVirtualListComponent, decorators: [{
2622
2680
  type: Component,
2623
- args: [{ selector: 'ng-virtual-list', imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, providers: [NgVirtualListService], 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\" #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"] }]
2681
+ args: [{ selector: 'ng-virtual-list', imports: [CommonModule], host: {
2682
+ 'style': 'position: relative;'
2683
+ }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, providers: [NgVirtualListService], 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()\" tabindex=\"0\" #list\r\n 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"] }]
2624
2684
  }], ctorParameters: () => [], propDecorators: { _listContainerRef: [{
2625
2685
  type: ViewChild,
2626
2686
  args: ['renderersContainer', { read: ViewContainerRef }]