ng-virtual-list 16.7.2 → 16.7.3

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.
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, Component, ChangeDetectionStrategy, EventEmitter as EventEmitter$1, ViewContainerRef, ElementRef, ViewEncapsulation, ViewChild, Output, Input, NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
3
- import { takeUntil, map, tap as tap$1 } from 'rxjs/operators';
4
- import { Subject, tap, BehaviorSubject as BehaviorSubject$1, combineLatest, filter, map as map$1, debounceTime, distinctUntilChanged, switchMap, of } from 'rxjs';
5
- import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
3
+ import { tap as tap$1, map } from 'rxjs/operators';
4
+ import { Subject, tap, BehaviorSubject as BehaviorSubject$1, fromEvent, combineLatest, filter, map as map$1, debounceTime, distinctUntilChanged, switchMap, of } from 'rxjs';
6
5
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
+ import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
7
7
  import * as i2 from '@angular/common';
8
8
  import { CommonModule } from '@angular/common';
9
9
 
@@ -110,10 +110,11 @@ const CLASS_LIST_VERTICAL = 'vertical';
110
110
  const CLASS_LIST_HORIZONTAL = 'horizontal';
111
111
  // styles
112
112
  const PART_DEFAULT_ITEM = 'item';
113
- const PART_ITEM_ODD = ' odd';
114
- const PART_ITEM_EVEN = ' even';
115
- const PART_ITEM_SNAPPED = ' snapped';
116
- const PART_ITEM_SELECTED = ' selected';
113
+ const PART_ITEM_ODD = ' item-odd';
114
+ const PART_ITEM_EVEN = ' item-even';
115
+ const PART_ITEM_SNAPPED = ' item-snapped';
116
+ const PART_ITEM_SELECTED = ' item-selected';
117
+ const PART_ITEM_FOCUSED = ' item-focused';
117
118
 
118
119
  /**
119
120
  * Virtual List Item Interface
@@ -157,8 +158,9 @@ class NgVirtualListService {
157
158
  set methodOfSelecting(v) {
158
159
  this._$methodOfSelecting.next(v);
159
160
  }
160
- selectByClick = DEFAULT_SELECT_BY_CLICK;
161
161
  _trackBox;
162
+ selectByClick = DEFAULT_SELECT_BY_CLICK;
163
+ listElement = null;
162
164
  constructor() {
163
165
  this._$methodOfSelecting.pipe(takeUntilDestroyed(), tap(v => {
164
166
  switch (v) {
@@ -265,7 +267,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
265
267
  }]
266
268
  }], ctorParameters: function () { return []; } });
267
269
 
268
- const ATTR_AREA_SELECTED = 'area-selected';
270
+ 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";
269
271
  /**
270
272
  * Virtual list item component
271
273
  * @link https://github.com/DjonnyX/ng-virtual-list/blob/16.x/projects/ng-virtual-list/src/lib/components/ng-virtual-list-item.component.ts
@@ -276,7 +278,6 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
276
278
  _cdr;
277
279
  _elementRef;
278
280
  _service;
279
- _$unsubscribe = new Subject();
280
281
  _id;
281
282
  get id() {
282
283
  return this._id;
@@ -284,8 +285,11 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
284
285
  _part = PART_DEFAULT_ITEM;
285
286
  get part() { return this._part; }
286
287
  _isSelected = false;
287
- config = new BehaviorSubject$1({});
288
+ _$config = new BehaviorSubject$1({});
289
+ $config = this._$config.asObservable();
288
290
  measures = new BehaviorSubject$1(undefined);
291
+ _$focus = new BehaviorSubject$1(false);
292
+ $focus = this._$focus.asObservable();
289
293
  regular = false;
290
294
  data;
291
295
  _$data = new BehaviorSubject$1(this.data);
@@ -343,7 +347,55 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
343
347
  this._service = _service;
344
348
  this._id = this._service.generateComponentId();
345
349
  const $data = this.$data;
346
- combineLatest([$data, this._service.$methodOfSelecting, this._service.$selectedIds]).pipe(takeUntil(this._$unsubscribe), map(([, m, ids]) => ({ method: m, ids })), tap$1(({ method, ids }) => {
350
+ fromEvent(this.element, 'focusin').pipe(takeUntilDestroyed(), tap$1(e => {
351
+ this._$focus.next(true);
352
+ this.updateConfig(this.data);
353
+ this.updatePartStr(this.data, this._isSelected);
354
+ })).subscribe(),
355
+ fromEvent(this.element, 'focusout').pipe(takeUntilDestroyed(), tap$1(e => {
356
+ this._$focus.next(false);
357
+ this.updateConfig(this.data);
358
+ this.updatePartStr(this.data, this._isSelected);
359
+ })).subscribe(),
360
+ fromEvent(this.element, 'keydown').pipe(takeUntilDestroyed(), tap$1(e => {
361
+ switch (e.key) {
362
+ case KEY_SPACE: {
363
+ e.stopImmediatePropagation();
364
+ e.preventDefault();
365
+ this._service.select(this.data);
366
+ break;
367
+ }
368
+ case KEY_ARR_LEFT:
369
+ if (!this._$config.getValue().isVertical) {
370
+ e.stopImmediatePropagation();
371
+ e.preventDefault();
372
+ this.focusPrev();
373
+ }
374
+ break;
375
+ case KEY_ARR_UP:
376
+ if (this._$config.getValue().isVertical) {
377
+ e.stopImmediatePropagation();
378
+ e.preventDefault();
379
+ this.focusPrev();
380
+ }
381
+ break;
382
+ case KEY_ARR_RIGHT:
383
+ if (!this._$config.getValue().isVertical) {
384
+ e.stopImmediatePropagation();
385
+ e.preventDefault();
386
+ this.focusNext();
387
+ }
388
+ break;
389
+ case KEY_ARR_DOWN:
390
+ if (this._$config.getValue().isVertical) {
391
+ e.stopImmediatePropagation();
392
+ e.preventDefault();
393
+ this.focusNext();
394
+ }
395
+ break;
396
+ }
397
+ })).subscribe();
398
+ combineLatest([$data, this._service.$methodOfSelecting, this._service.$selectedIds]).pipe(takeUntilDestroyed(), map(([, m, ids]) => ({ method: m, ids })), tap$1(({ method, ids }) => {
347
399
  switch (method) {
348
400
  case MethodsForSelectingTypes.SELECT: {
349
401
  const id = ids, isSelected = id === this.itemId;
@@ -369,11 +421,29 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
369
421
  this.updateMeasures(this.data);
370
422
  })).subscribe();
371
423
  }
424
+ focusNext() {
425
+ const tabIndex = this._$config.getValue()?.tabIndex ?? 0;
426
+ if (this._service.listElement && tabIndex > 0) {
427
+ const el = this._service.listElement.querySelector(`[${TABINDEX}="${tabIndex + 1}"]`);
428
+ if (el) {
429
+ el.focus();
430
+ }
431
+ }
432
+ }
433
+ focusPrev() {
434
+ const tabIndex = this._$config.getValue()?.tabIndex ?? 0;
435
+ if (this._service.listElement && tabIndex > 1) {
436
+ const el = this._service.listElement.querySelector(`[${TABINDEX}="${tabIndex - 1}"]`);
437
+ if (el) {
438
+ el.focus();
439
+ }
440
+ }
441
+ }
372
442
  updateMeasures(v) {
373
443
  this.measures.next(v?.measures ? { ...v.measures } : undefined);
374
444
  }
375
445
  updateConfig(v) {
376
- this.config.next({ ...v?.config || {}, selected: this._isSelected, select: this._selectHandler(v) });
446
+ this._$config.next({ ...v?.config || {}, selected: this._isSelected, select: this._selectHandler(v), focus: this._$focus.getValue() });
377
447
  }
378
448
  update() {
379
449
  const data = this.data, regular = this.regular, length = this._regularLength;
@@ -414,6 +484,9 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
414
484
  if (isSelected) {
415
485
  part += PART_ITEM_SELECTED;
416
486
  }
487
+ if (this._$focus.getValue()) {
488
+ part += PART_ITEM_FOCUSED;
489
+ }
417
490
  this._part = part;
418
491
  }
419
492
  getBounds() {
@@ -457,21 +530,15 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
457
530
  onClickHandler() {
458
531
  this._service.itemClick(this.data);
459
532
  }
460
- ngOnDestroy() {
461
- if (this._$unsubscribe) {
462
- this._$unsubscribe.next();
463
- this._$unsubscribe.complete();
464
- }
465
- }
466
533
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgVirtualListItemComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: NgVirtualListService }], target: i0.ɵɵFactoryTarget.Component });
467
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", 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\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': data.config.snapped,\r\n 'snapped-out': data.config.snappedOut}\" (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}\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 });
534
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", 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\" [attr.index]=\"data.config.tabIndex\" tabindex=\"1\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': data.config.snapped,\r\n 'snapped-out': data.config.snappedOut, 'focus': $focus | 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 });
468
535
  }
469
536
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgVirtualListItemComponent, decorators: [{
470
537
  type: Component,
471
538
  args: [{ selector: 'ng-virtual-list-item', host: {
472
539
  'class': 'ngvl__item',
473
540
  'role': 'listitem',
474
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"data\">\r\n <div #listItem [part]=\"part\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': data.config.snapped,\r\n 'snapped-out': data.config.snappedOut}\" (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}\n"] }]
541
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"data\">\r\n <div #listItem [part]=\"part\" [attr.index]=\"data.config.tabIndex\" tabindex=\"1\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': data.config.snapped,\r\n 'snapped-out': data.config.snappedOut, 'focus': $focus | 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"] }]
475
542
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: NgVirtualListService }]; } });
476
543
 
477
544
  /**
@@ -1567,7 +1634,7 @@ class TrackBox extends CacheMap {
1567
1634
  const { width, height, normalizedItemWidth, normalizedItemHeight, dynamicSize, itemsOnDisplayLength, itemsFromStartToScrollEnd, isVertical, renderItems: renderItemsLength, scrollSize, sizeProperty, snap, snippedPos, startPosition, totalLength, startIndex, typicalItemSize, } = metrics, displayItems = [];
1568
1635
  if (items.length) {
1569
1636
  const actualSnippedPosition = snippedPos, isSnappingMethodAdvanced = this.isSnappingMethodAdvanced, boundsSize = isVertical ? height : width, actualEndSnippedPosition = boundsSize;
1570
- let pos = startPosition, renderItems = renderItemsLength, stickyItem, nextSticky, stickyItemIndex = -1, stickyItemSize = 0, endStickyItem, nextEndSticky, endStickyItemIndex = -1, endStickyItemSize = 0;
1637
+ let pos = startPosition, renderItems = renderItemsLength, stickyItem, nextSticky, stickyItemIndex = -1, stickyItemSize = 0, endStickyItem, nextEndSticky, endStickyItemIndex = -1, endStickyItemSize = 0, count = 1;
1571
1638
  if (snap) {
1572
1639
  for (let i = Math.min(itemsFromStartToScrollEnd > 0 ? itemsFromStartToScrollEnd : 0, totalLength - 1); i >= 0; i--) {
1573
1640
  if (!items[i]) {
@@ -1592,6 +1659,7 @@ class TrackBox extends CacheMap {
1592
1659
  snappedOut: false,
1593
1660
  dynamic: dynamicSize,
1594
1661
  isSnappingMethodAdvanced,
1662
+ tabIndex: count,
1595
1663
  zIndex: '1',
1596
1664
  };
1597
1665
  const itemData = items[i];
@@ -1599,6 +1667,7 @@ class TrackBox extends CacheMap {
1599
1667
  stickyItemIndex = i;
1600
1668
  stickyItemSize = size;
1601
1669
  displayItems.push(stickyItem);
1670
+ count++;
1602
1671
  break;
1603
1672
  }
1604
1673
  }
@@ -1630,6 +1699,7 @@ class TrackBox extends CacheMap {
1630
1699
  snappedOut: false,
1631
1700
  dynamic: dynamicSize,
1632
1701
  isSnappingMethodAdvanced,
1702
+ tabIndex: count,
1633
1703
  zIndex: '1',
1634
1704
  };
1635
1705
  const itemData = items[i];
@@ -1637,6 +1707,7 @@ class TrackBox extends CacheMap {
1637
1707
  endStickyItemIndex = i;
1638
1708
  endStickyItemSize = size;
1639
1709
  displayItems.push(endStickyItem);
1710
+ count++;
1640
1711
  break;
1641
1712
  }
1642
1713
  }
@@ -1668,6 +1739,7 @@ class TrackBox extends CacheMap {
1668
1739
  snappedOut: false,
1669
1740
  dynamic: dynamicSize,
1670
1741
  isSnappingMethodAdvanced,
1742
+ tabIndex: count,
1671
1743
  zIndex: '0',
1672
1744
  };
1673
1745
  if (snapped) {
@@ -1692,6 +1764,7 @@ class TrackBox extends CacheMap {
1692
1764
  nextEndSticky.measures.delta = isVertical ? (item.measures.y - scrollSize) : (item.measures.x - scrollSize);
1693
1765
  }
1694
1766
  displayItems.push(item);
1767
+ count++;
1695
1768
  }
1696
1769
  renderItems -= 1;
1697
1770
  pos += size;
@@ -2183,7 +2256,9 @@ class NgVirtualListComponent {
2183
2256
  }
2184
2257
  };
2185
2258
  _$initialized = new BehaviorSubject$1(false);
2186
- $initialized;
2259
+ $initialized = this._$initialized.asObservable();
2260
+ _$viewInitialized = new BehaviorSubject$1(false);
2261
+ $viewInitialized = this._$viewInitialized.asObservable();
2187
2262
  /**
2188
2263
  * Base class of the element component
2189
2264
  */
@@ -2209,8 +2284,9 @@ class NgVirtualListComponent {
2209
2284
  ? 0 : NgVirtualListComponent.__nextId + 1;
2210
2285
  this._id = NgVirtualListComponent.__nextId;
2211
2286
  this._service.initialize(this._trackBox);
2212
- this._$initialized = new BehaviorSubject$1(false);
2213
- this.$initialized = this._$initialized.asObservable();
2287
+ this.$viewInitialized.pipe(takeUntilDestroyed(), filter(v => !!v), tap(v => {
2288
+ this._service.listElement = this._list?.nativeElement ?? null;
2289
+ })).subscribe();
2214
2290
  this._trackBox.displayComponents = this._displayComponents;
2215
2291
  const $trackBy = this.$trackBy, $selectByClick = this.$selectByClick;
2216
2292
  $selectByClick.pipe(takeUntilDestroyed(), tap(v => {
@@ -2536,6 +2612,7 @@ class NgVirtualListComponent {
2536
2612
  this._resizeObserver.observe(containerEl.nativeElement);
2537
2613
  this._onResizeHandler();
2538
2614
  }
2615
+ this._$viewInitialized.next(true);
2539
2616
  }
2540
2617
  /** @internal */
2541
2618
  ngOnDestroy() {