ng-virtual-list 14.7.13 → 14.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 +20 -1
- package/esm2020/lib/components/ng-virtual-list-item.component.mjs +34 -12
- package/esm2020/lib/const/index.mjs +2 -1
- package/esm2020/lib/enums/focus-alignments.mjs +14 -0
- package/esm2020/lib/enums/index.mjs +3 -2
- package/esm2020/lib/models/display-object-config.model.mjs +2 -0
- package/esm2020/lib/models/display-object-measures.model.mjs +2 -0
- package/esm2020/lib/models/index.mjs +1 -1
- package/esm2020/lib/ng-virtual-list.component.mjs +107 -11
- package/esm2020/lib/ng-virtual-list.service.mjs +15 -4
- package/esm2020/lib/types/focus-alignment.mjs +2 -0
- package/esm2020/lib/types/index.mjs +1 -1
- package/fesm2015/ng-virtual-list.mjs +166 -22
- package/fesm2015/ng-virtual-list.mjs.map +1 -1
- package/fesm2020/ng-virtual-list.mjs +165 -23
- package/fesm2020/ng-virtual-list.mjs.map +1 -1
- package/lib/components/ng-virtual-list-item.component.d.ts +8 -36
- package/lib/const/index.d.ts +1 -0
- package/lib/enums/focus-alignments.d.ts +12 -0
- package/lib/enums/index.d.ts +2 -1
- 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 +19 -2
- package/lib/ng-virtual-list.service.d.ts +9 -5
- package/lib/types/focus-alignment.d.ts +8 -0
- package/lib/types/index.d.ts +2 -1
- package/package.json +1 -1
|
@@ -82,6 +82,20 @@ var SnappingMethods;
|
|
|
82
82
|
SnappingMethods["ADVANCED"] = "advanced";
|
|
83
83
|
})(SnappingMethods || (SnappingMethods = {}));
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Focus Alignments.
|
|
87
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/14.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
|
+
|
|
85
99
|
const DEFAULT_ITEM_SIZE = 24;
|
|
86
100
|
const DEFAULT_BUFFER_SIZE = 2;
|
|
87
101
|
const DEFAULT_MAX_BUFFER_SIZE = 10;
|
|
@@ -98,6 +112,7 @@ const DISPLAY_OBJECTS_LENGTH_MESUREMENT_ERROR = 1;
|
|
|
98
112
|
const MAX_SCROLL_TO_ITERATIONS = 5;
|
|
99
113
|
const DEFAULT_SNAPPING_METHOD = SnappingMethods.NORMAL;
|
|
100
114
|
const DEFAULT_SELECT_METHOD = MethodsForSelecting.NONE;
|
|
115
|
+
const DEFAULT_SCREEN_READER_MESSAGE = 'Showing items $1 to $2';
|
|
101
116
|
// presets
|
|
102
117
|
const BEHAVIOR_AUTO = 'auto';
|
|
103
118
|
const BEHAVIOR_INSTANT = 'instant';
|
|
@@ -241,7 +256,9 @@ class NgVirtualListService {
|
|
|
241
256
|
this.selectByClick = DEFAULT_SELECT_BY_CLICK;
|
|
242
257
|
this.collapseByClick = DEFAULT_COLLAPSE_BY_CLICK;
|
|
243
258
|
this.listElement = null;
|
|
244
|
-
this.
|
|
259
|
+
this._$displayItems = new BehaviorSubject([]);
|
|
260
|
+
this.$displayItems = this._$displayItems.asObservable();
|
|
261
|
+
this._collection = [];
|
|
245
262
|
this._$methodOfSelecting.pipe(takeUntil(this._$unsubscribe), tap(v => {
|
|
246
263
|
switch (v) {
|
|
247
264
|
case MethodsForSelectingTypes.SELECT: {
|
|
@@ -269,6 +286,14 @@ class NgVirtualListService {
|
|
|
269
286
|
this._$methodOfSelecting.next(v);
|
|
270
287
|
}
|
|
271
288
|
get focusedId() { return this._$focusedId.getValue(); }
|
|
289
|
+
set collection(v) {
|
|
290
|
+
if (this._collection === v) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
this._collection = v;
|
|
294
|
+
this._$displayItems.next(v);
|
|
295
|
+
}
|
|
296
|
+
get collection() { return this._collection; }
|
|
272
297
|
setSelectedIds(ids) {
|
|
273
298
|
if (JSON.stringify(this._$selectedIds.getValue()) !== JSON.stringify(ids)) {
|
|
274
299
|
this._$selectedIds.next(ids);
|
|
@@ -385,11 +410,11 @@ class NgVirtualListService {
|
|
|
385
410
|
initialize(trackBox) {
|
|
386
411
|
this._trackBox = trackBox;
|
|
387
412
|
}
|
|
388
|
-
focus(element) {
|
|
413
|
+
focus(element, align = FocusAlignments.CENTER) {
|
|
389
414
|
element.focus({ preventScroll: true });
|
|
390
415
|
if (element.parentElement) {
|
|
391
416
|
const pos = parseFloat(element.parentElement?.getAttribute('position') ?? '0');
|
|
392
|
-
this.itemToFocus?.(element, pos);
|
|
417
|
+
this.itemToFocus?.(element, pos, align);
|
|
393
418
|
}
|
|
394
419
|
}
|
|
395
420
|
areaFocus(id) {
|
|
@@ -415,7 +440,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
|
|
|
415
440
|
}]
|
|
416
441
|
}], ctorParameters: function () { return []; } });
|
|
417
442
|
|
|
418
|
-
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';
|
|
443
|
+
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';
|
|
419
444
|
const getElementByIndex = (index) => {
|
|
420
445
|
return `[${TABINDEX}="${index}"]`;
|
|
421
446
|
};
|
|
@@ -438,8 +463,8 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
438
463
|
this._$config = new BehaviorSubject$1({});
|
|
439
464
|
this.$config = this._$config.asObservable();
|
|
440
465
|
this.measures = new BehaviorSubject$1(undefined);
|
|
441
|
-
this._$
|
|
442
|
-
this.$
|
|
466
|
+
this._$focused = new BehaviorSubject$1(false);
|
|
467
|
+
this.$focused = this._$focused.asObservable();
|
|
443
468
|
this._$part = new BehaviorSubject$1(PART_DEFAULT_ITEM);
|
|
444
469
|
this.$part = this._$part.asObservable();
|
|
445
470
|
this.regular = false;
|
|
@@ -472,19 +497,26 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
472
497
|
}
|
|
473
498
|
this._service.collapse(data, collapsed);
|
|
474
499
|
};
|
|
500
|
+
this._focusHandler = () =>
|
|
501
|
+
/**
|
|
502
|
+
* Focus a list item
|
|
503
|
+
*/
|
|
504
|
+
(align = FocusAlignments.CENTER) => {
|
|
505
|
+
this.focus(align);
|
|
506
|
+
};
|
|
475
507
|
this._id = this._service.generateComponentId();
|
|
476
|
-
const $data = this.$data, $focus = this.$
|
|
508
|
+
const $data = this.$data, $focus = this.$focused;
|
|
477
509
|
this._elementRef.nativeElement.setAttribute('id', String(this._id));
|
|
478
510
|
$focus.pipe(takeUntil$1(this._$unsubscribe), tap$1(v => {
|
|
479
511
|
this._service.areaFocus(v ? this._id : this._service.focusedId === this._id ? null : this._service.focusedId);
|
|
480
512
|
})).subscribe();
|
|
481
513
|
fromEvent(this.element, EVENT_FOCUS_IN).pipe(takeUntil$1(this._$unsubscribe), tap$1(e => {
|
|
482
|
-
this._$
|
|
514
|
+
this._$focused.next(true);
|
|
483
515
|
this.updateConfig(this.data);
|
|
484
516
|
this.updatePartStr(this.data, this._isSelected, this._isCollapsed);
|
|
485
517
|
})).subscribe(),
|
|
486
518
|
fromEvent(this.element, EVENT_FOCUS_OUT).pipe(takeUntil$1(this._$unsubscribe), tap$1(e => {
|
|
487
|
-
this._$
|
|
519
|
+
this._$focused.next(false);
|
|
488
520
|
this.updateConfig(this.data);
|
|
489
521
|
this.updatePartStr(this.data, this._isSelected, this._isCollapsed);
|
|
490
522
|
})).subscribe(),
|
|
@@ -627,18 +659,29 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
627
659
|
}
|
|
628
660
|
}
|
|
629
661
|
}
|
|
662
|
+
focus(align = FocusAlignments.CENTER) {
|
|
663
|
+
if (this._service.listElement) {
|
|
664
|
+
const tabIndex = this.data?.config?.tabIndex ?? 0;
|
|
665
|
+
let index = tabIndex;
|
|
666
|
+
const el = this._service.listElement.querySelector(getElementByIndex(index));
|
|
667
|
+
if (el) {
|
|
668
|
+
this._service.focus(el, align);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
630
672
|
updateMeasures(v) {
|
|
631
673
|
this.measures.next(v?.measures ? { ...v.measures } : undefined);
|
|
632
674
|
}
|
|
633
675
|
updateConfig(v) {
|
|
634
676
|
this._$config.next({
|
|
635
|
-
...v?.config || {}, selected: this._isSelected, collapsed: this._isCollapsed,
|
|
636
|
-
collapse: this._collapseHandler(v), select: this._selectHandler(v)
|
|
677
|
+
...v?.config || {}, selected: this._isSelected, collapsed: this._isCollapsed, focused: this._$focused.getValue(),
|
|
678
|
+
collapse: this._collapseHandler(v), select: this._selectHandler(v), focus: this._focusHandler(),
|
|
637
679
|
});
|
|
638
680
|
}
|
|
639
681
|
update() {
|
|
640
682
|
const data = this.data, regular = this.regular, length = this._regularLength;
|
|
641
683
|
if (data) {
|
|
684
|
+
this._elementRef.nativeElement.setAttribute(ID, `${data.id}`);
|
|
642
685
|
const styles = this._elementRef.nativeElement.style;
|
|
643
686
|
styles.zIndex = data.config.zIndex;
|
|
644
687
|
if (data.config.snapped) {
|
|
@@ -662,6 +705,9 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
662
705
|
styles.height = data.config.isVertical ? data.config.dynamic ? SIZE_AUTO : `${data.measures.height}${PX}` : regular ? length : SIZE_100_PERSENT;
|
|
663
706
|
styles.width = data.config.isVertical ? regular ? length : SIZE_100_PERSENT : data.config.dynamic ? SIZE_AUTO : `${data.measures.width}${PX}`;
|
|
664
707
|
}
|
|
708
|
+
else {
|
|
709
|
+
this._elementRef.nativeElement.removeAttribute(ID);
|
|
710
|
+
}
|
|
665
711
|
this._cdr.markForCheck();
|
|
666
712
|
}
|
|
667
713
|
updatePartStr(v, isSelected, isCollapsed) {
|
|
@@ -683,7 +729,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
683
729
|
if (v ? v.config.new : false) {
|
|
684
730
|
part += PART_ITEM_NEW;
|
|
685
731
|
}
|
|
686
|
-
if (this._$
|
|
732
|
+
if (this._$focused.getValue()) {
|
|
687
733
|
part += PART_ITEM_FOCUSED;
|
|
688
734
|
}
|
|
689
735
|
this._$part.next(part);
|
|
@@ -737,13 +783,13 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
737
783
|
}
|
|
738
784
|
}
|
|
739
785
|
NgVirtualListItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgVirtualListItemComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: NgVirtualListService }], target: i0.ɵɵFactoryTarget.Component });
|
|
740
|
-
NgVirtualListItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgVirtualListItemComponent, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "<ng-container *ngIf=\"data\">\r\n <div #listItem [part]=\"$part | async\" [attr.ng-vl-index]=\"data.config.tabIndex || -1\" tabindex=\"0\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': data.config.snapped,\r\n 'snapped-out': data.config.snappedOut, 'focus': $
|
|
786
|
+
NgVirtualListItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgVirtualListItemComponent, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "<ng-container *ngIf=\"data\">\r\n <div #listItem [part]=\"$part | async\" [attr.ng-vl-index]=\"data.config.tabIndex || -1\" tabindex=\"0\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': data.config.snapped,\r\n 'snapped-out': data.config.snappedOut, 'focus': $focused | async}\" (click)=\"onClickHandler()\">\r\n <ng-container *ngIf=\"itemRenderer\">\r\n <ng-container [ngTemplateOutlet]=\"itemRenderer\"\r\n [ngTemplateOutletContext]=\"{data: data.data || {}, measures: measures | async, config: $config | async}\"></ng-container>\r\n </ng-container>\r\n </div>\r\n</ng-container>", 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: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
741
787
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgVirtualListItemComponent, decorators: [{
|
|
742
788
|
type: Component,
|
|
743
789
|
args: [{ selector: 'ng-virtual-list-item', host: {
|
|
744
790
|
'class': 'ngvl__item',
|
|
745
791
|
'role': 'listitem',
|
|
746
|
-
}, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"data\">\r\n <div #listItem [part]=\"$part | async\" [attr.ng-vl-index]=\"data.config.tabIndex || -1\" tabindex=\"0\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': data.config.snapped,\r\n 'snapped-out': data.config.snappedOut, 'focus': $
|
|
792
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"data\">\r\n <div #listItem [part]=\"$part | async\" [attr.ng-vl-index]=\"data.config.tabIndex || -1\" tabindex=\"0\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': data.config.snapped,\r\n 'snapped-out': data.config.snappedOut, 'focus': $focused | async}\" (click)=\"onClickHandler()\">\r\n <ng-container *ngIf=\"itemRenderer\">\r\n <ng-container [ngTemplateOutlet]=\"itemRenderer\"\r\n [ngTemplateOutletContext]=\"{data: data.data || {}, measures: measures | async, config: $config | async}\"></ng-container>\r\n </ng-container>\r\n </div>\r\n</ng-container>", 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"] }]
|
|
747
793
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: NgVirtualListService }]; } });
|
|
748
794
|
|
|
749
795
|
/**
|
|
@@ -2202,7 +2248,7 @@ const isCollectionMode = (src, expected) => {
|
|
|
2202
2248
|
return NORMAL_ALIASES.includes(src);
|
|
2203
2249
|
};
|
|
2204
2250
|
|
|
2205
|
-
const ROLE_LIST = 'list', ROLE_LIST_BOX = 'listbox';
|
|
2251
|
+
const ROLE_LIST = 'list', ROLE_LIST_BOX = 'listbox', ITEM_ID = 'item-id', ITEM_CONTAINER = 'ngvl-item__container';
|
|
2206
2252
|
const validateScrollIteration = (value) => {
|
|
2207
2253
|
return Number.isNaN(value) || (value < 0) ? 0 : value > MAX_SCROLL_TO_ITERATIONS ? MAX_SCROLL_TO_ITERATIONS : value;
|
|
2208
2254
|
}, validateId = (id) => {
|
|
@@ -2221,6 +2267,35 @@ const validateScrollIteration = (value) => {
|
|
|
2221
2267
|
if (!valid) {
|
|
2222
2268
|
throw Error('The "iteration" parameter must be of type `number`.');
|
|
2223
2269
|
}
|
|
2270
|
+
}, validateFocusAlignment = (align) => {
|
|
2271
|
+
const valid = validateString(align) && (align === 'none' || align === 'start' || align === 'center' || align === 'end');
|
|
2272
|
+
if (!valid) {
|
|
2273
|
+
throw Error('The "align" parameter must have the value `none`, `start`, `center` or `end`.');
|
|
2274
|
+
}
|
|
2275
|
+
};
|
|
2276
|
+
const formatScreenReaderMessage = (items, messagePattern, scrollSize, isVertical, bounds) => {
|
|
2277
|
+
if (!messagePattern) {
|
|
2278
|
+
return '';
|
|
2279
|
+
}
|
|
2280
|
+
const list = items ?? [], size = isVertical ? bounds.height : bounds.width;
|
|
2281
|
+
let start = Number.NaN, end = Number.NaN, prevItem;
|
|
2282
|
+
for (let i = 0, l = list.length; i < l; i++) {
|
|
2283
|
+
const item = list[i], position = isVertical ? item.measures.y : item.measures.x, itemSize = isVertical ? item.measures.height : item.measures.width;
|
|
2284
|
+
if (((position + itemSize) >= scrollSize) && Number.isNaN(start)) {
|
|
2285
|
+
start = item.index + 1;
|
|
2286
|
+
}
|
|
2287
|
+
if ((position >= (scrollSize + size)) && Number.isNaN(end) && prevItem) {
|
|
2288
|
+
end = prevItem.index + 1;
|
|
2289
|
+
}
|
|
2290
|
+
prevItem = item;
|
|
2291
|
+
}
|
|
2292
|
+
if (Number.isNaN(start) || Number.isNaN(end)) {
|
|
2293
|
+
return '';
|
|
2294
|
+
}
|
|
2295
|
+
let formatted = messagePattern ?? '';
|
|
2296
|
+
formatted = formatted.replace('$1', `${start}`);
|
|
2297
|
+
formatted = formatted.replace('$2', `${end}`);
|
|
2298
|
+
return formatted;
|
|
2224
2299
|
};
|
|
2225
2300
|
/**
|
|
2226
2301
|
* Virtual list component.
|
|
@@ -2508,6 +2583,18 @@ class NgVirtualListComponent extends DisposableComponent {
|
|
|
2508
2583
|
}
|
|
2509
2584
|
return v;
|
|
2510
2585
|
};
|
|
2586
|
+
this._$screenReaderMessage = new BehaviorSubject$1(DEFAULT_SCREEN_READER_MESSAGE);
|
|
2587
|
+
this.$screenReaderMessage = this._$screenReaderMessage.asObservable();
|
|
2588
|
+
this._screenReaderMessageTransform = (v) => {
|
|
2589
|
+
const valid = validateString(v);
|
|
2590
|
+
if (!valid) {
|
|
2591
|
+
console.error('The "screenReaderMessage" parameter must be of type `string`.');
|
|
2592
|
+
return DEFAULT_SCREEN_READER_MESSAGE;
|
|
2593
|
+
}
|
|
2594
|
+
return v;
|
|
2595
|
+
};
|
|
2596
|
+
this._$screenReaderFormattedMessage = new BehaviorSubject$1(DEFAULT_SCREEN_READER_MESSAGE);
|
|
2597
|
+
this.$screenReaderFormattedMessage = this._$screenReaderFormattedMessage.asObservable();
|
|
2511
2598
|
this._isVertical = this.getIsVertical();
|
|
2512
2599
|
this._isLazy = this.getIsLazy();
|
|
2513
2600
|
this._$focusedElement = new BehaviorSubject$1(undefined);
|
|
@@ -2577,12 +2664,33 @@ class NgVirtualListComponent extends DisposableComponent {
|
|
|
2577
2664
|
this._$scrollSize.next(scrollSize);
|
|
2578
2665
|
}
|
|
2579
2666
|
};
|
|
2580
|
-
this.itemToFocus = (element, position) => {
|
|
2667
|
+
this.itemToFocus = (element, position, align = FocusAlignments.CENTER) => {
|
|
2581
2668
|
const container = this._container?.nativeElement;
|
|
2582
2669
|
if (container) {
|
|
2583
|
-
const { width, height } = this._$bounds.getValue(), { width: elementWidth, height: elementHeight } = element.getBoundingClientRect(), isVertical = this._isVertical
|
|
2584
|
-
|
|
2585
|
-
|
|
2670
|
+
const { width, height } = this._$bounds.getValue(), { width: elementWidth, height: elementHeight } = element.getBoundingClientRect(), isVertical = this._isVertical;
|
|
2671
|
+
let pos = Number.NaN;
|
|
2672
|
+
switch (align) {
|
|
2673
|
+
case FocusAlignments.START: {
|
|
2674
|
+
pos = isVertical ? position : position;
|
|
2675
|
+
break;
|
|
2676
|
+
}
|
|
2677
|
+
case FocusAlignments.CENTER: {
|
|
2678
|
+
pos = isVertical ? position - (height - elementHeight) * .5 : position - (width - elementWidth) * .5;
|
|
2679
|
+
break;
|
|
2680
|
+
}
|
|
2681
|
+
case FocusAlignments.END: {
|
|
2682
|
+
pos = isVertical ? position - (height - elementHeight) : position - (width - elementWidth);
|
|
2683
|
+
break;
|
|
2684
|
+
}
|
|
2685
|
+
case FocusAlignments.NONE:
|
|
2686
|
+
default: {
|
|
2687
|
+
break;
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
if (!Number.isNaN(pos)) {
|
|
2691
|
+
const params = { [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: pos, behavior: 'instant' };
|
|
2692
|
+
container.scrollTo(params);
|
|
2693
|
+
}
|
|
2586
2694
|
}
|
|
2587
2695
|
};
|
|
2588
2696
|
this._$initialized = new BehaviorSubject$1(false);
|
|
@@ -2681,7 +2789,10 @@ class NgVirtualListComponent extends DisposableComponent {
|
|
|
2681
2789
|
$trackBy.pipe(takeUntil(this._$unsubscribe), tap(v => {
|
|
2682
2790
|
this._trackBox.trackingPropertyName = v;
|
|
2683
2791
|
})).subscribe();
|
|
2684
|
-
const $bounds = this._$bounds.asObservable().pipe(filter(b => !!b)), $items = this.$items.pipe(map$1(i => !i ? [] : i)), $scrollSize = this._$scrollSize.asObservable(), $itemSize = this.$itemSize.pipe(map$1(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $bufferSize = this.$bufferSize.pipe(map$1(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $maxBufferSize = this.$maxBufferSize.pipe(map$1(v => v < 0 ? DEFAULT_MAX_BUFFER_SIZE : v)), $itemConfigMap = this.$itemConfigMap.pipe(map$1(v => !v ? {} : v)), $snap = this.$snap, $isVertical = this.$direction.pipe(map$1(v => this.getIsVertical(v || DEFAULT_DIRECTION))), $isLazy = this.$collectionMode.pipe(map$1(v => this.getIsLazy(v || DEFAULT_COLLECTION_MODE))), $dynamicSize = this.$dynamicSize, $enabledBufferOptimization = this.$enabledBufferOptimization, $snappingMethod = this.$snappingMethod.pipe(map$1(v => this.getIsSnappingMethodAdvanced(v || DEFAULT_SNAPPING_METHOD))), $methodForSelecting = this.$methodForSelecting, $selectedIds = this.$selectedIds, $collapsedIds = this.$collapsedIds.pipe(map$1(v => Array.isArray(v) ? v : [])), $collapsedItemIds = this._$collapsedItemIds.asObservable().pipe(map$1(v => Array.isArray(v) ? v : [])), $actualItems = this._$actualItems.asObservable(), $cacheVersion = this.$cacheVersion;
|
|
2792
|
+
const $bounds = this._$bounds.asObservable().pipe(filter(b => !!b)), $items = this.$items.pipe(map$1(i => !i ? [] : i)), $scrollSize = this._$scrollSize.asObservable(), $itemSize = this.$itemSize.pipe(map$1(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $bufferSize = this.$bufferSize.pipe(map$1(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $maxBufferSize = this.$maxBufferSize.pipe(map$1(v => v < 0 ? DEFAULT_MAX_BUFFER_SIZE : v)), $itemConfigMap = this.$itemConfigMap.pipe(map$1(v => !v ? {} : v)), $snap = this.$snap, $isVertical = this.$direction.pipe(map$1(v => this.getIsVertical(v || DEFAULT_DIRECTION))), $isLazy = this.$collectionMode.pipe(map$1(v => this.getIsLazy(v || DEFAULT_COLLECTION_MODE))), $dynamicSize = this.$dynamicSize, $enabledBufferOptimization = this.$enabledBufferOptimization, $snappingMethod = this.$snappingMethod.pipe(map$1(v => this.getIsSnappingMethodAdvanced(v || DEFAULT_SNAPPING_METHOD))), $methodForSelecting = this.$methodForSelecting, $selectedIds = this.$selectedIds, $collapsedIds = this.$collapsedIds.pipe(map$1(v => Array.isArray(v) ? v : [])), $collapsedItemIds = this._$collapsedItemIds.asObservable().pipe(map$1(v => Array.isArray(v) ? v : [])), $actualItems = this._$actualItems.asObservable(), $screenReaderMessage = this.$screenReaderMessage, $displayItems = this._service.$displayItems, $cacheVersion = this.$cacheVersion;
|
|
2793
|
+
combineLatest([$displayItems, $screenReaderMessage, $isVertical, $scrollSize, $bounds]).pipe(takeUntil(this._$unsubscribe), distinctUntilChanged(), debounceTime(100), tap(([items, screenReaderMessage, isVertical, scrollSize, bounds]) => {
|
|
2794
|
+
this._$screenReaderFormattedMessage.next(formatScreenReaderMessage(items, screenReaderMessage, scrollSize, isVertical, bounds));
|
|
2795
|
+
})).subscribe();
|
|
2685
2796
|
$isLazy.pipe(takeUntil(this._$unsubscribe), tap(v => {
|
|
2686
2797
|
this._trackBox.isLazy = v;
|
|
2687
2798
|
})).subscribe();
|
|
@@ -3078,6 +3189,21 @@ class NgVirtualListComponent extends DisposableComponent {
|
|
|
3078
3189
|
}
|
|
3079
3190
|
;
|
|
3080
3191
|
get trackBy() { return this._$trackBy.getValue(); }
|
|
3192
|
+
/**
|
|
3193
|
+
* Message for screen reader.
|
|
3194
|
+
* The message format is: "some text $1 some text $2",
|
|
3195
|
+
* where $1 is the number of the first element of the screen collection,
|
|
3196
|
+
* $2 is the number of the last element of the screen collection.
|
|
3197
|
+
*/
|
|
3198
|
+
set screenReaderMessage(v) {
|
|
3199
|
+
if (this._$screenReaderMessage.getValue() === v) {
|
|
3200
|
+
return;
|
|
3201
|
+
}
|
|
3202
|
+
const transformedValue = this._screenReaderMessageTransform(v);
|
|
3203
|
+
this._$screenReaderMessage.next(transformedValue);
|
|
3204
|
+
}
|
|
3205
|
+
;
|
|
3206
|
+
get screenReaderMessage() { return this._$screenReaderMessage.getValue(); }
|
|
3081
3207
|
get orientation() {
|
|
3082
3208
|
return this._isVertical ? Directions.VERTICAL : Directions.HORIZONTAL;
|
|
3083
3209
|
}
|
|
@@ -3190,6 +3316,20 @@ class NgVirtualListComponent extends DisposableComponent {
|
|
|
3190
3316
|
validateId(id);
|
|
3191
3317
|
return this._trackBox.getItemBounds(id);
|
|
3192
3318
|
}
|
|
3319
|
+
/**
|
|
3320
|
+
* Focus an list item by a given id.
|
|
3321
|
+
*/
|
|
3322
|
+
focus(id, align = FocusAlignments.NONE) {
|
|
3323
|
+
validateId(id);
|
|
3324
|
+
validateFocusAlignment(align);
|
|
3325
|
+
const el = this._list?.nativeElement.querySelector(`[${ITEM_ID}="${id}"]`);
|
|
3326
|
+
if (el) {
|
|
3327
|
+
const focusedEl = el.querySelector(`.${ITEM_CONTAINER}`);
|
|
3328
|
+
if (focusedEl) {
|
|
3329
|
+
this._service.focus(focusedEl, align);
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3193
3333
|
/**
|
|
3194
3334
|
* The method scrolls the list to the element with the given id and returns the value of the scrolled area.
|
|
3195
3335
|
* Behavior accepts the values "auto", "instant" and "smooth".
|
|
@@ -3330,12 +3470,12 @@ class NgVirtualListComponent extends DisposableComponent {
|
|
|
3330
3470
|
}
|
|
3331
3471
|
NgVirtualListComponent.__nextId = 0;
|
|
3332
3472
|
NgVirtualListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgVirtualListComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: NgVirtualListService }], target: i0.ɵɵFactoryTarget.Component });
|
|
3333
|
-
NgVirtualListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgVirtualListComponent, selector: "ng-virtual-list", inputs: { items: "items", selectedIds: "selectedIds", collapsedIds: "collapsedIds", selectByClick: "selectByClick", collapseByClick: "collapseByClick", snap: "snap", enabledBufferOptimization: "enabledBufferOptimization", itemRenderer: "itemRenderer", itemConfigMap: "itemConfigMap", itemSize: "itemSize", dynamicSize: "dynamicSize", direction: "direction", collectionMode: "collectionMode", bufferSize: "bufferSize", maxBufferSize: "maxBufferSize", snappingMethod: "snappingMethod", methodForSelecting: "methodForSelecting", trackBy: "trackBy" }, 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: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, read: (ElementRef) }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, read: (ElementRef) }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, read: ViewContainerRef }], usesInheritance: true, ngImport: i0, template: "<div *ngIf=\"snap\" #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n</div>\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" [attr.aria-activedescendant]=\"$focusedElement | async\" #list part=\"list\"\r\n 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: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
|
|
3473
|
+
NgVirtualListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgVirtualListComponent, selector: "ng-virtual-list", inputs: { items: "items", selectedIds: "selectedIds", collapsedIds: "collapsedIds", selectByClick: "selectByClick", collapseByClick: "collapseByClick", snap: "snap", enabledBufferOptimization: "enabledBufferOptimization", itemRenderer: "itemRenderer", itemConfigMap: "itemConfigMap", itemSize: "itemSize", dynamicSize: "dynamicSize", direction: "direction", collectionMode: "collectionMode", bufferSize: "bufferSize", maxBufferSize: "maxBufferSize", snappingMethod: "snappingMethod", methodForSelecting: "methodForSelecting", trackBy: "trackBy", screenReaderMessage: "screenReaderMessage" }, 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: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, read: (ElementRef) }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, read: (ElementRef) }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, read: ViewContainerRef }], usesInheritance: true, ngImport: i0, template: "<div aria-live=\"polite\" aria-atomic=\"true\" class=\"ngvl__screen-reader\">\r\n {{ $screenReaderFormattedMessage | async}}\r\n</div>\r\n<div *ngIf=\"snap\" #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n</div>\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" [attr.aria-activedescendant]=\"$focusedElement | async\" #list part=\"list\"\r\n 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%}.ngvl__screen-reader{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
|
|
3334
3474
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgVirtualListComponent, decorators: [{
|
|
3335
3475
|
type: Component,
|
|
3336
3476
|
args: [{ selector: 'ng-virtual-list', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, providers: [NgVirtualListService], host: {
|
|
3337
3477
|
'style': 'position: relative;'
|
|
3338
|
-
}, template: "<div *ngIf=\"snap\" #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n</div>\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" [attr.aria-activedescendant]=\"$focusedElement | async\" #list part=\"list\"\r\n 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"] }]
|
|
3478
|
+
}, template: "<div aria-live=\"polite\" aria-atomic=\"true\" class=\"ngvl__screen-reader\">\r\n {{ $screenReaderFormattedMessage | async}}\r\n</div>\r\n<div *ngIf=\"snap\" #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n</div>\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" [attr.aria-activedescendant]=\"$focusedElement | async\" #list part=\"list\"\r\n 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%}.ngvl__screen-reader{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
|
|
3339
3479
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: NgVirtualListService }]; }, propDecorators: { _listContainerRef: [{
|
|
3340
3480
|
type: ViewChild,
|
|
3341
3481
|
args: ['renderersContainer', { read: ViewContainerRef }]
|
|
@@ -3403,6 +3543,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
|
|
|
3403
3543
|
type: Input
|
|
3404
3544
|
}], trackBy: [{
|
|
3405
3545
|
type: Input
|
|
3546
|
+
}], screenReaderMessage: [{
|
|
3547
|
+
type: Input
|
|
3406
3548
|
}] } });
|
|
3407
3549
|
|
|
3408
3550
|
class NgVirtualListModule {
|
|
@@ -3428,5 +3570,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
|
|
|
3428
3570
|
* Generated bundle index. Do not edit.
|
|
3429
3571
|
*/
|
|
3430
3572
|
|
|
3431
|
-
export { CollectionModes, Directions, MethodsForSelecting, NgVirtualListComponent, NgVirtualListItemComponent, NgVirtualListModule, SnappingMethods };
|
|
3573
|
+
export { CollectionModes, Directions, FocusAlignments, MethodsForSelecting, NgVirtualListComponent, NgVirtualListItemComponent, NgVirtualListModule, SnappingMethods };
|
|
3432
3574
|
//# sourceMappingURL=ng-virtual-list.mjs.map
|