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.
- package/README.md +29 -9
- package/esm2022/lib/components/ng-virtual-list-item.component.mjs +41 -19
- package/esm2022/lib/const/index.mjs +3 -2
- package/esm2022/lib/enums/collection-mode.mjs +2 -0
- package/esm2022/lib/enums/collection-modes.mjs +18 -0
- package/esm2022/lib/enums/focus-alignments.mjs +14 -0
- package/esm2022/lib/enums/index.mjs +4 -2
- package/esm2022/lib/models/display-object-config.model.mjs +2 -0
- package/esm2022/lib/models/display-object-measures.model.mjs +2 -0
- package/esm2022/lib/models/index.mjs +1 -1
- package/esm2022/lib/ng-virtual-list.component.mjs +103 -22
- package/esm2022/lib/ng-virtual-list.service.mjs +6 -5
- package/esm2022/lib/types/focus-alignment.mjs +2 -0
- package/esm2022/lib/types/index.mjs +1 -1
- package/esm2022/lib/utils/isCollectionMode.mjs +15 -0
- package/esm2022/lib/utils/trackBox.mjs +45 -16
- package/fesm2022/ng-virtual-list.mjs +231 -54
- package/fesm2022/ng-virtual-list.mjs.map +1 -1
- package/lib/components/ng-virtual-list-item.component.d.ts +7 -35
- package/lib/const/index.d.ts +2 -1
- package/lib/enums/collection-mode.d.ts +8 -0
- package/lib/enums/collection-modes.d.ts +16 -0
- package/lib/enums/focus-alignments.d.ts +12 -0
- package/lib/enums/index.d.ts +5 -2
- package/lib/models/display-object-config.model.d.ts +35 -0
- package/lib/models/display-object-measures.model.d.ts +13 -0
- package/lib/models/index.d.ts +3 -1
- package/lib/ng-virtual-list.component.d.ts +16 -3
- package/lib/ng-virtual-list.service.d.ts +4 -4
- package/lib/types/focus-alignment.d.ts +8 -0
- package/lib/types/index.d.ts +2 -1
- package/lib/utils/isCollectionMode.d.ts +8 -0
- package/lib/utils/trackBox.d.ts +17 -9
- package/package.json +1 -1
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Injectable, inject, ChangeDetectorRef, signal, ElementRef, 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
|
-
|
|
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), $
|
|
486
|
-
$
|
|
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.
|
|
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.
|
|
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,
|
|
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(
|
|
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}
|
|
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(
|
|
624
|
-
styles.transform = `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.delta}${PX}, ${data.config.isVertical ? data.measures.delta : 0}${PX}
|
|
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(
|
|
628
|
-
styles.transform = `${TRANSLATE_3D}(${data.config.isVertical ? 0 : data.measures.x}${PX}, ${data.config.isVertical ? data.measures.y : 0}${PX}
|
|
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.
|
|
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':
|
|
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':
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
1354
|
-
|
|
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
|
|
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
|
|
1591
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2577
|
-
|
|
2578
|
-
|
|
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(),
|
|
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(),
|
|
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
|
-
|
|
2715
|
-
|
|
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(
|
|
2785
|
-
this._trackBox.addEventListener(
|
|
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(
|
|
2790
|
-
this._trackBox.removeEventListener(
|
|
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
|